@metamask-previews/assets-controller 6.0.0-preview-e7ff8e76d → 6.0.0-preview-8a15a8aa8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/AssetsController.cjs +50 -12
  3. package/dist/AssetsController.cjs.map +1 -1
  4. package/dist/AssetsController.d.cts.map +1 -1
  5. package/dist/AssetsController.d.mts.map +1 -1
  6. package/dist/AssetsController.mjs +50 -12
  7. package/dist/AssetsController.mjs.map +1 -1
  8. package/dist/data-sources/BackendWebsocketDataSource.cjs +2 -1
  9. package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
  10. package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
  11. package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
  12. package/dist/data-sources/BackendWebsocketDataSource.mjs +2 -1
  13. package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
  14. package/dist/data-sources/RpcDataSource.cjs +8 -5
  15. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  16. package/dist/data-sources/RpcDataSource.d.cts +4 -3
  17. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  18. package/dist/data-sources/RpcDataSource.d.mts +4 -3
  19. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  20. package/dist/data-sources/RpcDataSource.mjs +8 -5
  21. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  22. package/dist/data-sources/TokenDataSource.cjs +8 -6
  23. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  24. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  25. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  26. package/dist/data-sources/TokenDataSource.mjs +8 -6
  27. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  28. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +4 -3
  29. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
  30. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
  31. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
  32. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +4 -3
  33. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
  34. package/dist/utils/formatExchangeRatesForBridge.cjs +9 -6
  35. package/dist/utils/formatExchangeRatesForBridge.cjs.map +1 -1
  36. package/dist/utils/formatExchangeRatesForBridge.d.cts.map +1 -1
  37. package/dist/utils/formatExchangeRatesForBridge.d.mts.map +1 -1
  38. package/dist/utils/formatExchangeRatesForBridge.mjs +10 -7
  39. package/dist/utils/formatExchangeRatesForBridge.mjs.map +1 -1
  40. package/dist/utils/formatStateForTransactionPay.cjs +7 -4
  41. package/dist/utils/formatStateForTransactionPay.cjs.map +1 -1
  42. package/dist/utils/formatStateForTransactionPay.d.cts.map +1 -1
  43. package/dist/utils/formatStateForTransactionPay.d.mts.map +1 -1
  44. package/dist/utils/formatStateForTransactionPay.mjs +7 -4
  45. package/dist/utils/formatStateForTransactionPay.mjs.map +1 -1
  46. package/dist/utils/isNativeAsset.cjs +39 -0
  47. package/dist/utils/isNativeAsset.cjs.map +1 -0
  48. package/dist/utils/isNativeAsset.d.cts +16 -0
  49. package/dist/utils/isNativeAsset.d.cts.map +1 -0
  50. package/dist/utils/isNativeAsset.d.mts +16 -0
  51. package/dist/utils/isNativeAsset.d.mts.map +1 -0
  52. package/dist/utils/isNativeAsset.mjs +35 -0
  53. package/dist/utils/isNativeAsset.mjs.map +1 -0
  54. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"RpcDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/RpcDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport { toHex } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n NetworkState,\n NetworkStatus,\n} from '@metamask/network-controller';\nimport type { NetworkEnablementControllerGetStateAction } from '@metamask/network-enablement-controller';\nimport type {\n TransactionControllerIncomingTransactionsReceivedEvent,\n TransactionControllerTransactionConfirmedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport {\n isStrictHexString,\n isCaipChainId,\n parseCaipAssetType,\n parseCaipChainId,\n} from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type {\n AssetsControllerGetStateAction,\n AssetsControllerMessenger,\n} from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n AssetMetadata,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\nimport { normalizeAssetId } from '../utils';\nimport { ZERO_ADDRESS } from '../utils/constants';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport {\n BalanceFetcher,\n MulticallClient,\n TokenDetector,\n TokensApiClient,\n} from './evm-rpc-services';\nimport type {\n BalancePollingInput,\n DetectionPollingInput,\n} from './evm-rpc-services';\nimport type {\n Address,\n AssetFetchEntry,\n Provider as RpcProvider,\n BalanceFetchResult,\n TokenDetectionResult,\n} from './evm-rpc-services/types';\n\nconst CONTROLLER_NAME = 'RpcDataSource';\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\nconst DEFAULT_DETECTION_INTERVAL = 180_000; // 3 minutes\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// Allowed actions that RpcDataSource can call\nexport type RpcDataSourceAllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | AssetsControllerGetStateAction\n | NetworkEnablementControllerGetStateAction;\n\n// Allowed events that RpcDataSource can subscribe to\nexport type RpcDataSourceAllowedEvents =\n | NetworkControllerStateChangeEvent\n | TransactionControllerTransactionConfirmedEvent\n | TransactionControllerIncomingTransactionsReceivedEvent;\n\n/** Network status for each chain */\nexport type ChainStatus = {\n chainId: ChainId;\n status: NetworkStatus;\n name: string;\n nativeCurrency: string;\n /** Network client ID for getting the provider */\n networkClientId: string;\n};\n\n/** RpcDataSource is stateless */\nexport type RpcDataSourceState = Record<never, never>;\n\n/** Optional configuration for RpcDataSource when the controller instantiates it. */\nexport type RpcDataSourceConfig = {\n balanceInterval?: number;\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n timeout?: number;\n};\n\nexport type RpcDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Request timeout in ms */\n timeout?: number;\n /** Balance polling interval in ms (default: 30s) */\n balanceInterval?: number;\n /** Token detection polling interval in ms (default: 180s / 3 min) */\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n};\n\n/**\n * Subscription data stored for each active subscription.\n */\ntype SubscriptionData = {\n /** Polling tokens from BalanceFetcher */\n balancePollingTokens: string[];\n /** Polling tokens from TokenDetector */\n detectionPollingTokens: string[];\n /** Chain IDs being polled */\n chains: ChainId[];\n /** Accounts being polled */\n accounts: InternalAccount[];\n /** Callback to report asset updates to the controller */\n onAssetsUpdate: (\n response: DataResponse,\n request?: DataRequest,\n ) => void | Promise<void>;\n};\n\n/**\n * Convert CAIP chain ID or hex chain ID to hex chain ID.\n *\n * @param chainId - CAIP chain ID or hex chain ID.\n * @returns Hex chain ID.\n */\nexport const caipChainIdToHex = (chainId: string): Hex => {\n if (isStrictHexString(chainId)) {\n return chainId;\n }\n\n if (isCaipChainId(chainId)) {\n return toHex(parseCaipChainId(chainId).reference);\n }\n\n throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');\n};\n\n/**\n * Data source for fetching balances via RPC calls.\n *\n * Orchestrates polling through BalanceFetcher and TokenDetector,\n * each of which handle their own polling intervals.\n *\n * Communicates with AssetsController via Messenger:\n *\n * Actions:\n * - RpcDataSource:getActiveChains\n * - RpcDataSource:fetch\n * - RpcDataSource:subscribe\n * - RpcDataSource:unsubscribe\n *\n * Events:\n * - RpcDataSource:activeChainsUpdated\n * - RpcDataSource:assetsUpdated\n */\nexport class RpcDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n DataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #timeout: number;\n\n readonly #tokenDetectionEnabled: () => boolean;\n\n readonly #useExternalService: () => boolean;\n\n readonly #isOnboarded: () => boolean;\n\n /** Currently active chains */\n #activeChains: ChainId[] = [];\n\n /** Network status for each active chain */\n #chainStatuses: Record<ChainId, ChainStatus> = {};\n\n /** Cache of Web3Provider instances by chainId */\n readonly #providerCache: Map<ChainId, Web3Provider> = new Map();\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<string, SubscriptionData> = new Map();\n\n #unsubscribeTransactionConfirmed: (() => void) | undefined = undefined;\n\n #unsubscribeIncomingTransactions: (() => void) | undefined = undefined;\n\n // Rpc-datasource components\n readonly #multicallClient: MulticallClient;\n\n readonly #balanceFetcher: BalanceFetcher;\n\n readonly #tokenDetector: TokenDetector;\n\n constructor(options: RpcDataSourceOptions) {\n super(CONTROLLER_NAME, { activeChains: [] });\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#timeout = options.timeout ?? 10_000;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#useExternalService =\n options.useExternalService ?? ((): boolean => true);\n this.#isOnboarded = options.isOnboarded ?? ((): boolean => true);\n\n const balanceInterval = options.balanceInterval ?? DEFAULT_BALANCE_INTERVAL;\n const detectionInterval =\n options.detectionInterval ?? DEFAULT_DETECTION_INTERVAL;\n\n log('Initializing RpcDataSource', {\n timeout: this.#timeout,\n balanceInterval,\n detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n });\n\n // Initialize MulticallClient with a provider getter\n this.#multicallClient = new MulticallClient((hexChainId: string) => {\n return this.#getMulticallProvider(hexChainId);\n });\n\n // Create messenger adapters for BalanceFetcher and TokenDetector\n const balanceFetcherMessenger = {\n call: (\n _action: 'AssetsController:getState',\n ): {\n assetsBalance: Record<string, Record<string, { amount: string }>>;\n } => {\n const state = this.#messenger.call('AssetsController:getState');\n return {\n assetsBalance: (state.assetsBalance ?? {}) as Record<\n string,\n Record<string, { amount: string }>\n >,\n };\n },\n };\n\n // Initialize BalanceFetcher with polling interval\n this.#balanceFetcher = new BalanceFetcher(\n this.#multicallClient,\n balanceFetcherMessenger,\n { pollingInterval: balanceInterval },\n );\n // Polling controller awaits this callback; rejections must not become unhandled.\n this.#balanceFetcher.setOnBalanceUpdate(async (result) => {\n try {\n await this.#handleBalanceUpdate(result);\n } catch (error) {\n log('Balance update handler failed', { error });\n }\n });\n\n // Initialize TokenDetector with polling interval\n const tokensApiClient = new TokensApiClient();\n this.#tokenDetector = new TokenDetector(\n this.#multicallClient,\n tokensApiClient,\n {\n pollingInterval: detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled,\n useExternalService: this.#useExternalService,\n },\n );\n // Sync throw in the detector would reject the poll tick if uncaught.\n this.#tokenDetector.setOnDetectionUpdate((result) => {\n try {\n this.#handleDetectionUpdate(result);\n } catch (error) {\n log('Detection update handler failed', { error });\n }\n });\n\n this.#subscribeToNetworkController();\n this.#subscribeToTransactionEvents();\n this.#initializeFromNetworkController();\n }\n\n /**\n * Convert a raw balance to human-readable format using decimals.\n *\n * @param rawBalance - The raw balance string.\n * @param decimals - The number of decimals for the token.\n * @returns The human-readable balance string.\n */\n #convertToHumanReadable(rawBalance: string, decimals: number): string {\n const rawAmount = new BigNumberJS(rawBalance);\n const divisor = new BigNumberJS(10).pow(decimals);\n return rawAmount.dividedBy(divisor).toFixed();\n }\n\n /**\n * Collect metadata for a list of balance entries.\n * For native tokens, generates metadata from chain status.\n * For ERC20 tokens, looks up from existing state or token list.\n *\n * @param balances - Array of balance entries with assetId.\n * @param chainId - The CAIP-2 chain ID.\n * @returns Record of asset metadata keyed by asset ID.\n */\n #collectMetadataForBalances(\n balances: { assetId: Caip19AssetId }[],\n chainId: ChainId,\n ): Record<Caip19AssetId, AssetMetadata> {\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n for (const balance of balances) {\n const isNative = balance.assetId.includes('/slip44:');\n if (isNative) {\n const chainStatus = this.#chainStatuses[chainId];\n\n if (chainStatus) {\n assetsInfo[balance.assetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n } else {\n // For ERC20 tokens, use existing metadata from state if available.\n // Unknown ERC-20s are omitted until TokenDataSource enriches them.\n const existingMeta = existingMetadata[balance.assetId];\n if (existingMeta) {\n assetsInfo[balance.assetId] = existingMeta;\n }\n }\n }\n\n return assetsInfo;\n }\n\n /**\n * Handle balance update from BalanceFetcher.\n *\n * @param result - The balance fetch result.\n */\n async #handleBalanceUpdate(result: BalanceFetchResult): Promise<void> {\n const newBalances: Record<string, { amount: string }> = {};\n\n // Convert hex chain ID to CAIP-2 format\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n\n // Normalize asset IDs from BalanceFetcher (lowercase) to checksummed form\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const assetsInfo = this.#collectMetadataForBalances(\n normalizedBalances,\n caipChainId,\n );\n\n // Convert balances to human-readable format.\n // Resolution: state metadata → pipeline metadata; skip if decimals unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n const decimals = stateMetadata?.decimals ?? pipelineMetadata?.decimals;\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n assetsInfo,\n updateMode: 'merge',\n };\n\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance'],\n };\n\n log('Balance update response', {\n accountId: result.accountId,\n newBalanceCount: Object.keys(newBalances).length,\n });\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update assets', { error });\n });\n }\n }\n\n /**\n * Handle detection update from TokenDetector.\n *\n * @param result - The token detection result.\n */\n #handleDetectionUpdate(result: TokenDetectionResult): void {\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n });\n\n // Build new metadata from detected assets\n const newMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n if (result.detectedAssets.length > 0) {\n for (const asset of result.detectedAssets) {\n // Only include if we have metadata (symbol and decimals at minimum)\n if (asset.symbol && asset.decimals !== undefined) {\n newMetadata[asset.assetId] = {\n type: 'erc20',\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n }\n\n // Build new balances from detected tokens\n const newBalances: Record<string, { amount: string }> = {};\n if (result.detectedBalances.length > 0) {\n for (const balance of result.detectedBalances) {\n // Get decimals from the detected asset metadata\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n detectedAssets: {\n [result.accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsInfo: newMetadata,\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n updateMode: 'merge',\n };\n\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance', 'metadata', 'price'],\n };\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update detected assets', { error });\n });\n }\n }\n\n #subscribeToNetworkController(): void {\n this.#messenger.subscribe(\n 'NetworkController:stateChange',\n (networkState: NetworkState) => {\n log('NetworkController state changed');\n this.#clearProviderCache();\n this.#updateFromNetworkState(networkState);\n },\n );\n }\n\n #subscribeToTransactionEvents(): void {\n const unsubConfirmed = this.#messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n this.#onTransactionConfirmed.bind(this),\n );\n this.#unsubscribeTransactionConfirmed =\n typeof unsubConfirmed === 'function' ? unsubConfirmed : undefined;\n\n const unsubIncoming = this.#messenger.subscribe(\n 'TransactionController:incomingTransactionsReceived',\n this.#onIncomingTransactions.bind(this),\n );\n this.#unsubscribeIncomingTransactions =\n typeof unsubIncoming === 'function' ? unsubIncoming : undefined;\n }\n\n #onTransactionConfirmed(payload: TransactionMeta): void {\n const hexChainId = payload?.chainId;\n if (!hexChainId) {\n return;\n }\n const caipChainId = `eip155:${parseInt(hexChainId, 16)}` as ChainId;\n this.#refreshBalanceForChains([caipChainId]).catch((error) => {\n log('Failed to refresh balance after transaction confirmed', { error });\n });\n }\n\n #onIncomingTransactions(payload: TransactionMeta[]): void {\n const chainIds = Array.from(\n new Set(\n (payload ?? [])\n .map((item) => item?.chainId)\n .filter((id): id is Hex => Boolean(id)),\n ),\n );\n const caipChainIds = chainIds.map(\n (hexChainId) => `eip155:${parseInt(hexChainId, 16)}` as ChainId,\n );\n const toRefresh =\n caipChainIds.length > 0 ? caipChainIds : [...this.#activeChains];\n this.#refreshBalanceForChains(toRefresh).catch((error) => {\n log('Failed to refresh balance after incoming transactions', { error });\n });\n }\n\n /**\n * Fetch balances for the given chains across all active subscriptions and\n * push updates to the controller.\n *\n * @param chainIds - CAIP-2 chain IDs to refresh.\n */\n async #refreshBalanceForChains(chainIds: ChainId[]): Promise<void> {\n const chainIdsSet = new Set(chainIds);\n const chainsToFetch = chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n if (chainsToFetch.length === 0) {\n return;\n }\n\n for (const subscription of this.#activeSubscriptions.values()) {\n const subscriptionChains = subscription.chains.filter((chainId) =>\n chainIdsSet.has(chainId),\n );\n if (subscriptionChains.length === 0) {\n continue;\n }\n\n const request: DataRequest = {\n accountsWithSupportedChains: subscription.accounts.map((account) => ({\n account,\n supportedChains: subscriptionChains,\n })),\n chainIds: subscriptionChains,\n dataTypes: ['balance'],\n };\n\n try {\n const response = await this.fetch(request);\n if (\n response.assetsBalance &&\n Object.keys(response.assetsBalance).length > 0\n ) {\n subscription.onAssetsUpdate(response)?.catch((error) => {\n log('Failed to report balance update after transaction', {\n error,\n });\n });\n }\n } catch (error) {\n log('Failed to fetch balance after transaction', {\n chains: subscriptionChains,\n error,\n });\n }\n }\n }\n\n #initializeFromNetworkController(): void {\n log('Initializing from NetworkController');\n try {\n const networkState = this.#messenger.call('NetworkController:getState');\n this.#updateFromNetworkState(networkState);\n } catch (error) {\n log('Failed to initialize from NetworkController', error);\n }\n }\n\n #updateFromNetworkState(networkState: NetworkState): void {\n const { networkConfigurationsByChainId, networksMetadata } = networkState;\n\n const chainStatuses: Record<ChainId, ChainStatus> = {};\n const activeChains: ChainId[] = [];\n\n for (const [hexChainId, config] of Object.entries(\n networkConfigurationsByChainId,\n )) {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const defaultRpcEndpoint =\n config.rpcEndpoints[config.defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n const { networkClientId } = defaultRpcEndpoint;\n const metadata = networksMetadata[networkClientId];\n\n const status: NetworkStatus =\n metadata?.status ?? ('unknown' as NetworkStatus);\n\n chainStatuses[caip2ChainId] = {\n chainId: caip2ChainId,\n status,\n name: config.name,\n nativeCurrency: config.nativeCurrency,\n networkClientId,\n };\n\n if (status === 'available' || status === 'unknown') {\n activeChains.push(caip2ChainId);\n }\n }\n\n log('Network state updated', {\n configuredChains: Object.keys(chainStatuses),\n activeChains,\n });\n\n // Check if chains changed\n const previousChains = [...this.#activeChains];\n const previousSet = new Set(previousChains);\n const hasChanges =\n previousChains.length !== activeChains.length ||\n activeChains.some((chain) => !previousSet.has(chain));\n\n // Update internal state and data source state before notifying, so that\n // when the controller handles the callback and calls getActiveChainsSync(),\n // it receives the updated chains (same order as AbstractDataSource.updateActiveChains).\n this.#chainStatuses = chainStatuses;\n this.#activeChains = activeChains;\n this.state.activeChains = activeChains;\n\n if (hasChanges) {\n this.#onActiveChainsUpdated(this.getName(), activeChains, previousChains);\n }\n }\n\n #getProvider(chainId: ChainId): Web3Provider | undefined {\n const cached = this.#providerCache.get(chainId);\n if (cached) {\n return cached;\n }\n\n const chainStatus = this.#chainStatuses[chainId];\n if (!chainStatus) {\n return undefined;\n }\n\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n chainStatus.networkClientId,\n );\n if (!networkClient?.provider) {\n return undefined;\n }\n const web3Provider = new Web3Provider(networkClient.provider);\n this.#providerCache.set(chainId, web3Provider);\n\n return web3Provider;\n } catch (error) {\n log('Failed to get provider for chain', { chainId, error });\n return undefined;\n }\n }\n\n /**\n * Get provider for MulticallClient using a hex chainId.\n *\n * @param hexChainId - The hex string representation of the chain id.\n * @returns An RpcProvider instance for the specified chain.\n */\n #getMulticallProvider(hexChainId: string): RpcProvider {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const web3Provider = this.#getProvider(caip2ChainId);\n\n if (!web3Provider) {\n throw new Error(`No provider available for chain ${hexChainId}`);\n }\n\n return {\n call: async (params: { to: string; data: string }): Promise<string> => {\n return web3Provider.call({\n to: params.to,\n data: params.data,\n });\n },\n getBalance: async (address: string): Promise<{ toString(): string }> => {\n const balance = await web3Provider.getBalance(address);\n return balance;\n },\n };\n }\n\n #clearProviderCache(): void {\n this.#providerCache.clear();\n }\n\n /**\n * Fetch the `decimals()` value from an ERC20 contract via RPC.\n *\n * @param chainId - CAIP-2 chain ID.\n * @param tokenAddress - The token contract address.\n * @returns The decimals value, or undefined if the call fails.\n */\n async #fetchDecimalsViaRpc(\n chainId: ChainId,\n tokenAddress: string,\n ): Promise<number | undefined> {\n try {\n const provider = this.#getProvider(chainId);\n if (!provider) {\n return undefined;\n }\n // ERC20 decimals() selector: keccak256(\"decimals()\") = 0x313ce567\n const result = await provider.call({\n to: tokenAddress,\n data: '0x313ce567',\n });\n if (!result || result === '0x') {\n return undefined;\n }\n const parsed = parseInt(result, 16);\n if (Number.isNaN(parsed) || parsed < 0 || parsed > 255) {\n return undefined;\n }\n return parsed;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Get the data source name.\n *\n * @returns The name of this data source.\n */\n /**\n * Get the status of all configured chains.\n *\n * @returns Record of chain statuses keyed by chain ID.\n */\n getChainStatuses(): Record<ChainId, ChainStatus> {\n return { ...this.#chainStatuses };\n }\n\n /**\n * Get the status of a specific chain.\n *\n * @param chainId - The chain ID to get status for.\n * @returns The chain status or undefined if not found.\n */\n getChainStatus(chainId: ChainId): ChainStatus | undefined {\n return this.#chainStatuses[chainId];\n }\n\n /**\n * Set the balance polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setBalancePollingInterval(interval: number): void {\n log('Setting balance polling interval', { interval });\n this.#balanceFetcher.setIntervalLength(interval);\n }\n\n /**\n * Get the current balance polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getBalancePollingInterval(): number | undefined {\n return this.#balanceFetcher.getIntervalLength();\n }\n\n /**\n * Set the token detection polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setDetectionPollingInterval(interval: number): void {\n log('Setting detection polling interval', { interval });\n this.#tokenDetector.setIntervalLength(interval);\n }\n\n /**\n * Get the current token detection polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getDetectionPollingInterval(): number | undefined {\n return this.#tokenDetector.getIntervalLength();\n }\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n if (!this.#isOnboarded()) {\n log('Skipping fetch - onboarding not complete');\n return {};\n }\n\n const response: DataResponse = {};\n\n const chainsToFetch = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n log('Fetch requested', {\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n requestedChains: request.chainIds,\n chainsToFetch,\n });\n\n if (chainsToFetch.length === 0) {\n log('No active chains to fetch');\n return response;\n }\n\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const failedChains: ChainId[] = [];\n\n // Fetch balances for each account and its supported chains (pre-computed in request)\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToFetch.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n // Build a single AssetFetchEntry[] for native + custom ERC-20s\n const nativeAssetId = this.#buildNativeAssetId(chainId);\n const assetsToFetch: AssetFetchEntry[] = [\n { assetId: nativeAssetId, address: ZERO_ADDRESS },\n ];\n\n if (request.customAssets) {\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n for (const assetId of request.customAssets) {\n try {\n const parsed = parseCaipAssetType(assetId);\n const assetChainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n if (\n assetChainId === chainId &&\n parsed.assetNamespace === 'erc20'\n ) {\n const tokenAddress =\n parsed.assetReference.toLowerCase() as Address;\n const normalizedId = normalizeAssetId(assetId);\n const decimals = existingMetadata[normalizedId]?.decimals;\n\n assetsToFetch.push({\n assetId,\n address: tokenAddress,\n decimals,\n });\n }\n } catch {\n // Skip unparseable asset IDs\n }\n }\n }\n\n try {\n const result = await this.#balanceFetcher.fetchBalancesForAssets(\n hexChainId,\n accountId,\n address as Address,\n assetsToFetch,\n );\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset IDs from BalanceFetcher (which uses lowercase\n // addresses) to checksummed form so they match assetsInfo state keys.\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const balanceMetadata = this.#collectMetadataForBalances(\n normalizedBalances,\n chainId,\n );\n Object.assign(assetsInfo, balanceMetadata);\n\n // Convert balances to human-readable format using decimals from\n // assetsInfo state (which includes pendingMetadata from addCustomAsset).\n // Resolution: state → pipeline metadata → RPC `decimals()`; omit balance if still unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n let decimals: number | undefined =\n stateMetadata?.decimals ?? pipelineMetadata?.decimals;\n\n if (decimals === undefined) {\n const parsed = parseCaipAssetType(balance.assetId);\n if (parsed.assetNamespace === 'erc20') {\n decimals = await this.#fetchDecimalsViaRpc(\n chainId,\n parsed.assetReference,\n );\n }\n }\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n assetsBalance[accountId][balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n } catch (error) {\n log('Failed to fetch balance', { address, chainId, error });\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n assetsBalance[accountId][nativeAssetId] = { amount: '0' };\n\n // Even on error, include native token metadata\n const chainStatus = this.#chainStatuses[chainId];\n if (chainStatus) {\n assetsInfo[nativeAssetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n\n if (!failedChains.includes(chainId)) {\n failedChains.push(chainId);\n }\n }\n }\n }\n\n if (failedChains.length > 0) {\n log('Fetch PARTIAL - some chains failed', {\n successChains: chainsToFetch.filter(\n (chain) => !failedChains.includes(chain),\n ),\n failedChains,\n });\n\n response.errors = {};\n for (const chainId of failedChains) {\n response.errors[chainId] = 'RPC fetch failed';\n }\n } else {\n log('Fetch SUCCESS', {\n chains: chainsToFetch,\n accountCount: Object.keys(assetsBalance).length,\n });\n }\n\n response.assetsBalance = assetsBalance;\n\n // Include metadata for native tokens if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n return response;\n }\n\n /**\n * Run token detection for an account on a chain.\n *\n * @param chainId - The chain ID to detect tokens on.\n * @param account - The account to detect tokens for.\n * @returns Promise resolving to a DataResponse with detected assets.\n */\n async detectTokens(\n chainId: ChainId,\n account: InternalAccount,\n ): Promise<DataResponse> {\n if (!this.#tokenDetectionEnabled() || !this.#useExternalService()) {\n return {};\n }\n\n const hexChainId = caipChainIdToHex(chainId);\n const { address, id: accountId } = account;\n\n log('Running token detection', { chainId, accountId });\n\n try {\n const result = await this.#tokenDetector.detectTokens(\n hexChainId,\n accountId,\n address as Address,\n {\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n },\n );\n\n if (result.detectedAssets.length === 0) {\n log('No new tokens detected');\n return {};\n }\n\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n chainId,\n accountId,\n });\n\n // Convert detected assets to DataResponse format\n const balances: Record<Caip19AssetId, AssetBalance> = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n\n // Build metadata from detected assets\n for (const asset of result.detectedAssets) {\n if (asset.symbol && asset.decimals !== undefined) {\n assetsInfo[asset.assetId] = {\n type: 'erc20',\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n\n // Add balances for detected tokens (converted to human-readable format)\n for (const balance of result.detectedBalances) {\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n balances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n const response: DataResponse = {\n detectedAssets: {\n [accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsBalance: {\n [accountId]: balances,\n },\n };\n\n // Include metadata if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n return response;\n } catch (error) {\n log('Token detection failed', { chainId, accountId, error });\n return {};\n }\n }\n\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n log('Middleware fetching', {\n chains: supportedChains,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n });\n\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] ??= {};\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n\n if (response.assetsInfo) {\n context.response.assetsInfo ??= {};\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n\n return next({\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n });\n }\n\n return next(context);\n };\n }\n\n /**\n * Subscribe to updates for the given request.\n * Starts polling through BalanceFetcher and TokenDetector.\n *\n * @param subscriptionRequest - The subscription request details.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n if (!this.#isOnboarded()) {\n log('Skipping subscribe - onboarding not complete');\n return;\n }\n\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Use request.chainIds when activeChains is not yet populated (e.g. before\n // NetworkController state has been applied) so polling can start.\n const chainsToSubscribe =\n this.#activeChains.length > 0\n ? request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n )\n : request.chainIds;\n\n log('Subscribe requested', {\n subscriptionId,\n isUpdate,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n chainsToSubscribe,\n activeChainsFallback: this.#activeChains.length === 0,\n });\n\n if (chainsToSubscribe.length === 0) {\n log('No active chains to subscribe');\n return;\n }\n\n // Handle subscription update - restart polling for new chains\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n log('Updating existing subscription - restarting polling', {\n subscriptionId,\n existingChains: existing.chains,\n newChains: chainsToSubscribe,\n });\n // Don't return early - continue to unsubscribe and restart polling\n }\n }\n\n // Clean up existing subscription (stops old polling)\n await this.unsubscribe(subscriptionId);\n // Start polling through BalanceFetcher and TokenDetector\n const balancePollingTokens: string[] = [];\n const detectionPollingTokens: string[] = [];\n\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToSubscribe.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n // Start balance polling\n const balanceInput: BalancePollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n };\n const balanceToken = this.#balanceFetcher.startPolling(balanceInput);\n balancePollingTokens.push(balanceToken);\n\n // Start detection polling if enabled and external services allowed\n if (this.#tokenDetectionEnabled() && this.#useExternalService()) {\n const detectionInput: DetectionPollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n };\n const detectionToken =\n this.#tokenDetector.startPolling(detectionInput);\n detectionPollingTokens.push(detectionToken);\n }\n }\n }\n\n // Store subscription data\n const accounts = request.accountsWithSupportedChains.map(\n (entry) => entry.account,\n );\n this.#activeSubscriptions.set(subscriptionId, {\n balancePollingTokens,\n detectionPollingTokens,\n chains: chainsToSubscribe,\n accounts,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n log('Subscription SUCCESS', {\n subscriptionId,\n chains: chainsToSubscribe,\n balancePollingCount: balancePollingTokens.length,\n detectionPollingCount: detectionPollingTokens.length,\n });\n }\n\n /**\n * Unsubscribe from updates and stop polling.\n *\n * @param subscriptionId - The subscription ID to unsubscribe.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n // Stop balance polling\n for (const token of subscription.balancePollingTokens) {\n this.#balanceFetcher.stopPollingByPollingToken(token);\n }\n\n // Stop detection polling\n for (const token of subscription.detectionPollingTokens) {\n this.#tokenDetector.stopPollingByPollingToken(token);\n }\n\n this.#activeSubscriptions.delete(subscriptionId);\n log('Unsubscribed and stopped polling', { subscriptionId });\n }\n }\n\n /**\n * Build the native asset ID for a given chain using NetworkEnablementController state.\n *\n * @param chainId - The CAIP-2 chain ID (e.g., \"eip155:1\")\n * @returns The CAIP-19 native asset ID (e.g., \"eip155:1/slip44:60\")\n */\n #buildNativeAssetId(chainId: ChainId): Caip19AssetId {\n const { nativeAssetIdentifiers } = this.#messenger.call(\n 'NetworkEnablementController:getState',\n );\n\n return nativeAssetIdentifiers[chainId] ?? `${chainId}/slip44:60`;\n }\n\n /**\n * Get existing assets metadata from AssetsController state.\n * Used to include metadata for ERC20 tokens when returning balance updates.\n *\n * @returns Record of asset IDs to their metadata.\n */\n #getExistingAssetsMetadata(): Record<Caip19AssetId, AssetMetadata> {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n return state.assetsInfo ?? {};\n } catch (error) {\n log('Failed to get existing assets metadata', { error });\n return {};\n }\n }\n\n /**\n * Destroy the data source and clean up resources.\n */\n destroy(): void {\n log('Destroying RpcDataSource');\n\n this.#unsubscribeTransactionConfirmed?.();\n this.#unsubscribeIncomingTransactions?.();\n\n // Stop all polling\n this.#balanceFetcher.stopAllPolling();\n this.#tokenDetector.stopAllPolling();\n\n // Clear subscriptions\n this.#activeSubscriptions.clear();\n\n // Clear caches\n this.#providerCache.clear();\n }\n}\n\nexport function createRpcDataSource(\n options: RpcDataSourceOptions,\n): RpcDataSource {\n return new RpcDataSource(options);\n}\n"]}
