Skip to content

Commit d20e885

Browse files
cherry-pick: always use remote token list for default petnames (#23919) (#23984)
Cherry-pick of PR #23919 for issue [#2339](MetaMask/MetaMask-planning#2339). Conflicts in `MetamaskController` and `useDisplayName`.
1 parent 7e92a7f commit d20e885

File tree

10 files changed

+307
-78
lines changed

10 files changed

+307
-78
lines changed

app/scripts/controllers/preferences.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ export default class PreferencesController {
118118

119119
this.store = new ObservableStore(initState);
120120
this.store.setMaxListeners(13);
121-
this.tokenListController = opts.tokenListController;
122121

123122
opts.onKeyringStateChange((state) => {
124123
const accounts = new Set();
@@ -217,13 +216,6 @@ export default class PreferencesController {
217216
*/
218217
setUseTokenDetection(val) {
219218
this.store.updateState({ useTokenDetection: val });
220-
this.tokenListController.updatePreventPollingOnNetworkRestart(!val);
221-
if (val) {
222-
this.tokenListController.start();
223-
} else {
224-
this.tokenListController.clearingTokenListData();
225-
this.tokenListController.stop();
226-
}
227219
}
228220

229221
/**

app/scripts/metamask-controller.js

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,6 @@ export default class MetamaskController extends EventEmitter {
518518
initState: initState.PreferencesController,
519519
initLangCode: opts.initLangCode,
520520
messenger: preferencesMessenger,
521-
tokenListController: this.tokenListController,
522521
provider: this.provider,
523522
networkConfigurations: this.networkController.state.networkConfigurations,
524523
onKeyringStateChange: (listener) =>
@@ -2210,12 +2209,19 @@ export default class MetamaskController extends EventEmitter {
22102209
this.accountTracker.start();
22112210
this.txController.startIncomingTransactionPolling();
22122211
this.tokenDetectionController.enable();
2213-
if (this.preferencesController.store.getState().useCurrencyRateCheck) {
2212+
2213+
const preferencesControllerState =
2214+
this.preferencesController.store.getState();
2215+
2216+
const { useCurrencyRateCheck } = preferencesControllerState;
2217+
2218+
if (useCurrencyRateCheck) {
22142219
this.currencyRateController.startPollingByNetworkClientId(
22152220
this.networkController.state.selectedNetworkClientId,
22162221
);
22172222
}
2218-
if (this.preferencesController.store.getState().useTokenDetection) {
2223+
2224+
if (this.#isTokenListPollingRequired(preferencesControllerState)) {
22192225
this.tokenListController.start();
22202226
}
22212227
}
@@ -2224,10 +2230,17 @@ export default class MetamaskController extends EventEmitter {
22242230
this.accountTracker.stop();
22252231
this.txController.stopIncomingTransactionPolling();
22262232
this.tokenDetectionController.disable();
2227-
if (this.preferencesController.store.getState().useCurrencyRateCheck) {
2233+
2234+
const preferencesControllerState =
2235+
this.preferencesController.store.getState();
2236+
2237+
const { useCurrencyRateCheck } = preferencesControllerState;
2238+
2239+
if (useCurrencyRateCheck) {
22282240
this.currencyRateController.stopAllPolling();
22292241
}
2230-
if (this.preferencesController.store.getState().useTokenDetection) {
2242+
2243+
if (this.#isTokenListPollingRequired(preferencesControllerState)) {
22312244
this.tokenListController.stop();
22322245
this.tokenRatesController.stop();
22332246
}
@@ -2488,25 +2501,11 @@ export default class MetamaskController extends EventEmitter {
24882501
setupControllerEventSubscriptions() {
24892502
let lastSelectedAddress;
24902503

2491-
this.preferencesController.store.subscribe(async (state) => {
2492-
const { currentLocale } = state;
2493-
2494-
const { chainId } = this.networkController.state.providerConfig;
2495-
await updateCurrentLocale(currentLocale);
2496-
2497-
if (state.incomingTransactionsPreferences?.[chainId]) {
2498-
this.txController.startIncomingTransactionPolling();
2499-
} else {
2500-
this.txController.stopIncomingTransactionPolling();
2501-
}
2502-
2503-
// TODO: Remove once the preferences controller has been replaced with the core monorepo implementation
2504-
this.controllerMessenger.publish(
2505-
'PreferencesController:stateChange',
2506-
state,
2507-
[],
2508-
);
2509-
});
2504+
this.preferencesController.store.subscribe(
2505+
previousValueComparator((prevState, currState) => {
2506+
this.#onPreferencesControllerStateChange(currState, prevState);
2507+
}, this.preferencesController.store.getState()),
2508+
);
25102509

25112510
this.controllerMessenger.subscribe(
25122511
`${this.accountsController.name}:selectedAccountChange`,
@@ -6020,4 +6019,55 @@ export default class MetamaskController extends EventEmitter {
60206019
{ updatedTransactionMeta },
60216020
);
60226021
}
6022+
6023+
async #onPreferencesControllerStateChange(currentState, previousState) {
6024+
const { currentLocale } = currentState;
6025+
const { chainId } = this.networkController.state.providerConfig;
6026+
6027+
await updateCurrentLocale(currentLocale);
6028+
6029+
if (currentState.incomingTransactionsPreferences?.[chainId]) {
6030+
this.txController.startIncomingTransactionPolling();
6031+
} else {
6032+
this.txController.stopIncomingTransactionPolling();
6033+
}
6034+
6035+
this.#checkTokenListPolling(currentState, previousState);
6036+
6037+
// TODO: Remove once the preferences controller has been replaced with the core monorepo implementation
6038+
this.controllerMessenger.publish(
6039+
'PreferencesController:stateChange',
6040+
currentState,
6041+
[],
6042+
);
6043+
}
6044+
6045+
#checkTokenListPolling(currentState, previousState) {
6046+
const previousEnabled = this.#isTokenListPollingRequired(previousState);
6047+
const newEnabled = this.#isTokenListPollingRequired(currentState);
6048+
6049+
if (previousEnabled === newEnabled) {
6050+
return;
6051+
}
6052+
6053+
this.tokenListController.updatePreventPollingOnNetworkRestart(!newEnabled);
6054+
6055+
if (newEnabled) {
6056+
log.debug('Started token list controller polling');
6057+
this.tokenListController.start();
6058+
} else {
6059+
log.debug('Stopped token list controller polling');
6060+
this.tokenListController.clearingTokenListData();
6061+
this.tokenListController.stop();
6062+
}
6063+
}
6064+
6065+
#isTokenListPollingRequired(preferencesControllerState) {
6066+
const { useTokenDetection, useTransactionSimulations, preferences } =
6067+
preferencesControllerState ?? {};
6068+
6069+
const { petnamesEnabled } = preferences ?? {};
6070+
6071+
return useTokenDetection || petnamesEnabled || useTransactionSimulations;
6072+
}
60236073
}

app/scripts/metamask-controller.test.js

Lines changed: 130 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ import { NetworkType } from '@metamask/controller-utils';
1919
import { ControllerMessenger } from '@metamask/base-controller';
2020
import { LoggingController, LogType } from '@metamask/logging-controller';
2121
import { TransactionController } from '@metamask/transaction-controller';
22+
import { TokenListController } from '@metamask/assets-controllers';
2223
import { NETWORK_TYPES } from '../../shared/constants/network';
2324
import { createTestProviderTools } from '../../test/stub/provider';
2425
import { HardwareDeviceNames } from '../../shared/constants/hardware-wallets';
2526
import { KeyringType } from '../../shared/constants/keyring';
2627
import { LOG_EVENT } from '../../shared/constants/logs';
2728
import mockEncryptor from '../../test/lib/mock-encryptor';
2829
import * as tokenUtils from '../../shared/lib/token-util';
30+
import { flushPromises } from '../../test/lib/timer-helpers';
2931
import { deferredPromise } from './lib/util';
3032
import MetaMaskController from './metamask-controller';
3133

@@ -294,6 +296,14 @@ describe('MetaMaskController', () => {
294296
describe('MetaMaskController Behaviour', () => {
295297
let metamaskController;
296298

299+
async function simulatePreferencesChange(preferences) {
300+
metamaskController.preferencesController.store.subscribe.mock.lastCall[0](
301+
preferences,
302+
);
303+
304+
await flushPromises();
305+
}
306+
297307
beforeEach(() => {
298308
jest.spyOn(MetaMaskController.prototype, 'resetStates');
299309

@@ -316,6 +326,9 @@ describe('MetaMaskController', () => {
316326
.mockReturnValue();
317327

318328
jest.spyOn(ControllerMessenger.prototype, 'subscribe');
329+
jest.spyOn(TokenListController.prototype, 'start');
330+
jest.spyOn(TokenListController.prototype, 'stop');
331+
jest.spyOn(TokenListController.prototype, 'clearingTokenListData');
319332

320333
metamaskController = new MetaMaskController({
321334
showUserConfirmation: noop,
@@ -1779,13 +1792,11 @@ describe('MetaMaskController', () => {
17791792
TransactionController.prototype.startIncomingTransactionPolling,
17801793
).not.toHaveBeenCalled();
17811794

1782-
await metamaskController.preferencesController.store.subscribe.mock.lastCall[0](
1783-
{
1784-
incomingTransactionsPreferences: {
1785-
[MAINNET_CHAIN_ID]: true,
1786-
},
1795+
await simulatePreferencesChange({
1796+
incomingTransactionsPreferences: {
1797+
[MAINNET_CHAIN_ID]: true,
17871798
},
1788-
);
1799+
});
17891800

17901801
expect(
17911802
TransactionController.prototype.startIncomingTransactionPolling,
@@ -1797,13 +1808,11 @@ describe('MetaMaskController', () => {
17971808
TransactionController.prototype.stopIncomingTransactionPolling,
17981809
).not.toHaveBeenCalled();
17991810

1800-
await metamaskController.preferencesController.store.subscribe.mock.lastCall[0](
1801-
{
1802-
incomingTransactionsPreferences: {
1803-
[MAINNET_CHAIN_ID]: false,
1804-
},
1811+
await simulatePreferencesChange({
1812+
incomingTransactionsPreferences: {
1813+
[MAINNET_CHAIN_ID]: false,
18051814
},
1806-
);
1815+
});
18071816

18081817
expect(
18091818
TransactionController.prototype.stopIncomingTransactionPolling,
@@ -1839,6 +1848,115 @@ describe('MetaMaskController', () => {
18391848
).toHaveBeenCalledTimes(1);
18401849
});
18411850
});
1851+
1852+
describe('token list controller', () => {
1853+
it('stops polling if petnames, simulations, and token detection disabled', async () => {
1854+
expect(TokenListController.prototype.stop).not.toHaveBeenCalled();
1855+
1856+
expect(
1857+
TokenListController.prototype.clearingTokenListData,
1858+
).not.toHaveBeenCalled();
1859+
1860+
await simulatePreferencesChange({
1861+
useTransactionSimulations: false,
1862+
useTokenDetection: false,
1863+
preferences: {
1864+
petnamesEnabled: false,
1865+
},
1866+
});
1867+
1868+
expect(TokenListController.prototype.stop).toHaveBeenCalledTimes(1);
1869+
1870+
expect(
1871+
TokenListController.prototype.clearingTokenListData,
1872+
).toHaveBeenCalledTimes(1);
1873+
});
1874+
1875+
it.each([
1876+
[
1877+
'petnames',
1878+
{
1879+
preferences: { petnamesEnabled: false },
1880+
useTokenDetection: true,
1881+
useTransactionSimulations: true,
1882+
},
1883+
],
1884+
[
1885+
'simulations',
1886+
{
1887+
preferences: { petnamesEnabled: true },
1888+
useTokenDetection: true,
1889+
useTransactionSimulations: false,
1890+
},
1891+
],
1892+
[
1893+
'token detection',
1894+
{
1895+
preferences: { petnamesEnabled: true },
1896+
useTokenDetection: false,
1897+
useTransactionSimulations: true,
1898+
},
1899+
],
1900+
])(
1901+
'does not stop polling if only %s disabled',
1902+
async (_, preferences) => {
1903+
expect(TokenListController.prototype.stop).not.toHaveBeenCalled();
1904+
1905+
expect(
1906+
TokenListController.prototype.clearingTokenListData,
1907+
).not.toHaveBeenCalled();
1908+
1909+
await simulatePreferencesChange(preferences);
1910+
1911+
expect(TokenListController.prototype.stop).not.toHaveBeenCalled();
1912+
1913+
expect(
1914+
TokenListController.prototype.clearingTokenListData,
1915+
).not.toHaveBeenCalled();
1916+
},
1917+
);
1918+
1919+
it.each([
1920+
[
1921+
'petnames',
1922+
{
1923+
preferences: { petnamesEnabled: true },
1924+
useTokenDetection: false,
1925+
useTransactionSimulations: false,
1926+
},
1927+
],
1928+
[
1929+
'simulations',
1930+
{
1931+
preferences: { petnamesEnabled: false },
1932+
useTokenDetection: false,
1933+
useTransactionSimulations: true,
1934+
},
1935+
],
1936+
[
1937+
'token detection',
1938+
{
1939+
preferences: { petnamesEnabled: false },
1940+
useTokenDetection: true,
1941+
useTransactionSimulations: false,
1942+
},
1943+
],
1944+
])('starts polling if only %s enabled', async (_, preferences) => {
1945+
expect(TokenListController.prototype.start).not.toHaveBeenCalled();
1946+
1947+
await simulatePreferencesChange({
1948+
useTransactionSimulations: false,
1949+
useTokenDetection: false,
1950+
preferences: {
1951+
petnamesEnabled: false,
1952+
},
1953+
});
1954+
1955+
await simulatePreferencesChange(preferences);
1956+
1957+
expect(TokenListController.prototype.start).toHaveBeenCalledTimes(1);
1958+
});
1959+
});
18421960
});
18431961

18441962
describe('MV3 Specific behaviour', () => {

test/e2e/mock-e2e.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,38 @@ async function setupMocking(server, testSpecificMock, { chainId }) {
305305
],
306306
occurrences: 9,
307307
},
308+
{
309+
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
310+
symbol: 'DAI',
311+
decimals: 18,
312+
name: 'Dai Stablecoin',
313+
iconUrl:
314+
'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/dai.svg',
315+
type: 'erc20',
316+
aggregators: [
317+
'metamask',
318+
'aave',
319+
'bancor',
320+
'cmc',
321+
'cryptocom',
322+
'coinGecko',
323+
'oneInch',
324+
'pmm',
325+
'sushiswap',
326+
'zerion',
327+
'lifi',
328+
'socket',
329+
'squid',
330+
'openswap',
331+
'sonarwatch',
332+
'uniswapLabs',
333+
'coinmarketcap',
334+
],
335+
occurrences: 17,
336+
erc20Permit: true,
337+
fees: { '0xb0da5965d43369968574d399dbe6374683773a65': 0 },
338+
storage: { balance: 2 },
339+
},
308340
],
309341
};
310342
});

0 commit comments

Comments
 (0)