From 2770df80e3cdd4d539b88c6d018108cb07211748 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Wed, 25 Jul 2018 16:14:10 -0400 Subject: [PATCH 01/18] add & delete tokens per account --- app/scripts/controllers/detect-tokens.js | 2 +- app/scripts/controllers/preferences.js | 33 +++++++++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index 195ec918a..62e639795 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -85,7 +85,7 @@ class DetectTokensController { set preferences (preferences) { if (!preferences) { return } this._preferences = preferences - preferences.store.subscribe(({ tokens }) => { this.tokenAddresses = tokens.map((obj) => { return obj.address }) }) + preferences.store.subscribe(({ tokens = [] }) => { this.tokenAddresses = tokens.map((obj) => { return obj.address }) }) preferences.store.subscribe(({ selectedAddress }) => { if (this.selectedAddress !== selectedAddress) { this.selectedAddress = selectedAddress diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index f6250dc16..878333481 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -24,6 +24,7 @@ class PreferencesController { const initState = extend({ frequentRpcList: [], currentAccountTab: 'history', + addressTokens: {}, tokens: [], useBlockie: false, featureFlags: {}, @@ -35,6 +36,16 @@ class PreferencesController { this.diagnostics = opts.diagnostics this.store = new ObservableStore(initState) + + Object.defineProperty(this.store._state, 'tokens', { + get: () => { + const selectedAddress = this.store.getState().selectedAddress + const tokens = this.store.getState().addressTokens + // TODO when create vault + if (!(selectedAddress in tokens)) return [] + return tokens[selectedAddress] + }, + }) } // PUBLIC METHODS @@ -117,14 +128,16 @@ class PreferencesController { */ addAddresses (addresses) { const identities = this.store.getState().identities + const addressTokens = this.store.getState().addressTokens addresses.forEach((address) => { // skip if already exists if (identities[address]) return // add missing identity const identityCount = Object.keys(identities).length + if (!(address in addressTokens)) addressTokens[address] = [] identities[address] = { name: `Account ${identityCount + 1}`, address } }) - this.store.updateState({ identities }) + this.store.updateState({ identities, addressTokens }) } /* @@ -181,7 +194,8 @@ class PreferencesController { setSelectedAddress (_address) { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) - this.store.updateState({ selectedAddress: address }) + const tokens = this.store.getState().addressTokens[_address] + this.store.updateState({ selectedAddress: address, tokens: tokens }) resolve() }) } @@ -233,7 +247,10 @@ class PreferencesController { tokens.push(newEntry) } - this.store.updateState({ tokens }) + const selectedAddress = this.store.getState().selectedAddress + const addressTokens = this.store.getState().addressTokens + addressTokens[selectedAddress] = tokens + this.store.updateState({ addressTokens }) return Promise.resolve(tokens) } @@ -246,11 +263,13 @@ class PreferencesController { * */ removeToken (rawAddress) { - const tokens = this.store.getState().tokens + const addressTokens = this.store.getState().addressTokens + const selectedAddress = this.store.getState().selectedAddress + + const updatedTokens = addressTokens[selectedAddress].filter(token => token.address !== rawAddress) + addressTokens[selectedAddress] = updatedTokens + this.store.updateState({ addressTokens, tokens: updatedTokens }) - const updatedTokens = tokens.filter(token => token.address !== rawAddress) - - this.store.updateState({ tokens: updatedTokens }) return Promise.resolve(updatedTokens) } From adee549c43ace4809e9e9779a3bd9c0dc75aaa17 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Wed, 25 Jul 2018 17:46:31 -0400 Subject: [PATCH 02/18] preferences test fixes for tokens per account --- app/scripts/controllers/preferences.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 878333481..1b1044955 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -40,10 +40,9 @@ class PreferencesController { Object.defineProperty(this.store._state, 'tokens', { get: () => { const selectedAddress = this.store.getState().selectedAddress - const tokens = this.store.getState().addressTokens - // TODO when create vault - if (!(selectedAddress in tokens)) return [] - return tokens[selectedAddress] + const addressTokens = this.store.getState().addressTokens + if (!(selectedAddress in addressTokens)) return [] + return addressTokens[selectedAddress] }, }) } @@ -88,12 +87,16 @@ class PreferencesController { */ setAddresses (addresses) { const oldIdentities = this.store.getState().identities + const addressTokens = this.store.getState().addressTokens const identities = addresses.reduce((ids, address, index) => { const oldId = oldIdentities[address] || {} ids[address] = {name: `Account ${index + 1}`, address, ...oldId} return ids }, {}) - this.store.updateState({ identities }) + for (const address in identities) { + if (!(address in addressTokens)) addressTokens[address] = [] + } + this.store.updateState({ identities, addressTokens }) } /** @@ -104,11 +107,13 @@ class PreferencesController { */ removeAddress (address) { const identities = this.store.getState().identities + const addressTokens = this.store.getState().addressTokens if (!identities[address]) { throw new Error(`${address} can't be deleted cause it was not found`) } delete identities[address] - this.store.updateState({ identities }) + delete addressTokens[address] + this.store.updateState({ identities, addressTokens }) // If the selected account is no longer valid, // select an arbitrary other account: @@ -194,8 +199,10 @@ class PreferencesController { setSelectedAddress (_address) { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) - const tokens = this.store.getState().addressTokens[_address] - this.store.updateState({ selectedAddress: address, tokens: tokens }) + const addressTokens = this.store.getState().addressTokens + if (!(address in addressTokens)) addressTokens[address] = [] + const tokens = addressTokens[address] + this.store.updateState({ selectedAddress: address, tokens }) resolve() }) } @@ -265,7 +272,7 @@ class PreferencesController { removeToken (rawAddress) { const addressTokens = this.store.getState().addressTokens const selectedAddress = this.store.getState().selectedAddress - + const updatedTokens = addressTokens[selectedAddress].filter(token => token.address !== rawAddress) addressTokens[selectedAddress] = updatedTokens this.store.updateState({ addressTokens, tokens: updatedTokens }) From 1d3ad7cfbbdf5831f10eed774244ba1ccedf25d1 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Thu, 26 Jul 2018 18:04:34 -0400 Subject: [PATCH 03/18] tokens per network for individual account --- app/scripts/controllers/preferences.js | 66 ++++++++++++++++++++------ app/scripts/metamask-controller.js | 1 + 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 1b1044955..6ad8a5696 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -34,16 +34,17 @@ class PreferencesController { }, opts.initState) this.diagnostics = opts.diagnostics - + this.network = opts.network this.store = new ObservableStore(initState) - - Object.defineProperty(this.store._state, 'tokens', { - get: () => { + this._defineTokensGetter(this.store._state) + this.network.providerStore.subscribe(({ type }) => { const selectedAddress = this.store.getState().selectedAddress const addressTokens = this.store.getState().addressTokens - if (!(selectedAddress in addressTokens)) return [] - return addressTokens[selectedAddress] - }, + if (!(type in addressTokens)) addressTokens[type] = {} + if (!(selectedAddress in addressTokens[type])) addressTokens[type][selectedAddress] = [] + const tokens = addressTokens[type][selectedAddress] + this.store.updateState({ tokens }) + }) } // PUBLIC METHODS @@ -88,13 +89,15 @@ class PreferencesController { setAddresses (addresses) { const oldIdentities = this.store.getState().identities const addressTokens = this.store.getState().addressTokens + const providerType = this.network.providerStore.getState().type const identities = addresses.reduce((ids, address, index) => { const oldId = oldIdentities[address] || {} ids[address] = {name: `Account ${index + 1}`, address, ...oldId} return ids }, {}) for (const address in identities) { - if (!(address in addressTokens)) addressTokens[address] = [] + if (!(providerType in addressTokens)) addressTokens[providerType] = {} + if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] } this.store.updateState({ identities, addressTokens }) } @@ -134,12 +137,16 @@ class PreferencesController { addAddresses (addresses) { const identities = this.store.getState().identities const addressTokens = this.store.getState().addressTokens + const providerType = this.network.providerStore.getState().type + addresses.forEach((address) => { // skip if already exists if (identities[address]) return // add missing identity const identityCount = Object.keys(identities).length - if (!(address in addressTokens)) addressTokens[address] = [] + + if (!(providerType in addressTokens)) addressTokens[providerType] = {} + if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] identities[address] = { name: `Account ${identityCount + 1}`, address } }) this.store.updateState({ identities, addressTokens }) @@ -200,8 +207,14 @@ class PreferencesController { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) const addressTokens = this.store.getState().addressTokens - if (!(address in addressTokens)) addressTokens[address] = [] - const tokens = addressTokens[address] + const providerType = this.network.providerStore.getState().type + + if (!(providerType in addressTokens)) addressTokens[providerType] = {} + + if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] + + const tokens = addressTokens[providerType][address] + this.store.updateState({ selectedAddress: address, tokens }) resolve() }) @@ -256,7 +269,10 @@ class PreferencesController { const selectedAddress = this.store.getState().selectedAddress const addressTokens = this.store.getState().addressTokens - addressTokens[selectedAddress] = tokens + const providerType = this.network.providerStore.getState().type + + if (!(providerType in addressTokens)) addressTokens[providerType] = {} + addressTokens[providerType][selectedAddress] = tokens this.store.updateState({ addressTokens }) return Promise.resolve(tokens) @@ -272,9 +288,9 @@ class PreferencesController { removeToken (rawAddress) { const addressTokens = this.store.getState().addressTokens const selectedAddress = this.store.getState().selectedAddress - - const updatedTokens = addressTokens[selectedAddress].filter(token => token.address !== rawAddress) - addressTokens[selectedAddress] = updatedTokens + const providerType = this.network.providerStore.getState().type + const updatedTokens = addressTokens[providerType][selectedAddress].filter(token => token.address !== rawAddress) + addressTokens[providerType][selectedAddress] = updatedTokens this.store.updateState({ addressTokens, tokens: updatedTokens }) return Promise.resolve(updatedTokens) @@ -402,6 +418,26 @@ class PreferencesController { // // PRIVATE METHODS // + + /** + * Getter definition for the `tokens` property of store + * + * @param {object} object Store state + * + */ + + _defineTokensGetter (object) { + Object.defineProperty(object, 'tokens', { + get: () => { + const selectedAddress = this.store.getState().selectedAddress + const addressTokens = this.store.getState().addressTokens + const providerType = this.network.providerStore.getState().type + if (!(providerType in addressTokens)) addressTokens[providerType] = {} + if (!(selectedAddress in addressTokens[providerType])) return [] + return addressTokens[providerType][selectedAddress] + }, + }) + } } module.exports = PreferencesController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bcc7075c2..df84bcba4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -87,6 +87,7 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, + network: this.networkController, }) // currency controller From 2827e13caab87692aa085af380355aeb42a13bdf Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Thu, 26 Jul 2018 19:28:12 -0400 Subject: [PATCH 04/18] add & delete tokens per network --- app/scripts/controllers/preferences.js | 18 ++++++++---------- ui/app/actions.js | 3 ++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 6ad8a5696..7ad3ce1e3 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -204,20 +204,18 @@ class PreferencesController { * */ setSelectedAddress (_address) { - return new Promise((resolve, reject) => { - const address = normalizeAddress(_address) - const addressTokens = this.store.getState().addressTokens - const providerType = this.network.providerStore.getState().type + const address = normalizeAddress(_address) + const addressTokens = this.store.getState().addressTokens + const providerType = this.network.providerStore.getState().type - if (!(providerType in addressTokens)) addressTokens[providerType] = {} + if (!(providerType in addressTokens)) addressTokens[providerType] = {} - if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] + if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] - const tokens = addressTokens[providerType][address] + const tokens = addressTokens[providerType][address] - this.store.updateState({ selectedAddress: address, tokens }) - resolve() - }) + this.store.updateState({ selectedAddress: address, tokens }) + return Promise.resolve(tokens) } /** diff --git a/ui/app/actions.js b/ui/app/actions.js index 7a8d9667d..4f71d911b 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1483,11 +1483,12 @@ function showAccountDetail (address) { return (dispatch) => { dispatch(actions.showLoadingIndication()) log.debug(`background.setSelectedAddress`) - background.setSelectedAddress(address, (err) => { + background.setSelectedAddress(address, (err, tokens) => { dispatch(actions.hideLoadingIndication()) if (err) { return dispatch(actions.displayWarning(err.message)) } + dispatch(updateTokens(tokens)) dispatch({ type: actions.SHOW_ACCOUNT_DETAIL, value: address, From f79a249bcc65e594dcd058c30eab2620242ade9c Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Thu, 26 Jul 2018 20:04:57 -0400 Subject: [PATCH 05/18] modify tests according to tokens by network --- .../app/controllers/detect-tokens-test.js | 21 ++++--------------- .../preferences-controller-test.js | 5 ++++- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index 426ffe23a..d6c3fad8a 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -7,10 +7,11 @@ const PreferencesController = require('../../../../app/scripts/controllers/prefe describe('DetectTokensController', () => { const sandbox = sinon.createSandbox() - let clock - let keyringMemStore - before(async () => { + let clock, keyringMemStore, network, preferences + beforeEach(async () => { keyringMemStore = new ObservableStore({ isUnlocked: false}) + network = new NetworkController({ provider: { type: 'mainnet' }}) + preferences = new PreferencesController({ network }) }) after(() => { sandbox.restore() @@ -25,9 +26,7 @@ describe('DetectTokensController', () => { it('should be called on every polling period', async () => { clock = sandbox.useFakeTimers() - const network = new NetworkController() network.setProviderType('mainnet') - const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true controller.isUnlocked = true @@ -45,9 +44,7 @@ describe('DetectTokensController', () => { }) it('should not check tokens while in test network', async () => { - const network = new NetworkController() network.setProviderType('rinkeby') - const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true controller.isUnlocked = true @@ -61,9 +58,7 @@ describe('DetectTokensController', () => { }) it('should only check and add tokens while in main network', async () => { - const network = new NetworkController() network.setProviderType('mainnet') - const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true controller.isUnlocked = true @@ -80,9 +75,7 @@ describe('DetectTokensController', () => { }) it('should not detect same token while in main network', async () => { - const network = new NetworkController() network.setProviderType('mainnet') - const preferences = new PreferencesController() preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8) const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true @@ -100,9 +93,7 @@ describe('DetectTokensController', () => { }) it('should trigger detect new tokens when change address', async () => { - const network = new NetworkController() network.setProviderType('mainnet') - const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true controller.isUnlocked = true @@ -112,9 +103,7 @@ describe('DetectTokensController', () => { }) it('should trigger detect new tokens when submit password', async () => { - const network = new NetworkController() network.setProviderType('mainnet') - const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true controller.selectedAddress = '0x0' @@ -124,9 +113,7 @@ describe('DetectTokensController', () => { }) it('should not trigger detect new tokens when not open or not unlocked', async () => { - const network = new NetworkController() network.setProviderType('mainnet') - const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isOpen = true controller.isUnlocked = false diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index e055500b1..0b96fdfa5 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -1,11 +1,14 @@ const assert = require('assert') +const ObservableStore = require('obs-store') const PreferencesController = require('../../../../app/scripts/controllers/preferences') describe('preferences controller', function () { let preferencesController + let network beforeEach(() => { - preferencesController = new PreferencesController() + network = {providerStore: new ObservableStore({ type: 'mainnet' })} + preferencesController = new PreferencesController({ network }) }) describe('setAddresses', function () { From f5107fa12efcafe2d7e6531399f53c524192e6d6 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 27 Jul 2018 14:56:03 -0400 Subject: [PATCH 06/18] migration for preferences controller tokens --- app/scripts/migrations/028.js | 37 +++++++++++++++++++++++++++++++++ app/scripts/migrations/index.js | 1 + 2 files changed, 38 insertions(+) create mode 100644 app/scripts/migrations/028.js diff --git a/app/scripts/migrations/028.js b/app/scripts/migrations/028.js new file mode 100644 index 000000000..ce52cec05 --- /dev/null +++ b/app/scripts/migrations/028.js @@ -0,0 +1,37 @@ +// next version number +const version = 28 + +/* + +normalizes txParams on unconfirmed txs + +*/ +const clone = require('clone') + +module.exports = { + version, + + migrate: async function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + return versionedData + }, +} + +function transformState (state) { + const newState = state + + if (newState.PreferencesController) { + if (newState.PreferencesController.tokens) { + const tokens = newState.TransactionController.tokens + const selectedAddress = newState.PreferencesController.selectedAddress + newState.PreferencesController.tokens = [] + newState.PreferencesController.addressTokens = {'mainnet': {selectedAddress: tokens}} + } + } + + return newState +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 04d90bfff..2499b7fd1 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -37,4 +37,5 @@ module.exports = [ require('./024'), require('./025'), require('./026'), + require('./028'), ] From 5b9725d1f154e8ed0994c3aab844f696937b0e6e Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 27 Jul 2018 16:05:12 -0400 Subject: [PATCH 07/18] refactor to accountTokens --- app/scripts/controllers/preferences.js | 100 ++++++++++++------------- app/scripts/migrations/028.js | 2 +- 2 files changed, 48 insertions(+), 54 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 7ad3ce1e3..88b6fa998 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -13,6 +13,7 @@ class PreferencesController { * @property {array} store.frequentRpcList A list of custom rpcs to provide the user * @property {string} store.currentAccountTab Indicates the selected tab in the ui * @property {array} store.tokens The tokens the user wants display in their token lists + * @property {object} store.accountTokens The tokens stored per account and then per network type * @property {boolean} store.useBlockie The users preference for blockie identicons within the UI * @property {object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the * user wishes to see that feature @@ -24,7 +25,7 @@ class PreferencesController { const initState = extend({ frequentRpcList: [], currentAccountTab: 'history', - addressTokens: {}, + accountTokens: {}, tokens: [], useBlockie: false, featureFlags: {}, @@ -36,16 +37,8 @@ class PreferencesController { this.diagnostics = opts.diagnostics this.network = opts.network this.store = new ObservableStore(initState) - this._defineTokensGetter(this.store._state) - this.network.providerStore.subscribe(({ type }) => { - const selectedAddress = this.store.getState().selectedAddress - const addressTokens = this.store.getState().addressTokens - if (!(type in addressTokens)) addressTokens[type] = {} - if (!(selectedAddress in addressTokens[type])) addressTokens[type][selectedAddress] = [] - const tokens = addressTokens[type][selectedAddress] - this.store.updateState({ tokens }) - - }) + this._defineTokens() + this._subscribeProviderType() } // PUBLIC METHODS @@ -88,18 +81,17 @@ class PreferencesController { */ setAddresses (addresses) { const oldIdentities = this.store.getState().identities - const addressTokens = this.store.getState().addressTokens - const providerType = this.network.providerStore.getState().type + const accountTokens = this.store.getState().accountTokens + const identities = addresses.reduce((ids, address, index) => { const oldId = oldIdentities[address] || {} ids[address] = {name: `Account ${index + 1}`, address, ...oldId} return ids }, {}) for (const address in identities) { - if (!(providerType in addressTokens)) addressTokens[providerType] = {} - if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] + if (!(address in accountTokens)) accountTokens[address] = {} } - this.store.updateState({ identities, addressTokens }) + this.store.updateState({ identities, accountTokens }) } /** @@ -110,13 +102,13 @@ class PreferencesController { */ removeAddress (address) { const identities = this.store.getState().identities - const addressTokens = this.store.getState().addressTokens + const accountTokens = this.store.getState().accountTokens if (!identities[address]) { throw new Error(`${address} can't be deleted cause it was not found`) } delete identities[address] - delete addressTokens[address] - this.store.updateState({ identities, addressTokens }) + delete accountTokens[address] + this.store.updateState({ identities, accountTokens }) // If the selected account is no longer valid, // select an arbitrary other account: @@ -136,20 +128,17 @@ class PreferencesController { */ addAddresses (addresses) { const identities = this.store.getState().identities - const addressTokens = this.store.getState().addressTokens - const providerType = this.network.providerStore.getState().type - + const accountTokens = this.store.getState().accountTokens addresses.forEach((address) => { // skip if already exists if (identities[address]) return // add missing identity const identityCount = Object.keys(identities).length - if (!(providerType in addressTokens)) addressTokens[providerType] = {} - if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] + if (!(address in accountTokens)) accountTokens[address] = {} identities[address] = { name: `Account ${identityCount + 1}`, address } }) - this.store.updateState({ identities, addressTokens }) + this.store.updateState({ identities, accountTokens }) } /* @@ -205,16 +194,14 @@ class PreferencesController { */ setSelectedAddress (_address) { const address = normalizeAddress(_address) - const addressTokens = this.store.getState().addressTokens + const accountTokens = this.store.getState().accountTokens const providerType = this.network.providerStore.getState().type - if (!(providerType in addressTokens)) addressTokens[providerType] = {} - - if (!(address in addressTokens[providerType])) addressTokens[providerType][address] = [] - - const tokens = addressTokens[providerType][address] - + if (!(address in accountTokens)) accountTokens[address] = {} + if (!(providerType in accountTokens[address])) accountTokens[address][providerType] = [] + const tokens = accountTokens[address][providerType] this.store.updateState({ selectedAddress: address, tokens }) + return Promise.resolve(tokens) } @@ -266,12 +253,10 @@ class PreferencesController { } const selectedAddress = this.store.getState().selectedAddress - const addressTokens = this.store.getState().addressTokens + const accountTokens = this.store.getState().accountTokens const providerType = this.network.providerStore.getState().type - - if (!(providerType in addressTokens)) addressTokens[providerType] = {} - addressTokens[providerType][selectedAddress] = tokens - this.store.updateState({ addressTokens }) + accountTokens[selectedAddress][providerType] = tokens + this.store.updateState({ accountTokens, tokens }) return Promise.resolve(tokens) } @@ -284,12 +269,12 @@ class PreferencesController { * */ removeToken (rawAddress) { - const addressTokens = this.store.getState().addressTokens + const accountTokens = this.store.getState().accountTokens const selectedAddress = this.store.getState().selectedAddress const providerType = this.network.providerStore.getState().type - const updatedTokens = addressTokens[providerType][selectedAddress].filter(token => token.address !== rawAddress) - addressTokens[providerType][selectedAddress] = updatedTokens - this.store.updateState({ addressTokens, tokens: updatedTokens }) + const updatedTokens = accountTokens[selectedAddress][providerType].filter(token => token.address !== rawAddress) + accountTokens[selectedAddress][providerType] = updatedTokens + this.store.updateState({ accountTokens, tokens: updatedTokens }) return Promise.resolve(updatedTokens) } @@ -418,22 +403,31 @@ class PreferencesController { // /** - * Getter definition for the `tokens` property of store + * Getter definition for the `tokens` property of store when controller is initialized * - * @param {object} object Store state * */ + _defineTokens () { + const selectedAddress = this.store.getState().selectedAddress + const accountTokens = this.store.getState().accountTokens + const providerType = this.network.providerStore.getState().type + if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} + if (!(providerType in accountTokens[selectedAddress])) return [] + this.tokens = accountTokens[selectedAddress][providerType] + } - _defineTokensGetter (object) { - Object.defineProperty(object, 'tokens', { - get: () => { - const selectedAddress = this.store.getState().selectedAddress - const addressTokens = this.store.getState().addressTokens - const providerType = this.network.providerStore.getState().type - if (!(providerType in addressTokens)) addressTokens[providerType] = {} - if (!(selectedAddress in addressTokens[providerType])) return [] - return addressTokens[providerType][selectedAddress] - }, + /** + * Subscription to network provider type + * + * + */ + _subscribeProviderType () { + this.network.providerStore.subscribe(({ type }) => { + const selectedAddress = this.store.getState().selectedAddress + const accountTokens = this.store.getState().accountTokens + if (!(type in accountTokens[selectedAddress])) accountTokens[selectedAddress][type] = [] + const tokens = accountTokens[selectedAddress][type] + this.store.updateState({ tokens }) }) } } diff --git a/app/scripts/migrations/028.js b/app/scripts/migrations/028.js index ce52cec05..e36884a9c 100644 --- a/app/scripts/migrations/028.js +++ b/app/scripts/migrations/028.js @@ -29,7 +29,7 @@ function transformState (state) { const tokens = newState.TransactionController.tokens const selectedAddress = newState.PreferencesController.selectedAddress newState.PreferencesController.tokens = [] - newState.PreferencesController.addressTokens = {'mainnet': {selectedAddress: tokens}} + newState.PreferencesController.accountTokens = {selectedAddress: {'mainnet': tokens}} } } From e687bc5a47e2157193dfa099a0f45a97fa1aaed1 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 27 Jul 2018 16:17:28 -0400 Subject: [PATCH 08/18] fix migration for preferences controller tokens --- app/scripts/migrations/028.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/migrations/028.js b/app/scripts/migrations/028.js index e36884a9c..cbda48584 100644 --- a/app/scripts/migrations/028.js +++ b/app/scripts/migrations/028.js @@ -29,7 +29,7 @@ function transformState (state) { const tokens = newState.TransactionController.tokens const selectedAddress = newState.PreferencesController.selectedAddress newState.PreferencesController.tokens = [] - newState.PreferencesController.accountTokens = {selectedAddress: {'mainnet': tokens}} + newState.PreferencesController.accountTokens = {[selectedAddress]: {'mainnet': tokens}} } } From dd6a725e6d76b5910d1d23a5e36905b6057e54fd Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 27 Jul 2018 17:41:47 -0400 Subject: [PATCH 09/18] unit tests for tokens per account and network --- .../preferences-controller-test.js | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index 0b96fdfa5..dcf56e91f 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -161,6 +161,42 @@ describe('preferences controller', function () { await preferencesController.addToken(address, symbol, decimals) assert.equal(preferencesController.getTokens().length, 1, 'one token added for 2nd address') }) + + it('should add token per account', async function () { + const addressFirst = '0xabcdef1234567' + const addressSecond = '0xabcdef1234568' + const symbolFirst = 'ABBR' + const symbolSecond = 'ABBB' + const decimals = 5 + + await preferencesController.setSelectedAddress('0x7e57e2') + await preferencesController.addToken(addressFirst, symbolFirst, decimals) + const tokensFirstAddress = preferencesController.getTokens() + + await preferencesController.setSelectedAddress('0xda22le') + await preferencesController.addToken(addressSecond, symbolSecond, decimals) + const tokensSeconAddress = preferencesController.getTokens() + + assert.notEqual(tokensFirstAddress, tokensSeconAddress, 'add different tokens for two account and tokens are equal') + }) + + it('should add token per network', async function () { + const addressFirst = '0xabcdef1234567' + const addressSecond = '0xabcdef1234568' + const symbolFirst = 'ABBR' + const symbolSecond = 'ABBB' + const decimals = 5 + + network.providerStore.updateState({ type: 'mainnet' }) + await preferencesController.addToken(addressFirst, symbolFirst, decimals) + const tokensFirstAddress = preferencesController.getTokens() + + network.providerStore.updateState({ type: 'rinkeby' }) + await preferencesController.addToken(addressSecond, symbolSecond, decimals) + const tokensSeconAddress = preferencesController.getTokens() + + assert.notEqual(tokensFirstAddress, tokensSeconAddress, 'add different tokens for two networks and tokens are equal') + }) }) describe('removeToken', function () { @@ -185,6 +221,98 @@ describe('preferences controller', function () { const [token1] = tokens assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5}) }) + + it('should remove a token from its state on corresponding address', async function () { + await preferencesController.setSelectedAddress('0x7e57e2') + await preferencesController.addToken('0xa', 'A', 4) + await preferencesController.addToken('0xb', 'B', 5) + await preferencesController.setSelectedAddress('0x7e57e3') + await preferencesController.addToken('0xa', 'A', 4) + await preferencesController.addToken('0xb', 'B', 5) + const initialTokensSecond = preferencesController.getTokens() + await preferencesController.setSelectedAddress('0x7e57e2') + await preferencesController.removeToken('0xa') + + const tokensFirst = preferencesController.getTokens() + assert.equal(tokensFirst.length, 1, 'one token removed in account') + + const [token1] = tokensFirst + assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5}) + + await preferencesController.setSelectedAddress('0x7e57e3') + const tokensSecond = preferencesController.getTokens() + assert.deepEqual(tokensSecond, initialTokensSecond, 'token deleted for account') + }) + + it('should remove a token from its state on corresponding network', async function () { + network.providerStore.updateState({ type: 'mainnet' }) + await preferencesController.addToken('0xa', 'A', 4) + await preferencesController.addToken('0xb', 'B', 5) + network.providerStore.updateState({ type: 'rinkeby' }) + await preferencesController.addToken('0xa', 'A', 4) + await preferencesController.addToken('0xb', 'B', 5) + const initialTokensSecond = preferencesController.getTokens() + network.providerStore.updateState({ type: 'mainnet' }) + await preferencesController.removeToken('0xa') + + const tokensFirst = preferencesController.getTokens() + assert.equal(tokensFirst.length, 1, 'one token removed in network') + + const [token1] = tokensFirst + assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5}) + + network.providerStore.updateState({ type: 'rinkeby' }) + const tokensSecond = preferencesController.getTokens() + assert.deepEqual(tokensSecond, initialTokensSecond, 'token deleted for network') + }) + }) + + describe('on setSelectedAddress', function () { + it('should update tokens from its state on corresponding address', async function () { + await preferencesController.setSelectedAddress('0x7e57e2') + await preferencesController.addToken('0xa', 'A', 4) + await preferencesController.addToken('0xb', 'B', 5) + await preferencesController.setSelectedAddress('0x7e57e3') + await preferencesController.addToken('0xa', 'C', 4) + await preferencesController.addToken('0xb', 'D', 5) + + await preferencesController.setSelectedAddress('0x7e57e2') + const initialTokensFirst = preferencesController.getTokens() + await preferencesController.setSelectedAddress('0x7e57e3') + const initialTokensSecond = preferencesController.getTokens() + + assert.notDeepEqual(initialTokensFirst, initialTokensSecond, 'tokens not equal for different accounts and tokens') + + await preferencesController.setSelectedAddress('0x7e57e2') + const tokensFirst = preferencesController.getTokens() + await preferencesController.setSelectedAddress('0x7e57e3') + const tokensSecond = preferencesController.getTokens() + + assert.deepEqual(tokensFirst, initialTokensFirst, 'tokens equal for same account') + assert.deepEqual(tokensSecond, initialTokensSecond, 'tokens equal for same account') + }) + }) + + describe('on updateStateNetworkType', function () { + it('should remove a token from its state on corresponding network', async function () { + network.providerStore.updateState({ type: 'mainnet' }) + await preferencesController.addToken('0xa', 'A', 4) + await preferencesController.addToken('0xb', 'B', 5) + const initialTokensFirst = preferencesController.getTokens() + network.providerStore.updateState({ type: 'rinkeby' }) + await preferencesController.addToken('0xa', 'C', 4) + await preferencesController.addToken('0xb', 'D', 5) + const initialTokensSecond = preferencesController.getTokens() + + assert.notDeepEqual(initialTokensFirst, initialTokensSecond, 'tokens not equal for different networks and tokens') + + network.providerStore.updateState({ type: 'mainnet' }) + const tokensFirst = preferencesController.getTokens() + network.providerStore.updateState({ type: 'rinkeby' }) + const tokensSecond = preferencesController.getTokens() + assert.deepEqual(tokensFirst, initialTokensFirst, 'tokens equal for same network') + assert.deepEqual(tokensSecond, initialTokensSecond, 'tokens equal for same network') + }) }) }) From 0757f47e84d601792e65c32286465b115ae6770c Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Mon, 30 Jul 2018 11:41:31 -0400 Subject: [PATCH 10/18] passing tokens to all accounts in migration --- app/scripts/migrations/028.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/scripts/migrations/028.js b/app/scripts/migrations/028.js index cbda48584..6553a1052 100644 --- a/app/scripts/migrations/028.js +++ b/app/scripts/migrations/028.js @@ -26,10 +26,13 @@ function transformState (state) { if (newState.PreferencesController) { if (newState.PreferencesController.tokens) { - const tokens = newState.TransactionController.tokens - const selectedAddress = newState.PreferencesController.selectedAddress + const identities = newState.TransactionController.identities + const tokens = newState.PreferencesController.tokens + newState.PreferencesController.accountTokens = {} + for (const identity in identities) { + newState.PreferencesController.accountTokens[identity] = {'mainnet': tokens} + } newState.PreferencesController.tokens = [] - newState.PreferencesController.accountTokens = {[selectedAddress]: {'mainnet': tokens}} } } From 31286673c3bd0c35925f2d41f3e24c0a9d561fa8 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Mon, 30 Jul 2018 18:43:34 -0400 Subject: [PATCH 11/18] isolation of tokens related methods in preferences --- app/scripts/controllers/preferences.js | 87 +++++++++++++------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 88b6fa998..4daa196a9 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -37,7 +37,6 @@ class PreferencesController { this.diagnostics = opts.diagnostics this.network = opts.network this.store = new ObservableStore(initState) - this._defineTokens() this._subscribeProviderType() } // PUBLIC METHODS @@ -81,16 +80,16 @@ class PreferencesController { */ setAddresses (addresses) { const oldIdentities = this.store.getState().identities - const accountTokens = this.store.getState().accountTokens + const oldAccountTokens = this.store.getState().accountTokens const identities = addresses.reduce((ids, address, index) => { const oldId = oldIdentities[address] || {} ids[address] = {name: `Account ${index + 1}`, address, ...oldId} return ids }, {}) - for (const address in identities) { - if (!(address in accountTokens)) accountTokens[address] = {} - } + const accountTokens = addresses.reduce((address) => { + return oldAccountTokens[address] || {} + }, {}) this.store.updateState({ identities, accountTokens }) } @@ -135,7 +134,7 @@ class PreferencesController { // add missing identity const identityCount = Object.keys(identities).length - if (!(address in accountTokens)) accountTokens[address] = {} + accountTokens[address] = {} identities[address] = { name: `Account ${identityCount + 1}`, address } }) this.store.updateState({ identities, accountTokens }) @@ -194,14 +193,8 @@ class PreferencesController { */ setSelectedAddress (_address) { const address = normalizeAddress(_address) - const accountTokens = this.store.getState().accountTokens - const providerType = this.network.providerStore.getState().type - - if (!(address in accountTokens)) accountTokens[address] = {} - if (!(providerType in accountTokens[address])) accountTokens[address][providerType] = [] - const tokens = accountTokens[address][providerType] - this.store.updateState({ selectedAddress: address, tokens }) - + this.store.updateState({ selectedAddress: address }) + const tokens = this._updateTokens() return Promise.resolve(tokens) } @@ -251,13 +244,7 @@ class PreferencesController { } else { tokens.push(newEntry) } - - const selectedAddress = this.store.getState().selectedAddress - const accountTokens = this.store.getState().accountTokens - const providerType = this.network.providerStore.getState().type - accountTokens[selectedAddress][providerType] = tokens - this.store.updateState({ accountTokens, tokens }) - + this._updateAccountTokens(tokens) return Promise.resolve(tokens) } @@ -269,13 +256,9 @@ class PreferencesController { * */ removeToken (rawAddress) { - const accountTokens = this.store.getState().accountTokens - const selectedAddress = this.store.getState().selectedAddress - const providerType = this.network.providerStore.getState().type - const updatedTokens = accountTokens[selectedAddress][providerType].filter(token => token.address !== rawAddress) - accountTokens[selectedAddress][providerType] = updatedTokens - this.store.updateState({ accountTokens, tokens: updatedTokens }) - + const tokens = this.store.getState().tokens + const updatedTokens = tokens.filter(token => token.address !== rawAddress) + this._updateAccountTokens(updatedTokens) return Promise.resolve(updatedTokens) } @@ -401,23 +384,8 @@ class PreferencesController { // // PRIVATE METHODS // - /** - * Getter definition for the `tokens` property of store when controller is initialized - * - * - */ - _defineTokens () { - const selectedAddress = this.store.getState().selectedAddress - const accountTokens = this.store.getState().accountTokens - const providerType = this.network.providerStore.getState().type - if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} - if (!(providerType in accountTokens[selectedAddress])) return [] - this.tokens = accountTokens[selectedAddress][providerType] - } - - /** - * Subscription to network provider type + * Subscription to network provider type. * * */ @@ -425,11 +393,42 @@ class PreferencesController { this.network.providerStore.subscribe(({ type }) => { const selectedAddress = this.store.getState().selectedAddress const accountTokens = this.store.getState().accountTokens + if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} if (!(type in accountTokens[selectedAddress])) accountTokens[selectedAddress][type] = [] const tokens = accountTokens[selectedAddress][type] this.store.updateState({ tokens }) }) } + + /** + * Updates `accountTokens` and `tokens` of current account and network according to it. + * + * @param {[array]} tokens Array of tokens to be updated. + * + */ + _updateAccountTokens (tokens) { + const accountTokens = this.store.getState().accountTokens + const selectedAddress = this.store.getState().selectedAddress + const providerType = this.network.providerStore.getState().type + accountTokens[selectedAddress][providerType] = tokens + this.store.updateState({ accountTokens, tokens }) + } + + /** + * Updates `tokens` of current account and network. + * + * + */ + _updateTokens () { + const accountTokens = this.store.getState().accountTokens + const selectedAddress = this.store.getState().selectedAddress + const providerType = this.network.providerStore.getState().type + if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} + if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = [] + const tokens = accountTokens[selectedAddress][providerType] + this.store.updateState({ tokens }) + return tokens + } } module.exports = PreferencesController From fbcba8f019313c3b02429043578e044046c6cc68 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Mon, 30 Jul 2018 19:09:17 -0400 Subject: [PATCH 12/18] create tokens storage when setadresses --- app/scripts/controllers/preferences.js | 6 +++-- .../preferences-controller-test.js | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 4daa196a9..5c158288b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -87,8 +87,10 @@ class PreferencesController { ids[address] = {name: `Account ${index + 1}`, address, ...oldId} return ids }, {}) - const accountTokens = addresses.reduce((address) => { - return oldAccountTokens[address] || {} + const accountTokens = addresses.reduce((tokens, address) => { + const oldTokens = oldAccountTokens[address] || {} + tokens[address] = oldTokens + return tokens }, {}) this.store.updateState({ identities, accountTokens }) } diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index dcf56e91f..9b2c846bd 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -31,6 +31,20 @@ describe('preferences controller', function () { }) }) + it('should create account tokens for each account in the store', function () { + preferencesController.setAddresses([ + '0xda22le', + '0x7e57e2', + ]) + + const accountTokens = preferencesController.store.getState().accountTokens + + assert.deepEqual(accountTokens, { + '0xda22le': {}, + '0x7e57e2': {}, + }) + }) + it('should replace its list of addresses', function () { preferencesController.setAddresses([ '0xda22le', @@ -67,6 +81,17 @@ describe('preferences controller', function () { assert.equal(preferencesController.store.getState().identities['0xda22le'], undefined) }) + it('should remove an address from state and respective tokens', function () { + preferencesController.setAddresses([ + '0xda22le', + '0x7e57e2', + ]) + + preferencesController.removeAddress('0xda22le') + + assert.equal(preferencesController.store.getState().accountTokens['0xda22le'], undefined) + }) + it('should switch accounts if the selected address is removed', function () { preferencesController.setAddresses([ '0xda22le', From 822c1734d6e3cb9a60306c1b89617c1013627f57 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Mon, 30 Jul 2018 20:36:31 -0400 Subject: [PATCH 13/18] fix double state update when account changed --- app/scripts/controllers/preferences.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 5c158288b..193965c2c 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -195,8 +195,8 @@ class PreferencesController { */ setSelectedAddress (_address) { const address = normalizeAddress(_address) - this.store.updateState({ selectedAddress: address }) - const tokens = this._updateTokens() + const tokens = this._updateTokens(address) + this.store.updateState({ selectedAddress: address, tokens }) return Promise.resolve(tokens) } @@ -421,14 +421,12 @@ class PreferencesController { * * */ - _updateTokens () { + _updateTokens (selectedAddress) { const accountTokens = this.store.getState().accountTokens - const selectedAddress = this.store.getState().selectedAddress const providerType = this.network.providerStore.getState().type if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = [] const tokens = accountTokens[selectedAddress][providerType] - this.store.updateState({ tokens }) return tokens } } From 22cf5a1391be5babae1a05bfb7b3dcde7110e286 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Mon, 30 Jul 2018 20:44:22 -0400 Subject: [PATCH 14/18] improve comments --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index df84bcba4..db323e3fe 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1437,7 +1437,7 @@ module.exports = class MetamaskController extends EventEmitter { } /** - * A method for activating the retrieval of price data and auto detect tokens, + * A method for activating the retrieval of price data, * which should only be fetched when the UI is visible. * @private * @param {boolean} active - True if price data should be getting fetched. From ccae79d392b76d6277bbbb7c887f520e66f81a2f Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Tue, 31 Jul 2018 13:07:28 -0400 Subject: [PATCH 15/18] fix undefined for tokens on tests --- app/scripts/controllers/preferences.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 193965c2c..0cc61ba61 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -405,13 +405,15 @@ class PreferencesController { /** * Updates `accountTokens` and `tokens` of current account and network according to it. * - * @param {[array]} tokens Array of tokens to be updated. + * @param {array} tokens Array of tokens to be updated. * */ _updateAccountTokens (tokens) { const accountTokens = this.store.getState().accountTokens const selectedAddress = this.store.getState().selectedAddress const providerType = this.network.providerStore.getState().type + if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} + if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = [] accountTokens[selectedAddress][providerType] = tokens this.store.updateState({ accountTokens, tokens }) } From 3124e8c61209af960bc36d23677a8fcb5a4f7943 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Tue, 31 Jul 2018 15:59:19 -0400 Subject: [PATCH 16/18] tokens related functions refactor --- app/scripts/controllers/preferences.js | 37 +++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 0cc61ba61..fcbf9c186 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -190,13 +190,14 @@ class PreferencesController { * Setter for the `selectedAddress` property * * @param {string} _address A new hex address for an account - * @returns {Promise} Promise resolves with undefined + * @returns {Promise} Promise resolves with tokens * */ setSelectedAddress (_address) { const address = normalizeAddress(_address) - const tokens = this._updateTokens(address) - this.store.updateState({ selectedAddress: address, tokens }) + this._updateTokens(address) + this.store.updateState({ selectedAddress: address }) + const tokens = this.store.getState().tokens return Promise.resolve(tokens) } @@ -392,12 +393,8 @@ class PreferencesController { * */ _subscribeProviderType () { - this.network.providerStore.subscribe(({ type }) => { - const selectedAddress = this.store.getState().selectedAddress - const accountTokens = this.store.getState().accountTokens - if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} - if (!(type in accountTokens[selectedAddress])) accountTokens[selectedAddress][type] = [] - const tokens = accountTokens[selectedAddress][type] + this.network.providerStore.subscribe(() => { + const { tokens } = this._getTokenRelatedStates() this.store.updateState({ tokens }) }) } @@ -409,11 +406,7 @@ class PreferencesController { * */ _updateAccountTokens (tokens) { - const accountTokens = this.store.getState().accountTokens - const selectedAddress = this.store.getState().selectedAddress - const providerType = this.network.providerStore.getState().type - if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} - if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = [] + const { accountTokens, providerType, selectedAddress } = this._getTokenRelatedStates() accountTokens[selectedAddress][providerType] = tokens this.store.updateState({ accountTokens, tokens }) } @@ -421,15 +414,29 @@ class PreferencesController { /** * Updates `tokens` of current account and network. * + * @param {string} selectedAddress Account address to be updated with. * */ _updateTokens (selectedAddress) { + const { tokens } = this._getTokenRelatedStates(selectedAddress) + this.store.updateState({ tokens }) + } + + /** + * A getter for `tokens` and `accountTokens` related states. + * + * @param {string} selectedAddress A new hex address for an account + * @returns {array, object, string, string} States to interact with tokens in `accountTokens` + * + */ + _getTokenRelatedStates (selectedAddress) { const accountTokens = this.store.getState().accountTokens + if (!selectedAddress) selectedAddress = this.store.getState().selectedAddress const providerType = this.network.providerStore.getState().type if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {} if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = [] const tokens = accountTokens[selectedAddress][providerType] - return tokens + return { tokens, accountTokens, providerType, selectedAddress } } } From d8817b26466617920e47da1f5b1db642ba701a9e Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Tue, 31 Jul 2018 16:18:06 -0400 Subject: [PATCH 17/18] fix doc tag --- app/scripts/controllers/preferences.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index fcbf9c186..707fd7de9 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -426,7 +426,7 @@ class PreferencesController { * A getter for `tokens` and `accountTokens` related states. * * @param {string} selectedAddress A new hex address for an account - * @returns {array, object, string, string} States to interact with tokens in `accountTokens` + * @returns {Object.} States to interact with tokens in `accountTokens` * */ _getTokenRelatedStates (selectedAddress) { From 66c76c04ef5d0bfbe3881ea1dadf7c43c93a262e Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Tue, 7 Aug 2018 14:25:21 -0400 Subject: [PATCH 18/18] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aaa54485..ea5d90500 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- [#4884](https://github.com/MetaMask/metamask-extension/pull/4884): Allow to have tokens per account and network. + ## 4.9.0 Tue Aug 07 2018 - Add new tokens auto detection