1
+ {"version":3,"file":"RpcDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/RpcDataSource.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,iCAAiC;AACxD,OAAO,EAAE,KAAK,EAAE,mCAAmC;AAcnD,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EACjB,wBAAwB;AAEzB,OAAO,WAAW,qBAAqB;AAMvC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,sBAAkB;AAU9D,OAAO,EAAE,gBAAgB,EAAE,2BAAiB;AAC5C,OAAO,EAAE,YAAY,EAAE,+BAA2B;AAClD,OAAO,EAAE,aAAa,EAAE,mCAA+B;AACvD,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAK1D,OAAO,EACL,cAAc,EACd,eAAe,EACf,aAAa,EACb,eAAe,EAChB,qCAA2B;AAa5B,MAAM,eAAe,GAAG,eAAe,CAAC;AACxC,MAAM,wBAAwB,GAAG,KAAM,CAAC,CAAC,aAAa;AACtD,MAAM,0BAA0B,GAAG,MAAO,CAAC,CAAC,YAAY;AAExD,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAoF/D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAO,EAAE;IACvD,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;AAChF,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,aAAc,SAAQ,kBAGlC;IA4CC,YAAY,OAA6B;QACvC,KAAK,CAAC,eAAe,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;;QA5CtC,2CAAsC;QAEtC,uDAIC;QAED,wDAEsB;QAEtB,yCAAiB;QAEjB,uDAAsC;QAEtC,oDAAmC;QAEnC,6CAA4B;QAErC,8BAA8B;QAC9B,sCAA2B,EAAE,EAAC;QAE9B,2CAA2C;QAC3C,uCAA+C,EAAE,EAAC;QAElD,iDAAiD;QACxC,uCAA6C,IAAI,GAAG,EAAE,EAAC;QAEhE,iCAAiC;QACxB,6CAAsD,IAAI,GAAG,EAAE,EAAC;QAEzE,yDAA6D,SAAS,EAAC;QAEvE,yDAA6D,SAAS,EAAC;QAEvE,4BAA4B;QACnB,iDAAkC;QAElC,gDAAgC;QAEhC,+CAA8B;QAIrC,uBAAA,IAAI,4BAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,wCAA0B,OAAO,CAAC,qBAAqB,MAAA,CAAC;QAC5D,uBAAA,IAAI,yCACF,OAAO,CAAC,sBAAsB,IAAI,CAAC,GAAc,EAAE,CAAC,SAAS,CAAC,MAAA,CAAC;QACjE,uBAAA,IAAI,0BAAY,OAAO,CAAC,OAAO,IAAI,KAAM,MAAA,CAAC;QAC1C,uBAAA,IAAI,wCACF,OAAO,CAAC,qBAAqB,IAAI,CAAC,GAAY,EAAE,CAAC,IAAI,CAAC,MAAA,CAAC;QACzD,uBAAA,IAAI,qCACF,OAAO,CAAC,kBAAkB,IAAI,CAAC,GAAY,EAAE,CAAC,IAAI,CAAC,MAAA,CAAC;QACtD,uBAAA,IAAI,8BAAgB,OAAO,CAAC,WAAW,IAAI,CAAC,GAAY,EAAE,CAAC,IAAI,CAAC,MAAA,CAAC;QAEjE,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,wBAAwB,CAAC;QAC5E,MAAM,iBAAiB,GACrB,OAAO,CAAC,iBAAiB,IAAI,0BAA0B,CAAC;QAE1D,GAAG,CAAC,4BAA4B,EAAE;YAChC,OAAO,EAAE,uBAAA,IAAI,8BAAS;YACtB,eAAe;YACf,iBAAiB;YACjB,qBAAqB,EAAE,uBAAA,IAAI,4CAAuB,MAA3B,IAAI,CAAyB;YACpD,kBAAkB,EAAE,uBAAA,IAAI,yCAAoB,MAAxB,IAAI,CAAsB;SAC/C,CAAC,CAAC;QAEH,oDAAoD;QACpD,uBAAA,IAAI,kCAAoB,IAAI,eAAe,CAAC,CAAC,UAAkB,EAAE,EAAE;YACjE,OAAO,uBAAA,IAAI,qEAAsB,MAA1B,IAAI,EAAuB,UAAU,CAAC,CAAC;QAChD,CAAC,CAAC,MAAA,CAAC;QAEH,iEAAiE;QACjE,MAAM,uBAAuB,GAAG;YAC9B,IAAI,EAAE,CACJ,OAAoC,EAGpC,EAAE;gBACF,MAAM,KAAK,GAAG,uBAAA,IAAI,gCAAW,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBAChE,OAAO;oBACL,aAAa,EAAE,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAGxC;iBACF,CAAC;YACJ,CAAC;SACF,CAAC;QAEF,kDAAkD;QAClD,uBAAA,IAAI,iCAAmB,IAAI,cAAc,CACvC,uBAAA,IAAI,sCAAiB,EACrB,uBAAuB,EACvB,EAAE,eAAe,EAAE,eAAe,EAAE,CACrC,MAAA,CAAC;QACF,iFAAiF;QACjF,uBAAA,IAAI,qCAAgB,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACvD,IAAI,CAAC;gBACH,MAAM,uBAAA,IAAI,oEAAqB,MAAzB,IAAI,EAAsB,MAAM,CAAC,CAAC;YAC1C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,+BAA+B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,iDAAiD;QACjD,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,uBAAA,IAAI,gCAAkB,IAAI,aAAa,CACrC,uBAAA,IAAI,sCAAiB,EACrB,eAAe,EACf;YACE,eAAe,EAAE,iBAAiB;YAClC,qBAAqB,EAAE,uBAAA,IAAI,4CAAuB;YAClD,kBAAkB,EAAE,uBAAA,IAAI,yCAAoB;SAC7C,CACF,MAAA,CAAC;QACF,qEAAqE;QACrE,uBAAA,IAAI,oCAAe,CAAC,oBAAoB,CAAC,CAAC,MAAM,EAAE,EAAE;YAClD,IAAI,CAAC;gBACH,uBAAA,IAAI,sEAAuB,MAA3B,IAAI,EAAwB,MAAM,CAAC,CAAC;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,uBAAA,IAAI,6EAA8B,MAAlC,IAAI,CAAgC,CAAC;QACrC,uBAAA,IAAI,6EAA8B,MAAlC,IAAI,CAAgC,CAAC;QACrC,uBAAA,IAAI,gFAAiC,MAArC,IAAI,CAAmC,CAAC;IAC1C,CAAC;IAqeD;;;;OAIG;IACH;;;;OAIG;IACH,gBAAgB;QACd,OAAO,EAAE,GAAG,uBAAA,IAAI,oCAAe,EAAE,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,OAAgB;QAC7B,OAAO,uBAAA,IAAI,oCAAe,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACH,yBAAyB,CAAC,QAAgB;QACxC,GAAG,CAAC,kCAAkC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtD,uBAAA,IAAI,qCAAgB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACH,yBAAyB;QACvB,OAAO,uBAAA,IAAI,qCAAgB,CAAC,iBAAiB,EAAE,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,2BAA2B,CAAC,QAAgB;QAC1C,GAAG,CAAC,oCAAoC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxD,uBAAA,IAAI,oCAAe,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,2BAA2B;QACzB,OAAO,uBAAA,IAAI,oCAAe,CAAC,iBAAiB,EAAE,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,IAAI,CAAC,uBAAA,IAAI,kCAAa,MAAjB,IAAI,CAAe,EAAE,CAAC;YACzB,GAAG,CAAC,0CAA0C,CAAC,CAAC;YAChD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,QAAQ,GAAiB,EAAE,CAAC;QAElC,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CACxD,uBAAA,IAAI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CACrC,CAAC;QAEF,GAAG,CAAC,iBAAiB,EAAE;YACrB,QAAQ,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YACtE,eAAe,EAAE,OAAO,CAAC,QAAQ;YACjC,aAAa;SACd,CAAC,CAAC;QAEH,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACjC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,aAAa,GAGf,EAAE,CAAC;QACP,MAAM,UAAU,GAAyC,EAAE,CAAC;QAC5D,MAAM,YAAY,GAAc,EAAE,CAAC;QAEnC,qFAAqF;QACrF,KAAK,MAAM,EACT,OAAO,EACP,eAAe,GAChB,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;YACzC,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CACtD,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAChC,CAAC;YACF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,SAAS;YACX,CAAC;YAED,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;YAE3C,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;gBACvC,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAE7C,+DAA+D;gBAC/D,MAAM,aAAa,GAAG,uBAAA,IAAI,mEAAoB,MAAxB,IAAI,EAAqB,OAAO,CAAC,CAAC;gBACxD,MAAM,aAAa,GAAsB;oBACvC,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE;iBAClD,CAAC;gBAEF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;oBACzB,MAAM,gBAAgB,GAAG,uBAAA,IAAI,0EAA2B,MAA/B,IAAI,CAA6B,CAAC;oBAE3D,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;wBAC3C,IAAI,CAAC;4BACH,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;4BAC3C,MAAM,YAAY,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;4BAC3E,IACE,YAAY,KAAK,OAAO;gCACxB,MAAM,CAAC,cAAc,KAAK,OAAO,EACjC,CAAC;gCACD,MAAM,YAAY,GAChB,MAAM,CAAC,cAAc,CAAC,WAAW,EAAa,CAAC;gCACjD,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gCAC/C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC;gCAE1D,aAAa,CAAC,IAAI,CAAC;oCACjB,OAAO;oCACP,OAAO,EAAE,YAAY;oCACrB,QAAQ;iCACT,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;wBAAC,MAAM,CAAC;4BACP,6BAA6B;wBAC/B,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,qCAAgB,CAAC,sBAAsB,CAC9D,UAAU,EACV,SAAS,EACT,OAAkB,EAClB,aAAa,CACd,CAAC;oBAEF,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC9B,aAAa,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;oBAChC,CAAC;oBAED,gEAAgE;oBAChE,sEAAsE;oBACtE,MAAM,kBAAkB,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACrD,GAAG,CAAC;wBACJ,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;qBACrC,CAAC,CAAC,CAAC;oBAEJ,oCAAoC;oBACpC,MAAM,eAAe,GAAG,uBAAA,IAAI,2EAA4B,MAAhC,IAAI,EAC1B,kBAAkB,EAClB,OAAO,CACR,CAAC;oBACF,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;oBAE3C,gEAAgE;oBAChE,yEAAyE;oBACzE,2FAA2F;oBAC3F,MAAM,gBAAgB,GAAG,uBAAA,IAAI,0EAA2B,MAA/B,IAAI,CAA6B,CAAC;oBAC3D,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;wBACzC,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;wBACxD,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;wBACrD,IAAI,QAAQ,GACV,aAAa,EAAE,QAAQ,IAAI,gBAAgB,EAAE,QAAQ,CAAC;wBAExD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;4BAC3B,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;4BACnD,IAAI,MAAM,CAAC,cAAc,KAAK,OAAO,EAAE,CAAC;gCACtC,QAAQ,GAAG,MAAM,uBAAA,IAAI,oEAAqB,MAAzB,IAAI,EACnB,OAAO,EACP,MAAM,CAAC,cAAc,CACtB,CAAC;4BACJ,CAAC;wBACH,CAAC;wBAED,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;4BAC3B,SAAS;wBACX,CAAC;wBAED,MAAM,mBAAmB,GAAG,uBAAA,IAAI,uEAAwB,MAA5B,IAAI,EAC9B,OAAO,CAAC,OAAO,EACf,QAAQ,CACT,CAAC;wBAEF,aAAa,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;4BAC1C,MAAM,EAAE,mBAAmB;yBAC5B,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,GAAG,CAAC,yBAAyB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;oBAE5D,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC9B,aAAa,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;oBAChC,CAAC;oBACD,aAAa,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;oBAE1D,+CAA+C;oBAC/C,MAAM,WAAW,GAAG,uBAAA,IAAI,oCAAe,CAAC,OAAO,CAAC,CAAC;oBACjD,IAAI,WAAW,EAAE,CAAC;wBAChB,UAAU,CAAC,aAAa,CAAC,GAAG;4BAC1B,IAAI,EAAE,QAAQ;4BACd,MAAM,EAAE,WAAW,CAAC,cAAc;4BAClC,IAAI,EAAE,WAAW,CAAC,cAAc;4BAChC,QAAQ,EAAE,EAAE;yBACb,CAAC;oBACJ,CAAC;oBAED,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;wBACpC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,GAAG,CAAC,oCAAoC,EAAE;gBACxC,aAAa,EAAE,aAAa,CAAC,MAAM,CACjC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CACzC;gBACD,YAAY;aACb,CAAC,CAAC;YAEH,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC;YACrB,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;gBACnC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC;YAChD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,eAAe,EAAE;gBACnB,MAAM,EAAE,aAAa;gBACrB,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM;aAChD,CAAC,CAAC;QACL,CAAC;QAED,QAAQ,CAAC,aAAa,GAAG,aAAa,CAAC;QAEvC,oDAAoD;QACpD,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvC,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;QACnC,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY,CAChB,OAAgB,EAChB,OAAwB;QAExB,IAAI,CAAC,uBAAA,IAAI,4CAAuB,MAA3B,IAAI,CAAyB,IAAI,CAAC,uBAAA,IAAI,yCAAoB,MAAxB,IAAI,CAAsB,EAAE,CAAC;YAClE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;QAE3C,GAAG,CAAC,yBAAyB,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QAEvD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,oCAAe,CAAC,YAAY,CACnD,UAAU,EACV,SAAS,EACT,OAAkB,EAClB;gBACE,qBAAqB,EAAE,uBAAA,IAAI,4CAAuB,MAA3B,IAAI,CAAyB;gBACpD,kBAAkB,EAAE,uBAAA,IAAI,yCAAoB,MAAxB,IAAI,CAAsB;aAC/C,CACF,CAAC;YAEF,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvC,GAAG,CAAC,wBAAwB,CAAC,CAAC;gBAC9B,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,GAAG,CAAC,qBAAqB,EAAE;gBACzB,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM;gBACnC,OAAO;gBACP,SAAS;aACV,CAAC,CAAC;YAEH,iDAAiD;YACjD,MAAM,QAAQ,GAAwC,EAAE,CAAC;YACzD,MAAM,UAAU,GAAyC,EAAE,CAAC;YAE5D,sCAAsC;YACtC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC1C,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;oBACjD,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG;wBAC1B,IAAI,EAAE,OAAO;wBACb,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM;wBAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;qBACnB,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,wEAAwE;YACxE,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAC9C,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAC9C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAC7C,CAAC;gBACF,IAAI,aAAa,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC1C,SAAS;gBACX,CAAC;gBACD,MAAM,mBAAmB,GAAG,uBAAA,IAAI,uEAAwB,MAA5B,IAAI,EAC9B,OAAO,CAAC,OAAO,EACf,aAAa,CAAC,QAAQ,CACvB,CAAC;gBAEF,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;oBAC1B,MAAM,EAAE,mBAAmB;iBAC5B,CAAC;YACJ,CAAC;YAED,MAAM,QAAQ,GAAiB;gBAC7B,cAAc,EAAE;oBACd,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;iBACjE;gBACD,aAAa,EAAE;oBACb,CAAC,SAAS,CAAC,EAAE,QAAQ;iBACtB;aACF,CAAC;YAEF,kCAAkC;YAClC,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvC,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;YACnC,CAAC;YAED,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,wBAAwB,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7D,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;;YAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;YAE5B,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1D,uBAAA,IAAI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CACrC,CAAC;YAEF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;YAED,IAAI,yBAAyB,GAAc,EAAE,CAAC;YAE9C,GAAG,CAAC,qBAAqB,EAAE;gBACzB,MAAM,EAAE,eAAe;gBACvB,QAAQ,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;aACvE,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;gBAChC,GAAG,OAAO;gBACV,QAAQ,EAAE,eAAe;aAC1B,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAC3B,MAAA,OAAO,CAAC,QAAQ,EAAC,aAAa,QAAb,aAAa,GAAK,EAAE,EAAC;gBACtC,KAAK,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,IAAI,MAAM,CAAC,OAAO,CACvD,QAAQ,CAAC,aAAa,CACvB,EAAE,CAAC;oBACF,MAAA,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAC,SAAS,SAAT,SAAS,IAAM,EAAE,EAAC;oBACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG;wBAC1C,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC;wBAC5C,GAAG,eAAe;qBACnB,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBACxB,MAAA,OAAO,CAAC,QAAQ,EAAC,UAAU,QAAV,UAAU,GAAK,EAAE,EAAC;gBACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,GAAG;oBAC5B,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU;oBAC9B,GAAG,QAAQ,CAAC,UAAU;iBACvB,CAAC;YACJ,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;YACjE,yBAAyB,GAAG,eAAe,CAAC,MAAM,CAChD,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CACxC,CAAC;YAEF,IAAI,yBAAyB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAC7C,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,yBAAyB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAC1D,CAAC;gBAEF,OAAO,IAAI,CAAC;oBACV,GAAG,OAAO;oBACV,OAAO,EAAE;wBACP,GAAG,OAAO;wBACV,QAAQ,EAAE,eAAe;qBAC1B;iBACF,CAAC,CAAC;YACL,CAAC;YAED,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,mBAAwC;QACtD,IAAI,CAAC,uBAAA,IAAI,kCAAa,MAAjB,IAAI,CAAe,EAAE,CAAC;YACzB,GAAG,CAAC,8CAA8C,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,mBAAmB,CAAC;QAElE,2EAA2E;QAC3E,kEAAkE;QAClE,MAAM,iBAAiB,GACrB,uBAAA,IAAI,mCAAc,CAAC,MAAM,GAAG,CAAC;YAC3B,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAClC,uBAAA,IAAI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CACrC;YACH,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QAEvB,GAAG,CAAC,qBAAqB,EAAE;YACzB,cAAc;YACd,QAAQ;YACR,QAAQ,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YACtE,iBAAiB;YACjB,oBAAoB,EAAE,uBAAA,IAAI,mCAAc,CAAC,MAAM,KAAK,CAAC;SACtD,CAAC,CAAC;QAEH,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,8DAA8D;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,uBAAA,IAAI,0CAAqB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC/D,IAAI,QAAQ,EAAE,CAAC;gBACb,GAAG,CAAC,qDAAqD,EAAE;oBACzD,cAAc;oBACd,cAAc,EAAE,QAAQ,CAAC,MAAM;oBAC/B,SAAS,EAAE,iBAAiB;iBAC7B,CAAC,CAAC;gBACH,mEAAmE;YACrE,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACvC,yDAAyD;QACzD,MAAM,oBAAoB,GAAa,EAAE,CAAC;QAC1C,MAAM,sBAAsB,GAAa,EAAE,CAAC;QAE5C,KAAK,MAAM,EACT,OAAO,EACP,eAAe,GAChB,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;YACzC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAC1D,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAChC,CAAC;YACF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,SAAS;YACX,CAAC;YAED,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;YAE3C,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;gBACvC,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAE7C,wBAAwB;gBACxB,MAAM,YAAY,GAAwB;oBACxC,OAAO,EAAE,UAAU;oBACnB,SAAS;oBACT,cAAc,EAAE,OAAkB;iBACnC,CAAC;gBACF,MAAM,YAAY,GAAG,uBAAA,IAAI,qCAAgB,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;gBACrE,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAExC,mEAAmE;gBACnE,IAAI,uBAAA,IAAI,4CAAuB,MAA3B,IAAI,CAAyB,IAAI,uBAAA,IAAI,yCAAoB,MAAxB,IAAI,CAAsB,EAAE,CAAC;oBAChE,MAAM,cAAc,GAA0B;wBAC5C,OAAO,EAAE,UAAU;wBACnB,SAAS;wBACT,cAAc,EAAE,OAAkB;qBACnC,CAAC;oBACF,MAAM,cAAc,GAClB,uBAAA,IAAI,oCAAe,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;oBACnD,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,2BAA2B,CAAC,GAAG,CACtD,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CACzB,CAAC;QACF,uBAAA,IAAI,0CAAqB,CAAC,GAAG,CAAC,cAAc,EAAE;YAC5C,oBAAoB;YACpB,sBAAsB;YACtB,MAAM,EAAE,iBAAiB;YACzB,QAAQ;YACR,cAAc,EAAE,mBAAmB,CAAC,cAAc;SACnD,CAAC,CAAC;QAEH,GAAG,CAAC,sBAAsB,EAAE;YAC1B,cAAc;YACd,MAAM,EAAE,iBAAiB;YACzB,mBAAmB,EAAE,oBAAoB,CAAC,MAAM;YAChD,qBAAqB,EAAE,sBAAsB,CAAC,MAAM;SACrD,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,cAAsB;QACtC,MAAM,YAAY,GAAG,uBAAA,IAAI,0CAAqB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACnE,IAAI,YAAY,EAAE,CAAC;YACjB,uBAAuB;YACvB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,oBAAoB,EAAE,CAAC;gBACtD,uBAAA,IAAI,qCAAgB,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;YACxD,CAAC;YAED,yBAAyB;YACzB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,sBAAsB,EAAE,CAAC;gBACxD,uBAAA,IAAI,oCAAe,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;YACvD,CAAC;YAED,uBAAA,IAAI,0CAAqB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;YACjD,GAAG,CAAC,kCAAkC,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAiCD;;OAEG;IACH,OAAO;QACL,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAEhC,uBAAA,IAAI,sDAAiC,EAAE,KAAvC,IAAI,CAAqC,CAAC;QAC1C,uBAAA,IAAI,sDAAiC,EAAE,KAAvC,IAAI,CAAqC,CAAC;QAE1C,mBAAmB;QACnB,uBAAA,IAAI,qCAAgB,CAAC,cAAc,EAAE,CAAC;QACtC,uBAAA,IAAI,oCAAe,CAAC,cAAc,EAAE,CAAC;QAErC,sBAAsB;QACtB,uBAAA,IAAI,0CAAqB,CAAC,KAAK,EAAE,CAAC;QAElC,eAAe;QACf,uBAAA,IAAI,oCAAe,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;CACF;+5BA9jCyB,UAAkB,EAAE,QAAgB;IAC1D,MAAM,SAAS,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAClD,OAAO,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;AAChD,CAAC,iGAYC,QAAsC,EACtC,OAAgB;IAEhB,MAAM,UAAU,GAAyC,EAAE,CAAC;IAC5D,MAAM,gBAAgB,GAAG,uBAAA,IAAI,0EAA2B,MAA/B,IAAI,CAA6B,CAAC;IAE3D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,WAAW,GAAG,uBAAA,IAAI,oCAAe,CAAC,OAAO,CAAC,CAAC;YAEjD,IAAI,WAAW,EAAE,CAAC;gBAChB,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;oBAC5B,IAAI,EAAE,QAAQ;oBACd,MAAM,EAAE,WAAW,CAAC,cAAc;oBAClC,IAAI,EAAE,WAAW,CAAC,cAAc;oBAChC,QAAQ,EAAE,EAAE;iBACb,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,mEAAmE;YACnE,mEAAmE;YACnE,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,YAAY,EAAE,CAAC;gBACjB,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,KAAK,6CAAsB,MAA0B;IACnD,MAAM,WAAW,GAAuC,EAAE,CAAC;IAE3D,wCAAwC;IACxC,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,UAAU,cAAc,EAAa,CAAC;IAE1D,0EAA0E;IAC1E,MAAM,kBAAkB,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,GAAG,CAAC;QACJ,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;KACrC,CAAC,CAAC,CAAC;IAEJ,oCAAoC;IACpC,MAAM,UAAU,GAAG,uBAAA,IAAI,2EAA4B,MAAhC,IAAI,EACrB,kBAAkB,EAClB,WAAW,CACZ,CAAC;IAEF,6CAA6C;IAC7C,4EAA4E;IAC5E,MAAM,gBAAgB,GAAG,uBAAA,IAAI,0EAA2B,MAA/B,IAAI,CAA6B,CAAC;IAC3D,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,aAAa,EAAE,QAAQ,IAAI,gBAAgB,EAAE,QAAQ,CAAC;QAEvE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,MAAM,mBAAmB,GAAG,uBAAA,IAAI,uEAAwB,MAA5B,IAAI,EAC9B,OAAO,CAAC,OAAO,EACf,QAAQ,CACT,CAAC;QAEF,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;YAC7B,MAAM,EAAE,mBAAmB;SAC5B,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,8EAA8E;IAC9E,MAAM,QAAQ,GAAiB;QAC7B,aAAa,EAAE;YACb,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,WAAW;SAChC;QACD,UAAU;QACV,UAAU,EAAE,OAAO;KACpB,CAAC;IAEF,MAAM,OAAO,GAAgB;QAC3B,2BAA2B,EAAE,EAAE;QAC/B,QAAQ,EAAE,CAAC,WAAW,CAAC;QACvB,SAAS,EAAE,CAAC,SAAS,CAAC;KACvB,CAAC;IAEF,GAAG,CAAC,yBAAyB,EAAE;QAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM;KACjD,CAAC,CAAC;IAEH,KAAK,MAAM,YAAY,IAAI,uBAAA,IAAI,0CAAqB,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9D,YAAY,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC9D,GAAG,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,uFAOsB,MAA4B;IACjD,GAAG,CAAC,qBAAqB,EAAE;QACzB,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM;KACpC,CAAC,CAAC;IAEH,0CAA0C;IAC1C,MAAM,WAAW,GAAyC,EAAE,CAAC;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YAC1C,oEAAoE;YACpE,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACjD,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG;oBAC3B,IAAI,EAAE,OAAO;oBACb,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM;oBAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;iBACnB,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,MAAM,WAAW,GAAuC,EAAE,CAAC;IAC3D,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAC9C,gDAAgD;YAChD,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAC9C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAC7C,CAAC;YACF,IAAI,aAAa,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC1C,SAAS;YACX,CAAC;YACD,MAAM,mBAAmB,GAAG,uBAAA,IAAI,uEAAwB,MAA5B,IAAI,EAC9B,OAAO,CAAC,OAAO,EACf,aAAa,CAAC,QAAQ,CACvB,CAAC;YAEF,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;gBAC7B,MAAM,EAAE,mBAAmB;aAC5B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,8EAA8E;IAC9E,MAAM,QAAQ,GAAiB;QAC7B,cAAc,EAAE;YACd,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;SACxE;QACD,UAAU,EAAE,WAAW;QACvB,aAAa,EAAE;YACb,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,WAAW;SAChC;QACD,UAAU,EAAE,OAAO;KACpB,CAAC;IAEF,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,UAAU,cAAc,EAAa,CAAC;IAC1D,MAAM,OAAO,GAAgB;QAC3B,2BAA2B,EAAE,EAAE;QAC/B,QAAQ,EAAE,CAAC,WAAW,CAAC;QACvB,SAAS,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC;KAC5C,CAAC;IAEF,KAAK,MAAM,YAAY,IAAI,uBAAA,IAAI,0CAAqB,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9D,YAAY,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC9D,GAAG,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;IAGC,uBAAA,IAAI,gCAAW,CAAC,SAAS,CACvB,+BAA+B,EAC/B,CAAC,YAA0B,EAAE,EAAE;QAC7B,GAAG,CAAC,iCAAiC,CAAC,CAAC;QACvC,uBAAA,IAAI,mEAAoB,MAAxB,IAAI,CAAsB,CAAC;QAC3B,uBAAA,IAAI,uEAAwB,MAA5B,IAAI,EAAyB,YAAY,CAAC,CAAC;IAC7C,CAAC,CACF,CAAC;AACJ,CAAC;IAGC,MAAM,cAAc,GAAG,uBAAA,IAAI,gCAAW,CAAC,SAAS,CAC9C,4CAA4C,EAC5C,uBAAA,IAAI,uEAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CACxC,CAAC;IACF,uBAAA,IAAI,kDACF,OAAO,cAAc,KAAK,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,MAAA,CAAC;IAEpE,MAAM,aAAa,GAAG,uBAAA,IAAI,gCAAW,CAAC,SAAS,CAC7C,oDAAoD,EACpD,uBAAA,IAAI,uEAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CACxC,CAAC;IACF,uBAAA,IAAI,kDACF,OAAO,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,MAAA,CAAC;AACpE,CAAC,yFAEuB,OAAwB;IAC9C,MAAM,UAAU,GAAG,OAAO,EAAE,OAAO,CAAC;IACpC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;IACT,CAAC;IACD,MAAM,WAAW,GAAG,UAAU,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,EAAa,CAAC;IACpE,uBAAA,IAAI,wEAAyB,MAA7B,IAAI,EAA0B,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3D,GAAG,CAAC,uDAAuD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC,yFAEuB,OAA0B;IAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CACzB,IAAI,GAAG,CACL,CAAC,OAAO,IAAI,EAAE,CAAC;SACZ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;SAC5B,MAAM,CAAC,CAAC,EAAE,EAAa,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAC1C,CACF,CAAC;IACF,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAC/B,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,EAAa,CAChE,CAAC;IACF,MAAM,SAAS,GACb,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,uBAAA,IAAI,mCAAc,CAAC,CAAC;IACnE,uBAAA,IAAI,wEAAyB,MAA7B,IAAI,EAA0B,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACvD,GAAG,CAAC,uDAAuD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,KAAK,iDAA0B,QAAmB;IAChD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAChD,uBAAA,IAAI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CACrC,CAAC;IACF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,KAAK,MAAM,YAAY,IAAI,uBAAA,IAAI,0CAAqB,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9D,MAAM,kBAAkB,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAChE,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CACzB,CAAC;QACF,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpC,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAgB;YAC3B,2BAA2B,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACnE,OAAO;gBACP,eAAe,EAAE,kBAAkB;aACpC,CAAC,CAAC;YACH,QAAQ,EAAE,kBAAkB;YAC5B,SAAS,EAAE,CAAC,SAAS,CAAC;SACvB,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3C,IACE,QAAQ,CAAC,aAAa;gBACtB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,EAC9C,CAAC;gBACD,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACrD,GAAG,CAAC,mDAAmD,EAAE;wBACvD,KAAK;qBACN,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,2CAA2C,EAAE;gBAC/C,MAAM,EAAE,kBAAkB;gBAC1B,KAAK;aACN,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;IAGC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,uBAAA,IAAI,gCAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACxE,uBAAA,IAAI,uEAAwB,MAA5B,IAAI,EAAyB,YAAY,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC,yFAEuB,YAA0B;IAChD,MAAM,EAAE,8BAA8B,EAAE,gBAAgB,EAAE,GAAG,YAAY,CAAC;IAE1E,MAAM,aAAa,GAAiC,EAAE,CAAC;IACvD,MAAM,YAAY,GAAc,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAC/C,8BAA8B,CAC/B,EAAE,CAAC;QACF,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,YAAY,GAAG,UAAU,cAAc,EAAa,CAAC;QAE3D,MAAM,kBAAkB,GACtB,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;QACtD,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,SAAS;QACX,CAAC;QAED,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC;QAC/C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,eAAe,CAAC,CAAC;QAEnD,MAAM,MAAM,GACV,QAAQ,EAAE,MAAM,IAAK,SAA2B,CAAC;QAEnD,aAAa,CAAC,YAAY,CAAC,GAAG;YAC5B,OAAO,EAAE,YAAY;YACrB,MAAM;YACN,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,eAAe;SAChB,CAAC;QAEF,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnD,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,GAAG,CAAC,uBAAuB,EAAE;QAC3B,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC;QAC5C,YAAY;KACb,CAAC,CAAC;IAEH,0BAA0B;IAC1B,MAAM,cAAc,GAAG,CAAC,GAAG,uBAAA,IAAI,mCAAc,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5C,MAAM,UAAU,GACd,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM;QAC7C,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAExD,wEAAwE;IACxE,4EAA4E;IAC5E,wFAAwF;IACxF,uBAAA,IAAI,gCAAkB,aAAa,MAAA,CAAC;IACpC,uBAAA,IAAI,+BAAiB,YAAY,MAAA,CAAC;IAClC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC;IAEvC,IAAI,UAAU,EAAE,CAAC;QACf,uBAAA,IAAI,4CAAuB,MAA3B,IAAI,EAAwB,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC,mEAEY,OAAgB;IAC3B,MAAM,MAAM,GAAG,uBAAA,IAAI,oCAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,WAAW,GAAG,uBAAA,IAAI,oCAAe,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,uBAAA,IAAI,gCAAW,CAAC,IAAI,CACxC,wCAAwC,EACxC,WAAW,CAAC,eAAe,CAC5B,CAAC;QACF,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC9D,uBAAA,IAAI,oCAAe,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAE/C,OAAO,YAAY,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,kCAAkC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,qFAQqB,UAAkB;IACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,UAAU,cAAc,EAAa,CAAC;IAE3D,MAAM,YAAY,GAAG,uBAAA,IAAI,4DAAa,MAAjB,IAAI,EAAc,YAAY,CAAC,CAAC;IAErD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,mCAAmC,UAAU,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,MAAoC,EAAmB,EAAE;YACpE,OAAO,YAAY,CAAC,IAAI,CAAC;gBACvB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB,CAAC,CAAC;QACL,CAAC;QACD,UAAU,EAAE,KAAK,EAAE,OAAe,EAAmC,EAAE;YACrE,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACvD,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;IAGC,uBAAA,IAAI,oCAAe,CAAC,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;GAMG;AACH,KAAK,6CACH,OAAgB,EAChB,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,uBAAA,IAAI,4DAAa,MAAjB,IAAI,EAAc,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,kEAAkE;QAClE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;YACjC,EAAE,EAAE,YAAY;YAChB,IAAI,EAAE,YAAY;SACnB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;YACvD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,iFA0jBmB,OAAgB;IAClC,OAAO,CACL,uBAAA,IAAI,6CAAwB,MAA5B,IAAI,EAAyB,OAAO,CAAC;QACrC,GAAG,OAAO,UAAU,YAAY,EAAE,CACnC,CAAC;AACJ,CAAC;IASC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,uBAAA,IAAI,gCAAW,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,wCAAwC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAuBH,MAAM,UAAU,mBAAmB,CACjC,OAA6B;IAE7B,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport { toHex } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n NetworkState,\n NetworkStatus,\n} from '@metamask/network-controller';\nimport type {\n TransactionControllerIncomingTransactionsReceivedEvent,\n TransactionControllerTransactionConfirmedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport {\n isStrictHexString,\n isCaipChainId,\n parseCaipAssetType,\n parseCaipChainId,\n} from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type {\n AssetsControllerGetStateAction,\n AssetsControllerMessenger,\n} from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n AssetMetadata,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\nimport { normalizeAssetId } from '../utils';\nimport { ZERO_ADDRESS } from '../utils/constants';\nimport { isNativeAsset } from '../utils/isNativeAsset';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport {\n BalanceFetcher,\n MulticallClient,\n TokenDetector,\n TokensApiClient,\n} from './evm-rpc-services';\nimport type {\n BalancePollingInput,\n DetectionPollingInput,\n} from './evm-rpc-services';\nimport type {\n Address,\n AssetFetchEntry,\n Provider as RpcProvider,\n BalanceFetchResult,\n TokenDetectionResult,\n} from './evm-rpc-services/types';\n\nconst CONTROLLER_NAME = 'RpcDataSource';\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\nconst DEFAULT_DETECTION_INTERVAL = 180_000; // 3 minutes\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// Allowed actions that RpcDataSource can call\nexport type RpcDataSourceAllowedActions =\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | AssetsControllerGetStateAction;\n\n// Allowed events that RpcDataSource can subscribe to\nexport type RpcDataSourceAllowedEvents =\n | NetworkControllerStateChangeEvent\n | TransactionControllerTransactionConfirmedEvent\n | TransactionControllerIncomingTransactionsReceivedEvent;\n\n/** Network status for each chain */\nexport type ChainStatus = {\n chainId: ChainId;\n status: NetworkStatus;\n name: string;\n nativeCurrency: string;\n /** Network client ID for getting the provider */\n networkClientId: string;\n};\n\n/** RpcDataSource is stateless */\nexport type RpcDataSourceState = Record<never, never>;\n\n/** Optional configuration for RpcDataSource when the controller instantiates it. */\nexport type RpcDataSourceConfig = {\n balanceInterval?: number;\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n timeout?: number;\n};\n\nexport type RpcDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Resolves CAIP-2 chain ID to CAIP-19 native asset ID from the cached native asset map. */\n getNativeAssetForChain?: (chainId: ChainId) => Caip19AssetId | undefined;\n /** Request timeout in ms */\n timeout?: number;\n /** Balance polling interval in ms (default: 30s) */\n balanceInterval?: number;\n /** Token detection polling interval in ms (default: 180s / 3 min) */\n detectionInterval?: number;\n /** Function returning whether token detection is enabled (avoids stale value) */\n tokenDetectionEnabled?: () => boolean;\n /** Function returning whether external services are allowed (avoids stale value; default: () => true) */\n useExternalService?: () => boolean;\n /** Function returning whether onboarding is complete. When false, fetch and subscribe are no-ops. Defaults to () => true. */\n isOnboarded?: () => boolean;\n};\n\n/**\n * Subscription data stored for each active subscription.\n */\ntype SubscriptionData = {\n /** Polling tokens from BalanceFetcher */\n balancePollingTokens: string[];\n /** Polling tokens from TokenDetector */\n detectionPollingTokens: string[];\n /** Chain IDs being polled */\n chains: ChainId[];\n /** Accounts being polled */\n accounts: InternalAccount[];\n /** Callback to report asset updates to the controller */\n onAssetsUpdate: (\n response: DataResponse,\n request?: DataRequest,\n ) => void | Promise<void>;\n};\n\n/**\n * Convert CAIP chain ID or hex chain ID to hex chain ID.\n *\n * @param chainId - CAIP chain ID or hex chain ID.\n * @returns Hex chain ID.\n */\nexport const caipChainIdToHex = (chainId: string): Hex => {\n if (isStrictHexString(chainId)) {\n return chainId;\n }\n\n if (isCaipChainId(chainId)) {\n return toHex(parseCaipChainId(chainId).reference);\n }\n\n throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');\n};\n\n/**\n * Data source for fetching balances via RPC calls.\n *\n * Orchestrates polling through BalanceFetcher and TokenDetector,\n * each of which handle their own polling intervals.\n *\n * Communicates with AssetsController via Messenger:\n *\n * Actions:\n * - RpcDataSource:getActiveChains\n * - RpcDataSource:fetch\n * - RpcDataSource:subscribe\n * - RpcDataSource:unsubscribe\n *\n * Events:\n * - RpcDataSource:activeChainsUpdated\n * - RpcDataSource:assetsUpdated\n */\nexport class RpcDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n DataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #getNativeAssetForChain: (\n chainId: ChainId,\n ) => Caip19AssetId | undefined;\n\n readonly #timeout: number;\n\n readonly #tokenDetectionEnabled: () => boolean;\n\n readonly #useExternalService: () => boolean;\n\n readonly #isOnboarded: () => boolean;\n\n /** Currently active chains */\n #activeChains: ChainId[] = [];\n\n /** Network status for each active chain */\n #chainStatuses: Record<ChainId, ChainStatus> = {};\n\n /** Cache of Web3Provider instances by chainId */\n readonly #providerCache: Map<ChainId, Web3Provider> = new Map();\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<string, SubscriptionData> = new Map();\n\n #unsubscribeTransactionConfirmed: (() => void) | undefined = undefined;\n\n #unsubscribeIncomingTransactions: (() => void) | undefined = undefined;\n\n // Rpc-datasource components\n readonly #multicallClient: MulticallClient;\n\n readonly #balanceFetcher: BalanceFetcher;\n\n readonly #tokenDetector: TokenDetector;\n\n constructor(options: RpcDataSourceOptions) {\n super(CONTROLLER_NAME, { activeChains: [] });\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#getNativeAssetForChain =\n options.getNativeAssetForChain ?? ((): undefined => undefined);\n this.#timeout = options.timeout ?? 10_000;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#useExternalService =\n options.useExternalService ?? ((): boolean => true);\n this.#isOnboarded = options.isOnboarded ?? ((): boolean => true);\n\n const balanceInterval = options.balanceInterval ?? DEFAULT_BALANCE_INTERVAL;\n const detectionInterval =\n options.detectionInterval ?? DEFAULT_DETECTION_INTERVAL;\n\n log('Initializing RpcDataSource', {\n timeout: this.#timeout,\n balanceInterval,\n detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n });\n\n // Initialize MulticallClient with a provider getter\n this.#multicallClient = new MulticallClient((hexChainId: string) => {\n return this.#getMulticallProvider(hexChainId);\n });\n\n // Create messenger adapters for BalanceFetcher and TokenDetector\n const balanceFetcherMessenger = {\n call: (\n _action: 'AssetsController:getState',\n ): {\n assetsBalance: Record<string, Record<string, { amount: string }>>;\n } => {\n const state = this.#messenger.call('AssetsController:getState');\n return {\n assetsBalance: (state.assetsBalance ?? {}) as Record<\n string,\n Record<string, { amount: string }>\n >,\n };\n },\n };\n\n // Initialize BalanceFetcher with polling interval\n this.#balanceFetcher = new BalanceFetcher(\n this.#multicallClient,\n balanceFetcherMessenger,\n { pollingInterval: balanceInterval },\n );\n // Polling controller awaits this callback; rejections must not become unhandled.\n this.#balanceFetcher.setOnBalanceUpdate(async (result) => {\n try {\n await this.#handleBalanceUpdate(result);\n } catch (error) {\n log('Balance update handler failed', { error });\n }\n });\n\n // Initialize TokenDetector with polling interval\n const tokensApiClient = new TokensApiClient();\n this.#tokenDetector = new TokenDetector(\n this.#multicallClient,\n tokensApiClient,\n {\n pollingInterval: detectionInterval,\n tokenDetectionEnabled: this.#tokenDetectionEnabled,\n useExternalService: this.#useExternalService,\n },\n );\n // Sync throw in the detector would reject the poll tick if uncaught.\n this.#tokenDetector.setOnDetectionUpdate((result) => {\n try {\n this.#handleDetectionUpdate(result);\n } catch (error) {\n log('Detection update handler failed', { error });\n }\n });\n\n this.#subscribeToNetworkController();\n this.#subscribeToTransactionEvents();\n this.#initializeFromNetworkController();\n }\n\n /**\n * Convert a raw balance to human-readable format using decimals.\n *\n * @param rawBalance - The raw balance string.\n * @param decimals - The number of decimals for the token.\n * @returns The human-readable balance string.\n */\n #convertToHumanReadable(rawBalance: string, decimals: number): string {\n const rawAmount = new BigNumberJS(rawBalance);\n const divisor = new BigNumberJS(10).pow(decimals);\n return rawAmount.dividedBy(divisor).toFixed();\n }\n\n /**\n * Collect metadata for a list of balance entries.\n * For native tokens, generates metadata from chain status.\n * For ERC20 tokens, looks up from existing state or token list.\n *\n * @param balances - Array of balance entries with assetId.\n * @param chainId - The CAIP-2 chain ID.\n * @returns Record of asset metadata keyed by asset ID.\n */\n #collectMetadataForBalances(\n balances: { assetId: Caip19AssetId }[],\n chainId: ChainId,\n ): Record<Caip19AssetId, AssetMetadata> {\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n for (const balance of balances) {\n const isNative = isNativeAsset(balance.assetId);\n if (isNative) {\n const chainStatus = this.#chainStatuses[chainId];\n\n if (chainStatus) {\n assetsInfo[balance.assetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n } else {\n // For ERC20 tokens, use existing metadata from state if available.\n // Unknown ERC-20s are omitted until TokenDataSource enriches them.\n const existingMeta = existingMetadata[balance.assetId];\n if (existingMeta) {\n assetsInfo[balance.assetId] = existingMeta;\n }\n }\n }\n\n return assetsInfo;\n }\n\n /**\n * Handle balance update from BalanceFetcher.\n *\n * @param result - The balance fetch result.\n */\n async #handleBalanceUpdate(result: BalanceFetchResult): Promise<void> {\n const newBalances: Record<string, { amount: string }> = {};\n\n // Convert hex chain ID to CAIP-2 format\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n\n // Normalize asset IDs from BalanceFetcher (lowercase) to checksummed form\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const assetsInfo = this.#collectMetadataForBalances(\n normalizedBalances,\n caipChainId,\n );\n\n // Convert balances to human-readable format.\n // Resolution: state metadata → pipeline metadata; skip if decimals unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n const decimals = stateMetadata?.decimals ?? pipelineMetadata?.decimals;\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n assetsInfo,\n updateMode: 'merge',\n };\n\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance'],\n };\n\n log('Balance update response', {\n accountId: result.accountId,\n newBalanceCount: Object.keys(newBalances).length,\n });\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update assets', { error });\n });\n }\n }\n\n /**\n * Handle detection update from TokenDetector.\n *\n * @param result - The token detection result.\n */\n #handleDetectionUpdate(result: TokenDetectionResult): void {\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n });\n\n // Build new metadata from detected assets\n const newMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n if (result.detectedAssets.length > 0) {\n for (const asset of result.detectedAssets) {\n // Only include if we have metadata (symbol and decimals at minimum)\n if (asset.symbol && asset.decimals !== undefined) {\n newMetadata[asset.assetId] = {\n type: 'erc20',\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n }\n\n // Build new balances from detected tokens\n const newBalances: Record<string, { amount: string }> = {};\n if (result.detectedBalances.length > 0) {\n for (const balance of result.detectedBalances) {\n // Get decimals from the detected asset metadata\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n newBalances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n }\n\n // Only send new data to AssetsController - it handles merging atomically\n // to avoid race conditions when concurrent updates occur for the same account\n const response: DataResponse = {\n detectedAssets: {\n [result.accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsInfo: newMetadata,\n assetsBalance: {\n [result.accountId]: newBalances,\n },\n updateMode: 'merge',\n };\n\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n const request: DataRequest = {\n accountsWithSupportedChains: [],\n chainIds: [caipChainId],\n dataTypes: ['balance', 'metadata', 'price'],\n };\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response, request)?.catch((error) => {\n log('Failed to update detected assets', { error });\n });\n }\n }\n\n #subscribeToNetworkController(): void {\n this.#messenger.subscribe(\n 'NetworkController:stateChange',\n (networkState: NetworkState) => {\n log('NetworkController state changed');\n this.#clearProviderCache();\n this.#updateFromNetworkState(networkState);\n },\n );\n }\n\n #subscribeToTransactionEvents(): void {\n const unsubConfirmed = this.#messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n this.#onTransactionConfirmed.bind(this),\n );\n this.#unsubscribeTransactionConfirmed =\n typeof unsubConfirmed === 'function' ? unsubConfirmed : undefined;\n\n const unsubIncoming = this.#messenger.subscribe(\n 'TransactionController:incomingTransactionsReceived',\n this.#onIncomingTransactions.bind(this),\n );\n this.#unsubscribeIncomingTransactions =\n typeof unsubIncoming === 'function' ? unsubIncoming : undefined;\n }\n\n #onTransactionConfirmed(payload: TransactionMeta): void {\n const hexChainId = payload?.chainId;\n if (!hexChainId) {\n return;\n }\n const caipChainId = `eip155:${parseInt(hexChainId, 16)}` as ChainId;\n this.#refreshBalanceForChains([caipChainId]).catch((error) => {\n log('Failed to refresh balance after transaction confirmed', { error });\n });\n }\n\n #onIncomingTransactions(payload: TransactionMeta[]): void {\n const chainIds = Array.from(\n new Set(\n (payload ?? [])\n .map((item) => item?.chainId)\n .filter((id): id is Hex => Boolean(id)),\n ),\n );\n const caipChainIds = chainIds.map(\n (hexChainId) => `eip155:${parseInt(hexChainId, 16)}` as ChainId,\n );\n const toRefresh =\n caipChainIds.length > 0 ? caipChainIds : [...this.#activeChains];\n this.#refreshBalanceForChains(toRefresh).catch((error) => {\n log('Failed to refresh balance after incoming transactions', { error });\n });\n }\n\n /**\n * Fetch balances for the given chains across all active subscriptions and\n * push updates to the controller.\n *\n * @param chainIds - CAIP-2 chain IDs to refresh.\n */\n async #refreshBalanceForChains(chainIds: ChainId[]): Promise<void> {\n const chainIdsSet = new Set(chainIds);\n const chainsToFetch = chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n if (chainsToFetch.length === 0) {\n return;\n }\n\n for (const subscription of this.#activeSubscriptions.values()) {\n const subscriptionChains = subscription.chains.filter((chainId) =>\n chainIdsSet.has(chainId),\n );\n if (subscriptionChains.length === 0) {\n continue;\n }\n\n const request: DataRequest = {\n accountsWithSupportedChains: subscription.accounts.map((account) => ({\n account,\n supportedChains: subscriptionChains,\n })),\n chainIds: subscriptionChains,\n dataTypes: ['balance'],\n };\n\n try {\n const response = await this.fetch(request);\n if (\n response.assetsBalance &&\n Object.keys(response.assetsBalance).length > 0\n ) {\n subscription.onAssetsUpdate(response)?.catch((error) => {\n log('Failed to report balance update after transaction', {\n error,\n });\n });\n }\n } catch (error) {\n log('Failed to fetch balance after transaction', {\n chains: subscriptionChains,\n error,\n });\n }\n }\n }\n\n #initializeFromNetworkController(): void {\n log('Initializing from NetworkController');\n try {\n const networkState = this.#messenger.call('NetworkController:getState');\n this.#updateFromNetworkState(networkState);\n } catch (error) {\n log('Failed to initialize from NetworkController', error);\n }\n }\n\n #updateFromNetworkState(networkState: NetworkState): void {\n const { networkConfigurationsByChainId, networksMetadata } = networkState;\n\n const chainStatuses: Record<ChainId, ChainStatus> = {};\n const activeChains: ChainId[] = [];\n\n for (const [hexChainId, config] of Object.entries(\n networkConfigurationsByChainId,\n )) {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const defaultRpcEndpoint =\n config.rpcEndpoints[config.defaultRpcEndpointIndex];\n if (!defaultRpcEndpoint) {\n continue;\n }\n\n const { networkClientId } = defaultRpcEndpoint;\n const metadata = networksMetadata[networkClientId];\n\n const status: NetworkStatus =\n metadata?.status ?? ('unknown' as NetworkStatus);\n\n chainStatuses[caip2ChainId] = {\n chainId: caip2ChainId,\n status,\n name: config.name,\n nativeCurrency: config.nativeCurrency,\n networkClientId,\n };\n\n if (status === 'available' || status === 'unknown') {\n activeChains.push(caip2ChainId);\n }\n }\n\n log('Network state updated', {\n configuredChains: Object.keys(chainStatuses),\n activeChains,\n });\n\n // Check if chains changed\n const previousChains = [...this.#activeChains];\n const previousSet = new Set(previousChains);\n const hasChanges =\n previousChains.length !== activeChains.length ||\n activeChains.some((chain) => !previousSet.has(chain));\n\n // Update internal state and data source state before notifying, so that\n // when the controller handles the callback and calls getActiveChainsSync(),\n // it receives the updated chains (same order as AbstractDataSource.updateActiveChains).\n this.#chainStatuses = chainStatuses;\n this.#activeChains = activeChains;\n this.state.activeChains = activeChains;\n\n if (hasChanges) {\n this.#onActiveChainsUpdated(this.getName(), activeChains, previousChains);\n }\n }\n\n #getProvider(chainId: ChainId): Web3Provider | undefined {\n const cached = this.#providerCache.get(chainId);\n if (cached) {\n return cached;\n }\n\n const chainStatus = this.#chainStatuses[chainId];\n if (!chainStatus) {\n return undefined;\n }\n\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n chainStatus.networkClientId,\n );\n if (!networkClient?.provider) {\n return undefined;\n }\n const web3Provider = new Web3Provider(networkClient.provider);\n this.#providerCache.set(chainId, web3Provider);\n\n return web3Provider;\n } catch (error) {\n log('Failed to get provider for chain', { chainId, error });\n return undefined;\n }\n }\n\n /**\n * Get provider for MulticallClient using a hex chainId.\n *\n * @param hexChainId - The hex string representation of the chain id.\n * @returns An RpcProvider instance for the specified chain.\n */\n #getMulticallProvider(hexChainId: string): RpcProvider {\n const decimalChainId = parseInt(hexChainId, 16);\n const caip2ChainId = `eip155:${decimalChainId}` as ChainId;\n\n const web3Provider = this.#getProvider(caip2ChainId);\n\n if (!web3Provider) {\n throw new Error(`No provider available for chain ${hexChainId}`);\n }\n\n return {\n call: async (params: { to: string; data: string }): Promise<string> => {\n return web3Provider.call({\n to: params.to,\n data: params.data,\n });\n },\n getBalance: async (address: string): Promise<{ toString(): string }> => {\n const balance = await web3Provider.getBalance(address);\n return balance;\n },\n };\n }\n\n #clearProviderCache(): void {\n this.#providerCache.clear();\n }\n\n /**\n * Fetch the `decimals()` value from an ERC20 contract via RPC.\n *\n * @param chainId - CAIP-2 chain ID.\n * @param tokenAddress - The token contract address.\n * @returns The decimals value, or undefined if the call fails.\n */\n async #fetchDecimalsViaRpc(\n chainId: ChainId,\n tokenAddress: string,\n ): Promise<number | undefined> {\n try {\n const provider = this.#getProvider(chainId);\n if (!provider) {\n return undefined;\n }\n // ERC20 decimals() selector: keccak256(\"decimals()\") = 0x313ce567\n const result = await provider.call({\n to: tokenAddress,\n data: '0x313ce567',\n });\n if (!result || result === '0x') {\n return undefined;\n }\n const parsed = parseInt(result, 16);\n if (Number.isNaN(parsed) || parsed < 0 || parsed > 255) {\n return undefined;\n }\n return parsed;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Get the data source name.\n *\n * @returns The name of this data source.\n */\n /**\n * Get the status of all configured chains.\n *\n * @returns Record of chain statuses keyed by chain ID.\n */\n getChainStatuses(): Record<ChainId, ChainStatus> {\n return { ...this.#chainStatuses };\n }\n\n /**\n * Get the status of a specific chain.\n *\n * @param chainId - The chain ID to get status for.\n * @returns The chain status or undefined if not found.\n */\n getChainStatus(chainId: ChainId): ChainStatus | undefined {\n return this.#chainStatuses[chainId];\n }\n\n /**\n * Set the balance polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setBalancePollingInterval(interval: number): void {\n log('Setting balance polling interval', { interval });\n this.#balanceFetcher.setIntervalLength(interval);\n }\n\n /**\n * Get the current balance polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getBalancePollingInterval(): number | undefined {\n return this.#balanceFetcher.getIntervalLength();\n }\n\n /**\n * Set the token detection polling interval.\n *\n * @param interval - The polling interval in milliseconds.\n */\n setDetectionPollingInterval(interval: number): void {\n log('Setting detection polling interval', { interval });\n this.#tokenDetector.setIntervalLength(interval);\n }\n\n /**\n * Get the current token detection polling interval.\n *\n * @returns The polling interval in milliseconds, or undefined if not set.\n */\n getDetectionPollingInterval(): number | undefined {\n return this.#tokenDetector.getIntervalLength();\n }\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n if (!this.#isOnboarded()) {\n log('Skipping fetch - onboarding not complete');\n return {};\n }\n\n const response: DataResponse = {};\n\n const chainsToFetch = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n log('Fetch requested', {\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n requestedChains: request.chainIds,\n chainsToFetch,\n });\n\n if (chainsToFetch.length === 0) {\n log('No active chains to fetch');\n return response;\n }\n\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const failedChains: ChainId[] = [];\n\n // Fetch balances for each account and its supported chains (pre-computed in request)\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToFetch.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n // Build a single AssetFetchEntry[] for native + custom ERC-20s\n const nativeAssetId = this.#buildNativeAssetId(chainId);\n const assetsToFetch: AssetFetchEntry[] = [\n { assetId: nativeAssetId, address: ZERO_ADDRESS },\n ];\n\n if (request.customAssets) {\n const existingMetadata = this.#getExistingAssetsMetadata();\n\n for (const assetId of request.customAssets) {\n try {\n const parsed = parseCaipAssetType(assetId);\n const assetChainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n if (\n assetChainId === chainId &&\n parsed.assetNamespace === 'erc20'\n ) {\n const tokenAddress =\n parsed.assetReference.toLowerCase() as Address;\n const normalizedId = normalizeAssetId(assetId);\n const decimals = existingMetadata[normalizedId]?.decimals;\n\n assetsToFetch.push({\n assetId,\n address: tokenAddress,\n decimals,\n });\n }\n } catch {\n // Skip unparseable asset IDs\n }\n }\n }\n\n try {\n const result = await this.#balanceFetcher.fetchBalancesForAssets(\n hexChainId,\n accountId,\n address as Address,\n assetsToFetch,\n );\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset IDs from BalanceFetcher (which uses lowercase\n // addresses) to checksummed form so they match assetsInfo state keys.\n const normalizedBalances = result.balances.map((b) => ({\n ...b,\n assetId: normalizeAssetId(b.assetId),\n }));\n\n // Collect metadata for all balances\n const balanceMetadata = this.#collectMetadataForBalances(\n normalizedBalances,\n chainId,\n );\n Object.assign(assetsInfo, balanceMetadata);\n\n // Convert balances to human-readable format using decimals from\n // assetsInfo state (which includes pendingMetadata from addCustomAsset).\n // Resolution: state → pipeline metadata → RPC `decimals()`; omit balance if still unknown.\n const existingMetadata = this.#getExistingAssetsMetadata();\n for (const balance of normalizedBalances) {\n const stateMetadata = existingMetadata[balance.assetId];\n const pipelineMetadata = assetsInfo[balance.assetId];\n let decimals: number | undefined =\n stateMetadata?.decimals ?? pipelineMetadata?.decimals;\n\n if (decimals === undefined) {\n const parsed = parseCaipAssetType(balance.assetId);\n if (parsed.assetNamespace === 'erc20') {\n decimals = await this.#fetchDecimalsViaRpc(\n chainId,\n parsed.assetReference,\n );\n }\n }\n\n if (decimals === undefined) {\n continue;\n }\n\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n decimals,\n );\n\n assetsBalance[accountId][balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n } catch (error) {\n log('Failed to fetch balance', { address, chainId, error });\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n assetsBalance[accountId][nativeAssetId] = { amount: '0' };\n\n // Even on error, include native token metadata\n const chainStatus = this.#chainStatuses[chainId];\n if (chainStatus) {\n assetsInfo[nativeAssetId] = {\n type: 'native',\n symbol: chainStatus.nativeCurrency,\n name: chainStatus.nativeCurrency,\n decimals: 18,\n };\n }\n\n if (!failedChains.includes(chainId)) {\n failedChains.push(chainId);\n }\n }\n }\n }\n\n if (failedChains.length > 0) {\n log('Fetch PARTIAL - some chains failed', {\n successChains: chainsToFetch.filter(\n (chain) => !failedChains.includes(chain),\n ),\n failedChains,\n });\n\n response.errors = {};\n for (const chainId of failedChains) {\n response.errors[chainId] = 'RPC fetch failed';\n }\n } else {\n log('Fetch SUCCESS', {\n chains: chainsToFetch,\n accountCount: Object.keys(assetsBalance).length,\n });\n }\n\n response.assetsBalance = assetsBalance;\n\n // Include metadata for native tokens if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n return response;\n }\n\n /**\n * Run token detection for an account on a chain.\n *\n * @param chainId - The chain ID to detect tokens on.\n * @param account - The account to detect tokens for.\n * @returns Promise resolving to a DataResponse with detected assets.\n */\n async detectTokens(\n chainId: ChainId,\n account: InternalAccount,\n ): Promise<DataResponse> {\n if (!this.#tokenDetectionEnabled() || !this.#useExternalService()) {\n return {};\n }\n\n const hexChainId = caipChainIdToHex(chainId);\n const { address, id: accountId } = account;\n\n log('Running token detection', { chainId, accountId });\n\n try {\n const result = await this.#tokenDetector.detectTokens(\n hexChainId,\n accountId,\n address as Address,\n {\n tokenDetectionEnabled: this.#tokenDetectionEnabled(),\n useExternalService: this.#useExternalService(),\n },\n );\n\n if (result.detectedAssets.length === 0) {\n log('No new tokens detected');\n return {};\n }\n\n log('Detected new tokens', {\n count: result.detectedAssets.length,\n chainId,\n accountId,\n });\n\n // Convert detected assets to DataResponse format\n const balances: Record<Caip19AssetId, AssetBalance> = {};\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n\n // Build metadata from detected assets\n for (const asset of result.detectedAssets) {\n if (asset.symbol && asset.decimals !== undefined) {\n assetsInfo[asset.assetId] = {\n type: 'erc20',\n symbol: asset.symbol,\n name: asset.name ?? asset.symbol,\n decimals: asset.decimals,\n image: asset.image,\n };\n }\n }\n\n // Add balances for detected tokens (converted to human-readable format)\n for (const balance of result.detectedBalances) {\n const detectedAsset = result.detectedAssets.find(\n (asset) => asset.assetId === balance.assetId,\n );\n if (detectedAsset?.decimals === undefined) {\n continue;\n }\n const humanReadableAmount = this.#convertToHumanReadable(\n balance.balance,\n detectedAsset.decimals,\n );\n\n balances[balance.assetId] = {\n amount: humanReadableAmount,\n };\n }\n\n const response: DataResponse = {\n detectedAssets: {\n [accountId]: result.detectedAssets.map((asset) => asset.assetId),\n },\n assetsBalance: {\n [accountId]: balances,\n },\n };\n\n // Include metadata if we have any\n if (Object.keys(assetsInfo).length > 0) {\n response.assetsInfo = assetsInfo;\n }\n\n return response;\n } catch (error) {\n log('Token detection failed', { chainId, accountId, error });\n return {};\n }\n }\n\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n );\n\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n log('Middleware fetching', {\n chains: supportedChains,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n });\n\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] ??= {};\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n\n if (response.assetsInfo) {\n context.response.assetsInfo ??= {};\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n\n return next({\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n });\n }\n\n return next(context);\n };\n }\n\n /**\n * Subscribe to updates for the given request.\n * Starts polling through BalanceFetcher and TokenDetector.\n *\n * @param subscriptionRequest - The subscription request details.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n if (!this.#isOnboarded()) {\n log('Skipping subscribe - onboarding not complete');\n return;\n }\n\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Use request.chainIds when activeChains is not yet populated (e.g. before\n // NetworkController state has been applied) so polling can start.\n const chainsToSubscribe =\n this.#activeChains.length > 0\n ? request.chainIds.filter((chainId) =>\n this.#activeChains.includes(chainId),\n )\n : request.chainIds;\n\n log('Subscribe requested', {\n subscriptionId,\n isUpdate,\n accounts: request.accountsWithSupportedChains.map((a) => a.account.id),\n chainsToSubscribe,\n activeChainsFallback: this.#activeChains.length === 0,\n });\n\n if (chainsToSubscribe.length === 0) {\n log('No active chains to subscribe');\n return;\n }\n\n // Handle subscription update - restart polling for new chains\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n log('Updating existing subscription - restarting polling', {\n subscriptionId,\n existingChains: existing.chains,\n newChains: chainsToSubscribe,\n });\n // Don't return early - continue to unsubscribe and restart polling\n }\n }\n\n // Clean up existing subscription (stops old polling)\n await this.unsubscribe(subscriptionId);\n // Start polling through BalanceFetcher and TokenDetector\n const balancePollingTokens: string[] = [];\n const detectionPollingTokens: string[] = [];\n\n for (const {\n account,\n supportedChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToSubscribe.filter((chain) =>\n supportedChains.includes(chain),\n );\n if (chainsForAccount.length === 0) {\n continue;\n }\n\n const { address, id: accountId } = account;\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n // Start balance polling\n const balanceInput: BalancePollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n };\n const balanceToken = this.#balanceFetcher.startPolling(balanceInput);\n balancePollingTokens.push(balanceToken);\n\n // Start detection polling if enabled and external services allowed\n if (this.#tokenDetectionEnabled() && this.#useExternalService()) {\n const detectionInput: DetectionPollingInput = {\n chainId: hexChainId,\n accountId,\n accountAddress: address as Address,\n };\n const detectionToken =\n this.#tokenDetector.startPolling(detectionInput);\n detectionPollingTokens.push(detectionToken);\n }\n }\n }\n\n // Store subscription data\n const accounts = request.accountsWithSupportedChains.map(\n (entry) => entry.account,\n );\n this.#activeSubscriptions.set(subscriptionId, {\n balancePollingTokens,\n detectionPollingTokens,\n chains: chainsToSubscribe,\n accounts,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n log('Subscription SUCCESS', {\n subscriptionId,\n chains: chainsToSubscribe,\n balancePollingCount: balancePollingTokens.length,\n detectionPollingCount: detectionPollingTokens.length,\n });\n }\n\n /**\n * Unsubscribe from updates and stop polling.\n *\n * @param subscriptionId - The subscription ID to unsubscribe.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n // Stop balance polling\n for (const token of subscription.balancePollingTokens) {\n this.#balanceFetcher.stopPollingByPollingToken(token);\n }\n\n // Stop detection polling\n for (const token of subscription.detectionPollingTokens) {\n this.#tokenDetector.stopPollingByPollingToken(token);\n }\n\n this.#activeSubscriptions.delete(subscriptionId);\n log('Unsubscribed and stopped polling', { subscriptionId });\n }\n }\n\n /**\n * Build the native asset ID for a given chain using the cached native asset\n * map (injected via constructor callback). Falls back to the ERC20 zero-address\n * format when the chain has no known native asset mapping.\n *\n * @param chainId - The CAIP-2 chain ID (e.g., \"eip155:1\")\n * @returns The CAIP-19 native asset ID (e.g., \"eip155:1/slip44:60\")\n */\n #buildNativeAssetId(chainId: ChainId): Caip19AssetId {\n return (\n this.#getNativeAssetForChain(chainId) ??\n `${chainId}/erc20:${ZERO_ADDRESS}`\n );\n }\n\n /**\n * Get existing assets metadata from AssetsController state.\n * Used to include metadata for ERC20 tokens when returning balance updates.\n *\n * @returns Record of asset IDs to their metadata.\n */\n #getExistingAssetsMetadata(): Record<Caip19AssetId, AssetMetadata> {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n return state.assetsInfo ?? {};\n } catch (error) {\n log('Failed to get existing assets metadata', { error });\n return {};\n }\n }\n\n /**\n * Destroy the data source and clean up resources.\n */\n destroy(): void {\n log('Destroying RpcDataSource');\n\n this.#unsubscribeTransactionConfirmed?.();\n this.#unsubscribeIncomingTransactions?.();\n\n // Stop all polling\n this.#balanceFetcher.stopAllPolling();\n this.#tokenDetector.stopAllPolling();\n\n // Clear subscriptions\n this.#activeSubscriptions.clear();\n\n // Clear caches\n this.#providerCache.clear();\n }\n}\n\nexport function createRpcDataSource(\n options: RpcDataSourceOptions,\n): RpcDataSource {\n return new RpcDataSource(options);\n}\n"]}
@@ -18,6 +18,7 @@ const phishing_controller_1 = require("@metamask/phishing-controller");
18
18
  const utils_1 = require("@metamask/utils");
