@metamask-previews/assets-controller 14.0.3-preview-e12b5ece6 → 14.0.3-preview-fe4b3be11

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +5 -10
  2. package/dist/AssetsController.cjs +592 -273
  3. package/dist/AssetsController.cjs.map +1 -1
  4. package/dist/AssetsController.d.cts +7 -10
  5. package/dist/AssetsController.d.cts.map +1 -1
  6. package/dist/AssetsController.d.mts +7 -10
  7. package/dist/AssetsController.d.mts.map +1 -1
  8. package/dist/AssetsController.mjs +592 -273
  9. package/dist/AssetsController.mjs.map +1 -1
  10. package/dist/data-sources/AbstractDataSource.cjs +23 -0
  11. package/dist/data-sources/AbstractDataSource.cjs.map +1 -1
  12. package/dist/data-sources/AbstractDataSource.d.cts +13 -1
  13. package/dist/data-sources/AbstractDataSource.d.cts.map +1 -1
  14. package/dist/data-sources/AbstractDataSource.d.mts +13 -1
  15. package/dist/data-sources/AbstractDataSource.d.mts.map +1 -1
  16. package/dist/data-sources/AbstractDataSource.mjs +23 -0
  17. package/dist/data-sources/AbstractDataSource.mjs.map +1 -1
  18. package/dist/data-sources/AccountActivityDataSource.cjs +2 -0
  19. package/dist/data-sources/AccountActivityDataSource.cjs.map +1 -1
  20. package/dist/data-sources/AccountActivityDataSource.d.cts.map +1 -1
  21. package/dist/data-sources/AccountActivityDataSource.d.mts.map +1 -1
  22. package/dist/data-sources/AccountActivityDataSource.mjs +2 -0
  23. package/dist/data-sources/AccountActivityDataSource.mjs.map +1 -1
  24. package/dist/data-sources/AccountsApiDataSource.cjs +144 -31
  25. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  26. package/dist/data-sources/AccountsApiDataSource.d.cts +18 -2
  27. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  28. package/dist/data-sources/AccountsApiDataSource.d.mts +18 -2
  29. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  30. package/dist/data-sources/AccountsApiDataSource.mjs +145 -32
  31. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  32. package/dist/data-sources/RpcDataSource.cjs +163 -24
  33. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  34. package/dist/data-sources/RpcDataSource.d.cts +17 -0
  35. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  36. package/dist/data-sources/RpcDataSource.d.mts +17 -0
  37. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  38. package/dist/data-sources/RpcDataSource.mjs +164 -25
  39. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  40. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +21 -12
  41. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
  42. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +7 -2
  43. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
  44. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +7 -2
  45. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
  46. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +21 -12
  47. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
  48. package/dist/data-sources/evm-rpc-services/types/state.cjs.map +1 -1
  49. package/dist/data-sources/evm-rpc-services/types/state.d.cts +3 -2
  50. package/dist/data-sources/evm-rpc-services/types/state.d.cts.map +1 -1
  51. package/dist/data-sources/evm-rpc-services/types/state.d.mts +3 -2
  52. package/dist/data-sources/evm-rpc-services/types/state.d.mts.map +1 -1
  53. package/dist/data-sources/evm-rpc-services/types/state.mjs.map +1 -1
  54. package/dist/middlewares/ParallelMiddleware.cjs +9 -0
  55. package/dist/middlewares/ParallelMiddleware.cjs.map +1 -1
  56. package/dist/middlewares/ParallelMiddleware.d.cts.map +1 -1
  57. package/dist/middlewares/ParallelMiddleware.d.mts.map +1 -1
  58. package/dist/middlewares/ParallelMiddleware.mjs +9 -0
  59. package/dist/middlewares/ParallelMiddleware.mjs.map +1 -1
  60. package/dist/middlewares/RpcFallbackMiddleware.cjs +158 -128
  61. package/dist/middlewares/RpcFallbackMiddleware.cjs.map +1 -1
  62. package/dist/middlewares/RpcFallbackMiddleware.d.cts +10 -14
  63. package/dist/middlewares/RpcFallbackMiddleware.d.cts.map +1 -1
  64. package/dist/middlewares/RpcFallbackMiddleware.d.mts +10 -14
  65. package/dist/middlewares/RpcFallbackMiddleware.d.mts.map +1 -1
  66. package/dist/middlewares/RpcFallbackMiddleware.mjs +158 -128
  67. package/dist/middlewares/RpcFallbackMiddleware.mjs.map +1 -1
  68. package/dist/selectors/balance.cjs +4 -9
  69. package/dist/selectors/balance.cjs.map +1 -1
  70. package/dist/selectors/balance.d.cts.map +1 -1
  71. package/dist/selectors/balance.d.mts.map +1 -1
  72. package/dist/selectors/balance.mjs +4 -9
  73. package/dist/selectors/balance.mjs.map +1 -1
  74. package/dist/types.cjs.map +1 -1
  75. package/dist/types.d.cts +28 -26
  76. package/dist/types.d.cts.map +1 -1
  77. package/dist/types.d.mts +28 -26
  78. package/dist/types.d.mts.map +1 -1
  79. package/dist/types.mjs.map +1 -1
  80. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"RpcDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/RpcDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport { toHex } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n NetworkState,\n NetworkStatus,\n} from '@metamask/network-controller';\nimport type {\n TransactionControllerTransactionConfirmedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport {\n isStrictHexString,\n isCaipChainId,\n parseCaipAssetType,\n parseCaipChainId,\n hexToNumber,\n toCaipChainId,\n KnownCaipNamespace,\n} from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type {\n AssetsControllerGetStateAction,\n AssetsControllerMessenger,\n} from '../AssetsController.js';\nimport { projectLogger, createModuleLogger } from '../logger.js';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n AssetMetadata,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types.js';\nimport { ZERO_ADDRESS } from '../utils/constants.js';\nimport { normalizeAssetId } from '../utils/index.js';\nimport { AbstractDataSource } from './AbstractDataSource.js';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource.js';\nimport {\n BalanceFetcher,\n MulticallClient,\n TokenDetector,\n TokensApiClient,\n} from './evm-rpc-services/index.js';\nimport type {\n BalancePollingInput,\n DetectionPollingInput,\n TokenListQueryClient,\n} from './evm-rpc-services/index.js';\nimport type {\n Address,\n AssetFetchEntry,\n Provider as RpcProvider,\n BalanceFetchResult,\n TokenDetectionResult,\n} from './evm-rpc-services/types/index.js';\nimport { shouldSkipNativeForCaipChainId } from './evm-rpc-services/utils/assets.js';\n\nconst CONTROLLER_NAME = 'RpcDataSource';\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\nconst DEFAULT_DETECTION_INTERVAL = 180_000; // 3 minutes\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// Allowed actions that RpcDataSource can call\nexport type RpcDataSourceAllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | AssetsControllerGetStateAction;\n\n// Allowed events that RpcDataSource can subscribe to\nexport type RpcDataSourceAllowedEvents =\n | NetworkControllerStateChangeEvent\n | TransactionControllerTransactionConfirmedEvent;\n\n/** Network status for each chain */\nexport type ChainStatus = {\n chainId: ChainId;\n status: NetworkStatus;\n name: string;\n nativeCurrency: string;\n /** Network client ID for getting the provider */\n networkClientId: string;\n};\n\n/** RpcDataSource is stateless */\nexport type RpcDataSourceState = Record<never, never>;\n\n/** Optional configuration for RpcDataSource when the controller instantiates it. */\nexport type RpcDataSourceConfig = {\n balanceInterval?: number;\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n timeout?: number;\n /**\n * Optional shared TanStack Query client used by `TokensApiClient` to cache\n * token-list responses across detector polls. Pass `apiPlatformClient.queryClient`\n * to share the cache with other API clients in the host app.\n */\n queryClient?: TokenListQueryClient;\n};\n\nexport type RpcDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Resolves CAIP-2 chain ID to CAIP-19 native asset ID from the cached native asset map. */\n getNativeAssetForChain: (chainId: ChainId) => Caip19AssetId;\n /** Request timeout in ms */\n timeout?: number;\n /** Balance polling interval in ms (default: 30s) */\n balanceInterval?: number;\n /** Token detection polling interval in ms (default: 180s / 3 min) */\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n /**\n * Optional shared TanStack Query client used by `TokensApiClient` to cache\n * token-list responses across detector polls.\n */\n queryClient?: TokenListQueryClient;\n\n /** Returns the asset type ('native' | 'erc20' | 'spl') for the given CAIP-19 asset ID */\n getAssetType: (assetId: Caip19AssetId) => 'native' | 'erc20' | 'spl';\n};\n\n/**\n * Subscription data stored for each active subscription.\n */\ntype SubscriptionData = {\n /** Polling tokens from BalanceFetcher */\n balancePollingTokens: string[];\n /** Polling tokens from TokenDetector */\n detectionPollingTokens: string[];\n /** Chain IDs being polled */\n chains: ChainId[];\n /** Accounts being polled */\n accounts: InternalAccount[];\n /** Callback to report asset updates to the controller */\n onAssetsUpdate: (\n response: DataResponse,\n request?: DataRequest,\n ) => void | Promise<void>;\n};\n\n/**\n * Convert CAIP chain ID or hex chain ID to hex chain ID.\n *\n * @param chainId - CAIP chain ID or hex chain ID.\n * @returns Hex chain ID.\n */\nexport const caipChainIdToHex = (chainId: string): Hex => {\n if (isStrictHexString(chainId)) {\n return chainId;\n }\n\n if (isCaipChainId(chainId)) {\n return toHex(parseCaipChainId(chainId).reference);\n }\n\n throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');\n};\n\n/**\n * Data source for fetching balances via RPC calls.\n *\n * Orchestrates polling through BalanceFetcher and TokenDetector,\n * each of which handle their own polling intervals.\n *\n * Communicates with AssetsController via Messenger:\n *\n * Actions:\n * - RpcDataSource:getActiveChains\n * - RpcDataSource:fetch\n * - RpcDataSource:subscribe\n * - RpcDataSource:unsubscribe\n *\n * Events:\n * - RpcDataSource:activeChainsUpdated\n * - RpcDataSource:assetsUpdated\n */\nexport class RpcDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n DataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #getNativeAssetForChain: (chainId: ChainId) => Caip19AssetId;\n\n readonly #timeout: number;\n\n readonly #tokenDetectionEnabled: () => boolean;\n\n readonly #useExternalService: () => boolean;\n\n readonly #isOnboarded: () => boolean;\n\n /** Currently active chains */\n #activeChains: ChainId[] = [];\n\n /** Network status for each active chain */\n #chainStatuses: Record<ChainId, ChainStatus> = {};\n\n /** Cache of Web3Provider instances by chainId */\n readonly #providerCache: Map<ChainId, Web3Provider> = new Map();\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<string, SubscriptionData> = new Map();\n\n #unsubscribeTransactionConfirmed: (() => void) | undefined = undefined;\n\n // Rpc-datasource components\n readonly #multicallClient: MulticallClient;\n\n readonly #balanceFetcher: BalanceFetcher;\n\n readonly #tokenDetector: TokenDetector;\n\n readonly #getAssetType: (\n assetId: Caip19AssetId,\n ) => 'native' | 'erc20' | 'spl';\n\n constructor(options: RpcDataSourceOptions) {\n super(CONTROLLER_NAME, { activeChains: [] });\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#getNativeAssetForChain = options.getNativeAssetForChain;\n this.#getAssetType = options.getAssetType;\n this.#timeout = options.timeout ?? 10_000;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#useExternalService =\n options.useExternalService ?? ((): boolean => true);\n this.#isOnboarded = options.isOnboarded ?? ((): boolean => true);\n\n const balanceInterval = options.balanceInterval ?? DEFAULT_BALANCE_INTERVAL;\n const detectionInterval =\n options.detectionInterval ?? DEFAULT_DETECTION_INTERVAL;\n\n log('Initializing RpcDataSource', {\n timeout: this.#timeout,\n balanceInterval,\n detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n });\n\n // Initialize MulticallClient with a provider getter\n this.#multicallClient = new MulticallClient({\n getProvider: (hexChainId: string): RpcProvider => {\n return this.#getMulticallProvider(hexChainId);\n },\n getMulticall3AddressForChain: (hexChainId: Hex): Hex | undefined =>\n // The messenger is not being called from a constructor, so this is safe.\n // eslint-disable-next-line no-restricted-syntax\n this.#messenger.call(\n 'ConfigRegistryController:getNetworkConfigByCaip2ChainId',\n toCaipChainId(\n KnownCaipNamespace.Eip155,\n hexToNumber(hexChainId).toString(),\n ),\n )?.contracts?.multicall3,\n });\n\n // Create messenger adapters for BalanceFetcher and TokenDetector\n const balanceFetcherMessenger = {\n call: (\n _action: 'AssetsController:getState',\n ): {\n assetsBalance: Record<string, Record<string, { amount: string }>>;\n customAssets?: Record<string, string[]>;\n } => {\n // The messenger is not being called from a constructor, so this is safe.\n // eslint-disable-next-line no-restricted-syntax\n const state = this.#messenger.call('AssetsController:getState');\n return {\n assetsBalance: (state.assetsBalance ?? {}) as Record<\n string,\n Record<string, { amount: string }>\n >,\n customAssets: (state.customAssets ?? {}) as Record<string, string[]>,\n };\n },\n };\n\n // Initialize BalanceFetcher with polling interval\n this.#balanceFetcher = new BalanceFetcher(\n this.#multicallClient,\n balanceFetcherMessenger,\n {\n pollingInterval: balanceInterval,\n isNativeAsset: (assetId: Caip19AssetId): boolean => {\n const { chainId } = parseCaipAssetType(assetId);\n const nativeId = this.#getNativeAssetForChain(chainId);\n return nativeId?.toLowerCase() === assetId.toLowerCase();\n },\n },\n );\n // Polling controller awaits this callback; rejections must not become unhandled.\n this.#balanceFetcher.setOnBalanceUpdate(async (result) => {\n try {\n await this.#handleBalanceUpdate(result);\n } catch (error) {\n log('Balance update handler failed', { error });\n }\n });\n\n // Initialize TokenDetector with polling interval. The TokensApiClient is\n // configured with the shared TanStack Query client (when the controller\n // provides one) so concurrent detector polls/accounts/instances share a\n // single in-flight request and cached result per chain.\n const tokensApiClient = new TokensApiClient({\n queryClient: options.queryClient,\n });\n this.#tokenDetector = new TokenDetector(\n this.#multicallClient,\n tokensApiClient,\n {\n pollingInterval: detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled,\n useExternalService: this.#useExternalService,\n },\n );\n // Sync throw in the detector would reject the poll tick if uncaught.\n this.#tokenDetector.setOnDetectionUpdate((result) => {\n try {\n this.#handleDetectionUpdate(result);\n } catch (error) {\n log('Detection update handler failed', { error });\n }\n });\n\n this.#subscribeToNetworkController();\n this.#subscribeToTransactionEvents();\n this.#initializeFromNetworkController();\n }\n\n /**\n * Convert a raw balance to human-readable format using decimals.\n *\n * Returns `'0'` when either input is invalid (e.g. `decimals` is `null`,\n * `NaN`, negative or non-finite, or `rawBalance` cannot be parsed as a\n * number). Defaulting to a fixed decimals value would silently produce\n * wrong amounts; `'0'` keeps state safe and never lets `NaN` leak in.\n *\n * @param rawBalance - The raw balance string.\n * @param decimals - The number of decimals for the token.\n * @returns The human-readable balance string, or `'0'` when inputs are invalid.\n */\n #convertToHumanReadable(rawBalance: string, decimals: number): string {\n if (!Number.isFinite(decimals) || decimals < 0) {\n log('Invalid decimals — defaulting balance to \"0\"', {\n rawBalance,\n decimals,\n });\n return '0';\n }\n\n const rawAmount = new BigNumberJS(rawBalance);\n if (!rawAmount.isFinite()) {\n log('Invalid raw balance — defaulting to \"0\"', { rawBalance, decimals });\n return '0';\n }\n\n const divisor = new BigNumberJS(10).pow(decimals);\n return rawAmount.dividedBy(divisor).toFixed();\n }\n\n /**\n * Collect metadata for a list of balance entries.\n * For native tokens, generates metadata from chain status.\n * For ERC20 tokens, looks up from existing state or token list.\n *\n * @param balances - Array of balance entries with assetId.\n * @param chainId - The CAIP-2 chain ID.\n * @returns Record of asset metadata keyed by asset ID.\n */\n #collectMetadataForBalances(\n balances: { assetId: Caip19AssetId }[],\n chainId: ChainId,\n ): Record<Caip19AssetId, AssetMetadata> {\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n const nativeAssetId = this.#getNativeAssetForChain(chainId);\n for (const balance of balances) {\n const existingMeta = existingMetadata[balance.assetId];\n const isNative =\n existingMeta?.type === 'native' ||\n balance.assetId.toLowerCase() === nativeAssetId?.toLowerCase() ||\n this.#getAssetType(balance.assetId) === 'native';\n\n if (isNative && !this.#hasValidDecimals(existingMeta)) {\n // Only emit a stub when no valid metadata exists in state yet.\n // Re-emitting existing metadata into the response would overwrite\n // richer entries (e.g. image/description added by AccountsAPI) with\n // a simpler stub on every balance poll cycle.\n const chainStatus = this.#chainStatuses[chainId];\n if (chainStatus) {\n assetsInfo[balance.assetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n }\n // For ERC-20 tokens and native tokens with existing valid metadata:\n // do not re-emit — the existing state entry is already correct.\n // Decimals for balance conversion are resolved via stateMetadata in\n // the callers (pickValidDecimals(stateMetadata, pipelineMetadata)).\n }\n\n return assetsInfo;\n }\n\n /**\n * Type guard for metadata whose `decimals` is safe to use for balance\n * conversion.\n *\n * Mirrors the validity rules in `#convertToHumanReadable` (finite and\n * non-negative). Keeping these in sync ensures that whenever the metadata\n * guard accepts a value, the balance guard will also accept it — so we\n * never end up emitting metadata with `decimals: -1` while silently\n * defaulting the balance to `'0'`.\n *\n * @param metadata - The metadata to check.\n * @returns `true` if `decimals` is a finite, non-negative number.\n */\n #hasValidDecimals(\n metadata: AssetMetadata | undefined,\n ): metadata is AssetMetadata {\n return Boolean(\n metadata && Number.isFinite(metadata.decimals) && metadata.decimals >= 0,\n );\n }\n\n /**\n * Pick the first valid `decimals` value from a list of metadata sources.\n *\n * `??` only short-circuits on `null`/`undefined`, so a stale state entry\n * with `decimals: NaN` would otherwise win over a later source that holds\n * a correct value (e.g. the chain-status stub produced by\n * `#collectMetadataForBalances`). This helper treats `NaN`, negative, and\n * non-finite values as missing so the next source can supply a usable one.\n *\n * @param metadatas - Metadata candidates in priority order.\n * @returns The first finite `decimals` value, or `undefined` if none are valid.\n */\n #pickValidDecimals(\n ...metadatas: (AssetMetadata | undefined)[]\n ): number | undefined {\n for (const metadata of metadatas) {\n if (this.#hasValidDecimals(metadata)) {\n return metadata.decimals;\n }\n }\n return undefined;\n }\n\n /**\n * Handle balance update from BalanceFetcher.\n *\n * @param result - The balance fetch result.\n */\n async #handleBalanceUpdate(result: BalanceFetchResult): Promise<void> {\n const newBalances: Record<string, { amount: string }> = {};\n\n // Convert hex chain ID to CAIP-2 format\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n\n // Normalize asset IDs from BalanceFetcher (lowercase) to checksummed form\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const assetsInfo = this.#collectMetadataForBalances(\n normalizedBalances,\n caipChainId,\n );\n\n // Convert balances to human-readable format.\n // Resolution: state metadata → pipeline metadata; skip if decimals unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n const decimals = this.#pickValidDecimals(stateMetadata, pipelineMetadata);\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n assetsInfo,\n updateMode: 'merge',\n };\n\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance'],\n };\n\n log('Balance update response', {\n accountId: result.accountId,\n newBalanceCount: Object.keys(newBalances).length,\n });\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update assets', { error });\n });\n }\n }\n\n /**\n * Handle detection update from TokenDetector.\n *\n * @param result - The token detection result.\n */\n #handleDetectionUpdate(result: TokenDetectionResult): void {\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n });\n\n // Build new metadata from detected assets\n const newMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n if (result.detectedAssets.length > 0) {\n for (const asset of result.detectedAssets) {\n // Only include if we have metadata (symbol and decimals at minimum)\n if (asset.symbol && asset.decimals !== undefined) {\n newMetadata[asset.assetId] = {\n type: this.#getAssetType(asset.assetId),\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n }\n\n // Build new balances from detected tokens\n const newBalances: Record<string, { amount: string }> = {};\n if (result.detectedBalances.length > 0) {\n for (const balance of result.detectedBalances) {\n // Get decimals from the detected asset metadata\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n detectedAssets: {\n [result.accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsInfo: newMetadata,\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n updateMode: 'merge',\n };\n\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance', 'metadata', 'price'],\n };\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update detected assets', { error });\n });\n }\n }\n\n #subscribeToNetworkController(): void {\n this.#messenger.subscribe(\n 'NetworkController:stateChange',\n (networkState: NetworkState) => {\n log('NetworkController state changed');\n this.#clearProviderCache();\n this.#updateFromNetworkState(networkState);\n },\n );\n }\n\n #subscribeToTransactionEvents(): void {\n const unsubConfirmed = this.#messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n this.#onTransactionConfirmed.bind(this),\n );\n this.#unsubscribeTransactionConfirmed =\n typeof unsubConfirmed === 'function' ? unsubConfirmed : undefined;\n }\n\n #onTransactionConfirmed(payload: TransactionMeta): void {\n const hexChainId = payload?.chainId;\n if (!hexChainId) {\n return;\n }\n const caipChainId = `eip155:${parseInt(hexChainId, 16)}` as ChainId;\n this.#refreshBalanceForChains([caipChainId], 'transactionConfirmed').catch(\n (error) => {\n log('Failed to refresh balance after transaction confirmed', { error });\n },\n );\n }\n\n /**\n * Fetch balances for the given chains across all active subscriptions and\n * push updates to the controller.\n *\n * @param chainIds - CAIP-2 chain IDs to refresh.\n * @param context - Why the refresh was triggered (for logging).\n */\n async #refreshBalanceForChains(\n chainIds: ChainId[],\n context: 'transactionConfirmed' | 'polling' = 'polling',\n ): Promise<void> {\n const chainIdsSet = new Set(chainIds);\n const chainsToFetch = chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n return;\n }\n\n let appliedCount = 0;\n\n for (const subscription of this.#activeSubscriptions.values()) {\n const subscriptionChains = subscription.chains.filter((chainId) =>\n chainIdsSet.has(chainId),\n );\n if (subscriptionChains.length === 0) {\n continue;\n }\n\n const request: DataRequest = {\n accountsWithSupportedChains: subscription.accounts.map((account) => ({\n account,\n supportedChains: subscriptionChains,\n })),\n chainIds: subscriptionChains,\n dataTypes: ['balance'],\n };\n\n try {\n const response = await this.fetch(request);\n const balanceCount = response.assetsBalance\n ? Object.values(response.assetsBalance).reduce(\n (sum, accountBalances) =>\n sum + Object.keys(accountBalances).length,\n 0,\n )\n : 0;\n\n if (balanceCount === 0) {\n continue;\n }\n\n const responseWithMode: DataResponse = {\n ...response,\n updateMode: response.updateMode ?? 'merge',\n };\n\n await subscription.onAssetsUpdate(responseWithMode, request);\n appliedCount += 1;\n } catch (error) {\n log('Failed to fetch balance after transaction', {\n context,\n chains: subscriptionChains,\n error,\n });\n }\n }\n\n if (appliedCount === 0 && context === 'transactionConfirmed') {\n log('No RpcDataSource subscription covers chain after transaction', {\n chainsToFetch,\n });\n }\n }\n\n #initializeFromNetworkController(): void {\n log('Initializing from NetworkController');\n try {\n const networkState = this.#messenger.call('NetworkController:getState');\n this.#updateFromNetworkState(networkState);\n } catch (error) {\n log('Failed to initialize from NetworkController', error);\n }\n }\n\n /**\n * Re-read NetworkController state and refresh Rpc `activeChains` (e.g. when\n * network availability metadata changes after an EVM network switch).\n */\n refreshActiveChainsFromNetworkState(): void {\n this.#initializeFromNetworkController();\n }\n\n #updateFromNetworkState(networkState: NetworkState): void {\n const { networkConfigurationsByChainId, networksMetadata } = networkState;\n\n const chainStatuses: Record<ChainId, ChainStatus> = {};\n const activeChains: ChainId[] = [];\n\n for (const [hexChainId, config] of Object.entries(\n networkConfigurationsByChainId,\n )) {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const defaultRpcEndpoint =\n config.rpcEndpoints[config.defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n const { networkClientId } = defaultRpcEndpoint;\n const metadata = networksMetadata[networkClientId];\n\n const status: NetworkStatus =\n metadata?.status ?? ('unknown' as NetworkStatus);\n\n chainStatuses[caip2ChainId] = {\n chainId: caip2ChainId,\n status,\n name: config.name,\n nativeCurrency: config.nativeCurrency,\n networkClientId,\n };\n\n if (status === 'available' || status === 'unknown') {\n activeChains.push(caip2ChainId);\n }\n }\n\n log('Network state updated', {\n configuredChains: Object.keys(chainStatuses),\n activeChains,\n });\n\n // Check if chains changed\n const previousChains = [...this.#activeChains];\n const previousSet = new Set(previousChains);\n const hasChanges =\n previousChains.length !== activeChains.length ||\n activeChains.some((chain) => !previousSet.has(chain));\n\n // Update internal state and data source state before notifying, so that\n // when the controller handles the callback and calls getActiveChainsSync(),\n // it receives the updated chains (same order as AbstractDataSource.updateActiveChains).\n this.#chainStatuses = chainStatuses;\n this.#activeChains = activeChains;\n this.state.activeChains = activeChains;\n\n if (hasChanges) {\n this.#onActiveChainsUpdated(this.getName(), activeChains, previousChains);\n }\n }\n\n #getProvider(chainId: ChainId): Web3Provider | undefined {\n const cached = this.#providerCache.get(chainId);\n if (cached) {\n return cached;\n }\n\n const chainStatus = this.#chainStatuses[chainId];\n if (!chainStatus) {\n return undefined;\n }\n\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n chainStatus.networkClientId,\n );\n if (!networkClient?.provider) {\n return undefined;\n }\n const web3Provider = new Web3Provider(networkClient.provider);\n this.#providerCache.set(chainId, web3Provider);\n\n return web3Provider;\n } catch (error) {\n log('Failed to get provider for chain', { chainId, error });\n return undefined;\n }\n }\n\n /**\n * Get provider for MulticallClient using a hex chainId.\n *\n * @param hexChainId - The hex string representation of the chain id.\n * @returns An RpcProvider instance for the specified chain.\n */\n #getMulticallProvider(hexChainId: string): RpcProvider {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const web3Provider = this.#getProvider(caip2ChainId);\n\n if (!web3Provider) {\n throw new Error(`No provider available for chain ${hexChainId}`);\n }\n\n return {\n call: async (params: { to: string; data: string }): Promise<string> => {\n return web3Provider.call({\n to: params.to,\n data: params.data,\n });\n },\n getBalance: async (address: string): Promise<{ toString(): string }> => {\n const balance = await web3Provider.getBalance(address);\n return balance;\n },\n };\n }\n\n #clearProviderCache(): void {\n this.#providerCache.clear();\n }\n\n /**\n * Fetch the `decimals()` value from an ERC20 contract via RPC.\n *\n * @param chainId - CAIP-2 chain ID.\n * @param tokenAddress - The token contract address.\n * @returns The decimals value, or undefined if the call fails.\n */\n async #fetchDecimalsViaRpc(\n chainId: ChainId,\n tokenAddress: string,\n ): Promise<number | undefined> {\n try {\n const provider = this.#getProvider(chainId);\n if (!provider) {\n return undefined;\n }\n // ERC20 decimals() selector: keccak256(\"decimals()\") = 0x313ce567\n const result = await provider.call({\n to: tokenAddress,\n data: '0x313ce567',\n });\n if (!result || result === '0x') {\n return undefined;\n }\n const parsed = parseInt(result, 16);\n if (Number.isNaN(parsed) || parsed < 0 || parsed > 255) {\n return undefined;\n }\n return parsed;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Get the data source name.\n *\n * @returns The name of this data source.\n */\n /**\n * Get the status of all configured chains.\n *\n * @returns Record of chain statuses keyed by chain ID.\n */\n getChainStatuses(): Record<ChainId, ChainStatus> {\n return { ...this.#chainStatuses };\n }\n\n /**\n * Get the status of a specific chain.\n *\n * @param chainId - The chain ID to get status for.\n * @returns The chain status or undefined if not found.\n */\n getChainStatus(chainId: ChainId): ChainStatus | undefined {\n return this.#chainStatuses[chainId];\n }\n\n /**\n * Set the balance polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setBalancePollingInterval(interval: number): void {\n log('Setting balance polling interval', { interval });\n this.#balanceFetcher.setIntervalLength(interval);\n }\n\n /**\n * Get the current balance polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getBalancePollingInterval(): number | undefined {\n return this.#balanceFetcher.getIntervalLength();\n }\n\n /**\n * Set the token detection polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setDetectionPollingInterval(interval: number): void {\n log('Setting detection polling interval', { interval });\n this.#tokenDetector.setIntervalLength(interval);\n }\n\n /**\n * Get the current token detection polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getDetectionPollingInterval(): number | undefined {\n return this.#tokenDetector.getIntervalLength();\n }\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n if (!this.#isOnboarded()) {\n log('Skipping fetch - onboarding not complete');\n return {};\n }\n\n const response: DataResponse = {};\n\n const chainsToFetch = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n log('Fetch requested', {\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n requestedChains: request.chainIds,\n chainsToFetch,\n });\n\n if (chainsToFetch.length === 0) {\n log('No active chains to fetch');\n return response;\n }\n\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const failedChains: ChainId[] = [];\n\n // Fetch balances for each account and its supported chains (pre-computed in request)\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToFetch.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n const nativeAssetId = this.#getNativeAssetForChain(chainId);\n\n const shouldSkipNative = shouldSkipNativeForCaipChainId(chainId);\n const assetsToFetch: AssetFetchEntry[] = [];\n if (!shouldSkipNative) {\n // Build a single AssetFetchEntry[] for native + custom ERC-20s\n assetsToFetch.push({ assetId: nativeAssetId, address: ZERO_ADDRESS });\n }\n\n if (request.customAssets) {\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n for (const assetId of request.customAssets) {\n try {\n const parsed = parseCaipAssetType(assetId);\n const assetChainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n if (\n assetChainId === chainId &&\n this.#getAssetType(assetId) === 'erc20'\n ) {\n const tokenAddress =\n parsed.assetReference.toLowerCase() as Address;\n const normalizedId = normalizeAssetId(assetId);\n const decimals = existingMetadata[normalizedId]?.decimals;\n\n assetsToFetch.push({\n assetId,\n address: tokenAddress,\n decimals,\n });\n }\n } catch {\n // Skip unparseable asset IDs\n }\n }\n }\n\n try {\n const result = await this.#balanceFetcher.fetchBalancesForAssets(\n hexChainId,\n accountId,\n address as Address,\n assetsToFetch,\n );\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset IDs from BalanceFetcher (which uses lowercase\n // addresses) to checksummed form so they match assetsInfo state keys.\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const balanceMetadata = this.#collectMetadataForBalances(\n normalizedBalances,\n chainId,\n );\n Object.assign(assetsInfo, balanceMetadata);\n\n // Convert balances to human-readable format using decimals from\n // assetsInfo state (which includes pendingMetadata from addCustomAsset).\n // Resolution: state → pipeline metadata → RPC `decimals()`; omit balance if still unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n let decimals: number | undefined = this.#pickValidDecimals(\n stateMetadata,\n pipelineMetadata,\n );\n\n if (decimals === undefined) {\n const parsed = parseCaipAssetType(balance.assetId);\n if (this.#getAssetType(balance.assetId) === 'erc20') {\n decimals = await this.#fetchDecimalsViaRpc(\n chainId,\n parsed.assetReference,\n );\n }\n }\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n assetsBalance[accountId][balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n } catch (error) {\n log('Failed to fetch balance', { address, chainId, error });\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n if (!shouldSkipNative) {\n assetsBalance[accountId][nativeAssetId] = { amount: '0' };\n }\n // On error, emit a stub only when no valid metadata exists in state\n // yet. Re-emitting existing metadata would overwrite richer entries\n // (e.g. image/description added by AccountsAPI) with a simpler stub.\n const existingNativeMeta =\n this.#getExistingAssetsMetadata()[nativeAssetId];\n if (!this.#hasValidDecimals(existingNativeMeta)) {\n const chainStatus = this.#chainStatuses[chainId];\n if (chainStatus) {\n assetsInfo[nativeAssetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n }\n\n if (!failedChains.includes(chainId)) {\n failedChains.push(chainId);\n }\n }\n }\n }\n\n if (failedChains.length > 0) {\n log('Fetch PARTIAL - some chains failed', {\n successChains: chainsToFetch.filter(\n (chain) => !failedChains.includes(chain),\n ),\n failedChains,\n });\n\n response.errors = {};\n for (const chainId of failedChains) {\n response.errors[chainId] = 'RPC fetch failed';\n }\n } else {\n log('Fetch SUCCESS', {\n chains: chainsToFetch,\n accountCount: Object.keys(assetsBalance).length,\n });\n }\n\n response.assetsBalance = assetsBalance;\n\n // Include metadata for native tokens if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n response.updateMode = 'merge';\n\n return response;\n }\n\n /**\n * Run token detection for an account on a chain.\n *\n * @param chainId - The chain ID to detect tokens on.\n * @param account - The account to detect tokens for.\n * @returns Promise resolving to a DataResponse with detected assets.\n */\n async detectTokens(\n chainId: ChainId,\n account: InternalAccount,\n ): Promise<DataResponse> {\n if (!this.#tokenDetectionEnabled() || !this.#useExternalService()) {\n return {};\n }\n\n const hexChainId = caipChainIdToHex(chainId);\n const { address, id: accountId } = account;\n\n log('Running token detection', { chainId, accountId });\n\n try {\n const result = await this.#tokenDetector.detectTokens(\n hexChainId,\n accountId,\n address as Address,\n {\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n },\n );\n\n if (result.detectedAssets.length === 0) {\n log('No new tokens detected');\n return {};\n }\n\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n chainId,\n accountId,\n });\n\n // Convert detected assets to DataResponse format\n const balances: Record<Caip19AssetId, AssetBalance> = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n\n // Build metadata from detected assets\n for (const asset of result.detectedAssets) {\n if (asset.symbol && asset.decimals !== undefined) {\n assetsInfo[asset.assetId] = {\n type: this.#getAssetType(asset.assetId),\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n\n // Add balances for detected tokens (converted to human-readable format)\n for (const balance of result.detectedBalances) {\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n balances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n const response: DataResponse = {\n detectedAssets: {\n [accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsBalance: {\n [accountId]: balances,\n },\n };\n\n // Include metadata if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n return response;\n } catch (error) {\n log('Token detection failed', { chainId, accountId, error });\n return {};\n }\n }\n\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n log('Middleware fetching', {\n chains: supportedChains,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n });\n\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] ??= {};\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n\n if (response.assetsInfo) {\n context.response.assetsInfo ??= {};\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n\n // Propagate per-chain fetch errors so downstream consumers (e.g.\n // RpcFallbackMiddleware) can tell which chains this source actually\n // failed on and discard their failure stubs instead of merging them.\n if (response.errors) {\n context.response.errors = {\n ...context.response.errors,\n ...response.errors,\n };\n }\n\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n\n return next({\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n });\n }\n\n return next(context);\n };\n }\n\n /**\n * Subscribe to updates for the given request.\n * Starts polling through BalanceFetcher and TokenDetector.\n *\n * @param subscriptionRequest - The subscription request details.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n if (!this.#isOnboarded()) {\n log('Skipping subscribe - onboarding not complete');\n return;\n }\n\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Use request.chainIds when activeChains is not yet populated (e.g. before\n // NetworkController state has been applied) so polling can start.\n const chainsToSubscribe =\n this.#activeChains.length > 0\n ? request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n )\n : request.chainIds;\n\n log('Subscribe requested', {\n subscriptionId,\n isUpdate,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n chainsToSubscribe,\n activeChainsFallback: this.#activeChains.length === 0,\n });\n\n if (chainsToSubscribe.length === 0) {\n log('No active chains to subscribe');\n return;\n }\n\n // Handle subscription update - restart polling for new chains\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n log('Updating existing subscription - restarting polling', {\n subscriptionId,\n existingChains: existing.chains,\n newChains: chainsToSubscribe,\n });\n // Don't return early - continue to unsubscribe and restart polling\n }\n }\n\n // Clean up existing subscription (stops old polling)\n await this.unsubscribe(subscriptionId);\n // Start polling through BalanceFetcher and TokenDetector\n const balancePollingTokens: string[] = [];\n const detectionPollingTokens: string[] = [];\n\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToSubscribe.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n // Start balance polling\n const balanceInput: BalancePollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n ...(request.customAssetsOnly === true\n ? { customAssetsOnly: true }\n : {}),\n };\n const balanceToken = this.#balanceFetcher.startPolling(balanceInput);\n balancePollingTokens.push(balanceToken);\n\n // Token detection is only relevant for \"regular\" subscriptions —\n // a customAssetsOnly subscription should never run detection.\n if (\n request.customAssetsOnly !== true &&\n this.#tokenDetectionEnabled() &&\n this.#useExternalService()\n ) {\n const detectionInput: DetectionPollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n };\n const detectionToken =\n this.#tokenDetector.startPolling(detectionInput);\n detectionPollingTokens.push(detectionToken);\n }\n }\n }\n\n // Store subscription data\n const accounts = request.accountsWithSupportedChains.map(\n (entry) => entry.account,\n );\n this.#activeSubscriptions.set(subscriptionId, {\n balancePollingTokens,\n detectionPollingTokens,\n chains: chainsToSubscribe,\n accounts,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n log('Subscription SUCCESS', {\n subscriptionId,\n chains: chainsToSubscribe,\n balancePollingCount: balancePollingTokens.length,\n detectionPollingCount: detectionPollingTokens.length,\n });\n }\n\n /**\n * Unsubscribe from updates and stop polling.\n *\n * @param subscriptionId - The subscription ID to unsubscribe.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n // Stop balance polling\n for (const token of subscription.balancePollingTokens) {\n this.#balanceFetcher.stopPollingByPollingToken(token);\n }\n\n // Stop detection polling\n for (const token of subscription.detectionPollingTokens) {\n this.#tokenDetector.stopPollingByPollingToken(token);\n }\n\n this.#activeSubscriptions.delete(subscriptionId);\n log('Unsubscribed and stopped polling', { subscriptionId });\n }\n }\n\n /**\n * Get existing assets metadata from AssetsController state.\n * Used to include metadata for ERC20 tokens when returning balance updates.\n *\n * @returns Record of asset IDs to their metadata.\n */\n #getExistingAssetsMetadata(): Record<Caip19AssetId, AssetMetadata> {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n return state.assetsInfo ?? {};\n } catch (error) {\n log('Failed to get existing assets metadata', { error });\n return {};\n }\n }\n\n /**\n * Destroy the data source and clean up resources.\n */\n destroy(): void {\n log('Destroying RpcDataSource');\n\n this.#unsubscribeTransactionConfirmed?.();\n\n // Stop all polling\n this.#balanceFetcher.stopAllPolling();\n this.#tokenDetector.stopAllPolling();\n\n // Clear subscriptions\n this.#activeSubscriptions.clear();\n\n // Clear caches\n this.#providerCache.clear();\n }\n}\n\nexport function createRpcDataSource(\n options: RpcDataSourceOptions,\n): RpcDataSource {\n return new RpcDataSource(options);\n}\n"]}
