@metamask/assets-controllers 45.0.0 → 45.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -1
- package/dist/AccountTrackerController.d.cts +4 -4
- package/dist/AccountTrackerController.d.mts +4 -4
- package/dist/CurrencyRateController.d.cts +4 -4
- package/dist/CurrencyRateController.d.mts +4 -4
- package/dist/Standards/ERC20Standard.mjs +2 -4
- package/dist/Standards/ERC20Standard.mjs.map +1 -1
- package/dist/TokenBalancesController.d.cts +4 -4
- package/dist/TokenBalancesController.d.mts +4 -4
- package/dist/TokenDetectionController.cjs +3 -0
- package/dist/TokenDetectionController.cjs.map +1 -1
- package/dist/TokenDetectionController.d.cts +4 -4
- package/dist/TokenDetectionController.d.cts.map +1 -1
- package/dist/TokenDetectionController.d.mts +4 -4
- package/dist/TokenDetectionController.d.mts.map +1 -1
- package/dist/TokenDetectionController.mjs +3 -0
- package/dist/TokenDetectionController.mjs.map +1 -1
- package/dist/TokenListController.d.cts +4 -4
- package/dist/TokenListController.d.mts +4 -4
- package/dist/TokenRatesController.cjs +2 -2
- package/dist/TokenRatesController.cjs.map +1 -1
- package/dist/TokenRatesController.d.cts +4 -4
- package/dist/TokenRatesController.d.mts +4 -4
- package/dist/TokenRatesController.mjs +3 -3
- package/dist/TokenRatesController.mjs.map +1 -1
- package/dist/TokensController.cjs +6 -3
- package/dist/TokensController.cjs.map +1 -1
- package/dist/TokensController.d.cts.map +1 -1
- package/dist/TokensController.d.mts.map +1 -1
- package/dist/TokensController.mjs +6 -3
- package/dist/TokensController.mjs.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.cjs +19 -3
- package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.cts +8 -0
- package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.mts +8 -0
- package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
- package/dist/token-prices-service/codefi-v2.mjs +18 -4
- package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
- package/dist/token-prices-service/index.cjs +2 -1
- package/dist/token-prices-service/index.cjs.map +1 -1
- package/dist/token-prices-service/index.d.cts +1 -1
- package/dist/token-prices-service/index.d.cts.map +1 -1
- package/dist/token-prices-service/index.d.mts +1 -1
- package/dist/token-prices-service/index.d.mts.map +1 -1
- package/dist/token-prices-service/index.mjs +1 -1
- package/dist/token-prices-service/index.mjs.map +1 -1
- package/package.json +14 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenDetectionController.mjs","sourceRoot":"","sources":["../src/TokenDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerGetAccountAction,\n AccountsControllerSelectedEvmAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport contractMap from '@metamask/contract-metadata';\nimport {\n ASSET_TYPES,\n ChainId,\n ERC20,\n safelyExecute,\n isEqualCaseInsensitive,\n} from '@metamask/controller-utils';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetNetworkConfigurationByNetworkClientId,\n NetworkControllerGetStateAction,\n NetworkControllerNetworkDidChangeEvent,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n PreferencesControllerGetStateAction,\n PreferencesControllerStateChangeEvent,\n} from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { hexToNumber } from '@metamask/utils';\nimport { isEqual, mapValues, isObject, get } from 'lodash';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport { isTokenDetectionSupportedForNetwork } from './assetsUtil';\nimport {\n fetchMultiChainBalances,\n fetchSupportedNetworks,\n} from './multi-chain-accounts-service';\nimport type {\n GetTokenListState,\n TokenListMap,\n TokenListStateChange,\n TokensChainsCache,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\nimport type {\n TokensControllerAddDetectedTokensAction,\n TokensControllerGetStateAction,\n} from './TokensController';\n\nconst DEFAULT_INTERVAL = 180000;\n\ntype LegacyToken = {\n name: string;\n logo: `${string}.svg`;\n symbol: string;\n decimals: number;\n erc20?: boolean;\n erc721?: boolean;\n};\n\ntype TokenDetectionMap = {\n [P in keyof TokenListMap]: Omit<TokenListMap[P], 'occurrences'>;\n};\n\ntype NetworkClient = {\n chainId: Hex;\n networkClientId: string;\n};\n\nexport const STATIC_MAINNET_TOKEN_LIST = Object.entries<LegacyToken>(\n contractMap,\n).reduce<TokenDetectionMap>((acc, [base, contract]) => {\n const { logo, erc20, erc721, ...tokenMetadata } = contract;\n return {\n ...acc,\n [base.toLowerCase()]: {\n ...tokenMetadata,\n address: base.toLowerCase(),\n iconUrl: `images/contract/${logo}`,\n aggregators: [],\n },\n };\n}, {});\n\n/**\n * Function that takes a TokensChainsCache object and maps chainId with TokenListMap.\n * @param tokensChainsCache - TokensChainsCache input object\n * @returns returns the map of chainId with TokenListMap\n */\nexport function mapChainIdWithTokenListMap(\n tokensChainsCache: TokensChainsCache,\n) {\n return mapValues(tokensChainsCache, (value) => {\n if (isObject(value) && 'data' in value) {\n return get(value, ['data']);\n }\n return value;\n });\n}\n\nexport const controllerName = 'TokenDetectionController';\n\nexport type TokenDetectionState = Record<never, never>;\n\nexport type TokenDetectionControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenDetectionState\n>;\n\nexport type TokenDetectionControllerActions =\n TokenDetectionControllerGetStateAction;\n\nexport type AllowedActions =\n | AccountsControllerGetSelectedAccountAction\n | AccountsControllerGetAccountAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetNetworkConfigurationByNetworkClientId\n | NetworkControllerGetStateAction\n | GetTokenListState\n | KeyringControllerGetStateAction\n | PreferencesControllerGetStateAction\n | TokensControllerGetStateAction\n | TokensControllerAddDetectedTokensAction;\n\nexport type TokenDetectionControllerStateChangeEvent =\n ControllerStateChangeEvent<typeof controllerName, TokenDetectionState>;\n\nexport type TokenDetectionControllerEvents =\n TokenDetectionControllerStateChangeEvent;\n\nexport type AllowedEvents =\n | AccountsControllerSelectedEvmAccountChangeEvent\n | NetworkControllerNetworkDidChangeEvent\n | TokenListStateChange\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | PreferencesControllerStateChangeEvent;\n\nexport type TokenDetectionControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenDetectionControllerActions | AllowedActions,\n TokenDetectionControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/** The input to start polling for the {@link TokenDetectionController} */\ntype TokenDetectionPollingInput = {\n chainIds: Hex[];\n address: string;\n};\n\n/**\n * Controller that passively polls on a set interval for Tokens auto detection\n * @property intervalId - Polling interval used to fetch new token rates\n * @property selectedAddress - Vault selected address\n * @property networkClientId - The network client ID of the current selected network\n * @property disabled - Boolean to track if network requests are blocked\n * @property isUnlocked - Boolean to track if the keyring state is unlocked\n * @property isDetectionEnabledFromPreferences - Boolean to track if detection is enabled from PreferencesController\n * @property isDetectionEnabledForNetwork - Boolean to track if detected is enabled for current network\n */\nexport class TokenDetectionController extends StaticIntervalPollingController<TokenDetectionPollingInput>()<\n typeof controllerName,\n TokenDetectionState,\n TokenDetectionControllerMessenger\n> {\n #intervalId?: ReturnType<typeof setTimeout>;\n\n #selectedAccountId: string;\n\n #networkClientId: NetworkClientId;\n\n #tokensChainsCache: TokensChainsCache = {};\n\n #disabled: boolean;\n\n #isUnlocked: boolean;\n\n #isDetectionEnabledFromPreferences: boolean;\n\n #isDetectionEnabledForNetwork: boolean;\n\n readonly #getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n\n readonly #trackMetaMetricsEvent: (options: {\n event: string;\n category: string;\n properties: {\n tokens: string[];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: string;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: string;\n };\n }) => void;\n\n #accountsAPI = {\n isAccountsAPIEnabled: true,\n supportedNetworksCache: null as number[] | null,\n platform: '' as 'extension' | 'mobile',\n\n async getSupportedNetworks() {\n /* istanbul ignore next */\n if (!this.isAccountsAPIEnabled) {\n throw new Error('Accounts API Feature Switch is disabled');\n }\n\n /* istanbul ignore next */\n if (this.supportedNetworksCache) {\n return this.supportedNetworksCache;\n }\n\n const result = await fetchSupportedNetworks().catch(() => null);\n this.supportedNetworksCache = result;\n return result;\n },\n\n async getMultiNetworksBalances(\n address: string,\n chainIds: Hex[],\n supportedNetworks: number[] | null,\n ) {\n const chainIdNumbers = chainIds.map((chainId) => hexToNumber(chainId));\n\n if (\n !supportedNetworks ||\n !chainIdNumbers.every((id) => supportedNetworks.includes(id))\n ) {\n const supportedNetworksErrStr = (supportedNetworks ?? []).toString();\n throw new Error(\n `Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`,\n );\n }\n\n const result = await fetchMultiChainBalances(\n address,\n {\n networks: chainIdNumbers,\n },\n this.platform,\n );\n\n return result.balances;\n },\n };\n\n /**\n * Creates a TokenDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The controller messaging system.\n * @param options.disabled - If set to true, all network requests are blocked.\n * @param options.interval - Polling interval used to fetch new token rates\n * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.\n * @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.\n * @param options.useAccountsAPI - Feature Switch for using the accounts API when detecting tokens (default: true)\n * @param options.platform - Indicates whether the platform is extension or mobile\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n disabled = true,\n getBalancesInSingleCall,\n trackMetaMetricsEvent,\n messenger,\n useAccountsAPI = true,\n platform,\n }: {\n interval?: number;\n disabled?: boolean;\n getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n trackMetaMetricsEvent: (options: {\n event: string;\n category: string;\n properties: {\n tokens: string[];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: string;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: string;\n };\n }) => void;\n messenger: TokenDetectionControllerMessenger;\n useAccountsAPI?: boolean;\n platform: 'extension' | 'mobile';\n }) {\n super({\n name: controllerName,\n messenger,\n state: {},\n metadata: {},\n });\n\n this.#disabled = disabled;\n this.setIntervalLength(interval);\n\n this.#selectedAccountId = this.#getSelectedAccount().id;\n\n const { chainId, networkClientId } =\n this.#getCorrectChainIdAndNetworkClientId();\n this.#networkClientId = networkClientId;\n\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n\n this.#tokensChainsCache = tokensChainsCache;\n\n const { useTokenDetection: defaultUseTokenDetection } =\n this.messagingSystem.call('PreferencesController:getState');\n this.#isDetectionEnabledFromPreferences = defaultUseTokenDetection;\n this.#isDetectionEnabledForNetwork =\n isTokenDetectionSupportedForNetwork(chainId);\n\n this.#getBalancesInSingleCall = getBalancesInSingleCall;\n\n this.#trackMetaMetricsEvent = trackMetaMetricsEvent;\n\n const { isUnlocked } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n this.#isUnlocked = isUnlocked;\n\n this.#accountsAPI.isAccountsAPIEnabled = useAccountsAPI;\n this.#accountsAPI.platform = platform;\n\n this.#registerEventListeners();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system subscriptions to controller events.\n */\n #registerEventListeners() {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.messagingSystem.subscribe('KeyringController:unlock', async () => {\n this.#isUnlocked = true;\n await this.#restartTokenDetection();\n });\n\n this.messagingSystem.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#stopPolling();\n });\n\n this.messagingSystem.subscribe(\n 'TokenListController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ tokensChainsCache }) => {\n const isEqualValues = this.#compareTokensChainsCache(\n tokensChainsCache,\n this.#tokensChainsCache,\n );\n if (!isEqualValues) {\n await this.#restartTokenDetection();\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'PreferencesController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ useTokenDetection }) => {\n const selectedAccount = this.#getSelectedAccount();\n const isDetectionChangedFromPreferences =\n this.#isDetectionEnabledFromPreferences !== useTokenDetection;\n\n this.#isDetectionEnabledFromPreferences = useTokenDetection;\n\n if (isDetectionChangedFromPreferences) {\n await this.#restartTokenDetection({\n selectedAddress: selectedAccount.address,\n });\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:selectedEvmAccountChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (selectedAccount) => {\n const isSelectedAccountIdChanged =\n this.#selectedAccountId !== selectedAccount.id;\n if (isSelectedAccountIdChanged) {\n this.#selectedAccountId = selectedAccount.id;\n await this.#restartTokenDetection({\n selectedAddress: selectedAccount.address,\n });\n }\n },\n );\n }\n\n /**\n * Allows controller to make active and passive polling requests\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from making network calls\n */\n disable(): void {\n this.#disabled = true;\n }\n\n /**\n * Internal isActive state\n * @type {boolean}\n */\n get isActive(): boolean {\n return !this.#disabled && this.#isUnlocked;\n }\n\n /**\n * Start polling for detected tokens.\n */\n async start(): Promise<void> {\n this.enable();\n await this.#startPolling();\n }\n\n /**\n * Stop polling for detected tokens.\n */\n stop(): void {\n this.disable();\n this.#stopPolling();\n }\n\n #stopPolling(): void {\n if (this.#intervalId) {\n clearInterval(this.#intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n async #startPolling(): Promise<void> {\n if (!this.isActive) {\n return;\n }\n this.#stopPolling();\n await this.detectTokens();\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#intervalId = setInterval(async () => {\n await this.detectTokens();\n }, this.getIntervalLength());\n }\n\n /**\n * Compares current and previous tokensChainsCache object focusing only on the data object.\n * @param tokensChainsCache - current tokensChainsCache input object\n * @param previousTokensChainsCache - previous tokensChainsCache input object\n * @returns boolean indicating if the two objects are equal\n */\n\n #compareTokensChainsCache(\n tokensChainsCache: TokensChainsCache,\n previousTokensChainsCache: TokensChainsCache,\n ): boolean {\n const cleanPreviousTokensChainsCache = mapChainIdWithTokenListMap(\n previousTokensChainsCache,\n );\n const cleanTokensChainsCache =\n mapChainIdWithTokenListMap(tokensChainsCache);\n const isEqualValues = isEqual(\n cleanTokensChainsCache,\n cleanPreviousTokensChainsCache,\n );\n return isEqualValues;\n }\n\n #getCorrectNetworkClientIdByChainId(\n chainIds: Hex[] | undefined,\n ): { chainId: Hex; networkClientId: NetworkClientId }[] {\n const { networkConfigurationsByChainId, selectedNetworkClientId } =\n this.messagingSystem.call('NetworkController:getState');\n\n if (!chainIds) {\n const networkConfiguration = this.messagingSystem.call(\n 'NetworkController:getNetworkConfigurationByNetworkClientId',\n selectedNetworkClientId,\n );\n\n return [\n {\n chainId: networkConfiguration?.chainId ?? ChainId.mainnet,\n networkClientId: selectedNetworkClientId,\n },\n ];\n }\n\n return chainIds.map((chainId) => {\n const configuration = networkConfigurationsByChainId[chainId];\n return {\n chainId,\n networkClientId:\n configuration.rpcEndpoints[configuration.defaultRpcEndpointIndex]\n .networkClientId,\n };\n });\n }\n\n #getCorrectChainIdAndNetworkClientId() {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return {\n chainId,\n networkClientId: selectedNetworkClientId,\n };\n }\n\n async _executePoll({\n chainIds,\n address,\n }: TokenDetectionPollingInput): Promise<void> {\n if (!this.isActive) {\n return;\n }\n await this.detectTokens({\n chainIds,\n selectedAddress: address,\n });\n }\n\n /**\n * Restart token detection polling period and call detectNewTokens\n * in case of address change or user session initialization.\n *\n * @param options - Options for restart token detection.\n * @param options.selectedAddress - the selectedAddress against which to detect for token balances\n * @param options.chainIds - The chain IDs of the network client to use.\n */\n async #restartTokenDetection({\n selectedAddress,\n chainIds,\n }: {\n selectedAddress?: string;\n chainIds?: Hex[];\n } = {}): Promise<void> {\n await this.detectTokens({\n chainIds,\n selectedAddress,\n });\n this.setIntervalLength(DEFAULT_INTERVAL);\n }\n\n #getChainsToDetect(\n clientNetworks: NetworkClient[],\n supportedNetworks: number[] | null | undefined,\n ) {\n const chainsToDetectUsingAccountAPI: Hex[] = [];\n const chainsToDetectUsingRpc: NetworkClient[] = [];\n\n clientNetworks.forEach(({ chainId, networkClientId }) => {\n if (supportedNetworks?.includes(hexToNumber(chainId))) {\n chainsToDetectUsingAccountAPI.push(chainId);\n } else {\n chainsToDetectUsingRpc.push({ chainId, networkClientId });\n }\n });\n\n return { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI };\n }\n\n async #attemptAccountAPIDetection(\n chainsToDetectUsingAccountAPI: Hex[],\n addressToDetect: string,\n supportedNetworks: number[] | null,\n ) {\n return await this.#addDetectedTokensViaAPI({\n chainIds: chainsToDetectUsingAccountAPI,\n selectedAddress: addressToDetect,\n supportedNetworks,\n });\n }\n\n #addChainsToRpcDetection(\n chainsToDetectUsingRpc: NetworkClient[],\n chainsToDetectUsingAccountAPI: Hex[],\n clientNetworks: NetworkClient[],\n ): void {\n chainsToDetectUsingAccountAPI.forEach((chainId) => {\n const networkEntry = clientNetworks.find(\n (network) => network.chainId === chainId,\n );\n if (networkEntry) {\n chainsToDetectUsingRpc.push({\n chainId: networkEntry.chainId,\n networkClientId: networkEntry.networkClientId,\n });\n }\n });\n }\n\n #shouldDetectTokens(chainId: Hex): boolean {\n if (!isTokenDetectionSupportedForNetwork(chainId)) {\n return false;\n }\n if (\n !this.#isDetectionEnabledFromPreferences &&\n chainId !== ChainId.mainnet\n ) {\n return false;\n }\n\n const isMainnetDetectionInactive =\n !this.#isDetectionEnabledFromPreferences && chainId === ChainId.mainnet;\n if (isMainnetDetectionInactive) {\n this.#tokensChainsCache = this.#getConvertedStaticMainnetTokenList();\n } else {\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n this.#tokensChainsCache = tokensChainsCache ?? {};\n }\n\n return true;\n }\n\n async #detectTokensUsingRpc(\n chainsToDetectUsingRpc: NetworkClient[],\n addressToDetect: string,\n ): Promise<void> {\n for (const { chainId, networkClientId } of chainsToDetectUsingRpc) {\n if (!this.#shouldDetectTokens(chainId)) {\n continue;\n }\n\n const tokenCandidateSlices = this.#getSlicesOfTokensToDetect({\n chainId,\n selectedAddress: addressToDetect,\n });\n const tokenDetectionPromises = tokenCandidateSlices.map((tokensSlice) =>\n this.#addDetectedTokens({\n tokensSlice,\n selectedAddress: addressToDetect,\n networkClientId,\n chainId,\n }),\n );\n\n await Promise.all(tokenDetectionPromises);\n }\n }\n\n /**\n * For each token in the token list provided by the TokenListController, checks the token's balance for the selected account address on the active network.\n * On mainnet, if token detection is disabled in preferences, ERC20 token auto detection will be triggered for each contract address in the legacy token list from the @metamask/contract-metadata repo.\n *\n * @param options - Options for token detection.\n * @param options.chainIds - The chain IDs of the network client to use.\n * @param options.selectedAddress - the selectedAddress against which to detect for token balances.\n */\n async detectTokens({\n chainIds,\n selectedAddress,\n }: {\n chainIds?: Hex[];\n selectedAddress?: string;\n } = {}): Promise<void> {\n if (!this.isActive) {\n return;\n }\n\n const addressToDetect = selectedAddress ?? this.#getSelectedAddress();\n const clientNetworks = this.#getCorrectNetworkClientIdByChainId(chainIds);\n\n let supportedNetworks;\n if (this.#accountsAPI.isAccountsAPIEnabled) {\n supportedNetworks = await this.#accountsAPI.getSupportedNetworks();\n }\n const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } =\n this.#getChainsToDetect(clientNetworks, supportedNetworks);\n\n // Try detecting tokens via Account API first if conditions allow\n if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {\n const apiResult = await this.#attemptAccountAPIDetection(\n chainsToDetectUsingAccountAPI,\n addressToDetect,\n supportedNetworks,\n );\n\n // If the account API call failed, have those chains fall back to RPC detection\n if (apiResult?.result === 'failed') {\n this.#addChainsToRpcDetection(\n chainsToDetectUsingRpc,\n chainsToDetectUsingAccountAPI,\n clientNetworks,\n );\n }\n }\n\n // Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc\n if (chainsToDetectUsingRpc.length > 0) {\n await this.#detectTokensUsingRpc(chainsToDetectUsingRpc, addressToDetect);\n }\n }\n\n #getSlicesOfTokensToDetect({\n chainId,\n selectedAddress,\n }: {\n chainId: Hex;\n selectedAddress: string;\n }): string[][] {\n const { allTokens, allDetectedTokens, allIgnoredTokens } =\n this.messagingSystem.call('TokensController:getState');\n const [tokensAddresses, detectedTokensAddresses, ignoredTokensAddresses] = [\n allTokens,\n allDetectedTokens,\n allIgnoredTokens,\n ].map((tokens) =>\n (tokens[chainId]?.[selectedAddress] ?? []).map((value) =>\n typeof value === 'string' ? value : value.address,\n ),\n );\n\n const tokensToDetect: string[] = [];\n for (const tokenAddress of Object.keys(\n this.#tokensChainsCache?.[chainId]?.data || {},\n )) {\n if (\n [\n tokensAddresses,\n detectedTokensAddresses,\n ignoredTokensAddresses,\n ].every(\n (addresses) =>\n !addresses.find((address) =>\n isEqualCaseInsensitive(address, tokenAddress),\n ),\n )\n ) {\n tokensToDetect.push(tokenAddress);\n }\n }\n\n const slicesOfTokensToDetect = [];\n for (let i = 0, size = 1000; i < tokensToDetect.length; i += size) {\n slicesOfTokensToDetect.push(tokensToDetect.slice(i, i + size));\n }\n\n return slicesOfTokensToDetect;\n }\n\n #getConvertedStaticMainnetTokenList(): TokensChainsCache {\n const data: TokenListMap = Object.entries(STATIC_MAINNET_TOKEN_LIST).reduce(\n (acc, [key, value]) => ({\n ...acc,\n [key]: {\n name: value.name,\n symbol: value.symbol,\n decimals: value.decimals,\n address: value.address,\n aggregators: [],\n iconUrl: value?.iconUrl,\n },\n }),\n {},\n );\n return {\n '0x1': {\n data,\n timestamp: 0,\n },\n };\n }\n\n /**\n * This adds detected tokens from the Accounts API, avoiding the multi-call RPC calls for balances\n * @param options - method arguments\n * @param options.selectedAddress - address to check against\n * @param options.chainIds - array of chainIds to check tokens for\n * @param options.supportedNetworks - array of chainIds to check tokens for\n * @returns a success or failed object\n */\n async #addDetectedTokensViaAPI({\n selectedAddress,\n chainIds,\n supportedNetworks,\n }: {\n selectedAddress: string;\n chainIds: Hex[];\n supportedNetworks: number[] | null;\n }) {\n return await safelyExecute(async () => {\n // Fetch balances for multiple chain IDs at once\n const tokenBalancesByChain = await this.#accountsAPI\n .getMultiNetworksBalances(selectedAddress, chainIds, supportedNetworks)\n .catch(() => null);\n\n if (tokenBalancesByChain === null) {\n return { result: 'failed' } as const;\n }\n\n // Process each chain ID individually\n for (const chainId of chainIds) {\n const isTokenDetectionInactiveInMainnet =\n !this.#isDetectionEnabledFromPreferences &&\n chainId === ChainId.mainnet;\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n this.#tokensChainsCache = isTokenDetectionInactiveInMainnet\n ? this.#getConvertedStaticMainnetTokenList()\n : tokensChainsCache ?? {};\n\n // Generate token candidates based on chainId and selectedAddress\n const tokenCandidateSlices = this.#getSlicesOfTokensToDetect({\n chainId,\n selectedAddress,\n });\n\n // Filter balances for the current chainId\n const tokenBalances = tokenBalancesByChain.filter(\n (balance) => balance.chainId === hexToNumber(chainId),\n );\n\n if (!tokenBalances || tokenBalances.length === 0) {\n continue;\n }\n\n // Use helper function to filter tokens with balance for this chainId\n const { tokensWithBalance, eventTokensDetails } =\n this.#filterAndBuildTokensWithBalance(\n tokenCandidateSlices,\n tokenBalances,\n chainId,\n );\n\n if (tokensWithBalance.length) {\n this.#trackMetaMetricsEvent({\n event: 'Token Detected',\n category: 'Wallet',\n properties: {\n tokens: eventTokensDetails,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: ERC20,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: ASSET_TYPES.TOKEN,\n },\n });\n\n await this.messagingSystem.call(\n 'TokensController:addDetectedTokens',\n tokensWithBalance,\n {\n selectedAddress,\n chainId,\n },\n );\n }\n }\n\n return { result: 'success' } as const;\n });\n }\n\n /**\n * Helper function to filter and build token data for detected tokens\n * @param options.tokenCandidateSlices - these are tokens we know a user does not have (by checking the tokens controller).\n * We will use these these token candidates to determine if a token found from the API is valid to be added on the users wallet.\n * It will also prevent us to adding tokens a user already has\n * @param tokenBalances - Tokens balances fetched from API\n * @param chainId - The chain ID being processed\n * @returns an object containing tokensWithBalance and eventTokensDetails arrays\n */\n\n #filterAndBuildTokensWithBalance(\n tokenCandidateSlices: string[][],\n tokenBalances:\n | {\n object: string;\n type?: string;\n timestamp?: string;\n address: string;\n symbol: string;\n name: string;\n decimals: number;\n chainId: number;\n balance: string;\n }[]\n | null,\n chainId: Hex,\n ) {\n const tokensWithBalance: Token[] = [];\n const eventTokensDetails: string[] = [];\n\n const tokenCandidateSet = new Set<string>(tokenCandidateSlices.flat());\n\n tokenBalances?.forEach((token) => {\n const tokenAddress = token.address;\n\n // Make sure the token to add is in our candidate list\n if (!tokenCandidateSet.has(tokenAddress)) {\n return;\n }\n\n // Retrieve token data from cache to safely add it\n const tokenData = this.#tokensChainsCache[chainId]?.data[tokenAddress];\n\n // We need specific data from tokensChainsCache to correctly create a token\n // So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.\n if (!tokenData) {\n return;\n }\n\n const { decimals, symbol, aggregators, iconUrl, name } = tokenData;\n eventTokensDetails.push(`${symbol} - ${tokenAddress}`);\n tokensWithBalance.push({\n address: tokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n name,\n });\n });\n\n return { tokensWithBalance, eventTokensDetails };\n }\n\n async #addDetectedTokens({\n tokensSlice,\n selectedAddress,\n networkClientId,\n chainId,\n }: {\n tokensSlice: string[];\n selectedAddress: string;\n networkClientId: NetworkClientId;\n chainId: Hex;\n }): Promise<void> {\n await safelyExecute(async () => {\n const balances = await this.#getBalancesInSingleCall(\n selectedAddress,\n tokensSlice,\n networkClientId,\n );\n\n const tokensWithBalance: Token[] = [];\n const eventTokensDetails: string[] = [];\n for (const nonZeroTokenAddress of Object.keys(balances)) {\n const { decimals, symbol, aggregators, iconUrl, name } =\n this.#tokensChainsCache[chainId].data[nonZeroTokenAddress];\n eventTokensDetails.push(`${symbol} - ${nonZeroTokenAddress}`);\n tokensWithBalance.push({\n address: nonZeroTokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n name,\n });\n }\n\n if (tokensWithBalance.length) {\n this.#trackMetaMetricsEvent({\n event: 'Token Detected',\n category: 'Wallet',\n properties: {\n tokens: eventTokensDetails,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: ERC20,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: ASSET_TYPES.TOKEN,\n },\n });\n\n await this.messagingSystem.call(\n 'TokensController:addDetectedTokens',\n tokensWithBalance,\n {\n selectedAddress,\n chainId,\n },\n );\n }\n });\n }\n\n #getSelectedAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n #getSelectedAddress() {\n // If the address is not defined (or empty), we fallback to the currently selected account's address\n const account = this.messagingSystem.call(\n 'AccountsController:getAccount',\n this.#selectedAccountId,\n );\n return account?.address || '';\n }\n}\n\nexport default TokenDetectionController;\n"]}
|
|
1
|
+
{"version":3,"file":"TokenDetectionController.mjs","sourceRoot":"","sources":["../src/TokenDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerGetAccountAction,\n AccountsControllerSelectedEvmAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport contractMap from '@metamask/contract-metadata';\nimport {\n ASSET_TYPES,\n ChainId,\n ERC20,\n safelyExecute,\n isEqualCaseInsensitive,\n} from '@metamask/controller-utils';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetNetworkConfigurationByNetworkClientId,\n NetworkControllerGetStateAction,\n NetworkControllerNetworkDidChangeEvent,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n PreferencesControllerGetStateAction,\n PreferencesControllerStateChangeEvent,\n} from '@metamask/preferences-controller';\nimport type { Hex } from '@metamask/utils';\nimport { hexToNumber } from '@metamask/utils';\nimport { isEqual, mapValues, isObject, get } from 'lodash';\n\nimport type { AssetsContractController } from './AssetsContractController';\nimport { isTokenDetectionSupportedForNetwork } from './assetsUtil';\nimport {\n fetchMultiChainBalances,\n fetchSupportedNetworks,\n} from './multi-chain-accounts-service';\nimport type {\n GetTokenListState,\n TokenListMap,\n TokenListStateChange,\n TokensChainsCache,\n} from './TokenListController';\nimport type { Token } from './TokenRatesController';\nimport type {\n TokensControllerAddDetectedTokensAction,\n TokensControllerGetStateAction,\n} from './TokensController';\n\nconst DEFAULT_INTERVAL = 180000;\n\ntype LegacyToken = {\n name: string;\n logo: `${string}.svg`;\n symbol: string;\n decimals: number;\n erc20?: boolean;\n erc721?: boolean;\n};\n\ntype TokenDetectionMap = {\n [P in keyof TokenListMap]: Omit<TokenListMap[P], 'occurrences'>;\n};\n\ntype NetworkClient = {\n chainId: Hex;\n networkClientId: string;\n};\n\nexport const STATIC_MAINNET_TOKEN_LIST = Object.entries<LegacyToken>(\n contractMap,\n).reduce<TokenDetectionMap>((acc, [base, contract]) => {\n const { logo, erc20, erc721, ...tokenMetadata } = contract;\n return {\n ...acc,\n [base.toLowerCase()]: {\n ...tokenMetadata,\n address: base.toLowerCase(),\n iconUrl: `images/contract/${logo}`,\n aggregators: [],\n },\n };\n}, {});\n\n/**\n * Function that takes a TokensChainsCache object and maps chainId with TokenListMap.\n * @param tokensChainsCache - TokensChainsCache input object\n * @returns returns the map of chainId with TokenListMap\n */\nexport function mapChainIdWithTokenListMap(\n tokensChainsCache: TokensChainsCache,\n) {\n return mapValues(tokensChainsCache, (value) => {\n if (isObject(value) && 'data' in value) {\n return get(value, ['data']);\n }\n return value;\n });\n}\n\nexport const controllerName = 'TokenDetectionController';\n\nexport type TokenDetectionState = Record<never, never>;\n\nexport type TokenDetectionControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenDetectionState\n>;\n\nexport type TokenDetectionControllerActions =\n TokenDetectionControllerGetStateAction;\n\nexport type AllowedActions =\n | AccountsControllerGetSelectedAccountAction\n | AccountsControllerGetAccountAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetNetworkConfigurationByNetworkClientId\n | NetworkControllerGetStateAction\n | GetTokenListState\n | KeyringControllerGetStateAction\n | PreferencesControllerGetStateAction\n | TokensControllerGetStateAction\n | TokensControllerAddDetectedTokensAction;\n\nexport type TokenDetectionControllerStateChangeEvent =\n ControllerStateChangeEvent<typeof controllerName, TokenDetectionState>;\n\nexport type TokenDetectionControllerEvents =\n TokenDetectionControllerStateChangeEvent;\n\nexport type AllowedEvents =\n | AccountsControllerSelectedEvmAccountChangeEvent\n | NetworkControllerNetworkDidChangeEvent\n | TokenListStateChange\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | PreferencesControllerStateChangeEvent;\n\nexport type TokenDetectionControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenDetectionControllerActions | AllowedActions,\n TokenDetectionControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/** The input to start polling for the {@link TokenDetectionController} */\ntype TokenDetectionPollingInput = {\n chainIds: Hex[];\n address: string;\n};\n\n/**\n * Controller that passively polls on a set interval for Tokens auto detection\n * @property intervalId - Polling interval used to fetch new token rates\n * @property selectedAddress - Vault selected address\n * @property networkClientId - The network client ID of the current selected network\n * @property disabled - Boolean to track if network requests are blocked\n * @property isUnlocked - Boolean to track if the keyring state is unlocked\n * @property isDetectionEnabledFromPreferences - Boolean to track if detection is enabled from PreferencesController\n * @property isDetectionEnabledForNetwork - Boolean to track if detected is enabled for current network\n */\nexport class TokenDetectionController extends StaticIntervalPollingController<TokenDetectionPollingInput>()<\n typeof controllerName,\n TokenDetectionState,\n TokenDetectionControllerMessenger\n> {\n #intervalId?: ReturnType<typeof setTimeout>;\n\n #selectedAccountId: string;\n\n #networkClientId: NetworkClientId;\n\n #tokensChainsCache: TokensChainsCache = {};\n\n #disabled: boolean;\n\n #isUnlocked: boolean;\n\n #isDetectionEnabledFromPreferences: boolean;\n\n #isDetectionEnabledForNetwork: boolean;\n\n readonly #getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n\n readonly #trackMetaMetricsEvent: (options: {\n event: string;\n category: string;\n properties: {\n tokens: string[];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: string;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: string;\n };\n }) => void;\n\n #accountsAPI = {\n isAccountsAPIEnabled: true,\n supportedNetworksCache: null as number[] | null,\n platform: '' as 'extension' | 'mobile',\n\n async getSupportedNetworks() {\n /* istanbul ignore next */\n if (!this.isAccountsAPIEnabled) {\n throw new Error('Accounts API Feature Switch is disabled');\n }\n\n /* istanbul ignore next */\n if (this.supportedNetworksCache) {\n return this.supportedNetworksCache;\n }\n\n const result = await fetchSupportedNetworks().catch(() => null);\n this.supportedNetworksCache = result;\n return result;\n },\n\n async getMultiNetworksBalances(\n address: string,\n chainIds: Hex[],\n supportedNetworks: number[] | null,\n ) {\n const chainIdNumbers = chainIds.map((chainId) => hexToNumber(chainId));\n\n if (\n !supportedNetworks ||\n !chainIdNumbers.every((id) => supportedNetworks.includes(id))\n ) {\n const supportedNetworksErrStr = (supportedNetworks ?? []).toString();\n throw new Error(\n `Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`,\n );\n }\n\n const result = await fetchMultiChainBalances(\n address,\n {\n networks: chainIdNumbers,\n },\n this.platform,\n );\n\n return result.balances;\n },\n };\n\n /**\n * Creates a TokenDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The controller messaging system.\n * @param options.disabled - If set to true, all network requests are blocked.\n * @param options.interval - Polling interval used to fetch new token rates\n * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.\n * @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.\n * @param options.useAccountsAPI - Feature Switch for using the accounts API when detecting tokens (default: true)\n * @param options.platform - Indicates whether the platform is extension or mobile\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n disabled = true,\n getBalancesInSingleCall,\n trackMetaMetricsEvent,\n messenger,\n useAccountsAPI = true,\n platform,\n }: {\n interval?: number;\n disabled?: boolean;\n getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n trackMetaMetricsEvent: (options: {\n event: string;\n category: string;\n properties: {\n tokens: string[];\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: string;\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: string;\n };\n }) => void;\n messenger: TokenDetectionControllerMessenger;\n useAccountsAPI?: boolean;\n platform: 'extension' | 'mobile';\n }) {\n super({\n name: controllerName,\n messenger,\n state: {},\n metadata: {},\n });\n\n this.#disabled = disabled;\n this.setIntervalLength(interval);\n\n this.#selectedAccountId = this.#getSelectedAccount().id;\n\n const { chainId, networkClientId } =\n this.#getCorrectChainIdAndNetworkClientId();\n this.#networkClientId = networkClientId;\n\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n\n this.#tokensChainsCache = tokensChainsCache;\n\n const { useTokenDetection: defaultUseTokenDetection } =\n this.messagingSystem.call('PreferencesController:getState');\n this.#isDetectionEnabledFromPreferences = defaultUseTokenDetection;\n this.#isDetectionEnabledForNetwork =\n isTokenDetectionSupportedForNetwork(chainId);\n\n this.#getBalancesInSingleCall = getBalancesInSingleCall;\n\n this.#trackMetaMetricsEvent = trackMetaMetricsEvent;\n\n const { isUnlocked } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n this.#isUnlocked = isUnlocked;\n\n this.#accountsAPI.isAccountsAPIEnabled = useAccountsAPI;\n this.#accountsAPI.platform = platform;\n\n this.#registerEventListeners();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system subscriptions to controller events.\n */\n #registerEventListeners() {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.messagingSystem.subscribe('KeyringController:unlock', async () => {\n this.#isUnlocked = true;\n await this.#restartTokenDetection();\n });\n\n this.messagingSystem.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n this.#stopPolling();\n });\n\n this.messagingSystem.subscribe(\n 'TokenListController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ tokensChainsCache }) => {\n const isEqualValues = this.#compareTokensChainsCache(\n tokensChainsCache,\n this.#tokensChainsCache,\n );\n if (!isEqualValues) {\n await this.#restartTokenDetection();\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'PreferencesController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ useTokenDetection }) => {\n const selectedAccount = this.#getSelectedAccount();\n const isDetectionChangedFromPreferences =\n this.#isDetectionEnabledFromPreferences !== useTokenDetection;\n\n this.#isDetectionEnabledFromPreferences = useTokenDetection;\n\n if (isDetectionChangedFromPreferences) {\n await this.#restartTokenDetection({\n selectedAddress: selectedAccount.address,\n });\n }\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:selectedEvmAccountChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (selectedAccount) => {\n const { networkConfigurationsByChainId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const chainIds = Object.keys(networkConfigurationsByChainId) as Hex[];\n const isSelectedAccountIdChanged =\n this.#selectedAccountId !== selectedAccount.id;\n if (isSelectedAccountIdChanged) {\n this.#selectedAccountId = selectedAccount.id;\n await this.#restartTokenDetection({\n selectedAddress: selectedAccount.address,\n chainIds,\n });\n }\n },\n );\n }\n\n /**\n * Allows controller to make active and passive polling requests\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from making network calls\n */\n disable(): void {\n this.#disabled = true;\n }\n\n /**\n * Internal isActive state\n * @type {boolean}\n */\n get isActive(): boolean {\n return !this.#disabled && this.#isUnlocked;\n }\n\n /**\n * Start polling for detected tokens.\n */\n async start(): Promise<void> {\n this.enable();\n await this.#startPolling();\n }\n\n /**\n * Stop polling for detected tokens.\n */\n stop(): void {\n this.disable();\n this.#stopPolling();\n }\n\n #stopPolling(): void {\n if (this.#intervalId) {\n clearInterval(this.#intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n */\n async #startPolling(): Promise<void> {\n if (!this.isActive) {\n return;\n }\n this.#stopPolling();\n await this.detectTokens();\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#intervalId = setInterval(async () => {\n await this.detectTokens();\n }, this.getIntervalLength());\n }\n\n /**\n * Compares current and previous tokensChainsCache object focusing only on the data object.\n * @param tokensChainsCache - current tokensChainsCache input object\n * @param previousTokensChainsCache - previous tokensChainsCache input object\n * @returns boolean indicating if the two objects are equal\n */\n\n #compareTokensChainsCache(\n tokensChainsCache: TokensChainsCache,\n previousTokensChainsCache: TokensChainsCache,\n ): boolean {\n const cleanPreviousTokensChainsCache = mapChainIdWithTokenListMap(\n previousTokensChainsCache,\n );\n const cleanTokensChainsCache =\n mapChainIdWithTokenListMap(tokensChainsCache);\n const isEqualValues = isEqual(\n cleanTokensChainsCache,\n cleanPreviousTokensChainsCache,\n );\n return isEqualValues;\n }\n\n #getCorrectNetworkClientIdByChainId(\n chainIds: Hex[] | undefined,\n ): { chainId: Hex; networkClientId: NetworkClientId }[] {\n const { networkConfigurationsByChainId, selectedNetworkClientId } =\n this.messagingSystem.call('NetworkController:getState');\n\n if (!chainIds) {\n const networkConfiguration = this.messagingSystem.call(\n 'NetworkController:getNetworkConfigurationByNetworkClientId',\n selectedNetworkClientId,\n );\n\n return [\n {\n chainId: networkConfiguration?.chainId ?? ChainId.mainnet,\n networkClientId: selectedNetworkClientId,\n },\n ];\n }\n\n return chainIds.map((chainId) => {\n const configuration = networkConfigurationsByChainId[chainId];\n return {\n chainId,\n networkClientId:\n configuration.rpcEndpoints[configuration.defaultRpcEndpointIndex]\n .networkClientId,\n };\n });\n }\n\n #getCorrectChainIdAndNetworkClientId() {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return {\n chainId,\n networkClientId: selectedNetworkClientId,\n };\n }\n\n async _executePoll({\n chainIds,\n address,\n }: TokenDetectionPollingInput): Promise<void> {\n if (!this.isActive) {\n return;\n }\n await this.detectTokens({\n chainIds,\n selectedAddress: address,\n });\n }\n\n /**\n * Restart token detection polling period and call detectNewTokens\n * in case of address change or user session initialization.\n *\n * @param options - Options for restart token detection.\n * @param options.selectedAddress - the selectedAddress against which to detect for token balances\n * @param options.chainIds - The chain IDs of the network client to use.\n */\n async #restartTokenDetection({\n selectedAddress,\n chainIds,\n }: {\n selectedAddress?: string;\n chainIds?: Hex[];\n } = {}): Promise<void> {\n await this.detectTokens({\n chainIds,\n selectedAddress,\n });\n this.setIntervalLength(DEFAULT_INTERVAL);\n }\n\n #getChainsToDetect(\n clientNetworks: NetworkClient[],\n supportedNetworks: number[] | null | undefined,\n ) {\n const chainsToDetectUsingAccountAPI: Hex[] = [];\n const chainsToDetectUsingRpc: NetworkClient[] = [];\n\n clientNetworks.forEach(({ chainId, networkClientId }) => {\n if (supportedNetworks?.includes(hexToNumber(chainId))) {\n chainsToDetectUsingAccountAPI.push(chainId);\n } else {\n chainsToDetectUsingRpc.push({ chainId, networkClientId });\n }\n });\n\n return { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI };\n }\n\n async #attemptAccountAPIDetection(\n chainsToDetectUsingAccountAPI: Hex[],\n addressToDetect: string,\n supportedNetworks: number[] | null,\n ) {\n return await this.#addDetectedTokensViaAPI({\n chainIds: chainsToDetectUsingAccountAPI,\n selectedAddress: addressToDetect,\n supportedNetworks,\n });\n }\n\n #addChainsToRpcDetection(\n chainsToDetectUsingRpc: NetworkClient[],\n chainsToDetectUsingAccountAPI: Hex[],\n clientNetworks: NetworkClient[],\n ): void {\n chainsToDetectUsingAccountAPI.forEach((chainId) => {\n const networkEntry = clientNetworks.find(\n (network) => network.chainId === chainId,\n );\n if (networkEntry) {\n chainsToDetectUsingRpc.push({\n chainId: networkEntry.chainId,\n networkClientId: networkEntry.networkClientId,\n });\n }\n });\n }\n\n #shouldDetectTokens(chainId: Hex): boolean {\n if (!isTokenDetectionSupportedForNetwork(chainId)) {\n return false;\n }\n if (\n !this.#isDetectionEnabledFromPreferences &&\n chainId !== ChainId.mainnet\n ) {\n return false;\n }\n\n const isMainnetDetectionInactive =\n !this.#isDetectionEnabledFromPreferences && chainId === ChainId.mainnet;\n if (isMainnetDetectionInactive) {\n this.#tokensChainsCache = this.#getConvertedStaticMainnetTokenList();\n } else {\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n this.#tokensChainsCache = tokensChainsCache ?? {};\n }\n\n return true;\n }\n\n async #detectTokensUsingRpc(\n chainsToDetectUsingRpc: NetworkClient[],\n addressToDetect: string,\n ): Promise<void> {\n for (const { chainId, networkClientId } of chainsToDetectUsingRpc) {\n if (!this.#shouldDetectTokens(chainId)) {\n continue;\n }\n\n const tokenCandidateSlices = this.#getSlicesOfTokensToDetect({\n chainId,\n selectedAddress: addressToDetect,\n });\n const tokenDetectionPromises = tokenCandidateSlices.map((tokensSlice) =>\n this.#addDetectedTokens({\n tokensSlice,\n selectedAddress: addressToDetect,\n networkClientId,\n chainId,\n }),\n );\n\n await Promise.all(tokenDetectionPromises);\n }\n }\n\n /**\n * For each token in the token list provided by the TokenListController, checks the token's balance for the selected account address on the active network.\n * On mainnet, if token detection is disabled in preferences, ERC20 token auto detection will be triggered for each contract address in the legacy token list from the @metamask/contract-metadata repo.\n *\n * @param options - Options for token detection.\n * @param options.chainIds - The chain IDs of the network client to use.\n * @param options.selectedAddress - the selectedAddress against which to detect for token balances.\n */\n async detectTokens({\n chainIds,\n selectedAddress,\n }: {\n chainIds?: Hex[];\n selectedAddress?: string;\n } = {}): Promise<void> {\n if (!this.isActive) {\n return;\n }\n\n const addressToDetect = selectedAddress ?? this.#getSelectedAddress();\n const clientNetworks = this.#getCorrectNetworkClientIdByChainId(chainIds);\n\n let supportedNetworks;\n if (this.#accountsAPI.isAccountsAPIEnabled) {\n supportedNetworks = await this.#accountsAPI.getSupportedNetworks();\n }\n const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } =\n this.#getChainsToDetect(clientNetworks, supportedNetworks);\n\n // Try detecting tokens via Account API first if conditions allow\n if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {\n const apiResult = await this.#attemptAccountAPIDetection(\n chainsToDetectUsingAccountAPI,\n addressToDetect,\n supportedNetworks,\n );\n\n // If the account API call failed, have those chains fall back to RPC detection\n if (apiResult?.result === 'failed') {\n this.#addChainsToRpcDetection(\n chainsToDetectUsingRpc,\n chainsToDetectUsingAccountAPI,\n clientNetworks,\n );\n }\n }\n\n // Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc\n if (chainsToDetectUsingRpc.length > 0) {\n await this.#detectTokensUsingRpc(chainsToDetectUsingRpc, addressToDetect);\n }\n }\n\n #getSlicesOfTokensToDetect({\n chainId,\n selectedAddress,\n }: {\n chainId: Hex;\n selectedAddress: string;\n }): string[][] {\n const { allTokens, allDetectedTokens, allIgnoredTokens } =\n this.messagingSystem.call('TokensController:getState');\n const [tokensAddresses, detectedTokensAddresses, ignoredTokensAddresses] = [\n allTokens,\n allDetectedTokens,\n allIgnoredTokens,\n ].map((tokens) =>\n (tokens[chainId]?.[selectedAddress] ?? []).map((value) =>\n typeof value === 'string' ? value : value.address,\n ),\n );\n\n const tokensToDetect: string[] = [];\n for (const tokenAddress of Object.keys(\n this.#tokensChainsCache?.[chainId]?.data || {},\n )) {\n if (\n [\n tokensAddresses,\n detectedTokensAddresses,\n ignoredTokensAddresses,\n ].every(\n (addresses) =>\n !addresses.find((address) =>\n isEqualCaseInsensitive(address, tokenAddress),\n ),\n )\n ) {\n tokensToDetect.push(tokenAddress);\n }\n }\n\n const slicesOfTokensToDetect = [];\n for (let i = 0, size = 1000; i < tokensToDetect.length; i += size) {\n slicesOfTokensToDetect.push(tokensToDetect.slice(i, i + size));\n }\n\n return slicesOfTokensToDetect;\n }\n\n #getConvertedStaticMainnetTokenList(): TokensChainsCache {\n const data: TokenListMap = Object.entries(STATIC_MAINNET_TOKEN_LIST).reduce(\n (acc, [key, value]) => ({\n ...acc,\n [key]: {\n name: value.name,\n symbol: value.symbol,\n decimals: value.decimals,\n address: value.address,\n aggregators: [],\n iconUrl: value?.iconUrl,\n },\n }),\n {},\n );\n return {\n '0x1': {\n data,\n timestamp: 0,\n },\n };\n }\n\n /**\n * This adds detected tokens from the Accounts API, avoiding the multi-call RPC calls for balances\n * @param options - method arguments\n * @param options.selectedAddress - address to check against\n * @param options.chainIds - array of chainIds to check tokens for\n * @param options.supportedNetworks - array of chainIds to check tokens for\n * @returns a success or failed object\n */\n async #addDetectedTokensViaAPI({\n selectedAddress,\n chainIds,\n supportedNetworks,\n }: {\n selectedAddress: string;\n chainIds: Hex[];\n supportedNetworks: number[] | null;\n }) {\n return await safelyExecute(async () => {\n // Fetch balances for multiple chain IDs at once\n const tokenBalancesByChain = await this.#accountsAPI\n .getMultiNetworksBalances(selectedAddress, chainIds, supportedNetworks)\n .catch(() => null);\n\n if (tokenBalancesByChain === null) {\n return { result: 'failed' } as const;\n }\n\n // Process each chain ID individually\n for (const chainId of chainIds) {\n const isTokenDetectionInactiveInMainnet =\n !this.#isDetectionEnabledFromPreferences &&\n chainId === ChainId.mainnet;\n const { tokensChainsCache } = this.messagingSystem.call(\n 'TokenListController:getState',\n );\n this.#tokensChainsCache = isTokenDetectionInactiveInMainnet\n ? this.#getConvertedStaticMainnetTokenList()\n : tokensChainsCache ?? {};\n\n // Generate token candidates based on chainId and selectedAddress\n const tokenCandidateSlices = this.#getSlicesOfTokensToDetect({\n chainId,\n selectedAddress,\n });\n\n // Filter balances for the current chainId\n const tokenBalances = tokenBalancesByChain.filter(\n (balance) => balance.chainId === hexToNumber(chainId),\n );\n\n if (!tokenBalances || tokenBalances.length === 0) {\n continue;\n }\n\n // Use helper function to filter tokens with balance for this chainId\n const { tokensWithBalance, eventTokensDetails } =\n this.#filterAndBuildTokensWithBalance(\n tokenCandidateSlices,\n tokenBalances,\n chainId,\n );\n\n if (tokensWithBalance.length) {\n this.#trackMetaMetricsEvent({\n event: 'Token Detected',\n category: 'Wallet',\n properties: {\n tokens: eventTokensDetails,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: ERC20,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: ASSET_TYPES.TOKEN,\n },\n });\n\n await this.messagingSystem.call(\n 'TokensController:addDetectedTokens',\n tokensWithBalance,\n {\n selectedAddress,\n chainId,\n },\n );\n }\n }\n\n return { result: 'success' } as const;\n });\n }\n\n /**\n * Helper function to filter and build token data for detected tokens\n * @param options.tokenCandidateSlices - these are tokens we know a user does not have (by checking the tokens controller).\n * We will use these these token candidates to determine if a token found from the API is valid to be added on the users wallet.\n * It will also prevent us to adding tokens a user already has\n * @param tokenBalances - Tokens balances fetched from API\n * @param chainId - The chain ID being processed\n * @returns an object containing tokensWithBalance and eventTokensDetails arrays\n */\n\n #filterAndBuildTokensWithBalance(\n tokenCandidateSlices: string[][],\n tokenBalances:\n | {\n object: string;\n type?: string;\n timestamp?: string;\n address: string;\n symbol: string;\n name: string;\n decimals: number;\n chainId: number;\n balance: string;\n }[]\n | null,\n chainId: Hex,\n ) {\n const tokensWithBalance: Token[] = [];\n const eventTokensDetails: string[] = [];\n\n const tokenCandidateSet = new Set<string>(tokenCandidateSlices.flat());\n\n tokenBalances?.forEach((token) => {\n const tokenAddress = token.address;\n\n // Make sure the token to add is in our candidate list\n if (!tokenCandidateSet.has(tokenAddress)) {\n return;\n }\n\n // Retrieve token data from cache to safely add it\n const tokenData = this.#tokensChainsCache[chainId]?.data[tokenAddress];\n\n // We need specific data from tokensChainsCache to correctly create a token\n // So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.\n if (!tokenData) {\n return;\n }\n\n const { decimals, symbol, aggregators, iconUrl, name } = tokenData;\n eventTokensDetails.push(`${symbol} - ${tokenAddress}`);\n tokensWithBalance.push({\n address: tokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n name,\n });\n });\n\n return { tokensWithBalance, eventTokensDetails };\n }\n\n async #addDetectedTokens({\n tokensSlice,\n selectedAddress,\n networkClientId,\n chainId,\n }: {\n tokensSlice: string[];\n selectedAddress: string;\n networkClientId: NetworkClientId;\n chainId: Hex;\n }): Promise<void> {\n await safelyExecute(async () => {\n const balances = await this.#getBalancesInSingleCall(\n selectedAddress,\n tokensSlice,\n networkClientId,\n );\n\n const tokensWithBalance: Token[] = [];\n const eventTokensDetails: string[] = [];\n for (const nonZeroTokenAddress of Object.keys(balances)) {\n const { decimals, symbol, aggregators, iconUrl, name } =\n this.#tokensChainsCache[chainId].data[nonZeroTokenAddress];\n eventTokensDetails.push(`${symbol} - ${nonZeroTokenAddress}`);\n tokensWithBalance.push({\n address: nonZeroTokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n name,\n });\n }\n\n if (tokensWithBalance.length) {\n this.#trackMetaMetricsEvent({\n event: 'Token Detected',\n category: 'Wallet',\n properties: {\n tokens: eventTokensDetails,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n token_standard: ERC20,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asset_type: ASSET_TYPES.TOKEN,\n },\n });\n\n await this.messagingSystem.call(\n 'TokensController:addDetectedTokens',\n tokensWithBalance,\n {\n selectedAddress,\n chainId,\n },\n );\n }\n });\n }\n\n #getSelectedAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n #getSelectedAddress() {\n // If the address is not defined (or empty), we fallback to the currently selected account's address\n const account = this.messagingSystem.call(\n 'AccountsController:getAccount',\n this.#selectedAccountId,\n );\n return account?.address || '';\n }\n}\n\nexport default TokenDetectionController;\n"]}
|
|
@@ -37,14 +37,14 @@ type TokenListPollingInput = {
|
|
|
37
37
|
chainId: Hex;
|
|
38
38
|
};
|
|
39
39
|
declare const TokenListController_base: (abstract new (...args: any[]) => {
|
|
40
|
-
readonly "__#
|
|
41
|
-
"__#
|
|
40
|
+
readonly "__#11@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
41
|
+
"__#11@#intervalLength": number | undefined;
|
|
42
42
|
setIntervalLength(intervalLength: number): void;
|
|
43
43
|
getIntervalLength(): number | undefined;
|
|
44
44
|
_startPolling(input: TokenListPollingInput): void;
|
|
45
45
|
_stopPollingByPollingTokenSetId(key: string): void;
|
|
46
|
-
readonly "__#
|
|
47
|
-
"__#
|
|
46
|
+
readonly "__#3@#pollingTokenSets": Map<string, Set<string>>;
|
|
47
|
+
"__#3@#callbacks": Map<string, Set<(input: TokenListPollingInput) => void>>;
|
|
48
48
|
_executePoll(input: TokenListPollingInput): Promise<void>;
|
|
49
49
|
startPolling(input: TokenListPollingInput): string;
|
|
50
50
|
stopAllPolling(): void;
|
|
@@ -37,14 +37,14 @@ type TokenListPollingInput = {
|
|
|
37
37
|
chainId: Hex;
|
|
38
38
|
};
|
|
39
39
|
declare const TokenListController_base: (abstract new (...args: any[]) => {
|
|
40
|
-
readonly "__#
|
|
41
|
-
"__#
|
|
40
|
+
readonly "__#11@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
41
|
+
"__#11@#intervalLength": number | undefined;
|
|
42
42
|
setIntervalLength(intervalLength: number): void;
|
|
43
43
|
getIntervalLength(): number | undefined;
|
|
44
44
|
_startPolling(input: TokenListPollingInput): void;
|
|
45
45
|
_stopPollingByPollingTokenSetId(key: string): void;
|
|
46
|
-
readonly "__#
|
|
47
|
-
"__#
|
|
46
|
+
readonly "__#3@#pollingTokenSets": Map<string, Set<string>>;
|
|
47
|
+
"__#3@#callbacks": Map<string, Set<(input: TokenListPollingInput) => void>>;
|
|
48
48
|
_executePoll(input: TokenListPollingInput): Promise<void>;
|
|
49
49
|
startPolling(input: TokenListPollingInput): string;
|
|
50
50
|
stopAllPolling(): void;
|
|
@@ -406,9 +406,9 @@ async function _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeC
|
|
|
406
406
|
currency: nativeCurrency,
|
|
407
407
|
});
|
|
408
408
|
contractNativeInformations = {
|
|
409
|
-
[codefi_v2_1.
|
|
409
|
+
[(0, codefi_v2_1.getNativeTokenAddress)(chainId)]: {
|
|
410
410
|
currency: nativeCurrency,
|
|
411
|
-
...contractNativeInformationsNative[codefi_v2_1.
|
|
411
|
+
...contractNativeInformationsNative[(0, codefi_v2_1.getNativeTokenAddress)(chainId)],
|
|
412
412
|
},
|
|
413
413
|
};
|
|
414
414
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenRatesController.cjs","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedEvmAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n toHex,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-api';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { createDeferredPromise, type Hex } from '@metamask/utils';\nimport { isEqual } from 'lodash';\n\nimport { reduceInBatchesSerially, TOKEN_PRICES_BATCH_SIZE } from './assetsUtil';\nimport { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from './crypto-compare-service';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { ZERO_ADDRESS } from './token-prices-service/codefi-v2';\nimport type {\n TokensControllerGetStateAction,\n TokensControllerStateChangeEvent,\n TokensControllerState,\n} from './TokensController';\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property aggregators - An array containing the token's aggregators\n * @property image - Image of the token, url or bit32 image\n * @property hasBalanceError - 'true' if there is an error while updating the token balance\n * @property isERC721 - 'true' if the token is a ERC721 token\n * @property name - Name of the token\n */\nexport type Token = {\n address: string;\n decimals: number;\n symbol: string;\n aggregators?: string[];\n image?: string;\n hasBalanceError?: boolean;\n isERC721?: boolean;\n name?: string;\n};\n\nconst DEFAULT_INTERVAL = 180000;\n\nexport type ContractExchangeRates = {\n [address: string]: number | undefined;\n};\n\nexport type MarketDataDetails = {\n tokenAddress: `0x${string}`;\n currency: string;\n allTimeHigh: number;\n allTimeLow: number;\n circulatingSupply: number;\n dilutedMarketCap: number;\n high1d: number;\n low1d: number;\n marketCap: number;\n marketCapPercentChange1d: number;\n price: number;\n priceChange1d: number;\n pricePercentChange1d: number;\n pricePercentChange1h: number;\n pricePercentChange1y: number;\n pricePercentChange7d: number;\n pricePercentChange14d: number;\n pricePercentChange30d: number;\n pricePercentChange200d: number;\n totalVolume: number;\n};\n\n/**\n * Represents a mapping of token contract addresses to their market data.\n */\nexport type ContractMarketData = Record<Hex, MarketDataDetails>;\n\nenum PollState {\n Active = 'Active',\n Inactive = 'Inactive',\n}\n\n/**\n * The external actions available to the {@link TokenRatesController}.\n */\nexport type AllowedActions =\n | TokensControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedAccountAction;\n\n/**\n * The external events available to the {@link TokenRatesController}.\n */\nexport type AllowedEvents =\n | TokensControllerStateChangeEvent\n | NetworkControllerStateChangeEvent\n | AccountsControllerSelectedEvmAccountChangeEvent;\n\n/**\n * The name of the {@link TokenRatesController}.\n */\nexport const controllerName = 'TokenRatesController';\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property marketData - Market data for tokens, keyed by chain ID and then token contract address.\n */\nexport type TokenRatesControllerState = {\n marketData: Record<Hex, Record<Hex, MarketDataDetails>>;\n};\n\n/**\n * The action that can be performed to get the state of the {@link TokenRatesController}.\n */\nexport type TokenRatesControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenRatesControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link TokenRatesController}.\n */\nexport type TokenRatesControllerActions = TokenRatesControllerGetStateAction;\n\n/**\n * The event that {@link TokenRatesController} can emit.\n */\nexport type TokenRatesControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n TokenRatesControllerState\n>;\n\n/**\n * The events that {@link TokenRatesController} can emit.\n */\nexport type TokenRatesControllerEvents = TokenRatesControllerStateChangeEvent;\n\n/**\n * The messenger of the {@link TokenRatesController} for communication.\n */\nexport type TokenRatesControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenRatesControllerActions | AllowedActions,\n TokenRatesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Uses the CryptoCompare API to fetch the exchange rate between one currency\n * and another, i.e., the multiplier to apply the amount of one currency in\n * order to convert it to another.\n *\n * @param args - The arguments to this function.\n * @param args.from - The currency to convert from.\n * @param args.to - The currency to convert to.\n * @returns The exchange rate between `fromCurrency` to `toCurrency` if one\n * exists, or null if one does not.\n */\nasync function getCurrencyConversionRate({\n from,\n to,\n}: {\n from: string;\n to: string;\n}) {\n const includeUSDRate = false;\n try {\n const result = await fetchNativeCurrencyExchangeRate(\n to,\n from,\n includeUSDRate,\n );\n return result.conversionRate;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return null;\n }\n throw error;\n }\n}\n\nconst tokenRatesControllerMetadata = {\n marketData: { persist: true, anonymous: false },\n};\n\n/**\n * Get the default {@link TokenRatesController} state.\n *\n * @returns The default {@link TokenRatesController} state.\n */\nexport const getDefaultTokenRatesControllerState =\n (): TokenRatesControllerState => {\n return {\n marketData: {},\n };\n };\n\n/** The input to start polling for the {@link TokenRatesController} */\nexport type TokenRatesPollingInput = {\n chainId: Hex;\n};\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends StaticIntervalPollingController<TokenRatesPollingInput>()<\n typeof controllerName,\n TokenRatesControllerState,\n TokenRatesControllerMessenger\n> {\n #handle?: ReturnType<typeof setTimeout>;\n\n #pollState = PollState.Inactive;\n\n #tokenPricesService: AbstractTokenPricesService;\n\n #inProcessExchangeRateUpdates: Record<`${Hex}:${string}`, Promise<void>> = {};\n\n #selectedAccountId: string;\n\n #disabled: boolean;\n\n #chainId: Hex;\n\n #ticker: string;\n\n #interval: number;\n\n #allTokens: TokensControllerState['allTokens'];\n\n #allDetectedTokens: TokensControllerState['allDetectedTokens'];\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.interval - The polling interval in ms\n * @param options.disabled - Boolean to track if network requests are blocked\n * @param options.tokenPricesService - An object in charge of retrieving token price\n * @param options.messenger - The controller messenger instance for communication\n * @param options.state - Initial state to set on this controller\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n disabled = false,\n tokenPricesService,\n messenger,\n state,\n }: {\n interval?: number;\n disabled?: boolean;\n tokenPricesService: AbstractTokenPricesService;\n messenger: TokenRatesControllerMessenger;\n state?: Partial<TokenRatesControllerState>;\n }) {\n super({\n name: controllerName,\n messenger,\n state: { ...getDefaultTokenRatesControllerState(), ...state },\n metadata: tokenRatesControllerMetadata,\n });\n\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n this.#disabled = disabled;\n this.#interval = interval;\n\n const { chainId: currentChainId, ticker: currentTicker } =\n this.#getChainIdAndTicker();\n this.#chainId = currentChainId;\n this.#ticker = currentTicker;\n\n this.#selectedAccountId = this.#getSelectedAccount().id;\n\n const { allTokens, allDetectedTokens } = this.#getTokensControllerState();\n this.#allTokens = allTokens;\n this.#allDetectedTokens = allDetectedTokens;\n\n this.#subscribeToTokensStateChange();\n\n this.#subscribeToNetworkStateChange();\n }\n\n #subscribeToTokensStateChange() {\n this.messagingSystem.subscribe(\n 'TokensController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ allTokens, allDetectedTokens }) => {\n if (this.#disabled) {\n return;\n }\n\n const chainIds = [\n ...new Set([\n ...Object.keys(allTokens),\n ...Object.keys(allDetectedTokens),\n ]),\n ] as Hex[];\n\n const chainIdsToUpdate = chainIds.filter(\n (chainId) =>\n !isEqual(this.#allTokens[chainId], allTokens[chainId]) ||\n !isEqual(\n this.#allDetectedTokens[chainId],\n allDetectedTokens[chainId],\n ),\n );\n\n this.#allTokens = allTokens;\n this.#allDetectedTokens = allDetectedTokens;\n\n const { networkConfigurationsByChainId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n await Promise.allSettled(\n chainIdsToUpdate.map(async (chainId) => {\n const nativeCurrency =\n networkConfigurationsByChainId[chainId as Hex]?.nativeCurrency;\n\n if (nativeCurrency) {\n await this.updateExchangeRatesByChainId({\n chainId: chainId as Hex,\n nativeCurrency,\n });\n }\n }),\n );\n },\n ({ allTokens, allDetectedTokens }) => {\n return { allTokens, allDetectedTokens };\n },\n );\n }\n\n #subscribeToNetworkStateChange() {\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ selectedNetworkClientId }, patches) => {\n const {\n configuration: { chainId, ticker },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n if (this.#chainId !== chainId || this.#ticker !== ticker) {\n this.#chainId = chainId;\n this.#ticker = ticker;\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n\n // Remove state for deleted networks\n for (const patch of patches) {\n if (\n patch.op === 'remove' &&\n patch.path[0] === 'networkConfigurationsByChainId'\n ) {\n const removedChainId = patch.path[1] as Hex;\n this.update((state) => {\n delete state.marketData[removedChainId];\n });\n }\n }\n },\n );\n }\n\n /**\n * Get the tokens for the given chain.\n *\n * @param chainId - The chain ID.\n * @returns The list of tokens addresses for the current chain\n */\n #getTokenAddresses(chainId: Hex): Hex[] {\n const getTokens = (allTokens: Record<Hex, { address: string }[]>) =>\n Object.values(allTokens ?? {}).flatMap((tokens) =>\n tokens.map(({ address }) => toHex(toChecksumHexAddress(address))),\n );\n\n const tokenAddresses = getTokens(this.#allTokens[chainId]);\n const detectedTokenAddresses = getTokens(this.#allDetectedTokens[chainId]);\n\n return [...new Set([...tokenAddresses, ...detectedTokenAddresses])].sort();\n }\n\n /**\n * Allows controller to make active and passive polling requests\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from making network calls\n */\n disable(): void {\n this.#disabled = true;\n }\n\n /**\n * Start (or restart) polling.\n */\n async start() {\n this.#stopPoll();\n this.#pollState = PollState.Active;\n await this.#poll();\n }\n\n /**\n * Stop polling.\n */\n stop() {\n this.#stopPoll();\n this.#pollState = PollState.Inactive;\n }\n\n #getSelectedAccount(): InternalAccount {\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n\n return selectedAccount;\n }\n\n #getChainIdAndTicker(): {\n chainId: Hex;\n ticker: string;\n } {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return {\n chainId: networkClient.configuration.chainId,\n ticker: networkClient.configuration.ticker,\n };\n }\n\n #getTokensControllerState(): {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n } {\n const { allTokens, allDetectedTokens } = this.messagingSystem.call(\n 'TokensController:getState',\n );\n\n return {\n allTokens,\n allDetectedTokens,\n };\n }\n\n /**\n * Clear the active polling timer, if present.\n */\n #stopPoll() {\n if (this.#handle) {\n clearTimeout(this.#handle);\n }\n }\n\n /**\n * Poll for exchange rate updates.\n */\n async #poll() {\n await safelyExecute(() => this.updateExchangeRates());\n\n // Poll using recursive `setTimeout` instead of `setInterval` so that\n // requests don't stack if they take longer than the polling interval\n this.#handle = setTimeout(() => {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#poll();\n }, this.#interval);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n await this.updateExchangeRatesByChainId({\n chainId: this.#chainId,\n nativeCurrency: this.#ticker,\n });\n }\n\n /**\n * Updates exchange rates for all tokens.\n *\n * @param options - The options to fetch exchange rates.\n * @param options.chainId - The chain ID.\n * @param options.nativeCurrency - The ticker for the chain.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n }) {\n if (this.#disabled) {\n return;\n }\n\n const tokenAddresses = this.#getTokenAddresses(chainId);\n\n const updateKey: `${Hex}:${string}` = `${chainId}:${nativeCurrency}`;\n if (updateKey in this.#inProcessExchangeRateUpdates) {\n // This prevents redundant updates\n // This promise is resolved after the in-progress update has finished,\n // and state has been updated.\n await this.#inProcessExchangeRateUpdates[updateKey];\n return;\n }\n\n const {\n promise: inProgressUpdate,\n resolve: updateSucceeded,\n reject: updateFailed,\n } = createDeferredPromise({ suppressUnhandledRejection: true });\n this.#inProcessExchangeRateUpdates[updateKey] = inProgressUpdate;\n\n try {\n const contractInformations = await this.#fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n\n const marketData = {\n [chainId]: {\n ...(contractInformations ?? {}),\n },\n };\n\n this.update((state) => {\n state.marketData = {\n ...state.marketData,\n ...marketData,\n };\n });\n updateSucceeded();\n } catch (error: unknown) {\n updateFailed(error);\n throw error;\n } finally {\n delete this.#inProcessExchangeRateUpdates[updateKey];\n }\n }\n\n /**\n * Uses the token prices service to retrieve exchange rates for tokens in a\n * particular currency.\n *\n * If the price API does not support the given chain ID, returns an empty\n * object.\n *\n * If the price API does not support the given currency, retrieves exchange\n * rates in a known currency instead, then converts those rates using the\n * exchange rate between the known currency and desired currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * exchange rates.\n * @returns A map from token address to its exchange rate in the native\n * currency, or an empty map if no exchange rates can be obtained for the\n * chain ID.\n */\n async #fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractMarketData> {\n if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {\n return tokenAddresses.reduce((obj, tokenAddress) => {\n obj = {\n ...obj,\n [tokenAddress]: undefined,\n };\n\n return obj;\n }, {});\n }\n\n if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {\n return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n }\n\n return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n chainId,\n tokenAddresses,\n nativeCurrency,\n });\n }\n\n /**\n * Updates token rates for the given networkClientId\n *\n * @param input - The input for the poll.\n * @param input.chainId - The chain id to poll token rates on.\n */\n async _executePoll({ chainId }: TokenRatesPollingInput): Promise<void> {\n const { networkConfigurationsByChainId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n console.error(\n `TokenRatesController: No network configuration found for chainId ${chainId}`,\n );\n return;\n }\n\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency: networkConfiguration.nativeCurrency,\n });\n }\n\n /**\n * Retrieves prices in the given currency for the given tokens on the given\n * chain. Ensures that token addresses are checksum addresses.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractMarketData> {\n let contractNativeInformations;\n const tokenPricesByTokenAddress = await reduceInBatchesSerially<\n Hex,\n Awaited<ReturnType<AbstractTokenPricesService['fetchTokenPrices']>>\n >({\n values: [...tokenAddresses].sort(),\n batchSize: TOKEN_PRICES_BATCH_SIZE,\n eachBatch: async (allTokenPricesByTokenAddress, batch) => {\n const tokenPricesByTokenAddressForBatch =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenAddresses: batch,\n chainId,\n currency: nativeCurrency,\n });\n\n return {\n ...allTokenPricesByTokenAddress,\n ...tokenPricesByTokenAddressForBatch,\n };\n },\n initialResult: {},\n });\n contractNativeInformations = tokenPricesByTokenAddress;\n\n // fetch for native token\n if (tokenAddresses.length === 0) {\n const contractNativeInformationsNative =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenAddresses: [],\n chainId,\n currency: nativeCurrency,\n });\n\n contractNativeInformations = {\n [ZERO_ADDRESS]: {\n currency: nativeCurrency,\n ...contractNativeInformationsNative[ZERO_ADDRESS],\n },\n };\n }\n return Object.entries(contractNativeInformations).reduce(\n (obj, [tokenAddress, token]) => {\n obj = {\n ...obj,\n [tokenAddress]: { ...token },\n };\n\n return obj;\n },\n {},\n );\n }\n\n /**\n * If the price API does not support a given native currency, then we need to\n * convert it to a fallback currency and feed that currency into the price\n * API, then convert the prices to our desired native currency.\n *\n * @param args - The arguments to this function.\n * @param args.chainId - The chain id to fetch prices for.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n chainId,\n tokenAddresses,\n nativeCurrency,\n }: {\n chainId: Hex;\n tokenAddresses: Hex[];\n nativeCurrency: string;\n }): Promise<ContractMarketData> {\n const [\n contractExchangeInformations,\n fallbackCurrencyToNativeCurrencyConversionRate,\n ] = await Promise.all([\n this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency: FALL_BACK_VS_CURRENCY,\n }),\n getCurrencyConversionRate({\n from: FALL_BACK_VS_CURRENCY,\n to: nativeCurrency,\n }),\n ]);\n\n if (fallbackCurrencyToNativeCurrencyConversionRate === null) {\n return {};\n }\n\n // Converts the price in the fallback currency to the native currency\n const convertFallbackToNative = (value: number | undefined) =>\n value !== undefined && value !== null\n ? value * fallbackCurrencyToNativeCurrencyConversionRate\n : undefined;\n\n const updatedContractExchangeRates = Object.entries(\n contractExchangeInformations,\n ).reduce((acc, [tokenAddress, token]) => {\n acc = {\n ...acc,\n [tokenAddress]: {\n ...token,\n currency: nativeCurrency,\n price: convertFallbackToNative(token.price),\n marketCap: convertFallbackToNative(token.marketCap),\n allTimeHigh: convertFallbackToNative(token.allTimeHigh),\n allTimeLow: convertFallbackToNative(token.allTimeLow),\n totalVolume: convertFallbackToNative(token.totalVolume),\n high1d: convertFallbackToNative(token.high1d),\n low1d: convertFallbackToNative(token.low1d),\n dilutedMarketCap: convertFallbackToNative(token.dilutedMarketCap),\n },\n };\n return acc;\n }, {});\n\n return updatedContractExchangeRates;\n }\n\n /**\n * Reset the controller state to the default state.\n */\n resetState() {\n this.update(() => {\n return getDefaultTokenRatesControllerState();\n });\n }\n}\n\nexport default TokenRatesController;\n"]}
|
|
1
|
+
{"version":3,"file":"TokenRatesController.cjs","sourceRoot":"","sources":["../src/TokenRatesController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAUA,iEAKoC;AAOpC,qEAA+E;AAC/E,2CAAkE;AAClE,mCAAiC;AAEjC,iDAAgF;AAChF,+EAAgG;AAEhG,oEAAyE;AA+BzE,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAkChC,IAAK,SAGJ;AAHD,WAAK,SAAS;IACZ,8BAAiB,CAAA;IACjB,kCAAqB,CAAA;AACvB,CAAC,EAHI,SAAS,KAAT,SAAS,QAGb;AAoBD;;GAEG;AACU,QAAA,cAAc,GAAG,sBAAsB,CAAC;AAiDrD;;;;;;;;;;GAUG;AACH,KAAK,UAAU,yBAAyB,CAAC,EACvC,IAAI,EACJ,EAAE,GAIH;IACC,MAAM,cAAc,GAAG,KAAK,CAAC;IAC7B,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,IAAA,0CAA+B,EAClD,EAAE,EACF,IAAI,EACJ,cAAc,CACf,CAAC;QACF,OAAO,MAAM,CAAC,cAAc,CAAC;KAC9B;IAAC,OAAO,KAAK,EAAE;QACd,IACE,KAAK,YAAY,KAAK;YACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,0CAA0C,CAAC,EAClE;YACA,OAAO,IAAI,CAAC;SACb;QACD,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AAED,MAAM,4BAA4B,GAAG;IACnC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;CAChD,CAAC;AAEF;;;;GAIG;AACI,MAAM,mCAAmC,GAC9C,GAA8B,EAAE;IAC9B,OAAO;QACL,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC,CAAC;AALS,QAAA,mCAAmC,uCAK5C;AAOJ;;;GAGG;AACH,MAAa,oBAAqB,SAAQ,IAAA,oDAA+B,GAIxE;IAuBC;;;;;;;;;OASG;IACH,YAAY,EACV,QAAQ,GAAG,gBAAgB,EAC3B,QAAQ,GAAG,KAAK,EAChB,kBAAkB,EAClB,SAAS,EACT,KAAK,GAON;QACC,KAAK,CAAC;YACJ,IAAI,EAAE,sBAAc;YACpB,SAAS;YACT,KAAK,EAAE,EAAE,GAAG,IAAA,2CAAmC,GAAE,EAAE,GAAG,KAAK,EAAE;YAC7D,QAAQ,EAAE,4BAA4B;SACvC,CAAC,CAAC;;QAlDL,+CAAwC;QAExC,0CAAa,SAAS,CAAC,QAAQ,EAAC;QAEhC,2DAAgD;QAEhD,6DAA2E,EAAE,EAAC;QAE9E,0DAA2B;QAE3B,iDAAmB;QAEnB,gDAAc;QAEd,+CAAgB;QAEhB,iDAAkB;QAElB,kDAA+C;QAE/C,0DAA+D;QAgC7D,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACjC,uBAAA,IAAI,4CAAuB,kBAAkB,MAAA,CAAC;QAC9C,uBAAA,IAAI,kCAAa,QAAQ,MAAA,CAAC;QAC1B,uBAAA,IAAI,kCAAa,QAAQ,MAAA,CAAC;QAE1B,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,GACtD,uBAAA,IAAI,kFAAqB,MAAzB,IAAI,CAAuB,CAAC;QAC9B,uBAAA,IAAI,iCAAY,cAAc,MAAA,CAAC;QAC/B,uBAAA,IAAI,gCAAW,aAAa,MAAA,CAAC;QAE7B,uBAAA,IAAI,2CAAsB,uBAAA,IAAI,iFAAoB,MAAxB,IAAI,CAAsB,CAAC,EAAE,MAAA,CAAC;QAExD,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,uBAAA,IAAI,uFAA0B,MAA9B,IAAI,CAA4B,CAAC;QAC1E,uBAAA,IAAI,mCAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,2CAAsB,iBAAiB,MAAA,CAAC;QAE5C,uBAAA,IAAI,2FAA8B,MAAlC,IAAI,CAAgC,CAAC;QAErC,uBAAA,IAAI,4FAA+B,MAAnC,IAAI,CAAiC,CAAC;IACxC,CAAC;IA8GD;;OAEG;IACH,MAAM;QACJ,uBAAA,IAAI,kCAAa,KAAK,MAAA,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,uBAAA,IAAI,kCAAa,IAAI,MAAA,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,uBAAA,IAAI,uEAAU,MAAd,IAAI,CAAY,CAAC;QACjB,uBAAA,IAAI,mCAAc,SAAS,CAAC,MAAM,MAAA,CAAC;QACnC,MAAM,uBAAA,IAAI,mEAAM,MAAV,IAAI,CAAQ,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,uBAAA,IAAI,uEAAU,MAAd,IAAI,CAAY,CAAC;QACjB,uBAAA,IAAI,mCAAc,SAAS,CAAC,QAAQ,MAAA,CAAC;IACvC,CAAC;IAiED;;OAEG;IACH,KAAK,CAAC,mBAAmB;QACvB,MAAM,IAAI,CAAC,4BAA4B,CAAC;YACtC,OAAO,EAAE,uBAAA,IAAI,qCAAS;YACtB,cAAc,EAAE,uBAAA,IAAI,oCAAQ;SAC7B,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,4BAA4B,CAAC,EACjC,OAAO,EACP,cAAc,GAIf;QACC,IAAI,uBAAA,IAAI,sCAAU,EAAE;YAClB,OAAO;SACR;QAED,MAAM,cAAc,GAAG,uBAAA,IAAI,gFAAmB,MAAvB,IAAI,EAAoB,OAAO,CAAC,CAAC;QAExD,MAAM,SAAS,GAAuB,GAAG,OAAO,IAAI,cAAc,EAAE,CAAC;QACrE,IAAI,SAAS,IAAI,uBAAA,IAAI,0DAA8B,EAAE;YACnD,kCAAkC;YAClC,sEAAsE;YACtE,8BAA8B;YAC9B,MAAM,uBAAA,IAAI,0DAA8B,CAAC,SAAS,CAAC,CAAC;YACpD,OAAO;SACR;QAED,MAAM,EACJ,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,YAAY,GACrB,GAAG,IAAA,6BAAqB,EAAC,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,uBAAA,IAAI,0DAA8B,CAAC,SAAS,CAAC,GAAG,gBAAgB,CAAC;QAEjE,IAAI;YACF,MAAM,oBAAoB,GAAG,MAAM,uBAAA,IAAI,uFAA0B,MAA9B,IAAI,EAA2B;gBAChE,cAAc;gBACd,OAAO;gBACP,cAAc;aACf,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG;gBACjB,CAAC,OAAO,CAAC,EAAE;oBACT,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;iBAChC;aACF,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,KAAK,CAAC,UAAU,GAAG;oBACjB,GAAG,KAAK,CAAC,UAAU;oBACnB,GAAG,UAAU;iBACd,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,eAAe,EAAE,CAAC;SACnB;QAAC,OAAO,KAAc,EAAE;YACvB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,KAAK,CAAC;SACb;gBAAS;YACR,OAAO,uBAAA,IAAI,0DAA8B,CAAC,SAAS,CAAC,CAAC;SACtD;IACH,CAAC;IAyDD;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,EAAE,OAAO,EAA0B;QACpD,MAAM,EAAE,8BAA8B,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAClE,4BAA4B,CAC7B,CAAC;QAEF,MAAM,oBAAoB,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,oBAAoB,EAAE;YACzB,OAAO,CAAC,KAAK,CACX,oEAAoE,OAAO,EAAE,CAC9E,CAAC;YACF,OAAO;SACR;QAED,MAAM,IAAI,CAAC,4BAA4B,CAAC;YACtC,OAAO;YACP,cAAc,EAAE,oBAAoB,CAAC,cAAc;SACpD,CAAC,CAAC;IACL,CAAC;IAmJD;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;YACf,OAAO,IAAA,2CAAmC,GAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA3kBD,oDA2kBC;;IA5fG,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,8BAA8B;IAC9B,gFAAgF;IAChF,kEAAkE;IAClE,KAAK,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,EAAE;QACzC,IAAI,uBAAA,IAAI,sCAAU,EAAE;YAClB,OAAO;SACR;QAED,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI,GAAG,CAAC;gBACT,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;gBACzB,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC;aAClC,CAAC;SACM,CAAC;QAEX,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CACtC,CAAC,OAAO,EAAE,EAAE,CACV,CAAC,IAAA,gBAAO,EAAC,uBAAA,IAAI,uCAAW,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;YACtD,CAAC,IAAA,gBAAO,EACN,uBAAA,IAAI,+CAAmB,CAAC,OAAO,CAAC,EAChC,iBAAiB,CAAC,OAAO,CAAC,CAC3B,CACJ,CAAC;QAEF,uBAAA,IAAI,mCAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,2CAAsB,iBAAiB,MAAA,CAAC;QAE5C,MAAM,EAAE,8BAA8B,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAClE,4BAA4B,CAC7B,CAAC;QAEF,MAAM,OAAO,CAAC,UAAU,CACtB,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACrC,MAAM,cAAc,GAClB,8BAA8B,CAAC,OAAc,CAAC,EAAE,cAAc,CAAC;YAEjE,IAAI,cAAc,EAAE;gBAClB,MAAM,IAAI,CAAC,4BAA4B,CAAC;oBACtC,OAAO,EAAE,OAAc;oBACvB,cAAc;iBACf,CAAC,CAAC;aACJ;QACH,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,EACD,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,EAAE;QACnC,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC1C,CAAC,CACF,CAAC;AACJ,CAAC;IAGC,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,+BAA+B;IAC/B,gFAAgF;IAChF,kEAAkE;IAClE,KAAK,EAAE,EAAE,uBAAuB,EAAE,EAAE,OAAO,EAAE,EAAE;QAC7C,MAAM,EACJ,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GACnC,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC3B,wCAAwC,EACxC,uBAAuB,CACxB,CAAC;QAEF,IAAI,uBAAA,IAAI,qCAAS,KAAK,OAAO,IAAI,uBAAA,IAAI,oCAAQ,KAAK,MAAM,EAAE;YACxD,uBAAA,IAAI,iCAAY,OAAO,MAAA,CAAC;YACxB,uBAAA,IAAI,gCAAW,MAAM,MAAA,CAAC;YACtB,IAAI,uBAAA,IAAI,uCAAW,KAAK,SAAS,CAAC,MAAM,EAAE;gBACxC,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;aAClC;SACF;QAED,oCAAoC;QACpC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;YAC3B,IACE,KAAK,CAAC,EAAE,KAAK,QAAQ;gBACrB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,gCAAgC,EAClD;gBACA,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAQ,CAAC;gBAC5C,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;oBACpB,OAAO,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;gBAC1C,CAAC,CAAC,CAAC;aACJ;SACF;IACH,CAAC,CACF,CAAC;AACJ,CAAC,6FAQkB,OAAY;IAC7B,MAAM,SAAS,GAAG,CAAC,SAA6C,EAAE,EAAE,CAClE,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAChD,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,IAAA,wBAAK,EAAC,IAAA,uCAAoB,EAAC,OAAO,CAAC,CAAC,CAAC,CAClE,CAAC;IAEJ,MAAM,cAAc,GAAG,SAAS,CAAC,uBAAA,IAAI,uCAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,MAAM,sBAAsB,GAAG,SAAS,CAAC,uBAAA,IAAI,+CAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAE3E,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,cAAc,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC7E,CAAC;IAkCC,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC/C,uCAAuC,CACxC,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC;IAMC,MAAM,EAAE,uBAAuB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC3D,4BAA4B,CAC7B,CAAC;IACF,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC7C,wCAAwC,EACxC,uBAAuB,CACxB,CAAC;IACF,OAAO;QACL,OAAO,EAAE,aAAa,CAAC,aAAa,CAAC,OAAO;QAC5C,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM;KAC3C,CAAC;AACJ,CAAC;IAMC,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAChE,2BAA2B,CAC5B,CAAC;IAEF,OAAO;QACL,SAAS;QACT,iBAAiB;KAClB,CAAC;AACJ,CAAC;IAMC,IAAI,uBAAA,IAAI,oCAAQ,EAAE;QAChB,YAAY,CAAC,uBAAA,IAAI,oCAAQ,CAAC,CAAC;KAC5B;AACH,CAAC;AAED;;GAEG;AACH,KAAK;IACH,MAAM,IAAA,gCAAa,EAAC,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAEtD,qEAAqE;IACrE,qEAAqE;IACrE,uBAAA,IAAI,gCAAW,UAAU,CAAC,GAAG,EAAE;QAC7B,gFAAgF;QAChF,mEAAmE;QACnE,uBAAA,IAAI,mEAAM,MAAV,IAAI,CAAQ,CAAC;IACf,CAAC,EAAE,uBAAA,IAAI,sCAAU,CAAC,MAAA,CAAC;AACrB,CAAC;AA4ED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,KAAK,yDAA2B,EAC9B,cAAc,EACd,OAAO,EACP,cAAc,GAKf;IACC,IAAI,CAAC,uBAAA,IAAI,gDAAoB,CAAC,wBAAwB,CAAC,OAAO,CAAC,EAAE;QAC/D,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE;YACjD,GAAG,GAAG;gBACJ,GAAG,GAAG;gBACN,CAAC,YAAY,CAAC,EAAE,SAAS;aAC1B,CAAC;YAEF,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC,CAAC;KACR;IAED,IAAI,uBAAA,IAAI,gDAAoB,CAAC,yBAAyB,CAAC,cAAc,CAAC,EAAE;QACtE,OAAO,MAAM,uBAAA,IAAI,iHAAoD,MAAxD,IAAI,EAAqD;YACpE,cAAc;YACd,OAAO;YACP,cAAc;SACf,CAAC,CAAC;KACJ;IAED,OAAO,MAAM,uBAAA,IAAI,mHAAsD,MAA1D,IAAI,EAAuD;QACtE,OAAO;QACP,cAAc;QACd,cAAc;KACf,CAAC,CAAC;AACL,CAAC;AA2BD;;;;;;;;;;;GAWG;AACH,KAAK,mFAAqD,EACxD,cAAc,EACd,OAAO,EACP,cAAc,GAKf;IACC,IAAI,0BAA0B,CAAC;IAC/B,MAAM,yBAAyB,GAAG,MAAM,IAAA,oCAAuB,EAG7D;QACA,MAAM,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,IAAI,EAAE;QAClC,SAAS,EAAE,oCAAuB;QAClC,SAAS,EAAE,KAAK,EAAE,4BAA4B,EAAE,KAAK,EAAE,EAAE;YACvD,MAAM,iCAAiC,GACrC,MAAM,uBAAA,IAAI,gDAAoB,CAAC,gBAAgB,CAAC;gBAC9C,cAAc,EAAE,KAAK;gBACrB,OAAO;gBACP,QAAQ,EAAE,cAAc;aACzB,CAAC,CAAC;YAEL,OAAO;gBACL,GAAG,4BAA4B;gBAC/B,GAAG,iCAAiC;aACrC,CAAC;QACJ,CAAC;QACD,aAAa,EAAE,EAAE;KAClB,CAAC,CAAC;IACH,0BAA0B,GAAG,yBAAyB,CAAC;IAEvD,yBAAyB;IACzB,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE;QAC/B,MAAM,gCAAgC,GACpC,MAAM,uBAAA,IAAI,gDAAoB,CAAC,gBAAgB,CAAC;YAC9C,cAAc,EAAE,EAAE;YAClB,OAAO;YACP,QAAQ,EAAE,cAAc;SACzB,CAAC,CAAC;QAEL,0BAA0B,GAAG;YAC3B,CAAC,IAAA,iCAAqB,EAAC,OAAO,CAAC,CAAC,EAAE;gBAChC,QAAQ,EAAE,cAAc;gBACxB,GAAG,gCAAgC,CAAC,IAAA,iCAAqB,EAAC,OAAO,CAAC,CAAC;aACpE;SACF,CAAC;KACH;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC,MAAM,CACtD,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE;QAC7B,GAAG,GAAG;YACJ,GAAG,GAAG;YACN,CAAC,YAAY,CAAC,EAAE,EAAE,GAAG,KAAK,EAAE;SAC7B,CAAC;QAEF,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,CACH,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,qFAAuD,EAC1D,OAAO,EACP,cAAc,EACd,cAAc,GAKf;IACC,MAAM,CACJ,4BAA4B,EAC5B,8CAA8C,EAC/C,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpB,uBAAA,IAAI,iHAAoD,MAAxD,IAAI,EAAqD;YACvD,cAAc;YACd,OAAO;YACP,cAAc,EAAE,wCAAqB;SACtC,CAAC;QACF,yBAAyB,CAAC;YACxB,IAAI,EAAE,wCAAqB;YAC3B,EAAE,EAAE,cAAc;SACnB,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,8CAA8C,KAAK,IAAI,EAAE;QAC3D,OAAO,EAAE,CAAC;KACX;IAED,qEAAqE;IACrE,MAAM,uBAAuB,GAAG,CAAC,KAAyB,EAAE,EAAE,CAC5D,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QACnC,CAAC,CAAC,KAAK,GAAG,8CAA8C;QACxD,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,4BAA4B,GAAG,MAAM,CAAC,OAAO,CACjD,4BAA4B,CAC7B,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE;QACtC,GAAG,GAAG;YACJ,GAAG,GAAG;YACN,CAAC,YAAY,CAAC,EAAE;gBACd,GAAG,KAAK;gBACR,QAAQ,EAAE,cAAc;gBACxB,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC;gBAC3C,SAAS,EAAE,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC;gBACnD,WAAW,EAAE,uBAAuB,CAAC,KAAK,CAAC,WAAW,CAAC;gBACvD,UAAU,EAAE,uBAAuB,CAAC,KAAK,CAAC,UAAU,CAAC;gBACrD,WAAW,EAAE,uBAAuB,CAAC,KAAK,CAAC,WAAW,CAAC;gBACvD,MAAM,EAAE,uBAAuB,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC7C,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC;gBAC3C,gBAAgB,EAAE,uBAAuB,CAAC,KAAK,CAAC,gBAAgB,CAAC;aAClE;SACF,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,4BAA4B,CAAC;AACtC,CAAC;AAYH,kBAAe,oBAAoB,CAAC","sourcesContent":["import type {\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedEvmAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n FALL_BACK_VS_CURRENCY,\n toHex,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-api';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { createDeferredPromise, type Hex } from '@metamask/utils';\nimport { isEqual } from 'lodash';\n\nimport { reduceInBatchesSerially, TOKEN_PRICES_BATCH_SIZE } from './assetsUtil';\nimport { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from './crypto-compare-service';\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\nimport type {\n TokensControllerGetStateAction,\n TokensControllerStateChangeEvent,\n TokensControllerState,\n} from './TokensController';\n\n/**\n * @type Token\n *\n * Token representation\n * @property address - Hex address of the token contract\n * @property decimals - Number of decimals the token uses\n * @property symbol - Symbol of the token\n * @property aggregators - An array containing the token's aggregators\n * @property image - Image of the token, url or bit32 image\n * @property hasBalanceError - 'true' if there is an error while updating the token balance\n * @property isERC721 - 'true' if the token is a ERC721 token\n * @property name - Name of the token\n */\nexport type Token = {\n address: string;\n decimals: number;\n symbol: string;\n aggregators?: string[];\n image?: string;\n hasBalanceError?: boolean;\n isERC721?: boolean;\n name?: string;\n};\n\nconst DEFAULT_INTERVAL = 180000;\n\nexport type ContractExchangeRates = {\n [address: string]: number | undefined;\n};\n\nexport type MarketDataDetails = {\n tokenAddress: `0x${string}`;\n currency: string;\n allTimeHigh: number;\n allTimeLow: number;\n circulatingSupply: number;\n dilutedMarketCap: number;\n high1d: number;\n low1d: number;\n marketCap: number;\n marketCapPercentChange1d: number;\n price: number;\n priceChange1d: number;\n pricePercentChange1d: number;\n pricePercentChange1h: number;\n pricePercentChange1y: number;\n pricePercentChange7d: number;\n pricePercentChange14d: number;\n pricePercentChange30d: number;\n pricePercentChange200d: number;\n totalVolume: number;\n};\n\n/**\n * Represents a mapping of token contract addresses to their market data.\n */\nexport type ContractMarketData = Record<Hex, MarketDataDetails>;\n\nenum PollState {\n Active = 'Active',\n Inactive = 'Inactive',\n}\n\n/**\n * The external actions available to the {@link TokenRatesController}.\n */\nexport type AllowedActions =\n | TokensControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedAccountAction;\n\n/**\n * The external events available to the {@link TokenRatesController}.\n */\nexport type AllowedEvents =\n | TokensControllerStateChangeEvent\n | NetworkControllerStateChangeEvent\n | AccountsControllerSelectedEvmAccountChangeEvent;\n\n/**\n * The name of the {@link TokenRatesController}.\n */\nexport const controllerName = 'TokenRatesController';\n\n/**\n * @type TokenRatesState\n *\n * Token rates controller state\n * @property marketData - Market data for tokens, keyed by chain ID and then token contract address.\n */\nexport type TokenRatesControllerState = {\n marketData: Record<Hex, Record<Hex, MarketDataDetails>>;\n};\n\n/**\n * The action that can be performed to get the state of the {@link TokenRatesController}.\n */\nexport type TokenRatesControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n TokenRatesControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link TokenRatesController}.\n */\nexport type TokenRatesControllerActions = TokenRatesControllerGetStateAction;\n\n/**\n * The event that {@link TokenRatesController} can emit.\n */\nexport type TokenRatesControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n TokenRatesControllerState\n>;\n\n/**\n * The events that {@link TokenRatesController} can emit.\n */\nexport type TokenRatesControllerEvents = TokenRatesControllerStateChangeEvent;\n\n/**\n * The messenger of the {@link TokenRatesController} for communication.\n */\nexport type TokenRatesControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n TokenRatesControllerActions | AllowedActions,\n TokenRatesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Uses the CryptoCompare API to fetch the exchange rate between one currency\n * and another, i.e., the multiplier to apply the amount of one currency in\n * order to convert it to another.\n *\n * @param args - The arguments to this function.\n * @param args.from - The currency to convert from.\n * @param args.to - The currency to convert to.\n * @returns The exchange rate between `fromCurrency` to `toCurrency` if one\n * exists, or null if one does not.\n */\nasync function getCurrencyConversionRate({\n from,\n to,\n}: {\n from: string;\n to: string;\n}) {\n const includeUSDRate = false;\n try {\n const result = await fetchNativeCurrencyExchangeRate(\n to,\n from,\n includeUSDRate,\n );\n return result.conversionRate;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('market does not exist for this coin pair')\n ) {\n return null;\n }\n throw error;\n }\n}\n\nconst tokenRatesControllerMetadata = {\n marketData: { persist: true, anonymous: false },\n};\n\n/**\n * Get the default {@link TokenRatesController} state.\n *\n * @returns The default {@link TokenRatesController} state.\n */\nexport const getDefaultTokenRatesControllerState =\n (): TokenRatesControllerState => {\n return {\n marketData: {},\n };\n };\n\n/** The input to start polling for the {@link TokenRatesController} */\nexport type TokenRatesPollingInput = {\n chainId: Hex;\n};\n\n/**\n * Controller that passively polls on a set interval for token-to-fiat exchange rates\n * for tokens stored in the TokensController\n */\nexport class TokenRatesController extends StaticIntervalPollingController<TokenRatesPollingInput>()<\n typeof controllerName,\n TokenRatesControllerState,\n TokenRatesControllerMessenger\n> {\n #handle?: ReturnType<typeof setTimeout>;\n\n #pollState = PollState.Inactive;\n\n #tokenPricesService: AbstractTokenPricesService;\n\n #inProcessExchangeRateUpdates: Record<`${Hex}:${string}`, Promise<void>> = {};\n\n #selectedAccountId: string;\n\n #disabled: boolean;\n\n #chainId: Hex;\n\n #ticker: string;\n\n #interval: number;\n\n #allTokens: TokensControllerState['allTokens'];\n\n #allDetectedTokens: TokensControllerState['allDetectedTokens'];\n\n /**\n * Creates a TokenRatesController instance.\n *\n * @param options - The controller options.\n * @param options.interval - The polling interval in ms\n * @param options.disabled - Boolean to track if network requests are blocked\n * @param options.tokenPricesService - An object in charge of retrieving token price\n * @param options.messenger - The controller messenger instance for communication\n * @param options.state - Initial state to set on this controller\n */\n constructor({\n interval = DEFAULT_INTERVAL,\n disabled = false,\n tokenPricesService,\n messenger,\n state,\n }: {\n interval?: number;\n disabled?: boolean;\n tokenPricesService: AbstractTokenPricesService;\n messenger: TokenRatesControllerMessenger;\n state?: Partial<TokenRatesControllerState>;\n }) {\n super({\n name: controllerName,\n messenger,\n state: { ...getDefaultTokenRatesControllerState(), ...state },\n metadata: tokenRatesControllerMetadata,\n });\n\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n this.#disabled = disabled;\n this.#interval = interval;\n\n const { chainId: currentChainId, ticker: currentTicker } =\n this.#getChainIdAndTicker();\n this.#chainId = currentChainId;\n this.#ticker = currentTicker;\n\n this.#selectedAccountId = this.#getSelectedAccount().id;\n\n const { allTokens, allDetectedTokens } = this.#getTokensControllerState();\n this.#allTokens = allTokens;\n this.#allDetectedTokens = allDetectedTokens;\n\n this.#subscribeToTokensStateChange();\n\n this.#subscribeToNetworkStateChange();\n }\n\n #subscribeToTokensStateChange() {\n this.messagingSystem.subscribe(\n 'TokensController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ allTokens, allDetectedTokens }) => {\n if (this.#disabled) {\n return;\n }\n\n const chainIds = [\n ...new Set([\n ...Object.keys(allTokens),\n ...Object.keys(allDetectedTokens),\n ]),\n ] as Hex[];\n\n const chainIdsToUpdate = chainIds.filter(\n (chainId) =>\n !isEqual(this.#allTokens[chainId], allTokens[chainId]) ||\n !isEqual(\n this.#allDetectedTokens[chainId],\n allDetectedTokens[chainId],\n ),\n );\n\n this.#allTokens = allTokens;\n this.#allDetectedTokens = allDetectedTokens;\n\n const { networkConfigurationsByChainId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n await Promise.allSettled(\n chainIdsToUpdate.map(async (chainId) => {\n const nativeCurrency =\n networkConfigurationsByChainId[chainId as Hex]?.nativeCurrency;\n\n if (nativeCurrency) {\n await this.updateExchangeRatesByChainId({\n chainId: chainId as Hex,\n nativeCurrency,\n });\n }\n }),\n );\n },\n ({ allTokens, allDetectedTokens }) => {\n return { allTokens, allDetectedTokens };\n },\n );\n }\n\n #subscribeToNetworkStateChange() {\n this.messagingSystem.subscribe(\n 'NetworkController:stateChange',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ selectedNetworkClientId }, patches) => {\n const {\n configuration: { chainId, ticker },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n if (this.#chainId !== chainId || this.#ticker !== ticker) {\n this.#chainId = chainId;\n this.#ticker = ticker;\n if (this.#pollState === PollState.Active) {\n await this.updateExchangeRates();\n }\n }\n\n // Remove state for deleted networks\n for (const patch of patches) {\n if (\n patch.op === 'remove' &&\n patch.path[0] === 'networkConfigurationsByChainId'\n ) {\n const removedChainId = patch.path[1] as Hex;\n this.update((state) => {\n delete state.marketData[removedChainId];\n });\n }\n }\n },\n );\n }\n\n /**\n * Get the tokens for the given chain.\n *\n * @param chainId - The chain ID.\n * @returns The list of tokens addresses for the current chain\n */\n #getTokenAddresses(chainId: Hex): Hex[] {\n const getTokens = (allTokens: Record<Hex, { address: string }[]>) =>\n Object.values(allTokens ?? {}).flatMap((tokens) =>\n tokens.map(({ address }) => toHex(toChecksumHexAddress(address))),\n );\n\n const tokenAddresses = getTokens(this.#allTokens[chainId]);\n const detectedTokenAddresses = getTokens(this.#allDetectedTokens[chainId]);\n\n return [...new Set([...tokenAddresses, ...detectedTokenAddresses])].sort();\n }\n\n /**\n * Allows controller to make active and passive polling requests\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Blocks controller from making network calls\n */\n disable(): void {\n this.#disabled = true;\n }\n\n /**\n * Start (or restart) polling.\n */\n async start() {\n this.#stopPoll();\n this.#pollState = PollState.Active;\n await this.#poll();\n }\n\n /**\n * Stop polling.\n */\n stop() {\n this.#stopPoll();\n this.#pollState = PollState.Inactive;\n }\n\n #getSelectedAccount(): InternalAccount {\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n\n return selectedAccount;\n }\n\n #getChainIdAndTicker(): {\n chainId: Hex;\n ticker: string;\n } {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const networkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n return {\n chainId: networkClient.configuration.chainId,\n ticker: networkClient.configuration.ticker,\n };\n }\n\n #getTokensControllerState(): {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n } {\n const { allTokens, allDetectedTokens } = this.messagingSystem.call(\n 'TokensController:getState',\n );\n\n return {\n allTokens,\n allDetectedTokens,\n };\n }\n\n /**\n * Clear the active polling timer, if present.\n */\n #stopPoll() {\n if (this.#handle) {\n clearTimeout(this.#handle);\n }\n }\n\n /**\n * Poll for exchange rate updates.\n */\n async #poll() {\n await safelyExecute(() => this.updateExchangeRates());\n\n // Poll using recursive `setTimeout` instead of `setInterval` so that\n // requests don't stack if they take longer than the polling interval\n this.#handle = setTimeout(() => {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#poll();\n }, this.#interval);\n }\n\n /**\n * Updates exchange rates for all tokens.\n */\n async updateExchangeRates() {\n await this.updateExchangeRatesByChainId({\n chainId: this.#chainId,\n nativeCurrency: this.#ticker,\n });\n }\n\n /**\n * Updates exchange rates for all tokens.\n *\n * @param options - The options to fetch exchange rates.\n * @param options.chainId - The chain ID.\n * @param options.nativeCurrency - The ticker for the chain.\n */\n async updateExchangeRatesByChainId({\n chainId,\n nativeCurrency,\n }: {\n chainId: Hex;\n nativeCurrency: string;\n }) {\n if (this.#disabled) {\n return;\n }\n\n const tokenAddresses = this.#getTokenAddresses(chainId);\n\n const updateKey: `${Hex}:${string}` = `${chainId}:${nativeCurrency}`;\n if (updateKey in this.#inProcessExchangeRateUpdates) {\n // This prevents redundant updates\n // This promise is resolved after the in-progress update has finished,\n // and state has been updated.\n await this.#inProcessExchangeRateUpdates[updateKey];\n return;\n }\n\n const {\n promise: inProgressUpdate,\n resolve: updateSucceeded,\n reject: updateFailed,\n } = createDeferredPromise({ suppressUnhandledRejection: true });\n this.#inProcessExchangeRateUpdates[updateKey] = inProgressUpdate;\n\n try {\n const contractInformations = await this.#fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n\n const marketData = {\n [chainId]: {\n ...(contractInformations ?? {}),\n },\n };\n\n this.update((state) => {\n state.marketData = {\n ...state.marketData,\n ...marketData,\n };\n });\n updateSucceeded();\n } catch (error: unknown) {\n updateFailed(error);\n throw error;\n } finally {\n delete this.#inProcessExchangeRateUpdates[updateKey];\n }\n }\n\n /**\n * Uses the token prices service to retrieve exchange rates for tokens in a\n * particular currency.\n *\n * If the price API does not support the given chain ID, returns an empty\n * object.\n *\n * If the price API does not support the given currency, retrieves exchange\n * rates in a known currency instead, then converts those rates using the\n * exchange rate between the known currency and desired currency.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * exchange rates.\n * @returns A map from token address to its exchange rate in the native\n * currency, or an empty map if no exchange rates can be obtained for the\n * chain ID.\n */\n async #fetchAndMapExchangeRates({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractMarketData> {\n if (!this.#tokenPricesService.validateChainIdSupported(chainId)) {\n return tokenAddresses.reduce((obj, tokenAddress) => {\n obj = {\n ...obj,\n [tokenAddress]: undefined,\n };\n\n return obj;\n }, {});\n }\n\n if (this.#tokenPricesService.validateCurrencySupported(nativeCurrency)) {\n return await this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n });\n }\n\n return await this.#fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n chainId,\n tokenAddresses,\n nativeCurrency,\n });\n }\n\n /**\n * Updates token rates for the given networkClientId\n *\n * @param input - The input for the poll.\n * @param input.chainId - The chain id to poll token rates on.\n */\n async _executePoll({ chainId }: TokenRatesPollingInput): Promise<void> {\n const { networkConfigurationsByChainId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const networkConfiguration = networkConfigurationsByChainId[chainId];\n if (!networkConfiguration) {\n console.error(\n `TokenRatesController: No network configuration found for chainId ${chainId}`,\n );\n return;\n }\n\n await this.updateExchangeRatesByChainId({\n chainId,\n nativeCurrency: networkConfiguration.nativeCurrency,\n });\n }\n\n /**\n * Retrieves prices in the given currency for the given tokens on the given\n * chain. Ensures that token addresses are checksum addresses.\n *\n * @param args - The arguments to this function.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.chainId - The EIP-155 ID of the chain where the tokens live.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency,\n }: {\n tokenAddresses: Hex[];\n chainId: Hex;\n nativeCurrency: string;\n }): Promise<ContractMarketData> {\n let contractNativeInformations;\n const tokenPricesByTokenAddress = await reduceInBatchesSerially<\n Hex,\n Awaited<ReturnType<AbstractTokenPricesService['fetchTokenPrices']>>\n >({\n values: [...tokenAddresses].sort(),\n batchSize: TOKEN_PRICES_BATCH_SIZE,\n eachBatch: async (allTokenPricesByTokenAddress, batch) => {\n const tokenPricesByTokenAddressForBatch =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenAddresses: batch,\n chainId,\n currency: nativeCurrency,\n });\n\n return {\n ...allTokenPricesByTokenAddress,\n ...tokenPricesByTokenAddressForBatch,\n };\n },\n initialResult: {},\n });\n contractNativeInformations = tokenPricesByTokenAddress;\n\n // fetch for native token\n if (tokenAddresses.length === 0) {\n const contractNativeInformationsNative =\n await this.#tokenPricesService.fetchTokenPrices({\n tokenAddresses: [],\n chainId,\n currency: nativeCurrency,\n });\n\n contractNativeInformations = {\n [getNativeTokenAddress(chainId)]: {\n currency: nativeCurrency,\n ...contractNativeInformationsNative[getNativeTokenAddress(chainId)],\n },\n };\n }\n return Object.entries(contractNativeInformations).reduce(\n (obj, [tokenAddress, token]) => {\n obj = {\n ...obj,\n [tokenAddress]: { ...token },\n };\n\n return obj;\n },\n {},\n );\n }\n\n /**\n * If the price API does not support a given native currency, then we need to\n * convert it to a fallback currency and feed that currency into the price\n * API, then convert the prices to our desired native currency.\n *\n * @param args - The arguments to this function.\n * @param args.chainId - The chain id to fetch prices for.\n * @param args.tokenAddresses - Addresses for tokens.\n * @param args.nativeCurrency - The native currency in which to request\n * prices.\n * @returns A map of the token addresses (as checksums) to their prices in the\n * native currency.\n */\n async #fetchAndMapExchangeRatesForUnsupportedNativeCurrency({\n chainId,\n tokenAddresses,\n nativeCurrency,\n }: {\n chainId: Hex;\n tokenAddresses: Hex[];\n nativeCurrency: string;\n }): Promise<ContractMarketData> {\n const [\n contractExchangeInformations,\n fallbackCurrencyToNativeCurrencyConversionRate,\n ] = await Promise.all([\n this.#fetchAndMapExchangeRatesForSupportedNativeCurrency({\n tokenAddresses,\n chainId,\n nativeCurrency: FALL_BACK_VS_CURRENCY,\n }),\n getCurrencyConversionRate({\n from: FALL_BACK_VS_CURRENCY,\n to: nativeCurrency,\n }),\n ]);\n\n if (fallbackCurrencyToNativeCurrencyConversionRate === null) {\n return {};\n }\n\n // Converts the price in the fallback currency to the native currency\n const convertFallbackToNative = (value: number | undefined) =>\n value !== undefined && value !== null\n ? value * fallbackCurrencyToNativeCurrencyConversionRate\n : undefined;\n\n const updatedContractExchangeRates = Object.entries(\n contractExchangeInformations,\n ).reduce((acc, [tokenAddress, token]) => {\n acc = {\n ...acc,\n [tokenAddress]: {\n ...token,\n currency: nativeCurrency,\n price: convertFallbackToNative(token.price),\n marketCap: convertFallbackToNative(token.marketCap),\n allTimeHigh: convertFallbackToNative(token.allTimeHigh),\n allTimeLow: convertFallbackToNative(token.allTimeLow),\n totalVolume: convertFallbackToNative(token.totalVolume),\n high1d: convertFallbackToNative(token.high1d),\n low1d: convertFallbackToNative(token.low1d),\n dilutedMarketCap: convertFallbackToNative(token.dilutedMarketCap),\n },\n };\n return acc;\n }, {});\n\n return updatedContractExchangeRates;\n }\n\n /**\n * Reset the controller state to the default state.\n */\n resetState() {\n this.update(() => {\n return getDefaultTokenRatesControllerState();\n });\n }\n}\n\nexport default TokenRatesController;\n"]}
|
|
@@ -108,14 +108,14 @@ export type TokenRatesPollingInput = {
|
|
|
108
108
|
chainId: Hex;
|
|
109
109
|
};
|
|
110
110
|
declare const TokenRatesController_base: (abstract new (...args: any[]) => {
|
|
111
|
-
readonly "__#
|
|
112
|
-
"__#
|
|
111
|
+
readonly "__#11@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
112
|
+
"__#11@#intervalLength": number | undefined;
|
|
113
113
|
setIntervalLength(intervalLength: number): void;
|
|
114
114
|
getIntervalLength(): number | undefined;
|
|
115
115
|
_startPolling(input: TokenRatesPollingInput): void;
|
|
116
116
|
_stopPollingByPollingTokenSetId(key: string): void;
|
|
117
|
-
readonly "__#
|
|
118
|
-
"__#
|
|
117
|
+
readonly "__#3@#pollingTokenSets": Map<string, Set<string>>;
|
|
118
|
+
"__#3@#callbacks": Map<string, Set<(input: TokenRatesPollingInput) => void>>;
|
|
119
119
|
_executePoll(input: TokenRatesPollingInput): Promise<void>;
|
|
120
120
|
startPolling(input: TokenRatesPollingInput): string;
|
|
121
121
|
stopAllPolling(): void;
|
|
@@ -108,14 +108,14 @@ export type TokenRatesPollingInput = {
|
|
|
108
108
|
chainId: Hex;
|
|
109
109
|
};
|
|
110
110
|
declare const TokenRatesController_base: (abstract new (...args: any[]) => {
|
|
111
|
-
readonly "__#
|
|
112
|
-
"__#
|
|
111
|
+
readonly "__#11@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
112
|
+
"__#11@#intervalLength": number | undefined;
|
|
113
113
|
setIntervalLength(intervalLength: number): void;
|
|
114
114
|
getIntervalLength(): number | undefined;
|
|
115
115
|
_startPolling(input: TokenRatesPollingInput): void;
|
|
116
116
|
_stopPollingByPollingTokenSetId(key: string): void;
|
|
117
|
-
readonly "__#
|
|
118
|
-
"__#
|
|
117
|
+
readonly "__#3@#pollingTokenSets": Map<string, Set<string>>;
|
|
118
|
+
"__#3@#callbacks": Map<string, Set<(input: TokenRatesPollingInput) => void>>;
|
|
119
119
|
_executePoll(input: TokenRatesPollingInput): Promise<void>;
|
|
120
120
|
startPolling(input: TokenRatesPollingInput): string;
|
|
121
121
|
stopAllPolling(): void;
|
|
@@ -17,7 +17,7 @@ import $lodash from "lodash";
|
|
|
17
17
|
const { isEqual } = $lodash;
|
|
18
18
|
import { reduceInBatchesSerially, TOKEN_PRICES_BATCH_SIZE } from "./assetsUtil.mjs";
|
|
19
19
|
import { fetchExchangeRate as fetchNativeCurrencyExchangeRate } from "./crypto-compare-service/index.mjs";
|
|
20
|
-
import {
|
|
20
|
+
import { getNativeTokenAddress } from "./token-prices-service/codefi-v2.mjs";
|
|
21
21
|
const DEFAULT_INTERVAL = 180000;
|
|
22
22
|
var PollState;
|
|
23
23
|
(function (PollState) {
|
|
@@ -402,9 +402,9 @@ async function _TokenRatesController_fetchAndMapExchangeRatesForSupportedNativeC
|
|
|
402
402
|
currency: nativeCurrency,
|
|
403
403
|
});
|
|
404
404
|
contractNativeInformations = {
|
|
405
|
-
[
|
|
405
|
+
[getNativeTokenAddress(chainId)]: {
|
|
406
406
|
currency: nativeCurrency,
|
|
407
|
-
...contractNativeInformationsNative[
|
|
407
|
+
...contractNativeInformationsNative[getNativeTokenAddress(chainId)],
|
|
408
408
|
},
|
|
409
409
|
};
|
|
410
410
|
}
|