Skip to content

Commit

Permalink
fix detect tokens on account switch (#4957)
Browse files Browse the repository at this point in the history
  • Loading branch information
salimtb authored Nov 22, 2024
1 parent 3a12692 commit 1e23e90
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 1 deletion.
105 changes: 104 additions & 1 deletion packages/assets-controllers/src/TokenDetectionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {
} from '@metamask/controller-utils';
import type { InternalAccount } from '@metamask/keyring-api';
import type { KeyringControllerState } from '@metamask/keyring-controller';
import { getDefaultNetworkControllerState } from '@metamask/network-controller';
import {
getDefaultNetworkControllerState,
RpcEndpointType,
} from '@metamask/network-controller';
import type {
NetworkState,
NetworkConfiguration,
Expand Down Expand Up @@ -1014,6 +1017,7 @@ describe('TokenDetectionController', () => {
async ({
mockGetAccount,
mockTokenListGetState,
mockNetworkState,
triggerPreferencesStateChange,
triggerSelectedAccountChange,
callActionSpy,
Expand All @@ -1038,6 +1042,26 @@ describe('TokenDetectionController', () => {
},
},
});
mockNetworkState({
networkConfigurationsByChainId: {
'0x1': {
name: 'ethereum',
nativeCurrency: 'ETH',
rpcEndpoints: [
{
networkClientId: 'mainnet',
type: RpcEndpointType.Infura,
url: 'https://mainnet.infura.io/v3/{infuraProjectId}',
},
],
blockExplorerUrls: [],
chainId: '0x1',
defaultRpcEndpointIndex: 0,
},
},
networksMetadata: {},
selectedNetworkClientId: 'mainnet',
});

triggerPreferencesStateChange({
...getDefaultPreferencesState(),
Expand All @@ -1059,6 +1083,85 @@ describe('TokenDetectionController', () => {
);
});

it('should detect new tokens after switching between accounts on different chains', async () => {
const mockGetBalancesInSingleCall = jest.fn().mockResolvedValue({
[sampleTokenA.address]: new BN(1),
});
const firstSelectedAccount = createMockInternalAccount({
address: '0x0000000000000000000000000000000000000001',
});
const secondSelectedAccount = createMockInternalAccount({
address: '0x0000000000000000000000000000000000000002',
});
await withController(
{
options: {
disabled: false,
getBalancesInSingleCall: mockGetBalancesInSingleCall,
useAccountsAPI: true, // USING ACCOUNTS API
},
mocks: {
getSelectedAccount: firstSelectedAccount,
},
},
async ({
mockGetAccount,
mockTokenListGetState,
mockNetworkState,
triggerPreferencesStateChange,
triggerSelectedAccountChange,
controller,
}) => {
const mockTokens = jest.spyOn(controller, 'detectTokens');
mockMultiChainAccountsService();
mockTokenListGetState({
...getDefaultTokenListState(),
tokensChainsCache: {
'0x1': {
timestamp: 0,
data: {
[sampleTokenA.address]: {
name: sampleTokenA.name,
symbol: sampleTokenA.symbol,
decimals: sampleTokenA.decimals,
address: sampleTokenA.address,
occurrences: 1,
aggregators: sampleTokenA.aggregators,
iconUrl: sampleTokenA.image,
},
},
},
},
});
mockNetworkState({
...getDefaultNetworkControllerState(),
selectedNetworkClientId: NetworkType.mainnet,
});

triggerPreferencesStateChange({
...getDefaultPreferencesState(),
useTokenDetection: true,
});
mockGetAccount(secondSelectedAccount);
triggerSelectedAccountChange(secondSelectedAccount);

await advanceTime({ clock, duration: 1 });

expect(mockTokens).toHaveBeenNthCalledWith(1, {
chainIds: [
'0x1',
'0x5',
'0xaa36a7',
'0xe704',
'0xe705',
'0xe708',
],
selectedAddress: secondSelectedAccount.address,
});
},
);
});

it('should detect new tokens after enabling token detection', async () => {
const mockGetBalancesInSingleCall = jest.fn().mockResolvedValue({
[sampleTokenA.address]: new BN(1),
Expand Down
6 changes: 6 additions & 0 deletions packages/assets-controllers/src/TokenDetectionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,12 +394,18 @@ export class TokenDetectionController extends StaticIntervalPollingController<To
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
// eslint-disable-next-line @typescript-eslint/no-misused-promises
async (selectedAccount) => {
const { networkConfigurationsByChainId } = this.messagingSystem.call(
'NetworkController:getState',
);

const chainIds = Object.keys(networkConfigurationsByChainId) as Hex[];
const isSelectedAccountIdChanged =
this.#selectedAccountId !== selectedAccount.id;
if (isSelectedAccountIdChanged) {
this.#selectedAccountId = selectedAccount.id;
await this.#restartTokenDetection({
selectedAddress: selectedAccount.address,
chainIds,
});
}
},
Expand Down

0 comments on commit 1e23e90

Please sign in to comment.