@metamask-previews/assets-controllers 73.2.0-preview-daea9b9c → 73.2.0-preview-d12fc71
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 +5 -0
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +11 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +11 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fix precision loss in AccountsApiBalanceFetcher causing incorrect token balance conversion ([#6330](https://github.com/MetaMask/core/pull/6330))
|
|
13
|
+
- Replaced floating-point arithmetic with string-based precision conversion to avoid JavaScript precision limitations
|
|
14
|
+
|
|
10
15
|
## [73.2.0]
|
|
11
16
|
|
|
12
17
|
### Added
|
|
@@ -81,7 +81,17 @@ class AccountsApiBalanceFetcher {
|
|
|
81
81
|
const chainId = (0, controller_utils_1.toHex)(b.chainId);
|
|
82
82
|
let value;
|
|
83
83
|
try {
|
|
84
|
-
|
|
84
|
+
// Convert string balance to BN avoiding floating point precision issues
|
|
85
|
+
const { balance: balanceStr, decimals } = b;
|
|
86
|
+
// Split the balance string into integer and decimal parts
|
|
87
|
+
const [integerPart = '0', decimalPart = ''] = balanceStr.split('.');
|
|
88
|
+
// Pad or truncate decimal part to match token decimals
|
|
89
|
+
const paddedDecimalPart = decimalPart
|
|
90
|
+
.padEnd(decimals, '0')
|
|
91
|
+
.slice(0, decimals);
|
|
92
|
+
// Combine and create BN
|
|
93
|
+
const fullIntegerStr = integerPart + paddedDecimalPart;
|
|
94
|
+
value = new bn_js_1.default(fullIntegerStr);
|
|
85
95
|
}
|
|
86
96
|
catch {
|
|
87
97
|
value = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BigNumber } from '@ethersproject/bignumber';\nimport { Contract } from '@ethersproject/contracts';\nimport type { Web3Provider } from '@ethersproject/providers';\nimport {\n safelyExecute,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n SupportedStakedBalanceNetworks,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 50;\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 checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n readonly #getProvider?: GetProviderFunction;\n\n constructor(\n platform: 'extension' | 'mobile' = 'extension',\n getProvider?: GetProviderFunction,\n ) {\n this.#platform = platform;\n this.#getProvider = getProvider;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchStakedBalances(\n addrs: CaipAccountAddress[],\n ): Promise<ProcessedBalance[]> {\n // Return empty array if no provider is available for blockchain calls\n if (!this.#getProvider) {\n return [];\n }\n\n const results: ProcessedBalance[] = [];\n\n // Group addresses by chain ID\n const addressesByChain: Record<ChainIdHex, ChecksumAddress[]> = {};\n\n for (const caipAddr of addrs) {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressesByChain[chainId]) {\n addressesByChain[chainId] = [];\n }\n addressesByChain[chainId].push(checksumAddress);\n }\n\n // Process each supported chain\n for (const [chainId, addresses] of Object.entries(addressesByChain)) {\n const chainIdHex = chainId as ChainIdHex;\n\n // Only fetch staked balance on supported networks (mainnet and hoodi)\n if (\n ![\n SupportedStakedBalanceNetworks.mainnet,\n SupportedStakedBalanceNetworks.hoodi,\n ].includes(chainIdHex as SupportedStakedBalanceNetworks)\n ) {\n continue;\n }\n\n // Only fetch staked balance if contract address exists\n if (!(chainIdHex in STAKING_CONTRACT_ADDRESS_BY_CHAINID)) {\n continue;\n }\n\n const contractAddress =\n STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainIdHex as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n const provider = this.#getProvider(chainIdHex);\n\n const abi = [\n {\n inputs: [\n { internalType: 'address', name: 'account', type: 'address' },\n ],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { internalType: 'uint256', name: 'shares', type: 'uint256' },\n ],\n name: 'convertToAssets',\n outputs: [\n { internalType: 'uint256', name: 'assets', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ];\n\n try {\n const contract = new Contract(contractAddress, abi, provider);\n\n // Get shares for each address\n for (const address of addresses) {\n try {\n const shares = await safelyExecute(() =>\n contract.getShares(address),\n );\n\n if (shares && (shares as BigNumber).gt(0)) {\n // Convert shares to assets (actual staked ETH amount)\n const assets = await safelyExecute(() =>\n contract.convertToAssets(shares),\n );\n\n if (assets) {\n results.push({\n success: true,\n value: new BN((assets as BigNumber).toString()),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } else {\n // Return zero balance for accounts with no staked assets\n results.push({\n success: true,\n value: new BN('0'),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } catch (error) {\n // Log error and continue with next address\n console.error(\n `Error fetching staked balance for ${address}:`,\n error,\n );\n results.push({\n success: false,\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n }\n } catch (error) {\n console.error(\n `Error setting up staking contract for chain ${chainId}:`,\n error,\n );\n }\n }\n\n return results;\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[]) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n );\n return balances;\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n );\n return [...(workingResult || []), ...balances];\n },\n initialResult: [],\n });\n\n return allBalances;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return [];\n }\n\n const [balances, stakedBalances] = await Promise.all([\n safelyExecute(() => this.#fetchBalances(caipAddrs)),\n this.#fetchStakedBalances(caipAddrs),\n ]);\n\n const results: ProcessedBalance[] = [];\n\n // Collect all unique addresses and chains from the CAIP addresses\n const addressChainMap = new Map<string, Set<ChainIdHex>>();\n caipAddrs.forEach((caipAddr) => {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressChainMap.has(checksumAddress)) {\n addressChainMap.set(checksumAddress, new Set());\n }\n addressChainMap.get(checksumAddress)?.add(chainId);\n });\n\n // Ensure native token entries exist for all addresses on all requested chains\n const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n const nativeBalancesFromAPI = new Map<string, BN>(); // key: `${address}-${chainId}`\n\n // Process regular API balances\n if (balances) {\n const apiBalances = balances.flatMap((b) => {\n const account = b.accountAddress?.split(':')[2] as ChecksumAddress;\n if (!account) {\n return [];\n }\n const token = checksum(b.address);\n const chainId = toHex(b.chainId) as ChainIdHex;\n\n let value: BN | undefined;\n try {\n value = new BN((parseFloat(b.balance) * 10 ** b.decimals).toFixed(0));\n } catch {\n value = undefined;\n }\n\n // Track native balances for later\n if (token === ZERO_ADDRESS && value !== undefined) {\n nativeBalancesFromAPI.set(`${account}-${chainId}`, value);\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account,\n token,\n chainId,\n },\n ];\n });\n results.push(...apiBalances);\n }\n\n // Ensure native token entries exist for all addresses/chains, even if not returned by API\n addressChainMap.forEach((chains, address) => {\n chains.forEach((chainId) => {\n const key = `${address}-${chainId}`;\n const existingBalance = nativeBalancesFromAPI.get(key);\n\n if (!existingBalance) {\n // Add zero native balance entry if API didn't return one\n results.push({\n success: true,\n value: new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n }\n });\n });\n\n // Add staked balances\n results.push(...stakedBalances);\n\n return results;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"api-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BigNumber } from '@ethersproject/bignumber';\nimport { Contract } from '@ethersproject/contracts';\nimport type { Web3Provider } from '@ethersproject/providers';\nimport {\n safelyExecute,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n SupportedStakedBalanceNetworks,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 50;\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 checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n readonly #getProvider?: GetProviderFunction;\n\n constructor(\n platform: 'extension' | 'mobile' = 'extension',\n getProvider?: GetProviderFunction,\n ) {\n this.#platform = platform;\n this.#getProvider = getProvider;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchStakedBalances(\n addrs: CaipAccountAddress[],\n ): Promise<ProcessedBalance[]> {\n // Return empty array if no provider is available for blockchain calls\n if (!this.#getProvider) {\n return [];\n }\n\n const results: ProcessedBalance[] = [];\n\n // Group addresses by chain ID\n const addressesByChain: Record<ChainIdHex, ChecksumAddress[]> = {};\n\n for (const caipAddr of addrs) {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressesByChain[chainId]) {\n addressesByChain[chainId] = [];\n }\n addressesByChain[chainId].push(checksumAddress);\n }\n\n // Process each supported chain\n for (const [chainId, addresses] of Object.entries(addressesByChain)) {\n const chainIdHex = chainId as ChainIdHex;\n\n // Only fetch staked balance on supported networks (mainnet and hoodi)\n if (\n ![\n SupportedStakedBalanceNetworks.mainnet,\n SupportedStakedBalanceNetworks.hoodi,\n ].includes(chainIdHex as SupportedStakedBalanceNetworks)\n ) {\n continue;\n }\n\n // Only fetch staked balance if contract address exists\n if (!(chainIdHex in STAKING_CONTRACT_ADDRESS_BY_CHAINID)) {\n continue;\n }\n\n const contractAddress =\n STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainIdHex as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n const provider = this.#getProvider(chainIdHex);\n\n const abi = [\n {\n inputs: [\n { internalType: 'address', name: 'account', type: 'address' },\n ],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { internalType: 'uint256', name: 'shares', type: 'uint256' },\n ],\n name: 'convertToAssets',\n outputs: [\n { internalType: 'uint256', name: 'assets', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ];\n\n try {\n const contract = new Contract(contractAddress, abi, provider);\n\n // Get shares for each address\n for (const address of addresses) {\n try {\n const shares = await safelyExecute(() =>\n contract.getShares(address),\n );\n\n if (shares && (shares as BigNumber).gt(0)) {\n // Convert shares to assets (actual staked ETH amount)\n const assets = await safelyExecute(() =>\n contract.convertToAssets(shares),\n );\n\n if (assets) {\n results.push({\n success: true,\n value: new BN((assets as BigNumber).toString()),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } else {\n // Return zero balance for accounts with no staked assets\n results.push({\n success: true,\n value: new BN('0'),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } catch (error) {\n // Log error and continue with next address\n console.error(\n `Error fetching staked balance for ${address}:`,\n error,\n );\n results.push({\n success: false,\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n }\n } catch (error) {\n console.error(\n `Error setting up staking contract for chain ${chainId}:`,\n error,\n );\n }\n }\n\n return results;\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[]) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n );\n return balances;\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n );\n return [...(workingResult || []), ...balances];\n },\n initialResult: [],\n });\n\n return allBalances;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return [];\n }\n\n const [balances, stakedBalances] = await Promise.all([\n safelyExecute(() => this.#fetchBalances(caipAddrs)),\n this.#fetchStakedBalances(caipAddrs),\n ]);\n\n const results: ProcessedBalance[] = [];\n\n // Collect all unique addresses and chains from the CAIP addresses\n const addressChainMap = new Map<string, Set<ChainIdHex>>();\n caipAddrs.forEach((caipAddr) => {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressChainMap.has(checksumAddress)) {\n addressChainMap.set(checksumAddress, new Set());\n }\n addressChainMap.get(checksumAddress)?.add(chainId);\n });\n\n // Ensure native token entries exist for all addresses on all requested chains\n const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n const nativeBalancesFromAPI = new Map<string, BN>(); // key: `${address}-${chainId}`\n\n // Process regular API balances\n if (balances) {\n const apiBalances = balances.flatMap((b) => {\n const account = b.accountAddress?.split(':')[2] as ChecksumAddress;\n if (!account) {\n return [];\n }\n const token = checksum(b.address);\n const chainId = toHex(b.chainId) as ChainIdHex;\n\n let value: BN | undefined;\n try {\n // Convert string balance to BN avoiding floating point precision issues\n const { balance: balanceStr, decimals } = b;\n\n // Split the balance string into integer and decimal parts\n const [integerPart = '0', decimalPart = ''] = balanceStr.split('.');\n\n // Pad or truncate decimal part to match token decimals\n const paddedDecimalPart = decimalPart\n .padEnd(decimals, '0')\n .slice(0, decimals);\n\n // Combine and create BN\n const fullIntegerStr = integerPart + paddedDecimalPart;\n value = new BN(fullIntegerStr);\n } catch {\n value = undefined;\n }\n\n // Track native balances for later\n if (token === ZERO_ADDRESS && value !== undefined) {\n nativeBalancesFromAPI.set(`${account}-${chainId}`, value);\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account,\n token,\n chainId,\n },\n ];\n });\n results.push(...apiBalances);\n }\n\n // Ensure native token entries exist for all addresses/chains, even if not returned by API\n addressChainMap.forEach((chains, address) => {\n chains.forEach((chainId) => {\n const key = `${address}-${chainId}`;\n const existingBalance = nativeBalancesFromAPI.get(key);\n\n if (!existingBalance) {\n // Add zero native balance entry if API didn't return one\n results.push({\n success: true,\n value: new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n }\n });\n });\n\n // Add staked balances\n results.push(...stakedBalances);\n\n return results;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAM7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAsB,GAAG,EAAE,wBAAwB;AAC/D,OAAO,EAAE,cAAc;AAcvB,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;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAM5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB;IAMnC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IA0KhC,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;
|
|
1
|
+
{"version":3,"file":"api-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAM7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAsB,GAAG,EAAE,wBAAwB;AAC/D,OAAO,EAAE,cAAc;AAcvB,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;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAM5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB;IAMnC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IA0KhC,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;CAkHxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAM7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAsB,GAAG,EAAE,wBAAwB;AAC/D,OAAO,EAAE,cAAc;AAcvB,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;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAM5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB;IAMnC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IA0KhC,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;
|
|
1
|
+
{"version":3,"file":"api-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAM7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAsB,GAAG,EAAE,wBAAwB;AAC/D,OAAO,EAAE,cAAc;AAcvB,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;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAM5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB;IAMnC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IA0KhC,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;CAkHxE"}
|
|
@@ -82,7 +82,17 @@ export class AccountsApiBalanceFetcher {
|
|
|
82
82
|
const chainId = toHex(b.chainId);
|
|
83
83
|
let value;
|
|
84
84
|
try {
|
|
85
|
-
|
|
85
|
+
// Convert string balance to BN avoiding floating point precision issues
|
|
86
|
+
const { balance: balanceStr, decimals } = b;
|
|
87
|
+
// Split the balance string into integer and decimal parts
|
|
88
|
+
const [integerPart = '0', decimalPart = ''] = balanceStr.split('.');
|
|
89
|
+
// Pad or truncate decimal part to match token decimals
|
|
90
|
+
const paddedDecimalPart = decimalPart
|
|
91
|
+
.padEnd(decimals, '0')
|
|
92
|
+
.slice(0, decimals);
|
|
93
|
+
// Combine and create BN
|
|
94
|
+
const fullIntegerStr = integerPart + paddedDecimalPart;
|
|
95
|
+
value = new BN(fullIntegerStr);
|
|
86
96
|
}
|
|
87
97
|
catch {
|
|
88
98
|
value = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.mjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BigNumber } from '@ethersproject/bignumber';\nimport { Contract } from '@ethersproject/contracts';\nimport type { Web3Provider } from '@ethersproject/providers';\nimport {\n safelyExecute,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n SupportedStakedBalanceNetworks,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 50;\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 checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n readonly #getProvider?: GetProviderFunction;\n\n constructor(\n platform: 'extension' | 'mobile' = 'extension',\n getProvider?: GetProviderFunction,\n ) {\n this.#platform = platform;\n this.#getProvider = getProvider;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchStakedBalances(\n addrs: CaipAccountAddress[],\n ): Promise<ProcessedBalance[]> {\n // Return empty array if no provider is available for blockchain calls\n if (!this.#getProvider) {\n return [];\n }\n\n const results: ProcessedBalance[] = [];\n\n // Group addresses by chain ID\n const addressesByChain: Record<ChainIdHex, ChecksumAddress[]> = {};\n\n for (const caipAddr of addrs) {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressesByChain[chainId]) {\n addressesByChain[chainId] = [];\n }\n addressesByChain[chainId].push(checksumAddress);\n }\n\n // Process each supported chain\n for (const [chainId, addresses] of Object.entries(addressesByChain)) {\n const chainIdHex = chainId as ChainIdHex;\n\n // Only fetch staked balance on supported networks (mainnet and hoodi)\n if (\n ![\n SupportedStakedBalanceNetworks.mainnet,\n SupportedStakedBalanceNetworks.hoodi,\n ].includes(chainIdHex as SupportedStakedBalanceNetworks)\n ) {\n continue;\n }\n\n // Only fetch staked balance if contract address exists\n if (!(chainIdHex in STAKING_CONTRACT_ADDRESS_BY_CHAINID)) {\n continue;\n }\n\n const contractAddress =\n STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainIdHex as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n const provider = this.#getProvider(chainIdHex);\n\n const abi = [\n {\n inputs: [\n { internalType: 'address', name: 'account', type: 'address' },\n ],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { internalType: 'uint256', name: 'shares', type: 'uint256' },\n ],\n name: 'convertToAssets',\n outputs: [\n { internalType: 'uint256', name: 'assets', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ];\n\n try {\n const contract = new Contract(contractAddress, abi, provider);\n\n // Get shares for each address\n for (const address of addresses) {\n try {\n const shares = await safelyExecute(() =>\n contract.getShares(address),\n );\n\n if (shares && (shares as BigNumber).gt(0)) {\n // Convert shares to assets (actual staked ETH amount)\n const assets = await safelyExecute(() =>\n contract.convertToAssets(shares),\n );\n\n if (assets) {\n results.push({\n success: true,\n value: new BN((assets as BigNumber).toString()),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } else {\n // Return zero balance for accounts with no staked assets\n results.push({\n success: true,\n value: new BN('0'),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } catch (error) {\n // Log error and continue with next address\n console.error(\n `Error fetching staked balance for ${address}:`,\n error,\n );\n results.push({\n success: false,\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n }\n } catch (error) {\n console.error(\n `Error setting up staking contract for chain ${chainId}:`,\n error,\n );\n }\n }\n\n return results;\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[]) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n );\n return balances;\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n );\n return [...(workingResult || []), ...balances];\n },\n initialResult: [],\n });\n\n return allBalances;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return [];\n }\n\n const [balances, stakedBalances] = await Promise.all([\n safelyExecute(() => this.#fetchBalances(caipAddrs)),\n this.#fetchStakedBalances(caipAddrs),\n ]);\n\n const results: ProcessedBalance[] = [];\n\n // Collect all unique addresses and chains from the CAIP addresses\n const addressChainMap = new Map<string, Set<ChainIdHex>>();\n caipAddrs.forEach((caipAddr) => {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressChainMap.has(checksumAddress)) {\n addressChainMap.set(checksumAddress, new Set());\n }\n addressChainMap.get(checksumAddress)?.add(chainId);\n });\n\n // Ensure native token entries exist for all addresses on all requested chains\n const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n const nativeBalancesFromAPI = new Map<string, BN>(); // key: `${address}-${chainId}`\n\n // Process regular API balances\n if (balances) {\n const apiBalances = balances.flatMap((b) => {\n const account = b.accountAddress?.split(':')[2] as ChecksumAddress;\n if (!account) {\n return [];\n }\n const token = checksum(b.address);\n const chainId = toHex(b.chainId) as ChainIdHex;\n\n let value: BN | undefined;\n try {\n value = new BN((parseFloat(b.balance) * 10 ** b.decimals).toFixed(0));\n } catch {\n value = undefined;\n }\n\n // Track native balances for later\n if (token === ZERO_ADDRESS && value !== undefined) {\n nativeBalancesFromAPI.set(`${account}-${chainId}`, value);\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account,\n token,\n chainId,\n },\n ];\n });\n results.push(...apiBalances);\n }\n\n // Ensure native token entries exist for all addresses/chains, even if not returned by API\n addressChainMap.forEach((chains, address) => {\n chains.forEach((chainId) => {\n const key = `${address}-${chainId}`;\n const existingBalance = nativeBalancesFromAPI.get(key);\n\n if (!existingBalance) {\n // Add zero native balance entry if API didn't return one\n results.push({\n success: true,\n value: new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n }\n });\n });\n\n // Add staked balances\n results.push(...stakedBalances);\n\n return results;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"api-balance-fetcher.mjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AACA,OAAO,EAAE,QAAQ,EAAE,iCAAiC;AAEpD,OAAO,EACL,aAAa,EACb,KAAK,EACL,oBAAoB,EACrB,mCAAmC;AAGpC,OAAO,GAAE,cAAc;;AAEvB,OAAO,EAAE,yBAAyB,EAAE,mCAA+B;AACnE,OAAO,EAAE,mCAAmC,EAAE,wCAAoC;AAClF,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,8BAA8B,EAC/B,0BAAsB;AACvB,OAAO,EAAE,kCAAkC,EAAE,yBAAqB;AAElE,+FAA+F;AAC/F,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAuBnC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAmB,EAAE,CACjD,oBAAoB,CAAC,IAAI,CAAoB,CAAC;AAEhD,MAAM,aAAa,GAAG,CACpB,OAAmB,EACnB,OAAwB,EACJ,EAAE,CAAC,6BAA6B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAIzE,MAAM,OAAO,yBAAyB;IAKpC,YACE,WAAmC,WAAW,EAC9C,WAAiC;;QAN1B,8CAAoC,WAAW,EAAC;QAEhD,yDAAmC;QAM1C,uBAAA,IAAI,uCAAa,QAAQ,MAAA,CAAC;QAC1B,uBAAA,IAAI,0CAAgB,WAAW,MAAA,CAAC;IAClC,CAAC;IAED,QAAQ,CAAC,OAAmB;QAC1B,OAAO,kCAAkC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9D,CAAC;IAwKD,KAAK,CAAC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,GAC4B;QACvC,MAAM,SAAS,GAAyB,EAAE,CAAC;QAE3C,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9D,IAAI,gBAAgB,EAAE;gBACpB,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CACxB,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,OAA0B,CAAC,CAAC,CACrE,CAAC;aACH;iBAAM;gBACL,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;aACzD;SACF;QAED,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE;YACrB,OAAO,EAAE,CAAC;SACX;QAED,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACnD,aAAa,CAAC,GAAG,EAAE,CAAC,uBAAA,IAAI,sFAAe,MAAnB,IAAI,EAAgB,SAAS,CAAC,CAAC;YACnD,uBAAA,IAAI,4FAAqB,MAAzB,IAAI,EAAsB,SAAS,CAAC;SACrC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAuB,EAAE,CAAC;QAEvC,kEAAkE;QAClE,MAAM,eAAe,GAAG,IAAI,GAAG,EAA2B,CAAC;QAC3D,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC7B,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAClD,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAe,CAAC;YAC5D,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;YAE1C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE;gBACzC,eAAe,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;aACjD;YACD,eAAe,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,8EAA8E;QAC9E,MAAM,YAAY,GAChB,4CAA+D,CAAC;QAClE,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAc,CAAC,CAAC,+BAA+B;QAEpF,+BAA+B;QAC/B,IAAI,QAAQ,EAAE;YACZ,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBACzC,MAAM,OAAO,GAAG,CAAC,CAAC,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAoB,CAAC;gBACnE,IAAI,CAAC,OAAO,EAAE;oBACZ,OAAO,EAAE,CAAC;iBACX;gBACD,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAClC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,CAAe,CAAC;gBAE/C,IAAI,KAAqB,CAAC;gBAC1B,IAAI;oBACF,wEAAwE;oBACxE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;oBAE5C,0DAA0D;oBAC1D,MAAM,CAAC,WAAW,GAAG,GAAG,EAAE,WAAW,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAEpE,uDAAuD;oBACvD,MAAM,iBAAiB,GAAG,WAAW;yBAClC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC;yBACrB,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;oBAEtB,wBAAwB;oBACxB,MAAM,cAAc,GAAG,WAAW,GAAG,iBAAiB,CAAC;oBACvD,KAAK,GAAG,IAAI,EAAE,CAAC,cAAc,CAAC,CAAC;iBAChC;gBAAC,MAAM;oBACN,KAAK,GAAG,SAAS,CAAC;iBACnB;gBAED,kCAAkC;gBAClC,IAAI,KAAK,KAAK,YAAY,IAAI,KAAK,KAAK,SAAS,EAAE;oBACjD,qBAAqB,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;iBAC3D;gBAED,OAAO;oBACL;wBACE,OAAO,EAAE,KAAK,KAAK,SAAS;wBAC5B,KAAK;wBACL,OAAO;wBACP,KAAK;wBACL,OAAO;qBACR;iBACF,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;SAC9B;QAED,0FAA0F;QAC1F,eAAe,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;YAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACzB,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;gBACpC,MAAM,eAAe,GAAG,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEvD,IAAI,CAAC,eAAe,EAAE;oBACpB,yDAAyD;oBACzD,OAAO,CAAC,IAAI,CAAC;wBACX,OAAO,EAAE,IAAI;wBACb,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC;wBAClB,OAAO,EAAE,OAA0B;wBACnC,KAAK,EAAE,YAAY;wBACnB,OAAO;qBACR,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,sBAAsB;QACtB,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;QAEhC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;oNA7RC,KAAK,yDACH,KAA2B;IAE3B,sEAAsE;IACtE,IAAI,CAAC,uBAAA,IAAI,8CAAa,EAAE;QACtB,OAAO,EAAE,CAAC;KACX;IAED,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,8BAA8B;IAC9B,MAAM,gBAAgB,GAA0C,EAAE,CAAC;IAEnE,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE;QAC5B,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAe,CAAC;QAC5D,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE1C,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE;YAC9B,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;SAChC;QACD,gBAAgB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;KACjD;IAED,+BAA+B;IAC/B,KAAK,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;QACnE,MAAM,UAAU,GAAG,OAAqB,CAAC;QAEzC,sEAAsE;QACtE,IACE,CAAC;YACC,8BAA8B,CAAC,OAAO;YACtC,8BAA8B,CAAC,KAAK;SACrC,CAAC,QAAQ,CAAC,UAA4C,CAAC,EACxD;YACA,SAAS;SACV;QAED,uDAAuD;QACvD,IAAI,CAAC,CAAC,UAAU,IAAI,mCAAmC,CAAC,EAAE;YACxD,SAAS;SACV;QAED,MAAM,eAAe,GACnB,mCAAmC,CACjC,UAA8D,CAC/D,CAAC;QACJ,MAAM,QAAQ,GAAG,uBAAA,IAAI,8CAAa,MAAjB,IAAI,EAAc,UAAU,CAAC,CAAC;QAE/C,MAAM,GAAG,GAAG;YACV;gBACE,MAAM,EAAE;oBACN,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC9D;gBACD,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBACjE,eAAe,EAAE,MAAM;gBACvB,IAAI,EAAE,UAAU;aACjB;YACD;gBACE,MAAM,EAAE;oBACN,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC7D;gBACD,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE;oBACP,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC7D;gBACD,eAAe,EAAE,MAAM;gBACvB,IAAI,EAAE,UAAU;aACjB;SACF,CAAC;QAEF,IAAI;YACF,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YAE9D,8BAA8B;YAC9B,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE;gBAC/B,IAAI;oBACF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,CACtC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAC5B,CAAC;oBAEF,IAAI,MAAM,IAAK,MAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;wBACzC,sDAAsD;wBACtD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,CACtC,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,CACjC,CAAC;wBAEF,IAAI,MAAM,EAAE;4BACV,OAAO,CAAC,IAAI,CAAC;gCACX,OAAO,EAAE,IAAI;gCACb,KAAK,EAAE,IAAI,EAAE,CAAE,MAAoB,CAAC,QAAQ,EAAE,CAAC;gCAC/C,OAAO,EAAE,OAAO;gCAChB,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAoB;gCACnD,OAAO,EAAE,UAAU;6BACpB,CAAC,CAAC;yBACJ;qBACF;yBAAM;wBACL,yDAAyD;wBACzD,OAAO,CAAC,IAAI,CAAC;4BACX,OAAO,EAAE,IAAI;4BACb,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC;4BAClB,OAAO,EAAE,OAAO;4BAChB,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAoB;4BACnD,OAAO,EAAE,UAAU;yBACpB,CAAC,CAAC;qBACJ;iBACF;gBAAC,OAAO,KAAK,EAAE;oBACd,2CAA2C;oBAC3C,OAAO,CAAC,KAAK,CACX,qCAAqC,OAAO,GAAG,EAC/C,KAAK,CACN,CAAC;oBACF,OAAO,CAAC,IAAI,CAAC;wBACX,OAAO,EAAE,KAAK;wBACd,OAAO,EAAE,OAAO;wBAChB,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAoB;wBACnD,OAAO,EAAE,UAAU;qBACpB,CAAC,CAAC;iBACJ;aACF;SACF;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CACX,+CAA+C,OAAO,GAAG,EACzD,KAAK,CACN,CAAC;SACH;KACF;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,6CAED,KAAK,mDAAgB,KAA2B;IAC9C,0EAA0E;IAC1E,IAAI,KAAK,CAAC,MAAM,IAAI,uBAAuB,EAAE;QAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,yBAAyB,CAClD,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAC3B,uBAAA,IAAI,2CAAU,CACf,CAAC;QACF,OAAO,QAAQ,CAAC;KACjB;IAOD,MAAM,WAAW,GAAG,MAAM,uBAAuB,CAG/C;QACA,MAAM,EAAE,KAAK;QACb,SAAS,EAAE,uBAAuB;QAClC,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE;YACxC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,yBAAyB,CAClD,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAC3B,uBAAA,IAAI,2CAAU,CACf,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC;QACjD,CAAC;QACD,aAAa,EAAE,EAAE;KAClB,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC","sourcesContent":["import type { BigNumber } from '@ethersproject/bignumber';\nimport { Contract } from '@ethersproject/contracts';\nimport type { Web3Provider } from '@ethersproject/providers';\nimport {\n safelyExecute,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n SupportedStakedBalanceNetworks,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 50;\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 checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n readonly #getProvider?: GetProviderFunction;\n\n constructor(\n platform: 'extension' | 'mobile' = 'extension',\n getProvider?: GetProviderFunction,\n ) {\n this.#platform = platform;\n this.#getProvider = getProvider;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchStakedBalances(\n addrs: CaipAccountAddress[],\n ): Promise<ProcessedBalance[]> {\n // Return empty array if no provider is available for blockchain calls\n if (!this.#getProvider) {\n return [];\n }\n\n const results: ProcessedBalance[] = [];\n\n // Group addresses by chain ID\n const addressesByChain: Record<ChainIdHex, ChecksumAddress[]> = {};\n\n for (const caipAddr of addrs) {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressesByChain[chainId]) {\n addressesByChain[chainId] = [];\n }\n addressesByChain[chainId].push(checksumAddress);\n }\n\n // Process each supported chain\n for (const [chainId, addresses] of Object.entries(addressesByChain)) {\n const chainIdHex = chainId as ChainIdHex;\n\n // Only fetch staked balance on supported networks (mainnet and hoodi)\n if (\n ![\n SupportedStakedBalanceNetworks.mainnet,\n SupportedStakedBalanceNetworks.hoodi,\n ].includes(chainIdHex as SupportedStakedBalanceNetworks)\n ) {\n continue;\n }\n\n // Only fetch staked balance if contract address exists\n if (!(chainIdHex in STAKING_CONTRACT_ADDRESS_BY_CHAINID)) {\n continue;\n }\n\n const contractAddress =\n STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainIdHex as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n const provider = this.#getProvider(chainIdHex);\n\n const abi = [\n {\n inputs: [\n { internalType: 'address', name: 'account', type: 'address' },\n ],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { internalType: 'uint256', name: 'shares', type: 'uint256' },\n ],\n name: 'convertToAssets',\n outputs: [\n { internalType: 'uint256', name: 'assets', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ];\n\n try {\n const contract = new Contract(contractAddress, abi, provider);\n\n // Get shares for each address\n for (const address of addresses) {\n try {\n const shares = await safelyExecute(() =>\n contract.getShares(address),\n );\n\n if (shares && (shares as BigNumber).gt(0)) {\n // Convert shares to assets (actual staked ETH amount)\n const assets = await safelyExecute(() =>\n contract.convertToAssets(shares),\n );\n\n if (assets) {\n results.push({\n success: true,\n value: new BN((assets as BigNumber).toString()),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } else {\n // Return zero balance for accounts with no staked assets\n results.push({\n success: true,\n value: new BN('0'),\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n } catch (error) {\n // Log error and continue with next address\n console.error(\n `Error fetching staked balance for ${address}:`,\n error,\n );\n results.push({\n success: false,\n account: address,\n token: checksum(contractAddress) as ChecksumAddress,\n chainId: chainIdHex,\n });\n }\n }\n } catch (error) {\n console.error(\n `Error setting up staking contract for chain ${chainId}:`,\n error,\n );\n }\n }\n\n return results;\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[]) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n );\n return balances;\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n );\n return [...(workingResult || []), ...balances];\n },\n initialResult: [],\n });\n\n return allBalances;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return [];\n }\n\n const [balances, stakedBalances] = await Promise.all([\n safelyExecute(() => this.#fetchBalances(caipAddrs)),\n this.#fetchStakedBalances(caipAddrs),\n ]);\n\n const results: ProcessedBalance[] = [];\n\n // Collect all unique addresses and chains from the CAIP addresses\n const addressChainMap = new Map<string, Set<ChainIdHex>>();\n caipAddrs.forEach((caipAddr) => {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10)) as ChainIdHex;\n const checksumAddress = checksum(address);\n\n if (!addressChainMap.has(checksumAddress)) {\n addressChainMap.set(checksumAddress, new Set());\n }\n addressChainMap.get(checksumAddress)?.add(chainId);\n });\n\n // Ensure native token entries exist for all addresses on all requested chains\n const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n const nativeBalancesFromAPI = new Map<string, BN>(); // key: `${address}-${chainId}`\n\n // Process regular API balances\n if (balances) {\n const apiBalances = balances.flatMap((b) => {\n const account = b.accountAddress?.split(':')[2] as ChecksumAddress;\n if (!account) {\n return [];\n }\n const token = checksum(b.address);\n const chainId = toHex(b.chainId) as ChainIdHex;\n\n let value: BN | undefined;\n try {\n // Convert string balance to BN avoiding floating point precision issues\n const { balance: balanceStr, decimals } = b;\n\n // Split the balance string into integer and decimal parts\n const [integerPart = '0', decimalPart = ''] = balanceStr.split('.');\n\n // Pad or truncate decimal part to match token decimals\n const paddedDecimalPart = decimalPart\n .padEnd(decimals, '0')\n .slice(0, decimals);\n\n // Combine and create BN\n const fullIntegerStr = integerPart + paddedDecimalPart;\n value = new BN(fullIntegerStr);\n } catch {\n value = undefined;\n }\n\n // Track native balances for later\n if (token === ZERO_ADDRESS && value !== undefined) {\n nativeBalancesFromAPI.set(`${account}-${chainId}`, value);\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account,\n token,\n chainId,\n },\n ];\n });\n results.push(...apiBalances);\n }\n\n // Ensure native token entries exist for all addresses/chains, even if not returned by API\n addressChainMap.forEach((chains, address) => {\n chains.forEach((chainId) => {\n const key = `${address}-${chainId}`;\n const existingBalance = nativeBalancesFromAPI.get(key);\n\n if (!existingBalance) {\n // Add zero native balance entry if API didn't return one\n results.push({\n success: true,\n value: new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n }\n });\n });\n\n // Add staked balances\n results.push(...stakedBalances);\n\n return results;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/assets-controllers",
|
|
3
|
-
"version": "73.2.0-preview-
|
|
3
|
+
"version": "73.2.0-preview-d12fc71",
|
|
4
4
|
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|