diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index ddb14755a..bd2c91a09 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -51,6 +51,7 @@ export default class PreferencesController { useNonceField: false, usePhishDetect: true, dismissSeedBackUpReminder: false, + useStaticTokenList: false, // WARNING: Do not use feature flags for security-sensitive things. // Feature flag toggling is available in the global namespace @@ -138,6 +139,16 @@ export default class PreferencesController { this.store.updateState({ usePhishDetect: val }); } + /** + * Setter for the `useStaticTokenList` property + * + * @param {boolean} val - Whether or not the user prefers to use the static token list or dynamic token list from the API + * + */ + setUseStaticTokenList(val) { + this.store.updateState({ useStaticTokenList: val }); + } + /** * Setter for the `firstTimeFlowType` property * diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index 5e454d55a..f088199ed 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -869,4 +869,22 @@ describe('preferences controller', function () { ); }); }); + describe('setUseStaticTokenList', function () { + it('should default to false', function () { + const state = preferencesController.store.getState(); + assert.equal(state.useStaticTokenList, false); + }); + + it('should set the useStaticTokenList property in state', function () { + assert.equal( + preferencesController.store.getState().useStaticTokenList, + false, + ); + preferencesController.setUseStaticTokenList(true); + assert.equal( + preferencesController.store.getState().useStaticTokenList, + true, + ); + }); + }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f74041946..b45a1a613 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -25,6 +25,7 @@ import { PhishingController, NotificationController, GasFeeController, + TokenListController, } from '@metamask/controllers'; import { TRANSACTION_STATUSES } from '../../shared/constants/transaction'; import { MAINNET_CHAIN_ID } from '../../shared/constants/network'; @@ -32,6 +33,7 @@ import { UI_NOTIFICATIONS } from '../../shared/notifications'; import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; import { MILLISECOND } from '../../shared/constants/time'; +import { hexToDecimal } from '../../ui/helpers/utils/conversions.util'; import ComposableObservableStore from './lib/ComposableObservableStore'; import AccountTracker from './lib/account-tracker'; import createLoggerMiddleware from './lib/createLoggerMiddleware'; @@ -219,6 +221,31 @@ export default class MetamaskController extends EventEmitter { state: initState.CurrencyController, }); + const tokenListMessenger = controllerMessenger.getRestricted({ + name: 'TokenListController', + }); + this.tokenListController = new TokenListController({ + chainId: hexToDecimal(this.networkController.getCurrentChainId()), + useStaticTokenList: this.preferencesController.store.getState() + .useStaticTokenList, + onNetworkStateChange: (cb) => + this.networkController.store.subscribe((networkState) => { + const modifiedNetworkState = { + ...networkState, + provider: { + ...networkState.provider, + chainId: hexToDecimal(networkState.provider.chainId), + }, + }; + return cb(modifiedNetworkState); + }), + onPreferencesStateChange: this.preferencesController.store.subscribe.bind( + this.preferencesController.store, + ), + messenger: tokenListMessenger, + state: initState.tokenListController, + }); + this.phishingController = new PhishingController(); this.notificationController = new NotificationController( @@ -275,11 +302,13 @@ export default class MetamaskController extends EventEmitter { this.incomingTransactionsController.start(); this.tokenRatesController.start(); this.currencyRateController.start(); + this.tokenListController.start(); } else { this.accountTracker.stop(); this.incomingTransactionsController.stop(); this.tokenRatesController.stop(); this.currencyRateController.stop(); + this.tokenListController.stop(); } }); @@ -498,6 +527,7 @@ export default class MetamaskController extends EventEmitter { ThreeBoxController: this.threeBoxController.store, NotificationController: this.notificationController, GasFeeController: this.gasFeeController, + TokenListController: this.tokenListController, }); this.memStore = new ComposableObservableStore({ @@ -530,6 +560,7 @@ export default class MetamaskController extends EventEmitter { ApprovalController: this.approvalController, NotificationController: this.notificationController, GasFeeController: this.gasFeeController, + TokenListController: this.tokenListController, }, controllerMessenger, }); @@ -723,6 +754,10 @@ export default class MetamaskController extends EventEmitter { setUseBlockie: this.setUseBlockie.bind(this), setUseNonceField: this.setUseNonceField.bind(this), setUsePhishDetect: this.setUsePhishDetect.bind(this), + setUseStaticTokenList: nodeify( + this.preferencesController.setUseStaticTokenList, + this.preferencesController, + ), setIpfsGateway: this.setIpfsGateway.bind(this), setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this), setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this), diff --git a/ui/store/actions.js b/ui/store/actions.js index d9f629952..312324990 100644 --- a/ui/store/actions.js +++ b/ui/store/actions.js @@ -2046,6 +2046,19 @@ export function setUsePhishDetect(val) { }; } +export function setUseStaticTokenList(val) { + return (dispatch) => { + dispatch(showLoadingIndication()); + log.debug(`background.setUseStaticTokenList`); + background.setUseStaticTokenList(val, (err) => { + dispatch(hideLoadingIndication()); + if (err) { + dispatch(displayWarning(err.message)); + } + }); + }; +} + export function setIpfsGateway(val) { return (dispatch) => { dispatch(showLoadingIndication());