diff --git a/packages/accounts-controller/CHANGELOG.md b/packages/accounts-controller/CHANGELOG.md index 31c212349d9..aafeebe9251 100644 --- a/packages/accounts-controller/CHANGELOG.md +++ b/packages/accounts-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `accountIdByAddress` mapping to state and update `getAccountByAddress` function ([#7893](https://github.com/MetaMask/core/pull/7893)) + - This state was added to improve lookup times for an account by address from O(n) to O(1). + ## [36.0.1] ### Changed diff --git a/packages/accounts-controller/src/AccountsController.test.ts b/packages/accounts-controller/src/AccountsController.test.ts index 30efe029834..ffd12c2f644 100644 --- a/packages/accounts-controller/src/AccountsController.test.ts +++ b/packages/accounts-controller/src/AccountsController.test.ts @@ -67,6 +67,7 @@ const defaultState: AccountsControllerState = { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }; const mockGetKeyringByType = jest.fn(); @@ -380,6 +381,9 @@ describe('AccountsController', () => { }, selectedAccount: mockSnapAccount.id, }, + accountIdByAddress: { + [mockSnapAccount.address]: mockSnapAccount.id, + }, }, messenger, }); @@ -424,6 +428,9 @@ describe('AccountsController', () => { }, selectedAccount: mockSnapAccount.id, }, + accountIdByAddress: { + [mockSnapAccount.address]: mockSnapAccount.id, + }, }, messenger, }); @@ -468,6 +475,9 @@ describe('AccountsController', () => { }, selectedAccount: mockSnapAccount.id, }, + accountIdByAddress: { + [mockSnapAccount.address]: mockSnapAccount.id, + }, }, messenger, }); @@ -513,6 +523,9 @@ describe('AccountsController', () => { }, selectedAccount: mockSnapAccount.id, }, + accountIdByAddress: { + [mockSnapAccount.address]: mockSnapAccount.id, + }, }, messenger, }); @@ -560,6 +573,9 @@ describe('AccountsController', () => { }, selectedAccount: mockSnapAccount.id, }, + accountIdByAddress: { + [mockSnapAccount.address]: mockSnapAccount.id, + }, }, messenger, }); @@ -589,6 +605,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -629,6 +646,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -667,6 +685,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -710,6 +729,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount3.address]: mockAccount3.id, + }, }, messenger, }); @@ -779,6 +802,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount4.address]: mockAccount4.id, + }, }, messenger, }); @@ -854,6 +881,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount4.address]: mockAccount4.id, + }, }, messenger, }); @@ -915,6 +946,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -963,6 +997,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, messenger, }); @@ -1032,6 +1070,11 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2WithCustomName.address]: + mockAccount2WithCustomName.id, + }, }, messenger, }); @@ -1103,6 +1146,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: 'missing', }, + accountIdByAddress: {}, }, messenger, }); @@ -1145,6 +1189,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount3.address]: mockAccount3.id, + }, }, messenger, }); @@ -1180,6 +1228,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -1247,6 +1298,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, messenger, }); @@ -1303,6 +1358,10 @@ describe('AccountsController', () => { }, selectedAccount: 'missing-account', }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, messenger, }); @@ -1367,6 +1426,10 @@ describe('AccountsController', () => { }, selectedAccount: 'missing-account', }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, messenger, }); @@ -1439,6 +1502,10 @@ describe('AccountsController', () => { }, selectedAccount: 'missing-account', }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, messenger, }); @@ -1482,6 +1549,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount3.address]: mockAccount3.id, + }, }, messenger, }); @@ -1559,6 +1630,9 @@ describe('AccountsController', () => { }, selectedAccount: mockInitialAccount.id, }, + accountIdByAddress: { + [mockInitialAccount.address]: mockInitialAccount.id, + }, }, messenger, }); @@ -1637,6 +1711,10 @@ describe('AccountsController', () => { }, selectedAccount: 'unknown', }, + accountIdByAddress: { + [mockExistingAccount1.address]: mockExistingAccount1.id, + [mockExistingAccount2.address]: mockExistingAccount2.id, + }, }, messenger, }); @@ -1679,6 +1757,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -1753,6 +1832,9 @@ describe('AccountsController', () => { }, selectedAccount: account.id, }, + accountIdByAddress: { + [account.address]: account.id, + }, }, messenger, }); @@ -1860,6 +1942,11 @@ describe('AccountsController', () => { }, selectedAccount: mockNewerEvmAccount.id, }, + accountIdByAddress: { + [mockOlderEvmAccount.address]: mockOlderEvmAccount.id, + [mockNewerEvmAccount.address]: mockNewerEvmAccount.id, + [mockBtcAccount.address]: mockBtcAccount.id, + }, }, messenger, }); @@ -1885,6 +1972,10 @@ describe('AccountsController', () => { }, selectedAccount: mockBtcAccount.id, }, + accountIdByAddress: { + [mockOlderEvmAccount.address]: mockOlderEvmAccount.id, + [mockBtcAccount.address]: mockBtcAccount.id, + }, }, messenger, }); @@ -1910,6 +2001,9 @@ describe('AccountsController', () => { }, selectedAccount: mockOlderEvmAccount.id, }, + accountIdByAddress: { + [mockOlderEvmAccount.address]: mockOlderEvmAccount.id, + }, }, messenger, }); @@ -2009,6 +2103,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2074,6 +2169,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2127,6 +2223,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2178,6 +2275,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -2248,6 +2348,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2320,6 +2421,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2392,6 +2494,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2442,6 +2545,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, messenger, }); @@ -2541,6 +2645,10 @@ describe('AccountsController', () => { }, selectedAccount: 'unknown', }, + accountIdByAddress: { + [mockExistingAccount1.address]: mockExistingAccount1.id, + [mockExistingAccount2.address]: mockExistingAccount2.id, + }, }, messenger, }); @@ -2623,6 +2731,9 @@ describe('AccountsController', () => { }, selectedAccount: mockHdAccount.id, }, + accountIdByAddress: { + [mockHdAccount.address]: mockHdAccount.id, + }, }, messenger, }); @@ -2710,6 +2821,9 @@ describe('AccountsController', () => { }, selectedAccount: mockHdAccount.id, }, + accountIdByAddress: { + [mockHdAccount.address]: mockHdAccount.id, + }, }, messenger, }); @@ -2737,6 +2851,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, }); @@ -2747,6 +2862,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }); expect(accountsController.state).toStrictEqual({ @@ -2756,6 +2874,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }); }); @@ -2766,6 +2887,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -2779,6 +2903,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }); }); }); @@ -2791,6 +2918,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -2805,6 +2935,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -2826,6 +2959,11 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + [mockAccount3.address]: mockAccount3.id, + }, }, }); @@ -2865,6 +3003,11 @@ describe('AccountsController', () => { }, selectedAccount: lastSelectedAccount.id, }, + accountIdByAddress: { + [mockOlderEvmAccount.address]: mockOlderEvmAccount.id, + [mockNewerEvmAccount.address]: mockNewerEvmAccount.id, + [mockBtcAccount.address]: mockBtcAccount.id, + }, }, }); @@ -2881,6 +3024,9 @@ describe('AccountsController', () => { }, selectedAccount: mockBtcAccount.id, }, + accountIdByAddress: { + [mockBtcAccount.address]: mockBtcAccount.id, + }, }, }); @@ -2896,6 +3042,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, }); @@ -2940,6 +3087,11 @@ describe('AccountsController', () => { }, selectedAccount: selectedAccount.id, }, + accountIdByAddress: { + [mockOlderEvmAccount.address]: mockOlderEvmAccount.id, + [mockNewerEvmAccount.address]: mockNewerEvmAccount.id, + [mockBtcAccount.address]: mockBtcAccount.id, + }, }, }); @@ -2965,6 +3117,11 @@ describe('AccountsController', () => { }, selectedAccount: mockBtcAccount.id, }, + accountIdByAddress: { + [mockOlderEvmAccount.address]: mockOlderEvmAccount.id, + [mockNewerEvmAccount.address]: mockNewerEvmAccount.id, + [mockBtcAccount.address]: mockBtcAccount.id, + }, }, }); @@ -2983,6 +3140,7 @@ describe('AccountsController', () => { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }, }); @@ -3011,6 +3169,11 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + [mockNonEvmAccount.address]: mockNonEvmAccount.id, + }, }, }); @@ -3107,6 +3270,15 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + [mockErc4337MainnetAccount.address]: mockErc4337MainnetAccount.id, + [mockErc4337TestnetAccount.address]: mockErc4337TestnetAccount.id, + [mockBtcMainnetAccount.address]: mockBtcMainnetAccount.id, + [mockBtcMainnetAccount2.address]: mockBtcMainnetAccount2.id, + [mockBtcTestnetAccount.address]: mockBtcTestnetAccount.id, + }, }, }); expect( @@ -3124,6 +3296,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, }); @@ -3144,6 +3320,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); const result = accountsController.getAccountExpect(mockAccount.id); @@ -3159,6 +3338,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -3179,6 +3361,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, }); @@ -3212,6 +3398,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockNonEvmAccount.address]: mockNonEvmAccount.id, + }, }, }); @@ -3245,6 +3435,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }; @@ -3274,6 +3467,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, }); @@ -3334,6 +3531,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); accountsController.setAccountName(mockAccount.id, 'new name'); @@ -3354,6 +3554,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -3373,6 +3576,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -3404,6 +3610,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccountWithName.address]: mockAccountWithName.id, + }, }, }); @@ -3421,6 +3631,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); accountsController.updateAccountMetadata(mockAccount.id, { @@ -3499,6 +3712,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3538,6 +3754,9 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3586,6 +3805,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -3603,6 +3825,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, }); @@ -3628,6 +3853,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockNonEvmAccount.address]: mockNonEvmAccount.id, + }, }, }); @@ -3664,6 +3893,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3694,6 +3926,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockNonEvmAccount.address]: mockNonEvmAccount.id, + }, }, messenger, }); @@ -3723,6 +3959,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockNonEvmAccount.address]: mockNonEvmAccount.id, + }, }, messenger, }); @@ -3746,6 +3986,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3774,6 +4017,10 @@ describe('AccountsController', () => { }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + [mockAccount2.address]: mockAccount2.id, + }, }, messenger, }); @@ -3811,6 +4058,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3830,6 +4080,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3855,6 +4108,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3875,6 +4131,9 @@ describe('AccountsController', () => { accounts: { [mockAccount.id]: mockAccount }, selectedAccount: mockAccount.id, }, + accountIdByAddress: { + [mockAccount.address]: mockAccount.id, + }, }, messenger, }); @@ -3953,6 +4212,7 @@ describe('AccountsController', () => { ), ).toMatchInlineSnapshot(` { + "accountIdByAddress": {}, "internalAccounts": { "accounts": {}, "selectedAccount": "", diff --git a/packages/accounts-controller/src/AccountsController.ts b/packages/accounts-controller/src/AccountsController.ts index 58aace7d3fd..d87e0d6525a 100644 --- a/packages/accounts-controller/src/AccountsController.ts +++ b/packages/accounts-controller/src/AccountsController.ts @@ -42,6 +42,7 @@ import type { MultichainNetworkControllerNetworkDidChangeEvent } from './types'; import type { AccountsControllerStrictState } from './typing'; import type { HdSnapKeyringAccount } from './utils'; import { + constructAccountIdByAddress, getEvmDerivationPathForIndex, getEvmGroupIndexFromAddressIndex, getUUIDFromAddressOfNormalAccount, @@ -60,6 +61,7 @@ export type AccountsControllerState = { accounts: Record; selectedAccount: string; // id of the selected account }; + accountIdByAddress: Record; }; export type AccountsControllerGetStateAction = ControllerGetStateAction< @@ -223,6 +225,12 @@ const accountsControllerMetadata = { includeInDebugSnapshot: false, usedInUi: true, }, + accountIdByAddress: { + includeInStateLogs: false, + persist: false, + includeInDebugSnapshot: false, + usedInUi: true, + }, }; const defaultState: AccountsControllerState = { @@ -230,6 +238,7 @@ const defaultState: AccountsControllerState = { accounts: {}, selectedAccount: '', }, + accountIdByAddress: {}, }; export const EMPTY_ACCOUNT = { @@ -288,6 +297,9 @@ export class AccountsController extends BaseController< messenger: AccountsControllerMessenger; state: AccountsControllerState; }) { + const accountIdByAddress = constructAccountIdByAddress( + state.internalAccounts.accounts, + ); super({ messenger, name: controllerName, @@ -295,6 +307,7 @@ export class AccountsController extends BaseController< state: { ...defaultState, ...state, + accountIdByAddress, }, }); @@ -437,9 +450,8 @@ export class AccountsController extends BaseController< * @returns The account with the specified address, or undefined if not found. */ getAccountByAddress(address: string): InternalAccount | undefined { - return this.listMultichainAccounts().find( - (account) => account.address.toLowerCase() === address.toLowerCase(), - ); + const accountId = this.state.accountIdByAddress[address.toLowerCase()]; + return accountId ? this.getAccount(accountId) : undefined; } /** @@ -571,6 +583,8 @@ export class AccountsController extends BaseController< const existingInternalAccounts = this.state.internalAccounts.accounts; const internalAccounts: AccountsControllerState['internalAccounts']['accounts'] = {}; + const accountIdByAddress: AccountsControllerState['accountIdByAddress'] = + {}; const { keyrings } = this.messenger.call('KeyringController:getState'); for (const keyring of keyrings) { @@ -610,6 +624,10 @@ export class AccountsController extends BaseController< }, }; + // FIXME: We should not lowercase all addresses since some accounts addresses might be case-sensitive + accountIdByAddress[internalAccount.address.toLowerCase()] = + internalAccount.id; + // Increment the account index for this keyring. keyringAccountIndexes.set(keyringTypeName, keyringAccountIndex + 1); } @@ -617,6 +635,7 @@ export class AccountsController extends BaseController< this.#update((state) => { state.internalAccounts.accounts = internalAccounts; + state.accountIdByAddress = accountIdByAddress; }); } @@ -627,9 +646,13 @@ export class AccountsController extends BaseController< */ loadBackup(backup: AccountsControllerState): void { if (backup.internalAccounts) { + const accountIdByAddress = constructAccountIdByAddress( + backup.internalAccounts.accounts, + ); this.update( (currentState: WritableDraft) => { currentState.internalAccounts = backup.internalAccounts; + currentState.accountIdByAddress = accountIdByAddress; }, ); } @@ -852,11 +875,13 @@ export class AccountsController extends BaseController< this.#update( (state) => { - const { internalAccounts } = state; + const { internalAccounts, accountIdByAddress } = state; for (const patch of [patches.snap, patches.normal]) { for (const account of patch.removed) { delete internalAccounts.accounts[account.id]; + // FIXME: We should not lowercase all addresses since some accounts addresses might be case-sensitive + delete accountIdByAddress[account.address.toLowerCase()]; diff.removed.push(account.id); } @@ -885,6 +910,9 @@ export class AccountsController extends BaseController< }, }; + // FIXME: We should not lowercase all addresses since some accounts addresses might be case-sensitive + accountIdByAddress[account.address.toLowerCase()] = account.id; + diff.added.push(internalAccounts.accounts[account.id]); } } diff --git a/packages/accounts-controller/src/typing.ts b/packages/accounts-controller/src/typing.ts index 1160df39ab3..81d038ac998 100644 --- a/packages/accounts-controller/src/typing.ts +++ b/packages/accounts-controller/src/typing.ts @@ -32,4 +32,5 @@ export type AccountsControllerStrictState = IsAccountControllerState<{ accounts: Record; selectedAccount: InternalAccount['id']; }; + accountIdByAddress: Record; }>; diff --git a/packages/accounts-controller/src/utils.test.ts b/packages/accounts-controller/src/utils.test.ts index b118cc4836a..b006848c155 100644 --- a/packages/accounts-controller/src/utils.test.ts +++ b/packages/accounts-controller/src/utils.test.ts @@ -2,7 +2,9 @@ import { toChecksumAddress } from '@ethereumjs/util'; import type { KeyringObject } from '@metamask/keyring-controller'; import { KeyringTypes } from '@metamask/keyring-controller'; +import { createMockInternalAccount } from './tests/mocks'; import { + constructAccountIdByAddress, getEvmGroupIndexFromAddressIndex, isNormalKeyringType, isSimpleKeyringType, @@ -132,4 +134,21 @@ describe('utils', () => { ); }); }); + + describe('constructAccountIdByAddress', () => { + it('returns the account id by address for a map of accounts', () => { + const accounts = createMockInternalAccount({ + id: '1', + address: '0x123abc', + }); + + const accountIdByAddress = constructAccountIdByAddress({ + [accounts.id]: accounts, + }); + + expect(accountIdByAddress).toStrictEqual({ + '0x123abc': accounts.id, + }); + }); + }); }); diff --git a/packages/accounts-controller/src/utils.ts b/packages/accounts-controller/src/utils.ts index e2bbcc93fbd..3b964bb7af7 100644 --- a/packages/accounts-controller/src/utils.ts +++ b/packages/accounts-controller/src/utils.ts @@ -8,6 +8,8 @@ import { sha256 } from 'ethereum-cryptography/sha256'; import type { V4Options } from 'uuid'; import { v4 as uuid } from 'uuid'; +import { AccountId } from './AccountsController'; + /** * Returns the name of the keyring type. * @@ -206,3 +208,13 @@ export function isHdSnapKeyringAccount( ): account is HdSnapKeyringAccount { return is(account.options, HdSnapKeyringAccountOptionsStruct); } + +export function constructAccountIdByAddress( + accountsMap: Record, +): Record { + const accounts = Object.values(accountsMap); + return accounts.reduce>((acc, account) => { + acc[account.address.toLowerCase()] = account.id; + return acc; + }, {}); +} diff --git a/packages/assets-controllers/src/selectors/token-selectors.test.ts b/packages/assets-controllers/src/selectors/token-selectors.test.ts index 6b3126d8c08..73be7e610e1 100644 --- a/packages/assets-controllers/src/selectors/token-selectors.test.ts +++ b/packages/assets-controllers/src/selectors/token-selectors.test.ts @@ -467,6 +467,16 @@ const mockAccountControllerState: AccountsControllerState = { }, selectedAccount: 'd7f11451-9d79-4df4-a012-afd253443639', }, + accountIdByAddress: { + '0x2bd63233fe369b0f13eaf25292af5a9b63d2b7ab': + 'd7f11451-9d79-4df4-a012-afd253443639', + '0x0413078b85a6cb85f8f75181ad1a23d265d49202': + '2c311cc8-eeeb-48c7-a629-bb1d9c146b47', + '4ktpypssbugxhe67nc9jurqwfcbnkdqto4k8rzmyaps7': + '2d89e6a0-b4e6-45a8-a707-f10cef143b42', + '7xrst6xecmjwtvrdfgch6jfvaisnokb8ldwcvimugbjc': + '40fe5e20-525a-4434-bb83-c51ce5560a8c', + }, }; const mockMultichainBalancesControllerState = { diff --git a/packages/profile-metrics-controller/src/ProfileMetricsController.test.ts b/packages/profile-metrics-controller/src/ProfileMetricsController.test.ts index b6890783e76..681314ddd3f 100644 --- a/packages/profile-metrics-controller/src/ProfileMetricsController.test.ts +++ b/packages/profile-metrics-controller/src/ProfileMetricsController.test.ts @@ -106,6 +106,10 @@ describe('ProfileMetricsController', () => { }, selectedAccount: account1.id, }, + accountIdByAddress: { + [account1.address]: account1.id, + [account2.address]: account2.id, + }, }; }, ); @@ -152,6 +156,10 @@ describe('ProfileMetricsController', () => { }, selectedAccount: account1.id, }, + accountIdByAddress: { + [account1.address]: account1.id, + [account2.address]: account2.id, + }, }; }, );