From afeb45efe27916db5d359b6bd58942c0ef86ffea Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Tue, 9 Feb 2021 16:34:57 -0600 Subject: [PATCH] fix race condition with network switching --- app/scripts/controllers/token-rates.js | 17 ++++--- app/scripts/metamask-controller.js | 9 +++- .../app/controllers/token-rates-controller.js | 46 ++++++++++++++++++- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js index a3f0f671094e..7505e4c843fc 100644 --- a/app/scripts/controllers/token-rates.js +++ b/app/scripts/controllers/token-rates.js @@ -19,10 +19,17 @@ export default class TokenRatesController { * * @param {Object} [config] - Options to configure controller */ - constructor({ currency, preferences } = {}) { + constructor({ preferences, onNetworkDidChange, getNativeCurrency } = {}) { this.store = new ObservableStore(); - this.currency = currency; - this.preferences = preferences; + this.nativeCurrency = getNativeCurrency() ?? 'ETH'; + this.tokens = preferences.getState().tokens; + preferences.subscribe(({ tokens = [] }) => { + this.tokens = tokens; + }); + onNetworkDidChange(() => { + this.nativeCurrency = getNativeCurrency() ?? 'ETH'; + this.updateExchangeRates(); + }); } /** @@ -30,9 +37,7 @@ export default class TokenRatesController { */ async updateExchangeRates() { const contractExchangeRates = {}; - const nativeCurrency = this.currency - ? this.currency.state.nativeCurrency.toLowerCase() - : 'eth'; + const nativeCurrency = this.nativeCurrency.toLowerCase(); const pairs = this._tokens.map((token) => token.address).join(','); const query = `contract_addresses=${pairs}&vs_currencies=${nativeCurrency}`; if (this._tokens.length > 0) { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 93404fd39919..91ca1c414f30 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -169,8 +169,15 @@ export default class MetamaskController extends EventEmitter { // token exchange rate tracker this.tokenRatesController = new TokenRatesController({ - currency: this.currencyRateController, preferences: this.preferencesController.store, + onNetworkDidChange: this.networkController.on.bind( + this.networkController, + NETWORK_EVENTS.NETWORK_DID_CHANGE, + ), + getNativeCurrency: () => { + const { ticker } = this.networkController.getProviderConfig(); + return ticker; + }, }); this.ensController = new EnsController({ diff --git a/test/unit/app/controllers/token-rates-controller.js b/test/unit/app/controllers/token-rates-controller.js index c1f69d54fba7..8015d6d5f0cd 100644 --- a/test/unit/app/controllers/token-rates-controller.js +++ b/test/unit/app/controllers/token-rates-controller.js @@ -4,10 +4,22 @@ import { ObservableStore } from '@metamask/obs-store'; import TokenRatesController from '../../../../app/scripts/controllers/token-rates'; describe('TokenRatesController', function () { + let onNetworkDidChange; + let nativeCurrency; + let getNativeCurrency; + beforeEach(function () { + onNetworkDidChange = sinon.spy(); + nativeCurrency = 'ETH'; + getNativeCurrency = () => nativeCurrency; + }); it('should listen for preferences store updates', function () { const preferences = new ObservableStore({ tokens: [] }); preferences.putState({ tokens: ['foo'] }); - const controller = new TokenRatesController({ preferences }); + const controller = new TokenRatesController({ + preferences, + onNetworkDidChange, + getNativeCurrency, + }); assert.deepEqual(controller._tokens, ['foo']); }); @@ -15,11 +27,41 @@ describe('TokenRatesController', function () { const stub = sinon.stub(global, 'setInterval'); const preferences = new ObservableStore({ tokens: [] }); preferences.putState({ tokens: ['foo'] }); - const controller = new TokenRatesController({ preferences }); + const controller = new TokenRatesController({ + preferences, + onNetworkDidChange, + getNativeCurrency, + }); controller.start(1337); assert.strictEqual(stub.getCall(0).args[1], 1337); stub.restore(); controller.stop(); }); + + it('should update native currency if network changes', async function () { + const preferences = new ObservableStore({ tokens: [] }); + preferences.putState({ tokens: ['foo'] }); + const controller = new TokenRatesController({ + preferences, + onNetworkDidChange, + getNativeCurrency, + }); + nativeCurrency = 'xDAI'; + onNetworkDidChange.getCall(0).args[0](); + assert.strictEqual(controller.nativeCurrency, 'xDAI'); + }); + + it('should update exchange rates if network changes', async function () { + const preferences = new ObservableStore({ tokens: [] }); + preferences.putState({ tokens: ['foo'] }); + const controller = new TokenRatesController({ + preferences, + onNetworkDidChange, + getNativeCurrency, + }); + sinon.spy(controller, 'updateExchangeRates'); + onNetworkDidChange.getCall(0).args[0](); + assert(controller.updateExchangeRates.calledOnce); + }); });