@metamask/assets-controllers 99.3.1 → 99.4.0

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 (52) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/dist/DeFiPositionsController/DeFiPositionsController.cjs +2 -3
  3. package/dist/DeFiPositionsController/DeFiPositionsController.cjs.map +1 -1
  4. package/dist/DeFiPositionsController/DeFiPositionsController.d.cts.map +1 -1
  5. package/dist/DeFiPositionsController/DeFiPositionsController.d.mts.map +1 -1
  6. package/dist/DeFiPositionsController/DeFiPositionsController.mjs +2 -3
  7. package/dist/DeFiPositionsController/DeFiPositionsController.mjs.map +1 -1
  8. package/dist/TokenBalancesController.cjs +2 -3
  9. package/dist/TokenBalancesController.cjs.map +1 -1
  10. package/dist/TokenBalancesController.d.cts.map +1 -1
  11. package/dist/TokenBalancesController.d.mts.map +1 -1
  12. package/dist/TokenBalancesController.mjs +2 -3
  13. package/dist/TokenBalancesController.mjs.map +1 -1
  14. package/dist/TokenListController.cjs +1 -1
  15. package/dist/TokenListController.cjs.map +1 -1
  16. package/dist/TokenListController.mjs +1 -1
  17. package/dist/TokenListController.mjs.map +1 -1
  18. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +33 -4
  19. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
  20. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts +7 -1
  21. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
  22. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts +7 -1
  23. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
  24. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +33 -4
  25. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
  26. package/dist/multicall.cjs +2 -0
  27. package/dist/multicall.cjs.map +1 -1
  28. package/dist/multicall.d.cts.map +1 -1
  29. package/dist/multicall.d.mts.map +1 -1
  30. package/dist/multicall.mjs +2 -0
  31. package/dist/multicall.mjs.map +1 -1
  32. package/dist/selectors/token-selectors.d.cts +54 -18
  33. package/dist/selectors/token-selectors.d.cts.map +1 -1
  34. package/dist/selectors/token-selectors.d.mts +54 -18
  35. package/dist/selectors/token-selectors.d.mts.map +1 -1
  36. package/dist/token-prices-service/codefi-v2.cjs +40 -9
  37. package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
  38. package/dist/token-prices-service/codefi-v2.d.cts +5 -2
  39. package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
  40. package/dist/token-prices-service/codefi-v2.d.mts +5 -2
  41. package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
  42. package/dist/token-prices-service/codefi-v2.mjs +40 -9
  43. package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
  44. package/dist/token-service.cjs +4 -5
  45. package/dist/token-service.cjs.map +1 -1
  46. package/dist/token-service.d.cts +2 -1
  47. package/dist/token-service.d.cts.map +1 -1
  48. package/dist/token-service.d.mts +2 -1
  49. package/dist/token-service.d.mts.map +1 -1
  50. package/dist/token-service.mjs +4 -5
  51. package/dist/token-service.mjs.map +1 -1
  52. package/package.json +15 -15