1
+ {"version":3,"file":"RpcDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/RpcDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport { toHex } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n NetworkState,\n NetworkStatus,\n} from '@metamask/network-controller';\nimport type {\n TransactionControllerTransactionConfirmedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport {\n isStrictHexString,\n isCaipChainId,\n KnownCaipNamespace,\n parseCaipAssetType,\n parseCaipChainId,\n hexToNumber,\n toCaipChainId,\n} from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type {\n AssetsControllerGetStateAction,\n AssetsControllerMessenger,\n} from '../AssetsController.js';\nimport { projectLogger, createModuleLogger } from '../logger.js';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n AssetMetadata,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types.js';\nimport { ZERO_ADDRESS } from '../utils/constants.js';\nimport { normalizeAssetId } from '../utils/index.js';\nimport { AbstractDataSource } from './AbstractDataSource.js';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource.js';\nimport {\n BalanceFetcher,\n MulticallClient,\n TokenDetector,\n TokensApiClient,\n} from './evm-rpc-services/index.js';\nimport type {\n BalancePollingInput,\n DetectionPollingInput,\n TokenListQueryClient,\n} from './evm-rpc-services/index.js';\nimport type {\n Address,\n AssetFetchEntry,\n Provider as RpcProvider,\n BalanceFetchResult,\n TokenDetectionResult,\n} from './evm-rpc-services/types/index.js';\nimport { shouldSkipNativeForCaipChainId } from './evm-rpc-services/utils/assets.js';\n\nconst CONTROLLER_NAME = 'RpcDataSource';\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\nconst DEFAULT_DETECTION_INTERVAL = 180_000; // 3 minutes\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// Allowed actions that RpcDataSource can call\nexport type RpcDataSourceAllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | AssetsControllerGetStateAction;\n\n// Allowed events that RpcDataSource can subscribe to\nexport type RpcDataSourceAllowedEvents =\n | NetworkControllerStateChangeEvent\n | TransactionControllerTransactionConfirmedEvent;\n\n/** Network status for each chain */\nexport type ChainStatus = {\n chainId: ChainId;\n status: NetworkStatus;\n name: string;\n nativeCurrency: string;\n /** Network client ID for getting the provider */\n networkClientId: string;\n};\n\n/** RpcDataSource is stateless */\nexport type RpcDataSourceState = Record<never, never>;\n\n/** Optional configuration for RpcDataSource when the controller instantiates it. */\nexport type RpcDataSourceConfig = {\n balanceInterval?: number;\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n timeout?: number;\n /**\n * Optional shared TanStack Query client used by `TokensApiClient` to cache\n * token-list responses across detector polls. Pass `apiPlatformClient.queryClient`\n * to share the cache with other API clients in the host app.\n */\n queryClient?: TokenListQueryClient;\n};\n\nexport type RpcDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Resolves CAIP-2 chain ID to CAIP-19 native asset ID from the cached native asset map. */\n getNativeAssetForChain: (chainId: ChainId) => Caip19AssetId;\n /** Request timeout in ms */\n timeout?: number;\n /** Balance polling interval in ms (default: 30s) */\n balanceInterval?: number;\n /** Token detection polling interval in ms (default: 180s / 3 min) */\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n /**\n * Optional shared TanStack Query client used by `TokensApiClient` to cache\n * token-list responses across detector polls.\n */\n queryClient?: TokenListQueryClient;\n\n /** Returns the asset type ('native' | 'erc20' | 'spl') for the given CAIP-19 asset ID */\n getAssetType: (assetId: Caip19AssetId) => 'native' | 'erc20' | 'spl';\n /**\n * Whether Accounts API v6 pin filtering and asset-scoped polls are enabled.\n * Injected by AssetsController; defaults to v5 when omitted.\n */\n isBalanceV6Enabled?: () => boolean;\n};\n\n/**\n * Subscription data stored for each active subscription.\n */\ntype SubscriptionData = {\n /** Polling tokens from BalanceFetcher */\n balancePollingTokens: string[];\n /** Polling tokens from TokenDetector */\n detectionPollingTokens: string[];\n /** Chain IDs being polled */\n chains: ChainId[];\n /** Accounts being polled */\n accounts: InternalAccount[];\n /** Callback to report asset updates to the controller */\n onAssetsUpdate: (\n response: DataResponse,\n request?: DataRequest,\n ) => void | Promise<void>;\n};\n\n/**\n * Convert CAIP chain ID or hex chain ID to hex chain ID.\n *\n * @param chainId - CAIP chain ID or hex chain ID.\n * @returns Hex chain ID.\n */\nexport const caipChainIdToHex = (chainId: string): Hex => {\n if (isStrictHexString(chainId)) {\n return chainId;\n }\n\n if (isCaipChainId(chainId)) {\n return toHex(parseCaipChainId(chainId).reference);\n }\n\n throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');\n};\n\n/**\n * Data source for fetching balances via RPC calls.\n *\n * Orchestrates polling through BalanceFetcher and TokenDetector,\n * each of which handle their own polling intervals.\n *\n * Communicates with AssetsController via Messenger:\n *\n * Actions:\n * - RpcDataSource:getActiveChains\n * - RpcDataSource:fetch\n * - RpcDataSource:subscribe\n * - RpcDataSource:unsubscribe\n *\n * Events:\n * - RpcDataSource:activeChainsUpdated\n * - RpcDataSource:assetsUpdated\n */\nexport class RpcDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n DataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #getNativeAssetForChain: (chainId: ChainId) => Caip19AssetId;\n\n readonly #timeout: number;\n\n readonly #tokenDetectionEnabled: () => boolean;\n\n readonly #useExternalService: () => boolean;\n\n readonly #isOnboarded: () => boolean;\n\n readonly #isBalanceV6Enabled: () => boolean;\n\n /** Currently active chains */\n #activeChains: ChainId[] = [];\n\n /** Network status for each active chain */\n #chainStatuses: Record<ChainId, ChainStatus> = {};\n\n /** Cache of Web3Provider instances by chainId */\n readonly #providerCache: Map<ChainId, Web3Provider> = new Map();\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<string, SubscriptionData> = new Map();\n\n #unsubscribeTransactionConfirmed: (() => void) | undefined = undefined;\n\n // Rpc-datasource components\n readonly #multicallClient: MulticallClient;\n\n readonly #balanceFetcher: BalanceFetcher;\n\n readonly #tokenDetector: TokenDetector;\n\n readonly #getAssetType: (\n assetId: Caip19AssetId,\n ) => 'native' | 'erc20' | 'spl';\n\n constructor(options: RpcDataSourceOptions) {\n super(CONTROLLER_NAME, { activeChains: [] });\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#getNativeAssetForChain = options.getNativeAssetForChain;\n this.#getAssetType = options.getAssetType;\n this.#timeout = options.timeout ?? 10_000;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#useExternalService =\n options.useExternalService ?? ((): boolean => true);\n this.#isOnboarded = options.isOnboarded ?? ((): boolean => true);\n this.#isBalanceV6Enabled =\n options.isBalanceV6Enabled ?? ((): boolean => false);\n\n const balanceInterval = options.balanceInterval ?? DEFAULT_BALANCE_INTERVAL;\n const detectionInterval =\n options.detectionInterval ?? DEFAULT_DETECTION_INTERVAL;\n\n log('Initializing RpcDataSource', {\n timeout: this.#timeout,\n balanceInterval,\n detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n });\n\n // Initialize MulticallClient with a provider getter\n this.#multicallClient = new MulticallClient({\n getProvider: (hexChainId: string): RpcProvider => {\n return this.#getMulticallProvider(hexChainId);\n },\n getMulticall3AddressForChain: (hexChainId: Hex): Hex | undefined =>\n // The messenger is not being called from a constructor, so this is safe.\n // eslint-disable-next-line no-restricted-syntax\n this.#messenger.call(\n 'ConfigRegistryController:getNetworkConfigByCaip2ChainId',\n toCaipChainId(\n KnownCaipNamespace.Eip155,\n hexToNumber(hexChainId).toString(),\n ),\n )?.contracts?.multicall3,\n });\n\n // Create messenger adapters for BalanceFetcher and TokenDetector\n const balanceFetcherMessenger = {\n call: (\n _action: 'AssetsController:getState',\n ): {\n assetsBalance: Record<string, Record<string, { amount: string }>>;\n customAssets?: Record<string, string[]>;\n } => {\n // The messenger is not being called from a constructor, so this is safe.\n // eslint-disable-next-line no-restricted-syntax\n const state = this.#messenger.call('AssetsController:getState');\n return {\n assetsBalance: (state.assetsBalance ?? {}) as Record<\n string,\n Record<string, { amount: string }>\n >,\n customAssets: (state.customAssets ?? {}) as Record<string, string[]>,\n };\n },\n };\n\n // Initialize BalanceFetcher with polling interval\n this.#balanceFetcher = new BalanceFetcher(\n this.#multicallClient,\n balanceFetcherMessenger,\n {\n pollingInterval: balanceInterval,\n isNativeAsset: (assetId: Caip19AssetId): boolean => {\n const { chainId } = parseCaipAssetType(assetId);\n const nativeId = this.#getNativeAssetForChain(chainId);\n return nativeId?.toLowerCase() === assetId.toLowerCase();\n },\n },\n );\n // Polling controller awaits this callback; rejections must not become unhandled.\n this.#balanceFetcher.setOnBalanceUpdate(async (result) => {\n try {\n await this.#handleBalanceUpdate(result);\n } catch (error) {\n log('Balance update handler failed', { error });\n }\n });\n\n // Initialize TokenDetector with polling interval. The TokensApiClient is\n // configured with the shared TanStack Query client (when the controller\n // provides one) so concurrent detector polls/accounts/instances share a\n // single in-flight request and cached result per chain.\n const tokensApiClient = new TokensApiClient({\n queryClient: options.queryClient,\n });\n this.#tokenDetector = new TokenDetector(\n this.#multicallClient,\n tokensApiClient,\n {\n pollingInterval: detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled,\n useExternalService: this.#useExternalService,\n },\n );\n // Sync throw in the detector would reject the poll tick if uncaught.\n this.#tokenDetector.setOnDetectionUpdate((result) => {\n try {\n this.#handleDetectionUpdate(result);\n } catch (error) {\n log('Detection update handler failed', { error });\n }\n });\n\n this.#subscribeToNetworkController();\n this.#subscribeToTransactionEvents();\n this.#initializeFromNetworkController();\n }\n\n /**\n * Convert a raw balance to human-readable format using decimals.\n *\n * Returns `'0'` when either input is invalid (e.g. `decimals` is `null`,\n * `NaN`, negative or non-finite, or `rawBalance` cannot be parsed as a\n * number). Defaulting to a fixed decimals value would silently produce\n * wrong amounts; `'0'` keeps state safe and never lets `NaN` leak in.\n *\n * @param rawBalance - The raw balance string.\n * @param decimals - The number of decimals for the token.\n * @returns The human-readable balance string, or `'0'` when inputs are invalid.\n */\n #convertToHumanReadable(rawBalance: string, decimals: number): string {\n if (!Number.isFinite(decimals) || decimals < 0) {\n log('Invalid decimals — defaulting balance to \"0\"', {\n rawBalance,\n decimals,\n });\n return '0';\n }\n\n const rawAmount = new BigNumberJS(rawBalance);\n if (!rawAmount.isFinite()) {\n log('Invalid raw balance — defaulting to \"0\"', { rawBalance, decimals });\n return '0';\n }\n\n const divisor = new BigNumberJS(10).pow(decimals);\n return rawAmount.dividedBy(divisor).toFixed();\n }\n\n /**\n * Collect metadata for a list of balance entries.\n * For native tokens, generates metadata from chain status.\n * For ERC20 tokens, looks up from existing state or token list.\n *\n * @param balances - Array of balance entries with assetId.\n * @param chainId - The CAIP-2 chain ID.\n * @returns Record of asset metadata keyed by asset ID.\n */\n #collectMetadataForBalances(\n balances: { assetId: Caip19AssetId }[],\n chainId: ChainId,\n ): Record<Caip19AssetId, AssetMetadata> {\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n const nativeAssetId = this.#getNativeAssetForChain(chainId);\n for (const balance of balances) {\n const existingMeta = existingMetadata[balance.assetId];\n const isNative =\n existingMeta?.type === 'native' ||\n balance.assetId.toLowerCase() === nativeAssetId?.toLowerCase() ||\n this.#getAssetType(balance.assetId) === 'native';\n\n if (isNative && !this.#hasValidDecimals(existingMeta)) {\n // Only emit a stub when no valid metadata exists in state yet.\n // Re-emitting existing metadata into the response would overwrite\n // richer entries (e.g. image/description added by AccountsAPI) with\n // a simpler stub on every balance poll cycle.\n const chainStatus = this.#chainStatuses[chainId];\n if (chainStatus) {\n assetsInfo[balance.assetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n }\n // For ERC-20 tokens and native tokens with existing valid metadata:\n // do not re-emit — the existing state entry is already correct.\n // Decimals for balance conversion are resolved via stateMetadata in\n // the callers (pickValidDecimals(stateMetadata, pipelineMetadata)).\n }\n\n return assetsInfo;\n }\n\n /**\n * Type guard for metadata whose `decimals` is safe to use for balance\n * conversion.\n *\n * Mirrors the validity rules in `#convertToHumanReadable` (finite and\n * non-negative). Keeping these in sync ensures that whenever the metadata\n * guard accepts a value, the balance guard will also accept it — so we\n * never end up emitting metadata with `decimals: -1` while silently\n * defaulting the balance to `'0'`.\n *\n * @param metadata - The metadata to check.\n * @returns `true` if `decimals` is a finite, non-negative number.\n */\n #hasValidDecimals(\n metadata: AssetMetadata | undefined,\n ): metadata is AssetMetadata {\n return Boolean(\n metadata && Number.isFinite(metadata.decimals) && metadata.decimals >= 0,\n );\n }\n\n /**\n * Pick the first valid `decimals` value from a list of metadata sources.\n *\n * `??` only short-circuits on `null`/`undefined`, so a stale state entry\n * with `decimals: NaN` would otherwise win over a later source that holds\n * a correct value (e.g. the chain-status stub produced by\n * `#collectMetadataForBalances`). This helper treats `NaN`, negative, and\n * non-finite values as missing so the next source can supply a usable one.\n *\n * @param metadatas - Metadata candidates in priority order.\n * @returns The first finite `decimals` value, or `undefined` if none are valid.\n */\n #pickValidDecimals(\n ...metadatas: (AssetMetadata | undefined)[]\n ): number | undefined {\n for (const metadata of metadatas) {\n if (this.#hasValidDecimals(metadata)) {\n return metadata.decimals;\n }\n }\n return undefined;\n }\n\n /**\n * Handle balance update from BalanceFetcher.\n *\n * @param result - The balance fetch result.\n */\n async #handleBalanceUpdate(result: BalanceFetchResult): Promise<void> {\n const newBalances: Record<string, { amount: string }> = {};\n\n // Convert hex chain ID to CAIP-2 format\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n\n // Normalize asset IDs from BalanceFetcher (lowercase) to checksummed form\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const assetsInfo = this.#collectMetadataForBalances(\n normalizedBalances,\n caipChainId,\n );\n\n // Convert balances to human-readable format.\n // Resolution: state metadata → pipeline metadata; skip if decimals unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n const decimals = this.#pickValidDecimals(stateMetadata, pipelineMetadata);\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n assetsInfo,\n updateMode: 'merge',\n };\n\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance'],\n };\n\n log('Balance update response', {\n accountId: result.accountId,\n newBalanceCount: Object.keys(newBalances).length,\n });\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update assets', { error });\n });\n }\n }\n\n /**\n * Handle detection update from TokenDetector.\n *\n * @param result - The token detection result.\n */\n #handleDetectionUpdate(result: TokenDetectionResult): void {\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n });\n\n // Build new metadata from detected assets\n const newMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n if (result.detectedAssets.length > 0) {\n for (const asset of result.detectedAssets) {\n // Only include if we have metadata (symbol and decimals at minimum)\n if (asset.symbol && asset.decimals !== undefined) {\n newMetadata[asset.assetId] = {\n type: this.#getAssetType(asset.assetId),\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n }\n\n // Build new balances from detected tokens\n const newBalances: Record<string, { amount: string }> = {};\n if (result.detectedBalances.length > 0) {\n for (const balance of result.detectedBalances) {\n // Get decimals from the detected asset metadata\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n detectedAssets: {\n [result.accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsInfo: newMetadata,\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n updateMode: 'merge',\n };\n\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance', 'metadata', 'price'],\n };\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update detected assets', { error });\n });\n }\n }\n\n #subscribeToNetworkController(): void {\n this.#messenger.subscribe(\n 'NetworkController:stateChange',\n (networkState: NetworkState) => {\n log('NetworkController state changed');\n this.#clearProviderCache();\n this.#updateFromNetworkState(networkState);\n },\n );\n }\n\n #subscribeToTransactionEvents(): void {\n const unsubConfirmed = this.#messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n this.#onTransactionConfirmed.bind(this),\n );\n this.#unsubscribeTransactionConfirmed =\n typeof unsubConfirmed === 'function' ? unsubConfirmed : undefined;\n }\n\n #onTransactionConfirmed(payload: TransactionMeta): void {\n const hexChainId = payload?.chainId;\n if (!hexChainId) {\n return;\n }\n const caipChainId = `eip155:${parseInt(hexChainId, 16)}` as ChainId;\n this.#refreshBalanceForChains([caipChainId], 'transactionConfirmed').catch(\n (error) => {\n log('Failed to refresh balance after transaction confirmed', { error });\n },\n );\n }\n\n /**\n * Fetch balances for the given chains across all active subscriptions and\n * push updates to the controller.\n *\n * @param chainIds - CAIP-2 chain IDs to refresh.\n * @param context - Why the refresh was triggered (for logging).\n */\n async #refreshBalanceForChains(\n chainIds: ChainId[],\n context: 'transactionConfirmed' | 'polling' = 'polling',\n ): Promise<void> {\n const chainIdsSet = new Set(chainIds);\n const chainsToFetch = chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n return;\n }\n\n let appliedCount = 0;\n\n for (const subscription of this.#activeSubscriptions.values()) {\n const subscriptionChains = subscription.chains.filter((chainId) =>\n chainIdsSet.has(chainId),\n );\n if (subscriptionChains.length === 0) {\n continue;\n }\n\n const request: DataRequest = {\n accountsWithSupportedChains: subscription.accounts.map((account) => ({\n account,\n supportedChains: subscriptionChains,\n })),\n chainIds: subscriptionChains,\n dataTypes: ['balance'],\n };\n\n try {\n const response = await this.fetch(request);\n const balanceCount = response.assetsBalance\n ? Object.values(response.assetsBalance).reduce(\n (sum, accountBalances) =>\n sum + Object.keys(accountBalances).length,\n 0,\n )\n : 0;\n\n if (balanceCount === 0) {\n continue;\n }\n\n const responseWithMode: DataResponse = {\n ...response,\n updateMode: response.updateMode ?? 'merge',\n };\n\n await subscription.onAssetsUpdate(responseWithMode, request);\n appliedCount += 1;\n } catch (error) {\n log('Failed to fetch balance after transaction', {\n context,\n chains: subscriptionChains,\n error,\n });\n }\n }\n\n if (appliedCount === 0 && context === 'transactionConfirmed') {\n log('No RpcDataSource subscription covers chain after transaction', {\n chainsToFetch,\n });\n }\n }\n\n #initializeFromNetworkController(): void {\n log('Initializing from NetworkController');\n try {\n const networkState = this.#messenger.call('NetworkController:getState');\n this.#updateFromNetworkState(networkState);\n } catch (error) {\n log('Failed to initialize from NetworkController', error);\n }\n }\n\n /**\n * Re-read NetworkController state and refresh Rpc `activeChains` (e.g. when\n * network availability metadata changes after an EVM network switch).\n */\n refreshActiveChainsFromNetworkState(): void {\n this.#initializeFromNetworkController();\n }\n\n #updateFromNetworkState(networkState: NetworkState): void {\n const { networkConfigurationsByChainId, networksMetadata } = networkState;\n\n const chainStatuses: Record<ChainId, ChainStatus> = {};\n const activeChains: ChainId[] = [];\n\n for (const [hexChainId, config] of Object.entries(\n networkConfigurationsByChainId,\n )) {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const defaultRpcEndpoint =\n config.rpcEndpoints[config.defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n const { networkClientId } = defaultRpcEndpoint;\n const metadata = networksMetadata[networkClientId];\n\n const status: NetworkStatus =\n metadata?.status ?? ('unknown' as NetworkStatus);\n\n chainStatuses[caip2ChainId] = {\n chainId: caip2ChainId,\n status,\n name: config.name,\n nativeCurrency: config.nativeCurrency,\n networkClientId,\n };\n\n if (status === 'available' || status === 'unknown') {\n activeChains.push(caip2ChainId);\n }\n }\n\n log('Network state updated', {\n configuredChains: Object.keys(chainStatuses),\n activeChains,\n });\n\n // Check if chains changed\n const previousChains = [...this.#activeChains];\n const previousSet = new Set(previousChains);\n const hasChanges =\n previousChains.length !== activeChains.length ||\n activeChains.some((chain) => !previousSet.has(chain));\n\n // Update internal state and data source state before notifying, so that\n // when the controller handles the callback and calls getActiveChainsSync(),\n // it receives the updated chains (same order as AbstractDataSource.updateActiveChains).\n this.#chainStatuses = chainStatuses;\n this.#activeChains = activeChains;\n this.state.activeChains = activeChains;\n\n if (hasChanges) {\n this.#onActiveChainsUpdated(this.getName(), activeChains, previousChains);\n }\n }\n\n #getProvider(chainId: ChainId): Web3Provider | undefined {\n const cached = this.#providerCache.get(chainId);\n if (cached) {\n return cached;\n }\n\n const chainStatus = this.#chainStatuses[chainId];\n if (!chainStatus) {\n return undefined;\n }\n\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n chainStatus.networkClientId,\n );\n if (!networkClient?.provider) {\n return undefined;\n }\n const web3Provider = new Web3Provider(networkClient.provider);\n this.#providerCache.set(chainId, web3Provider);\n\n return web3Provider;\n } catch (error) {\n log('Failed to get provider for chain', { chainId, error });\n return undefined;\n }\n }\n\n /**\n * Get provider for MulticallClient using a hex chainId.\n *\n * @param hexChainId - The hex string representation of the chain id.\n * @returns An RpcProvider instance for the specified chain.\n */\n #getMulticallProvider(hexChainId: string): RpcProvider {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const web3Provider = this.#getProvider(caip2ChainId);\n\n if (!web3Provider) {\n throw new Error(`No provider available for chain ${hexChainId}`);\n }\n\n return {\n call: async (params: { to: string; data: string }): Promise<string> => {\n return web3Provider.call({\n to: params.to,\n data: params.data,\n });\n },\n getBalance: async (address: string): Promise<{ toString(): string }> => {\n const balance = await web3Provider.getBalance(address);\n return balance;\n },\n };\n }\n\n #clearProviderCache(): void {\n this.#providerCache.clear();\n }\n\n /**\n * Fetch the `decimals()` value from an ERC20 contract via RPC.\n *\n * @param chainId - CAIP-2 chain ID.\n * @param tokenAddress - The token contract address.\n * @returns The decimals value, or undefined if the call fails.\n */\n async #fetchDecimalsViaRpc(\n chainId: ChainId,\n tokenAddress: string,\n ): Promise<number | undefined> {\n try {\n const provider = this.#getProvider(chainId);\n if (!provider) {\n return undefined;\n }\n // ERC20 decimals() selector: keccak256(\"decimals()\") = 0x313ce567\n const result = await provider.call({\n to: tokenAddress,\n data: '0x313ce567',\n });\n if (!result || result === '0x') {\n return undefined;\n }\n const parsed = parseInt(result, 16);\n if (Number.isNaN(parsed) || parsed < 0 || parsed > 255) {\n return undefined;\n }\n return parsed;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Get the data source name.\n *\n * @returns The name of this data source.\n */\n /**\n * Get the status of all configured chains.\n *\n * @returns Record of chain statuses keyed by chain ID.\n */\n getChainStatuses(): Record<ChainId, ChainStatus> {\n return { ...this.#chainStatuses };\n }\n\n /**\n * Get the status of a specific chain.\n *\n * @param chainId - The chain ID to get status for.\n * @returns The chain status or undefined if not found.\n */\n getChainStatus(chainId: ChainId): ChainStatus | undefined {\n return this.#chainStatuses[chainId];\n }\n\n /**\n * Set the balance polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setBalancePollingInterval(interval: number): void {\n log('Setting balance polling interval', { interval });\n this.#balanceFetcher.setIntervalLength(interval);\n }\n\n /**\n * Get the current balance polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getBalancePollingInterval(): number | undefined {\n return this.#balanceFetcher.getIntervalLength();\n }\n\n /**\n * Set the token detection polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setDetectionPollingInterval(interval: number): void {\n log('Setting detection polling interval', { interval });\n this.#tokenDetector.setIntervalLength(interval);\n }\n\n /**\n * Get the current token detection polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getDetectionPollingInterval(): number | undefined {\n return this.#tokenDetector.getIntervalLength();\n }\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n if (!this.#isOnboarded()) {\n log('Skipping fetch - onboarding not complete');\n return {};\n }\n\n const response: DataResponse = {};\n\n const chainsToFetch = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n log('Fetch requested', {\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n requestedChains: request.chainIds,\n chainsToFetch,\n });\n\n if (chainsToFetch.length === 0) {\n log('No active chains to fetch');\n return response;\n }\n\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const failedChains: ChainId[] = [];\n\n // request.customAssets is flat. v6 resolves pin ownership from state so\n // each account only fetches its own pins; v5 applies the flat list as on main.\n const customAssetsByAccount = request.customAssets\n ? this.#getCustomAssetsByAccount()\n : {};\n\n // Fetch balances for each account and its supported chains (pre-computed in request)\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToFetch.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n const nativeAssetId = this.#getNativeAssetForChain(chainId);\n\n const shouldSkipNative = shouldSkipNativeForCaipChainId(chainId);\n const assetsToFetch: AssetFetchEntry[] = [];\n if (!shouldSkipNative) {\n // Build a single AssetFetchEntry[] for native + custom ERC-20s\n assetsToFetch.push({ assetId: nativeAssetId, address: ZERO_ADDRESS });\n }\n\n if (request.customAssets) {\n const existingMetadata = this.#getExistingAssetsMetadata();\n if (this.#isBalanceV6Enabled()) {\n this.#appendRequestCustomErc20sV6(\n assetsToFetch,\n request.customAssets,\n chainId,\n existingMetadata,\n new Set(\n (customAssetsByAccount[accountId] ?? []).map(normalizeAssetId),\n ),\n );\n } else {\n this.#appendRequestCustomErc20sV5(\n assetsToFetch,\n request.customAssets,\n chainId,\n existingMetadata,\n );\n }\n }\n\n try {\n const result = await this.#balanceFetcher.fetchBalancesForAssets(\n hexChainId,\n accountId,\n address as Address,\n assetsToFetch,\n );\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset IDs from BalanceFetcher (which uses lowercase\n // addresses) to checksummed form so they match assetsInfo state keys.\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const balanceMetadata = this.#collectMetadataForBalances(\n normalizedBalances,\n chainId,\n );\n Object.assign(assetsInfo, balanceMetadata);\n\n // Convert balances to human-readable format using decimals from\n // assetsInfo state (which includes pendingMetadata from addCustomAsset).\n // Resolution: state → pipeline metadata → RPC `decimals()`; omit balance if still unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n let decimals: number | undefined = this.#pickValidDecimals(\n stateMetadata,\n pipelineMetadata,\n );\n\n if (decimals === undefined) {\n const parsed = parseCaipAssetType(balance.assetId);\n if (this.#getAssetType(balance.assetId) === 'erc20') {\n decimals = await this.#fetchDecimalsViaRpc(\n chainId,\n parsed.assetReference,\n );\n }\n }\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n assetsBalance[accountId][balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n } catch (error) {\n log('Failed to fetch balance', { address, chainId, error });\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n if (!shouldSkipNative) {\n assetsBalance[accountId][nativeAssetId] = { amount: '0' };\n }\n // On error, emit a stub only when no valid metadata exists in state\n // yet. Re-emitting existing metadata would overwrite richer entries\n // (e.g. image/description added by AccountsAPI) with a simpler stub.\n const existingNativeMeta =\n this.#getExistingAssetsMetadata()[nativeAssetId];\n if (!this.#hasValidDecimals(existingNativeMeta)) {\n const chainStatus = this.#chainStatuses[chainId];\n if (chainStatus) {\n assetsInfo[nativeAssetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n }\n\n if (!failedChains.includes(chainId)) {\n failedChains.push(chainId);\n }\n }\n }\n }\n\n if (failedChains.length > 0) {\n log('Fetch PARTIAL - some chains failed', {\n successChains: chainsToFetch.filter(\n (chain) => !failedChains.includes(chain),\n ),\n failedChains,\n });\n\n response.errors = {};\n for (const chainId of failedChains) {\n response.errors[chainId] = 'RPC fetch failed';\n }\n } else {\n log('Fetch SUCCESS', {\n chains: chainsToFetch,\n accountCount: Object.keys(assetsBalance).length,\n });\n }\n\n response.assetsBalance = assetsBalance;\n\n // Include metadata for native tokens if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n response.updateMode = 'merge';\n\n return response;\n }\n\n /**\n * Run token detection for an account on a chain.\n *\n * @param chainId - The chain ID to detect tokens on.\n * @param account - The account to detect tokens for.\n * @returns Promise resolving to a DataResponse with detected assets.\n */\n async detectTokens(\n chainId: ChainId,\n account: InternalAccount,\n ): Promise<DataResponse> {\n if (!this.#tokenDetectionEnabled() || !this.#useExternalService()) {\n return {};\n }\n\n const hexChainId = caipChainIdToHex(chainId);\n const { address, id: accountId } = account;\n\n log('Running token detection', { chainId, accountId });\n\n try {\n const result = await this.#tokenDetector.detectTokens(\n hexChainId,\n accountId,\n address as Address,\n {\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n },\n );\n\n if (result.detectedAssets.length === 0) {\n log('No new tokens detected');\n return {};\n }\n\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n chainId,\n accountId,\n });\n\n // Convert detected assets to DataResponse format\n const balances: Record<Caip19AssetId, AssetBalance> = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n\n // Build metadata from detected assets\n for (const asset of result.detectedAssets) {\n if (asset.symbol && asset.decimals !== undefined) {\n assetsInfo[asset.assetId] = {\n type: this.#getAssetType(asset.assetId),\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n\n // Add balances for detected tokens (converted to human-readable format)\n for (const balance of result.detectedBalances) {\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n balances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n const response: DataResponse = {\n detectedAssets: {\n [accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsBalance: {\n [accountId]: balances,\n },\n };\n\n // Include metadata if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n return response;\n } catch (error) {\n log('Token detection failed', { chainId, accountId, error });\n return {};\n }\n }\n\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n log('Middleware fetching', {\n chains: supportedChains,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n });\n\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] ??= {};\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n\n if (response.assetsInfo) {\n context.response.assetsInfo ??= {};\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n\n // Propagate per-chain fetch errors so downstream consumers (e.g.\n // RpcFallbackMiddleware) can tell which chains this source actually\n // failed on and discard their failure stubs instead of merging them.\n if (response.errors) {\n context.response.errors = {\n ...context.response.errors,\n ...response.errors,\n };\n }\n\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n\n return next({\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n });\n }\n\n return next(context);\n };\n }\n\n /**\n * RPC is the terminal claimer on the asset axis: it claims every EVM pin it\n * has a provider for, even on chains claimed by higher-priority sources.\n * Pins outside the regular RPC assignment get an asset-scoped poll (see\n * `subscribe`).\n *\n * @param customAssets - Candidate CAIP-19 asset IDs still unclaimed.\n * @param assignedChains - Chains assigned to RPC; availability fallback\n * before network state is applied.\n * @returns The claimed subset of `customAssets`.\n */\n claimCustomAssets(\n customAssets: Caip19AssetId[],\n assignedChains: ChainId[],\n ): Caip19AssetId[] {\n const available = new Set<ChainId>(\n this.#activeChains.length > 0 ? this.#activeChains : assignedChains,\n );\n return customAssets.filter((assetId) => {\n try {\n const parsed = parseCaipAssetType(assetId);\n return (\n parsed.chain.namespace === KnownCaipNamespace.Eip155 &&\n available.has(parsed.chainId)\n );\n } catch {\n return false;\n }\n });\n }\n\n /**\n * Subscribe to updates for the given request.\n * Starts polling through BalanceFetcher and TokenDetector.\n *\n * @param subscriptionRequest - The subscription request details.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n if (!this.#isOnboarded()) {\n log('Skipping subscribe - onboarding not complete');\n return;\n }\n\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Use request.chainIds when activeChains is not yet populated (e.g. before\n // NetworkController state has been applied) so polling can start.\n const chainsToSubscribe =\n this.#activeChains.length > 0\n ? request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n )\n : request.chainIds;\n\n // Pins claimed on chains outside the regular RPC assignment get an\n // asset-scoped poll below.\n const supplementalChains = this.#getSupplementalCustomAssetChains(\n request,\n chainsToSubscribe,\n );\n\n log('Subscribe requested', {\n subscriptionId,\n isUpdate,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n chainsToSubscribe,\n supplementalChains,\n activeChainsFallback: this.#activeChains.length === 0,\n });\n\n if (chainsToSubscribe.length === 0 && supplementalChains.length === 0) {\n log('No active chains to subscribe');\n return;\n }\n\n // Handle subscription update - restart polling for new chains\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n log('Updating existing subscription - restarting polling', {\n subscriptionId,\n existingChains: existing.chains,\n newChains: chainsToSubscribe,\n });\n // Don't return early - continue to unsubscribe and restart polling\n }\n }\n\n // Clean up existing subscription (stops old polling)\n await this.unsubscribe(subscriptionId);\n // Start polling through BalanceFetcher and TokenDetector\n const balancePollingTokens: string[] = [];\n const detectionPollingTokens: string[] = [];\n\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToSubscribe.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n // Start balance polling\n const balanceInput: BalancePollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n ...(request.customAssetsOnly === true\n ? { customAssetsOnly: true }\n : {}),\n };\n const balanceToken = this.#balanceFetcher.startPolling(balanceInput);\n balancePollingTokens.push(balanceToken);\n\n if (\n request.customAssetsOnly !== true &&\n this.#tokenDetectionEnabled() &&\n this.#useExternalService()\n ) {\n const detectionInput: DetectionPollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n };\n const detectionToken =\n this.#tokenDetector.startPolling(detectionInput);\n detectionPollingTokens.push(detectionToken);\n }\n }\n }\n\n // Asset-scoped polls on chains another source claimed: poll ONLY the\n // claimed pins to avoid double-polling tracked balances. Pin changes\n // re-run the subscription pass, which rebuilds these polls.\n // Asset-scoped polls on chains another source claimed (v6 only).\n if (this.#isBalanceV6Enabled() && supplementalChains.length > 0) {\n const supplemental = new Set<ChainId>(supplementalChains);\n const claimedAssetsByChain = new Map<ChainId, Caip19AssetId[]>();\n for (const assetId of request.customAssets ?? []) {\n try {\n const { chainId } = parseCaipAssetType(assetId);\n if (supplemental.has(chainId)) {\n const chainAssets = claimedAssetsByChain.get(chainId) ?? [];\n chainAssets.push(assetId);\n claimedAssetsByChain.set(chainId, chainAssets);\n }\n } catch {\n // Skip unparseable asset IDs\n }\n }\n // request.customAssets is flat; ownership comes from controller state.\n const customAssetsByAccount = this.#getCustomAssetsByAccount();\n for (const { account } of request.accountsWithSupportedChains) {\n const pinned = new Set(customAssetsByAccount[account.id] ?? []);\n if (pinned.size === 0) {\n continue;\n }\n for (const [chainId, chainAssets] of claimedAssetsByChain) {\n // Sorted so the polling input (the dedupe key) is deterministic.\n const assetIds = chainAssets\n .filter((assetId) => pinned.has(assetId))\n .sort();\n if (assetIds.length === 0) {\n continue;\n }\n const balanceInput: BalancePollingInput = {\n chainId: caipChainIdToHex(chainId),\n accountId: account.id,\n accountAddress: account.address as Address,\n assetIds,\n };\n balancePollingTokens.push(\n this.#balanceFetcher.startPolling(balanceInput),\n );\n }\n }\n }\n\n // Store subscription data\n const accounts = request.accountsWithSupportedChains.map(\n (entry) => entry.account,\n );\n this.#activeSubscriptions.set(subscriptionId, {\n balancePollingTokens,\n detectionPollingTokens,\n chains: chainsToSubscribe,\n accounts,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n log('Subscription SUCCESS', {\n subscriptionId,\n chains: chainsToSubscribe,\n balancePollingCount: balancePollingTokens.length,\n detectionPollingCount: detectionPollingTokens.length,\n });\n }\n\n /**\n * Unsubscribe from updates and stop polling.\n *\n * @param subscriptionId - The subscription ID to unsubscribe.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n // Stop balance polling\n for (const token of subscription.balancePollingTokens) {\n this.#balanceFetcher.stopPollingByPollingToken(token);\n }\n\n // Stop detection polling\n for (const token of subscription.detectionPollingTokens) {\n this.#tokenDetector.stopPollingByPollingToken(token);\n }\n\n this.#activeSubscriptions.delete(subscriptionId);\n log('Unsubscribed and stopped polling', { subscriptionId });\n }\n }\n\n /**\n * Chains needing a supplemental asset-scoped poll: chains of pins not\n * covered by the regular RPC polling. Only EVM chains RPC can serve;\n * malformed IDs are skipped.\n *\n * @param request - The subscription's data request (carries `customAssets`).\n * @param chainsToSubscribe - Chains covered by the regular polling loop.\n * @returns Chains requiring an asset-scoped poll.\n */\n #getSupplementalCustomAssetChains(\n request: DataRequest,\n chainsToSubscribe: ChainId[],\n ): ChainId[] {\n if (!request.customAssets || request.customAssets.length === 0) {\n return [];\n }\n\n const covered = new Set<ChainId>(chainsToSubscribe);\n const chains = new Set<ChainId>();\n\n for (const assetId of request.customAssets) {\n let parsed: ReturnType<typeof parseCaipAssetType>;\n try {\n parsed = parseCaipAssetType(assetId);\n } catch {\n continue;\n }\n const { chainId } = parsed;\n if (\n parsed.chain.namespace === KnownCaipNamespace.Eip155 &&\n !covered.has(chainId) &&\n (this.#activeChains.length === 0 ||\n this.#activeChains.includes(chainId))\n ) {\n chains.add(chainId);\n }\n }\n\n return [...chains];\n }\n\n /**\n * v5: include every `request.customAssets` ERC-20 on this chain (main behavior).\n * Delete with the rest of the v5 path when `assetsAccountsApiV6` is the default.\n *\n * @param assetsToFetch - Native/custom entries for this account-chain fetch.\n * @param customAssets - Flat pin list from the data request.\n * @param chainId - Chain being fetched.\n * @param existingMetadata - Metadata already in AssetsController state.\n */\n #appendRequestCustomErc20sV5(\n assetsToFetch: AssetFetchEntry[],\n customAssets: Caip19AssetId[],\n chainId: ChainId,\n existingMetadata: Record<Caip19AssetId, AssetMetadata>,\n ): void {\n for (const assetId of customAssets) {\n try {\n const parsed = parseCaipAssetType(assetId);\n const assetChainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n if (\n assetChainId === chainId &&\n this.#getAssetType(assetId) === 'erc20'\n ) {\n const tokenAddress = parsed.assetReference.toLowerCase() as Address;\n const normalizedId = normalizeAssetId(assetId);\n const decimals = existingMetadata[normalizedId]?.decimals;\n\n assetsToFetch.push({\n assetId,\n address: tokenAddress,\n decimals,\n });\n }\n } catch {\n // Skip unparseable asset IDs\n }\n }\n }\n\n /**\n * v6: include only pins owned by this account on this chain.\n *\n * @param assetsToFetch - Native/custom entries for this account-chain fetch.\n * @param customAssets - Flat pin list from the data request.\n * @param chainId - Chain being fetched.\n * @param existingMetadata - Metadata already in AssetsController state.\n * @param pinnedByAccount - This account's pins from controller state.\n */\n #appendRequestCustomErc20sV6(\n assetsToFetch: AssetFetchEntry[],\n customAssets: Caip19AssetId[],\n chainId: ChainId,\n existingMetadata: Record<Caip19AssetId, AssetMetadata>,\n pinnedByAccount: Set<Caip19AssetId>,\n ): void {\n for (const assetId of customAssets) {\n try {\n const parsed = parseCaipAssetType(assetId);\n const assetChainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n const normalizedId = normalizeAssetId(assetId);\n if (\n assetChainId === chainId &&\n pinnedByAccount.has(normalizedId) &&\n this.#getAssetType(assetId) === 'erc20'\n ) {\n const tokenAddress = parsed.assetReference.toLowerCase() as Address;\n const decimals = existingMetadata[normalizedId]?.decimals;\n\n assetsToFetch.push({\n assetId,\n address: tokenAddress,\n decimals,\n });\n }\n } catch {\n // Skip unparseable asset IDs\n }\n }\n }\n\n /**\n * Get per-account pins from AssetsController state — the request's flat\n * `customAssets` list carries no account association.\n *\n * @returns Record of account ID to pinned CAIP-19 asset IDs.\n */\n #getCustomAssetsByAccount(): Record<string, Caip19AssetId[]> {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n return (state.customAssets ?? {}) as Record<string, Caip19AssetId[]>;\n } catch (error) {\n log('Failed to get customAssets from state', { error });\n return {};\n }\n }\n\n /**\n * Get existing assets metadata from AssetsController state.\n * Used to include metadata for ERC20 tokens when returning balance updates.\n *\n * @returns Record of asset IDs to their metadata.\n */\n #getExistingAssetsMetadata(): Record<Caip19AssetId, AssetMetadata> {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n return state.assetsInfo ?? {};\n } catch (error) {\n log('Failed to get existing assets metadata', { error });\n return {};\n }\n }\n\n /**\n * Destroy the data source and clean up resources.\n */\n destroy(): void {\n log('Destroying RpcDataSource');\n\n this.#unsubscribeTransactionConfirmed?.();\n\n // Stop all polling\n this.#balanceFetcher.stopAllPolling();\n this.#tokenDetector.stopAllPolling();\n\n // Clear subscriptions\n this.#activeSubscriptions.clear();\n\n // Clear caches\n this.#providerCache.clear();\n }\n}\n\nexport function createRpcDataSource(\n options: RpcDataSourceOptions,\n): RpcDataSource {\n return new RpcDataSource(options);\n}\n"]}
@@ -61,7 +61,7 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
61
61
  * @param input - The polling input.
