From 1ca6fff31719c4ff8d155dc9f7c88663a6719046 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 9 Mar 2017 11:31:00 -0800 Subject: [PATCH 01/14] Display owned addresses in datalist. --- ui/app/components/ens-input.js | 10 ++++++++++ ui/app/send.js | 2 ++ 2 files changed, 12 insertions(+) diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index ffc4eab4a..80c8deb22 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -21,6 +21,7 @@ function EnsInput () { EnsInput.prototype.render = function () { const props = this.props const opts = extend(props, { + list: 'addresses', onChange: () => { const network = this.props.network let resolverAddress = networkResolvers[network] @@ -46,6 +47,15 @@ EnsInput.prototype.render = function () { style: { width: '100%' }, }, [ h('input.large-input', opts), + h('datalist', + { + id: 'addresses', + }, + [ + Object.keys(props.identities).map((key) => { + return h('option', props.identities[key].address) + }), + ]), this.ensIcon(), ]) } diff --git a/ui/app/send.js b/ui/app/send.js index a281a5fcf..a2ce696cf 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -44,6 +44,7 @@ SendTransactionScreen.prototype.render = function () { var account = state.account var identity = state.identity var network = state.network + var identities = state.identities return ( @@ -153,6 +154,7 @@ SendTransactionScreen.prototype.render = function () { placeholder: 'Recipient Address', onChange: this.recipientDidChange.bind(this), network, + identities, }), ]), From d270cbc9d2f45b6dae184efbe6c405889ee8cba5 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 9 Mar 2017 13:07:38 -0800 Subject: [PATCH 02/14] Create distinct labels and names for addresses. --- app/scripts/controllers/preferences.js | 4 +++- ui/app/components/ens-input.js | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 18fccf11b..c7f675a41 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -5,7 +5,9 @@ const extend = require('xtend') class PreferencesController { constructor (opts = {}) { - const initState = extend({ frequentRpcList: [] }, opts.initState) + const initState = extend({ + frequentRpcList: [], + }, opts.initState) this.store = new ObservableStore(initState) } diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 80c8deb22..2b224fa3e 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -53,7 +53,11 @@ EnsInput.prototype.render = function () { }, [ Object.keys(props.identities).map((key) => { - return h('option', props.identities[key].address) + let identity = props.identities[key] + return h('option', { + value: identity.address, + label: identity.name, + }) }), ]), this.ensIcon(), From 9f6c04055419f54a730bcbd3f1da4c5f992db94d Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 9 Mar 2017 13:58:42 -0800 Subject: [PATCH 03/14] Create persistence address book. --- app/scripts/controllers/address-book.js | 46 +++++++++++++++++++++++++ app/scripts/metamask-controller.js | 11 ++++++ ui/app/reducers/metamask.js | 1 + 3 files changed, 58 insertions(+) create mode 100644 app/scripts/controllers/address-book.js diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js new file mode 100644 index 000000000..824a256d1 --- /dev/null +++ b/app/scripts/controllers/address-book.js @@ -0,0 +1,46 @@ +const ObservableStore = require('obs-store') +const extend = require('xtend') + +class AddressBookController { + + constructor (opts = {}) { + const initState = extend({ + addressBook: [], + }, opts.initState) + this.store = new ObservableStore(initState) + } + + // + // PUBLIC METHODS + // + + setAddressList (address, name) { + return this.addToAddressList(address, name) + .then((addressBook) => { + this.store.updateState({ + addressBook, + }) + return Promise.resolve() + }) + } + + addToAddressList (address, name) { + let addressBook = this.getAddressList() + let index = addressBook.findIndex((element) => { return element.address === address }) + if (index !== -1) { + addressBook.splice(index, 1) + } + addressBook.push({ + address, + name, + }) + return Promise.resolve(addressBook) + } + + getAddressList () { + return this.store.getState().addressBook + } + +} + +module.exports = AddressBookController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 536891dc6..6cdd8e96f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -15,6 +15,7 @@ const PreferencesController = require('./controllers/preferences') const CurrencyController = require('./controllers/currency') const NoticeController = require('./notice-controller') const ShapeShiftController = require('./controllers/shapeshift') +const AddressBookController = require('./controllers/address-book') const MessageManager = require('./lib/message-manager') const PersonalMessageManager = require('./lib/personal-message-manager') const TxManager = require('./transaction-manager') @@ -50,6 +51,11 @@ module.exports = class MetamaskController extends EventEmitter { initState: initState.PreferencesController, }) + // address book controller + this.addressBookController = new AddressBookController({ + initState: initState.AddressBookController, + }) + // currency controller this.currencyController = new CurrencyController({ initState: initState.CurrencyController, @@ -124,6 +130,9 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController.store.subscribe((state) => { this.store.updateState({ PreferencesController: state }) }) + this.addressBookController.store.subscribe((state) => { + this.store.updateState({ AddressBookController: state }) + }) this.currencyController.store.subscribe((state) => { this.store.updateState({ CurrencyController: state }) }) @@ -142,6 +151,7 @@ module.exports = class MetamaskController extends EventEmitter { this.personalMessageManager.memStore.subscribe(this.sendUpdate.bind(this)) this.keyringController.memStore.subscribe(this.sendUpdate.bind(this)) this.preferencesController.store.subscribe(this.sendUpdate.bind(this)) + this.addressBookController.store.subscribe(this.sendUpdate.bind(this)) this.currencyController.store.subscribe(this.sendUpdate.bind(this)) this.noticeController.memStore.subscribe(this.sendUpdate.bind(this)) this.shapeshiftController.store.subscribe(this.sendUpdate.bind(this)) @@ -219,6 +229,7 @@ module.exports = class MetamaskController extends EventEmitter { this.personalMessageManager.memStore.getState(), this.keyringController.memStore.getState(), this.preferencesController.store.getState(), + this.addressBookController.store.getState(), this.currencyController.store.getState(), this.noticeController.memStore.getState(), // config manager diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index a3c07d977..10d3b0461 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -19,6 +19,7 @@ function reduceMetamask (state, action) { noActiveNotices: true, lastUnreadNotice: undefined, frequentRpcList: [], + addressBook: [], }, state.metamask) switch (action.type) { From b296640f1b2e8cb808297715146a9370ff4f41ec Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 9 Mar 2017 15:09:50 -0800 Subject: [PATCH 04/14] Rename functions for consistency. --- app/scripts/controllers/address-book.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js index 824a256d1..3c2a73dd7 100644 --- a/app/scripts/controllers/address-book.js +++ b/app/scripts/controllers/address-book.js @@ -14,8 +14,8 @@ class AddressBookController { // PUBLIC METHODS // - setAddressList (address, name) { - return this.addToAddressList(address, name) + setAddressBook (address, name) { + return this.addToAddressBook(address, name) .then((addressBook) => { this.store.updateState({ addressBook, @@ -24,9 +24,9 @@ class AddressBookController { }) } - addToAddressList (address, name) { - let addressBook = this.getAddressList() - let index = addressBook.findIndex((element) => { return element.address === address }) + addToAddressBook (address, name) { + let addressBook = this.getAddressBook() + let index = addressBook.findIndex((element) => { return element.address === address || element.name === name }) if (index !== -1) { addressBook.splice(index, 1) } @@ -37,7 +37,7 @@ class AddressBookController { return Promise.resolve(addressBook) } - getAddressList () { + getAddressBook () { return this.store.getState().addressBook } From b34ee4daa145c1d4eea2da6fd0cba0763e5c6483 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 9 Mar 2017 15:10:27 -0800 Subject: [PATCH 05/14] Allow for adding recently used addresses to address book. --- app/scripts/metamask-controller.js | 4 ++++ ui/app/actions.js | 14 ++++++++++++++ ui/app/components/ens-input.js | 13 +++++++++++-- ui/app/send.js | 13 +++++++++++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6cdd8e96f..45905db72 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -251,6 +251,7 @@ module.exports = class MetamaskController extends EventEmitter { const preferencesController = this.preferencesController const txManager = this.txManager const noticeController = this.noticeController + const addressBookController = this.addressBookController return { // etc @@ -278,6 +279,9 @@ module.exports = class MetamaskController extends EventEmitter { setDefaultRpc: nodeify(this.setDefaultRpc).bind(this), setCustomRpc: nodeify(this.setCustomRpc).bind(this), + // AddressController + setAddressBook: nodeify(addressBookController.setAddressBook).bind(addressBookController), + // KeyringController setLocked: nodeify(keyringController.setLocked).bind(keyringController), createNewVaultAndKeychain: nodeify(keyringController.createNewVaultAndKeychain).bind(keyringController), diff --git a/ui/app/actions.js b/ui/app/actions.js index d4fd7553b..e21b6257d 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -75,6 +75,8 @@ var actions = { // account detail screen SHOW_SEND_PAGE: 'SHOW_SEND_PAGE', showSendPage: showSendPage, + ADD_TO_ADDRESS_BOOK: 'ADD_TO_ADDRESS_BOOK', + addToAddressBook: addToAddressBook, REQUEST_ACCOUNT_EXPORT: 'REQUEST_ACCOUNT_EXPORT', requestExportAccount: requestExportAccount, EXPORT_ACCOUNT: 'EXPORT_ACCOUNT', @@ -696,6 +698,18 @@ function setRpcTarget (newRpc) { } } +function addToAddressBook (recipient, nickname) { + log.debug(`background.addToAddressBook`) + return (dispatch) => { + background.setAddressBook(recipient, nickname, (err, result) => { + if (err) { + log.error(err) + return dispatch(self.displayWarning('Address book failed to update')) + } + }) + } +} + function setProviderType (type) { log.debug(`background.setProviderType`) background.setProviderType(type) diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 2b224fa3e..06efe6652 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -59,6 +59,12 @@ EnsInput.prototype.render = function () { label: identity.name, }) }), + props.addressBook.map((identity) => { + return h('option', { + value: identity.address, + label: identity.name, + }) + }), ]), this.ensIcon(), ]) @@ -94,11 +100,13 @@ EnsInput.prototype.lookupEnsName = function () { this.setState({ loadingEns: false, ensResolution: address, + nickname: recipient.trim(), hoverText: address + '\nClick to Copy', }) } }) .catch((reason) => { + log.error(reason) return this.setState({ loadingEns: false, ensFailure: true, @@ -109,10 +117,11 @@ EnsInput.prototype.lookupEnsName = function () { EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) { const state = this.state || {} - const { ensResolution } = state + const ensResolution = state.ensResolution + const nickname = state.nickname || ' ' if (ensResolution && this.props.onChange && ensResolution !== prevState.ensResolution) { - this.props.onChange(ensResolution) + this.props.onChange(ensResolution, nickname) } } diff --git a/ui/app/send.js b/ui/app/send.js index a2ce696cf..eb32d5e06 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -20,6 +20,7 @@ function mapStateToProps (state) { identities: state.metamask.identities, warning: state.appState.warning, network: state.metamask.network, + addressBook: state.metamask.addressBook, } result.error = result.warning && result.warning.split('.')[0] @@ -45,6 +46,7 @@ SendTransactionScreen.prototype.render = function () { var identity = state.identity var network = state.network var identities = state.identities + var addressBook = state.addressBook return ( @@ -155,6 +157,7 @@ SendTransactionScreen.prototype.render = function () { onChange: this.recipientDidChange.bind(this), network, identities, + addressBook, }), ]), @@ -224,13 +227,17 @@ SendTransactionScreen.prototype.back = function () { this.props.dispatch(actions.backToAccountDetail(address)) } -SendTransactionScreen.prototype.recipientDidChange = function (recipient) { - this.setState({ recipient }) +SendTransactionScreen.prototype.recipientDidChange = function (recipient, nickname) { + this.setState({ + recipient: recipient, + nickname: nickname, + }) } SendTransactionScreen.prototype.onSubmit = function () { const state = this.state || {} const recipient = state.recipient || document.querySelector('input[name="address"]').value + const nickname = state.nickname || ' ' const input = document.querySelector('input[name="amount"]').value const value = util.normalizeEthStringToWei(input) const txData = document.querySelector('input[name="txData"]').value @@ -259,6 +266,8 @@ SendTransactionScreen.prototype.onSubmit = function () { this.props.dispatch(actions.hideWarning()) + this.props.dispatch(actions.addToAddressBook(recipient, nickname)) + var txParams = { from: this.props.address, value: '0x' + value.toString(16), From 2ab86b001dfc4ade4fc6df030175e64359b757e6 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 10 Mar 2017 09:34:13 -0800 Subject: [PATCH 06/14] Add comments. --- app/scripts/controllers/address-book.js | 23 +++++++++++++++++++---- ui/app/actions.js | 1 + ui/app/components/ens-input.js | 5 +++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js index 3c2a73dd7..a75ef06ce 100644 --- a/app/scripts/controllers/address-book.js +++ b/app/scripts/controllers/address-book.js @@ -3,6 +3,10 @@ const extend = require('xtend') class AddressBookController { + + // Controller in charge of managing the address book functionality from the + // recipients field on the send screen. Manages a history of all saved + // addresses and all currently owned addresses. constructor (opts = {}) { const initState = extend({ addressBook: [], @@ -14,8 +18,9 @@ class AddressBookController { // PUBLIC METHODS // + // Sets a new address book in store by accepting a new address and nickname. setAddressBook (address, name) { - return this.addToAddressBook(address, name) + return this._addToAddressBook(address, name) .then((addressBook) => { this.store.updateState({ addressBook, @@ -24,8 +29,16 @@ class AddressBookController { }) } - addToAddressBook (address, name) { - let addressBook = this.getAddressBook() + // + // PRIVATE METHODS + // + + + // Performs the logic to add the address and name into the address book. The + // pushed object is an object of two fields. Current behavior does not set an + // upper limit to the number of addresses. + _addToAddressBook (address, name) { + let addressBook = this._getAddressBook() let index = addressBook.findIndex((element) => { return element.address === address || element.name === name }) if (index !== -1) { addressBook.splice(index, 1) @@ -37,7 +50,9 @@ class AddressBookController { return Promise.resolve(addressBook) } - getAddressBook () { + // Internal method to get the address book. Current persistence behavior + // should not require that this method be called from the UI directly. + _getAddressBook () { return this.store.getState().addressBook } diff --git a/ui/app/actions.js b/ui/app/actions.js index e21b6257d..4e0435ade 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -698,6 +698,7 @@ function setRpcTarget (newRpc) { } } +// Calls the addressBookController to add a new address. function addToAddressBook (recipient, nickname) { log.debug(`background.addToAddressBook`) return (dispatch) => { diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 06efe6652..d5348ea62 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -47,11 +47,13 @@ EnsInput.prototype.render = function () { style: { width: '100%' }, }, [ h('input.large-input', opts), + // The address book functionality. h('datalist', { id: 'addresses', }, [ + // Corresponds to the addresses owned. Object.keys(props.identities).map((key) => { let identity = props.identities[key] return h('option', { @@ -59,6 +61,7 @@ EnsInput.prototype.render = function () { label: identity.name, }) }), + // Corresponds to previously sent-to addresses. props.addressBook.map((identity) => { return h('option', { value: identity.address, @@ -118,6 +121,8 @@ EnsInput.prototype.lookupEnsName = function () { EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) { const state = this.state || {} const ensResolution = state.ensResolution + // If an address is sent without a nickname, meaning not from ENS or from + // the user's own accounts, a default of a one-space string is used. const nickname = state.nickname || ' ' if (ensResolution && this.props.onChange && ensResolution !== prevState.ensResolution) { From dc2d614da68ca851c3b1c0c108e7c2f22185751c Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 10 Mar 2017 09:52:05 -0800 Subject: [PATCH 07/14] Add basic tests. --- test/unit/address-book-controller.js | 28 +++++++++++++++++++++++++++ test/unit/currency-controller-test.js | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/unit/address-book-controller.js diff --git a/test/unit/address-book-controller.js b/test/unit/address-book-controller.js new file mode 100644 index 000000000..f00547167 --- /dev/null +++ b/test/unit/address-book-controller.js @@ -0,0 +1,28 @@ +const assert = require('assert') +const extend = require('xtend') +const AddressBookController = require('../../app/scripts/controllers/address-book') + +describe('address-book-controller', function() { + var addressBookController + + beforeEach(function() { + addressBookController = new AddressBookController() + }) + + describe('addres book management', function () { + describe('#_getAddressBook', function () { + it('should be empty by default.', function () { + assert.equal(addressBookController._getAddressBook().length, 0) + }) + }) + describe('#setAddressBook', function () { + it('should properly set a new address.', function () { + addressBookController.setAddressBook('0x01234', 'test') + var addressBook = addressBookController._getAddressBook() + assert.equal(addressBook.length, 1, 'incorrect address book length.') + assert.equal(addressBook[0].address, '0x01234', 'incorrect addresss') + assert.equal(addressBook[0].name, 'test', 'incorrect nickname') + }) + }) + }) +}) diff --git a/test/unit/currency-controller-test.js b/test/unit/currency-controller-test.js index dd7fa91e0..079f8b488 100644 --- a/test/unit/currency-controller-test.js +++ b/test/unit/currency-controller-test.js @@ -7,7 +7,7 @@ const rp = require('request-promise') const nock = require('nock') const CurrencyController = require('../../app/scripts/controllers/currency') -describe('config-manager', function() { +describe('currency-controller', function() { var currencyController beforeEach(function() { From 7182a2be4332e7802c8d2375b9380490aed7ca0b Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 10 Mar 2017 10:05:10 -0800 Subject: [PATCH 08/14] Improve duplicate checking in address book. --- app/scripts/controllers/address-book.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js index a75ef06ce..914fbded2 100644 --- a/app/scripts/controllers/address-book.js +++ b/app/scripts/controllers/address-book.js @@ -39,12 +39,12 @@ class AddressBookController { // upper limit to the number of addresses. _addToAddressBook (address, name) { let addressBook = this._getAddressBook() - let index = addressBook.findIndex((element) => { return element.address === address || element.name === name }) + let index = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name }) if (index !== -1) { addressBook.splice(index, 1) } addressBook.push({ - address, + address: address, name, }) return Promise.resolve(addressBook) From c47f7f6a765e748c33ffde6ff38e881199251eda Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 10 Mar 2017 10:34:18 -0800 Subject: [PATCH 09/14] Add another test for duplicates. --- test/unit/address-book-controller.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/address-book-controller.js b/test/unit/address-book-controller.js index f00547167..51dc898b8 100644 --- a/test/unit/address-book-controller.js +++ b/test/unit/address-book-controller.js @@ -23,6 +23,13 @@ describe('address-book-controller', function() { assert.equal(addressBook[0].address, '0x01234', 'incorrect addresss') assert.equal(addressBook[0].name, 'test', 'incorrect nickname') }) + + it('should reject duplicates.', function () { + addressBookController.setAddressBook('0x01234', 'test') + addressBookController.setAddressBook('0x01234', 'test') + var addressBook = addressBookController._getAddressBook() + assert.equal(addressBook.length, 1, 'incorrect address book length.') + }) }) }) }) From 7dcab52a9e6aa0532a712cb4e502846a383efc94 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 10 Mar 2017 10:34:46 -0800 Subject: [PATCH 10/14] Connect keyring controller to address book to prevent additional duplicates. --- app/scripts/controllers/address-book.js | 22 ++++++++++++++++++---- app/scripts/metamask-controller.js | 10 +++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js index 914fbded2..0e97cc477 100644 --- a/app/scripts/controllers/address-book.js +++ b/app/scripts/controllers/address-book.js @@ -7,11 +7,12 @@ class AddressBookController { // Controller in charge of managing the address book functionality from the // recipients field on the send screen. Manages a history of all saved // addresses and all currently owned addresses. - constructor (opts = {}) { + constructor (opts = {}, keyringController) { const initState = extend({ addressBook: [], }, opts.initState) this.store = new ObservableStore(initState) + this.keyringController = keyringController } // @@ -39,9 +40,16 @@ class AddressBookController { // upper limit to the number of addresses. _addToAddressBook (address, name) { let addressBook = this._getAddressBook() - let index = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name }) - if (index !== -1) { - addressBook.splice(index, 1) + let identities = this._getIdentities() + + let addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name }) + let identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() }) + // trigger this condition if we own this address--no need to overwrite. + if (identitiesIndex !== -1) { + return Promise.resolve(addressBook) + // trigger this condition if we've seen this address before--may need to update nickname. + } else if (addressBookIndex !== -1) { + addressBook.splice(addressBookIndex, 1) } addressBook.push({ address: address, @@ -56,6 +64,12 @@ class AddressBookController { return this.store.getState().addressBook } + // Retrieves identities from the keyring controller in order to avoid + // duplication + _getIdentities () { + return this.keyringController.memStore.getState().identities + } + } module.exports = AddressBookController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 45905db72..1fcee61da 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -51,11 +51,6 @@ module.exports = class MetamaskController extends EventEmitter { initState: initState.PreferencesController, }) - // address book controller - this.addressBookController = new AddressBookController({ - initState: initState.AddressBookController, - }) - // currency controller this.currencyController = new CurrencyController({ initState: initState.CurrencyController, @@ -86,6 +81,11 @@ module.exports = class MetamaskController extends EventEmitter { autoFaucet(address) }) + // address book controller + this.addressBookController = new AddressBookController({ + initState: initState.AddressBookController, + }, this.keyringController) + // tx mgmt this.txManager = new TxManager({ initState: initState.TransactionManager, From d85cc7ec4ef4e93d424ef4debbca1bb27b952a4e Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 10 Mar 2017 10:48:07 -0800 Subject: [PATCH 11/14] Add test to account for prevention of identities duplication. --- test/unit/address-book-controller.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/unit/address-book-controller.js b/test/unit/address-book-controller.js index 51dc898b8..f345b0328 100644 --- a/test/unit/address-book-controller.js +++ b/test/unit/address-book-controller.js @@ -2,11 +2,27 @@ const assert = require('assert') const extend = require('xtend') const AddressBookController = require('../../app/scripts/controllers/address-book') +const mockKeyringController = { + memStore: { + getState: function () { + return { + identities: { + '0x0aaa' : { + address: '0x0aaa', + name: 'owned', + } + } + } + } + } +} + + describe('address-book-controller', function() { var addressBookController beforeEach(function() { - addressBookController = new AddressBookController() + addressBookController = new AddressBookController({}, mockKeyringController) }) describe('addres book management', function () { @@ -30,6 +46,11 @@ describe('address-book-controller', function() { var addressBook = addressBookController._getAddressBook() assert.equal(addressBook.length, 1, 'incorrect address book length.') }) + it('should not add any identities that are under user control', function () { + addressBookController.setAddressBook('0x0aaa', ' ') + var addressBook = addressBookController._getAddressBook() + assert.equal(addressBook.length, 0, 'incorrect address book length.') + }) }) }) }) From 4933e2e2eefa103d6b0d3f3ce264aaf661b50291 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 13 Mar 2017 16:37:53 -0700 Subject: [PATCH 12/14] Limit the number of addresses stored in our book. --- app/scripts/controllers/address-book.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js index 0e97cc477..c66eb2bd4 100644 --- a/app/scripts/controllers/address-book.js +++ b/app/scripts/controllers/address-book.js @@ -50,7 +50,11 @@ class AddressBookController { // trigger this condition if we've seen this address before--may need to update nickname. } else if (addressBookIndex !== -1) { addressBook.splice(addressBookIndex, 1) + } else if (addressBook.length > 15) { + addressBook.shift() } + + addressBook.push({ address: address, name, From c136cb6cd428b54f1a2da36b60f164c6ec3410b2 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 14 Mar 2017 11:44:54 -0700 Subject: [PATCH 13/14] Add to changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f070d9a9..45030cc15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Current Master - Allow sending to ENS names in send form on Ropsten. +- Added an address book functionality that remembers the last 15 unique addresses sent to. ## 3.4.0 2017-3-8 From 1ec7930c75f10390e3e4ab553e1032056d1d2c2f Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 14 Mar 2017 14:04:52 -0700 Subject: [PATCH 14/14] Minor change in removing opts object. --- ui/app/components/ens-input.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index d5348ea62..facf29d97 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -48,10 +48,7 @@ EnsInput.prototype.render = function () { }, [ h('input.large-input', opts), // The address book functionality. - h('datalist', - { - id: 'addresses', - }, + h('datalist#addresses', [ // Corresponds to the addresses owned. Object.keys(props.identities).map((key) => {