@metamask/assets-controller 9.0.2 → 9.1.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.
- package/CHANGELOG.md +24 -1
- package/dist/AssetsController.cjs +6 -15
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +6 -15
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.mjs +1 -1
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
- package/dist/data-sources/PriceDataSource.cjs +64 -13
- package/dist/data-sources/PriceDataSource.cjs.map +1 -1
- package/dist/data-sources/PriceDataSource.d.cts +13 -0
- package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
- package/dist/data-sources/PriceDataSource.d.mts +13 -0
- package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
- package/dist/data-sources/PriceDataSource.mjs +64 -13
- package/dist/data-sources/PriceDataSource.mjs.map +1 -1
- package/dist/data-sources/SnapDataSource.cjs +2 -2
- package/dist/data-sources/SnapDataSource.cjs.map +1 -1
- package/dist/data-sources/SnapDataSource.mjs +2 -2
- package/dist/data-sources/SnapDataSource.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.cjs +43 -23
- package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.cts +12 -13
- package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.mts +12 -13
- package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.mjs +43 -23
- package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
- package/dist/selectors/balance.cjs +191 -8
- package/dist/selectors/balance.cjs.map +1 -1
- package/dist/selectors/balance.d.cts +80 -0
- package/dist/selectors/balance.d.cts.map +1 -1
- package/dist/selectors/balance.d.mts +80 -0
- package/dist/selectors/balance.d.mts.map +1 -1
- package/dist/selectors/balance.mjs +186 -7
- package/dist/selectors/balance.mjs.map +1 -1
- package/dist/utils/dedupingBatchFetcher.cjs +157 -0
- package/dist/utils/dedupingBatchFetcher.cjs.map +1 -0
- package/dist/utils/dedupingBatchFetcher.d.cts +65 -0
- package/dist/utils/dedupingBatchFetcher.d.cts.map +1 -0
- package/dist/utils/dedupingBatchFetcher.d.mts +65 -0
- package/dist/utils/dedupingBatchFetcher.d.mts.map +1 -0
- package/dist/utils/dedupingBatchFetcher.mjs +153 -0
- package/dist/utils/dedupingBatchFetcher.mjs.map +1 -0
- package/package.json +5 -5
|
@@ -168,7 +168,7 @@ class AccountsApiDataSource extends AbstractDataSource_1.AbstractDataSource {
|
|
|
168
168
|
}
|
|
169
169
|
const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV5Balances).call(this, apiResponse.balances, request);
|
|
170
170
|
response.assetsBalance = assetsBalance;
|
|
171
|
-
response.updateMode = '
|
|
171
|
+
response.updateMode = 'merge';
|
|
172
172
|
}
|
|
173
173
|
catch (error) {
|
|
174
174
|
log('Fetch FAILED', { error, chains: chainsToFetch });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountsApiDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V5BalanceItem } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n DataRequest,\n DataResponse,\n Middleware,\n AssetsControllerStateInternal,\n} from '../types';\nimport { fetchWithTimeout, normalizeAssetId } from '../utils';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'AccountsApiDataSource';\nconst DEFAULT_POLL_INTERVAL = 30_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that AccountsApiDataSource can call (none - uses callbacks).\n// Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed\nexport type AccountsApiDataSourceAllowedActions = never;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type AccountsApiDataSourceState = DataSourceState;\n\nconst defaultState: AccountsApiDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\n/** Optional configuration for AccountsApiDataSource. */\nexport type AccountsApiDataSourceConfig = {\n /** Polling interval in ms (default: 30000) */\n pollInterval?: number;\n /**\n * Function returning whether token detection is enabled (default: () => true).\n * When it returns false, balances are only returned for tokens already in state.\n * Using a getter avoids stale values when the user toggles the preference at runtime.\n */\n tokenDetectionEnabled?: () => boolean;\n /**\n * Timeout in ms for a single balances fetch call (default: 15000).\n * When it fires, every requested chain is marked as errored so the\n * middleware hands them off to the next data source (e.g. RPC fallback).\n */\n fetchTimeoutMs?: number;\n};\n\nexport type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\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 state?: Partial<AccountsApiDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nfunction decimalToChainId(decimalChainId: number | string): ChainId {\n // Handle both decimal numbers and already-formatted CAIP chain IDs\n if (typeof decimalChainId === 'string') {\n if (isCaipChainId(decimalChainId)) {\n return decimalChainId;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, decimalChainId);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(decimalChainId));\n}\n\n/**\n * Convert a CAIP-2 chain ID from the API response to our ChainId type.\n * Handles both formats: \"eip155:1\" or just \"1\" (decimal).\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdStr - The chain ID string to convert.\n * @returns The normalized ChainId.\n */\nfunction caipChainIdToChainId(chainIdStr: string): ChainId {\n if (isCaipChainId(chainIdStr)) {\n return chainIdStr;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdStr);\n}\n\n/**\n * Filter a response to only include balances for assets already in state.\n * Used when tokenDetectionEnabled is false to prevent adding new tokens.\n *\n * @param response - The fetch response to filter.\n * @param assetsState - Current assets controller state to check existing balances against.\n * @returns A new response with only known asset balances.\n */\nexport function filterResponseToKnownAssets(\n response: DataResponse,\n assetsState: AssetsControllerStateInternal,\n): DataResponse {\n if (!response.assetsBalance) {\n return response;\n }\n\n const filteredBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const existingBalances = assetsState.assetsBalance[accountId];\n if (!existingBalances) {\n // Account has no balances in state yet — skip all its tokens\n continue;\n }\n\n const filtered: Record<Caip19AssetId, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(accountBalances)) {\n // Only include assets already tracked in state\n if (assetId in existingBalances) {\n filtered[assetId as Caip19AssetId] = balance;\n }\n }\n\n if (Object.keys(filtered).length > 0) {\n filteredBalance[accountId] = filtered;\n }\n }\n\n return {\n ...response,\n assetsBalance:\n Object.keys(filteredBalance).length > 0 ? filteredBalance : undefined,\n };\n}\n\n// ============================================================================\n// ACCOUNTS API DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for fetching balances from the MetaMask Accounts API.\n *\n * Uses ApiPlatformClient (queryApiClient) for all API calls. Does not use the\n * messenger. Reports active chains via onActiveChainsUpdated callback.\n */\nexport class AccountsApiDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n AccountsApiDataSourceState\n> {\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #fetchTimeoutMs: number;\n\n /** Getter avoids stale value when user toggles token detection at runtime. */\n readonly #tokenDetectionEnabled: () => boolean;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** State accessor from subscriptions (for filtering when tokenDetectionEnabled is false) */\n #getAssetsState?: () => AssetsControllerStateInternal;\n\n constructor(options: AccountsApiDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#apiClient = options.queryApiClient;\n\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n\n // Periodically refresh active chains (every 20 minutes)\n this.#chainsRefreshTimer = setInterval(\n () => {\n this.#refreshActiveChains().catch(console.error);\n },\n 20 * 60 * 1000,\n );\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n // Check if chains changed\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n\n // Use fullSupport networks as active chains\n return (\n response.fullSupport\n .map(decimalToChainId)\n // TODO Restore solana when there is a fix for how we handle non-evm chains here\n .filter((chainId) => chainId.startsWith('eip155:'))\n );\n }\n\n // ============================================================================\n // ACCOUNT SCOPE HELPERS\n // ============================================================================\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n let response: DataResponse = {};\n\n // Filter to only chains supported by Accounts API\n const supportedChains = new Set(this.state.activeChains);\n const chainsToFetch = request.chainIds.filter((chainId) =>\n supportedChains.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n return response;\n }\n\n try {\n // Build CAIP-10 account IDs (e.g., \"eip155:1:0x1234...\")\n // Use pre-computed supportedChains per account from the request\n const accountIds = request.accountsWithSupportedChains.flatMap(\n ({ account, supportedChains: accountChains }) =>\n chainsToFetch\n .filter((chainId) => accountChains.includes(chainId))\n .map((chainId) => `${chainId}:${account.address}`),\n );\n\n // Skip API call if no valid account-chain combinations\n if (accountIds.length === 0) {\n return response;\n }\n\n const apiResponse = await fetchWithTimeout(\n () => this.#apiClient.accounts.fetchV5MultiAccountBalances(accountIds),\n this.#fetchTimeoutMs,\n );\n\n // Handle unprocessed networks - these will be passed to next middleware\n if (apiResponse.unprocessedNetworks.length > 0) {\n const unprocessedChainIds =\n apiResponse.unprocessedNetworks.map(caipChainIdToChainId);\n\n // Add unprocessed chains to errors so middleware passes them to next data source\n response.errors = response.errors ?? {};\n for (const chainId of unprocessedChainIds) {\n response.errors[chainId] = 'Unprocessed by Accounts API';\n }\n }\n\n const { assetsBalance } = this.#processV5Balances(\n apiResponse.balances,\n request,\n );\n\n response.assetsBalance = assetsBalance;\n response.updateMode = 'full';\n } catch (error) {\n log('Fetch FAILED', { error, chains: chainsToFetch });\n\n // On error, mark all chains as errors so they can be handled by next middleware\n response.errors = response.errors ?? {};\n for (const chainId of chainsToFetch) {\n response.errors[chainId] =\n `Fetch failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n\n // When token detection is disabled, filter out tokens not already in state\n if (!this.#tokenDetectionEnabled() && this.#getAssetsState) {\n response = filterResponseToKnownAssets(response, this.#getAssetsState());\n }\n\n return response;\n }\n\n /**\n * Process V5 API balances response.\n * V5 returns a flat array of balance items, each with accountId and assetId.\n *\n * @param balances - Array of balance items from the V5 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV5Balances(\n balances: V5BalanceItem[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = new Map<string, string>();\n for (const { account } of request.accountsWithSupportedChains) {\n if (account.address) {\n addressToAccountId.set(account.address.toLowerCase(), account.id);\n }\n }\n\n // V5 response: array of { accountId, assetId, balance, ... }\n for (const item of balances) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = item.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(item.assetId as Caip19AssetId);\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n\n return { assetsBalance };\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Accounts API.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Uses unprocessedNetworks from API response to determine what to pass to next middleware\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // If no chains requested, skip to next middleware\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n const response = await this.fetch(request);\n\n // Merge response into context\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 ...accountBalances,\n };\n }\n }\n\n // Determine successfully handled chains (exclude unprocessed/error chains)\n const unprocessedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = request.chainIds.filter(\n (chainId) => !unprocessedChains.has(chainId),\n );\n\n // When token detection is off and we filtered out all balance data (e.g. new\n // account with empty state), do not claim any chain as handled so that RPC\n // middleware can still process them and fetch native balances (ETH, MATIC, etc.).\n if (\n !this.#tokenDetectionEnabled() &&\n (!response.assetsBalance ||\n Object.keys(response.assetsBalance).length === 0)\n ) {\n successfullyHandledChains = [];\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Remove successfully handled chains from request for next middleware\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 // No chains handled - pass context unchanged\n return next(context);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Store state accessor for filtering when tokenDetectionEnabled is false\n if (subscriptionRequest.getAssetsState) {\n this.#getAssetsState = subscriptionRequest.getAssetsState;\n }\n\n // Try all requested chains - API will handle unsupported ones via unprocessedNetworks\n const chainsToSubscribe = request.chainIds;\n\n if (chainsToSubscribe.length === 0) {\n return;\n }\n\n // Handle subscription update - update both chains AND request (for accounts)\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = chainsToSubscribe;\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function for this subscription\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (!subscription?.request) {\n return;\n }\n\n // Use stored request (which gets updated on account changes)\n const fetchResponse = await this.fetch({\n ...subscription.request,\n chainIds: subscription.chains,\n });\n\n // Report update to AssetsController via callback\n await subscription.onAssetsUpdate(fetchResponse);\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription with request for account updates\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // Clean up timers\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n }\n\n // Clean up subscriptions\n super.destroy();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccountsApiDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V5BalanceItem } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n DataRequest,\n DataResponse,\n Middleware,\n AssetsControllerStateInternal,\n} from '../types';\nimport { fetchWithTimeout, normalizeAssetId } from '../utils';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'AccountsApiDataSource';\nconst DEFAULT_POLL_INTERVAL = 30_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that AccountsApiDataSource can call (none - uses callbacks).\n// Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed\nexport type AccountsApiDataSourceAllowedActions = never;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type AccountsApiDataSourceState = DataSourceState;\n\nconst defaultState: AccountsApiDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\n/** Optional configuration for AccountsApiDataSource. */\nexport type AccountsApiDataSourceConfig = {\n /** Polling interval in ms (default: 30000) */\n pollInterval?: number;\n /**\n * Function returning whether token detection is enabled (default: () => true).\n * When it returns false, balances are only returned for tokens already in state.\n * Using a getter avoids stale values when the user toggles the preference at runtime.\n */\n tokenDetectionEnabled?: () => boolean;\n /**\n * Timeout in ms for a single balances fetch call (default: 15000).\n * When it fires, every requested chain is marked as errored so the\n * middleware hands them off to the next data source (e.g. RPC fallback).\n */\n fetchTimeoutMs?: number;\n};\n\nexport type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\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 state?: Partial<AccountsApiDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nfunction decimalToChainId(decimalChainId: number | string): ChainId {\n // Handle both decimal numbers and already-formatted CAIP chain IDs\n if (typeof decimalChainId === 'string') {\n if (isCaipChainId(decimalChainId)) {\n return decimalChainId;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, decimalChainId);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(decimalChainId));\n}\n\n/**\n * Convert a CAIP-2 chain ID from the API response to our ChainId type.\n * Handles both formats: \"eip155:1\" or just \"1\" (decimal).\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdStr - The chain ID string to convert.\n * @returns The normalized ChainId.\n */\nfunction caipChainIdToChainId(chainIdStr: string): ChainId {\n if (isCaipChainId(chainIdStr)) {\n return chainIdStr;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdStr);\n}\n\n/**\n * Filter a response to only include balances for assets already in state.\n * Used when tokenDetectionEnabled is false to prevent adding new tokens.\n *\n * @param response - The fetch response to filter.\n * @param assetsState - Current assets controller state to check existing balances against.\n * @returns A new response with only known asset balances.\n */\nexport function filterResponseToKnownAssets(\n response: DataResponse,\n assetsState: AssetsControllerStateInternal,\n): DataResponse {\n if (!response.assetsBalance) {\n return response;\n }\n\n const filteredBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const existingBalances = assetsState.assetsBalance[accountId];\n if (!existingBalances) {\n // Account has no balances in state yet — skip all its tokens\n continue;\n }\n\n const filtered: Record<Caip19AssetId, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(accountBalances)) {\n // Only include assets already tracked in state\n if (assetId in existingBalances) {\n filtered[assetId as Caip19AssetId] = balance;\n }\n }\n\n if (Object.keys(filtered).length > 0) {\n filteredBalance[accountId] = filtered;\n }\n }\n\n return {\n ...response,\n assetsBalance:\n Object.keys(filteredBalance).length > 0 ? filteredBalance : undefined,\n };\n}\n\n// ============================================================================\n// ACCOUNTS API DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for fetching balances from the MetaMask Accounts API.\n *\n * Uses ApiPlatformClient (queryApiClient) for all API calls. Does not use the\n * messenger. Reports active chains via onActiveChainsUpdated callback.\n */\nexport class AccountsApiDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n AccountsApiDataSourceState\n> {\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #fetchTimeoutMs: number;\n\n /** Getter avoids stale value when user toggles token detection at runtime. */\n readonly #tokenDetectionEnabled: () => boolean;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** State accessor from subscriptions (for filtering when tokenDetectionEnabled is false) */\n #getAssetsState?: () => AssetsControllerStateInternal;\n\n constructor(options: AccountsApiDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#apiClient = options.queryApiClient;\n\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n\n // Periodically refresh active chains (every 20 minutes)\n this.#chainsRefreshTimer = setInterval(\n () => {\n this.#refreshActiveChains().catch(console.error);\n },\n 20 * 60 * 1000,\n );\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n // Check if chains changed\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n\n // Use fullSupport networks as active chains\n return (\n response.fullSupport\n .map(decimalToChainId)\n // TODO Restore solana when there is a fix for how we handle non-evm chains here\n .filter((chainId) => chainId.startsWith('eip155:'))\n );\n }\n\n // ============================================================================\n // ACCOUNT SCOPE HELPERS\n // ============================================================================\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n let response: DataResponse = {};\n\n // Filter to only chains supported by Accounts API\n const supportedChains = new Set(this.state.activeChains);\n const chainsToFetch = request.chainIds.filter((chainId) =>\n supportedChains.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n return response;\n }\n\n try {\n // Build CAIP-10 account IDs (e.g., \"eip155:1:0x1234...\")\n // Use pre-computed supportedChains per account from the request\n const accountIds = request.accountsWithSupportedChains.flatMap(\n ({ account, supportedChains: accountChains }) =>\n chainsToFetch\n .filter((chainId) => accountChains.includes(chainId))\n .map((chainId) => `${chainId}:${account.address}`),\n );\n\n // Skip API call if no valid account-chain combinations\n if (accountIds.length === 0) {\n return response;\n }\n\n const apiResponse = await fetchWithTimeout(\n () => this.#apiClient.accounts.fetchV5MultiAccountBalances(accountIds),\n this.#fetchTimeoutMs,\n );\n\n // Handle unprocessed networks - these will be passed to next middleware\n if (apiResponse.unprocessedNetworks.length > 0) {\n const unprocessedChainIds =\n apiResponse.unprocessedNetworks.map(caipChainIdToChainId);\n\n // Add unprocessed chains to errors so middleware passes them to next data source\n response.errors = response.errors ?? {};\n for (const chainId of unprocessedChainIds) {\n response.errors[chainId] = 'Unprocessed by Accounts API';\n }\n }\n\n const { assetsBalance } = this.#processV5Balances(\n apiResponse.balances,\n request,\n );\n\n response.assetsBalance = assetsBalance;\n response.updateMode = 'merge';\n } catch (error) {\n log('Fetch FAILED', { error, chains: chainsToFetch });\n\n // On error, mark all chains as errors so they can be handled by next middleware\n response.errors = response.errors ?? {};\n for (const chainId of chainsToFetch) {\n response.errors[chainId] =\n `Fetch failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n\n // When token detection is disabled, filter out tokens not already in state\n if (!this.#tokenDetectionEnabled() && this.#getAssetsState) {\n response = filterResponseToKnownAssets(response, this.#getAssetsState());\n }\n\n return response;\n }\n\n /**\n * Process V5 API balances response.\n * V5 returns a flat array of balance items, each with accountId and assetId.\n *\n * @param balances - Array of balance items from the V5 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV5Balances(\n balances: V5BalanceItem[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = new Map<string, string>();\n for (const { account } of request.accountsWithSupportedChains) {\n if (account.address) {\n addressToAccountId.set(account.address.toLowerCase(), account.id);\n }\n }\n\n // V5 response: array of { accountId, assetId, balance, ... }\n for (const item of balances) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = item.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(item.assetId as Caip19AssetId);\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n\n return { assetsBalance };\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Accounts API.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Uses unprocessedNetworks from API response to determine what to pass to next middleware\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // If no chains requested, skip to next middleware\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n const response = await this.fetch(request);\n\n // Merge response into context\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 ...accountBalances,\n };\n }\n }\n\n // Determine successfully handled chains (exclude unprocessed/error chains)\n const unprocessedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = request.chainIds.filter(\n (chainId) => !unprocessedChains.has(chainId),\n );\n\n // When token detection is off and we filtered out all balance data (e.g. new\n // account with empty state), do not claim any chain as handled so that RPC\n // middleware can still process them and fetch native balances (ETH, MATIC, etc.).\n if (\n !this.#tokenDetectionEnabled() &&\n (!response.assetsBalance ||\n Object.keys(response.assetsBalance).length === 0)\n ) {\n successfullyHandledChains = [];\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Remove successfully handled chains from request for next middleware\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 // No chains handled - pass context unchanged\n return next(context);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Store state accessor for filtering when tokenDetectionEnabled is false\n if (subscriptionRequest.getAssetsState) {\n this.#getAssetsState = subscriptionRequest.getAssetsState;\n }\n\n // Try all requested chains - API will handle unsupported ones via unprocessedNetworks\n const chainsToSubscribe = request.chainIds;\n\n if (chainsToSubscribe.length === 0) {\n return;\n }\n\n // Handle subscription update - update both chains AND request (for accounts)\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = chainsToSubscribe;\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function for this subscription\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (!subscription?.request) {\n return;\n }\n\n // Use stored request (which gets updated on account changes)\n const fetchResponse = await this.fetch({\n ...subscription.request,\n chainIds: subscription.chains,\n });\n\n // Report update to AssetsController via callback\n await subscription.onAssetsUpdate(fetchResponse);\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription with request for account updates\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // Clean up timers\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n }\n\n // Clean up subscriptions\n super.destroy();\n }\n}\n"]}
|
|
@@ -164,7 +164,7 @@ export class AccountsApiDataSource extends AbstractDataSource {
|
|
|
164
164
|
}
|
|
165
165
|
const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV5Balances).call(this, apiResponse.balances, request);
|
|
166
166
|
response.assetsBalance = assetsBalance;
|
|
167
|
-
response.updateMode = '
|
|
167
|
+
response.updateMode = 'merge';
|
|
168
168
|
}
|
|
169
169
|
catch (error) {
|
|
170
170
|
log('Fetch FAILED', { error, chains: chainsToFetch });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountsApiDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V5BalanceItem } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n DataRequest,\n DataResponse,\n Middleware,\n AssetsControllerStateInternal,\n} from '../types';\nimport { fetchWithTimeout, normalizeAssetId } from '../utils';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'AccountsApiDataSource';\nconst DEFAULT_POLL_INTERVAL = 30_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that AccountsApiDataSource can call (none - uses callbacks).\n// Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed\nexport type AccountsApiDataSourceAllowedActions = never;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type AccountsApiDataSourceState = DataSourceState;\n\nconst defaultState: AccountsApiDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\n/** Optional configuration for AccountsApiDataSource. */\nexport type AccountsApiDataSourceConfig = {\n /** Polling interval in ms (default: 30000) */\n pollInterval?: number;\n /**\n * Function returning whether token detection is enabled (default: () => true).\n * When it returns false, balances are only returned for tokens already in state.\n * Using a getter avoids stale values when the user toggles the preference at runtime.\n */\n tokenDetectionEnabled?: () => boolean;\n /**\n * Timeout in ms for a single balances fetch call (default: 15000).\n * When it fires, every requested chain is marked as errored so the\n * middleware hands them off to the next data source (e.g. RPC fallback).\n */\n fetchTimeoutMs?: number;\n};\n\nexport type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\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 state?: Partial<AccountsApiDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nfunction decimalToChainId(decimalChainId: number | string): ChainId {\n // Handle both decimal numbers and already-formatted CAIP chain IDs\n if (typeof decimalChainId === 'string') {\n if (isCaipChainId(decimalChainId)) {\n return decimalChainId;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, decimalChainId);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(decimalChainId));\n}\n\n/**\n * Convert a CAIP-2 chain ID from the API response to our ChainId type.\n * Handles both formats: \"eip155:1\" or just \"1\" (decimal).\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdStr - The chain ID string to convert.\n * @returns The normalized ChainId.\n */\nfunction caipChainIdToChainId(chainIdStr: string): ChainId {\n if (isCaipChainId(chainIdStr)) {\n return chainIdStr;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdStr);\n}\n\n/**\n * Filter a response to only include balances for assets already in state.\n * Used when tokenDetectionEnabled is false to prevent adding new tokens.\n *\n * @param response - The fetch response to filter.\n * @param assetsState - Current assets controller state to check existing balances against.\n * @returns A new response with only known asset balances.\n */\nexport function filterResponseToKnownAssets(\n response: DataResponse,\n assetsState: AssetsControllerStateInternal,\n): DataResponse {\n if (!response.assetsBalance) {\n return response;\n }\n\n const filteredBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const existingBalances = assetsState.assetsBalance[accountId];\n if (!existingBalances) {\n // Account has no balances in state yet — skip all its tokens\n continue;\n }\n\n const filtered: Record<Caip19AssetId, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(accountBalances)) {\n // Only include assets already tracked in state\n if (assetId in existingBalances) {\n filtered[assetId as Caip19AssetId] = balance;\n }\n }\n\n if (Object.keys(filtered).length > 0) {\n filteredBalance[accountId] = filtered;\n }\n }\n\n return {\n ...response,\n assetsBalance:\n Object.keys(filteredBalance).length > 0 ? filteredBalance : undefined,\n };\n}\n\n// ============================================================================\n// ACCOUNTS API DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for fetching balances from the MetaMask Accounts API.\n *\n * Uses ApiPlatformClient (queryApiClient) for all API calls. Does not use the\n * messenger. Reports active chains via onActiveChainsUpdated callback.\n */\nexport class AccountsApiDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n AccountsApiDataSourceState\n> {\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #fetchTimeoutMs: number;\n\n /** Getter avoids stale value when user toggles token detection at runtime. */\n readonly #tokenDetectionEnabled: () => boolean;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** State accessor from subscriptions (for filtering when tokenDetectionEnabled is false) */\n #getAssetsState?: () => AssetsControllerStateInternal;\n\n constructor(options: AccountsApiDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#apiClient = options.queryApiClient;\n\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n\n // Periodically refresh active chains (every 20 minutes)\n this.#chainsRefreshTimer = setInterval(\n () => {\n this.#refreshActiveChains().catch(console.error);\n },\n 20 * 60 * 1000,\n );\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n // Check if chains changed\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n\n // Use fullSupport networks as active chains\n return (\n response.fullSupport\n .map(decimalToChainId)\n // TODO Restore solana when there is a fix for how we handle non-evm chains here\n .filter((chainId) => chainId.startsWith('eip155:'))\n );\n }\n\n // ============================================================================\n // ACCOUNT SCOPE HELPERS\n // ============================================================================\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n let response: DataResponse = {};\n\n // Filter to only chains supported by Accounts API\n const supportedChains = new Set(this.state.activeChains);\n const chainsToFetch = request.chainIds.filter((chainId) =>\n supportedChains.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n return response;\n }\n\n try {\n // Build CAIP-10 account IDs (e.g., \"eip155:1:0x1234...\")\n // Use pre-computed supportedChains per account from the request\n const accountIds = request.accountsWithSupportedChains.flatMap(\n ({ account, supportedChains: accountChains }) =>\n chainsToFetch\n .filter((chainId) => accountChains.includes(chainId))\n .map((chainId) => `${chainId}:${account.address}`),\n );\n\n // Skip API call if no valid account-chain combinations\n if (accountIds.length === 0) {\n return response;\n }\n\n const apiResponse = await fetchWithTimeout(\n () => this.#apiClient.accounts.fetchV5MultiAccountBalances(accountIds),\n this.#fetchTimeoutMs,\n );\n\n // Handle unprocessed networks - these will be passed to next middleware\n if (apiResponse.unprocessedNetworks.length > 0) {\n const unprocessedChainIds =\n apiResponse.unprocessedNetworks.map(caipChainIdToChainId);\n\n // Add unprocessed chains to errors so middleware passes them to next data source\n response.errors = response.errors ?? {};\n for (const chainId of unprocessedChainIds) {\n response.errors[chainId] = 'Unprocessed by Accounts API';\n }\n }\n\n const { assetsBalance } = this.#processV5Balances(\n apiResponse.balances,\n request,\n );\n\n response.assetsBalance = assetsBalance;\n response.updateMode = 'full';\n } catch (error) {\n log('Fetch FAILED', { error, chains: chainsToFetch });\n\n // On error, mark all chains as errors so they can be handled by next middleware\n response.errors = response.errors ?? {};\n for (const chainId of chainsToFetch) {\n response.errors[chainId] =\n `Fetch failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n\n // When token detection is disabled, filter out tokens not already in state\n if (!this.#tokenDetectionEnabled() && this.#getAssetsState) {\n response = filterResponseToKnownAssets(response, this.#getAssetsState());\n }\n\n return response;\n }\n\n /**\n * Process V5 API balances response.\n * V5 returns a flat array of balance items, each with accountId and assetId.\n *\n * @param balances - Array of balance items from the V5 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV5Balances(\n balances: V5BalanceItem[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = new Map<string, string>();\n for (const { account } of request.accountsWithSupportedChains) {\n if (account.address) {\n addressToAccountId.set(account.address.toLowerCase(), account.id);\n }\n }\n\n // V5 response: array of { accountId, assetId, balance, ... }\n for (const item of balances) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = item.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(item.assetId as Caip19AssetId);\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n\n return { assetsBalance };\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Accounts API.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Uses unprocessedNetworks from API response to determine what to pass to next middleware\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // If no chains requested, skip to next middleware\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n const response = await this.fetch(request);\n\n // Merge response into context\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 ...accountBalances,\n };\n }\n }\n\n // Determine successfully handled chains (exclude unprocessed/error chains)\n const unprocessedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = request.chainIds.filter(\n (chainId) => !unprocessedChains.has(chainId),\n );\n\n // When token detection is off and we filtered out all balance data (e.g. new\n // account with empty state), do not claim any chain as handled so that RPC\n // middleware can still process them and fetch native balances (ETH, MATIC, etc.).\n if (\n !this.#tokenDetectionEnabled() &&\n (!response.assetsBalance ||\n Object.keys(response.assetsBalance).length === 0)\n ) {\n successfullyHandledChains = [];\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Remove successfully handled chains from request for next middleware\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 // No chains handled - pass context unchanged\n return next(context);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Store state accessor for filtering when tokenDetectionEnabled is false\n if (subscriptionRequest.getAssetsState) {\n this.#getAssetsState = subscriptionRequest.getAssetsState;\n }\n\n // Try all requested chains - API will handle unsupported ones via unprocessedNetworks\n const chainsToSubscribe = request.chainIds;\n\n if (chainsToSubscribe.length === 0) {\n return;\n }\n\n // Handle subscription update - update both chains AND request (for accounts)\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = chainsToSubscribe;\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function for this subscription\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (!subscription?.request) {\n return;\n }\n\n // Use stored request (which gets updated on account changes)\n const fetchResponse = await this.fetch({\n ...subscription.request,\n chainIds: subscription.chains,\n });\n\n // Report update to AssetsController via callback\n await subscription.onAssetsUpdate(fetchResponse);\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription with request for account updates\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // Clean up timers\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n }\n\n // Clean up subscriptions\n super.destroy();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccountsApiDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V5BalanceItem } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n DataRequest,\n DataResponse,\n Middleware,\n AssetsControllerStateInternal,\n} from '../types';\nimport { fetchWithTimeout, normalizeAssetId } from '../utils';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'AccountsApiDataSource';\nconst DEFAULT_POLL_INTERVAL = 30_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that AccountsApiDataSource can call (none - uses callbacks).\n// Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed\nexport type AccountsApiDataSourceAllowedActions = never;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type AccountsApiDataSourceState = DataSourceState;\n\nconst defaultState: AccountsApiDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\n/** Optional configuration for AccountsApiDataSource. */\nexport type AccountsApiDataSourceConfig = {\n /** Polling interval in ms (default: 30000) */\n pollInterval?: number;\n /**\n * Function returning whether token detection is enabled (default: () => true).\n * When it returns false, balances are only returned for tokens already in state.\n * Using a getter avoids stale values when the user toggles the preference at runtime.\n */\n tokenDetectionEnabled?: () => boolean;\n /**\n * Timeout in ms for a single balances fetch call (default: 15000).\n * When it fires, every requested chain is marked as errored so the\n * middleware hands them off to the next data source (e.g. RPC fallback).\n */\n fetchTimeoutMs?: number;\n};\n\nexport type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\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 state?: Partial<AccountsApiDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nfunction decimalToChainId(decimalChainId: number | string): ChainId {\n // Handle both decimal numbers and already-formatted CAIP chain IDs\n if (typeof decimalChainId === 'string') {\n if (isCaipChainId(decimalChainId)) {\n return decimalChainId;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, decimalChainId);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(decimalChainId));\n}\n\n/**\n * Convert a CAIP-2 chain ID from the API response to our ChainId type.\n * Handles both formats: \"eip155:1\" or just \"1\" (decimal).\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdStr - The chain ID string to convert.\n * @returns The normalized ChainId.\n */\nfunction caipChainIdToChainId(chainIdStr: string): ChainId {\n if (isCaipChainId(chainIdStr)) {\n return chainIdStr;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdStr);\n}\n\n/**\n * Filter a response to only include balances for assets already in state.\n * Used when tokenDetectionEnabled is false to prevent adding new tokens.\n *\n * @param response - The fetch response to filter.\n * @param assetsState - Current assets controller state to check existing balances against.\n * @returns A new response with only known asset balances.\n */\nexport function filterResponseToKnownAssets(\n response: DataResponse,\n assetsState: AssetsControllerStateInternal,\n): DataResponse {\n if (!response.assetsBalance) {\n return response;\n }\n\n const filteredBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const existingBalances = assetsState.assetsBalance[accountId];\n if (!existingBalances) {\n // Account has no balances in state yet — skip all its tokens\n continue;\n }\n\n const filtered: Record<Caip19AssetId, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(accountBalances)) {\n // Only include assets already tracked in state\n if (assetId in existingBalances) {\n filtered[assetId as Caip19AssetId] = balance;\n }\n }\n\n if (Object.keys(filtered).length > 0) {\n filteredBalance[accountId] = filtered;\n }\n }\n\n return {\n ...response,\n assetsBalance:\n Object.keys(filteredBalance).length > 0 ? filteredBalance : undefined,\n };\n}\n\n// ============================================================================\n// ACCOUNTS API DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for fetching balances from the MetaMask Accounts API.\n *\n * Uses ApiPlatformClient (queryApiClient) for all API calls. Does not use the\n * messenger. Reports active chains via onActiveChainsUpdated callback.\n */\nexport class AccountsApiDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n AccountsApiDataSourceState\n> {\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #fetchTimeoutMs: number;\n\n /** Getter avoids stale value when user toggles token detection at runtime. */\n readonly #tokenDetectionEnabled: () => boolean;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** State accessor from subscriptions (for filtering when tokenDetectionEnabled is false) */\n #getAssetsState?: () => AssetsControllerStateInternal;\n\n constructor(options: AccountsApiDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#apiClient = options.queryApiClient;\n\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n\n // Periodically refresh active chains (every 20 minutes)\n this.#chainsRefreshTimer = setInterval(\n () => {\n this.#refreshActiveChains().catch(console.error);\n },\n 20 * 60 * 1000,\n );\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n // Check if chains changed\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n\n // Use fullSupport networks as active chains\n return (\n response.fullSupport\n .map(decimalToChainId)\n // TODO Restore solana when there is a fix for how we handle non-evm chains here\n .filter((chainId) => chainId.startsWith('eip155:'))\n );\n }\n\n // ============================================================================\n // ACCOUNT SCOPE HELPERS\n // ============================================================================\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n let response: DataResponse = {};\n\n // Filter to only chains supported by Accounts API\n const supportedChains = new Set(this.state.activeChains);\n const chainsToFetch = request.chainIds.filter((chainId) =>\n supportedChains.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n return response;\n }\n\n try {\n // Build CAIP-10 account IDs (e.g., \"eip155:1:0x1234...\")\n // Use pre-computed supportedChains per account from the request\n const accountIds = request.accountsWithSupportedChains.flatMap(\n ({ account, supportedChains: accountChains }) =>\n chainsToFetch\n .filter((chainId) => accountChains.includes(chainId))\n .map((chainId) => `${chainId}:${account.address}`),\n );\n\n // Skip API call if no valid account-chain combinations\n if (accountIds.length === 0) {\n return response;\n }\n\n const apiResponse = await fetchWithTimeout(\n () => this.#apiClient.accounts.fetchV5MultiAccountBalances(accountIds),\n this.#fetchTimeoutMs,\n );\n\n // Handle unprocessed networks - these will be passed to next middleware\n if (apiResponse.unprocessedNetworks.length > 0) {\n const unprocessedChainIds =\n apiResponse.unprocessedNetworks.map(caipChainIdToChainId);\n\n // Add unprocessed chains to errors so middleware passes them to next data source\n response.errors = response.errors ?? {};\n for (const chainId of unprocessedChainIds) {\n response.errors[chainId] = 'Unprocessed by Accounts API';\n }\n }\n\n const { assetsBalance } = this.#processV5Balances(\n apiResponse.balances,\n request,\n );\n\n response.assetsBalance = assetsBalance;\n response.updateMode = 'merge';\n } catch (error) {\n log('Fetch FAILED', { error, chains: chainsToFetch });\n\n // On error, mark all chains as errors so they can be handled by next middleware\n response.errors = response.errors ?? {};\n for (const chainId of chainsToFetch) {\n response.errors[chainId] =\n `Fetch failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n\n // When token detection is disabled, filter out tokens not already in state\n if (!this.#tokenDetectionEnabled() && this.#getAssetsState) {\n response = filterResponseToKnownAssets(response, this.#getAssetsState());\n }\n\n return response;\n }\n\n /**\n * Process V5 API balances response.\n * V5 returns a flat array of balance items, each with accountId and assetId.\n *\n * @param balances - Array of balance items from the V5 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV5Balances(\n balances: V5BalanceItem[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = new Map<string, string>();\n for (const { account } of request.accountsWithSupportedChains) {\n if (account.address) {\n addressToAccountId.set(account.address.toLowerCase(), account.id);\n }\n }\n\n // V5 response: array of { accountId, assetId, balance, ... }\n for (const item of balances) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = item.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(item.assetId as Caip19AssetId);\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n\n return { assetsBalance };\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Accounts API.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Uses unprocessedNetworks from API response to determine what to pass to next middleware\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // If no chains requested, skip to next middleware\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n const response = await this.fetch(request);\n\n // Merge response into context\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 ...accountBalances,\n };\n }\n }\n\n // Determine successfully handled chains (exclude unprocessed/error chains)\n const unprocessedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = request.chainIds.filter(\n (chainId) => !unprocessedChains.has(chainId),\n );\n\n // When token detection is off and we filtered out all balance data (e.g. new\n // account with empty state), do not claim any chain as handled so that RPC\n // middleware can still process them and fetch native balances (ETH, MATIC, etc.).\n if (\n !this.#tokenDetectionEnabled() &&\n (!response.assetsBalance ||\n Object.keys(response.assetsBalance).length === 0)\n ) {\n successfullyHandledChains = [];\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Remove successfully handled chains from request for next middleware\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 // No chains handled - pass context unchanged\n return next(context);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Store state accessor for filtering when tokenDetectionEnabled is false\n if (subscriptionRequest.getAssetsState) {\n this.#getAssetsState = subscriptionRequest.getAssetsState;\n }\n\n // Try all requested chains - API will handle unsupported ones via unprocessedNetworks\n const chainsToSubscribe = request.chainIds;\n\n if (chainsToSubscribe.length === 0) {\n return;\n }\n\n // Handle subscription update - update both chains AND request (for accounts)\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = chainsToSubscribe;\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function for this subscription\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (!subscription?.request) {\n return;\n }\n\n // Use stored request (which gets updated on account changes)\n const fetchResponse = await this.fetch({\n ...subscription.request,\n chainIds: subscription.chains,\n });\n\n // Report update to AssetsController via callback\n await subscription.onAssetsUpdate(fetchResponse);\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription with request for account updates\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // Clean up timers\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n }\n\n // Clean up subscriptions\n super.destroy();\n }\n}\n"]}
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _PriceDataSource_instances, _PriceDataSource_getSelectedCurrency, _PriceDataSource_pollInterval, _PriceDataSource_apiClient, _PriceDataSource_fetchTimeoutMs, _PriceDataSource_activeSubscriptions, _PriceDataSource_fetchSpotPricesBatch, _PriceDataSource_fetchSpotPrices, _PriceDataSource_getAssetIdsFromBalanceState;
|
|
13
|
+
var _PriceDataSource_instances, _PriceDataSource_getSelectedCurrency, _PriceDataSource_pollInterval, _PriceDataSource_apiClient, _PriceDataSource_fetchTimeoutMs, _PriceDataSource_deduper, _PriceDataSource_activeSubscriptions, _PriceDataSource_fetchSpotPricesBatch, _PriceDataSource_executeBatchFetch, _PriceDataSource_fetchSpotPrices, _PriceDataSource_getAssetIdsFromBalanceState;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.PriceDataSource = void 0;
|
|
16
16
|
const core_backend_1 = require("@metamask/core-backend");
|
|
@@ -18,6 +18,7 @@ const utils_1 = require("@metamask/utils");
|
|
|
18
18
|
const logger_1 = require("../logger.cjs");
|
|
19
19
|
const types_1 = require("../types.cjs");
|
|
20
20
|
const utils_2 = require("../utils/index.cjs");
|
|
21
|
+
const dedupingBatchFetcher_1 = require("../utils/dedupingBatchFetcher.cjs");
|
|
21
22
|
const evm_rpc_services_1 = require("./evm-rpc-services/index.cjs");
|
|
22
23
|
// ============================================================================
|
|
23
24
|
// CONSTANTS
|
|
@@ -25,6 +26,13 @@ const evm_rpc_services_1 = require("./evm-rpc-services/index.cjs");
|
|
|
25
26
|
const CONTROLLER_NAME = 'PriceDataSource';
|
|
26
27
|
const DEFAULT_POLL_INTERVAL = 60000; // 1 minute for price updates
|
|
27
28
|
const DEFAULT_FETCH_TIMEOUT_MS = 15000;
|
|
29
|
+
/**
|
|
30
|
+
* Fraction of the poll interval used to cap the freshness TTL. Kept strictly
|
|
31
|
+
* below 1 so an asset fetched on one poll is reliably stale by the next poll;
|
|
32
|
+
* the margin absorbs network latency and timer jitter (see the cap in
|
|
33
|
+
* `subscribe`).
|
|
34
|
+
*/
|
|
35
|
+
const FRESHNESS_TTL_POLL_RATIO = 0.9;
|
|
28
36
|
/** Maximum number of asset IDs per Price API request. */
|
|
29
37
|
const PRICE_API_BATCH_SIZE = 50;
|
|
30
38
|
const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_NAME);
|
|
@@ -93,12 +101,23 @@ class PriceDataSource {
|
|
|
93
101
|
/** ApiPlatformClient for cached API calls */
|
|
94
102
|
_PriceDataSource_apiClient.set(this, void 0);
|
|
95
103
|
_PriceDataSource_fetchTimeoutMs.set(this, void 0);
|
|
104
|
+
/**
|
|
105
|
+
* Deduplicates price fetches by asset ID: skips assets fetched within the
|
|
106
|
+
* freshness TTL and joins concurrent in-flight fetches for the same asset so
|
|
107
|
+
* overlapping triggers (middleware + subscription poll) don't issue duplicate
|
|
108
|
+
* API requests.
|
|
109
|
+
*/
|
|
110
|
+
_PriceDataSource_deduper.set(this, void 0);
|
|
96
111
|
/** Active subscriptions by ID */
|
|
97
112
|
_PriceDataSource_activeSubscriptions.set(this, new Map());
|
|
98
113
|
__classPrivateFieldSet(this, _PriceDataSource_getSelectedCurrency, options.getSelectedCurrency, "f");
|
|
99
114
|
__classPrivateFieldSet(this, _PriceDataSource_pollInterval, options.pollInterval ?? DEFAULT_POLL_INTERVAL, "f");
|
|
100
115
|
__classPrivateFieldSet(this, _PriceDataSource_apiClient, options.queryApiClient, "f");
|
|
101
116
|
__classPrivateFieldSet(this, _PriceDataSource_fetchTimeoutMs, options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS, "f");
|
|
117
|
+
__classPrivateFieldSet(this, _PriceDataSource_deduper, new dedupingBatchFetcher_1.DedupingBatchFetcher({
|
|
118
|
+
fetchBatch: (assetIds) => __classPrivateFieldGet(this, _PriceDataSource_instances, "m", _PriceDataSource_executeBatchFetch).call(this, assetIds),
|
|
119
|
+
freshnessTtlMs: options.priceFreshnessTtlMs ?? __classPrivateFieldGet(this, _PriceDataSource_pollInterval, "f"),
|
|
120
|
+
}), "f");
|
|
102
121
|
}
|
|
103
122
|
// ============================================================================
|
|
104
123
|
// MIDDLEWARE
|
|
@@ -212,14 +231,24 @@ class PriceDataSource {
|
|
|
212
231
|
// Clean up existing subscription
|
|
213
232
|
await this.unsubscribe(subscriptionId);
|
|
214
233
|
const pollInterval = request.updateInterval ?? __classPrivateFieldGet(this, _PriceDataSource_pollInterval, "f");
|
|
215
|
-
//
|
|
234
|
+
// Cap the freshness TTL strictly below the effective poll interval.
|
|
235
|
+
// `fetchedAt` is stamped when a fetch completes (slightly after the tick
|
|
236
|
+
// that triggered it), so a TTL equal to the poll interval would leave the
|
|
237
|
+
// asset still "fresh" at the next tick, making the subscription re-fetch
|
|
238
|
+
// only every other poll. The margin also absorbs network latency / jitter.
|
|
239
|
+
__classPrivateFieldGet(this, _PriceDataSource_deduper, "f").freshnessTtlMs = Math.min(__classPrivateFieldGet(this, _PriceDataSource_deduper, "f").freshnessTtlMs, Math.floor(pollInterval * FRESHNESS_TTL_POLL_RATIO));
|
|
240
|
+
// Create poll function - fetches prices using getAssetsState from subscription.
|
|
241
|
+
// The freshness TTL naturally gates re-fetches: assets fetched less than
|
|
242
|
+
// `priceFreshnessTtlMs` ago are skipped, preventing duplicates when middleware
|
|
243
|
+
// or other triggers already fetched the same assets between polls.
|
|
244
|
+
// Concurrent middleware calls will join the inflight promise rather than
|
|
245
|
+
// issuing duplicate requests.
|
|
216
246
|
const pollFn = async () => {
|
|
217
247
|
try {
|
|
218
248
|
const subscription = __classPrivateFieldGet(this, _PriceDataSource_activeSubscriptions, "f").get(subscriptionId);
|
|
219
249
|
if (!subscription) {
|
|
220
250
|
return;
|
|
221
251
|
}
|
|
222
|
-
// Fetch prices for all assets in balance state (uses subscription's getAssetsState)
|
|
223
252
|
const fetchResponse = await this.fetch(subscription.request, subscription.getAssetsState);
|
|
224
253
|
// Only report if we got prices
|
|
225
254
|
if (fetchResponse.assetsPrice &&
|
|
@@ -262,6 +291,14 @@ class PriceDataSource {
|
|
|
262
291
|
__classPrivateFieldGet(this, _PriceDataSource_activeSubscriptions, "f").delete(subscriptionId);
|
|
263
292
|
}
|
|
264
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Invalidate the price freshness cache, forcing the next fetch to call the
|
|
296
|
+
* API regardless of TTL. Use when external state changes (e.g. selected
|
|
297
|
+
* currency) require a full refresh.
|
|
298
|
+
*/
|
|
299
|
+
invalidatePriceCache() {
|
|
300
|
+
__classPrivateFieldGet(this, _PriceDataSource_deduper, "f").invalidate();
|
|
301
|
+
}
|
|
265
302
|
/**
|
|
266
303
|
* Destroy the data source and clean up all subscriptions.
|
|
267
304
|
*/
|
|
@@ -270,10 +307,11 @@ class PriceDataSource {
|
|
|
270
307
|
subscription.cleanup();
|
|
271
308
|
}
|
|
272
309
|
__classPrivateFieldGet(this, _PriceDataSource_activeSubscriptions, "f").clear();
|
|
310
|
+
__classPrivateFieldGet(this, _PriceDataSource_deduper, "f").destroy();
|
|
273
311
|
}
|
|
274
312
|
}
|
|
275
313
|
exports.PriceDataSource = PriceDataSource;
|
|
276
|
-
_PriceDataSource_getSelectedCurrency = new WeakMap(), _PriceDataSource_pollInterval = new WeakMap(), _PriceDataSource_apiClient = new WeakMap(), _PriceDataSource_fetchTimeoutMs = new WeakMap(), _PriceDataSource_activeSubscriptions = new WeakMap(), _PriceDataSource_instances = new WeakSet(), _PriceDataSource_fetchSpotPricesBatch =
|
|
314
|
+
_PriceDataSource_getSelectedCurrency = new WeakMap(), _PriceDataSource_pollInterval = new WeakMap(), _PriceDataSource_apiClient = new WeakMap(), _PriceDataSource_fetchTimeoutMs = new WeakMap(), _PriceDataSource_deduper = new WeakMap(), _PriceDataSource_activeSubscriptions = new WeakMap(), _PriceDataSource_instances = new WeakSet(), _PriceDataSource_fetchSpotPricesBatch =
|
|
277
315
|
// ============================================================================
|
|
278
316
|
// HELPERS
|
|
279
317
|
// ============================================================================
|
|
@@ -303,15 +341,17 @@ async function _PriceDataSource_fetchSpotPricesBatch(assetIds, selectedCurrency)
|
|
|
303
341
|
}), __classPrivateFieldGet(this, _PriceDataSource_fetchTimeoutMs, "f")),
|
|
304
342
|
]);
|
|
305
343
|
return { selectedCurrencyPrices, usdPrices };
|
|
306
|
-
},
|
|
344
|
+
}, _PriceDataSource_executeBatchFetch =
|
|
307
345
|
/**
|
|
308
|
-
*
|
|
309
|
-
*
|
|
346
|
+
* Execute the actual batched API call for a set of asset IDs and return
|
|
347
|
+
* parsed price results. Used as the `fetchBatch` callback for the deduper,
|
|
348
|
+
* so it does NOT check freshness or inflight state — that is handled by
|
|
349
|
+
* {@link DedupingBatchFetcher}.
|
|
310
350
|
*
|
|
311
|
-
* @param assetIds -
|
|
312
|
-
* @returns
|
|
351
|
+
* @param assetIds - Asset IDs to fetch (already filtered/deduplicated).
|
|
352
|
+
* @returns Parsed prices keyed by CAIP-19 asset ID.
|
|
313
353
|
*/
|
|
314
|
-
async function
|
|
354
|
+
async function _PriceDataSource_executeBatchFetch(assetIds) {
|
|
315
355
|
const selectedCurrency = __classPrivateFieldGet(this, _PriceDataSource_getSelectedCurrency, "f").call(this);
|
|
316
356
|
const batchResults = await (0, evm_rpc_services_1.reduceInBatchesSerially)({
|
|
317
357
|
values: assetIds,
|
|
@@ -322,6 +362,7 @@ async function _PriceDataSource_fetchSpotPrices(assetIds) {
|
|
|
322
362
|
},
|
|
323
363
|
initialResult: [],
|
|
324
364
|
});
|
|
365
|
+
const fetchedAt = Date.now();
|
|
325
366
|
const prices = {};
|
|
326
367
|
for (const { selectedCurrencyPrices, usdPrices } of batchResults) {
|
|
327
368
|
for (const [assetId, marketData] of Object.entries(selectedCurrencyPrices)) {
|
|
@@ -330,16 +371,26 @@ async function _PriceDataSource_fetchSpotPrices(assetIds) {
|
|
|
330
371
|
!isValidMarketData(usdMarketData)) {
|
|
331
372
|
continue;
|
|
332
373
|
}
|
|
333
|
-
|
|
334
|
-
prices[caipAssetId] = {
|
|
374
|
+
prices[assetId] = {
|
|
335
375
|
...marketData,
|
|
336
376
|
assetPriceType: 'fungible',
|
|
337
377
|
usdPrice: usdMarketData.price,
|
|
338
|
-
lastUpdated:
|
|
378
|
+
lastUpdated: fetchedAt,
|
|
339
379
|
};
|
|
340
380
|
}
|
|
341
381
|
}
|
|
342
382
|
return prices;
|
|
383
|
+
}, _PriceDataSource_fetchSpotPrices =
|
|
384
|
+
/**
|
|
385
|
+
* Fetch spot prices for all provided asset IDs, deduplicating via the
|
|
386
|
+
* deduper (freshness TTL + per-asset inflight coalescing).
|
|
387
|
+
*
|
|
388
|
+
* @param assetIds - Array of CAIP-19 asset IDs.
|
|
389
|
+
* @returns Spot prices response (only contains entries for assets that were
|
|
390
|
+
* actually fetched or joined from inflight).
|
|
391
|
+
*/
|
|
392
|
+
async function _PriceDataSource_fetchSpotPrices(assetIds) {
|
|
393
|
+
return __classPrivateFieldGet(this, _PriceDataSource_deduper, "f").fetch(assetIds);
|
|
343
394
|
}, _PriceDataSource_getAssetIdsFromBalanceState = function _PriceDataSource_getAssetIdsFromBalanceState(request, getAssetsState) {
|
|
344
395
|
if (!getAssetsState) {
|
|
345
396
|
return [];
|