@@ -1 +1 @@
1
- {"version":3,"file":"TokenListController.mjs","sourceRoot":"","sources":["../src/TokenListController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { safelyExecute } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerStateChangeEvent,\n NetworkState,\n NetworkControllerGetNetworkClientByIdAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n StorageServiceSetItemAction,\n StorageServiceGetItemAction,\n StorageServiceGetAllKeysAction,\n} from '@metamask/storage-service';\nimport type { Hex } from '@metamask/utils';\n\nimport {\n isTokenListSupportedForNetwork,\n formatAggregatorNames,\n formatIconUrlWithProxy,\n} from './assetsUtil';\nimport { TokenRwaData, fetchTokenListByChainId } from './token-service';\n\n// 4 Hour Interval Cache Refresh Threshold\nconst DEFAULT_INTERVAL = 4 * 60 * 60 * 1000;\nconst DEFAULT_THRESHOLD = 4 * 60 * 60 * 1000;\n\nconst name = 'TokenListController';\n\nexport type TokenListToken = {\n name: string;\n symbol: string;\n decimals: number;\n address: string;\n occurrences: number;\n aggregators: string[];\n iconUrl: string;\n rwaData?: TokenRwaData;\n};\n\nexport type TokenListMap = Record<string, TokenListToken>;\n\nexport type DataCache = {\n timestamp: number;\n data: TokenListMap;\n};\nexport type TokensChainsCache = {\n [chainId: Hex]: DataCache;\n};\n\nexport type TokenListState = {\n tokensChainsCache: TokensChainsCache;\n};\n\nexport type TokenListStateChange = ControllerStateChangeEvent<\n typeof name,\n TokenListState\n>;\n\nexport type TokenListControllerEvents = TokenListStateChange;\n\nexport type GetTokenListState = ControllerGetStateAction<\n typeof name,\n TokenListState\n>;\n\nexport type TokenListControllerActions = GetTokenListState;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | StorageServiceSetItemAction\n | StorageServiceGetItemAction\n | StorageServiceGetAllKeysAction;\n\ntype AllowedEvents = NetworkControllerStateChangeEvent;\n\nexport type TokenListControllerMessenger = Messenger<\n typeof name,\n TokenListControllerActions | AllowedActions,\n TokenListControllerEvents | AllowedEvents\n>;\n\nconst metadata: StateMetadata<TokenListState> = {\n tokensChainsCache: {\n includeInStateLogs: false,\n persist: false, // Persisted separately via StorageService\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nexport const getDefaultTokenListState = (): TokenListState => {\n return {\n tokensChainsCache: {},\n };\n};\n\n/** The input to start polling for the {@link TokenListController} */\ntype TokenListPollingInput = {\n chainId: Hex;\n};\n\n/**\n * Controller that passively polls on a set interval for the list of tokens from metaswaps api\n */\nexport class TokenListController extends StaticIntervalPollingController<TokenListPollingInput>()<\n typeof name,\n TokenListState,\n TokenListControllerMessenger\n> {\n /**\n * Debounce timer for persisting state changes to storage.\n */\n #persistDebounceTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Promise that resolves when the current persist operation completes.\n * Used to prevent race conditions between persist operations.\n */\n #persistInFlightPromise?: Promise<void>;\n\n /**\n * Tracks which chains have pending changes to persist.\n * Only changed chains are persisted to reduce write amplification.\n */\n readonly #changedChainsToPersist: Set<Hex> = new Set();\n\n /**\n * Previous tokensChainsCache for detecting which chains changed.\n */\n #previousTokensChainsCache: TokensChainsCache = {};\n\n /**\n * Debounce delay for persisting state changes (in milliseconds).\n */\n static readonly #persistDebounceMs = 500;\n\n // Storage key prefix for per-chain files\n static readonly #storageKeyPrefix = 'tokensChainsCache';\n\n /**\n * Get storage key for a specific chain.\n *\n * @param chainId - The chain ID.\n * @returns Storage key for the chain.\n */\n static #getChainStorageKey(chainId: Hex): string {\n return `${TokenListController.#storageKeyPrefix}:${chainId}`;\n }\n\n #intervalId?: ReturnType<typeof setTimeout>;\n\n readonly #intervalDelay: number;\n\n readonly #cacheRefreshThreshold: number;\n\n #chainId: Hex;\n\n #abortController: AbortController;\n\n /**\n * Creates a TokenListController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onNetworkStateChange - A function for registering an event handler for network state changes.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.cacheRefreshThreshold - The token cache expiry time, in milliseconds.\n * @param options.messenger - A restricted messenger.\n * @param options.state - Initial state to set on this controller.\n */\n constructor({\n chainId,\n onNetworkStateChange,\n interval = DEFAULT_INTERVAL,\n cacheRefreshThreshold = DEFAULT_THRESHOLD,\n messenger,\n state,\n }: {\n chainId: Hex;\n onNetworkStateChange?: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n interval?: number;\n cacheRefreshThreshold?: number;\n messenger: TokenListControllerMessenger;\n state?: Partial<TokenListState>;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...getDefaultTokenListState(), ...state },\n });\n\n this.#intervalDelay = interval;\n this.setIntervalLength(interval);\n this.#cacheRefreshThreshold = cacheRefreshThreshold;\n this.#chainId = chainId;\n this.#abortController = new AbortController();\n\n if (onNetworkStateChange) {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n onNetworkStateChange(async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n });\n } else {\n this.messenger.subscribe(\n 'NetworkController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n },\n );\n }\n }\n\n /**\n * Initialize the controller by loading cache from storage and running migration.\n * This method should be called by clients after construction.\n *\n * @returns A promise that resolves when initialization is complete.\n */\n async initialize(): Promise<void> {\n await this.#synchronizeCacheWithStorage();\n\n // Subscribe to state changes to automatically persist tokensChainsCache\n this.messenger.subscribe(\n 'TokenListController:stateChange',\n (newCache: TokensChainsCache) => this.#onCacheChanged(newCache),\n (controllerState) => controllerState.tokensChainsCache,\n );\n }\n\n /**\n * Handle tokensChainsCache changes by detecting which chains changed\n * and scheduling debounced persistence.\n *\n * @param newCache - The new tokensChainsCache state.\n */\n #onCacheChanged(newCache: TokensChainsCache): void {\n // Detect which chains changed by comparing with previous cache\n for (const chainId of Object.keys(newCache) as Hex[]) {\n const newData = newCache[chainId];\n const prevData = this.#previousTokensChainsCache[chainId];\n\n // Chain is new or timestamp changed (indicating data update)\n if (!prevData || prevData.timestamp !== newData.timestamp) {\n this.#changedChainsToPersist.add(chainId);\n }\n }\n\n // Update previous cache reference\n this.#previousTokensChainsCache = { ...newCache };\n\n // Schedule persistence if there are changes\n if (this.#changedChainsToPersist.size > 0) {\n this.#debouncePersist();\n }\n }\n\n /**\n * Debounce persistence of changed chains to storage.\n */\n #debouncePersist(): void {\n if (this.#persistDebounceTimer) {\n clearTimeout(this.#persistDebounceTimer);\n }\n\n this.#persistDebounceTimer = setTimeout(() => {\n // Note: #persistChangedChains handles errors internally via #saveChainCacheToStorage,\n // so this promise will not reject.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#persistChangedChains();\n }, TokenListController.#persistDebounceMs);\n }\n\n /**\n * Persist only the chains that have changed to storage.\n * Reduces write amplification by skipping unchanged chains.\n *\n * If a persist operation is already in-flight, this method returns early\n * and reschedules the debounce to ensure accumulated changes are retried\n * after the current operation completes.\n *\n * @returns A promise that resolves when changed chains are persisted.\n */\n async #persistChangedChains(): Promise<void> {\n if (this.#persistInFlightPromise) {\n // Reschedule debounce to retry accumulated changes after in-flight persist completes\n if (this.#changedChainsToPersist.size > 0) {\n this.#debouncePersist();\n }\n return;\n }\n\n const chainsToPersist = [...this.#changedChainsToPersist];\n this.#changedChainsToPersist.clear();\n\n if (chainsToPersist.length === 0) {\n return;\n }\n\n this.#persistInFlightPromise = Promise.all(\n chainsToPersist.map((chainId) => this.#saveChainCacheToStorage(chainId)),\n ).then(() => undefined);\n\n try {\n await this.#persistInFlightPromise;\n } finally {\n this.#persistInFlightPromise = undefined;\n }\n }\n\n /**\n * Synchronize tokensChainsCache between state and storage bidirectionally.\n *\n * This method:\n * 1. Loads cached chains from storage (per-chain files) in parallel\n * 2. Merges loaded data into state (preferring existing state to avoid overwriting fresh data)\n * 3. Persists any chains that exist in state but not in storage\n *\n * Called during initialization to ensure state and storage are consistent.\n *\n * @returns A promise that resolves when synchronization is complete.\n */\n async #synchronizeCacheWithStorage(): Promise<void> {\n try {\n const allKeys = await this.messenger.call(\n 'StorageService:getAllKeys',\n name,\n );\n\n // Filter keys that belong to tokensChainsCache (per-chain files)\n const cacheKeys = allKeys.filter((key) =>\n key.startsWith(`${TokenListController.#storageKeyPrefix}:`),\n );\n\n // Load all chains in parallel\n const chainCaches = await Promise.all(\n cacheKeys.map(async (key) => {\n // Extract chainId from key: 'tokensChainsCache:0x1' → '0x1'\n const chainId = key.split(':')[1] as Hex;\n\n const { result, error } = await this.messenger.call(\n 'StorageService:getItem',\n name,\n key,\n );\n\n if (error) {\n console.error(\n `TokenListController: Error loading cache for ${chainId}:`,\n error,\n );\n return null;\n }\n\n return result ? { chainId, data: result as DataCache } : null;\n }),\n );\n\n // Build complete cache from loaded chains\n const loadedCache: TokensChainsCache = {};\n chainCaches.forEach((chainCache) => {\n if (chainCache) {\n loadedCache[chainCache.chainId] = chainCache.data;\n }\n });\n\n // Chains in state _before loading persisted state_, from a recent update\n const chainsInState = new Set(\n Object.keys(this.state.tokensChainsCache) as Hex[],\n );\n\n // Merge loaded cache with existing state, preferring existing data\n // (which may be fresher if fetched during initialization)\n if (Object.keys(loadedCache).length > 0) {\n this.update((state) => {\n // Only load chains that don't already exist in state\n // This prevents overwriting fresh API data with stale cached data\n for (const [chainId, cacheData] of Object.entries(loadedCache)) {\n if (!state.tokensChainsCache[chainId as Hex]) {\n state.tokensChainsCache[chainId as Hex] = cacheData;\n }\n }\n });\n }\n\n // Persist chains that exist in state but were not loaded from storage.\n // This handles the case where initial state contains chains that don't exist\n // in storage yet (e.g., fresh data from API). Without this, those chains\n // would be lost on the next app restart.\n for (const chainId of chainsInState) {\n this.#changedChainsToPersist.add(chainId);\n }\n\n // Persist any chains that need to be saved\n if (this.#changedChainsToPersist.size > 0) {\n this.#debouncePersist();\n }\n\n this.#previousTokensChainsCache = { ...this.state.tokensChainsCache };\n } catch (error) {\n console.error(\n 'TokenListController: Failed to load cache from storage:',\n error,\n );\n }\n }\n\n /**\n * Save a specific chain's cache to StorageService.\n * This persists only the updated chain's data, reducing write amplification.\n *\n * @param chainId - The chain ID to save.\n * @returns A promise that resolves when saving is complete.\n */\n async #saveChainCacheToStorage(chainId: Hex): Promise<void> {\n try {\n const chainData = this.state.tokensChainsCache[chainId];\n\n if (!chainData) {\n console.warn(`TokenListController: No cache data for chain ${chainId}`);\n return;\n }\n\n const storageKey = TokenListController.#getChainStorageKey(chainId);\n\n await this.messenger.call(\n 'StorageService:setItem',\n name,\n storageKey,\n chainData,\n );\n } catch (error) {\n console.error(\n `TokenListController: Failed to save cache for ${chainId}:`,\n error,\n );\n }\n }\n\n /**\n * Updates state and restarts polling on changes to the network controller\n * state.\n *\n * @param networkControllerState - The updated network controller state.\n */\n async #onNetworkControllerStateChange(\n networkControllerState: NetworkState,\n ): Promise<void> {\n const selectedNetworkClient = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkControllerState.selectedNetworkClientId,\n );\n const { chainId } = selectedNetworkClient.configuration;\n\n if (this.#chainId !== chainId) {\n this.#abortController.abort();\n this.#abortController = new AbortController();\n this.#chainId = chainId;\n }\n }\n\n // Eventually we want to remove start/restart/stop controls in favor of new _executePoll API\n // Maintaining these functions for now until we can safely deprecate them for backwards compatibility\n /**\n * Start polling for the token list.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n async start(): Promise<void> {\n if (!isTokenListSupportedForNetwork(this.#chainId)) {\n return;\n }\n await this.#startDeprecatedPolling();\n }\n\n /**\n * Restart polling for the token list.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n async restart(): Promise<void> {\n this.#stopPolling();\n await this.#startDeprecatedPolling();\n }\n\n /**\n * Stop polling for the token list.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n stop(): void {\n this.#stopPolling();\n }\n\n /**\n * This stops any active polling.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n override destroy(): void {\n super.destroy();\n this.#stopPolling();\n\n // Cancel any pending debounced persistence operations\n if (this.#persistDebounceTimer) {\n clearTimeout(this.#persistDebounceTimer);\n this.#persistDebounceTimer = undefined;\n }\n this.#changedChainsToPersist.clear();\n }\n\n /**\n * This stops any active polling intervals.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n #stopPolling(): void {\n if (this.#intervalId) {\n clearInterval(this.#intervalId);\n }\n }\n\n /**\n * Starts a new polling interval for a given chainId (this should be deprecated in favor of _executePoll)\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n async #startDeprecatedPolling(): Promise<void> {\n // renaming this to avoid collision with base class\n await safelyExecute(() => this.fetchTokenList(this.#chainId));\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#intervalId = setInterval(async () => {\n await safelyExecute(() => this.fetchTokenList(this.#chainId));\n }, this.#intervalDelay);\n }\n\n /**\n * This starts a new polling loop for any given chain. Under the hood it is deduping polls\n *\n * @param input - The input for the poll.\n * @param input.chainId - The chainId of the chain to trigger the fetch.\n * @returns A promise that resolves when this operation completes.\n */\n async _executePoll({ chainId }: TokenListPollingInput): Promise<void> {\n return this.fetchTokenList(chainId);\n }\n\n /**\n * Fetching token list from the Token Service API. This will fetch tokens across chains.\n * State changes are automatically persisted via the stateChange subscription.\n *\n * @param chainId - The chainId of the current chain triggering the fetch.\n */\n async fetchTokenList(chainId: Hex): Promise<void> {\n if (this.isCacheValid(chainId)) {\n return;\n }\n\n // Fetch fresh token list from the API\n const tokensFromAPI = await safelyExecute(\n () =>\n fetchTokenListByChainId(\n chainId,\n this.#abortController.signal,\n ) as Promise<TokenListToken[]>,\n );\n\n // Have response - process and update list\n if (tokensFromAPI) {\n // Format tokens from API (HTTP) and update tokenList\n const tokenList: TokenListMap = {};\n for (const token of tokensFromAPI) {\n tokenList[token.address] = {\n ...token,\n aggregators: formatAggregatorNames(token.aggregators),\n iconUrl: formatIconUrlWithProxy({\n chainId,\n tokenAddress: token.address,\n }),\n };\n }\n\n // Update state - persistence happens automatically via subscription\n const newDataCache: DataCache = {\n data: tokenList,\n timestamp: Date.now(),\n };\n this.update((state) => {\n state.tokensChainsCache[chainId] = newDataCache;\n });\n return;\n }\n\n // No response - fallback to previous state, or initialise empty.\n // Only initialize with a new timestamp if there's no existing cache.\n // If there's existing cache, keep it as-is without updating the timestamp\n // to avoid making stale data appear \"fresh\" and preventing retry attempts.\n if (!tokensFromAPI) {\n const existingCache = this.state.tokensChainsCache[chainId];\n if (!existingCache) {\n // No existing cache - initialize empty (persistence happens automatically)\n const newDataCache: DataCache = { data: {}, timestamp: Date.now() };\n this.update((state) => {\n state.tokensChainsCache[chainId] = newDataCache;\n });\n }\n // If there's existing cache, keep it as-is (don't update timestamp or persist)\n }\n }\n\n isCacheValid(chainId: Hex): boolean {\n const { tokensChainsCache }: TokenListState = this.state;\n const timestamp: number | undefined = tokensChainsCache[chainId]?.timestamp;\n const now = Date.now();\n return (\n timestamp !== undefined && now - timestamp < this.#cacheRefreshThreshold\n );\n }\n}\n\nexport default TokenListController;\n"]}
1
+ {"version":3,"file":"TokenListController.mjs","sourceRoot":"","sources":["../src/TokenListController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { safelyExecute } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerStateChangeEvent,\n NetworkState,\n NetworkControllerGetNetworkClientByIdAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n StorageServiceSetItemAction,\n StorageServiceGetItemAction,\n StorageServiceGetAllKeysAction,\n} from '@metamask/storage-service';\nimport type { Hex } from '@metamask/utils';\n\nimport {\n isTokenListSupportedForNetwork,\n formatAggregatorNames,\n formatIconUrlWithProxy,\n} from './assetsUtil';\nimport { TokenRwaData, fetchTokenListByChainId } from './token-service';\n\n// 4 Hour Interval Cache Refresh Threshold\nconst DEFAULT_INTERVAL = 4 * 60 * 60 * 1000;\nconst DEFAULT_THRESHOLD = 4 * 60 * 60 * 1000;\n\nconst name = 'TokenListController';\n\nexport type TokenListToken = {\n name: string;\n symbol: string;\n decimals: number;\n address: string;\n occurrences: number;\n aggregators: string[];\n iconUrl: string;\n rwaData?: TokenRwaData;\n};\n\nexport type TokenListMap = Record<string, TokenListToken>;\n\nexport type DataCache = {\n timestamp: number;\n data: TokenListMap;\n};\nexport type TokensChainsCache = {\n [chainId: Hex]: DataCache;\n};\n\nexport type TokenListState = {\n tokensChainsCache: TokensChainsCache;\n};\n\nexport type TokenListStateChange = ControllerStateChangeEvent<\n typeof name,\n TokenListState\n>;\n\nexport type TokenListControllerEvents = TokenListStateChange;\n\nexport type GetTokenListState = ControllerGetStateAction<\n typeof name,\n TokenListState\n>;\n\nexport type TokenListControllerActions = GetTokenListState;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | StorageServiceSetItemAction\n | StorageServiceGetItemAction\n | StorageServiceGetAllKeysAction;\n\ntype AllowedEvents = NetworkControllerStateChangeEvent;\n\nexport type TokenListControllerMessenger = Messenger<\n typeof name,\n TokenListControllerActions | AllowedActions,\n TokenListControllerEvents | AllowedEvents\n>;\n\nconst metadata: StateMetadata<TokenListState> = {\n tokensChainsCache: {\n includeInStateLogs: false,\n persist: false, // Persisted separately via StorageService\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nexport const getDefaultTokenListState = (): TokenListState => {\n return {\n tokensChainsCache: {},\n };\n};\n\n/** The input to start polling for the {@link TokenListController} */\ntype TokenListPollingInput = {\n chainId: Hex;\n};\n\n/**\n * Controller that passively polls on a set interval for the list of tokens from metaswaps api\n */\nexport class TokenListController extends StaticIntervalPollingController<TokenListPollingInput>()<\n typeof name,\n TokenListState,\n TokenListControllerMessenger\n> {\n /**\n * Debounce timer for persisting state changes to storage.\n */\n #persistDebounceTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Promise that resolves when the current persist operation completes.\n * Used to prevent race conditions between persist operations.\n */\n #persistInFlightPromise?: Promise<void>;\n\n /**\n * Tracks which chains have pending changes to persist.\n * Only changed chains are persisted to reduce write amplification.\n */\n readonly #changedChainsToPersist: Set<Hex> = new Set();\n\n /**\n * Previous tokensChainsCache for detecting which chains changed.\n */\n #previousTokensChainsCache: TokensChainsCache = {};\n\n /**\n * Debounce delay for persisting state changes (in milliseconds).\n */\n static readonly #persistDebounceMs = 500;\n\n // Storage key prefix for per-chain files\n static readonly #storageKeyPrefix = 'tokensChainsCache';\n\n /**\n * Get storage key for a specific chain.\n *\n * @param chainId - The chain ID.\n * @returns Storage key for the chain.\n */\n static #getChainStorageKey(chainId: Hex): string {\n return `${TokenListController.#storageKeyPrefix}:${chainId}`;\n }\n\n #intervalId?: ReturnType<typeof setTimeout>;\n\n readonly #intervalDelay: number;\n\n readonly #cacheRefreshThreshold: number;\n\n #chainId: Hex;\n\n #abortController: AbortController;\n\n /**\n * Creates a TokenListController instance.\n *\n * @param options - The controller options.\n * @param options.chainId - The chain ID of the current network.\n * @param options.onNetworkStateChange - A function for registering an event handler for network state changes.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.cacheRefreshThreshold - The token cache expiry time, in milliseconds.\n * @param options.messenger - A restricted messenger.\n * @param options.state - Initial state to set on this controller.\n */\n constructor({\n chainId,\n onNetworkStateChange,\n interval = DEFAULT_INTERVAL,\n cacheRefreshThreshold = DEFAULT_THRESHOLD,\n messenger,\n state,\n }: {\n chainId: Hex;\n onNetworkStateChange?: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n interval?: number;\n cacheRefreshThreshold?: number;\n messenger: TokenListControllerMessenger;\n state?: Partial<TokenListState>;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...getDefaultTokenListState(), ...state },\n });\n\n this.#intervalDelay = interval;\n this.setIntervalLength(interval);\n this.#cacheRefreshThreshold = cacheRefreshThreshold;\n this.#chainId = chainId;\n this.#abortController = new AbortController();\n\n if (onNetworkStateChange) {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n onNetworkStateChange(async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n });\n } else {\n this.messenger.subscribe(\n 'NetworkController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (networkControllerState) => {\n await this.#onNetworkControllerStateChange(networkControllerState);\n },\n );\n }\n }\n\n /**\n * Initialize the controller by loading cache from storage and running migration.\n * This method should be called by clients after construction.\n *\n * @returns A promise that resolves when initialization is complete.\n */\n async initialize(): Promise<void> {\n await this.#synchronizeCacheWithStorage();\n\n // Subscribe to state changes to automatically persist tokensChainsCache\n this.messenger.subscribe(\n 'TokenListController:stateChange',\n (newCache: TokensChainsCache) => this.#onCacheChanged(newCache),\n (controllerState) => controllerState.tokensChainsCache,\n );\n }\n\n /**\n * Handle tokensChainsCache changes by detecting which chains changed\n * and scheduling debounced persistence.\n *\n * @param newCache - The new tokensChainsCache state.\n */\n #onCacheChanged(newCache: TokensChainsCache): void {\n // Detect which chains changed by comparing with previous cache\n for (const chainId of Object.keys(newCache) as Hex[]) {\n const newData = newCache[chainId];\n const prevData = this.#previousTokensChainsCache[chainId];\n\n // Chain is new or timestamp changed (indicating data update)\n if (prevData?.timestamp !== newData.timestamp) {\n this.#changedChainsToPersist.add(chainId);\n }\n }\n\n // Update previous cache reference\n this.#previousTokensChainsCache = { ...newCache };\n\n // Schedule persistence if there are changes\n if (this.#changedChainsToPersist.size > 0) {\n this.#debouncePersist();\n }\n }\n\n /**\n * Debounce persistence of changed chains to storage.\n */\n #debouncePersist(): void {\n if (this.#persistDebounceTimer) {\n clearTimeout(this.#persistDebounceTimer);\n }\n\n this.#persistDebounceTimer = setTimeout(() => {\n // Note: #persistChangedChains handles errors internally via #saveChainCacheToStorage,\n // so this promise will not reject.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#persistChangedChains();\n }, TokenListController.#persistDebounceMs);\n }\n\n /**\n * Persist only the chains that have changed to storage.\n * Reduces write amplification by skipping unchanged chains.\n *\n * If a persist operation is already in-flight, this method returns early\n * and reschedules the debounce to ensure accumulated changes are retried\n * after the current operation completes.\n *\n * @returns A promise that resolves when changed chains are persisted.\n */\n async #persistChangedChains(): Promise<void> {\n if (this.#persistInFlightPromise) {\n // Reschedule debounce to retry accumulated changes after in-flight persist completes\n if (this.#changedChainsToPersist.size > 0) {\n this.#debouncePersist();\n }\n return;\n }\n\n const chainsToPersist = [...this.#changedChainsToPersist];\n this.#changedChainsToPersist.clear();\n\n if (chainsToPersist.length === 0) {\n return;\n }\n\n this.#persistInFlightPromise = Promise.all(\n chainsToPersist.map((chainId) => this.#saveChainCacheToStorage(chainId)),\n ).then(() => undefined);\n\n try {\n await this.#persistInFlightPromise;\n } finally {\n this.#persistInFlightPromise = undefined;\n }\n }\n\n /**\n * Synchronize tokensChainsCache between state and storage bidirectionally.\n *\n * This method:\n * 1. Loads cached chains from storage (per-chain files) in parallel\n * 2. Merges loaded data into state (preferring existing state to avoid overwriting fresh data)\n * 3. Persists any chains that exist in state but not in storage\n *\n * Called during initialization to ensure state and storage are consistent.\n *\n * @returns A promise that resolves when synchronization is complete.\n */\n async #synchronizeCacheWithStorage(): Promise<void> {\n try {\n const allKeys = await this.messenger.call(\n 'StorageService:getAllKeys',\n name,\n );\n\n // Filter keys that belong to tokensChainsCache (per-chain files)\n const cacheKeys = allKeys.filter((key) =>\n key.startsWith(`${TokenListController.#storageKeyPrefix}:`),\n );\n\n // Load all chains in parallel\n const chainCaches = await Promise.all(\n cacheKeys.map(async (key) => {\n // Extract chainId from key: 'tokensChainsCache:0x1' → '0x1'\n const chainId = key.split(':')[1] as Hex;\n\n const { result, error } = await this.messenger.call(\n 'StorageService:getItem',\n name,\n key,\n );\n\n if (error) {\n console.error(\n `TokenListController: Error loading cache for ${chainId}:`,\n error,\n );\n return null;\n }\n\n return result ? { chainId, data: result as DataCache } : null;\n }),\n );\n\n // Build complete cache from loaded chains\n const loadedCache: TokensChainsCache = {};\n chainCaches.forEach((chainCache) => {\n if (chainCache) {\n loadedCache[chainCache.chainId] = chainCache.data;\n }\n });\n\n // Chains in state _before loading persisted state_, from a recent update\n const chainsInState = new Set(\n Object.keys(this.state.tokensChainsCache) as Hex[],\n );\n\n // Merge loaded cache with existing state, preferring existing data\n // (which may be fresher if fetched during initialization)\n if (Object.keys(loadedCache).length > 0) {\n this.update((state) => {\n // Only load chains that don't already exist in state\n // This prevents overwriting fresh API data with stale cached data\n for (const [chainId, cacheData] of Object.entries(loadedCache)) {\n if (!state.tokensChainsCache[chainId as Hex]) {\n state.tokensChainsCache[chainId as Hex] = cacheData;\n }\n }\n });\n }\n\n // Persist chains that exist in state but were not loaded from storage.\n // This handles the case where initial state contains chains that don't exist\n // in storage yet (e.g., fresh data from API). Without this, those chains\n // would be lost on the next app restart.\n for (const chainId of chainsInState) {\n this.#changedChainsToPersist.add(chainId);\n }\n\n // Persist any chains that need to be saved\n if (this.#changedChainsToPersist.size > 0) {\n this.#debouncePersist();\n }\n\n this.#previousTokensChainsCache = { ...this.state.tokensChainsCache };\n } catch (error) {\n console.error(\n 'TokenListController: Failed to load cache from storage:',\n error,\n );\n }\n }\n\n /**\n * Save a specific chain's cache to StorageService.\n * This persists only the updated chain's data, reducing write amplification.\n *\n * @param chainId - The chain ID to save.\n * @returns A promise that resolves when saving is complete.\n */\n async #saveChainCacheToStorage(chainId: Hex): Promise<void> {\n try {\n const chainData = this.state.tokensChainsCache[chainId];\n\n if (!chainData) {\n console.warn(`TokenListController: No cache data for chain ${chainId}`);\n return;\n }\n\n const storageKey = TokenListController.#getChainStorageKey(chainId);\n\n await this.messenger.call(\n 'StorageService:setItem',\n name,\n storageKey,\n chainData,\n );\n } catch (error) {\n console.error(\n `TokenListController: Failed to save cache for ${chainId}:`,\n error,\n );\n }\n }\n\n /**\n * Updates state and restarts polling on changes to the network controller\n * state.\n *\n * @param networkControllerState - The updated network controller state.\n */\n async #onNetworkControllerStateChange(\n networkControllerState: NetworkState,\n ): Promise<void> {\n const selectedNetworkClient = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkControllerState.selectedNetworkClientId,\n );\n const { chainId } = selectedNetworkClient.configuration;\n\n if (this.#chainId !== chainId) {\n this.#abortController.abort();\n this.#abortController = new AbortController();\n this.#chainId = chainId;\n }\n }\n\n // Eventually we want to remove start/restart/stop controls in favor of new _executePoll API\n // Maintaining these functions for now until we can safely deprecate them for backwards compatibility\n /**\n * Start polling for the token list.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n async start(): Promise<void> {\n if (!isTokenListSupportedForNetwork(this.#chainId)) {\n return;\n }\n await this.#startDeprecatedPolling();\n }\n\n /**\n * Restart polling for the token list.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n async restart(): Promise<void> {\n this.#stopPolling();\n await this.#startDeprecatedPolling();\n }\n\n /**\n * Stop polling for the token list.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n stop(): void {\n this.#stopPolling();\n }\n\n /**\n * This stops any active polling.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n override destroy(): void {\n super.destroy();\n this.#stopPolling();\n\n // Cancel any pending debounced persistence operations\n if (this.#persistDebounceTimer) {\n clearTimeout(this.#persistDebounceTimer);\n this.#persistDebounceTimer = undefined;\n }\n this.#changedChainsToPersist.clear();\n }\n\n /**\n * This stops any active polling intervals.\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n #stopPolling(): void {\n if (this.#intervalId) {\n clearInterval(this.#intervalId);\n }\n }\n\n /**\n * Starts a new polling interval for a given chainId (this should be deprecated in favor of _executePoll)\n *\n * @deprecated This method is deprecated and will be removed in the future.\n * Consider using the new polling approach instead\n */\n async #startDeprecatedPolling(): Promise<void> {\n // renaming this to avoid collision with base class\n await safelyExecute(() => this.fetchTokenList(this.#chainId));\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#intervalId = setInterval(async () => {\n await safelyExecute(() => this.fetchTokenList(this.#chainId));\n }, this.#intervalDelay);\n }\n\n /**\n * This starts a new polling loop for any given chain. Under the hood it is deduping polls\n *\n * @param input - The input for the poll.\n * @param input.chainId - The chainId of the chain to trigger the fetch.\n * @returns A promise that resolves when this operation completes.\n */\n async _executePoll({ chainId }: TokenListPollingInput): Promise<void> {\n return this.fetchTokenList(chainId);\n }\n\n /**\n * Fetching token list from the Token Service API. This will fetch tokens across chains.\n * State changes are automatically persisted via the stateChange subscription.\n *\n * @param chainId - The chainId of the current chain triggering the fetch.\n */\n async fetchTokenList(chainId: Hex): Promise<void> {\n if (this.isCacheValid(chainId)) {\n return;\n }\n\n // Fetch fresh token list from the API\n const tokensFromAPI = await safelyExecute(\n () =>\n fetchTokenListByChainId(\n chainId,\n this.#abortController.signal,\n ) as Promise<TokenListToken[]>,\n );\n\n // Have response - process and update list\n if (tokensFromAPI) {\n // Format tokens from API (HTTP) and update tokenList\n const tokenList: TokenListMap = {};\n for (const token of tokensFromAPI) {\n tokenList[token.address] = {\n ...token,\n aggregators: formatAggregatorNames(token.aggregators),\n iconUrl: formatIconUrlWithProxy({\n chainId,\n tokenAddress: token.address,\n }),\n };\n }\n\n // Update state - persistence happens automatically via subscription\n const newDataCache: DataCache = {\n data: tokenList,\n timestamp: Date.now(),\n };\n this.update((state) => {\n state.tokensChainsCache[chainId] = newDataCache;\n });\n return;\n }\n\n // No response - fallback to previous state, or initialise empty.\n // Only initialize with a new timestamp if there's no existing cache.\n // If there's existing cache, keep it as-is without updating the timestamp\n // to avoid making stale data appear \"fresh\" and preventing retry attempts.\n if (!tokensFromAPI) {\n const existingCache = this.state.tokensChainsCache[chainId];\n if (!existingCache) {\n // No existing cache - initialize empty (persistence happens automatically)\n const newDataCache: DataCache = { data: {}, timestamp: Date.now() };\n this.update((state) => {\n state.tokensChainsCache[chainId] = newDataCache;\n });\n }\n // If there's existing cache, keep it as-is (don't update timestamp or persist)\n }\n }\n\n isCacheValid(chainId: Hex): boolean {\n const { tokensChainsCache }: TokenListState = this.state;\n const timestamp: number | undefined = tokensChainsCache[chainId]?.timestamp;\n const now = Date.now();\n return (\n timestamp !== undefined && now - timestamp < this.#cacheRefreshThreshold\n );\n }\n}\n\nexport default TokenListController;\n"]}
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _AccountsApiBalanceFetcher_instances, _AccountsApiBalanceFetcher_platform, _AccountsApiBalanceFetcher_getProvider, _AccountsApiBalanceFetcher_fetchStakedBalances, _AccountsApiBalanceFetcher_fetchBalances;
16
+ var _AccountsApiBalanceFetcher_instances, _AccountsApiBalanceFetcher_platform, _AccountsApiBalanceFetcher_getProvider, _AccountsApiBalanceFetcher_getUserTokens, _AccountsApiBalanceFetcher_fetchStakedBalances, _AccountsApiBalanceFetcher_fetchBalances;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.AccountsApiBalanceFetcher = void 0;
19
19
  const contracts_1 = require("@ethersproject/contracts");
