Skip to content

Commit 14d5551

Browse files
authored
chore: remove TokenListController (#29872)
## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> `TokenListController` has been removed from `@metamask/assets-controllers` in favour of the token list being fetched directly by dependent controllers (e.g. `TokenDetectionController`, `TokenRatesController`). This PR removes all wiring of `TokenListController` from the mobile app. **Changes included:** - Deleted `token-list-controller-init.ts` and its messenger (`token-list-controller-messenger.ts`) along with their tests - Deleted `useTokenListPolling` hook and its test - Removed `TokenListController` from `Engine.ts` (instantiation, wiring, and exported state) - Removed `TokenListController` from `types.ts` (`MessengerClients`, `EngineState`, `MessengerClientsToInitialize`, global action/event union types) - Removed `TokenListController` from `messengers/index.ts` (`MESSENGER_FACTORIES`) - Removed `TokenListController:stateChange` from `constants.ts` (`BACKGROUND_STATE_CHANGE_EVENT_NAMES`) - Removed `TOKEN_LIST_STATE_CHANGE_EVENT` constant from `AppConstants.ts` - Removed `useTokenListPolling` call from `AssetPollingProvider` and `useEarnNetworkPolling` - Removed runtime access to `TokenListController.state.tokensChainsCache` from `TransactionElement/utils.js` - Removed `TokenListController.fetchTokenList` call from `AddAsset.tsx` - Cleaned up `initial-background-state.json`, E2E fixture files (`default-fixture.json`, `fixture-validation.ts`), and mock state files (`Bridge/initialState.ts`, `perpsStateMock.ts`, `other-controllers-mock.ts`, `component-view/mocks.ts`) ## **Changelog** CHANGELOG entry: remove TokenListController ## **Related issues** https://consensyssoftware.atlassian.net/browse/ASSETS-3181 ## **Manual testing steps** ```gherkin Feature: TokenListController removal Background: Given I am logged into MetaMask Mobile Scenario: NEW user imports SRP/PK with a lot of tokens (from app install) Tokens list and detection should work as expected There should be no issues loading tokens Scenario: EXISTING user imports SRP/PK with a lot of tokens Tokens list and detection should work as expected There should be no issues loading tokens Scenario: token detection still works after controller removal Given I am on the Wallet home screen And I have an account with no custom tokens When user navigates to Add Asset Then the token search screen should load without errors When user selects a different network Then no crash or error should occur Scenario: transaction list still displays correctly Given I am on the Wallet home screen And I have prior ERC-20 transactions When user navigates to the Activity tab Then all transactions should render without errors And token symbols should still appear where available ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** https://github.com/MetaMask/metamask-mobile/actions/runs/25657693707 https://github.com/MetaMask/metamask-mobile/actions/runs/25726986329 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it removes `TokenListController` from Engine wiring/state and strips related polling and fixtures, which can impact token discovery/display paths if any remaining callsites still expect the controller or its cached token metadata. > > **Overview** > Removes `TokenListController` integration from the app, including Engine initialization/exported state, messenger wiring, background state change constants, and shared type definitions. > > Eliminates token-list polling (`useTokenListPolling`) and stops calling it from `AssetPollingProvider` and `useEarnNetworkPolling`, along with deleting the hook and its tests. > > Cleans up UI callsites that depended on the controller: `AddAsset` no longer triggers `fetchTokenList` on network change, and `TransactionElement` no longer prefixes approval action labels using token-list cache data. Updates/cleans fixtures and tests to reflect the removed controller state. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ceeb3ef. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent e88fd67 commit 14d5551

24 files changed

Lines changed: 4 additions & 752 deletions

app/components/UI/Earn/hooks/useEarnNetworkPolling.test.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// Mock all the polling hooks
2-
jest.mock('../../../hooks/AssetPolling/useTokenListPolling', () => jest.fn());
32
jest.mock('../../../hooks/AssetPolling/useTokenBalancesPolling', () =>
43
jest.fn(),
54
);
@@ -34,7 +33,6 @@ import { renderHookWithProvider } from '../../../../util/test/renderWithProvider
3433
import useEarnNetworkPolling from './useEarnNetworkPolling';
3534
import { RootState } from '../../../../reducers';
3635
import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../../util/test/accountsControllerTestUtils';
37-
import useTokenListPolling from '../../../hooks/AssetPolling/useTokenListPolling';
3836
import useTokenBalancesPolling from '../../../hooks/AssetPolling/useTokenBalancesPolling';
3937
import useCurrencyRatePolling from '../../../hooks/AssetPolling/useCurrencyRatePolling';
4038
import useTokenRatesPolling from '../../../hooks/AssetPolling/useTokenRatesPolling';
@@ -52,7 +50,6 @@ afterAll(() => {
5250
});
5351

5452
describe('useEarnNetworkPolling', () => {
55-
const mockUseTokenListPolling = jest.mocked(useTokenListPolling);
5653
const mockUseTokenBalancesPolling = jest.mocked(useTokenBalancesPolling);
5754
const mockUseCurrencyRatePolling = jest.mocked(useCurrencyRatePolling);
5855
const mockUseTokenRatesPolling = jest.mocked(useTokenRatesPolling);
@@ -140,9 +137,6 @@ describe('useEarnNetworkPolling', () => {
140137
state: mockState,
141138
});
142139

143-
expect(mockUseTokenListPolling).toHaveBeenCalledWith({
144-
chainIds: expect.any(Array),
145-
});
146140
expect(mockUseTokenBalancesPolling).toHaveBeenCalledWith({
147141
chainIds: expect.any(Array),
148142
});
@@ -164,9 +158,6 @@ describe('useEarnNetworkPolling', () => {
164158
});
165159

166160
// Initially called with empty arrays
167-
expect(mockUseTokenListPolling).toHaveBeenCalledWith({
168-
chainIds: [],
169-
});
170161
expect(mockUseTokenBalancesPolling).toHaveBeenCalledWith({
171162
chainIds: [],
172163
});
@@ -367,7 +358,6 @@ describe('useEarnNetworkPolling', () => {
367358
rerender({});
368359

369360
// All polling hooks should be called again
370-
expect(mockUseTokenListPolling).toHaveBeenCalled();
371361
expect(mockUseTokenBalancesPolling).toHaveBeenCalled();
372362
expect(mockUseCurrencyRatePolling).toHaveBeenCalled();
373363
expect(mockUseTokenRatesPolling).toHaveBeenCalled();

app/components/UI/Earn/hooks/useEarnNetworkPolling.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { selectUseTokenDetection } from '../../../../selectors/preferencesContro
1010
import useCurrencyRatePolling from '../../../hooks/AssetPolling/useCurrencyRatePolling';
1111
import useTokenBalancesPolling from '../../../hooks/AssetPolling/useTokenBalancesPolling';
1212
import useTokenDetectionPolling from '../../../hooks/AssetPolling/useTokenDetectionPolling';
13-
import useTokenListPolling from '../../../hooks/AssetPolling/useTokenListPolling';
1413
import useTokenRatesPolling from '../../../hooks/AssetPolling/useTokenRatesPolling';
1514
import { RootState } from '../../BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal.test';
1615
import { EVM_SCOPE } from '../constants/networks';
@@ -61,7 +60,6 @@ export const useEarnNetworkPolling = () => {
6160
);
6261
const [lendingChainIds, setLendingChainIds] = useState<Hex[]>([]);
6362

64-
useTokenListPolling({ chainIds: lendingChainIds });
6563
useTokenBalancesPolling({ chainIds: lendingChainIds });
6664
useCurrencyRatePolling({ chainIds: lendingChainIds });
6765
useTokenRatesPolling({ chainIds: lendingChainIds });

app/components/UI/TransactionElement/utils.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -839,15 +839,7 @@ function decodeConfirmTx(args) {
839839

840840
const renderFrom = renderFullAddress(from);
841841
const renderTo = renderFullAddress(to);
842-
const chainId = txChainId;
843-
844-
const tokenList =
845-
Engine.context.TokenListController.state.tokensChainsCache?.[chainId]
846-
?.data || [];
847-
let symbol;
848-
if (renderTo in tokenList) {
849-
symbol = tokenList[renderTo].symbol;
850-
}
842+
851843
let transactionType;
852844
if (actionKey === strings('transactions.approve'))
853845
transactionType = TRANSACTION_TYPES.APPROVE;
@@ -876,7 +868,7 @@ function decodeConfirmTx(args) {
876868
const transactionElement = {
877869
renderTo,
878870
renderFrom,
879-
actionKey: symbol ? `${symbol} ${actionKey}` : actionKey,
871+
actionKey,
880872
value: renderTotalEth,
881873
fiatValue: renderTotalEthFiat,
882874
transactionType,

app/components/Views/AddAsset/AddAsset.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import { useNavigation } from '@react-navigation/native';
1010
import { useParams } from '../../../util/navigation/navUtils';
1111
import { BottomSheetRef } from '../../../component-library/components/BottomSheets/BottomSheet';
1212
import { Hex } from '@metamask/utils';
13-
import Engine from '../../../core/Engine';
1413
import { SupportedCaipChainId } from '@metamask/multichain-network-controller';
15-
import { isNonEvmChainId } from '../../../core/Multichain/utils';
1614
import { useNetworkEnablement } from '../../hooks/useNetworkEnablement/useNetworkEnablement';
1715
import HeaderCompactStandard from '../../../component-library/components-temp/HeaderCompactStandard';
1816
import NetworkListBottomSheet from './components/NetworkListBottomSheet/NetworkListBottomSheet';
@@ -56,9 +54,6 @@ const AddAsset = () => {
5654
selectedNetwork={selectedNetwork}
5755
setSelectedNetwork={async (network) => {
5856
setSelectedNetwork(network);
59-
if (!isNonEvmChainId(network)) {
60-
Engine.context.TokenListController.fetchTokenList(network as Hex);
61-
}
6257
}}
6358
setOpenNetworkSelector={setOpenNetworkSelector}
6459
sheetRef={sheetRef}

app/components/hooks/AssetPolling/AssetPollingProvider.test.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useSelector } from 'react-redux';
44
import useCurrencyRatePolling from './useCurrencyRatePolling';
55
import useTokenRatesPolling from './useTokenRatesPolling';
66
import useTokenDetectionPolling from './useTokenDetectionPolling';
7-
import useTokenListPolling from './useTokenListPolling';
87
import useTokenBalancesPolling from './useTokenBalancesPolling';
98

109
import { AssetPollingProvider } from './AssetPollingProvider';
@@ -18,7 +17,6 @@ jest.mock('react-redux', () => ({
1817
jest.mock('./useCurrencyRatePolling', () => jest.fn());
1918
jest.mock('./useTokenRatesPolling', () => jest.fn());
2019
jest.mock('./useTokenDetectionPolling', () => jest.fn());
21-
jest.mock('./useTokenListPolling', () => jest.fn());
2220
jest.mock('./useTokenBalancesPolling', () => jest.fn());
2321
jest.mock('./useAccountTrackerPolling', () => jest.fn());
2422
jest.mock('./useMultichainAssetsRatePolling', () => jest.fn());
@@ -34,7 +32,6 @@ describe('AssetPollingProvider', () => {
3432
const mockUseCurrencyRatePolling = jest.mocked(useCurrencyRatePolling);
3533
const mockUseTokenRatesPolling = jest.mocked(useTokenRatesPolling);
3634
const mockUseTokenDetectionPolling = jest.mocked(useTokenDetectionPolling);
37-
const mockUseTokenListPolling = jest.mocked(useTokenListPolling);
3835
const mockUseTokenBalancesPolling = jest.mocked(useTokenBalancesPolling);
3936
const mockUseMultichainAssetsRatePolling = jest.mocked(
4037
useMultichainAssetsRatePolling,
@@ -57,7 +54,6 @@ describe('AssetPollingProvider', () => {
5754
expect(mockUseCurrencyRatePolling).toHaveBeenCalledWith(undefined);
5855
expect(mockUseTokenRatesPolling).toHaveBeenCalledWith(undefined);
5956
expect(mockUseTokenDetectionPolling).toHaveBeenCalledWith(undefined);
60-
expect(mockUseTokenListPolling).toHaveBeenCalledWith(undefined);
6157
expect(mockUseTokenBalancesPolling).toHaveBeenCalledWith(undefined);
6258
expect(mockUseMultichainAssetsRatePolling).toHaveBeenCalledWith({
6359
accountId: 'mock-account-id',
@@ -85,10 +81,6 @@ describe('AssetPollingProvider', () => {
8581
address: '0x1234567890abcdef',
8682
});
8783

88-
expect(mockUseTokenListPolling).toHaveBeenCalledWith({
89-
chainIds: CHAIN_IDS_MOCK,
90-
});
91-
9284
expect(mockUseTokenBalancesPolling).toHaveBeenCalledWith({
9385
chainIds: CHAIN_IDS_MOCK,
9486
});

app/components/hooks/AssetPolling/AssetPollingProvider.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useSelector } from 'react-redux';
44
import useCurrencyRatePolling from './useCurrencyRatePolling';
55
import useTokenRatesPolling from './useTokenRatesPolling';
66
import useTokenDetectionPolling from './useTokenDetectionPolling';
7-
import useTokenListPolling from './useTokenListPolling';
87
import useTokenBalancesPolling from './useTokenBalancesPolling';
98
import useMultichainAssetsRatePolling from './useMultichainAssetsRatePolling';
109
import { selectSelectedInternalAccount } from '../../../selectors/accountsController';
@@ -29,7 +28,6 @@ export const AssetPollingProvider = memo(
2928
useCurrencyRatePolling(chainParams);
3029
useTokenRatesPolling(chainParams);
3130
useTokenDetectionPolling(tokenDetectionParams);
32-
useTokenListPolling(chainParams);
3331
useTokenBalancesPolling(chainParams);
3432

3533
useMultichainAssetsRatePolling(

0 commit comments

Comments
 (0)