62
62
  */
63
63
  async _executePoll(input) {
64
- const result = await __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_fetchBalances).call(this, input.chainId, input.accountId, input.accountAddress, input.customAssetsOnly === true);
64
+ const result = await __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_fetchBalances).call(this, input.chainId, input.accountId, input.accountAddress, input.assetIds, input.customAssetsOnly === true);
65
65
  if (__classPrivateFieldGet(this, _BalanceFetcher_onBalanceUpdate, "f") && result.balances.length > 0) {
66
66
  await __classPrivateFieldGet(this, _BalanceFetcher_onBalanceUpdate, "f").call(this, result);
67
67
  }
@@ -124,8 +124,7 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
124
124
  }
125
125
  }
126
126
  exports.BalanceFetcher = BalanceFetcher;
127
- _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new WeakMap(), _BalanceFetcher_config = new WeakMap(), _BalanceFetcher_isNativeAsset = new WeakMap(), _BalanceFetcher_onBalanceUpdate = new WeakMap(), _BalanceFetcher_instances = new WeakSet(), _BalanceFetcher_getAssetsToFetch = function _BalanceFetcher_getAssetsToFetch(chainId, accountId, customAssetsOnly) {
128
- const state = __classPrivateFieldGet(this, _BalanceFetcher_messenger, "f").call('AssetsController:getState');
127
+ _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new WeakMap(), _BalanceFetcher_config = new WeakMap(), _BalanceFetcher_isNativeAsset = new WeakMap(), _BalanceFetcher_onBalanceUpdate = new WeakMap(), _BalanceFetcher_instances = new WeakSet(), _BalanceFetcher_getAssetsToFetch = function _BalanceFetcher_getAssetsToFetch(chainId, accountId, assetIds, customAssetsOnly = false) {
129
128
  // Convert hex chainId to decimal for CAIP-2 matching
130
129
  // This is safe because we are filtring with an accountId that is for evm balances only
131
130
  const chainIdDecimal = parseInt(chainId, 16).toString();
@@ -147,9 +146,18 @@ _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new
147
146
  : parsed.assetReference.toLowerCase(),
148
147
  });
