Skip to content

Commit b1ccf26

Browse files
authored
chore: AccountTrackerController migration (#36808)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **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? --> This PR concludes the migration to `AccountsTrackerController` from core. This is necessary in order to benefit from performance changes added and planned to the core controller. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/36808?quickstart=1) ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-1368 ## **Manual testing steps** ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces the local AccountTrackerController with the core one, removes legacy tracker/polling and gas-limit state, and updates state shape, selectors, metrics, tests, and dependencies accordingly. > > - **Core/Controllers**: > - Replace local `AccountTrackerController` with `@metamask/assets-controllers` version; update init, messengers, allowed actions/events, and wiring. > - Remove legacy files (`account-tracker-controller*`, `batch-utils*`, `constants/contracts.ts`, types) and related listeners/APIs (e.g., balance-update on tx, account syncing). > - Drop `accounts` and `currentBlockGasLimit*` from background/UI state; rely on `accountsByChainId` only; update sentry state and types. > - Remove account-tracker polling APIs/hook; stop exposing start/stop polling from background. > - Bump `@metamask/assets-controllers` to `^86.0.0`; update LavaMoat policies. > - Preferences: add `isMultiAccountBalancesEnabled` mirroring `useMultiAccountBalanceChecker`. > - **MetaMaskController**: > - Remove tracker syncing/clearing and tx-balance update; use checksummed addresses in `getBalance` and metrics. > - **Transactions/Init**: > - Simplify listeners; stop updating balances on tx events. > - **UI/Selectors & Send Flow**: > - Normalize `accountsByChainId` address handling (lowercasing in selectors); remove `getBlockGasLimit` usage; adjust gas estimate logic. > - Fix `token-search` null guard; update tests/fixtures to checksummed addresses. > - **Metrics/Telemetry**: > - Compute `number_of_accounts` from `accountsByChainId`; update masked/removed fields. > - **Tests/Fixtures**: > - Update mocks to checksummed addresses; remove obsolete expectations/delays; align with new state shape. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3cfb04e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent b50a9d9 commit b1ccf26

File tree

59 files changed

+269
-4280
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+269
-4280
lines changed

.storybook/test-data.js

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -743,47 +743,26 @@ const state = {
743743
swapsWelcomeMessageHasBeenShown: true,
744744
defaultHomeActiveTabName: 'Tokens',
745745
network: '5',
746-
accounts: {
747-
'0x64a845a5b02460acf8a3d84503b0d68d028b4bb4': {
748-
address: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4',
749-
balance: '0x176e5b6f173ebe66',
750-
},
751-
'0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': {
752-
address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
753-
balance: '0x2d3142f5000',
754-
},
755-
'0x9d0ba4ddac06032527b140912ec808ab9451b788': {
756-
address: '0x9d0ba4ddac06032527b140912ec808ab9451b788',
757-
balance: '0x15f6f0b9d4f8d000',
758-
},
759-
},
760746
accountsByChainId: {
761747
'0x1': {
762-
'0x64a845a5b02460acf8a3d84503b0d68d028b4bb4': { balance: '0x0' },
763-
'0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': {
748+
'0x64A845a5b02460ACf8a3D84503b0D68d028B4bb4': { balance: '0x0' },
749+
'0xb19Ac54EfA18CC3A14A5B821bFeC73d284Bf0c5e': {
764750
balance: '0xcaf5317161f400',
765751
},
766-
'0x9d0ba4ddac06032527b140912ec808ab9451b788': { balance: '0x0' },
752+
'0x9D0ba4DDAC06032527B140912EC808ab9451b788': { balance: '0x0' },
767753
},
768754
'0x5': {
769-
'0x64a845a5b02460acf8a3d84503b0d68d028b4bb4': {
770-
address: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4',
755+
'0x64A845a5b02460ACf8a3D84503b0D68d028B4bb4': {
771756
balance: '0x176e5b6f173ebe66',
772757
},
773-
'0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': {
774-
address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
758+
'0xb19Ac54EfA18CC3A14A5B821bFeC73d284Bf0c5e': {
775759
balance: '0x2d3142f5000',
776760
},
777-
'0x9d0ba4ddac06032527b140912ec808ab9451b788': {
778-
address: '0x9d0ba4ddac06032527b140912ec808ab9451b788',
761+
'0x9D0ba4DDAC06032527B140912EC808ab9451b788': {
779762
balance: '0x15f6f0b9d4f8d000',
780763
},
781764
},
782765
},
783-
currentBlockGasLimit: '0x793af4',
784-
currentBlockGasLimitByChainId: {
785-
'0x5': '0x793af4',
786-
},
787766
transactions: [
788767
{
789768
chainId: '0x38',

app/scripts/background.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,10 +632,7 @@ function saveTimestamp() {
632632
* @property {boolean} welcomeScreen - True if welcome screen should be shown.
633633
* @property {string} currentLocale - A locale string matching the user's preferred display language.
634634
* @property {string} networkStatus - Either "unknown", "available", "unavailable", or "blocked", depending on the status of the currently selected network.
635-
* @property {object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values.
636635
* @property {object} accountsByChainId - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values keyed by chain id.
637-
* @property {hex} currentBlockGasLimit - The most recently seen block gas limit, in a lower case hex prefixed string.
638-
* @property {object} currentBlockGasLimitByChainId - The most recently seen block gas limit, in a lower case hex prefixed string keyed by chain id.
639636
* @property {object} unapprovedPersonalMsgs - An object of messages pending approval, mapping a unique ID to the options.
640637
* @property {number} unapprovedPersonalMsgCount - The number of messages in unapprovedPersonalMsgs.
641638
* @property {object} unapprovedEncryptionPublicKeyMsgs - An object of messages pending approval, mapping a unique ID to the options.

app/scripts/constants/contracts.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

app/scripts/constants/sentry-state.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ export const SENTRY_BACKGROUND_STATE = {
1414
},
1515
},
1616
AccountTracker: {
17-
accounts: false,
1817
accountsByChainId: false,
19-
currentBlockGasLimit: true,
20-
currentBlockGasLimitByChainId: true,
2118
},
2219
AddressBookController: {
2320
addressBook: false,

app/scripts/controller-init/account-tracker-controller-init.test.ts

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@ import {
44
Messenger,
55
MockAnyNamespace,
66
} from '@metamask/messenger';
7+
import { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller';
8+
import { AccountTrackerController } from '@metamask/assets-controllers';
79
import {
8-
NetworkControllerGetSelectedNetworkClientAction,
9-
NetworkControllerNetworkDidChangeEvent,
10+
AutoManagedNetworkClient,
11+
CustomNetworkClientConfiguration,
12+
NetworkControllerGetNetworkClientByIdAction,
13+
NetworkControllerGetStateAction,
14+
NetworkState,
1015
} from '@metamask/network-controller';
11-
import { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller';
12-
import AccountTrackerController from '../controllers/account-tracker-controller';
16+
import {
17+
PreferencesControllerGetStateAction,
18+
PreferencesState,
19+
} from '@metamask/preferences-controller';
1320
import { ControllerInitRequest } from './types';
1421
import { buildControllerInitRequestMock } from './test/utils';
1522
import {
@@ -20,13 +27,15 @@ import {
2027
} from './messengers';
2128
import { AccountTrackerControllerInit } from './account-tracker-controller-init';
2229

23-
jest.mock('../controllers/account-tracker-controller');
30+
jest.mock('@metamask/assets-controllers');
2431

2532
function getInitRequestMock(
2633
baseMessenger = new Messenger<
2734
MockAnyNamespace,
28-
| NetworkControllerGetSelectedNetworkClientAction
2935
| RemoteFeatureFlagControllerGetStateAction
36+
| NetworkControllerGetStateAction
37+
| NetworkControllerGetNetworkClientByIdAction
38+
| PreferencesControllerGetStateAction
3039
| ActionConstraint,
3140
never
3241
>({ namespace: MOCK_ANY_NAMESPACE }),
@@ -36,17 +45,6 @@ function getInitRequestMock(
3645
AccountTrackerControllerInitMessenger
3746
>
3847
> {
39-
baseMessenger.registerActionHandler(
40-
'NetworkController:getSelectedNetworkClient',
41-
() => ({
42-
// @ts-expect-error: Partial mock.
43-
provider: {},
44-
45-
// @ts-expect-error: Partial mock.
46-
blockTracker: {},
47-
}),
48-
);
49-
5048
baseMessenger.registerActionHandler(
5149
'RemoteFeatureFlagController:getState',
5250
() => ({
@@ -57,6 +55,30 @@ function getInitRequestMock(
5755
}),
5856
);
5957

58+
baseMessenger.registerActionHandler(
59+
'NetworkController:getState',
60+
() =>
61+
({
62+
selectedNetworkClientId: '0x1',
63+
}) as NetworkState,
64+
);
65+
66+
baseMessenger.registerActionHandler(
67+
'NetworkController:getNetworkClientById',
68+
() =>
69+
({
70+
configuration: { chainId: '0x1' },
71+
}) as unknown as AutoManagedNetworkClient<CustomNetworkClientConfiguration>,
72+
);
73+
74+
baseMessenger.registerActionHandler(
75+
'PreferencesController:getState',
76+
() =>
77+
({
78+
useExternalServices: true,
79+
}) as unknown as PreferencesState,
80+
);
81+
6082
const requestMock = {
6183
...buildControllerInitRequestMock(),
6284
controllerMessenger: getAccountTrackerControllerMessenger(baseMessenger),
@@ -78,11 +100,11 @@ describe('AccountTrackerControllerInit', () => {
78100
const controllerMock = jest.mocked(AccountTrackerController);
79101
expect(controllerMock).toHaveBeenCalledWith({
80102
messenger: expect.any(Object),
81-
state: { accounts: {} },
82-
provider: expect.any(Object),
83-
blockTracker: expect.any(Object),
84-
getNetworkIdentifier: expect.any(Function),
103+
getStakedBalanceForChain: expect.any(Function),
104+
includeStakedAssets: false,
105+
allowExternalServices: expect.any(Function),
85106
accountsApiChainIds: expect.any(Function),
107+
fetchingEnabled: expect.any(Function),
86108
});
87109
});
88110

@@ -99,27 +121,4 @@ describe('AccountTrackerControllerInit', () => {
99121
expect(chainIds).toContain('0x38'); // BSC
100122
expect(chainIds).toContain('0xe708'); // Linea
101123
});
102-
103-
it('calls `updateAccounts` when `NetworkController:networkDidChange` is emitted', () => {
104-
const messenger = new Messenger<
105-
MockAnyNamespace,
106-
| NetworkControllerGetSelectedNetworkClientAction
107-
| RemoteFeatureFlagControllerGetStateAction
108-
| ActionConstraint,
109-
NetworkControllerNetworkDidChangeEvent
110-
>({ namespace: MOCK_ANY_NAMESPACE });
111-
112-
const request = getInitRequestMock(messenger);
113-
const { controller } = AccountTrackerControllerInit(request);
114-
115-
expect(controller.updateAccounts).not.toHaveBeenCalled();
116-
117-
messenger.publish('NetworkController:networkDidChange', {
118-
selectedNetworkClientId: 'test',
119-
networkConfigurationsByChainId: {},
120-
networksMetadata: {},
121-
});
122-
123-
expect(controller.updateAccounts).toHaveBeenCalledTimes(1);
124-
});
125124
});

app/scripts/controller-init/account-tracker-controller-init.ts

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,39 @@
1-
import { assert } from '@metamask/utils';
2-
import { getProviderConfig } from '../../../shared/modules/selectors/networks';
3-
import { NETWORK_TYPES } from '../../../shared/constants/network';
4-
import AccountTrackerController from '../controllers/account-tracker-controller';
1+
import { AccountTrackerController } from '@metamask/assets-controllers';
2+
import { NetworkClientId } from '@metamask/network-controller';
53
import { ControllerInitFunction } from './types';
64
import {
75
AccountTrackerControllerInitMessenger,
86
AccountTrackerControllerMessenger,
97
} from './messengers';
108

11-
/**
12-
* Initialize the account tracker controller.
13-
*
14-
* @param request - The request object.
15-
* @param request.controllerMessenger - The messenger to use for the controller.
16-
* @param request.initMessenger - The messenger to use for initialization.
17-
* @returns The initialized controller.
18-
*/
199
export const AccountTrackerControllerInit: ControllerInitFunction<
2010
AccountTrackerController,
2111
AccountTrackerControllerMessenger,
2212
AccountTrackerControllerInitMessenger
23-
> = ({ controllerMessenger, initMessenger }) => {
24-
const { provider, blockTracker } =
25-
initMessenger.call('NetworkController:getSelectedNetworkClient') ?? {};
13+
> = ({ controllerMessenger, initMessenger, getController }) => {
14+
const getAssetsContractController = () =>
15+
getController('AssetsContractController');
2616

27-
assert(
28-
provider,
29-
'Provider is required to initialize AccountTrackerController.',
30-
);
31-
32-
assert(
33-
blockTracker,
34-
'Block tracker is required to initialize AccountTrackerController.',
35-
);
17+
const onboardingController = () => getController('OnboardingController');
3618

3719
const controller = new AccountTrackerController({
38-
state: { accounts: {} },
3920
messenger: controllerMessenger,
40-
provider,
41-
blockTracker,
42-
getNetworkIdentifier: (providerConfig): string => {
43-
const metamask = initMessenger.call('NetworkController:getState');
44-
45-
const config =
46-
providerConfig ??
47-
getProviderConfig({
48-
metamask,
49-
});
50-
51-
return config.type === NETWORK_TYPES.RPC && config.rpcUrl
52-
? config.rpcUrl
53-
: config.type;
21+
getStakedBalanceForChain: (
22+
addresses: string[],
23+
networkClientId?: NetworkClientId,
24+
) => {
25+
const assetsContractController = getAssetsContractController();
26+
return assetsContractController.getStakedBalanceForChain(
27+
addresses,
28+
networkClientId,
29+
);
30+
},
31+
includeStakedAssets: false,
32+
allowExternalServices: () => {
33+
const { useExternalServices } = initMessenger.call(
34+
'PreferencesController:getState',
35+
);
36+
return useExternalServices;
5437
},
5538
accountsApiChainIds: () => {
5639
const state = initMessenger.call('RemoteFeatureFlagController:getState');
@@ -59,14 +42,10 @@ export const AccountTrackerControllerInit: ControllerInitFunction<
5942
state?.remoteFeatureFlags?.assetsAccountApiBalances;
6043

6144
return Array.isArray(featureFlagForAccountApiBalances)
62-
? (featureFlagForAccountApiBalances as string[])
45+
? (featureFlagForAccountApiBalances as `0x${string}`[])
6346
: [];
6447
},
65-
});
66-
67-
// Ensure `AccountTrackerController` updates balances after network change.
68-
initMessenger.subscribe('NetworkController:networkDidChange', () => {
69-
controller.updateAccounts();
48+
fetchingEnabled: () => onboardingController().state.completedOnboarding,
7049
});
7150

7251
return {

app/scripts/controller-init/confirmations/transaction-controller-init.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ export const TransactionControllerInit: ControllerInitFunction<
5656
getFlatState,
5757
getPermittedAccounts,
5858
getTransactionMetricsRequest,
59-
updateAccountBalanceForTransactionNetwork,
6059
persistedState,
6160
} = request;
6261

@@ -198,7 +197,6 @@ export const TransactionControllerInit: ControllerInitFunction<
198197
addTransactionControllerListeners(
199198
initMessenger,
200199
getTransactionMetricsRequest,
201-
updateAccountBalanceForTransactionNetwork,
202200
);
203201

204202
const api = getApi(controller);
@@ -266,22 +264,9 @@ function getExternalPendingTransactions(
266264
function addTransactionControllerListeners(
267265
initMessenger: TransactionControllerInitMessenger,
268266
getTransactionMetricsRequest: () => TransactionMetricsRequest,
269-
updateAccountBalanceForTransactionNetwork: (
270-
transactionMeta: TransactionMeta,
271-
) => void,
272267
) {
273268
const transactionMetricsRequest = getTransactionMetricsRequest();
274269

275-
initMessenger.subscribe(
276-
'TransactionController:unapprovedTransactionAdded',
277-
updateAccountBalanceForTransactionNetwork,
278-
);
279-
280-
initMessenger.subscribe(
281-
'TransactionController:transactionConfirmed',
282-
updateAccountBalanceForTransactionNetwork,
283-
);
284-
285270
initMessenger.subscribe(
286271
'TransactionController:postTransactionBalanceUpdated',
287272
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31879

app/scripts/controller-init/controller-list.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { SmartTransactionsController } from '@metamask/smart-transactions-contro
1313
import { TransactionController } from '@metamask/transaction-controller';
1414
import { AccountsController } from '@metamask/accounts-controller';
1515
import {
16+
AccountTrackerController,
1617
AssetsContractController,
1718
CurrencyRateController,
1819
DeFiPositionsController,
@@ -88,7 +89,6 @@ import { NetworkOrderController } from '../controllers/network-order';
8889
import OAuthService from '../services/oauth/oauth-service';
8990
import MetaMetricsController from '../controllers/metametrics-controller';
9091
import { SnapsNameProvider } from '../lib/SnapsNameProvider';
91-
import AccountTrackerController from '../controllers/account-tracker-controller';
9292
import { AppStateController } from '../controllers/app-state-controller';
9393
import { SnapKeyringBuilder } from '../lib/snap-keyring/snap-keyring';
9494
import { SubscriptionService } from '../services/subscription/subscription-service';
@@ -262,4 +262,5 @@ export type ControllerFlatState = AccountOrderController['state'] &
262262
TokenRatesController['state'] &
263263
NftController['state'] &
264264
NftDetectionController['state'] &
265-
NetworkEnablementController['state'];
265+
NetworkEnablementController['state'] &
266+
AccountTrackerController['state'];

0 commit comments

Comments
 (0)