Skip to content

Commit

Permalink
fix race condition with network switching
Browse files Browse the repository at this point in the history
  • Loading branch information
brad-decker committed Feb 10, 2021
1 parent ba9a67f commit afeb45e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
17 changes: 11 additions & 6 deletions app/scripts/controllers/token-rates.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,25 @@ 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();
});
}

/**
* Updates exchange rates for all tokens
*/
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) {
Expand Down
9 changes: 8 additions & 1 deletion app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
46 changes: 44 additions & 2 deletions test/unit/app/controllers/token-rates-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,64 @@ 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']);
});

it('should poll on correct interval', async 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);
});
});

0 comments on commit afeb45e

Please sign in to comment.