149
148
  };
150
- // 1. Assets already tracked with a balance entry — only when not in
151
- // "customAssetsOnly" mode (otherwise another data source is already
152
- // refreshing them and we'd double-poll).
149
+ // Asset-scoped poll: fetch only the input's assets; tracked balances on
150
+ // this chain are another source's responsibility.
151
+ if (assetIds) {
152
+ for (const assetId of assetIds) {
153
+ collect(assetId);
154
+ }
155
+ return Array.from(assetsToFetch.values());
156
+ }
157
+ const state = __classPrivateFieldGet(this, _BalanceFetcher_messenger, "f").call('AssetsController:getState');
158
+ // Assets tracked with a balance entry — only when not in
159
+ // "customAssetsOnly" mode (otherwise another data source is already
160
+ // refreshing them and we'd double-poll).
153
161
  if (!customAssetsOnly) {
154
162
  const accountBalances = state?.assetsBalance?.[accountId];
155
163
  if (accountBalances) {
@@ -158,10 +166,9 @@ _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new
158
166
  }
159
167
  }
160
168
  }
161
- // 2. User-added custom assets — RPC is the sole balance fetcher for
162
- // these, so they must be polled even if they have no balance entry
163
- // yet (e.g. zero balance, first fetch failed, or state was hydrated
164
- // from disk before any successful fetch).
169
+ // User-added custom assets — on the v5 path RPC is the sole balance
170
+ // fetcher for these, so they must be polled even if they have no balance
171
+ // entry yet. On the v6 path they are usually already in `assetsBalance`.
165
172
  const customAssets = state?.customAssets?.[accountId];