@@ -31,12 +31,14 @@ const ACCOUNTS_API_TIMEOUT_MS = 10000;
31
31
  const checksum = (addr) => (0, controller_utils_1.toChecksumHexAddress)(addr);
32
32
  const toCaipAccount = (chainId, account) => (0, assetsUtil_1.accountAddressToCaipReference)(chainId, account);
33
33
  class AccountsApiBalanceFetcher {
34
- constructor(platform = 'extension', getProvider) {
34
+ constructor(platform = 'extension', getProvider, getUserTokens) {
35
35
  _AccountsApiBalanceFetcher_instances.add(this);
36
36
  _AccountsApiBalanceFetcher_platform.set(this, 'extension');
37
37
  _AccountsApiBalanceFetcher_getProvider.set(this, void 0);
38
+ _AccountsApiBalanceFetcher_getUserTokens.set(this, void 0);
38
39
  __classPrivateFieldSet(this, _AccountsApiBalanceFetcher_platform, platform, "f");
39
40
  __classPrivateFieldSet(this, _AccountsApiBalanceFetcher_getProvider, getProvider, "f");
41
+ __classPrivateFieldSet(this, _AccountsApiBalanceFetcher_getUserTokens, getUserTokens, "f");
40
42
  }
41
43
  supports(chainId) {
42
44
  return constants_1.SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);
@@ -91,7 +93,8 @@ class AccountsApiBalanceFetcher {
91
93
  });
92
94
  // Ensure native token entries exist for all addresses on all requested chains
93
95
  const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
94
- const nativeBalancesFromAPI = new Map(); // key: `${address}-${chainId}`
96
+ const nativeBalancesFromAPI = new Map(); // key: `${accountAddress}-${chainId}`
97
+ const nonNativeBalancesFromAPI = new Map(); // key: `${accountAddress}-${tokenAddress}-${chainId}`
95
98
  // Process regular API balances
96
99
  if (apiResponse.balances) {
97
100
  const apiBalances = apiResponse.balances.flatMap((b) => {
@@ -127,6 +130,9 @@ class AccountsApiBalanceFetcher {
127
130
  if (token === ZERO_ADDRESS && value !== undefined) {
128
131
  nativeBalancesFromAPI.set(`${finalAccount}-${chainId}`, value);
129
132
  }
133
+ if (token !== ZERO_ADDRESS && value !== undefined) {
134
+ nonNativeBalancesFromAPI.set(`${finalAccount.toLowerCase()}-${token.toLowerCase()}-${chainId}`, value);
135
+ }
130
136
  return [
131
137
  {
132
138
  success: value !== undefined,
@@ -156,6 +162,29 @@ class AccountsApiBalanceFetcher {
156
162
  }
157
163
  });
158
164
  });
165
+ // Add zero erc-20 balance entries for addresses that API didn't return
166
+ if (__classPrivateFieldGet(this, _AccountsApiBalanceFetcher_getUserTokens, "f")) {
167
+ const userTokens = __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_getUserTokens, "f").call(this);
168
+ Object.entries(userTokens).forEach(([account, chains]) => {
169
+ Object.entries(chains).forEach(([chainId, tokens]) => {
170
+ Object.entries(tokens).forEach(([tokenAddress]) => {
171
+ const tokenLowerCase = tokenAddress.toLowerCase();
172
+ const key = `${account.toLowerCase()}-${tokenLowerCase}-${chainId}`;
173
+ const isERC = tokenAddress !== ZERO_ADDRESS;
174
+ const existingBalance = nonNativeBalancesFromAPI.get(key);
175
+ if (isERC && !existingBalance) {
176
+ results.push({
177
+ success: true,
178
+ value: new bn_js_1.default('0'),
179
+ account: account,
180
+ token: tokenLowerCase,
181
+ chainId: chainId,
182
+ });
183
+ }
184
+ });
185
+ });
186
+ });
187
+ }
159
188
  // Add staked balances
160
189
  results.push(...stakedBalances);
161
190
  return {
@@ -165,7 +194,7 @@ class AccountsApiBalanceFetcher {
165
194
  }
166
195
  }
167
196
  exports.AccountsApiBalanceFetcher = AccountsApiBalanceFetcher;
168
- _AccountsApiBalanceFetcher_platform = new WeakMap(), _AccountsApiBalanceFetcher_getProvider = new WeakMap(), _AccountsApiBalanceFetcher_instances = new WeakSet(), _AccountsApiBalanceFetcher_fetchStakedBalances = async function _AccountsApiBalanceFetcher_fetchStakedBalances(addrs) {
197
+ _AccountsApiBalanceFetcher_platform = new WeakMap(), _AccountsApiBalanceFetcher_getProvider = new WeakMap(), _AccountsApiBalanceFetcher_getUserTokens = new WeakMap(), _AccountsApiBalanceFetcher_instances = new WeakSet(), _AccountsApiBalanceFetcher_fetchStakedBalances = async function _AccountsApiBalanceFetcher_fetchStakedBalances(addrs) {
169
198
  // Return empty array if no provider is available for blockchain calls
170
199
  if (!__classPrivateFieldGet(this, _AccountsApiBalanceFetcher_getProvider, "f")) {
171
200
  return [];
@@ -1 +1 @@
1
- {"version":3,"file":"api-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BigNumber } from '@ethersproject/bignumber';\nimport { Contract } from '@ethersproject/contracts';\nimport type { Web3Provider } from '@ethersproject/providers';\nimport {\n safelyExecute,\n safelyExecuteWithTimeout,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, CaipChainId, Hex } from '@metamask/utils';\nimport { parseCaipChainId } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport type { GetBalancesResponse } from './types';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n SupportedStakedBalanceNetworks,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 20;\n\n// Timeout for accounts API requests (10 seconds)\nconst ACCOUNTS_API_TIMEOUT_MS = 10_000;\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress | string;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetchResult = {\n balances: ProcessedBalance[];\n unprocessedChainIds?: ChainIdHex[];\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n jwtToken?: string;\n }): Promise<BalanceFetchResult>;\n};\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n readonly #getProvider?: GetProviderFunction;\n\n constructor(\n platform: 'extension' | 'mobile' = 'extension',\n getProvider?: GetProviderFunction,\n ) {\n this.#platform = platform;\n this.#getProvider = getProvider;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchStakedBalances(\n addrs: CaipAccountAddress[],\n ): Promise<ProcessedBalance[]> {\n // Return empty array if no provider is available for blockchain calls\n if (!this.#getProvider) {\n return [];\n }\n\n const results: ProcessedBalance[] = [];\n\n // Group addresses by chain ID\n const addressesByChain: Record<ChainIdHex, ChecksumAddress[]> = {};\n\n for (const caipAddr of addrs) {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10));\n const checksumAddress = checksum(address);\n\n if (!addressesByChain[chainId]) {\n addressesByChain[chainId] = [];\n }\n addressesByChain[chainId].push(checksumAddress);\n }\n\n // Process each supported chain\n for (const [chainId, addresses] of Object.entries(addressesByChain)) {\n const chainIdHex = chainId as ChainIdHex;\n\n // Only fetch staked balance on supported networks (mainnet and hoodi)\n if (\n ![\n SupportedStakedBalanceNetworks.Mainnet,\n SupportedStakedBalanceNetworks.Hoodi,\n ].includes(chainIdHex as SupportedStakedBalanceNetworks)\n ) {\n continue;\n }\n\n // Only fetch staked balance if contract address exists\n if (!(chainIdHex in STAKING_CONTRACT_ADDRESS_BY_CHAINID)) {\n continue;\n }\n\n const contractAddress = STAKING_CONTRACT_ADDRESS_BY_CHAINID[chainIdHex];\n const provider = this.#getProvider(chainIdHex);\n\n const abi = [\n {\n inputs: [\n { internalType: 'address', name: 'account', type: 'address' },\n ],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { internalType: 'uint256', name: 'shares', type: 'uint256' },\n ],\n name: 'convertToAssets',\n outputs: [\n { internalType: 'uint256', name: 'assets', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ];\n\n try {\n const contract = new Contract(contractAddress, abi, provider);\n\n // Get shares for each address\n for (const address of addresses) {\n try {\n const shares = await safelyExecute(() =>\n contract.getShares(address),\n );\n\n if (shares && (shares as BigNumber).gt(0)) {\n // Convert shares to assets (actual staked ETH amount)\n const assets = await safelyExecute(() =>\n contract.convertToAssets(shares),\n );\n\n if (assets) {\n results.push({\n success: true,\n value: new BN((assets as BigNumber).toString()),\n account: address,\n token: checksum(contractAddress),\n chainId: chainIdHex,\n });\n }\n } else {\n // Return zero balance for accounts with no staked assets\n results.push({\n success: true,\n value: new BN('0'),\n account: address,\n token: checksum(contractAddress),\n chainId: chainIdHex,\n });\n }\n } catch (error) {\n // Log error and continue with next address\n console.error(\n `Error fetching staked balance for ${address}:`,\n error,\n );\n results.push({\n success: false,\n account: address,\n token: checksum(contractAddress),\n chainId: chainIdHex,\n });\n }\n }\n } catch (error) {\n console.error(\n `Error setting up staking contract for chain ${chainId}:`,\n error,\n );\n }\n }\n\n return results;\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[], jwtToken?: string) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n return await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n jwtToken,\n );\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n type ResponseData = Awaited<ReturnType<typeof fetchMultiChainBalancesV4>>;\n\n const allUnprocessedNetworks = new Set<number | string>();\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const response = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n jwtToken,\n );\n // Collect unprocessed networks from each batch\n if (response.unprocessedNetworks) {\n response.unprocessedNetworks.forEach((network) =>\n allUnprocessedNetworks.add(network),\n );\n }\n return [...(workingResult || []), ...response.balances];\n },\n initialResult: [],\n });\n\n return {\n balances: allBalances,\n unprocessedNetworks: Array.from(allUnprocessedNetworks),\n } as ResponseData;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n jwtToken,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<BalanceFetchResult> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return { balances: [] };\n }\n\n // Let errors propagate to TokenBalancesController for RPC fallback\n // Use timeout to prevent hanging API calls (30 seconds)\n const apiResponse = await safelyExecuteWithTimeout(\n () => this.#fetchBalances(caipAddrs, jwtToken),\n false, // don't log error here, let it propagate\n ACCOUNTS_API_TIMEOUT_MS,\n );\n\n // If API call timed out or failed, throw error to trigger RPC fallback\n if (!apiResponse) {\n throw new Error('Accounts API request timed out or failed');\n }\n\n // Extract unprocessed networks and convert to hex chain IDs\n // V4 API returns CAIP chain IDs like 'eip155:1329', need to parse them\n // V2 API returns decimal numbers, handle both cases\n const unprocessedChainIds: ChainIdHex[] | undefined = apiResponse\n .unprocessedNetworks?.length\n ? apiResponse.unprocessedNetworks.map((network) => {\n if (typeof network === 'string') {\n // CAIP chain ID format: 'eip155:1329'\n return toHex(parseCaipChainId(network as CaipChainId).reference);\n }\n // Decimal number format\n return toHex(network);\n })\n : undefined;\n\n const stakedBalances = await this.#fetchStakedBalances(caipAddrs);\n\n const results: ProcessedBalance[] = [];\n\n // Collect all unique addresses and chains from the CAIP addresses\n const addressChainMap = new Map<string, Set<ChainIdHex>>();\n caipAddrs.forEach((caipAddr) => {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10));\n const checksumAddress = checksum(address);\n\n if (!addressChainMap.has(checksumAddress)) {\n addressChainMap.set(checksumAddress, new Set());\n }\n addressChainMap.get(checksumAddress)?.add(chainId);\n });\n\n // Ensure native token entries exist for all addresses on all requested chains\n const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n const nativeBalancesFromAPI = new Map<string, BN>(); // key: `${address}-${chainId}`\n\n // Process regular API balances\n if (apiResponse.balances) {\n const apiBalances = apiResponse.balances.flatMap(\n (b: GetBalancesResponse['balances'][number]) => {\n const addressPart = b.accountAddress?.split(':')[2];\n if (!addressPart) {\n return [];\n }\n const account = checksum(addressPart);\n const token = checksum(b.address);\n // Use original address for zero address tokens, checksummed for others\n // TODO: this is a hack to get the correct account address type but needs to be fixed\n // by mgrating tokenBalancesController to checksum addresses\n const finalAccount: ChecksumAddress | string =\n token === ZERO_ADDRESS ? account : addressPart;\n const chainId = toHex(b.chainId);\n\n let value: BN | undefined;\n try {\n // Convert string balance to BN avoiding floating point precision issues\n const { balance: balanceStr, decimals } = b;\n\n // Split the balance string into integer and decimal parts\n const [integerPart = '0', decimalPart = ''] = balanceStr.split('.');\n\n // Pad or truncate decimal part to match token decimals\n const paddedDecimalPart = decimalPart\n .padEnd(decimals, '0')\n .slice(0, decimals);\n\n // Combine and create BN\n const fullIntegerStr = integerPart + paddedDecimalPart;\n value = new BN(fullIntegerStr);\n } catch {\n value = undefined;\n }\n\n // Track native balances for later\n if (token === ZERO_ADDRESS && value !== undefined) {\n nativeBalancesFromAPI.set(`${finalAccount}-${chainId}`, value);\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account: finalAccount,\n token,\n chainId,\n },\n ];\n },\n );\n results.push(...apiBalances);\n }\n\n // Add zero native balance entries for addresses that API didn't return\n addressChainMap.forEach((chains, address) => {\n chains.forEach((chainId) => {\n const key = `${address}-${chainId}`;\n const existingBalance = nativeBalancesFromAPI.get(key);\n\n if (!existingBalance) {\n // Add zero native balance entry if API succeeded but didn't return one\n results.push({\n success: true,\n value: new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n }\n });\n });\n\n // Add staked balances\n results.push(...stakedBalances);\n\n return {\n balances: results,\n unprocessedChainIds,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"api-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BigNumber } from '@ethersproject/bignumber';\nimport { Contract } from '@ethersproject/contracts';\nimport type { Web3Provider } from '@ethersproject/providers';\nimport {\n safelyExecute,\n safelyExecuteWithTimeout,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, CaipChainId, Hex } from '@metamask/utils';\nimport { parseCaipChainId } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport type { GetBalancesResponse } from './types';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n SupportedStakedBalanceNetworks,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 20;\n\n// Timeout for accounts API requests (10 seconds)\nconst ACCOUNTS_API_TIMEOUT_MS = 10_000;\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress | string;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetchResult = {\n balances: ProcessedBalance[];\n unprocessedChainIds?: ChainIdHex[];\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n jwtToken?: string;\n }): Promise<BalanceFetchResult>;\n};\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n readonly #getProvider?: GetProviderFunction;\n\n readonly #getUserTokens?: () => {\n [accountId: ChecksumAddress]: {\n [chainId: ChainIdHex]: { [tokenAddress: ChecksumAddress]: unknown };\n };\n };\n\n constructor(\n platform: 'extension' | 'mobile' = 'extension',\n getProvider?: GetProviderFunction,\n getUserTokens?: () => {\n [account: ChecksumAddress]: {\n [chainId: ChainIdHex]: { [tokenAddress: ChecksumAddress]: unknown };\n };\n },\n ) {\n this.#platform = platform;\n this.#getProvider = getProvider;\n this.#getUserTokens = getUserTokens;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchStakedBalances(\n addrs: CaipAccountAddress[],\n ): Promise<ProcessedBalance[]> {\n // Return empty array if no provider is available for blockchain calls\n if (!this.#getProvider) {\n return [];\n }\n\n const results: ProcessedBalance[] = [];\n\n // Group addresses by chain ID\n const addressesByChain: Record<ChainIdHex, ChecksumAddress[]> = {};\n\n for (const caipAddr of addrs) {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10));\n const checksumAddress = checksum(address);\n\n if (!addressesByChain[chainId]) {\n addressesByChain[chainId] = [];\n }\n addressesByChain[chainId].push(checksumAddress);\n }\n\n // Process each supported chain\n for (const [chainId, addresses] of Object.entries(addressesByChain)) {\n const chainIdHex = chainId as ChainIdHex;\n\n // Only fetch staked balance on supported networks (mainnet and hoodi)\n if (\n ![\n SupportedStakedBalanceNetworks.Mainnet,\n SupportedStakedBalanceNetworks.Hoodi,\n ].includes(chainIdHex as SupportedStakedBalanceNetworks)\n ) {\n continue;\n }\n\n // Only fetch staked balance if contract address exists\n if (!(chainIdHex in STAKING_CONTRACT_ADDRESS_BY_CHAINID)) {\n continue;\n }\n\n const contractAddress = STAKING_CONTRACT_ADDRESS_BY_CHAINID[chainIdHex];\n const provider = this.#getProvider(chainIdHex);\n\n const abi = [\n {\n inputs: [\n { internalType: 'address', name: 'account', type: 'address' },\n ],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { internalType: 'uint256', name: 'shares', type: 'uint256' },\n ],\n name: 'convertToAssets',\n outputs: [\n { internalType: 'uint256', name: 'assets', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ];\n\n try {\n const contract = new Contract(contractAddress, abi, provider);\n\n // Get shares for each address\n for (const address of addresses) {\n try {\n const shares = await safelyExecute(() =>\n contract.getShares(address),\n );\n\n if (shares && (shares as BigNumber).gt(0)) {\n // Convert shares to assets (actual staked ETH amount)\n const assets = await safelyExecute(() =>\n contract.convertToAssets(shares),\n );\n\n if (assets) {\n results.push({\n success: true,\n value: new BN((assets as BigNumber).toString()),\n account: address,\n token: checksum(contractAddress),\n chainId: chainIdHex,\n });\n }\n } else {\n // Return zero balance for accounts with no staked assets\n results.push({\n success: true,\n value: new BN('0'),\n account: address,\n token: checksum(contractAddress),\n chainId: chainIdHex,\n });\n }\n } catch (error) {\n // Log error and continue with next address\n console.error(\n `Error fetching staked balance for ${address}:`,\n error,\n );\n results.push({\n success: false,\n account: address,\n token: checksum(contractAddress),\n chainId: chainIdHex,\n });\n }\n }\n } catch (error) {\n console.error(\n `Error setting up staking contract for chain ${chainId}:`,\n error,\n );\n }\n }\n\n return results;\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[], jwtToken?: string) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n return await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n jwtToken,\n );\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n type ResponseData = Awaited<ReturnType<typeof fetchMultiChainBalancesV4>>;\n\n const allUnprocessedNetworks = new Set<number | string>();\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const response = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n jwtToken,\n );\n // Collect unprocessed networks from each batch\n if (response.unprocessedNetworks) {\n response.unprocessedNetworks.forEach((network) =>\n allUnprocessedNetworks.add(network),\n );\n }\n return [...(workingResult || []), ...response.balances];\n },\n initialResult: [],\n });\n\n return {\n balances: allBalances,\n unprocessedNetworks: Array.from(allUnprocessedNetworks),\n } as ResponseData;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n jwtToken,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<BalanceFetchResult> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return { balances: [] };\n }\n\n // Let errors propagate to TokenBalancesController for RPC fallback\n // Use timeout to prevent hanging API calls (30 seconds)\n const apiResponse = await safelyExecuteWithTimeout(\n () => this.#fetchBalances(caipAddrs, jwtToken),\n false, // don't log error here, let it propagate\n ACCOUNTS_API_TIMEOUT_MS,\n );\n\n // If API call timed out or failed, throw error to trigger RPC fallback\n if (!apiResponse) {\n throw new Error('Accounts API request timed out or failed');\n }\n\n // Extract unprocessed networks and convert to hex chain IDs\n // V4 API returns CAIP chain IDs like 'eip155:1329', need to parse them\n // V2 API returns decimal numbers, handle both cases\n const unprocessedChainIds: ChainIdHex[] | undefined = apiResponse\n .unprocessedNetworks?.length\n ? apiResponse.unprocessedNetworks.map((network) => {\n if (typeof network === 'string') {\n // CAIP chain ID format: 'eip155:1329'\n return toHex(parseCaipChainId(network as CaipChainId).reference);\n }\n // Decimal number format\n return toHex(network);\n })\n : undefined;\n\n const stakedBalances = await this.#fetchStakedBalances(caipAddrs);\n\n const results: ProcessedBalance[] = [];\n\n // Collect all unique addresses and chains from the CAIP addresses\n const addressChainMap = new Map<string, Set<ChainIdHex>>();\n caipAddrs.forEach((caipAddr) => {\n const [, chainRef, address] = caipAddr.split(':');\n const chainId = toHex(parseInt(chainRef, 10));\n const checksumAddress = checksum(address);\n\n if (!addressChainMap.has(checksumAddress)) {\n addressChainMap.set(checksumAddress, new Set());\n }\n addressChainMap.get(checksumAddress)?.add(chainId);\n });\n\n // Ensure native token entries exist for all addresses on all requested chains\n const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n const nativeBalancesFromAPI = new Map<string, BN>(); // key: `${accountAddress}-${chainId}`\n const nonNativeBalancesFromAPI = new Map<string, BN>(); // key: `${accountAddress}-${tokenAddress}-${chainId}`\n\n // Process regular API balances\n if (apiResponse.balances) {\n const apiBalances = apiResponse.balances.flatMap(\n (b: GetBalancesResponse['balances'][number]) => {\n const addressPart = b.accountAddress?.split(':')[2];\n if (!addressPart) {\n return [];\n }\n const account = checksum(addressPart);\n const token = checksum(b.address);\n // Use original address for zero address tokens, checksummed for others\n // TODO: this is a hack to get the correct account address type but needs to be fixed\n // by mgrating tokenBalancesController to checksum addresses\n const finalAccount: ChecksumAddress | string =\n token === ZERO_ADDRESS ? account : addressPart;\n const chainId = toHex(b.chainId);\n\n let value: BN | undefined;\n try {\n // Convert string balance to BN avoiding floating point precision issues\n const { balance: balanceStr, decimals } = b;\n\n // Split the balance string into integer and decimal parts\n const [integerPart = '0', decimalPart = ''] = balanceStr.split('.');\n\n // Pad or truncate decimal part to match token decimals\n const paddedDecimalPart = decimalPart\n .padEnd(decimals, '0')\n .slice(0, decimals);\n\n // Combine and create BN\n const fullIntegerStr = integerPart + paddedDecimalPart;\n value = new BN(fullIntegerStr);\n } catch {\n value = undefined;\n }\n\n // Track native balances for later\n if (token === ZERO_ADDRESS && value !== undefined) {\n nativeBalancesFromAPI.set(`${finalAccount}-${chainId}`, value);\n }\n\n if (token !== ZERO_ADDRESS && value !== undefined) {\n nonNativeBalancesFromAPI.set(\n `${finalAccount.toLowerCase()}-${token.toLowerCase()}-${chainId}`,\n value,\n );\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account: finalAccount,\n token,\n chainId,\n },\n ];\n },\n );\n results.push(...apiBalances);\n }\n\n // Add zero native balance entries for addresses that API didn't return\n addressChainMap.forEach((chains, address) => {\n chains.forEach((chainId) => {\n const key = `${address}-${chainId}`;\n const existingBalance = nativeBalancesFromAPI.get(key);\n\n if (!existingBalance) {\n // Add zero native balance entry if API succeeded but didn't return one\n results.push({\n success: true,\n value: new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n }\n });\n });\n\n // Add zero erc-20 balance entries for addresses that API didn't return\n if (this.#getUserTokens) {\n const userTokens = this.#getUserTokens();\n Object.entries(userTokens).forEach(([account, chains]) => {\n Object.entries(chains).forEach(([chainId, tokens]) => {\n Object.entries(tokens).forEach(([tokenAddress]) => {\n const tokenLowerCase = tokenAddress.toLowerCase();\n const key = `${account.toLowerCase()}-${tokenLowerCase}-${chainId}`;\n const isERC = tokenAddress !== ZERO_ADDRESS;\n const existingBalance = nonNativeBalancesFromAPI.get(key);\n if (isERC && !existingBalance) {\n results.push({\n success: true,\n value: new BN('0'),\n account: account as ChecksumAddress,\n token: tokenLowerCase as ChecksumAddress,\n chainId: chainId as ChainIdHex,\n });\n }\n });\n });\n });\n }\n\n // Add staked balances\n results.push(...stakedBalances);\n\n return {\n balances: results,\n unprocessedChainIds,\n };\n }\n}\n"]}
@@ -28,7 +28,13 @@ export type BalanceFetcher = {
28
28
  export type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;
29
29
  export declare class AccountsApiBalanceFetcher implements BalanceFetcher {
30
30
  #private;
31
- constructor(platform?: 'extension' | 'mobile', getProvider?: GetProviderFunction);
31
+ constructor(platform?: 'extension' | 'mobile', getProvider?: GetProviderFunction, getUserTokens?: () => {
32
+ [account: ChecksumAddress]: {
33
+ [chainId: ChainIdHex]: {
34
+ [tokenAddress: ChecksumAddress]: unknown;
35
+ };
36
+ };
37
+ });
32
38
  supports(chainId: ChainIdHex): boolean;
33
39
  fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, jwtToken, }: Parameters<BalanceFetcher['fetch']>[0]): Promise<BalanceFetchResult>;
34
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAO7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAmC,GAAG,EAAE,wBAAwB;AAE5E,OAAO,EAAE,cAAc;AAkBvB,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjC,CAAC;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAM5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB;IAMnC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAoLhC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,QAAQ,GACT,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAsJxE"}
1
+ {"version":3,"file":"api-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAO7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAmC,GAAG,EAAE,wBAAwB;AAE5E,OAAO,EAAE,cAAc;AAkBvB,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjC,CAAC;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAY5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB,EACjC,aAAa,CAAC,EAAE,MAAM;QACpB,CAAC,OAAO,EAAE,eAAe,GAAG;YAC1B,CAAC,OAAO,EAAE,UAAU,GAAG;gBAAE,CAAC,YAAY,EAAE,eAAe,GAAG,OAAO,CAAA;aAAE,CAAC;SACrE,CAAC;KACH;IAOH,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAoLhC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,QAAQ,GACT,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAsLxE"}
@@ -28,7 +28,13 @@ export type BalanceFetcher = {
28
28
  export type GetProviderFunction = (chainId: ChainIdHex) => Web3Provider;
29
29
  export declare class AccountsApiBalanceFetcher implements BalanceFetcher {
30
30
  #private;
31
- constructor(platform?: 'extension' | 'mobile', getProvider?: GetProviderFunction);
31
+ constructor(platform?: 'extension' | 'mobile', getProvider?: GetProviderFunction, getUserTokens?: () => {
32
+ [account: ChecksumAddress]: {
33
+ [chainId: ChainIdHex]: {
34
+ [tokenAddress: ChecksumAddress]: unknown;
35
+ };
36
+ };
37
+ });
32
38
  supports(chainId: ChainIdHex): boolean;
33
39
  fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, jwtToken, }: Parameters<BalanceFetcher['fetch']>[0]): Promise<BalanceFetchResult>;
34
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAO7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAmC,GAAG,EAAE,wBAAwB;AAE5E,OAAO,EAAE,cAAc;AAkBvB,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjC,CAAC;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAM5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB;IAMnC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAoLhC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,QAAQ,GACT,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAsJxE"}
1
+ {"version":3,"file":"api-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,iCAAiC;AAO7D,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAmC,GAAG,EAAE,wBAAwB;AAE5E,OAAO,EAAE,cAAc;AAkBvB,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjC,CAAC;AAUF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,UAAU,KAAK,YAAY,CAAC;AAExE,qBAAa,yBAA0B,YAAW,cAAc;;gBAY5D,QAAQ,GAAE,WAAW,GAAG,QAAsB,EAC9C,WAAW,CAAC,EAAE,mBAAmB,EACjC,aAAa,CAAC,EAAE,MAAM;QACpB,CAAC,OAAO,EAAE,eAAe,GAAG;YAC1B,CAAC,OAAO,EAAE,UAAU,GAAG;gBAAE,CAAC,YAAY,EAAE,eAAe,GAAG,OAAO,CAAA;aAAE,CAAC;SACrE,CAAC;KACH;IAOH,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAoLhC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,QAAQ,GACT,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAsLxE"}
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _AccountsApiBalanceFetcher_instances, _AccountsApiBalanceFetcher_platform, _AccountsApiBalanceFetcher_getProvider, _AccountsApiBalanceFetcher_fetchStakedBalances, _AccountsApiBalanceFetcher_fetchBalances;
12
+ var _AccountsApiBalanceFetcher_instances, _AccountsApiBalanceFetcher_platform, _AccountsApiBalanceFetcher_getProvider, _AccountsApiBalanceFetcher_getUserTokens, _AccountsApiBalanceFetcher_fetchStakedBalances, _AccountsApiBalanceFetcher_fetchBalances;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -32,12 +32,14 @@ const ACCOUNTS_API_TIMEOUT_MS = 10000;
32
32
  const checksum = (addr) => toChecksumHexAddress(addr);
33
33
  const toCaipAccount = (chainId, account) => accountAddressToCaipReference(chainId, account);
34
34
  export class AccountsApiBalanceFetcher {
35
- constructor(platform = 'extension', getProvider) {
35
+ constructor(platform = 'extension', getProvider, getUserTokens) {
36
36
  _AccountsApiBalanceFetcher_instances.add(this);
37
37
  _AccountsApiBalanceFetcher_platform.set(this, 'extension');
38
38
  _AccountsApiBalanceFetcher_getProvider.set(this, void 0);
39
+ _AccountsApiBalanceFetcher_getUserTokens.set(this, void 0);
39
40
  __classPrivateFieldSet(this, _AccountsApiBalanceFetcher_platform, platform, "f");
40
41
  __classPrivateFieldSet(this, _AccountsApiBalanceFetcher_getProvider, getProvider, "f");
42
+ __classPrivateFieldSet(this, _AccountsApiBalanceFetcher_getUserTokens, getUserTokens, "f");
41
43
  }
42
44
  supports(chainId) {
43
45
  return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);
@@ -92,7 +94,8 @@ export class AccountsApiBalanceFetcher {
92
94
  });
93
95
  // Ensure native token entries exist for all addresses on all requested chains
94
96
  const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
95
- const nativeBalancesFromAPI = new Map(); // key: `${address}-${chainId}`
97
+ const nativeBalancesFromAPI = new Map(); // key: `${accountAddress}-${chainId}`
98
+ const nonNativeBalancesFromAPI = new Map(); // key: `${accountAddress}-${tokenAddress}-${chainId}`
96
99
  // Process regular API balances
97
100
  if (apiResponse.balances) {
98
101
  const apiBalances = apiResponse.balances.flatMap((b) => {
@@ -128,6 +131,9 @@ export class AccountsApiBalanceFetcher {
128
131
  if (token === ZERO_ADDRESS && value !== undefined) {
129
132
  nativeBalancesFromAPI.set(`${finalAccount}-${chainId}`, value);
130
133
  }
134
+ if (token !== ZERO_ADDRESS && value !== undefined) {
135
+ nonNativeBalancesFromAPI.set(`${finalAccount.toLowerCase()}-${token.toLowerCase()}-${chainId}`, value);
136
+ }
131
137
  return [
132
138
  {
133
139
  success: value !== undefined,
@@ -157,6 +163,29 @@ export class AccountsApiBalanceFetcher {
157
163
  }
158
164
  });
159
165
  });
166
+ // Add zero erc-20 balance entries for addresses that API didn't return
167
+ if (__classPrivateFieldGet(this, _AccountsApiBalanceFetcher_getUserTokens, "f")) {
168
+ const userTokens = __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_getUserTokens, "f").call(this);
169
+ Object.entries(userTokens).forEach(([account, chains]) => {
170
+ Object.entries(chains).forEach(([chainId, tokens]) => {
171
+ Object.entries(tokens).forEach(([tokenAddress]) => {
172
+ const tokenLowerCase = tokenAddress.toLowerCase();
173
+ const key = `${account.toLowerCase()}-${tokenLowerCase}-${chainId}`;
174
+ const isERC = tokenAddress !== ZERO_ADDRESS;
175
+ const existingBalance = nonNativeBalancesFromAPI.get(key);
176
+ if (isERC && !existingBalance) {
177
+ results.push({
178
+ success: true,
179
+ value: new BN('0'),
180
+ account: account,
181
+ token: tokenLowerCase,
182
+ chainId: chainId,
183
+ });
184
+ }
185
+ });
186
+ });
187
+ });
188
+ }
160
189
  // Add staked balances
161
190
  results.push(...stakedBalances);
162
191
  return {
@@ -165,7 +194,7 @@ export class AccountsApiBalanceFetcher {
165
194
  };
166
195
  }
167
196
  }
168
- _AccountsApiBalanceFetcher_platform = new WeakMap(), _AccountsApiBalanceFetcher_getProvider = new WeakMap(), _AccountsApiBalanceFetcher_instances = new WeakSet(), _AccountsApiBalanceFetcher_fetchStakedBalances = async function _AccountsApiBalanceFetcher_fetchStakedBalances(addrs) {
197
+ _AccountsApiBalanceFetcher_platform = new WeakMap(), _AccountsApiBalanceFetcher_getProvider = new WeakMap(), _AccountsApiBalanceFetcher_getUserTokens = new WeakMap(), _AccountsApiBalanceFetcher_instances = new WeakSet(), _AccountsApiBalanceFetcher_fetchStakedBalances = async function _AccountsApiBalanceFetcher_fetchStakedBalances(addrs) {
169
198
  // Return empty array if no provider is available for blockchain calls
170
199
  if (!__classPrivateFieldGet(this, _AccountsApiBalanceFetcher_getProvider, "f")) {
171
200
  return [];