@metamask/assets-controllers 74.0.0 → 74.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -1
- package/dist/AccountTrackerController.cjs +222 -84
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts +7 -1
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts +7 -1
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +224 -85
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/TokenBalancesController.cjs +17 -14
- package/dist/TokenBalancesController.cjs.map +1 -1
- package/dist/TokenBalancesController.d.cts.map +1 -1
- package/dist/TokenBalancesController.d.mts.map +1 -1
- package/dist/TokenBalancesController.mjs +18 -15
- package/dist/TokenBalancesController.mjs.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.cjs +31 -9
- package/dist/rpc-service/rpc-balance-fetcher.cjs.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.cts.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.mts.map +1 -1
- package/dist/rpc-service/rpc-balance-fetcher.mjs +32 -10
- package/dist/rpc-service/rpc-balance-fetcher.mjs.map +1 -1
- package/dist/selectors/token-selectors.cjs +24 -9
- package/dist/selectors/token-selectors.cjs.map +1 -1
- package/dist/selectors/token-selectors.d.cts +96 -20
- package/dist/selectors/token-selectors.d.cts.map +1 -1
- package/dist/selectors/token-selectors.d.mts +96 -20
- package/dist/selectors/token-selectors.d.mts.map +1 -1
- package/dist/selectors/token-selectors.mjs +24 -9
- package/dist/selectors/token-selectors.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Web3Provider } from '@ethersproject/providers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClient } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport { getTokenBalancesForMultipleAddresses } from '../multicall';\nimport type { TokensControllerState } from '../TokensController';\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<ProcessedBalance[]>;\n};\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nexport class RpcBalanceFetcher implements BalanceFetcher {\n readonly #getProvider: (chainId: ChainIdHex) => Web3Provider;\n\n readonly #getNetworkClient: (chainId: ChainIdHex) => NetworkClient;\n\n readonly #getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n };\n\n constructor(\n getProvider: (chainId: ChainIdHex) => Web3Provider,\n getNetworkClient: (chainId: ChainIdHex) => NetworkClient,\n getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n },\n ) {\n this.#getProvider = getProvider;\n this.#getNetworkClient = getNetworkClient;\n this.#getTokensState = getTokensState;\n }\n\n supports(): boolean {\n return true; // fallback – supports every chain\n }\n\n #getStakingContractAddress(chainId: ChainIdHex): string | undefined {\n return STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainId as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const results: ProcessedBalance[] = [];\n\n for (const chainId of chainIds) {\n const tokensState = this.#getTokensState();\n const accountTokenGroups = buildAccountTokenGroupsStatic(\n chainId,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n tokensState.allTokens,\n tokensState.allDetectedTokens,\n );\n if (!accountTokenGroups.length) {\n continue;\n }\n\n const provider = this.#getProvider(chainId);\n await this.#ensureFreshBlockData(chainId);\n\n const { tokenBalances, stakedBalances } =\n await getTokenBalancesForMultipleAddresses(\n accountTokenGroups,\n chainId,\n provider,\n true, // include native\n true, // include staked\n );\n\n // Add native token entries for all addresses being processed\n const allAddressesForNative = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddressesForNative.add(group.accountAddress);\n });\n\n // Ensure native token entries exist for all addresses\n allAddressesForNative.forEach((address) => {\n const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;\n results.push({\n success: true,\n value: nativeBalance ? (nativeBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n });\n\n // Add other token balances\n Object.entries(tokenBalances).forEach(([tokenAddr, balances]) => {\n // Skip native token since we handled it explicitly above\n if (tokenAddr === ZERO_ADDRESS) {\n return;\n }\n Object.entries(balances).forEach(([acct, bn]) => {\n results.push({\n success: bn !== null,\n value: bn as BN,\n account: acct as ChecksumAddress,\n token: checksum(tokenAddr),\n chainId,\n });\n });\n });\n\n // Add staked balances for all addresses being processed\n const stakingContractAddress = this.#getStakingContractAddress(chainId);\n if (stakingContractAddress) {\n // Get all unique addresses being processed for this chain\n const allAddresses = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddresses.add(group.accountAddress);\n });\n\n // Add staked balance entry for each address\n const checksummedStakingAddress = checksum(stakingContractAddress);\n allAddresses.forEach((address) => {\n const stakedBalance = stakedBalances?.[address] || null;\n results.push({\n success: true,\n value: stakedBalance ? (stakedBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: checksummedStakingAddress,\n chainId,\n });\n });\n }\n }\n\n return results;\n }\n\n /**\n * Ensures that the block tracker has the latest block data before performing multicall operations.\n * This is a temporary fix to ensure that the block number is up to date.\n *\n * @param chainId - The chain id to update block data for.\n */\n async #ensureFreshBlockData(chainId: Hex): Promise<void> {\n // Force fresh block data before multicall\n // TODO: This is a temporary fix to ensure that the block number is up to date.\n // We should remove this once we have a better solution for this on the block tracker controller.\n const networkClient = this.#getNetworkClient(chainId);\n await networkClient.blockTracker?.checkForLatestBlock?.();\n }\n}\n\n/**\n * Merges imported & detected tokens for the requested chain and returns a list\n * of `{ accountAddress, tokenAddresses[] }` suitable for getTokenBalancesForMultipleAddresses.\n *\n * @param chainId - The chain ID to build account token groups for\n * @param queryAllAccounts - Whether to query all accounts or just the selected one\n * @param selectedAccount - The currently selected account\n * @param allAccounts - All available accounts\n * @param allTokens - All tokens from TokensController\n * @param allDetectedTokens - All detected tokens from TokensController\n * @returns Array of account/token groups for multicall\n */\nfunction buildAccountTokenGroupsStatic(\n chainId: ChainIdHex,\n queryAllAccounts: boolean,\n selectedAccount: ChecksumAddress,\n allAccounts: InternalAccount[],\n allTokens: TokensControllerState['allTokens'],\n allDetectedTokens: TokensControllerState['allDetectedTokens'],\n): { accountAddress: ChecksumAddress; tokenAddresses: ChecksumAddress[] }[] {\n const pairs: {\n accountAddress: ChecksumAddress;\n tokenAddress: ChecksumAddress;\n }[] = [];\n\n const add = ([account, tokens]: [string, unknown[]]) => {\n const shouldInclude =\n queryAllAccounts || checksum(account) === checksum(selectedAccount);\n if (!shouldInclude) {\n return;\n }\n (tokens as unknown[]).forEach((t: unknown) =>\n pairs.push({\n accountAddress: account as ChecksumAddress,\n tokenAddress: checksum((t as { address: string }).address),\n }),\n );\n };\n\n Object.entries(allTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n Object.entries(allDetectedTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n\n // Always include native token for relevant accounts\n if (queryAllAccounts) {\n allAccounts.forEach((a) => {\n pairs.push({\n accountAddress: a.address as ChecksumAddress,\n tokenAddress: ZERO_ADDRESS,\n });\n });\n } else {\n pairs.push({\n accountAddress: selectedAccount,\n tokenAddress: ZERO_ADDRESS,\n });\n }\n\n if (!pairs.length) {\n return [];\n }\n\n // group by account\n const map = new Map<ChecksumAddress, ChecksumAddress[]>();\n pairs.forEach(({ accountAddress, tokenAddress }) => {\n if (!map.has(accountAddress)) {\n map.set(accountAddress, []);\n }\n const tokens = map.get(accountAddress);\n if (tokens) {\n tokens.push(tokenAddress);\n }\n });\n\n return Array.from(map.entries()).map(([accountAddress, tokenAddresses]) => ({\n accountAddress,\n tokenAddresses,\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rpc-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Web3Provider } from '@ethersproject/providers';\nimport {\n toChecksumHexAddress,\n safelyExecuteWithTimeout,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClient } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport { getTokenBalancesForMultipleAddresses } from '../multicall';\nimport type { TokensControllerState } from '../TokensController';\n\nconst RPC_TIMEOUT_MS = 30000;\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<ProcessedBalance[]>;\n};\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nexport class RpcBalanceFetcher implements BalanceFetcher {\n readonly #getProvider: (chainId: ChainIdHex) => Web3Provider;\n\n readonly #getNetworkClient: (chainId: ChainIdHex) => NetworkClient;\n\n readonly #getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n };\n\n constructor(\n getProvider: (chainId: ChainIdHex) => Web3Provider,\n getNetworkClient: (chainId: ChainIdHex) => NetworkClient,\n getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n },\n ) {\n this.#getProvider = getProvider;\n this.#getNetworkClient = getNetworkClient;\n this.#getTokensState = getTokensState;\n }\n\n supports(): boolean {\n return true; // fallback – supports every chain\n }\n\n #getStakingContractAddress(chainId: ChainIdHex): string | undefined {\n return STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainId as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n // Process all chains in parallel for better performance\n const chainProcessingPromises = chainIds.map(async (chainId) => {\n const tokensState = this.#getTokensState();\n const accountTokenGroups = buildAccountTokenGroupsStatic(\n chainId,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n tokensState.allTokens,\n tokensState.allDetectedTokens,\n );\n if (!accountTokenGroups.length) {\n return [];\n }\n\n const provider = this.#getProvider(chainId);\n await this.#ensureFreshBlockData(chainId);\n\n const balanceResult = await safelyExecuteWithTimeout(\n async () => {\n return await getTokenBalancesForMultipleAddresses(\n accountTokenGroups,\n chainId,\n provider,\n true, // include native\n true, // include staked\n );\n },\n true,\n RPC_TIMEOUT_MS,\n );\n\n // If timeout or error occurred, return empty array for this chain\n if (!balanceResult) {\n return [];\n }\n\n const { tokenBalances, stakedBalances } = balanceResult;\n const chainResults: ProcessedBalance[] = [];\n\n // Add native token entries for all addresses being processed\n const allAddressesForNative = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddressesForNative.add(group.accountAddress);\n });\n\n // Ensure native token entries exist for all addresses\n allAddressesForNative.forEach((address) => {\n const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;\n chainResults.push({\n success: true,\n value: nativeBalance ? (nativeBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n });\n\n // Add other token balances\n Object.entries(tokenBalances).forEach(([tokenAddr, balances]) => {\n // Skip native token since we handled it explicitly above\n if (tokenAddr === ZERO_ADDRESS) {\n return;\n }\n Object.entries(balances).forEach(([acct, bn]) => {\n chainResults.push({\n success: bn !== null,\n value: bn as BN,\n account: acct as ChecksumAddress,\n token: checksum(tokenAddr),\n chainId,\n });\n });\n });\n\n // Add staked balances for all addresses being processed\n const stakingContractAddress = this.#getStakingContractAddress(chainId);\n if (stakingContractAddress) {\n // Get all unique addresses being processed for this chain\n const allAddresses = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddresses.add(group.accountAddress);\n });\n\n // Add staked balance entry for each address\n const checksummedStakingAddress = checksum(stakingContractAddress);\n allAddresses.forEach((address) => {\n const stakedBalance = stakedBalances?.[address] || null;\n chainResults.push({\n success: true,\n value: stakedBalance ? (stakedBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: checksummedStakingAddress,\n chainId,\n });\n });\n }\n\n return chainResults;\n });\n\n // Wait for all chains to complete (or fail) and collect results\n const chainResultsArray = await Promise.allSettled(chainProcessingPromises);\n const results: ProcessedBalance[] = [];\n\n chainResultsArray.forEach((chainResult) => {\n if (chainResult.status === 'fulfilled') {\n results.push(...chainResult.value);\n } else {\n // Log error but continue with other chains\n console.warn('Chain processing failed:', chainResult.reason);\n }\n });\n\n return results;\n }\n\n /**\n * Ensures that the block tracker has the latest block data before performing multicall operations.\n * This is a temporary fix to ensure that the block number is up to date.\n *\n * @param chainId - The chain id to update block data for.\n */\n async #ensureFreshBlockData(chainId: Hex): Promise<void> {\n // Force fresh block data before multicall\n // TODO: This is a temporary fix to ensure that the block number is up to date.\n // We should remove this once we have a better solution for this on the block tracker controller.\n const networkClient = this.#getNetworkClient(chainId);\n await networkClient.blockTracker?.checkForLatestBlock?.();\n }\n}\n\n/**\n * Merges imported & detected tokens for the requested chain and returns a list\n * of `{ accountAddress, tokenAddresses[] }` suitable for getTokenBalancesForMultipleAddresses.\n *\n * @param chainId - The chain ID to build account token groups for\n * @param queryAllAccounts - Whether to query all accounts or just the selected one\n * @param selectedAccount - The currently selected account\n * @param allAccounts - All available accounts\n * @param allTokens - All tokens from TokensController\n * @param allDetectedTokens - All detected tokens from TokensController\n * @returns Array of account/token groups for multicall\n */\nfunction buildAccountTokenGroupsStatic(\n chainId: ChainIdHex,\n queryAllAccounts: boolean,\n selectedAccount: ChecksumAddress,\n allAccounts: InternalAccount[],\n allTokens: TokensControllerState['allTokens'],\n allDetectedTokens: TokensControllerState['allDetectedTokens'],\n): { accountAddress: ChecksumAddress; tokenAddresses: ChecksumAddress[] }[] {\n const pairs: {\n accountAddress: ChecksumAddress;\n tokenAddress: ChecksumAddress;\n }[] = [];\n\n const add = ([account, tokens]: [string, unknown[]]) => {\n const shouldInclude =\n queryAllAccounts || checksum(account) === checksum(selectedAccount);\n if (!shouldInclude) {\n return;\n }\n (tokens as unknown[]).forEach((t: unknown) =>\n pairs.push({\n accountAddress: account as ChecksumAddress,\n tokenAddress: checksum((t as { address: string }).address),\n }),\n );\n };\n\n Object.entries(allTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n Object.entries(allDetectedTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n\n // Always include native token for relevant accounts\n if (queryAllAccounts) {\n allAccounts.forEach((a) => {\n pairs.push({\n accountAddress: a.address as ChecksumAddress,\n tokenAddress: ZERO_ADDRESS,\n });\n });\n } else {\n pairs.push({\n accountAddress: selectedAccount,\n tokenAddress: ZERO_ADDRESS,\n });\n }\n\n if (!pairs.length) {\n return [];\n }\n\n // group by account\n const map = new Map<ChecksumAddress, ChecksumAddress[]>();\n pairs.forEach(({ accountAddress, tokenAddress }) => {\n if (!map.has(accountAddress)) {\n map.set(accountAddress, []);\n }\n const tokens = map.get(accountAddress);\n if (tokens) {\n tokens.push(tokenAddress);\n }\n });\n\n return Array.from(map.entries()).map(([accountAddress, tokenAddresses]) => ({\n accountAddress,\n tokenAddresses,\n }));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;
|
|
1
|
+
{"version":3,"file":"rpc-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAK7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,qCAAqC;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAC3C,OAAO,EAAE,cAAc;AAIvB,OAAO,KAAK,EAAE,qBAAqB,EAAE,gCAA4B;AAIjE,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;KAChC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;CACjC,CAAC;AAQF,qBAAa,iBAAkB,YAAW,cAAc;;gBAWpD,WAAW,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,EAClD,gBAAgB,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,aAAa,EACxD,cAAc,EAAE,MAAM;QACpB,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAC9C,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;KAC/D;IAOH,QAAQ,IAAI,OAAO;IAUb,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,GACZ,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAmIxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;
|
|
1
|
+
{"version":3,"file":"rpc-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAK7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,qCAAqC;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAC3C,OAAO,EAAE,cAAc;AAIvB,OAAO,KAAK,EAAE,qBAAqB,EAAE,gCAA4B;AAIjE,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;KAChC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;CACjC,CAAC;AAQF,qBAAa,iBAAkB,YAAW,cAAc;;gBAWpD,WAAW,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,EAClD,gBAAgB,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,aAAa,EACxD,cAAc,EAAE,MAAM;QACpB,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAC9C,iBAAiB,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;KAC/D;IAOH,QAAQ,IAAI,OAAO;IAUb,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,GACZ,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAmIxE"}
|
|
@@ -16,11 +16,12 @@ function $importDefault(module) {
|
|
|
16
16
|
}
|
|
17
17
|
return module;
|
|
18
18
|
}
|
|
19
|
-
import { toChecksumHexAddress } from "@metamask/controller-utils";
|
|
19
|
+
import { toChecksumHexAddress, safelyExecuteWithTimeout } from "@metamask/controller-utils";
|
|
20
20
|
import $BN from "bn.js";
|
|
21
21
|
const BN = $importDefault($BN);
|
|
22
22
|
import { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from "../AssetsContractController.mjs";
|
|
23
23
|
import { getTokenBalancesForMultipleAddresses } from "../multicall.mjs";
|
|
24
|
+
const RPC_TIMEOUT_MS = 30000;
|
|
24
25
|
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
25
26
|
const checksum = (addr) => toChecksumHexAddress(addr);
|
|
26
27
|
export class RpcBalanceFetcher {
|
|
@@ -37,17 +38,25 @@ export class RpcBalanceFetcher {
|
|
|
37
38
|
return true; // fallback – supports every chain
|
|
38
39
|
}
|
|
39
40
|
async fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }) {
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
// Process all chains in parallel for better performance
|
|
42
|
+
const chainProcessingPromises = chainIds.map(async (chainId) => {
|
|
42
43
|
const tokensState = __classPrivateFieldGet(this, _RpcBalanceFetcher_getTokensState, "f").call(this);
|
|
43
44
|
const accountTokenGroups = buildAccountTokenGroupsStatic(chainId, queryAllAccounts, selectedAccount, allAccounts, tokensState.allTokens, tokensState.allDetectedTokens);
|
|
44
45
|
if (!accountTokenGroups.length) {
|
|
45
|
-
|
|
46
|
+
return [];
|
|
46
47
|
}
|
|
47
48
|
const provider = __classPrivateFieldGet(this, _RpcBalanceFetcher_getProvider, "f").call(this, chainId);
|
|
48
49
|
await __classPrivateFieldGet(this, _RpcBalanceFetcher_instances, "m", _RpcBalanceFetcher_ensureFreshBlockData).call(this, chainId);
|
|
49
|
-
const
|
|
50
|
-
|
|
50
|
+
const balanceResult = await safelyExecuteWithTimeout(async () => {
|
|
51
|
+
return await getTokenBalancesForMultipleAddresses(accountTokenGroups, chainId, provider, true, // include native
|
|
52
|
+
true);
|
|
53
|
+
}, true, RPC_TIMEOUT_MS);
|
|
54
|
+
// If timeout or error occurred, return empty array for this chain
|
|
55
|
+
if (!balanceResult) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const { tokenBalances, stakedBalances } = balanceResult;
|
|
59
|
+
const chainResults = [];
|
|
51
60
|
// Add native token entries for all addresses being processed
|
|
52
61
|
const allAddressesForNative = new Set();
|
|
53
62
|
accountTokenGroups.forEach((group) => {
|
|
@@ -56,7 +65,7 @@ export class RpcBalanceFetcher {
|
|
|
56
65
|
// Ensure native token entries exist for all addresses
|
|
57
66
|
allAddressesForNative.forEach((address) => {
|
|
58
67
|
const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;
|
|
59
|
-
|
|
68
|
+
chainResults.push({
|
|
60
69
|
success: true,
|
|
61
70
|
value: nativeBalance ? nativeBalance : new BN('0'),
|
|
62
71
|
account: address,
|
|
@@ -71,7 +80,7 @@ export class RpcBalanceFetcher {
|
|
|
71
80
|
return;
|
|
72
81
|
}
|
|
73
82
|
Object.entries(balances).forEach(([acct, bn]) => {
|
|
74
|
-
|
|
83
|
+
chainResults.push({
|
|
75
84
|
success: bn !== null,
|
|
76
85
|
value: bn,
|
|
77
86
|
account: acct,
|
|
@@ -92,7 +101,7 @@ export class RpcBalanceFetcher {
|
|
|
92
101
|
const checksummedStakingAddress = checksum(stakingContractAddress);
|
|
93
102
|
allAddresses.forEach((address) => {
|
|
94
103
|
const stakedBalance = stakedBalances?.[address] || null;
|
|
95
|
-
|
|
104
|
+
chainResults.push({
|
|
96
105
|
success: true,
|
|
97
106
|
value: stakedBalance ? stakedBalance : new BN('0'),
|
|
98
107
|
account: address,
|
|
@@ -101,7 +110,20 @@ export class RpcBalanceFetcher {
|
|
|
101
110
|
});
|
|
102
111
|
});
|
|
103
112
|
}
|
|
104
|
-
|
|
113
|
+
return chainResults;
|
|
114
|
+
});
|
|
115
|
+
// Wait for all chains to complete (or fail) and collect results
|
|
116
|
+
const chainResultsArray = await Promise.allSettled(chainProcessingPromises);
|
|
117
|
+
const results = [];
|
|
118
|
+
chainResultsArray.forEach((chainResult) => {
|
|
119
|
+
if (chainResult.status === 'fulfilled') {
|
|
120
|
+
results.push(...chainResult.value);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Log error but continue with other chains
|
|
124
|
+
console.warn('Chain processing failed:', chainResult.reason);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
105
127
|
return results;
|
|
106
128
|
}
|
|
107
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-balance-fetcher.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AACA,OAAO,EAAE,oBAAoB,EAAE,mCAAmC;AAIlE,OAAO,GAAE,cAAc;;AAEvB,OAAO,EAAE,mCAAmC,EAAE,wCAAoC;AAClF,OAAO,EAAE,oCAAoC,EAAE,yBAAqB;AAwBpE,MAAM,YAAY,GAChB,4CAA+D,CAAC;AAElE,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAmB,EAAE,CACjD,oBAAoB,CAAC,IAAI,CAAoB,CAAC;AAEhD,MAAM,OAAO,iBAAiB;IAU5B,YACE,WAAkD,EAClD,gBAAwD,EACxD,cAGC;;QAfM,iDAAoD;QAEpD,sDAA0D;QAE1D,oDAGP;QAUA,uBAAA,IAAI,kCAAgB,WAAW,MAAA,CAAC;QAChC,uBAAA,IAAI,uCAAqB,gBAAgB,MAAA,CAAC;QAC1C,uBAAA,IAAI,qCAAmB,cAAc,MAAA,CAAC;IACxC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,CAAC,kCAAkC;IACjD,CAAC;IAQD,KAAK,CAAC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,GAC4B;QACvC,MAAM,OAAO,GAAuB,EAAE,CAAC;QAEvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC9B,MAAM,WAAW,GAAG,uBAAA,IAAI,yCAAgB,MAApB,IAAI,CAAkB,CAAC;YAC3C,MAAM,kBAAkB,GAAG,6BAA6B,CACtD,OAAO,EACP,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,WAAW,CAAC,SAAS,EACrB,WAAW,CAAC,iBAAiB,CAC9B,CAAC;YACF,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE;gBAC9B,SAAS;aACV;YAED,MAAM,QAAQ,GAAG,uBAAA,IAAI,sCAAa,MAAjB,IAAI,EAAc,OAAO,CAAC,CAAC;YAC5C,MAAM,uBAAA,IAAI,6EAAsB,MAA1B,IAAI,EAAuB,OAAO,CAAC,CAAC;YAE1C,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,GACrC,MAAM,oCAAoC,CACxC,kBAAkB,EAClB,OAAO,EACP,QAAQ,EACR,IAAI,EAAE,iBAAiB;YACvB,IAAI,CACL,CAAC;YAEJ,6DAA6D;YAC7D,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;YAChD,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACnC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAClD,CAAC,CAAC,CAAC;YAEH,sDAAsD;YACtD,qBAAqB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACxC,MAAM,aAAa,GAAG,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;gBACrE,OAAO,CAAC,IAAI,CAAC;oBACX,OAAO,EAAE,IAAI;oBACb,KAAK,EAAE,aAAa,CAAC,CAAC,CAAE,aAAoB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC;oBAC1D,OAAO,EAAE,OAA0B;oBACnC,KAAK,EAAE,YAAY;oBACnB,OAAO;iBACR,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,2BAA2B;YAC3B,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE;gBAC9D,yDAAyD;gBACzD,IAAI,SAAS,KAAK,YAAY,EAAE;oBAC9B,OAAO;iBACR;gBACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;oBAC9C,OAAO,CAAC,IAAI,CAAC;wBACX,OAAO,EAAE,EAAE,KAAK,IAAI;wBACpB,KAAK,EAAE,EAAQ;wBACf,OAAO,EAAE,IAAuB;wBAChC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC;wBAC1B,OAAO;qBACR,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,wDAAwD;YACxD,MAAM,sBAAsB,GAAG,uBAAA,IAAI,kFAA2B,MAA/B,IAAI,EAA4B,OAAO,CAAC,CAAC;YACxE,IAAI,sBAAsB,EAAE;gBAC1B,0DAA0D;gBAC1D,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;gBACvC,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;oBACnC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;gBACzC,CAAC,CAAC,CAAC;gBAEH,4CAA4C;gBAC5C,MAAM,yBAAyB,GAAG,QAAQ,CAAC,sBAAsB,CAAC,CAAC;gBACnE,YAAY,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;oBAC/B,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;oBACxD,OAAO,CAAC,IAAI,CAAC;wBACX,OAAO,EAAE,IAAI;wBACb,KAAK,EAAE,aAAa,CAAC,CAAC,CAAE,aAAoB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC;wBAC1D,OAAO,EAAE,OAA0B;wBACnC,KAAK,EAAE,yBAAyB;wBAChC,OAAO;qBACR,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;aACJ;SACF;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CAeF;2SAnH4B,OAAmB;IAC5C,OAAO,mCAAmC,CACxC,OAA2D,CAC5D,CAAC;AACJ,CAAC;AAkGD;;;;;GAKG;AACH,KAAK,kDAAuB,OAAY;IACtC,0CAA0C;IAC1C,+EAA+E;IAC/E,iGAAiG;IACjG,MAAM,aAAa,GAAG,uBAAA,IAAI,2CAAkB,MAAtB,IAAI,EAAmB,OAAO,CAAC,CAAC;IACtD,MAAM,aAAa,CAAC,YAAY,EAAE,mBAAmB,EAAE,EAAE,CAAC;AAC5D,CAAC;AAGH;;;;;;;;;;;GAWG;AACH,SAAS,6BAA6B,CACpC,OAAmB,EACnB,gBAAyB,EACzB,eAAgC,EAChC,WAA8B,EAC9B,SAA6C,EAC7C,iBAA6D;IAE7D,MAAM,KAAK,GAGL,EAAE,CAAC;IAET,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAsB,EAAE,EAAE;QACrD,MAAM,aAAa,GACjB,gBAAgB,IAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,eAAe,CAAC,CAAC;QACtE,IAAI,CAAC,aAAa,EAAE;YAClB,OAAO;SACR;QACA,MAAoB,CAAC,OAAO,CAAC,CAAC,CAAU,EAAE,EAAE,CAC3C,KAAK,CAAC,IAAI,CAAC;YACT,cAAc,EAAE,OAA0B;YAC1C,YAAY,EAAE,QAAQ,CAAE,CAAyB,CAAC,OAAO,CAAC;SAC3D,CAAC,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAC9C,GAAyC,CAC1C,CAAC;IACF,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CACtD,GAAyC,CAC1C,CAAC;IAEF,oDAAoD;IACpD,IAAI,gBAAgB,EAAE;QACpB,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACxB,KAAK,CAAC,IAAI,CAAC;gBACT,cAAc,EAAE,CAAC,CAAC,OAA0B;gBAC5C,YAAY,EAAE,YAAY;aAC3B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;KACJ;SAAM;QACL,KAAK,CAAC,IAAI,CAAC;YACT,cAAc,EAAE,eAAe;YAC/B,YAAY,EAAE,YAAY;SAC3B,CAAC,CAAC;KACJ;IAED,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;QACjB,OAAO,EAAE,CAAC;KACX;IAED,mBAAmB;IACnB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsC,CAAC;IAC1D,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,EAAE;QACjD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE;YAC5B,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;SAC7B;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvC,IAAI,MAAM,EAAE;YACV,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;SAC3B;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1E,cAAc;QACd,cAAc;KACf,CAAC,CAAC,CAAC;AACN,CAAC","sourcesContent":["import type { Web3Provider } from '@ethersproject/providers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClient } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport { getTokenBalancesForMultipleAddresses } from '../multicall';\nimport type { TokensControllerState } from '../TokensController';\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<ProcessedBalance[]>;\n};\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nexport class RpcBalanceFetcher implements BalanceFetcher {\n readonly #getProvider: (chainId: ChainIdHex) => Web3Provider;\n\n readonly #getNetworkClient: (chainId: ChainIdHex) => NetworkClient;\n\n readonly #getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n };\n\n constructor(\n getProvider: (chainId: ChainIdHex) => Web3Provider,\n getNetworkClient: (chainId: ChainIdHex) => NetworkClient,\n getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n },\n ) {\n this.#getProvider = getProvider;\n this.#getNetworkClient = getNetworkClient;\n this.#getTokensState = getTokensState;\n }\n\n supports(): boolean {\n return true; // fallback – supports every chain\n }\n\n #getStakingContractAddress(chainId: ChainIdHex): string | undefined {\n return STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainId as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const results: ProcessedBalance[] = [];\n\n for (const chainId of chainIds) {\n const tokensState = this.#getTokensState();\n const accountTokenGroups = buildAccountTokenGroupsStatic(\n chainId,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n tokensState.allTokens,\n tokensState.allDetectedTokens,\n );\n if (!accountTokenGroups.length) {\n continue;\n }\n\n const provider = this.#getProvider(chainId);\n await this.#ensureFreshBlockData(chainId);\n\n const { tokenBalances, stakedBalances } =\n await getTokenBalancesForMultipleAddresses(\n accountTokenGroups,\n chainId,\n provider,\n true, // include native\n true, // include staked\n );\n\n // Add native token entries for all addresses being processed\n const allAddressesForNative = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddressesForNative.add(group.accountAddress);\n });\n\n // Ensure native token entries exist for all addresses\n allAddressesForNative.forEach((address) => {\n const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;\n results.push({\n success: true,\n value: nativeBalance ? (nativeBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n });\n\n // Add other token balances\n Object.entries(tokenBalances).forEach(([tokenAddr, balances]) => {\n // Skip native token since we handled it explicitly above\n if (tokenAddr === ZERO_ADDRESS) {\n return;\n }\n Object.entries(balances).forEach(([acct, bn]) => {\n results.push({\n success: bn !== null,\n value: bn as BN,\n account: acct as ChecksumAddress,\n token: checksum(tokenAddr),\n chainId,\n });\n });\n });\n\n // Add staked balances for all addresses being processed\n const stakingContractAddress = this.#getStakingContractAddress(chainId);\n if (stakingContractAddress) {\n // Get all unique addresses being processed for this chain\n const allAddresses = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddresses.add(group.accountAddress);\n });\n\n // Add staked balance entry for each address\n const checksummedStakingAddress = checksum(stakingContractAddress);\n allAddresses.forEach((address) => {\n const stakedBalance = stakedBalances?.[address] || null;\n results.push({\n success: true,\n value: stakedBalance ? (stakedBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: checksummedStakingAddress,\n chainId,\n });\n });\n }\n }\n\n return results;\n }\n\n /**\n * Ensures that the block tracker has the latest block data before performing multicall operations.\n * This is a temporary fix to ensure that the block number is up to date.\n *\n * @param chainId - The chain id to update block data for.\n */\n async #ensureFreshBlockData(chainId: Hex): Promise<void> {\n // Force fresh block data before multicall\n // TODO: This is a temporary fix to ensure that the block number is up to date.\n // We should remove this once we have a better solution for this on the block tracker controller.\n const networkClient = this.#getNetworkClient(chainId);\n await networkClient.blockTracker?.checkForLatestBlock?.();\n }\n}\n\n/**\n * Merges imported & detected tokens for the requested chain and returns a list\n * of `{ accountAddress, tokenAddresses[] }` suitable for getTokenBalancesForMultipleAddresses.\n *\n * @param chainId - The chain ID to build account token groups for\n * @param queryAllAccounts - Whether to query all accounts or just the selected one\n * @param selectedAccount - The currently selected account\n * @param allAccounts - All available accounts\n * @param allTokens - All tokens from TokensController\n * @param allDetectedTokens - All detected tokens from TokensController\n * @returns Array of account/token groups for multicall\n */\nfunction buildAccountTokenGroupsStatic(\n chainId: ChainIdHex,\n queryAllAccounts: boolean,\n selectedAccount: ChecksumAddress,\n allAccounts: InternalAccount[],\n allTokens: TokensControllerState['allTokens'],\n allDetectedTokens: TokensControllerState['allDetectedTokens'],\n): { accountAddress: ChecksumAddress; tokenAddresses: ChecksumAddress[] }[] {\n const pairs: {\n accountAddress: ChecksumAddress;\n tokenAddress: ChecksumAddress;\n }[] = [];\n\n const add = ([account, tokens]: [string, unknown[]]) => {\n const shouldInclude =\n queryAllAccounts || checksum(account) === checksum(selectedAccount);\n if (!shouldInclude) {\n return;\n }\n (tokens as unknown[]).forEach((t: unknown) =>\n pairs.push({\n accountAddress: account as ChecksumAddress,\n tokenAddress: checksum((t as { address: string }).address),\n }),\n );\n };\n\n Object.entries(allTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n Object.entries(allDetectedTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n\n // Always include native token for relevant accounts\n if (queryAllAccounts) {\n allAccounts.forEach((a) => {\n pairs.push({\n accountAddress: a.address as ChecksumAddress,\n tokenAddress: ZERO_ADDRESS,\n });\n });\n } else {\n pairs.push({\n accountAddress: selectedAccount,\n tokenAddress: ZERO_ADDRESS,\n });\n }\n\n if (!pairs.length) {\n return [];\n }\n\n // group by account\n const map = new Map<ChecksumAddress, ChecksumAddress[]>();\n pairs.forEach(({ accountAddress, tokenAddress }) => {\n if (!map.has(accountAddress)) {\n map.set(accountAddress, []);\n }\n const tokens = map.get(accountAddress);\n if (tokens) {\n tokens.push(tokenAddress);\n }\n });\n\n return Array.from(map.entries()).map(([accountAddress, tokenAddresses]) => ({\n accountAddress,\n tokenAddresses,\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rpc-balance-fetcher.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Web3Provider } from '@ethersproject/providers';\nimport {\n toChecksumHexAddress,\n safelyExecuteWithTimeout,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClient } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport { getTokenBalancesForMultipleAddresses } from '../multicall';\nimport type { TokensControllerState } from '../TokensController';\n\nconst RPC_TIMEOUT_MS = 30000;\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<ProcessedBalance[]>;\n};\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nexport class RpcBalanceFetcher implements BalanceFetcher {\n readonly #getProvider: (chainId: ChainIdHex) => Web3Provider;\n\n readonly #getNetworkClient: (chainId: ChainIdHex) => NetworkClient;\n\n readonly #getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n };\n\n constructor(\n getProvider: (chainId: ChainIdHex) => Web3Provider,\n getNetworkClient: (chainId: ChainIdHex) => NetworkClient,\n getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n },\n ) {\n this.#getProvider = getProvider;\n this.#getNetworkClient = getNetworkClient;\n this.#getTokensState = getTokensState;\n }\n\n supports(): boolean {\n return true; // fallback – supports every chain\n }\n\n #getStakingContractAddress(chainId: ChainIdHex): string | undefined {\n return STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainId as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n // Process all chains in parallel for better performance\n const chainProcessingPromises = chainIds.map(async (chainId) => {\n const tokensState = this.#getTokensState();\n const accountTokenGroups = buildAccountTokenGroupsStatic(\n chainId,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n tokensState.allTokens,\n tokensState.allDetectedTokens,\n );\n if (!accountTokenGroups.length) {\n return [];\n }\n\n const provider = this.#getProvider(chainId);\n await this.#ensureFreshBlockData(chainId);\n\n const balanceResult = await safelyExecuteWithTimeout(\n async () => {\n return await getTokenBalancesForMultipleAddresses(\n accountTokenGroups,\n chainId,\n provider,\n true, // include native\n true, // include staked\n );\n },\n true,\n RPC_TIMEOUT_MS,\n );\n\n // If timeout or error occurred, return empty array for this chain\n if (!balanceResult) {\n return [];\n }\n\n const { tokenBalances, stakedBalances } = balanceResult;\n const chainResults: ProcessedBalance[] = [];\n\n // Add native token entries for all addresses being processed\n const allAddressesForNative = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddressesForNative.add(group.accountAddress);\n });\n\n // Ensure native token entries exist for all addresses\n allAddressesForNative.forEach((address) => {\n const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;\n chainResults.push({\n success: true,\n value: nativeBalance ? (nativeBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n });\n\n // Add other token balances\n Object.entries(tokenBalances).forEach(([tokenAddr, balances]) => {\n // Skip native token since we handled it explicitly above\n if (tokenAddr === ZERO_ADDRESS) {\n return;\n }\n Object.entries(balances).forEach(([acct, bn]) => {\n chainResults.push({\n success: bn !== null,\n value: bn as BN,\n account: acct as ChecksumAddress,\n token: checksum(tokenAddr),\n chainId,\n });\n });\n });\n\n // Add staked balances for all addresses being processed\n const stakingContractAddress = this.#getStakingContractAddress(chainId);\n if (stakingContractAddress) {\n // Get all unique addresses being processed for this chain\n const allAddresses = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddresses.add(group.accountAddress);\n });\n\n // Add staked balance entry for each address\n const checksummedStakingAddress = checksum(stakingContractAddress);\n allAddresses.forEach((address) => {\n const stakedBalance = stakedBalances?.[address] || null;\n chainResults.push({\n success: true,\n value: stakedBalance ? (stakedBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: checksummedStakingAddress,\n chainId,\n });\n });\n }\n\n return chainResults;\n });\n\n // Wait for all chains to complete (or fail) and collect results\n const chainResultsArray = await Promise.allSettled(chainProcessingPromises);\n const results: ProcessedBalance[] = [];\n\n chainResultsArray.forEach((chainResult) => {\n if (chainResult.status === 'fulfilled') {\n results.push(...chainResult.value);\n } else {\n // Log error but continue with other chains\n console.warn('Chain processing failed:', chainResult.reason);\n }\n });\n\n return results;\n }\n\n /**\n * Ensures that the block tracker has the latest block data before performing multicall operations.\n * This is a temporary fix to ensure that the block number is up to date.\n *\n * @param chainId - The chain id to update block data for.\n */\n async #ensureFreshBlockData(chainId: Hex): Promise<void> {\n // Force fresh block data before multicall\n // TODO: This is a temporary fix to ensure that the block number is up to date.\n // We should remove this once we have a better solution for this on the block tracker controller.\n const networkClient = this.#getNetworkClient(chainId);\n await networkClient.blockTracker?.checkForLatestBlock?.();\n }\n}\n\n/**\n * Merges imported & detected tokens for the requested chain and returns a list\n * of `{ accountAddress, tokenAddresses[] }` suitable for getTokenBalancesForMultipleAddresses.\n *\n * @param chainId - The chain ID to build account token groups for\n * @param queryAllAccounts - Whether to query all accounts or just the selected one\n * @param selectedAccount - The currently selected account\n * @param allAccounts - All available accounts\n * @param allTokens - All tokens from TokensController\n * @param allDetectedTokens - All detected tokens from TokensController\n * @returns Array of account/token groups for multicall\n */\nfunction buildAccountTokenGroupsStatic(\n chainId: ChainIdHex,\n queryAllAccounts: boolean,\n selectedAccount: ChecksumAddress,\n allAccounts: InternalAccount[],\n allTokens: TokensControllerState['allTokens'],\n allDetectedTokens: TokensControllerState['allDetectedTokens'],\n): { accountAddress: ChecksumAddress; tokenAddresses: ChecksumAddress[] }[] {\n const pairs: {\n accountAddress: ChecksumAddress;\n tokenAddress: ChecksumAddress;\n }[] = [];\n\n const add = ([account, tokens]: [string, unknown[]]) => {\n const shouldInclude =\n queryAllAccounts || checksum(account) === checksum(selectedAccount);\n if (!shouldInclude) {\n return;\n }\n (tokens as unknown[]).forEach((t: unknown) =>\n pairs.push({\n accountAddress: account as ChecksumAddress,\n tokenAddress: checksum((t as { address: string }).address),\n }),\n );\n };\n\n Object.entries(allTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n Object.entries(allDetectedTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n\n // Always include native token for relevant accounts\n if (queryAllAccounts) {\n allAccounts.forEach((a) => {\n pairs.push({\n accountAddress: a.address as ChecksumAddress,\n tokenAddress: ZERO_ADDRESS,\n });\n });\n } else {\n pairs.push({\n accountAddress: selectedAccount,\n tokenAddress: ZERO_ADDRESS,\n });\n }\n\n if (!pairs.length) {\n return [];\n }\n\n // group by account\n const map = new Map<ChecksumAddress, ChecksumAddress[]>();\n pairs.forEach(({ accountAddress, tokenAddress }) => {\n if (!map.has(accountAddress)) {\n map.set(accountAddress, []);\n }\n const tokens = map.get(accountAddress);\n if (tokens) {\n tokens.push(tokenAddress);\n }\n });\n\n return Array.from(map.entries()).map(([accountAddress, tokenAddresses]) => ({\n accountAddress,\n tokenAddresses,\n }));\n}\n"]}
|
|
@@ -22,7 +22,7 @@ const selectAccountsToGroupIdMap = createAssetListSelector([(state) => state.acc
|
|
|
22
22
|
// TODO: We would not need internalAccounts if evmTokens state had the accountId
|
|
23
23
|
internalAccount.type.startsWith('eip155')
|
|
24
24
|
? internalAccount.address
|
|
25
|
-
: accountId] = accountGroupId;
|
|
25
|
+
: accountId] = { accountGroupId, type: internalAccount.type, accountId };
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -41,7 +41,11 @@ const selectAllEvmAccountNativeBalances = createAssetListSelector([
|
|
|
41
41
|
const groupAssets = {};
|
|
42
42
|
for (const [chainId, chainAccounts] of Object.entries(accountsByChainId)) {
|
|
43
43
|
for (const [accountAddress, accountBalance] of Object.entries(chainAccounts)) {
|
|
44
|
-
const
|
|
44
|
+
const account = accountsMap[accountAddress.toLowerCase()];
|
|
45
|
+
if (!account) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const { accountGroupId, type, accountId } = account;
|
|
45
49
|
groupAssets[accountGroupId] ?? (groupAssets[accountGroupId] = {});
|
|
46
50
|
(_a = groupAssets[accountGroupId])[chainId] ?? (_a[chainId] = []);
|
|
47
51
|
const groupChainAssets = groupAssets[accountGroupId][chainId];
|
|
@@ -57,13 +61,14 @@ const selectAllEvmAccountNativeBalances = createAssetListSelector([
|
|
|
57
61
|
};
|
|
58
62
|
const fiatData = getFiatBalanceForEvmToken(rawBalance, nativeToken.decimals, marketData, currencyRates, chainId, nativeToken.address);
|
|
59
63
|
groupChainAssets.push({
|
|
60
|
-
type:
|
|
64
|
+
type: type,
|
|
61
65
|
assetId: nativeToken.address,
|
|
62
66
|
isNative: true,
|
|
63
67
|
address: nativeToken.address,
|
|
64
68
|
image: nativeToken.image,
|
|
65
69
|
name: nativeToken.name,
|
|
66
70
|
symbol: nativeToken.symbol,
|
|
71
|
+
accountId,
|
|
67
72
|
decimals: nativeToken.decimals,
|
|
68
73
|
balance: (0, stringify_balance_1.stringifyBalanceWithDecimals)((0, utils_1.hexToBigInt)(rawBalance), nativeToken.decimals),
|
|
69
74
|
fiat: fiatData
|
|
@@ -94,7 +99,11 @@ const selectAllEvmAssets = createAssetListSelector([
|
|
|
94
99
|
for (const [accountAddress, addressTokens] of Object.entries(chainTokens)) {
|
|
95
100
|
for (const token of addressTokens) {
|
|
96
101
|
const tokenAddress = token.address;
|
|
97
|
-
const
|
|
102
|
+
const account = accountsMap[accountAddress];
|
|
103
|
+
if (!account) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const { accountGroupId, type, accountId } = account;
|
|
98
107
|
if (ignoredEvmTokens[chainId]?.[accountAddress]?.includes(tokenAddress)) {
|
|
99
108
|
continue;
|
|
100
109
|
}
|
|
@@ -107,13 +116,14 @@ const selectAllEvmAssets = createAssetListSelector([
|
|
|
107
116
|
const groupChainAssets = groupAssets[accountGroupId][chainId];
|
|
108
117
|
const fiatData = getFiatBalanceForEvmToken(rawBalance, token.decimals, marketData, currencyRates, chainId, tokenAddress);
|
|
109
118
|
groupChainAssets.push({
|
|
110
|
-
type:
|
|
119
|
+
type: type,
|
|
111
120
|
assetId: tokenAddress,
|
|
112
121
|
isNative: false,
|
|
113
122
|
address: tokenAddress,
|
|
114
123
|
image: token.image ?? '',
|
|
115
124
|
name: token.name ?? token.symbol,
|
|
116
125
|
symbol: token.symbol,
|
|
126
|
+
accountId,
|
|
117
127
|
decimals: token.decimals,
|
|
118
128
|
balance: (0, stringify_balance_1.stringifyBalanceWithDecimals)((0, utils_1.hexToBigInt)(rawBalance), token.decimals),
|
|
119
129
|
fiat: fiatData
|
|
@@ -152,11 +162,12 @@ const selectAllMultichainAssets = createAssetListSelector([
|
|
|
152
162
|
}
|
|
153
163
|
const { chainId } = caipAsset;
|
|
154
164
|
const asset = `${caipAsset.assetNamespace}:${caipAsset.assetReference}`;
|
|
155
|
-
const
|
|
165
|
+
const account = accountsMap[accountId];
|
|
156
166
|
const assetMetadata = multichainAssetsMetadata[assetId];
|
|
157
|
-
if (!
|
|
167
|
+
if (!account || !assetMetadata) {
|
|
158
168
|
continue;
|
|
159
169
|
}
|
|
170
|
+
const { accountGroupId, type } = account;
|
|
160
171
|
groupAssets[accountGroupId] ?? (groupAssets[accountGroupId] = {});
|
|
161
172
|
(_a = groupAssets[accountGroupId])[chainId] ?? (_a[chainId] = []);
|
|
162
173
|
const groupChainAssets = groupAssets[accountGroupId][chainId];
|
|
@@ -167,12 +178,13 @@ const selectAllMultichainAssets = createAssetListSelector([
|
|
|
167
178
|
const fiatData = getFiatBalanceForMultichainAsset(balance, multichainConversionRates, assetId);
|
|
168
179
|
// TODO: We shouldn't have to rely on fallbacks for name and symbol, they should not be optional
|
|
169
180
|
groupChainAssets.push({
|
|
170
|
-
type:
|
|
181
|
+
type: type,
|
|
171
182
|
assetId,
|
|
172
183
|
isNative: MULTICHAIN_NATIVE_ASSET_IDS.includes(assetId),
|
|
173
184
|
image: assetMetadata.iconUrl,
|
|
174
185
|
name: assetMetadata.name ?? assetMetadata.symbol ?? asset,
|
|
175
186
|
symbol: assetMetadata.symbol ?? asset,
|
|
187
|
+
accountId,
|
|
176
188
|
decimals: assetMetadata.units.find((unit) => unit.name === assetMetadata.name &&
|
|
177
189
|
unit.symbol === assetMetadata.symbol)?.decimals ?? 0,
|
|
178
190
|
balance: balance.amount,
|
|
@@ -218,7 +230,10 @@ function mergeAssets(existingAssets, newAssets) {
|
|
|
218
230
|
for (const [accountGroupId, accountAssets] of Object.entries(newAssets)) {
|
|
219
231
|
const existingAccountGroupAssets = existingAssets[accountGroupId];
|
|
220
232
|
if (!existingAccountGroupAssets) {
|
|
221
|
-
existingAssets[accountGroupId] =
|
|
233
|
+
existingAssets[accountGroupId] = {};
|
|
234
|
+
for (const [network, chainAssets] of Object.entries(accountAssets)) {
|
|
235
|
+
existingAssets[accountGroupId][network] = [...chainAssets];
|
|
236
|
+
}
|
|
222
237
|
}
|
|
223
238
|
else {
|
|
224
239
|
for (const [network, chainAssets] of Object.entries(accountAssets)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-selectors.cjs","sourceRoot":"","sources":["../../src/selectors/token-selectors.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountGroupId } from '@metamask/account-api';\nimport type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport type { AccountsControllerState } from '@metamask/accounts-controller';\nimport { convertHexToDecimal } from '@metamask/controller-utils';\nimport type { NetworkState } from '@metamask/network-controller';\nimport { hexToBigInt, parseCaipAssetType, type Hex } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport { stringifyBalanceWithDecimals } from './stringify-balance';\nimport type { CurrencyRateState } from '../CurrencyRateController';\nimport type { MultichainAssetsControllerState } from '../MultichainAssetsController';\nimport type { MultichainAssetsRatesControllerState } from '../MultichainAssetsRatesController';\nimport type { MultichainBalancesControllerState } from '../MultichainBalancesController';\nimport { getNativeTokenAddress } from '../token-prices-service/codefi-v2';\nimport type { TokenBalancesControllerState } from '../TokenBalancesController';\nimport type { Token, TokenRatesControllerState } from '../TokenRatesController';\nimport type { TokensControllerState } from '../TokensController';\n\ntype AssetsByAccountGroup = {\n [accountGroupId: AccountGroupId]: AccountGroupAssets;\n};\n\nexport type AccountGroupAssets = {\n [network: string]: Asset[];\n};\n\n// If this gets out of hand with other chains, we should probably have a permanent object that defines them\nconst MULTICHAIN_NATIVE_ASSET_IDS = [\n `bip122:000000000019d6689c085ae165831e93/slip44:0`,\n `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501`,\n];\n\nexport type Asset = (\n | {\n type: 'evm';\n assetId: Hex; // This is also the address for EVM tokens\n address: Hex;\n chainId: Hex;\n }\n | {\n type: 'multichain';\n assetId: `${string}:${string}/${string}:${string}`;\n chainId: `${string}:${string}`;\n }\n) & {\n image: string;\n name: string;\n symbol: string;\n decimals: number;\n isNative: boolean;\n balance: string;\n fiat:\n | {\n balance: number;\n currency: string;\n conversionRate: number;\n }\n | undefined;\n};\n\nexport type AssetListState = {\n accountTree: AccountTreeControllerState['accountTree'];\n internalAccounts: AccountsControllerState['internalAccounts'];\n allTokens: TokensControllerState['allTokens'];\n allIgnoredTokens: TokensControllerState['allIgnoredTokens'];\n tokenBalances: TokenBalancesControllerState['tokenBalances'];\n marketData: TokenRatesControllerState['marketData'];\n currencyRates: CurrencyRateState['currencyRates'];\n accountsAssets: MultichainAssetsControllerState['accountsAssets'];\n assetsMetadata: MultichainAssetsControllerState['assetsMetadata'];\n balances: MultichainBalancesControllerState['balances'];\n conversionRates: MultichainAssetsRatesControllerState['conversionRates'];\n currentCurrency: CurrencyRateState['currentCurrency'];\n networkConfigurationsByChainId: NetworkState['networkConfigurationsByChainId'];\n // This is the state from AccountTrackerController. The state is different on mobile and extension\n // accountsByChainId with a balance is the only field that both clients have in common\n // This field could be removed once TokenBalancesController returns native balances\n accountsByChainId: Record<\n Hex,\n Record<\n Hex,\n {\n balance: Hex | null;\n }\n >\n >;\n};\n\nconst createAssetListSelector = createSelector.withTypes<AssetListState>();\n\nconst selectAccountsToGroupIdMap = createAssetListSelector(\n [(state) => state.accountTree, (state) => state.internalAccounts],\n (accountTree, internalAccounts) => {\n const accountsMap: Record<string, AccountGroupId> = {};\n for (const { groups } of Object.values(accountTree.wallets)) {\n for (const { id: accountGroupId, accounts } of Object.values(groups)) {\n for (const accountId of accounts) {\n const internalAccount = internalAccounts.accounts[accountId];\n\n accountsMap[\n // TODO: We would not need internalAccounts if evmTokens state had the accountId\n internalAccount.type.startsWith('eip155')\n ? internalAccount.address\n : accountId\n ] = accountGroupId;\n }\n }\n }\n\n return accountsMap;\n },\n);\n\n// TODO: This selector will not be needed once the native balances are part of the evm tokens state\nconst selectAllEvmAccountNativeBalances = createAssetListSelector(\n [\n selectAccountsToGroupIdMap,\n (state) => state.accountsByChainId,\n (state) => state.marketData,\n (state) => state.currencyRates,\n (state) => state.currentCurrency,\n (state) => state.networkConfigurationsByChainId,\n ],\n (\n accountsMap,\n accountsByChainId,\n marketData,\n currencyRates,\n currentCurrency,\n networkConfigurationsByChainId,\n ) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n for (const [chainId, chainAccounts] of Object.entries(\n accountsByChainId,\n ) as [Hex, Record<Hex, { balance: Hex | null }>][]) {\n for (const [accountAddress, accountBalance] of Object.entries(\n chainAccounts,\n )) {\n const accountGroupId = accountsMap[accountAddress];\n groupAssets[accountGroupId] ??= {};\n groupAssets[accountGroupId][chainId] ??= [];\n const groupChainAssets = groupAssets[accountGroupId][chainId];\n\n const rawBalance = accountBalance.balance || '0x0';\n\n const nativeCurrency =\n networkConfigurationsByChainId[chainId]?.nativeCurrency || 'NATIVE';\n\n const nativeToken = {\n address: getNativeTokenAddress(chainId),\n decimals: 18,\n name: nativeCurrency === 'ETH' ? 'Ethereum' : nativeCurrency,\n symbol: nativeCurrency,\n // This field need to be filled at client level for now\n image: '',\n };\n\n const fiatData = getFiatBalanceForEvmToken(\n rawBalance,\n nativeToken.decimals,\n marketData,\n currencyRates,\n chainId,\n nativeToken.address,\n );\n\n groupChainAssets.push({\n type: 'evm',\n assetId: nativeToken.address,\n isNative: true,\n address: nativeToken.address,\n image: nativeToken.image,\n name: nativeToken.name,\n symbol: nativeToken.symbol,\n decimals: nativeToken.decimals,\n balance: stringifyBalanceWithDecimals(\n hexToBigInt(rawBalance),\n nativeToken.decimals,\n ),\n fiat: fiatData\n ? {\n balance: fiatData.balance,\n currency: currentCurrency,\n conversionRate: fiatData.conversionRate,\n }\n : undefined,\n chainId,\n });\n }\n }\n\n return groupAssets;\n },\n);\n\nconst selectAllEvmAssets = createAssetListSelector(\n [\n selectAccountsToGroupIdMap,\n (state) => state.allTokens,\n (state) => state.allIgnoredTokens,\n (state) => state.tokenBalances,\n (state) => state.marketData,\n (state) => state.currencyRates,\n (state) => state.currentCurrency,\n ],\n (\n accountsMap,\n evmTokens,\n ignoredEvmTokens,\n tokenBalances,\n marketData,\n currencyRates,\n currentCurrency,\n ) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n for (const [chainId, chainTokens] of Object.entries(evmTokens) as [\n Hex,\n { [key: string]: Token[] },\n ][]) {\n for (const [accountAddress, addressTokens] of Object.entries(\n chainTokens,\n ) as [Hex, Token[]][]) {\n for (const token of addressTokens) {\n const tokenAddress = token.address as Hex;\n const accountGroupId = accountsMap[accountAddress];\n\n if (\n ignoredEvmTokens[chainId]?.[accountAddress]?.includes(tokenAddress)\n ) {\n continue;\n }\n\n const rawBalance =\n tokenBalances[accountAddress]?.[chainId]?.[tokenAddress];\n\n if (!rawBalance) {\n continue;\n }\n\n groupAssets[accountGroupId] ??= {};\n groupAssets[accountGroupId][chainId] ??= [];\n const groupChainAssets = groupAssets[accountGroupId][chainId];\n\n const fiatData = getFiatBalanceForEvmToken(\n rawBalance,\n token.decimals,\n marketData,\n currencyRates,\n chainId,\n tokenAddress,\n );\n\n groupChainAssets.push({\n type: 'evm',\n assetId: tokenAddress,\n isNative: false,\n address: tokenAddress,\n image: token.image ?? '',\n name: token.name ?? token.symbol,\n symbol: token.symbol,\n decimals: token.decimals,\n balance: stringifyBalanceWithDecimals(\n hexToBigInt(rawBalance),\n token.decimals,\n ),\n fiat: fiatData\n ? {\n balance: fiatData.balance,\n currency: currentCurrency,\n conversionRate: fiatData.conversionRate,\n }\n : undefined,\n chainId,\n });\n }\n }\n }\n\n return groupAssets;\n },\n);\n\nconst selectAllMultichainAssets = createAssetListSelector(\n [\n selectAccountsToGroupIdMap,\n (state) => state.accountsAssets,\n (state) => state.assetsMetadata,\n (state) => state.balances,\n (state) => state.conversionRates,\n (state) => state.currentCurrency,\n ],\n (\n accountsMap,\n multichainTokens,\n multichainAssetsMetadata,\n multichainBalances,\n multichainConversionRates,\n currentCurrency,\n ) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n for (const [accountId, accountAssets] of Object.entries(multichainTokens)) {\n for (const assetId of accountAssets) {\n let caipAsset: ReturnType<typeof parseCaipAssetType>;\n try {\n caipAsset = parseCaipAssetType(assetId);\n } catch {\n // TODO: We should log this error when we have the ability to inject a logger from the client\n continue;\n }\n\n const { chainId } = caipAsset;\n const asset = `${caipAsset.assetNamespace}:${caipAsset.assetReference}`;\n\n const accountGroupId = accountsMap[accountId];\n const assetMetadata = multichainAssetsMetadata[assetId];\n if (!accountGroupId || !assetMetadata) {\n continue;\n }\n\n groupAssets[accountGroupId] ??= {};\n groupAssets[accountGroupId][chainId] ??= [];\n const groupChainAssets = groupAssets[accountGroupId][chainId];\n\n const balance:\n | {\n amount: string;\n unit: string;\n }\n | undefined = multichainBalances[accountId]?.[assetId];\n\n if (!balance) {\n continue;\n }\n\n const fiatData = getFiatBalanceForMultichainAsset(\n balance,\n multichainConversionRates,\n assetId,\n );\n\n // TODO: We shouldn't have to rely on fallbacks for name and symbol, they should not be optional\n groupChainAssets.push({\n type: 'multichain',\n assetId,\n isNative: MULTICHAIN_NATIVE_ASSET_IDS.includes(assetId),\n image: assetMetadata.iconUrl,\n name: assetMetadata.name ?? assetMetadata.symbol ?? asset,\n symbol: assetMetadata.symbol ?? asset,\n decimals:\n assetMetadata.units.find(\n (unit) =>\n unit.name === assetMetadata.name &&\n unit.symbol === assetMetadata.symbol,\n )?.decimals ?? 0,\n balance: balance.amount,\n fiat: fiatData\n ? {\n balance: fiatData.balance,\n currency: currentCurrency,\n conversionRate: fiatData.conversionRate,\n }\n : undefined,\n chainId,\n });\n }\n }\n\n return groupAssets;\n },\n);\n\nconst selectAllAssets = createAssetListSelector(\n [\n selectAllEvmAssets,\n selectAllMultichainAssets,\n selectAllEvmAccountNativeBalances,\n ],\n (evmAssets, multichainAssets, evmAccountNativeBalances) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n mergeAssets(groupAssets, evmAssets);\n\n mergeAssets(groupAssets, multichainAssets);\n\n mergeAssets(groupAssets, evmAccountNativeBalances);\n\n return groupAssets;\n },\n);\n\nexport const selectAssetsBySelectedAccountGroup = createAssetListSelector(\n [selectAllAssets, (state) => state.accountTree],\n (groupAssets, accountTree) => {\n const { selectedAccountGroup } = accountTree;\n if (!selectedAccountGroup) {\n return {};\n }\n return groupAssets[selectedAccountGroup] || {};\n },\n);\n\n// TODO: Once native assets are part of the evm tokens state, this function can be simplified as chains will always be unique\n/**\n * Merges the new assets into the existing assets\n *\n * @param existingAssets - The existing assets\n * @param newAssets - The new assets\n */\nfunction mergeAssets(\n existingAssets: AssetsByAccountGroup,\n newAssets: AssetsByAccountGroup,\n) {\n for (const [accountGroupId, accountAssets] of Object.entries(newAssets) as [\n AccountGroupId,\n AccountGroupAssets,\n ][]) {\n const existingAccountGroupAssets = existingAssets[accountGroupId];\n\n if (!existingAccountGroupAssets) {\n existingAssets[accountGroupId] = accountAssets;\n } else {\n for (const [network, chainAssets] of Object.entries(accountAssets)) {\n existingAccountGroupAssets[network] ??= [];\n existingAccountGroupAssets[network].push(...chainAssets);\n }\n }\n }\n}\n\n/**\n * @param rawBalance - The balance of the token\n * @param decimals - The decimals of the token\n * @param marketData - The market data for the token\n * @param currencyRates - The currency rates for the token\n * @param chainId - The chain id of the token\n * @param tokenAddress - The address of the token\n * @returns The price and currency of the token in the current currency. Returns undefined if the asset is not found in the market data or currency rates.\n */\nfunction getFiatBalanceForEvmToken(\n rawBalance: Hex,\n decimals: number,\n marketData: TokenRatesControllerState['marketData'],\n currencyRates: CurrencyRateState['currencyRates'],\n chainId: Hex,\n tokenAddress: Hex,\n) {\n const tokenMarketData = marketData[chainId]?.[tokenAddress];\n\n if (!tokenMarketData) {\n return undefined;\n }\n\n const currencyRate = currencyRates[tokenMarketData.currency];\n\n if (!currencyRate?.conversionRate) {\n return undefined;\n }\n\n const fiatBalance =\n (convertHexToDecimal(rawBalance) / 10 ** decimals) *\n tokenMarketData.price *\n currencyRate.conversionRate;\n\n return {\n balance: fiatBalance,\n conversionRate: currencyRate.conversionRate,\n };\n}\n\n/**\n * @param balance - The balance of the asset, in the format { amount: string; unit: string }\n * @param balance.amount - The amount of the balance\n * @param balance.unit - The unit of the balance\n * @param multichainConversionRates - The conversion rates for the multichain asset\n * @param assetId - The asset id of the asset\n * @returns The price and currency of the token in the current currency. Returns undefined if the asset is not found in the conversion rates.\n */\nfunction getFiatBalanceForMultichainAsset(\n balance: { amount: string; unit: string },\n multichainConversionRates: MultichainAssetsRatesControllerState['conversionRates'],\n assetId: `${string}:${string}/${string}:${string}`,\n) {\n const assetMarketData = multichainConversionRates[assetId];\n\n if (!assetMarketData?.rate) {\n return undefined;\n }\n\n return {\n balance: Number(balance.amount) * Number(assetMarketData.rate),\n conversionRate: Number(assetMarketData.rate),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"token-selectors.cjs","sourceRoot":"","sources":["../../src/selectors/token-selectors.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountGroupId } from '@metamask/account-api';\nimport type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport type { AccountsControllerState } from '@metamask/accounts-controller';\nimport { convertHexToDecimal } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkState } from '@metamask/network-controller';\nimport { hexToBigInt, parseCaipAssetType, type Hex } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport { stringifyBalanceWithDecimals } from './stringify-balance';\nimport type { CurrencyRateState } from '../CurrencyRateController';\nimport type { MultichainAssetsControllerState } from '../MultichainAssetsController';\nimport type { MultichainAssetsRatesControllerState } from '../MultichainAssetsRatesController';\nimport type { MultichainBalancesControllerState } from '../MultichainBalancesController';\nimport { getNativeTokenAddress } from '../token-prices-service/codefi-v2';\nimport type { TokenBalancesControllerState } from '../TokenBalancesController';\nimport type { Token, TokenRatesControllerState } from '../TokenRatesController';\nimport type { TokensControllerState } from '../TokensController';\n\ntype AssetsByAccountGroup = {\n [accountGroupId: AccountGroupId]: AccountGroupAssets;\n};\n\nexport type AccountGroupAssets = {\n [network: string]: Asset[];\n};\n\n// If this gets out of hand with other chains, we should probably have a permanent object that defines them\nconst MULTICHAIN_NATIVE_ASSET_IDS = [\n `bip122:000000000019d6689c085ae165831e93/slip44:0`,\n `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501`,\n];\n\ntype EvmAccountType = Extract<InternalAccount['type'], `eip155:${string}`>;\ntype MultichainAccountType = Exclude<\n InternalAccount['type'],\n `eip155:${string}`\n>;\n\nexport type Asset = (\n | {\n type: EvmAccountType;\n assetId: Hex; // This is also the address for EVM tokens\n address: Hex;\n chainId: Hex;\n }\n | {\n type: MultichainAccountType;\n assetId: `${string}:${string}/${string}:${string}`;\n chainId: `${string}:${string}`;\n }\n) & {\n accountId: string;\n image: string;\n name: string;\n symbol: string;\n decimals: number;\n isNative: boolean;\n balance: string;\n fiat:\n | {\n balance: number;\n currency: string;\n conversionRate: number;\n }\n | undefined;\n};\n\nexport type AssetListState = {\n accountTree: AccountTreeControllerState['accountTree'];\n internalAccounts: AccountsControllerState['internalAccounts'];\n allTokens: TokensControllerState['allTokens'];\n allIgnoredTokens: TokensControllerState['allIgnoredTokens'];\n tokenBalances: TokenBalancesControllerState['tokenBalances'];\n marketData: TokenRatesControllerState['marketData'];\n currencyRates: CurrencyRateState['currencyRates'];\n accountsAssets: MultichainAssetsControllerState['accountsAssets'];\n assetsMetadata: MultichainAssetsControllerState['assetsMetadata'];\n balances: MultichainBalancesControllerState['balances'];\n conversionRates: MultichainAssetsRatesControllerState['conversionRates'];\n currentCurrency: CurrencyRateState['currentCurrency'];\n networkConfigurationsByChainId: NetworkState['networkConfigurationsByChainId'];\n // This is the state from AccountTrackerController. The state is different on mobile and extension\n // accountsByChainId with a balance is the only field that both clients have in common\n // This field could be removed once TokenBalancesController returns native balances\n accountsByChainId: Record<\n Hex,\n Record<\n Hex,\n {\n balance: Hex | null;\n }\n >\n >;\n};\n\nconst createAssetListSelector = createSelector.withTypes<AssetListState>();\n\nconst selectAccountsToGroupIdMap = createAssetListSelector(\n [(state) => state.accountTree, (state) => state.internalAccounts],\n (accountTree, internalAccounts) => {\n const accountsMap: Record<\n string,\n {\n accountGroupId: AccountGroupId;\n type: InternalAccount['type'];\n accountId: string;\n }\n > = {};\n for (const { groups } of Object.values(accountTree.wallets)) {\n for (const { id: accountGroupId, accounts } of Object.values(groups)) {\n for (const accountId of accounts) {\n const internalAccount = internalAccounts.accounts[accountId];\n\n accountsMap[\n // TODO: We would not need internalAccounts if evmTokens state had the accountId\n internalAccount.type.startsWith('eip155')\n ? internalAccount.address\n : accountId\n ] = { accountGroupId, type: internalAccount.type, accountId };\n }\n }\n }\n\n return accountsMap;\n },\n);\n\n// TODO: This selector will not be needed once the native balances are part of the evm tokens state\nconst selectAllEvmAccountNativeBalances = createAssetListSelector(\n [\n selectAccountsToGroupIdMap,\n (state) => state.accountsByChainId,\n (state) => state.marketData,\n (state) => state.currencyRates,\n (state) => state.currentCurrency,\n (state) => state.networkConfigurationsByChainId,\n ],\n (\n accountsMap,\n accountsByChainId,\n marketData,\n currencyRates,\n currentCurrency,\n networkConfigurationsByChainId,\n ) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n for (const [chainId, chainAccounts] of Object.entries(\n accountsByChainId,\n ) as [Hex, Record<Hex, { balance: Hex | null }>][]) {\n for (const [accountAddress, accountBalance] of Object.entries(\n chainAccounts,\n )) {\n const account = accountsMap[accountAddress.toLowerCase()];\n if (!account) {\n continue;\n }\n\n const { accountGroupId, type, accountId } = account;\n\n groupAssets[accountGroupId] ??= {};\n groupAssets[accountGroupId][chainId] ??= [];\n const groupChainAssets = groupAssets[accountGroupId][chainId];\n\n const rawBalance = accountBalance.balance || '0x0';\n\n const nativeCurrency =\n networkConfigurationsByChainId[chainId]?.nativeCurrency || 'NATIVE';\n\n const nativeToken = {\n address: getNativeTokenAddress(chainId),\n decimals: 18,\n name: nativeCurrency === 'ETH' ? 'Ethereum' : nativeCurrency,\n symbol: nativeCurrency,\n // This field need to be filled at client level for now\n image: '',\n };\n\n const fiatData = getFiatBalanceForEvmToken(\n rawBalance,\n nativeToken.decimals,\n marketData,\n currencyRates,\n chainId,\n nativeToken.address,\n );\n\n groupChainAssets.push({\n type: type as EvmAccountType,\n assetId: nativeToken.address,\n isNative: true,\n address: nativeToken.address,\n image: nativeToken.image,\n name: nativeToken.name,\n symbol: nativeToken.symbol,\n accountId,\n decimals: nativeToken.decimals,\n balance: stringifyBalanceWithDecimals(\n hexToBigInt(rawBalance),\n nativeToken.decimals,\n ),\n fiat: fiatData\n ? {\n balance: fiatData.balance,\n currency: currentCurrency,\n conversionRate: fiatData.conversionRate,\n }\n : undefined,\n chainId,\n });\n }\n }\n\n return groupAssets;\n },\n);\n\nconst selectAllEvmAssets = createAssetListSelector(\n [\n selectAccountsToGroupIdMap,\n (state) => state.allTokens,\n (state) => state.allIgnoredTokens,\n (state) => state.tokenBalances,\n (state) => state.marketData,\n (state) => state.currencyRates,\n (state) => state.currentCurrency,\n ],\n (\n accountsMap,\n evmTokens,\n ignoredEvmTokens,\n tokenBalances,\n marketData,\n currencyRates,\n currentCurrency,\n ) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n for (const [chainId, chainTokens] of Object.entries(evmTokens) as [\n Hex,\n { [key: string]: Token[] },\n ][]) {\n for (const [accountAddress, addressTokens] of Object.entries(\n chainTokens,\n ) as [Hex, Token[]][]) {\n for (const token of addressTokens) {\n const tokenAddress = token.address as Hex;\n const account = accountsMap[accountAddress];\n if (!account) {\n continue;\n }\n\n const { accountGroupId, type, accountId } = account;\n\n if (\n ignoredEvmTokens[chainId]?.[accountAddress]?.includes(tokenAddress)\n ) {\n continue;\n }\n\n const rawBalance =\n tokenBalances[accountAddress]?.[chainId]?.[tokenAddress];\n\n if (!rawBalance) {\n continue;\n }\n\n groupAssets[accountGroupId] ??= {};\n groupAssets[accountGroupId][chainId] ??= [];\n const groupChainAssets = groupAssets[accountGroupId][chainId];\n\n const fiatData = getFiatBalanceForEvmToken(\n rawBalance,\n token.decimals,\n marketData,\n currencyRates,\n chainId,\n tokenAddress,\n );\n\n groupChainAssets.push({\n type: type as EvmAccountType,\n assetId: tokenAddress,\n isNative: false,\n address: tokenAddress,\n image: token.image ?? '',\n name: token.name ?? token.symbol,\n symbol: token.symbol,\n accountId,\n decimals: token.decimals,\n balance: stringifyBalanceWithDecimals(\n hexToBigInt(rawBalance),\n token.decimals,\n ),\n fiat: fiatData\n ? {\n balance: fiatData.balance,\n currency: currentCurrency,\n conversionRate: fiatData.conversionRate,\n }\n : undefined,\n chainId,\n });\n }\n }\n }\n\n return groupAssets;\n },\n);\n\nconst selectAllMultichainAssets = createAssetListSelector(\n [\n selectAccountsToGroupIdMap,\n (state) => state.accountsAssets,\n (state) => state.assetsMetadata,\n (state) => state.balances,\n (state) => state.conversionRates,\n (state) => state.currentCurrency,\n ],\n (\n accountsMap,\n multichainTokens,\n multichainAssetsMetadata,\n multichainBalances,\n multichainConversionRates,\n currentCurrency,\n ) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n for (const [accountId, accountAssets] of Object.entries(multichainTokens)) {\n for (const assetId of accountAssets) {\n let caipAsset: ReturnType<typeof parseCaipAssetType>;\n try {\n caipAsset = parseCaipAssetType(assetId);\n } catch {\n // TODO: We should log this error when we have the ability to inject a logger from the client\n continue;\n }\n\n const { chainId } = caipAsset;\n const asset = `${caipAsset.assetNamespace}:${caipAsset.assetReference}`;\n\n const account = accountsMap[accountId];\n const assetMetadata = multichainAssetsMetadata[assetId];\n if (!account || !assetMetadata) {\n continue;\n }\n\n const { accountGroupId, type } = account;\n\n groupAssets[accountGroupId] ??= {};\n groupAssets[accountGroupId][chainId] ??= [];\n const groupChainAssets = groupAssets[accountGroupId][chainId];\n\n const balance:\n | {\n amount: string;\n unit: string;\n }\n | undefined = multichainBalances[accountId]?.[assetId];\n\n if (!balance) {\n continue;\n }\n\n const fiatData = getFiatBalanceForMultichainAsset(\n balance,\n multichainConversionRates,\n assetId,\n );\n\n // TODO: We shouldn't have to rely on fallbacks for name and symbol, they should not be optional\n groupChainAssets.push({\n type: type as MultichainAccountType,\n assetId,\n isNative: MULTICHAIN_NATIVE_ASSET_IDS.includes(assetId),\n image: assetMetadata.iconUrl,\n name: assetMetadata.name ?? assetMetadata.symbol ?? asset,\n symbol: assetMetadata.symbol ?? asset,\n accountId,\n decimals:\n assetMetadata.units.find(\n (unit) =>\n unit.name === assetMetadata.name &&\n unit.symbol === assetMetadata.symbol,\n )?.decimals ?? 0,\n balance: balance.amount,\n fiat: fiatData\n ? {\n balance: fiatData.balance,\n currency: currentCurrency,\n conversionRate: fiatData.conversionRate,\n }\n : undefined,\n chainId,\n });\n }\n }\n\n return groupAssets;\n },\n);\n\nconst selectAllAssets = createAssetListSelector(\n [\n selectAllEvmAssets,\n selectAllMultichainAssets,\n selectAllEvmAccountNativeBalances,\n ],\n (evmAssets, multichainAssets, evmAccountNativeBalances) => {\n const groupAssets: AssetsByAccountGroup = {};\n\n mergeAssets(groupAssets, evmAssets);\n\n mergeAssets(groupAssets, multichainAssets);\n\n mergeAssets(groupAssets, evmAccountNativeBalances);\n\n return groupAssets;\n },\n);\n\nexport const selectAssetsBySelectedAccountGroup = createAssetListSelector(\n [selectAllAssets, (state) => state.accountTree],\n (groupAssets, accountTree) => {\n const { selectedAccountGroup } = accountTree;\n if (!selectedAccountGroup) {\n return {};\n }\n return groupAssets[selectedAccountGroup] || {};\n },\n);\n\n// TODO: Once native assets are part of the evm tokens state, this function can be simplified as chains will always be unique\n/**\n * Merges the new assets into the existing assets\n *\n * @param existingAssets - The existing assets\n * @param newAssets - The new assets\n */\nfunction mergeAssets(\n existingAssets: AssetsByAccountGroup,\n newAssets: AssetsByAccountGroup,\n) {\n for (const [accountGroupId, accountAssets] of Object.entries(newAssets) as [\n AccountGroupId,\n AccountGroupAssets,\n ][]) {\n const existingAccountGroupAssets = existingAssets[accountGroupId];\n\n if (!existingAccountGroupAssets) {\n existingAssets[accountGroupId] = {};\n for (const [network, chainAssets] of Object.entries(accountAssets)) {\n existingAssets[accountGroupId][network] = [...chainAssets];\n }\n } else {\n for (const [network, chainAssets] of Object.entries(accountAssets)) {\n existingAccountGroupAssets[network] ??= [];\n existingAccountGroupAssets[network].push(...chainAssets);\n }\n }\n }\n}\n\n/**\n * @param rawBalance - The balance of the token\n * @param decimals - The decimals of the token\n * @param marketData - The market data for the token\n * @param currencyRates - The currency rates for the token\n * @param chainId - The chain id of the token\n * @param tokenAddress - The address of the token\n * @returns The price and currency of the token in the current currency. Returns undefined if the asset is not found in the market data or currency rates.\n */\nfunction getFiatBalanceForEvmToken(\n rawBalance: Hex,\n decimals: number,\n marketData: TokenRatesControllerState['marketData'],\n currencyRates: CurrencyRateState['currencyRates'],\n chainId: Hex,\n tokenAddress: Hex,\n) {\n const tokenMarketData = marketData[chainId]?.[tokenAddress];\n\n if (!tokenMarketData) {\n return undefined;\n }\n\n const currencyRate = currencyRates[tokenMarketData.currency];\n\n if (!currencyRate?.conversionRate) {\n return undefined;\n }\n\n const fiatBalance =\n (convertHexToDecimal(rawBalance) / 10 ** decimals) *\n tokenMarketData.price *\n currencyRate.conversionRate;\n\n return {\n balance: fiatBalance,\n conversionRate: currencyRate.conversionRate,\n };\n}\n\n/**\n * @param balance - The balance of the asset, in the format { amount: string; unit: string }\n * @param balance.amount - The amount of the balance\n * @param balance.unit - The unit of the balance\n * @param multichainConversionRates - The conversion rates for the multichain asset\n * @param assetId - The asset id of the asset\n * @returns The price and currency of the token in the current currency. Returns undefined if the asset is not found in the conversion rates.\n */\nfunction getFiatBalanceForMultichainAsset(\n balance: { amount: string; unit: string },\n multichainConversionRates: MultichainAssetsRatesControllerState['conversionRates'],\n assetId: `${string}:${string}/${string}:${string}`,\n) {\n const assetMarketData = multichainConversionRates[assetId];\n\n if (!assetMarketData?.rate) {\n return undefined;\n }\n\n return {\n balance: Number(balance.amount) * Number(assetMarketData.rate),\n conversionRate: Number(assetMarketData.rate),\n };\n}\n"]}
|