166
173
  if (customAssets) {
167
174
  for (const assetId of customAssets) {
@@ -177,11 +184,13 @@ _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new
177
184
  * @param chainId - Hex chain ID.
178
185
  * @param accountId - Account UUID.
179
186
  * @param accountAddress - On-chain address of the account.
187
+ * @param assetIds - When present, fetch exactly these assets instead of the
188
+ * tracked `assetsBalance` entries.
180
189
  * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.
181
190
  * @returns Balance fetch result.
182
191
  */
183
- async function _BalanceFetcher_fetchBalances(chainId, accountId, accountAddress, customAssetsOnly) {
184
- const assets = __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_getAssetsToFetch).call(this, chainId, accountId, customAssetsOnly);
192
+ async function _BalanceFetcher_fetchBalances(chainId, accountId, accountAddress, assetIds, customAssetsOnly = false) {
193
+ const assets = __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_getAssetsToFetch).call(this, chainId, accountId, assetIds, customAssetsOnly);
185
194
  return this.fetchBalancesForAssets(chainId, accountId, accountAddress, assets);
186
195
  }, _BalanceFetcher_processBalanceResponses = function _BalanceFetcher_processBalanceResponses(responses, accumulator, chainId, accountId, timestamp, entryByAddress) {
187
196
  const { balances, failedAddresses } = accumulator;
@@ -1 +1 @@
1
- {"version":3,"file":"BalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,qEAAmF;AACnF,2CAAqD;AAErD,+DAA2D;AAc3D,iDAA4D;AAE5D,MAAM,wBAAwB,GAAG,KAAM,CAAC,CAAC,aAAa;AA4CtD;;;;;;;;GAQG;AACH,MAAa,cAAe,SAAQ,IAAA,wDAAmC,GAAuB;IAa5F,YACE,eAAgC,EAChC,SAAkC,EAClC,MAA4B;QAE5B,KAAK,EAAE,CAAC;;QAjBD,kDAAkC;QAElC,4CAAoC;QAEpC,yCAEP;QAEO,gDAAoD;QAE7D,kDAAsD;QAQpD,uBAAA,IAAI,mCAAoB,eAAe,MAAA,CAAC;QACxC,uBAAA,IAAI,6BAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,0BAAW;YACb,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,GAAG;YAChD,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,KAAK;SACnD,MAAA,CAAC;QACF,uBAAA,IAAI,iCAAkB,MAAM,CAAC,aAAa,MAAA,CAAC;QAE3C,2BAA2B;QAC3B,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,eAAe,IAAI,wBAAwB,CAAC,CAAC;IAC9E,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,QAAiC;QAClD,uBAAA,IAAI,mCAAoB,QAAQ,MAAA,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,KAA0B;QAC3C,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,gEAAe,MAAnB,IAAI,EACvB,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,cAAc,EACpB,KAAK,CAAC,gBAAgB,KAAK,IAAI,CAChC,CAAC;QAEF,IAAI,uBAAA,IAAI,uCAAiB,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,MAAM,uBAAA,IAAI,uCAAiB,MAArB,IAAI,EAAkB,MAAM,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAmGD;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,sBAAsB,CAC1B,OAAgB,EAChB,SAAoB,EACpB,cAAuB,EACvB,MAAyB;QAEzB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,oEAAoE;QACpE,sEAAsE;QACtE,MAAM,eAAe,GAAuB,EAAE,CAAC;QAC/C,MAAM,cAAc,GAAG,IAAI,GAAG,EAA2B,CAAC;QAE1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;gBACrC,SAAS,CAAC,cAAc;YAC1B,CAAC;YAED,cAAc,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACxC,eAAe,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,OAAO;gBACP,SAAS;gBACT,cAAc;gBACd,QAAQ,EAAE,EAAE;gBACZ,eAAe,EAAE,EAAE;gBACnB,SAAS;aACV,CAAC;QACJ,CAAC;QAOD,MAAM,MAAM,GAAG,MAAM,IAAA,kCAAuB,EAG1C;YACA,MAAM,EAAE,eAAe;YACvB,SAAS,EAAE,uBAAA,IAAI,8BAAQ,CAAC,gBAAgB;YACxC,aAAa,EAAE;gBACb,QAAQ,EAAE,EAAE;gBACZ,eAAe,EAAE,EAAE;aACpB;YACD,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE;gBACxC,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,uCAAiB,CAAC,cAAc,CAC1D,OAAO,EACP,KAAK,EACL,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAChC,CAAC;gBAEF,OAAO,uBAAA,IAAI,0EAAyB,MAA7B,IAAI,EACT,SAAS,EACT,aAAiC,EACjC,OAAO,EACP,SAAS,EACT,SAAS,EACT,cAAc,CACf,CAAC;YACJ,CAAC;SACF,CAAC,CAAC;QAEH,OAAO;YACL,OAAO;YACP,SAAS;YACT,cAAc;YACd,GAAG,MAAM;YACT,SAAS;SACV,CAAC;IACJ,CAAC;CAqFF;AAvUD,wCAuUC;4VAlQG,OAAgB,EAChB,SAAoB,EACpB,gBAAyB;IAEzB,MAAM,KAAK,GAAG,uBAAA,IAAI,iCAAW,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAEhE,qDAAqD;IACrD,uFAAuF;IACvF,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAExD,MAAM,aAAa,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEzD,MAAM,OAAO,GAAG,CAAC,OAAsB,EAAQ,EAAE;QAC/C,MAAM,MAAM,GAAG,IAAA,0BAAkB,EAAC,OAAO,CAAC,CAAC;QAE3C,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,KAAK,cAAc,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QAEhD,IAAI,aAAa,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACzC,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,uBAAA,IAAI,qCAAe,MAAnB,IAAI,EAAgB,OAAO,CAAC,CAAC;QAE9C,aAAa,CAAC,GAAG,CAAC,iBAAiB,EAAE;YACnC,OAAO;YACP,OAAO,EAAE,QAAQ;gBACf,CAAC,CAAC,2BAAY;gBACd,CAAC,CAAE,MAAM,CAAC,cAAc,CAAC,WAAW,EAAc;SACrD,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,oEAAoE;IACpE,uEAAuE;IACvE,4CAA4C;IAC5C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,eAAe,GAAG,KAAK,EAAE,aAAa,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,eAAe,EAAE,CAAC;YACpB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,eAAe,CAAoB,EAAE,CAAC;gBACtE,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED,oEAAoE;IACpE,sEAAsE;IACtE,uEAAuE;IACvE,6CAA6C;IAC7C,MAAM,YAAY,GAAG,KAAK,EAAE,YAAY,EAAE,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,KAAK,MAAM,OAAO,IAAI,YAA+B,EAAE,CAAC;YACtD,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,wCACH,OAAgB,EAChB,SAAoB,EACpB,cAAuB,EACvB,gBAAyB;IAEzB,MAAM,MAAM,GAAG,uBAAA,IAAI,mEAAkB,MAAtB,IAAI,EAAmB,OAAO,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE5E,OAAO,IAAI,CAAC,sBAAsB,CAChC,OAAO,EACP,SAAS,EACT,cAAc,EACd,MAAM,CACP,CAAC;AACJ,CAAC,6FA2FC,SAA8B,EAC9B,WAGC,EACD,OAAgB,EAChB,SAAoB,EACpB,SAAiB,EACjB,cAA4C;IAK5C,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,WAAW,CAAC;IAElD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QACzD,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,GAAG,CAAC;QACxC,MAAM,QAAQ,GAAG,YAAY,KAAK,2BAAY,CAAC,WAAW,EAAE,CAAC;QAE7D,IAAI,QAA4B,CAAC;QACjC,IAAI,gBAAwB,CAAC;QAC7B,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,GAAG,EAAE,CAAC;YACd,gBAAgB,GAAG,uBAAA,IAAI,gEAAe,MAAnB,IAAI,EAAgB,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACxC,gBAAgB,GAAG,OAAO,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YAC1B,gBAAgB,GAAG,uBAAA,IAAI,gEAAe,MAAnB,IAAI,EAAgB,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,YAAY,GAAiB;YACjC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS;YACT,OAAO;YACP,OAAO;YACP,gBAAgB;YAChB,SAAS;SACV,CAAC;QACF,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,YAAY,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACnC,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;AACvC,CAAC,yEAEc,UAAkB,EAAE,QAAgB;IACjD,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,IAAI,QAAQ,CAAC,CAAC;QAEvC,MAAM,WAAW,GAAG,aAAa,GAAG,OAAO,CAAC;QAC5C,MAAM,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;QAC1C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACnE,MAAM,iBAAiB,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAE5D,IAAI,iBAAiB,KAAK,EAAE,EAAE,CAAC;YAC7B,OAAO,WAAW,CAAC,QAAQ,EAAE,CAAC;QAChC,CAAC;QAED,OAAO,GAAG,WAAW,IAAI,iBAAiB,EAAE,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,UAAU,CAAC;IACpB,CAAC;AACH,CAAC","sourcesContent":["import { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\nimport { parseCaipAssetType } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants.js';\nimport type { MulticallClient } from '../clients/index.js';\nimport type {\n AccountId,\n Address,\n AssetBalance,\n AssetFetchEntry,\n AssetsBalanceState,\n BalanceFetchResult,\n BalanceOfRequest,\n BalanceOfResponse,\n CaipAssetType,\n ChainId,\n} from '../types/index.js';\nimport { reduceInBatchesSerially } from '../utils/index.js';\n\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\n\n/**\n * Minimal messenger interface for BalanceFetcher.\n */\nexport type BalanceFetcherMessenger = {\n call: (action: 'AssetsController:getState') => AssetsBalanceState;\n};\n\nexport type BalanceFetcherConfig = {\n defaultBatchSize?: number;\n defaultTimeoutMs?: number;\n /** Polling interval in ms (default: 30s) */\n pollingInterval?: number;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: CaipAssetType) => boolean;\n};\n\n/**\n * Polling input for BalanceFetcher - identifies what to poll for.\n */\nexport type BalancePollingInput = {\n /** Chain ID (hex format) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n /**\n * When true, only fetch balances for entries in `state.customAssets`,\n * skipping `state.assetsBalance`. Used by the supplemental RPC\n * subscription on chains that another data source is already covering\n * for regular balance refreshes.\n */\n customAssetsOnly?: boolean;\n};\n\n/**\n * Callback type for balance updates.\n */\nexport type OnBalanceUpdateCallback = (\n result: BalanceFetchResult,\n) => void | Promise<void>;\n\n/**\n * BalanceFetcher - Fetches token balances via multicall.\n * Extends StaticIntervalPollingControllerOnly for built-in polling support.\n *\n * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses\n * (or uses the zero address for native assets) and maps multicall responses\n * back to the original asset IDs. This ensures the returned balance entries\n * always carry the correct identifier regardless of chain.\n */\nexport class BalanceFetcher extends StaticIntervalPollingControllerOnly<BalancePollingInput>() {\n readonly #multicallClient: MulticallClient;\n\n readonly #messenger: BalanceFetcherMessenger;\n\n readonly #config: Required<\n Omit<BalanceFetcherConfig, 'pollingInterval' | 'isNativeAsset'>\n >;\n\n readonly #isNativeAsset: (assetId: CaipAssetType) => boolean;\n\n #onBalanceUpdate: OnBalanceUpdateCallback | undefined;\n\n constructor(\n multicallClient: MulticallClient,\n messenger: BalanceFetcherMessenger,\n config: BalanceFetcherConfig,\n ) {\n super();\n this.#multicallClient = multicallClient;\n this.#messenger = messenger;\n this.#config = {\n defaultBatchSize: config.defaultBatchSize ?? 300,\n defaultTimeoutMs: config.defaultTimeoutMs ?? 30000,\n };\n this.#isNativeAsset = config.isNativeAsset;\n\n // Set the polling interval\n this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);\n }\n\n /**\n * Set the callback to receive balance updates during polling.\n *\n * @param callback - Function to call with balance results.\n */\n setOnBalanceUpdate(callback: OnBalanceUpdateCallback): void {\n this.#onBalanceUpdate = callback;\n }\n\n /**\n * Execute a poll cycle (required by base class).\n * Fetches balances and calls the update callback.\n *\n * @param input - The polling input.\n */\n async _executePoll(input: BalancePollingInput): Promise<void> {\n const result = await this.#fetchBalances(\n input.chainId,\n input.accountId,\n input.accountAddress,\n input.customAssetsOnly === true,\n );\n\n if (this.#onBalanceUpdate && result.balances.length > 0) {\n await this.#onBalanceUpdate(result);\n }\n }\n\n /**\n * Return asset fetch entries tracked in state for the given account and\n * chain. Both native (`slip44:`) and ERC-20 (`erc20:`) entries are included.\n *\n * @param chainId - Hex chain ID (e.g. \"0x1\").\n * @param accountId - Account UUID.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Array of asset fetch entries from state for the requested chain.\n */\n #getAssetsToFetch(\n chainId: ChainId,\n accountId: AccountId,\n customAssetsOnly: boolean,\n ): AssetFetchEntry[] {\n const state = this.#messenger.call('AssetsController:getState');\n\n // Convert hex chainId to decimal for CAIP-2 matching\n // This is safe because we are filtring with an accountId that is for evm balances only\n const chainIdDecimal = parseInt(chainId, 16).toString();\n\n const assetsToFetch = new Map<string, AssetFetchEntry>();\n\n const collect = (assetId: CaipAssetType): void => {\n const parsed = parseCaipAssetType(assetId);\n\n if (parsed.chain.reference !== chainIdDecimal) {\n return;\n }\n\n const normalizedAssetId = assetId.toLowerCase();\n\n if (assetsToFetch.has(normalizedAssetId)) {\n return;\n }\n\n const isNative = this.#isNativeAsset(assetId);\n\n assetsToFetch.set(normalizedAssetId, {\n assetId,\n address: isNative\n ? ZERO_ADDRESS\n : (parsed.assetReference.toLowerCase() as Address),\n });\n };\n\n // 1. Assets already tracked with a balance entry — only when not in\n // \"customAssetsOnly\" mode (otherwise another data source is already\n // refreshing them and we'd double-poll).\n if (!customAssetsOnly) {\n const accountBalances = state?.assetsBalance?.[accountId];\n if (accountBalances) {\n for (const assetId of Object.keys(accountBalances) as CaipAssetType[]) {\n collect(assetId);\n }\n }\n }\n\n // 2. User-added custom assets — RPC is the sole balance fetcher for\n // these, so they must be polled even if they have no balance entry\n // yet (e.g. zero balance, first fetch failed, or state was hydrated\n // from disk before any successful fetch).\n const customAssets = state?.customAssets?.[accountId];\n if (customAssets) {\n for (const assetId of customAssets as CaipAssetType[]) {\n collect(assetId);\n }\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n /**\n * Fetch balances for assets already tracked in state for the given\n * account and chain.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Balance fetch result.\n */\n async #fetchBalances(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n customAssetsOnly: boolean,\n ): Promise<BalanceFetchResult> {\n const assets = this.#getAssetsToFetch(chainId, accountId, customAssetsOnly);\n\n return this.fetchBalancesForAssets(\n chainId,\n accountId,\n accountAddress,\n assets,\n );\n }\n\n /**\n * Fetch balances for the given assets via multicall.\n *\n * Each entry bundles a CAIP-19 asset ID with its on-chain address and\n * optional decimals.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param assets - Asset fetch entries to fetch balances for.\n * @returns Balance fetch result.\n */\n async fetchBalancesForAssets(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n assets: AssetFetchEntry[],\n ): Promise<BalanceFetchResult> {\n const timestamp = Date.now();\n\n // Build a single map keyed by lowercase address that holds all info\n // needed to match multicall responses back to their original entries.\n const balanceRequests: BalanceOfRequest[] = [];\n const entryByAddress = new Map<string, AssetFetchEntry>();\n\n for (const entry of assets) {\n const lowerAddress = entry.address.toLowerCase();\n if (entryByAddress.has(lowerAddress)) {\n continue; // deduplicate\n }\n\n entryByAddress.set(lowerAddress, entry);\n balanceRequests.push({ tokenAddress: entry.address, accountAddress });\n }\n\n if (balanceRequests.length === 0) {\n return {\n chainId,\n accountId,\n accountAddress,\n balances: [],\n failedAddresses: [],\n timestamp,\n };\n }\n\n type FetchAccumulator = {\n balances: AssetBalance[];\n failedAddresses: Address[];\n };\n\n const result = await reduceInBatchesSerially<\n BalanceOfRequest,\n FetchAccumulator\n >({\n values: balanceRequests,\n batchSize: this.#config.defaultBatchSize,\n initialResult: {\n balances: [],\n failedAddresses: [],\n },\n eachBatch: async (workingResult, batch) => {\n const responses = await this.#multicallClient.batchBalanceOf(\n chainId,\n batch,\n { fallbackToSingleCalls: true },\n );\n\n return this.#processBalanceResponses(\n responses,\n workingResult as FetchAccumulator,\n chainId,\n accountId,\n timestamp,\n entryByAddress,\n );\n },\n });\n\n return {\n chainId,\n accountId,\n accountAddress,\n ...result,\n timestamp,\n };\n }\n\n #processBalanceResponses(\n responses: BalanceOfResponse[],\n accumulator: {\n balances: AssetBalance[];\n failedAddresses: Address[];\n },\n chainId: ChainId,\n accountId: AccountId,\n timestamp: number,\n entryByAddress: Map<string, AssetFetchEntry>,\n ): {\n balances: AssetBalance[];\n failedAddresses: Address[];\n } {\n const { balances, failedAddresses } = accumulator;\n\n for (const response of responses) {\n if (!response.success) {\n failedAddresses.push(response.tokenAddress);\n continue;\n }\n\n const lowerAddress = response.tokenAddress.toLowerCase();\n const entry = entryByAddress.get(lowerAddress);\n if (!entry) {\n continue;\n }\n\n const balance = response.balance ?? '0';\n const isNative = lowerAddress === ZERO_ADDRESS.toLowerCase();\n\n let decimals: number | undefined;\n let formattedBalance: string;\n if (isNative) {\n decimals = 18;\n formattedBalance = this.#formatBalance(balance, decimals);\n } else if (entry.decimals === undefined) {\n formattedBalance = balance;\n } else {\n decimals = entry.decimals;\n formattedBalance = this.#formatBalance(balance, decimals);\n }\n\n const balanceEntry: AssetBalance = {\n assetId: entry.assetId,\n accountId,\n chainId,\n balance,\n formattedBalance,\n timestamp,\n };\n if (typeof decimals === 'number') {\n balanceEntry.decimals = decimals;\n }\n balances.push(balanceEntry);\n }\n\n return { balances, failedAddresses };\n }\n\n #formatBalance(rawBalance: string, decimals: number): string {\n if (rawBalance === '0') {\n return '0';\n }\n\n try {\n const balanceBigInt = BigInt(rawBalance);\n const divisor = BigInt(10 ** decimals);\n\n const integerPart = balanceBigInt / divisor;\n const remainder = balanceBigInt % divisor;\n const fractionalStr = remainder.toString().padStart(decimals, '0');\n const trimmedFractional = fractionalStr.replace(/0+$/u, '');\n\n if (trimmedFractional === '') {\n return integerPart.toString();\n }\n\n return `${integerPart}.${trimmedFractional}`;\n } catch {\n return rawBalance;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"BalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\nimport { parseCaipAssetType } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants.js';\nimport type { MulticallClient } from '../clients/index.js';\nimport type {\n AccountId,\n Address,\n AssetBalance,\n AssetFetchEntry,\n AssetsBalanceState,\n BalanceFetchResult,\n BalanceOfRequest,\n BalanceOfResponse,\n CaipAssetType,\n ChainId,\n} from '../types/index.js';\nimport { reduceInBatchesSerially } from '../utils/index.js';\n\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\n\n/**\n * Minimal messenger interface for BalanceFetcher.\n */\nexport type BalanceFetcherMessenger = {\n call: (action: 'AssetsController:getState') => AssetsBalanceState;\n};\n\nexport type BalanceFetcherConfig = {\n defaultBatchSize?: number;\n defaultTimeoutMs?: number;\n /** Polling interval in ms (default: 30s) */\n pollingInterval?: number;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: CaipAssetType) => boolean;\n};\n\n/**\n * Polling input for BalanceFetcher - identifies what to poll for.\n */\nexport type BalancePollingInput = {\n /** Chain ID (hex format) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n /**\n * When present, fetch exactly these assets instead of the tracked\n * `assetsBalance` entries (Accounts API v6 asset-scoped RPC poll). Must be\n * deterministically ordered — the polling input is the dedupe key.\n */\n assetIds?: CaipAssetType[];\n /**\n * When true, only fetch balances for entries in `state.customAssets`,\n * skipping `state.assetsBalance`. Used by the supplemental RPC\n * subscription on the Accounts API v5 path.\n */\n customAssetsOnly?: boolean;\n};\n\n/**\n * Callback type for balance updates.\n */\nexport type OnBalanceUpdateCallback = (\n result: BalanceFetchResult,\n) => void | Promise<void>;\n\n/**\n * BalanceFetcher - Fetches token balances via multicall.\n * Extends StaticIntervalPollingControllerOnly for built-in polling support.\n *\n * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses\n * (or uses the zero address for native assets) and maps multicall responses\n * back to the original asset IDs. This ensures the returned balance entries\n * always carry the correct identifier regardless of chain.\n */\nexport class BalanceFetcher extends StaticIntervalPollingControllerOnly<BalancePollingInput>() {\n readonly #multicallClient: MulticallClient;\n\n readonly #messenger: BalanceFetcherMessenger;\n\n readonly #config: Required<\n Omit<BalanceFetcherConfig, 'pollingInterval' | 'isNativeAsset'>\n >;\n\n readonly #isNativeAsset: (assetId: CaipAssetType) => boolean;\n\n #onBalanceUpdate: OnBalanceUpdateCallback | undefined;\n\n constructor(\n multicallClient: MulticallClient,\n messenger: BalanceFetcherMessenger,\n config: BalanceFetcherConfig,\n ) {\n super();\n this.#multicallClient = multicallClient;\n this.#messenger = messenger;\n this.#config = {\n defaultBatchSize: config.defaultBatchSize ?? 300,\n defaultTimeoutMs: config.defaultTimeoutMs ?? 30000,\n };\n this.#isNativeAsset = config.isNativeAsset;\n\n // Set the polling interval\n this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);\n }\n\n /**\n * Set the callback to receive balance updates during polling.\n *\n * @param callback - Function to call with balance results.\n */\n setOnBalanceUpdate(callback: OnBalanceUpdateCallback): void {\n this.#onBalanceUpdate = callback;\n }\n\n /**\n * Execute a poll cycle (required by base class).\n * Fetches balances and calls the update callback.\n *\n * @param input - The polling input.\n */\n async _executePoll(input: BalancePollingInput): Promise<void> {\n const result = await this.#fetchBalances(\n input.chainId,\n input.accountId,\n input.accountAddress,\n input.assetIds,\n input.customAssetsOnly === true,\n );\n\n if (this.#onBalanceUpdate && result.balances.length > 0) {\n await this.#onBalanceUpdate(result);\n }\n }\n\n /**\n * Return asset fetch entries tracked in state for the given account and\n * chain. Both native (`slip44:`) and ERC-20 (`erc20:`) entries are included.\n *\n * @param chainId - Hex chain ID (e.g. \"0x1\").\n * @param accountId - Account UUID.\n * @param assetIds - When present, fetch exactly these assets instead of the\n * tracked `assetsBalance` entries.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Array of asset fetch entries from state for the requested chain.\n */\n #getAssetsToFetch(\n chainId: ChainId,\n accountId: AccountId,\n assetIds?: CaipAssetType[],\n customAssetsOnly = false,\n ): AssetFetchEntry[] {\n // Convert hex chainId to decimal for CAIP-2 matching\n // This is safe because we are filtring with an accountId that is for evm balances only\n const chainIdDecimal = parseInt(chainId, 16).toString();\n\n const assetsToFetch = new Map<string, AssetFetchEntry>();\n\n const collect = (assetId: CaipAssetType): void => {\n const parsed = parseCaipAssetType(assetId);\n\n if (parsed.chain.reference !== chainIdDecimal) {\n return;\n }\n\n const normalizedAssetId = assetId.toLowerCase();\n\n if (assetsToFetch.has(normalizedAssetId)) {\n return;\n }\n\n const isNative = this.#isNativeAsset(assetId);\n\n assetsToFetch.set(normalizedAssetId, {\n assetId,\n address: isNative\n ? ZERO_ADDRESS\n : (parsed.assetReference.toLowerCase() as Address),\n });\n };\n\n // Asset-scoped poll: fetch only the input's assets; tracked balances on\n // this chain are another source's responsibility.\n if (assetIds) {\n for (const assetId of assetIds) {\n collect(assetId);\n }\n return Array.from(assetsToFetch.values());\n }\n\n const state = this.#messenger.call('AssetsController:getState');\n\n // Assets tracked with a balance entry — only when not in\n // \"customAssetsOnly\" mode (otherwise another data source is already\n // refreshing them and we'd double-poll).\n if (!customAssetsOnly) {\n const accountBalances = state?.assetsBalance?.[accountId];\n if (accountBalances) {\n for (const assetId of Object.keys(accountBalances) as CaipAssetType[]) {\n collect(assetId);\n }\n }\n }\n\n // User-added custom assets — on the v5 path RPC is the sole balance\n // fetcher for these, so they must be polled even if they have no balance\n // entry yet. On the v6 path they are usually already in `assetsBalance`.\n const customAssets = state?.customAssets?.[accountId];\n if (customAssets) {\n for (const assetId of customAssets as CaipAssetType[]) {\n collect(assetId);\n }\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n /**\n * Fetch balances for assets already tracked in state for the given\n * account and chain.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param assetIds - When present, fetch exactly these assets instead of the\n * tracked `assetsBalance` entries.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Balance fetch result.\n */\n async #fetchBalances(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n assetIds?: CaipAssetType[],\n customAssetsOnly = false,\n ): Promise<BalanceFetchResult> {\n const assets = this.#getAssetsToFetch(\n chainId,\n accountId,\n assetIds,\n customAssetsOnly,\n );\n\n return this.fetchBalancesForAssets(\n chainId,\n accountId,\n accountAddress,\n assets,\n );\n }\n\n /**\n * Fetch balances for the given assets via multicall.\n *\n * Each entry bundles a CAIP-19 asset ID with its on-chain address and\n * optional decimals.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param assets - Asset fetch entries to fetch balances for.\n * @returns Balance fetch result.\n */\n async fetchBalancesForAssets(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n assets: AssetFetchEntry[],\n ): Promise<BalanceFetchResult> {\n const timestamp = Date.now();\n\n // Build a single map keyed by lowercase address that holds all info\n // needed to match multicall responses back to their original entries.\n const balanceRequests: BalanceOfRequest[] = [];\n const entryByAddress = new Map<string, AssetFetchEntry>();\n\n for (const entry of assets) {\n const lowerAddress = entry.address.toLowerCase();\n if (entryByAddress.has(lowerAddress)) {\n continue; // deduplicate\n }\n\n entryByAddress.set(lowerAddress, entry);\n balanceRequests.push({ tokenAddress: entry.address, accountAddress });\n }\n\n if (balanceRequests.length === 0) {\n return {\n chainId,\n accountId,\n accountAddress,\n balances: [],\n failedAddresses: [],\n timestamp,\n };\n }\n\n type FetchAccumulator = {\n balances: AssetBalance[];\n failedAddresses: Address[];\n };\n\n const result = await reduceInBatchesSerially<\n BalanceOfRequest,\n FetchAccumulator\n >({\n values: balanceRequests,\n batchSize: this.#config.defaultBatchSize,\n initialResult: {\n balances: [],\n failedAddresses: [],\n },\n eachBatch: async (workingResult, batch) => {\n const responses = await this.#multicallClient.batchBalanceOf(\n chainId,\n batch,\n { fallbackToSingleCalls: true },\n );\n\n return this.#processBalanceResponses(\n responses,\n workingResult as FetchAccumulator,\n chainId,\n accountId,\n timestamp,\n entryByAddress,\n );\n },\n });\n\n return {\n chainId,\n accountId,\n accountAddress,\n ...result,\n timestamp,\n };\n }\n\n #processBalanceResponses(\n responses: BalanceOfResponse[],\n accumulator: {\n balances: AssetBalance[];\n failedAddresses: Address[];\n },\n chainId: ChainId,\n accountId: AccountId,\n timestamp: number,\n entryByAddress: Map<string, AssetFetchEntry>,\n ): {\n balances: AssetBalance[];\n failedAddresses: Address[];\n } {\n const { balances, failedAddresses } = accumulator;\n\n for (const response of responses) {\n if (!response.success) {\n failedAddresses.push(response.tokenAddress);\n continue;\n }\n\n const lowerAddress = response.tokenAddress.toLowerCase();\n const entry = entryByAddress.get(lowerAddress);\n if (!entry) {\n continue;\n }\n\n const balance = response.balance ?? '0';\n const isNative = lowerAddress === ZERO_ADDRESS.toLowerCase();\n\n let decimals: number | undefined;\n let formattedBalance: string;\n if (isNative) {\n decimals = 18;\n formattedBalance = this.#formatBalance(balance, decimals);\n } else if (entry.decimals === undefined) {\n formattedBalance = balance;\n } else {\n decimals = entry.decimals;\n formattedBalance = this.#formatBalance(balance, decimals);\n }\n\n const balanceEntry: AssetBalance = {\n assetId: entry.assetId,\n accountId,\n chainId,\n balance,\n formattedBalance,\n timestamp,\n };\n if (typeof decimals === 'number') {\n balanceEntry.decimals = decimals;\n }\n balances.push(balanceEntry);\n }\n\n return { balances, failedAddresses };\n }\n\n #formatBalance(rawBalance: string, decimals: number): string {\n if (rawBalance === '0') {\n return '0';\n }\n\n try {\n const balanceBigInt = BigInt(rawBalance);\n const divisor = BigInt(10 ** decimals);\n\n const integerPart = balanceBigInt / divisor;\n const remainder = balanceBigInt % divisor;\n const fractionalStr = remainder.toString().padStart(decimals, '0');\n const trimmedFractional = fractionalStr.replace(/0+$/u, '');\n\n if (trimmedFractional === '') {\n return integerPart.toString();\n }\n\n return `${integerPart}.${trimmedFractional}`;\n } catch {\n return rawBalance;\n }\n }\n}\n"]}