19
19
  const logger_1 = require("../logger.cjs");
20
20
  const types_1 = require("../types.cjs");
21
+ const isNativeAsset_1 = require("../utils/isNativeAsset.cjs");
21
22
  const evm_rpc_services_1 = require("./evm-rpc-services/index.cjs");
22
23
  // ============================================================================
23
24
  // CONSTANTS
@@ -58,7 +59,7 @@ var CaipAssetNamespace;
58
59
  function transformV3AssetResponseToMetadata(assetId, assetData) {
59
60
  const parsed = (0, utils_1.parseCaipAssetType)(assetId);
60
61
  let tokenType = 'erc20';
61
- if (parsed.assetNamespace === 'slip44') {
62
+ if ((0, isNativeAsset_1.isNativeAsset)(assetId)) {
62
63
  tokenType = 'native';
63
64
  }
64
65
  else if (parsed.assetNamespace === 'spl') {
@@ -196,16 +197,17 @@ class TokenDataSource {
196
197
  const evmErc20Ids = [];
197
198
  const nonEvmTokenIds = [];
198
199
  for (const assetData of metadataResponse) {
199
- const { assetNamespace, chain } = (0, utils_1.parseCaipAssetType)(assetData.assetId);
200
- if (assetNamespace === CaipAssetNamespace.Slip44) {
200
+ const assetId = assetData.assetId;
201
+ const { assetNamespace, chain } = (0, utils_1.parseCaipAssetType)(assetId);
202
+ if ((0, isNativeAsset_1.isNativeAsset)(assetId)) {
201
203
  // Native assets are always kept — no filtering.
202
204
  }
203
205
  else if (assetNamespace === CaipAssetNamespace.Erc20 &&
204
206
  chain.namespace === utils_1.KnownCaipNamespace.Eip155) {
205
- evmErc20Ids.push(assetData.assetId);
207
+ evmErc20Ids.push(assetId);
206
208
  }
207
209
  else if (assetNamespace === CaipAssetNamespace.Token) {
208
- nonEvmTokenIds.push(assetData.assetId);
210
+ nonEvmTokenIds.push(assetId);
209
211
  }
210
212
  }
211
213
  // EVM: require minimum occurrence count to suppress low-signal tokens.
@@ -243,7 +245,7 @@ class TokenDataSource {
243
245
  continue;
244
246
  }
245
247
  const caipAssetId = assetData.assetId;
246
- response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(assetData.assetId, assetData);
248
+ response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(caipAssetId, assetData);
247
249
  }
248
250
  if (filteredOutAssets.size > 0) {
249
251
  if (response.assetsBalance) {
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V3AssetResponse } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { KnownCaipNamespace, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipAssetType } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetMetadata,\n Middleware,\n FungibleAssetMetadata,\n} from '../types';\nimport {\n isStakingContractAssetId,\n reduceInBatchesSerially,\n} from './evm-rpc-services';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'TokenDataSource';\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n/** Max asset IDs per tokens API request. */\nconst TOKENS_API_BATCH_SIZE = 50;\n\n/** Max tokens per PhishingController:bulkScanTokens request (see PhishingController). */\nconst BULK_SCAN_BATCH_SIZE = 100;\n\n/**\n * Minimum number of aggregator occurrences required for an EVM ERC-20 token to\n * pass the spam filter. Non-EVM tokens are filtered via Blockaid bulk scan instead.\n */\nconst MIN_TOKEN_OCCURRENCES = 3;\n\n/** CAIP-19 `assetNamespace` segments used across filtering logic. */\nenum CaipAssetNamespace {\n Slip44 = 'slip44',\n Erc20 = 'erc20',\n Token = 'token',\n}\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type TokenDataSourceOptions = {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n getNativeAssetIds: () => string[];\n};\n\n/**\n * Messenger actions `TokenDataSource` may invoke (via {@link AssetsControllerMessenger}).\n * Not re-exported from the package public `index` (repo ESLint); import from this module when\n * typing a messenger in the same package or tests.\n */\nexport type TokenDataSourceAllowedActions =\n PhishingControllerBulkScanTokensAction;\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Transform V3 API response to FungibleAssetMetadata for state storage.\n *\n * Mapping:\n * - assetId → used to derive `type` (native/erc20/spl)\n * - iconUrl → image\n * - All other fields map directly\n *\n * @param assetId - CAIP-19 asset ID used to derive token type.\n * @param assetData - V3 API response data.\n * @returns FungibleAssetMetadata for state storage.\n */\nfunction transformV3AssetResponseToMetadata(\n assetId: string,\n assetData: V3AssetResponse,\n): AssetMetadata {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n let tokenType: 'native' | 'erc20' | 'spl' = 'erc20';\n\n if (parsed.assetNamespace === 'slip44') {\n tokenType = 'native';\n } else if (parsed.assetNamespace === 'spl') {\n tokenType = 'spl';\n }\n\n const metadata: FungibleAssetMetadata = {\n // Type derived from assetId\n type: tokenType,\n // BaseAssetMetadata fields\n name: assetData.name,\n symbol: assetData.symbol,\n decimals: assetData.decimals,\n image: assetData.iconUrl,\n // Direct mapping fields\n coingeckoId: assetData.coingeckoId,\n occurrences: assetData.occurrences,\n aggregators: assetData.aggregators,\n labels: assetData.labels,\n erc20Permit: assetData.erc20Permit,\n fees: assetData.fees,\n honeypotStatus: assetData.honeypotStatus,\n storage: assetData.storage,\n isContractVerified: assetData.isContractVerified,\n description: assetData.description,\n };\n\n return metadata;\n}\n\n// ============================================================================\n// TOKEN DATA SOURCE\n// ============================================================================\n\n/**\n * TokenDataSource enriches responses with token metadata from the Tokens API.\n *\n * This middleware-based data source:\n * - Checks detected assets for missing metadata/images\n * - Fetches metadata from Tokens API v3 for assets needing enrichment\n * - Merges fetched metadata into the response\n *\n * Pass the same {@link AssetsControllerMessenger} as other data sources for Blockaid\n * token scans.\n */\nexport class TokenDataSource {\n readonly name = CONTROLLER_NAME;\n\n getName(): string {\n return this.name;\n }\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n readonly #getNativeAssetIds: () => string[];\n\n /** Shared controller messenger — used for `PhishingController:bulkScanTokens`. */\n readonly #messenger: AssetsControllerMessenger;\n\n constructor(\n messenger: AssetsControllerMessenger,\n options: TokenDataSourceOptions,\n ) {\n this.#messenger = messenger;\n this.#apiClient = options.queryApiClient;\n this.#getNativeAssetIds = options.getNativeAssetIds;\n }\n\n /**\n * Gets the supported networks from the API.\n * Caching is handled by ApiPlatformClient.\n *\n * @returns Set of supported chain IDs in CAIP format\n */\n async #getSupportedNetworks(): Promise<Set<string>> {\n try {\n // Use v2/supportedNetworks which returns CAIP chain IDs\n // ApiPlatformClient handles caching\n const response =\n await this.#apiClient.tokens.fetchTokenV2SupportedNetworks();\n\n // Combine full and partial support networks\n const allNetworks = [...response.fullSupport, ...response.partialSupport];\n\n return new Set(allNetworks);\n } catch (error) {\n log('Failed to fetch supported networks', { error });\n return new Set();\n }\n }\n\n /**\n * Filters asset IDs to only include those from supported networks.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @param supportedNetworks - Set of supported chain IDs\n * @returns Array of asset IDs from supported networks\n */\n #filterAssetsByNetwork(\n assetIds: string[],\n supportedNetworks: Set<string>,\n ): string[] {\n return assetIds.filter((assetId) => {\n try {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n // chainId is in format \"eip155:1\" or \"tron:728126428\"\n // parsed.chain has namespace and reference properties\n const chainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n return supportedNetworks.has(chainId);\n } catch {\n // If we can't parse the asset ID, filter it out\n return false;\n }\n });\n }\n\n /**\n * Filters non-EVM fungible `token` assets flagged as malicious by Blockaid\n * via `PhishingController:bulkScanTokens`. Only the `token` namespace (e.g.\n * Solana mints) is scanned; native (`slip44`) and EVM assets are not handled\n * here (EVM uses occurrence-count filtering instead). Fails open on error.\n *\n * @param assets - CAIP-19 asset IDs to filter (non-EVM only).\n * @returns Asset IDs with malicious tokens removed.\n */\n async #filterBlockaidSpamTokens(assets: string[]): Promise<string[]> {\n if (assets.length === 0) {\n return assets;\n }\n\n const tokensByChain: Record<string, { asset: string; address: string }[]> =\n {};\n\n for (const asset of assets) {\n try {\n const { assetNamespace, assetReference, chain } = parseCaipAssetType(\n asset as CaipAssetType,\n );\n\n if (assetNamespace === CaipAssetNamespace.Token) {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n } catch {\n // Malformed or unsupported for bulk scan — keep asset (fail open)\n }\n }\n\n if (Object.keys(tokensByChain).length === 0) {\n return assets;\n }\n\n const rejectedAssets = new Set<string>();\n\n try {\n for (const [chainId, tokenEntries] of Object.entries(tokensByChain)) {\n const addresses = tokenEntries.map((entry) => entry.address);\n const batches: string[][] = [];\n for (let i = 0; i < addresses.length; i += BULK_SCAN_BATCH_SIZE) {\n batches.push(addresses.slice(i, i + BULK_SCAN_BATCH_SIZE));\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.#messenger.call('PhishingController:bulkScanTokens', {\n chainId,\n tokens: batch,\n }),\n ),\n );\n\n const scanResponse: BulkTokenScanResponse = {};\n for (const result of batchResults) {\n if (result.status === 'fulfilled') {\n Object.assign(scanResponse, result.value);\n }\n }\n\n for (const entry of tokenEntries) {\n const result = scanResponse[entry.address];\n if (result?.result_type === TokenScanResultType.Malicious) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n } catch (error) {\n log('Blockaid bulk token scan failed; keeping all tokens', { error });\n return assets;\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * Get the middleware for enriching responses with token metadata.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches metadata for detected assets (assets without metadata)\n * 3. Enriches the response with fetched metadata\n * 4. Calls next() at the end to continue the middleware chain\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['metadata'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n const { assetsInfo: stateMetadata, customAssets } = ctx.getAssetsState();\n const assetIdsNeedingMetadata = new Set<string>();\n\n // Custom assets are user-imported — exempt from spam filtering.\n const customAssetIds = new Set<string>(\n Object.values(customAssets ?? {}).flat(),\n );\n\n // Always include native asset IDs from NetworkEnablementController\n for (const nativeAssetId of this.#getNativeAssetIds()) {\n assetIdsNeedingMetadata.add(nativeAssetId);\n }\n\n // Also fetch metadata for detected assets that are missing it\n if (response.detectedAssets) {\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n // Skip if response already has metadata with image\n const responseMetadata = response.assetsInfo?.[assetId];\n if (responseMetadata?.image) {\n continue;\n }\n\n // Skip if state already has metadata with image\n const existingMetadata = stateMetadata[assetId];\n if (existingMetadata?.image) {\n continue;\n }\n\n // Skip staking contracts; we use built-in metadata and do not fetch from the tokens API\n if (isStakingContractAssetId(assetId)) {\n continue;\n }\n\n assetIdsNeedingMetadata.add(assetId);\n }\n }\n }\n\n if (assetIdsNeedingMetadata.size === 0) {\n return next(ctx);\n }\n\n // Filter asset IDs to only include supported networks\n const supportedNetworks = await this.#getSupportedNetworks();\n const supportedAssetIds = this.#filterAssetsByNetwork(\n [...assetIdsNeedingMetadata],\n supportedNetworks,\n );\n\n if (supportedAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const fetchOptions = {\n includeIconUrl: true,\n includeMarketData: true,\n includeMetadata: true,\n includeLabels: true,\n includeRwaData: true,\n includeAggregators: true,\n includeOccurrences: true,\n };\n\n const metadataResponse = await reduceInBatchesSerially<\n string,\n V3AssetResponse[]\n >({\n values: supportedAssetIds,\n batchSize: TOKENS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const batchResponse = await this.#apiClient.tokens.fetchV3Assets(\n batch,\n fetchOptions,\n );\n return [...(workingResult as V3AssetResponse[]), ...batchResponse];\n },\n initialResult: [],\n });\n\n // Split assets by chain type: EVM uses occurrence-count filtering;\n // non-EVM non-native uses Blockaid; native (slip44) is always allowed.\n const occurrencesByAssetId = new Map(\n metadataResponse.map((a) => [a.assetId, a.occurrences]),\n );\n\n const evmErc20Ids: string[] = [];\n const nonEvmTokenIds: string[] = [];\n\n for (const assetData of metadataResponse) {\n const { assetNamespace, chain } = parseCaipAssetType(\n assetData.assetId as CaipAssetType,\n );\n if (assetNamespace === CaipAssetNamespace.Slip44) {\n // Native assets are always kept — no filtering.\n } else if (\n assetNamespace === CaipAssetNamespace.Erc20 &&\n chain.namespace === KnownCaipNamespace.Eip155\n ) {\n evmErc20Ids.push(assetData.assetId);\n } else if (assetNamespace === CaipAssetNamespace.Token) {\n nonEvmTokenIds.push(assetData.assetId);\n }\n }\n\n // EVM: require minimum occurrence count to suppress low-signal tokens.\n // Tokens with no occurrence data (undefined) are treated the same as\n // zero occurrences and filtered out.\n // Custom assets (user-imported) bypass the occurrence filter.\n const allowedEvmIds = new Set(\n evmErc20Ids.filter(\n (id) =>\n customAssetIds.has(id) ||\n (occurrencesByAssetId.get(id) ?? 0) >= MIN_TOKEN_OCCURRENCES,\n ),\n );\n\n // Non-EVM: Blockaid bulk scan.\n // Custom assets (user-imported) bypass Blockaid filtering.\n const nonEvmToScan = nonEvmTokenIds.filter(\n (id) => !customAssetIds.has(id),\n );\n const allowedNonEvmIds = new Set([\n ...nonEvmTokenIds.filter((id) => customAssetIds.has(id)),\n ...(await this.#filterBlockaidSpamTokens(nonEvmToScan)),\n ]);\n\n // Start with every asset the API returned; only remove those that\n // fail their respective filter (EVM occurrences / non-EVM Blockaid).\n // Native (slip44) and unrecognised namespaces are kept (fail open).\n const allowedAssetIds = new Set(metadataResponse.map((a) => a.assetId));\n\n for (const id of evmErc20Ids) {\n if (!allowedEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n for (const id of nonEvmTokenIds) {\n if (!allowedNonEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n\n response.assetsInfo ??= {};\n\n const filteredOutAssets = new Set<string>();\n\n for (const assetData of metadataResponse) {\n if (!allowedAssetIds.has(assetData.assetId)) {\n filteredOutAssets.add(assetData.assetId);\n continue;\n }\n\n const caipAssetId = assetData.assetId as Caip19AssetId;\n response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(\n assetData.assetId,\n assetData,\n );\n }\n\n if (filteredOutAssets.size > 0) {\n if (response.assetsBalance) {\n for (const accountBalances of Object.values(\n response.assetsBalance,\n )) {\n for (const assetId of filteredOutAssets) {\n delete (accountBalances as Record<string, unknown>)[assetId];\n }\n }\n }\n\n if (response.detectedAssets) {\n for (const [accountId, assetIds] of Object.entries(\n response.detectedAssets,\n )) {\n response.detectedAssets[accountId] = assetIds.filter(\n (id) => !filteredOutAssets.has(id),\n );\n }\n }\n }\n } catch (error) {\n log('Failed to fetch metadata', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n}\n"]}
1
+ {"version":3,"file":"TokenDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V3AssetResponse } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type {\n BulkTokenScanResponse,\n PhishingControllerBulkScanTokensAction,\n} from '@metamask/phishing-controller';\nimport { TokenScanResultType } from '@metamask/phishing-controller';\nimport { KnownCaipNamespace, parseCaipAssetType } from '@metamask/utils';\nimport type { CaipAssetType } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetMetadata,\n Middleware,\n FungibleAssetMetadata,\n} from '../types';\nimport { isNativeAsset } from '../utils/isNativeAsset';\nimport {\n isStakingContractAssetId,\n reduceInBatchesSerially,\n} from './evm-rpc-services';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'TokenDataSource';\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n/** Max asset IDs per tokens API request. */\nconst TOKENS_API_BATCH_SIZE = 50;\n\n/** Max tokens per PhishingController:bulkScanTokens request (see PhishingController). */\nconst BULK_SCAN_BATCH_SIZE = 100;\n\n/**\n * Minimum number of aggregator occurrences required for an EVM ERC-20 token to\n * pass the spam filter. Non-EVM tokens are filtered via Blockaid bulk scan instead.\n */\nconst MIN_TOKEN_OCCURRENCES = 3;\n\n/** CAIP-19 `assetNamespace` segments used across filtering logic. */\nenum CaipAssetNamespace {\n Slip44 = 'slip44',\n Erc20 = 'erc20',\n Token = 'token',\n}\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type TokenDataSourceOptions = {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n getNativeAssetIds: () => string[];\n};\n\n/**\n * Messenger actions `TokenDataSource` may invoke (via {@link AssetsControllerMessenger}).\n * Not re-exported from the package public `index` (repo ESLint); import from this module when\n * typing a messenger in the same package or tests.\n */\nexport type TokenDataSourceAllowedActions =\n PhishingControllerBulkScanTokensAction;\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Transform V3 API response to FungibleAssetMetadata for state storage.\n *\n * Mapping:\n * - assetId → used to derive `type` (native/erc20/spl)\n * - iconUrl → image\n * - All other fields map directly\n *\n * @param assetId - CAIP-19 asset ID used to derive token type.\n * @param assetData - V3 API response data.\n * @returns FungibleAssetMetadata for state storage.\n */\nfunction transformV3AssetResponseToMetadata(\n assetId: Caip19AssetId,\n assetData: V3AssetResponse,\n): AssetMetadata {\n const parsed = parseCaipAssetType(assetId);\n let tokenType: 'native' | 'erc20' | 'spl' = 'erc20';\n\n if (isNativeAsset(assetId)) {\n tokenType = 'native';\n } else if (parsed.assetNamespace === 'spl') {\n tokenType = 'spl';\n }\n\n const metadata: FungibleAssetMetadata = {\n // Type derived from assetId\n type: tokenType,\n // BaseAssetMetadata fields\n name: assetData.name,\n symbol: assetData.symbol,\n decimals: assetData.decimals,\n image: assetData.iconUrl,\n // Direct mapping fields\n coingeckoId: assetData.coingeckoId,\n occurrences: assetData.occurrences,\n aggregators: assetData.aggregators,\n labels: assetData.labels,\n erc20Permit: assetData.erc20Permit,\n fees: assetData.fees,\n honeypotStatus: assetData.honeypotStatus,\n storage: assetData.storage,\n isContractVerified: assetData.isContractVerified,\n description: assetData.description,\n };\n\n return metadata;\n}\n\n// ============================================================================\n// TOKEN DATA SOURCE\n// ============================================================================\n\n/**\n * TokenDataSource enriches responses with token metadata from the Tokens API.\n *\n * This middleware-based data source:\n * - Checks detected assets for missing metadata/images\n * - Fetches metadata from Tokens API v3 for assets needing enrichment\n * - Merges fetched metadata into the response\n *\n * Pass the same {@link AssetsControllerMessenger} as other data sources for Blockaid\n * token scans.\n */\nexport class TokenDataSource {\n readonly name = CONTROLLER_NAME;\n\n getName(): string {\n return this.name;\n }\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Returns CAIP-19 native asset IDs from NetworkEnablementController state */\n readonly #getNativeAssetIds: () => string[];\n\n /** Shared controller messenger — used for `PhishingController:bulkScanTokens`. */\n readonly #messenger: AssetsControllerMessenger;\n\n constructor(\n messenger: AssetsControllerMessenger,\n options: TokenDataSourceOptions,\n ) {\n this.#messenger = messenger;\n this.#apiClient = options.queryApiClient;\n this.#getNativeAssetIds = options.getNativeAssetIds;\n }\n\n /**\n * Gets the supported networks from the API.\n * Caching is handled by ApiPlatformClient.\n *\n * @returns Set of supported chain IDs in CAIP format\n */\n async #getSupportedNetworks(): Promise<Set<string>> {\n try {\n // Use v2/supportedNetworks which returns CAIP chain IDs\n // ApiPlatformClient handles caching\n const response =\n await this.#apiClient.tokens.fetchTokenV2SupportedNetworks();\n\n // Combine full and partial support networks\n const allNetworks = [...response.fullSupport, ...response.partialSupport];\n\n return new Set(allNetworks);\n } catch (error) {\n log('Failed to fetch supported networks', { error });\n return new Set();\n }\n }\n\n /**\n * Filters asset IDs to only include those from supported networks.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @param supportedNetworks - Set of supported chain IDs\n * @returns Array of asset IDs from supported networks\n */\n #filterAssetsByNetwork(\n assetIds: string[],\n supportedNetworks: Set<string>,\n ): string[] {\n return assetIds.filter((assetId) => {\n try {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n // chainId is in format \"eip155:1\" or \"tron:728126428\"\n // parsed.chain has namespace and reference properties\n const chainId = `${parsed.chain.namespace}:${parsed.chain.reference}`;\n return supportedNetworks.has(chainId);\n } catch {\n // If we can't parse the asset ID, filter it out\n return false;\n }\n });\n }\n\n /**\n * Filters non-EVM fungible `token` assets flagged as malicious by Blockaid\n * via `PhishingController:bulkScanTokens`. Only the `token` namespace (e.g.\n * Solana mints) is scanned; native (`slip44`) and EVM assets are not handled\n * here (EVM uses occurrence-count filtering instead). Fails open on error.\n *\n * @param assets - CAIP-19 asset IDs to filter (non-EVM only).\n * @returns Asset IDs with malicious tokens removed.\n */\n async #filterBlockaidSpamTokens(assets: string[]): Promise<string[]> {\n if (assets.length === 0) {\n return assets;\n }\n\n const tokensByChain: Record<string, { asset: string; address: string }[]> =\n {};\n\n for (const asset of assets) {\n try {\n const { assetNamespace, assetReference, chain } = parseCaipAssetType(\n asset as CaipAssetType,\n );\n\n if (assetNamespace === CaipAssetNamespace.Token) {\n const chainName = chain.namespace;\n if (!tokensByChain[chainName]) {\n tokensByChain[chainName] = [];\n }\n tokensByChain[chainName].push({ asset, address: assetReference });\n }\n } catch {\n // Malformed or unsupported for bulk scan — keep asset (fail open)\n }\n }\n\n if (Object.keys(tokensByChain).length === 0) {\n return assets;\n }\n\n const rejectedAssets = new Set<string>();\n\n try {\n for (const [chainId, tokenEntries] of Object.entries(tokensByChain)) {\n const addresses = tokenEntries.map((entry) => entry.address);\n const batches: string[][] = [];\n for (let i = 0; i < addresses.length; i += BULK_SCAN_BATCH_SIZE) {\n batches.push(addresses.slice(i, i + BULK_SCAN_BATCH_SIZE));\n }\n\n const batchResults = await Promise.allSettled(\n batches.map((batch) =>\n this.#messenger.call('PhishingController:bulkScanTokens', {\n chainId,\n tokens: batch,\n }),\n ),\n );\n\n const scanResponse: BulkTokenScanResponse = {};\n for (const result of batchResults) {\n if (result.status === 'fulfilled') {\n Object.assign(scanResponse, result.value);\n }\n }\n\n for (const entry of tokenEntries) {\n const result = scanResponse[entry.address];\n if (result?.result_type === TokenScanResultType.Malicious) {\n rejectedAssets.add(entry.asset);\n }\n }\n }\n } catch (error) {\n log('Blockaid bulk token scan failed; keeping all tokens', { error });\n return assets;\n }\n\n return assets.filter((asset) => !rejectedAssets.has(asset));\n }\n\n /**\n * Get the middleware for enriching responses with token metadata.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches metadata for detected assets (assets without metadata)\n * 3. Enriches the response with fetched metadata\n * 4. Calls next() at the end to continue the middleware chain\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['metadata'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n const { assetsInfo: stateMetadata, customAssets } = ctx.getAssetsState();\n const assetIdsNeedingMetadata = new Set<string>();\n\n // Custom assets are user-imported — exempt from spam filtering.\n const customAssetIds = new Set<string>(\n Object.values(customAssets ?? {}).flat(),\n );\n\n // Always include native asset IDs from NetworkEnablementController\n for (const nativeAssetId of this.#getNativeAssetIds()) {\n assetIdsNeedingMetadata.add(nativeAssetId);\n }\n\n // Also fetch metadata for detected assets that are missing it\n if (response.detectedAssets) {\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n // Skip if response already has metadata with image\n const responseMetadata = response.assetsInfo?.[assetId];\n if (responseMetadata?.image) {\n continue;\n }\n\n // Skip if state already has metadata with image\n const existingMetadata = stateMetadata[assetId];\n if (existingMetadata?.image) {\n continue;\n }\n\n // Skip staking contracts; we use built-in metadata and do not fetch from the tokens API\n if (isStakingContractAssetId(assetId)) {\n continue;\n }\n\n assetIdsNeedingMetadata.add(assetId);\n }\n }\n }\n\n if (assetIdsNeedingMetadata.size === 0) {\n return next(ctx);\n }\n\n // Filter asset IDs to only include supported networks\n const supportedNetworks = await this.#getSupportedNetworks();\n const supportedAssetIds = this.#filterAssetsByNetwork(\n [...assetIdsNeedingMetadata],\n supportedNetworks,\n );\n\n if (supportedAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const fetchOptions = {\n includeIconUrl: true,\n includeMarketData: true,\n includeMetadata: true,\n includeLabels: true,\n includeRwaData: true,\n includeAggregators: true,\n includeOccurrences: true,\n };\n\n const metadataResponse = await reduceInBatchesSerially<\n string,\n V3AssetResponse[]\n >({\n values: supportedAssetIds,\n batchSize: TOKENS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const batchResponse = await this.#apiClient.tokens.fetchV3Assets(\n batch,\n fetchOptions,\n );\n return [...(workingResult as V3AssetResponse[]), ...batchResponse];\n },\n initialResult: [],\n });\n\n // Split assets by chain type: EVM uses occurrence-count filtering;\n // non-EVM non-native uses Blockaid; native (slip44) is always allowed.\n const occurrencesByAssetId = new Map(\n metadataResponse.map((a) => [a.assetId, a.occurrences]),\n );\n\n const evmErc20Ids: string[] = [];\n const nonEvmTokenIds: string[] = [];\n\n for (const assetData of metadataResponse) {\n const assetId = assetData.assetId as Caip19AssetId;\n const { assetNamespace, chain } = parseCaipAssetType(assetId);\n if (isNativeAsset(assetId)) {\n // Native assets are always kept — no filtering.\n } else if (\n assetNamespace === CaipAssetNamespace.Erc20 &&\n chain.namespace === KnownCaipNamespace.Eip155\n ) {\n evmErc20Ids.push(assetId);\n } else if (assetNamespace === CaipAssetNamespace.Token) {\n nonEvmTokenIds.push(assetId);\n }\n }\n\n // EVM: require minimum occurrence count to suppress low-signal tokens.\n // Tokens with no occurrence data (undefined) are treated the same as\n // zero occurrences and filtered out.\n // Custom assets (user-imported) bypass the occurrence filter.\n const allowedEvmIds = new Set(\n evmErc20Ids.filter(\n (id) =>\n customAssetIds.has(id) ||\n (occurrencesByAssetId.get(id) ?? 0) >= MIN_TOKEN_OCCURRENCES,\n ),\n );\n\n // Non-EVM: Blockaid bulk scan.\n // Custom assets (user-imported) bypass Blockaid filtering.\n const nonEvmToScan = nonEvmTokenIds.filter(\n (id) => !customAssetIds.has(id),\n );\n const allowedNonEvmIds = new Set([\n ...nonEvmTokenIds.filter((id) => customAssetIds.has(id)),\n ...(await this.#filterBlockaidSpamTokens(nonEvmToScan)),\n ]);\n\n // Start with every asset the API returned; only remove those that\n // fail their respective filter (EVM occurrences / non-EVM Blockaid).\n // Native (slip44) and unrecognised namespaces are kept (fail open).\n const allowedAssetIds = new Set(metadataResponse.map((a) => a.assetId));\n\n for (const id of evmErc20Ids) {\n if (!allowedEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n for (const id of nonEvmTokenIds) {\n if (!allowedNonEvmIds.has(id)) {\n allowedAssetIds.delete(id);\n }\n }\n\n response.assetsInfo ??= {};\n\n const filteredOutAssets = new Set<string>();\n\n for (const assetData of metadataResponse) {\n if (!allowedAssetIds.has(assetData.assetId)) {\n filteredOutAssets.add(assetData.assetId);\n continue;\n }\n\n const caipAssetId = assetData.assetId as Caip19AssetId;\n response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(\n caipAssetId,\n assetData,\n );\n }\n\n if (filteredOutAssets.size > 0) {\n if (response.assetsBalance) {\n for (const accountBalances of Object.values(\n response.assetsBalance,\n )) {\n for (const assetId of filteredOutAssets) {\n delete (accountBalances as Record<string, unknown>)[assetId];\n }\n }\n }\n\n if (response.detectedAssets) {\n for (const [accountId, assetIds] of Object.entries(\n response.detectedAssets,\n )) {\n response.detectedAssets[accountId] = assetIds.filter(\n (id) => !filteredOutAssets.has(id),\n );\n }\n }\n }\n } catch (error) {\n log('Failed to fetch metadata', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AAqClB,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AA2DzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAcf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IAuIjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAkMjC;CACF"}
1
+ {"version":3,"file":"TokenDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AAsClB,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AA2DzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAcf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IAuIjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAiMjC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AAqClB,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AA2DzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAcf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IAuIjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAkMjC;CACF"}
1
+ {"version":3,"file":"TokenDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/TokenDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAEV,sCAAsC,EACvC,sCAAsC;AAKvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAGrE,OAAO,KAAK,EAGV,UAAU,EAEX,qBAAiB;AAsClB,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,8EAA8E;IAC9E,iBAAiB,EAAE,MAAM,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GACvC,sCAAsC,CAAC;AA2DzC;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;IAEhC,OAAO,IAAI,MAAM;gBAcf,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,sBAAsB;IAuIjC;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAiMjC;CACF"}
@@ -15,6 +15,7 @@ import { TokenScanResultType } from "@metamask/phishing-controller";
15
15
  import { KnownCaipNamespace, parseCaipAssetType } from "@metamask/utils";
16
16
  import { projectLogger, createModuleLogger } from "../logger.mjs";
17
17
  import { forDataTypes } from "../types.mjs";
18
+ import { isNativeAsset } from "../utils/isNativeAsset.mjs";
18
19
  import { isStakingContractAssetId, reduceInBatchesSerially } from "./evm-rpc-services/index.mjs";
19
20
  // ============================================================================
20
21
  // CONSTANTS
@@ -55,7 +56,7 @@ var CaipAssetNamespace;
55
56
  function transformV3AssetResponseToMetadata(assetId, assetData) {
56
57
  const parsed = parseCaipAssetType(assetId);
57
58
  let tokenType = 'erc20';
58
- if (parsed.assetNamespace === 'slip44') {
59
+ if (isNativeAsset(assetId)) {
59
60
  tokenType = 'native';
60
61
  }
61
62
  else if (parsed.assetNamespace === 'spl') {
@@ -193,16 +194,17 @@ export class TokenDataSource {
193
194
  const evmErc20Ids = [];
194
195
  const nonEvmTokenIds = [];
195
196
  for (const assetData of metadataResponse) {
196
- const { assetNamespace, chain } = parseCaipAssetType(assetData.assetId);
197
- if (assetNamespace === CaipAssetNamespace.Slip44) {
197
+ const assetId = assetData.assetId;
198
+ const { assetNamespace, chain } = parseCaipAssetType(assetId);
199
+ if (isNativeAsset(assetId)) {
198
200
  // Native assets are always kept — no filtering.
199
201
  }
200
202
  else if (assetNamespace === CaipAssetNamespace.Erc20 &&
201
203
  chain.namespace === KnownCaipNamespace.Eip155) {
202
- evmErc20Ids.push(assetData.assetId);
204
+ evmErc20Ids.push(assetId);
203
205
  }
204
206
  else if (assetNamespace === CaipAssetNamespace.Token) {
205
- nonEvmTokenIds.push(assetData.assetId);
207
+ nonEvmTokenIds.push(assetId);
206
208
  }
207
209
  }
208
210
  // EVM: require minimum occurrence count to suppress low-signal tokens.
@@ -240,7 +242,7 @@ export class TokenDataSource {
240
242
  continue;
241
243
  }
242
244
  const caipAssetId = assetData.assetId;
243
- response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(assetData.assetId, assetData);
245
+ response.assetsInfo[caipAssetId] = transformV3AssetResponseToMetadata(caipAssetId, assetData);
244
246
  }
245
247
  if (filteredOutAssets.size > 0) {
246
248
  if (response.assetsBalance) {