@metamask/assets-controllers 57.0.0 → 59.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +43 -4
  2. package/dist/AccountTrackerController.cjs +66 -33
  3. package/dist/AccountTrackerController.cjs.map +1 -1
  4. package/dist/AccountTrackerController.d.cts +5 -8
  5. package/dist/AccountTrackerController.d.cts.map +1 -1
  6. package/dist/AccountTrackerController.d.mts +5 -8
  7. package/dist/AccountTrackerController.d.mts.map +1 -1
  8. package/dist/AccountTrackerController.mjs +66 -33
  9. package/dist/AccountTrackerController.mjs.map +1 -1
  10. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.cjs +57 -4
  11. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.cjs.map +1 -1
  12. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.cts +16 -3
  13. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.cts.map +1 -1
  14. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.mts +16 -3
  15. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.mts.map +1 -1
  16. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.mjs +57 -4
  17. package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.mjs.map +1 -1
  18. package/dist/NftDetectionController.cjs +11 -5
  19. package/dist/NftDetectionController.cjs.map +1 -1
  20. package/dist/NftDetectionController.d.cts.map +1 -1
  21. package/dist/NftDetectionController.d.mts.map +1 -1
  22. package/dist/NftDetectionController.mjs +11 -5
  23. package/dist/NftDetectionController.mjs.map +1 -1
  24. package/dist/TokenRatesController.cjs +111 -96
  25. package/dist/TokenRatesController.cjs.map +1 -1
  26. package/dist/TokenRatesController.d.cts +22 -10
  27. package/dist/TokenRatesController.d.cts.map +1 -1
  28. package/dist/TokenRatesController.d.mts +22 -10
  29. package/dist/TokenRatesController.d.mts.map +1 -1
  30. package/dist/TokenRatesController.mjs +111 -96
  31. package/dist/TokenRatesController.mjs.map +1 -1
  32. package/dist/assetsUtil.cjs +3 -0
  33. package/dist/assetsUtil.cjs.map +1 -1
  34. package/dist/assetsUtil.d.cts +2 -1
  35. package/dist/assetsUtil.d.cts.map +1 -1
  36. package/dist/assetsUtil.d.mts +2 -1
  37. package/dist/assetsUtil.d.mts.map +1 -1
  38. package/dist/assetsUtil.mjs +3 -0
  39. package/dist/assetsUtil.mjs.map +1 -1
  40. package/dist/token-prices-service/codefi-v2.cjs +4 -0
  41. package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
  42. package/dist/token-prices-service/codefi-v2.d.cts +2 -2
  43. package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
  44. package/dist/token-prices-service/codefi-v2.d.mts +2 -2
  45. package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
  46. package/dist/token-prices-service/codefi-v2.mjs +4 -0
  47. package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
  48. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"AccountTrackerController.mjs","sourceRoot":"","sources":["../src/AccountTrackerController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerSelectedEvmAccountChangeEvent,\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerListAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport {\n query,\n safelyExecuteWithTimeout,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport EthQuery from '@metamask/eth-query';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { PreferencesControllerGetStateAction } from '@metamask/preferences-controller';\nimport { assert } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { cloneDeep } from 'lodash';\n\nimport type {\n AssetsContractController,\n StakedBalance,\n} from './AssetsContractController';\n\n/**\n * The name of the {@link AccountTrackerController}.\n */\nconst controllerName = 'AccountTrackerController';\n\n/**\n * @type AccountInformation\n *\n * Account information object\n * @property balance - Hex string of an account balance in wei\n * @property stakedBalance - Hex string of an account staked balance in wei\n */\nexport type AccountInformation = {\n balance: string;\n stakedBalance?: string;\n};\n\n/**\n * @type AccountTrackerControllerState\n *\n * Account tracker controller state\n * @property accountsByChainId - Map of addresses to account information by chain\n */\nexport type AccountTrackerControllerState = {\n accountsByChainId: Record<string, { [address: string]: AccountInformation }>;\n};\n\nconst accountTrackerMetadata = {\n accountsByChainId: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The action that can be performed to get the state of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTrackerControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerActions =\n AccountTrackerControllerGetStateAction;\n\n/**\n * The messenger of the {@link AccountTrackerController} for communication.\n */\nexport type AllowedActions =\n | AccountsControllerListAccountsAction\n | PreferencesControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction;\n\n/**\n * The event that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n AccountTrackerControllerState\n >;\n\n/**\n * The events that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerEvents =\n AccountTrackerControllerStateChangeEvent;\n\n/**\n * The external events available to the {@link AccountTrackerController}.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedEvmAccountChangeEvent\n | AccountsControllerSelectedAccountChangeEvent;\n\n/**\n * The messenger of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AccountTrackerControllerActions | AllowedActions,\n AccountTrackerControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/** The input to start polling for the {@link AccountTrackerController} */\ntype AccountTrackerPollingInput = {\n networkClientId: NetworkClientId;\n};\n\n/**\n * Controller that tracks the network balances for all user accounts.\n */\nexport class AccountTrackerController extends StaticIntervalPollingController<AccountTrackerPollingInput>()<\n typeof controllerName,\n AccountTrackerControllerState,\n AccountTrackerControllerMessenger\n> {\n readonly #refreshMutex = new Mutex();\n\n readonly #includeStakedAssets: boolean;\n\n readonly #getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n\n /**\n * Creates an AccountTracker instance.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new account balances.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messaging system.\n * @param options.getStakedBalanceForChain - The function to get the staked native asset balance for a chain.\n * @param options.includeStakedAssets - Whether to include staked assets in the account balances.\n */\n constructor({\n interval = 10000,\n state,\n messenger,\n getStakedBalanceForChain,\n includeStakedAssets = false,\n }: {\n interval?: number;\n state?: Partial<AccountTrackerControllerState>;\n messenger: AccountTrackerControllerMessenger;\n getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n includeStakedAssets?: boolean;\n }) {\n const { selectedNetworkClientId } = messenger.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n super({\n name: controllerName,\n messenger,\n state: {\n accountsByChainId: {\n [chainId]: {},\n },\n ...state,\n },\n metadata: accountTrackerMetadata,\n });\n this.#getStakedBalanceForChain = getStakedBalanceForChain;\n\n this.#includeStakedAssets = includeStakedAssets;\n\n this.setIntervalLength(interval);\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 () => this.refresh(),\n );\n }\n\n private syncAccounts(newChainId: string) {\n const accountsByChainId = cloneDeep(this.state.accountsByChainId);\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId: currentChainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n const existing = Object.keys(accountsByChainId?.[currentChainId] ?? {});\n\n if (!accountsByChainId[newChainId]) {\n accountsByChainId[newChainId] = {};\n existing.forEach((address) => {\n accountsByChainId[newChainId][address] = { balance: '0x0' };\n });\n }\n\n // Note: The address from the preferences controller are checksummed\n // The addresses from the accounts controller are lowercased\n const addresses = Object.values(\n this.messagingSystem\n .call('AccountsController:listAccounts')\n .map((internalAccount) =>\n toChecksumHexAddress(internalAccount.address),\n ),\n );\n const newAddresses = addresses.filter(\n (address) => !existing.includes(address),\n );\n const oldAddresses = existing.filter(\n (address) => !addresses.includes(address),\n );\n Object.keys(accountsByChainId).forEach((chainId) => {\n newAddresses.forEach((address) => {\n accountsByChainId[chainId][address] = {\n balance: '0x0',\n };\n });\n });\n\n Object.keys(accountsByChainId).forEach((chainId) => {\n oldAddresses.forEach((address) => {\n delete accountsByChainId[chainId][address];\n });\n });\n\n this.update((state) => {\n state.accountsByChainId = accountsByChainId;\n });\n }\n\n /**\n * Resolves a networkClientId to a network client config\n * or globally selected network config if not provided\n *\n * @param networkClientId - Optional networkClientId to fetch a network client with\n * @returns network client config\n */\n #getCorrectNetworkClient(networkClientId?: NetworkClientId): {\n chainId: string;\n ethQuery?: EthQuery;\n } {\n const selectedNetworkClientId =\n networkClientId ??\n this.messagingSystem.call('NetworkController:getState')\n .selectedNetworkClientId;\n const {\n configuration: { chainId },\n provider,\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n return {\n chainId,\n ethQuery: new EthQuery(provider),\n };\n }\n\n /**\n * Refreshes the balances of the accounts using the networkClientId\n *\n * @param input - The input for the poll.\n * @param input.networkClientId - The network client ID used to get balances.\n */\n async _executePoll({\n networkClientId,\n }: AccountTrackerPollingInput): Promise<void> {\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.refresh(networkClientId);\n }\n\n /**\n * Refreshes the balances of the accounts depending on the multi-account setting.\n * If multi-account is disabled, only updates the selected account balance.\n * If multi-account is enabled, updates balances for all accounts.\n *\n * @param networkClientId - Optional networkClientId to fetch a network client with\n */\n async refresh(networkClientId?: NetworkClientId) {\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n const releaseLock = await this.#refreshMutex.acquire();\n try {\n const { chainId, ethQuery } =\n this.#getCorrectNetworkClient(networkClientId);\n this.syncAccounts(chainId);\n const { accountsByChainId } = this.state;\n const { isMultiAccountBalancesEnabled } = this.messagingSystem.call(\n 'PreferencesController:getState',\n );\n\n const accountsToUpdate = isMultiAccountBalancesEnabled\n ? Object.keys(accountsByChainId[chainId])\n : [toChecksumHexAddress(selectedAccount.address)];\n\n const accountsForChain = { ...accountsByChainId[chainId] };\n for (const address of accountsToUpdate) {\n const balance = await this.#getBalanceFromChain(address, ethQuery);\n if (balance) {\n accountsForChain[address] = {\n balance,\n };\n }\n if (this.#includeStakedAssets) {\n const stakedBalance = await this.#getStakedBalanceForChain(\n address,\n networkClientId,\n );\n if (stakedBalance) {\n accountsForChain[address] = {\n ...accountsForChain[address],\n stakedBalance,\n };\n }\n }\n }\n\n this.update((state) => {\n state.accountsByChainId[chainId] = accountsForChain;\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Fetches the balance of a given address from the blockchain.\n *\n * @param address - The account address to fetch the balance for.\n * @param ethQuery - The EthQuery instance to query getBalnce with.\n * @returns A promise that resolves to the balance in a hex string format.\n */\n async #getBalanceFromChain(\n address: string,\n ethQuery?: EthQuery,\n ): Promise<string | undefined> {\n return await safelyExecuteWithTimeout(async () => {\n assert(ethQuery, 'Provider not set.');\n return await query(ethQuery, 'getBalance', [address]);\n });\n }\n\n /**\n * Sync accounts balances with some additional addresses.\n *\n * @param addresses - the additional addresses, may be hardware wallet addresses.\n * @param networkClientId - Optional networkClientId to fetch a network client with.\n * @returns accounts - addresses with synced balance\n */\n async syncBalanceWithAddresses(\n addresses: string[],\n networkClientId?: NetworkClientId,\n ): Promise<\n Record<string, { balance: string; stakedBalance?: StakedBalance }>\n > {\n const { ethQuery } = this.#getCorrectNetworkClient(networkClientId);\n\n return await Promise.all(\n addresses.map(\n (address): Promise<[string, string, StakedBalance] | undefined> => {\n return safelyExecuteWithTimeout(async () => {\n assert(ethQuery, 'Provider not set.');\n const balance = await query(ethQuery, 'getBalance', [address]);\n\n let stakedBalance: StakedBalance;\n if (this.#includeStakedAssets) {\n stakedBalance = await this.#getStakedBalanceForChain(\n address,\n networkClientId,\n );\n }\n return [address, balance, stakedBalance];\n });\n },\n ),\n ).then((value) => {\n return value.reduce((obj, item) => {\n if (!item) {\n return obj;\n }\n\n const [address, balance, stakedBalance] = item;\n return {\n ...obj,\n [address]: {\n balance,\n stakedBalance,\n },\n };\n }, {});\n });\n }\n}\n\nexport default AccountTrackerController;\n"]}
1
+ {"version":3,"file":"AccountTrackerController.mjs","sourceRoot":"","sources":["../src/AccountTrackerController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerSelectedEvmAccountChangeEvent,\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerListAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport {\n query,\n safelyExecuteWithTimeout,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport EthQuery from '@metamask/eth-query';\nimport type {\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { PreferencesControllerGetStateAction } from '@metamask/preferences-controller';\nimport { assert } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { cloneDeep } from 'lodash';\n\nimport type {\n AssetsContractController,\n StakedBalance,\n} from './AssetsContractController';\nimport { reduceInBatchesSerially, TOKEN_PRICES_BATCH_SIZE } from './assetsUtil';\n\n/**\n * The name of the {@link AccountTrackerController}.\n */\nconst controllerName = 'AccountTrackerController';\n\n/**\n * @type AccountInformation\n *\n * Account information object\n * @property balance - Hex string of an account balance in wei\n * @property stakedBalance - Hex string of an account staked balance in wei\n */\nexport type AccountInformation = {\n balance: string;\n stakedBalance?: string;\n};\n\n/**\n * @type AccountTrackerControllerState\n *\n * Account tracker controller state\n * @property accountsByChainId - Map of addresses to account information by chain\n */\nexport type AccountTrackerControllerState = {\n accountsByChainId: Record<string, { [address: string]: AccountInformation }>;\n};\n\nconst accountTrackerMetadata = {\n accountsByChainId: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The action that can be performed to get the state of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTrackerControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerActions =\n AccountTrackerControllerGetStateAction;\n\n/**\n * The messenger of the {@link AccountTrackerController} for communication.\n */\nexport type AllowedActions =\n | AccountsControllerListAccountsAction\n | PreferencesControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction;\n\n/**\n * The event that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n AccountTrackerControllerState\n >;\n\n/**\n * The events that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerEvents =\n AccountTrackerControllerStateChangeEvent;\n\n/**\n * The external events available to the {@link AccountTrackerController}.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedEvmAccountChangeEvent\n | AccountsControllerSelectedAccountChangeEvent;\n\n/**\n * The messenger of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AccountTrackerControllerActions | AllowedActions,\n AccountTrackerControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/** The input to start polling for the {@link AccountTrackerController} */\ntype AccountTrackerPollingInput = {\n networkClientIds: NetworkClientId[];\n};\n\n/**\n * Controller that tracks the network balances for all user accounts.\n */\nexport class AccountTrackerController extends StaticIntervalPollingController<AccountTrackerPollingInput>()<\n typeof controllerName,\n AccountTrackerControllerState,\n AccountTrackerControllerMessenger\n> {\n readonly #refreshMutex = new Mutex();\n\n readonly #includeStakedAssets: boolean;\n\n readonly #getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n\n /**\n * Creates an AccountTracker instance.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new account balances.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messaging system.\n * @param options.getStakedBalanceForChain - The function to get the staked native asset balance for a chain.\n * @param options.includeStakedAssets - Whether to include staked assets in the account balances.\n */\n constructor({\n interval = 10000,\n state,\n messenger,\n getStakedBalanceForChain,\n includeStakedAssets = false,\n }: {\n interval?: number;\n state?: Partial<AccountTrackerControllerState>;\n messenger: AccountTrackerControllerMessenger;\n getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n includeStakedAssets?: boolean;\n }) {\n const { selectedNetworkClientId } = messenger.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n super({\n name: controllerName,\n messenger,\n state: {\n accountsByChainId: {\n [chainId]: {},\n },\n ...state,\n },\n metadata: accountTrackerMetadata,\n });\n this.#getStakedBalanceForChain = getStakedBalanceForChain;\n\n this.#includeStakedAssets = includeStakedAssets;\n\n this.setIntervalLength(interval);\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 () => this.refresh(this.#getNetworkClientIds()),\n );\n }\n\n private syncAccounts(newChainId: string) {\n const accountsByChainId = cloneDeep(this.state.accountsByChainId);\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId: currentChainId },\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n const existing = Object.keys(accountsByChainId?.[currentChainId] ?? {});\n\n if (!accountsByChainId[newChainId]) {\n accountsByChainId[newChainId] = {};\n existing.forEach((address) => {\n accountsByChainId[newChainId][address] = { balance: '0x0' };\n });\n }\n\n // Note: The address from the preferences controller are checksummed\n // The addresses from the accounts controller are lowercased\n const addresses = Object.values(\n this.messagingSystem\n .call('AccountsController:listAccounts')\n .map((internalAccount) =>\n toChecksumHexAddress(internalAccount.address),\n ),\n );\n const newAddresses = addresses.filter(\n (address) => !existing.includes(address),\n );\n const oldAddresses = existing.filter(\n (address) => !addresses.includes(address),\n );\n Object.keys(accountsByChainId).forEach((chainId) => {\n newAddresses.forEach((address) => {\n accountsByChainId[chainId][address] = {\n balance: '0x0',\n };\n });\n });\n\n Object.keys(accountsByChainId).forEach((chainId) => {\n oldAddresses.forEach((address) => {\n delete accountsByChainId[chainId][address];\n });\n });\n\n this.update((state) => {\n state.accountsByChainId = accountsByChainId;\n });\n }\n\n /**\n * Resolves a networkClientId to a network client config\n * or globally selected network config if not provided\n *\n * @param networkClientId - Optional networkClientId to fetch a network client with\n * @returns network client config\n */\n #getCorrectNetworkClient(networkClientId?: NetworkClientId): {\n chainId: string;\n ethQuery?: EthQuery;\n } {\n const selectedNetworkClientId =\n networkClientId ??\n this.messagingSystem.call('NetworkController:getState')\n .selectedNetworkClientId;\n const {\n configuration: { chainId },\n provider,\n } = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n return {\n chainId,\n ethQuery: new EthQuery(provider),\n };\n }\n\n /**\n * Retrieves the list of network client IDs.\n *\n * @returns An array of network client IDs.\n */\n #getNetworkClientIds(): NetworkClientId[] {\n const { networkConfigurationsByChainId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n return Object.values(networkConfigurationsByChainId).flatMap(\n (networkConfiguration) =>\n networkConfiguration.rpcEndpoints.map(\n (rpcEndpoint) => rpcEndpoint.networkClientId,\n ),\n );\n }\n\n /**\n * Refreshes the balances of the accounts using the networkClientId\n *\n * @param input - The input for the poll.\n * @param input.networkClientIds - The network client IDs used to get balances.\n */\n async _executePoll({\n networkClientIds,\n }: AccountTrackerPollingInput): Promise<void> {\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.refresh(networkClientIds);\n }\n\n /**\n * Refreshes the balances of the accounts depending on the multi-account setting.\n * If multi-account is disabled, only updates the selected account balance.\n * If multi-account is enabled, updates balances for all accounts.\n *\n * @param networkClientIds - Optional network client IDs to fetch a network client with\n */\n async refresh(networkClientIds: NetworkClientId[]) {\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedAccount',\n );\n const releaseLock = await this.#refreshMutex.acquire();\n try {\n // Create an array of promises for each networkClientId\n const updatePromises = networkClientIds.map(async (networkClientId) => {\n const { chainId, ethQuery } =\n this.#getCorrectNetworkClient(networkClientId);\n this.syncAccounts(chainId);\n const { accountsByChainId } = this.state;\n const { isMultiAccountBalancesEnabled } = this.messagingSystem.call(\n 'PreferencesController:getState',\n );\n\n const accountsToUpdate = isMultiAccountBalancesEnabled\n ? Object.keys(accountsByChainId[chainId])\n : [toChecksumHexAddress(selectedAccount.address)];\n\n const accountsForChain = { ...accountsByChainId[chainId] };\n\n // Process accounts in batches using reduceInBatchesSerially\n await reduceInBatchesSerially<string, void>({\n values: accountsToUpdate,\n batchSize: TOKEN_PRICES_BATCH_SIZE,\n initialResult: undefined,\n eachBatch: async (workingResult: void, batch: string[]) => {\n const balancePromises = batch.map(async (address: string) => {\n const balancePromise = this.#getBalanceFromChain(\n address,\n ethQuery,\n );\n const stakedBalancePromise = this.#includeStakedAssets\n ? this.#getStakedBalanceForChain(address, networkClientId)\n : Promise.resolve(null);\n\n const [balanceResult, stakedBalanceResult] =\n await Promise.allSettled([\n balancePromise,\n stakedBalancePromise,\n ]);\n\n // Update account balances\n if (balanceResult.status === 'fulfilled' && balanceResult.value) {\n accountsForChain[address] = {\n balance: balanceResult.value,\n };\n }\n\n if (\n stakedBalanceResult.status === 'fulfilled' &&\n stakedBalanceResult.value\n ) {\n accountsForChain[address] = {\n ...accountsForChain[address],\n stakedBalance: stakedBalanceResult.value,\n };\n }\n });\n\n await Promise.allSettled(balancePromises);\n return workingResult;\n },\n });\n\n // After all batches are processed, return the updated data\n return { chainId, accountsForChain };\n });\n\n // Wait for all networkClientId updates to settle in parallel\n const allResults = await Promise.allSettled(updatePromises);\n\n // Update the state once all networkClientId updates are completed\n allResults.forEach((result) => {\n if (result.status === 'fulfilled') {\n const { chainId, accountsForChain } = result.value;\n this.update((state) => {\n state.accountsByChainId[chainId] = accountsForChain;\n });\n }\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Fetches the balance of a given address from the blockchain.\n *\n * @param address - The account address to fetch the balance for.\n * @param ethQuery - The EthQuery instance to query getBalnce with.\n * @returns A promise that resolves to the balance in a hex string format.\n */\n async #getBalanceFromChain(\n address: string,\n ethQuery?: EthQuery,\n ): Promise<string | undefined> {\n return await safelyExecuteWithTimeout(async () => {\n assert(ethQuery, 'Provider not set.');\n return await query(ethQuery, 'getBalance', [address]);\n });\n }\n\n /**\n * Sync accounts balances with some additional addresses.\n *\n * @param addresses - the additional addresses, may be hardware wallet addresses.\n * @param networkClientId - Optional networkClientId to fetch a network client with.\n * @returns accounts - addresses with synced balance\n */\n async syncBalanceWithAddresses(\n addresses: string[],\n networkClientId?: NetworkClientId,\n ): Promise<\n Record<string, { balance: string; stakedBalance?: StakedBalance }>\n > {\n const { ethQuery } = this.#getCorrectNetworkClient(networkClientId);\n\n return await Promise.all(\n addresses.map(\n (address): Promise<[string, string, StakedBalance] | undefined> => {\n return safelyExecuteWithTimeout(async () => {\n assert(ethQuery, 'Provider not set.');\n const balance = await query(ethQuery, 'getBalance', [address]);\n\n let stakedBalance: StakedBalance;\n if (this.#includeStakedAssets) {\n stakedBalance = await this.#getStakedBalanceForChain(\n address,\n networkClientId,\n );\n }\n return [address, balance, stakedBalance];\n });\n },\n ),\n ).then((value) => {\n return value.reduce((obj, item) => {\n if (!item) {\n return obj;\n }\n\n const [address, balance, stakedBalance] = item;\n return {\n ...obj,\n [address]: {\n balance,\n stakedBalance,\n },\n };\n }, {});\n });\n }\n}\n\nexport default AccountTrackerController;\n"]}
@@ -31,11 +31,12 @@ const controllerName = 'MultichainAssetsRatesController';
31
31
  * @returns The default {@link MultichainAssetsRatesController} state.
32
32
  */
33
33
  function getDefaultMultichainAssetsRatesControllerState() {
34
- return { conversionRates: {} };
34
+ return { conversionRates: {}, historicalPrices: {} };
35
35
  }
36
36
  exports.getDefaultMultichainAssetsRatesControllerState = getDefaultMultichainAssetsRatesControllerState;
37
37
  const metadata = {
38
38
  conversionRates: { persist: true, anonymous: true },
39
+ historicalPrices: { persist: false, anonymous: true },
39
40
  };
40
41
  /**
41
42
  * Controller that manages multichain token conversion rates.
@@ -122,11 +123,14 @@ class MultichainAssetsRatesController extends (0, polling_controller_1.StaticInt
122
123
  // Build the conversions array
123
124
  const conversions = __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_buildConversions).call(this, assets);
124
125
  // Retrieve rates from Snap
125
- const accountRates = await __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_handleSnapRequest).call(this, {
126
+ const accountRates = (await __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_handleSnapRequest).call(this, {
126
127
  snapId: account?.metadata.snap?.id,
127
128
  handler: snaps_utils_1.HandlerType.OnAssetsConversion,
128
- params: conversions,
129
- });
129
+ params: {
130
+ ...conversions,
131
+ includeMarketData: true,
132
+ },
133
+ }));
130
134
  // Flatten nested rates if needed
131
135
  const flattenedRates = __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_flattenRates).call(this, accountRates);
132
136
  // Build the updatedRates object for these assets
@@ -138,6 +142,55 @@ class MultichainAssetsRatesController extends (0, polling_controller_1.StaticInt
138
142
  releaseLock();
139
143
  });
140
144
  }
145
+ /**
146
+ * Fetches historical prices for the current account
147
+ *
148
+ * @param asset - The asset to fetch historical prices for.
149
+ * @returns The historical prices.
150
+ */
151
+ async fetchHistoricalPricesForAsset(asset) {
152
+ const releaseLock = await __classPrivateFieldGet(this, _MultichainAssetsRatesController_mutex, "f").acquire();
153
+ return (async () => {
154
+ const currentCaipCurrency = constant_1.MAP_CAIP_CURRENCIES[__classPrivateFieldGet(this, _MultichainAssetsRatesController_currentCurrency, "f")] ?? constant_1.MAP_CAIP_CURRENCIES.usd;
155
+ // Check if we already have historical prices for this asset and currency
156
+ const historicalPriceExpirationTime = this.state.historicalPrices[asset]?.[__classPrivateFieldGet(this, _MultichainAssetsRatesController_currentCurrency, "f")]
157
+ ?.expirationTime;
158
+ const historicalPriceHasExpired = historicalPriceExpirationTime &&
159
+ historicalPriceExpirationTime < Date.now();
160
+ if (historicalPriceHasExpired === false) {
161
+ return;
162
+ }
163
+ const selectedAccount = this.messagingSystem.call('AccountsController:getSelectedMultichainAccount');
164
+ try {
165
+ const historicalPricesResponse = await __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_handleSnapRequest).call(this, {
166
+ snapId: selectedAccount?.metadata.snap?.id,
167
+ handler: snaps_utils_1.HandlerType.OnAssetHistoricalPrice,
168
+ params: {
169
+ from: asset,
170
+ to: currentCaipCurrency,
171
+ },
172
+ });
173
+ // skip state update if no historical prices are returned
174
+ if (!historicalPricesResponse) {
175
+ return;
176
+ }
177
+ this.update((state) => {
178
+ state.historicalPrices = {
179
+ ...state.historicalPrices,
180
+ [asset]: {
181
+ ...state.historicalPrices[asset],
182
+ [__classPrivateFieldGet(this, _MultichainAssetsRatesController_currentCurrency, "f")]: historicalPricesResponse?.historicalPrice,
183
+ },
184
+ };
185
+ });
186
+ }
187
+ catch {
188
+ throw new Error(`Failed to fetch historical prices for asset: ${asset}`);
189
+ }
190
+ })().finally(() => {
191
+ releaseLock();
192
+ });
193
+ }
141
194
  }
142
195
  exports.MultichainAssetsRatesController = MultichainAssetsRatesController;
143
196
  _MultichainAssetsRatesController_mutex = new WeakMap(), _MultichainAssetsRatesController_currentCurrency = new WeakMap(), _MultichainAssetsRatesController_accountsAssets = new WeakMap(), _MultichainAssetsRatesController_isUnlocked = new WeakMap(), _MultichainAssetsRatesController_instances = new WeakSet(), _MultichainAssetsRatesController_isNonEvmAccount = function _MultichainAssetsRatesController_isNonEvmAccount(account) {
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainAssetsRatesController.cjs","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AASA,uDAA6E;AAM7E,qEAA+E;AAQ/E,uDAAoD;AACpD,6CAAoC;AAGpC,6CAAiD;AAYjD;;GAEG;AACH,MAAM,cAAc,GAAG,iCAAiC,CAAC;AA0BzD;;;;;;;GAOG;AACH,SAAgB,8CAA8C;IAC5D,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC;AACjC,CAAC;AAFD,wGAEC;AA4DD,MAAM,QAAQ,GAAG;IACf,eAAe,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;CACpD,CAAC;AAEF;;;;GAIG;AACH,MAAa,+BAAgC,SAAQ,IAAA,oDAA+B,GAInF;IASC;;;;;;;OAOG;IACH,YAAY,EACV,QAAQ,GAAG,KAAK,EAChB,KAAK,GAAG,EAAE,EACV,SAAS,GAKV;;QACC,KAAK,CAAC;YACJ,IAAI,EAAE,cAAc;YACpB,SAAS;YACT,KAAK,EAAE;gBACL,GAAG,8CAA8C,EAAE;gBACnD,GAAG,KAAK;aACT;YACD,QAAQ;SACT,CAAC,CAAC;;QAjCI,iDAAS,IAAI,mBAAK,EAAE,EAAC;QAE9B,mEAAuD;QAEvD,kEAAmE;QAEnE,sDAAc,IAAI,EAAC;QA6BjB,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAEjC,2CAA2C;QAC3C,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,wBAAwB,EAAE,GAAG,EAAE;YAC5D,uBAAA,IAAI,+CAAe,KAAK,MAAA,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAC9D,uBAAA,IAAI,+CAAe,IAAI,MAAA,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,MAAmB,IAAI,EAAtB,EAAE,cAAc,qHAAsB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CACnE,qCAAqC,CACtC,CAAC,CAAC;QAEH,MAAoB,IAAI,EAAvB,EAAE,eAAe,sHAAuB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CACrE,iCAAiC,CAClC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,oCAAoC,EACpC,KAAK,EAAE,kBAAqC,EAAE,EAAE;YAC9C,uBAAA,IAAI,oDAAoB,kBAAkB,CAAC,eAAe,MAAA,CAAC;YAC3D,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACjC,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,wCAAwC,EACxC,KAAK,EAAE,qBAAsD,EAAE,EAAE;YAC/D,uBAAA,IAAI,mDAAmB,qBAAqB,CAAC,cAAc,MAAA,CAAC;YAC5D,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACjC,CAAC,CACF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,IAAI,QAAQ;QACV,OAAO,uBAAA,IAAI,mDAAY,CAAC;IAC1B,CAAC;IAmCD;;;;OAIG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,WAAW,GAAG,MAAM,uBAAA,IAAI,8CAAO,CAAC,OAAO,EAAE,CAAC;QAEhD,OAAO,CAAC,KAAK,IAAI,EAAE;YACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAClB,OAAO;aACR;YACD,MAAM,QAAQ,GAAG,uBAAA,IAAI,iGAAc,MAAlB,IAAI,CAAgB,CAAC;YAEtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;gBAC9B,MAAM,MAAM,GAAG,uBAAA,IAAI,wGAAqB,MAAzB,IAAI,EAAsB,OAAO,CAAC,EAAE,CAAC,CAAC;gBAErD,IAAI,MAAM,EAAE,MAAM,KAAK,CAAC,EAAE;oBACxB,SAAS;iBACV;gBAED,8BAA8B;gBAC9B,MAAM,WAAW,GAAG,uBAAA,IAAI,qGAAkB,MAAtB,IAAI,EAAmB,MAAM,CAAC,CAAC;gBAEnD,2BAA2B;gBAC3B,MAAM,YAAY,GAAG,MAAM,uBAAA,IAAI,sGAAmB,MAAvB,IAAI,EAAoB;oBACjD,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAY;oBAC5C,OAAO,EAAE,yBAAW,CAAC,kBAAkB;oBACvC,MAAM,EAAE,WAAW;iBACpB,CAAC,CAAC;gBAEH,iCAAiC;gBACjC,MAAM,cAAc,GAAG,uBAAA,IAAI,iGAAc,MAAlB,IAAI,EAAe,YAAY,CAAC,CAAC;gBAExD,iDAAiD;gBACjD,MAAM,YAAY,GAAG,uBAAA,IAAI,sGAAmB,MAAvB,IAAI,EAAoB,MAAM,EAAE,cAAc,CAAC,CAAC;gBACrE,gDAAgD;gBAChD,uBAAA,IAAI,sGAAmB,MAAvB,IAAI,EAAoB,YAAY,CAAC,CAAC;aACvC;QACH,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YAChB,WAAW,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;CAgIF;AAxSD,0EAwSC;iaArMkB,OAAwB;IACvC,OAAO,CACL,CAAC,IAAA,8BAAgB,EAAC,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CACvE,CAAC;AACJ,CAAC;IAQC,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAC9B,2CAA2C,CAC5C,CAAC;AACJ,CAAC;IAQC,MAAM,QAAQ,GAAG,uBAAA,IAAI,2GAAwB,MAA5B,IAAI,CAA0B,CAAC;IAChD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,uBAAA,IAAI,oGAAiB,MAArB,IAAI,EAAkB,OAAO,CAAC,CAAC,CAAC;AACtE,CAAC,uHAqDoB,SAAiB;IACpC,OAAO,uBAAA,IAAI,uDAAgB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;AACjD,CAAC,iHAQiB,MAAuB;IACvC,MAAM,QAAQ,GACZ,8BAAmB,CAAC,uBAAA,IAAI,wDAAiB,CAAC,IAAI,8BAAmB,CAAC,GAAG,CAAC;IACxE,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClC,IAAI,EAAE,KAAK;YACX,EAAE,EAAE,QAAQ;SACb,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC,yGASC,wBAAoD;IAEpD,MAAM,EAAE,eAAe,EAAE,GAAG,wBAAwB,CAAC;IAErD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE;QACzD,uFAAuF;QACvF,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC9B,CAAC,CAAC,CACH,CAAC;AACJ,CAAC,mHAWC,MAAuB,EACvB,cAA6D;IAE7D,MAAM,YAAY,GAGd,EAAE,CAAC;IAEP,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;QAC1B,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,GAAG;gBACpB,GAAI,cAAc,CAAC,KAAK,CAAqB;gBAC7C,QAAQ,EACN,8BAAmB,CAAC,uBAAA,IAAI,wDAAiB,CAAC;oBAC1C,8BAAmB,CAAC,GAAG;aAC1B,CAAC;SACH;KACF;IACD,OAAO,YAAY,CAAC;AACtB,CAAC,mHAQC,YAGC;IAED,IAAI,CAAC,MAAM,CAAC,CAAC,KAAkD,EAAE,EAAE;QACjE,KAAK,CAAC,eAAe,GAAG;YACtB,GAAG,KAAK,CAAC,eAAe;YACxB,GAAG,YAAY;SAChB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,6DAAoB,EACvB,MAAM,EACN,OAAO,EACP,MAAM,GAKP;IACC,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,8BAA8B,EAAE;QAC/D,MAAM;QACN,MAAM,EAAE,UAAU;QAClB,OAAO;QACP,OAAO,EAAE;YACP,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,OAAO;YACf,MAAM;SACP;KACF,CAAwC,CAAC;AAC5C,CAAC","sourcesContent":["import type {\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountAddedEvent,\n} from '@metamask/accounts-controller';\nimport type {\n RestrictedMessenger,\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n} from '@metamask/base-controller';\nimport { type CaipAssetType, isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type {\n SnapId,\n AssetConversion,\n OnAssetsConversionArguments,\n OnAssetsConversionResponse,\n} from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Mutex } from 'async-mutex';\nimport type { Draft } from 'immer';\n\nimport { MAP_CAIP_CURRENCIES } from './constant';\nimport type {\n CurrencyRateState,\n CurrencyRateStateChange,\n GetCurrencyRateState,\n} from '../CurrencyRateController';\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerState,\n MultichainAssetsControllerStateChangeEvent,\n} from '../MultichainAssetsController';\n\n/**\n * The name of the MultichainAssetsRatesController.\n */\nconst controllerName = 'MultichainAssetsRatesController';\n\n/**\n * State used by the MultichainAssetsRatesController to cache token conversion rates.\n */\nexport type MultichainAssetsRatesControllerState = {\n conversionRates: Record<CaipAssetType, AssetConversion>;\n};\n\n/**\n * Returns the state of the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Action to update the rates of all supported tokens.\n */\nexport type MultichainAssetsRatesControllerUpdateRatesAction = {\n type: `${typeof controllerName}:updateAssetsRates`;\n handler: MultichainAssetsRatesController['updateAssetsRates'];\n};\n\n/**\n * Constructs the default {@link MultichainAssetsRatesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsRatesController} state.\n */\nexport function getDefaultMultichainAssetsRatesControllerState(): MultichainAssetsRatesControllerState {\n return { conversionRates: {} };\n}\n\n/**\n * Event emitted when the state of the MultichainAssetsRatesController changes.\n */\nexport type MultichainAssetsRatesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Actions exposed by the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerActions =\n | MultichainAssetsRatesControllerGetStateAction\n | MultichainAssetsRatesControllerUpdateRatesAction;\n\n/**\n * Events emitted by MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerEvents =\n MultichainAssetsRatesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\nexport type AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | GetCurrencyRateState\n | MultichainAssetsControllerGetStateAction;\n/**\n * Events that this controller is allowed to subscribe to.\n */\nexport type AllowedEvents =\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | AccountsControllerAccountAddedEvent\n | CurrencyRateStateChange\n | MultichainAssetsControllerStateChangeEvent;\n\n/**\n * Messenger type for the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n MultichainAssetsRatesControllerActions | AllowedActions,\n MultichainAssetsRatesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * The input for starting polling in MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesPollingInput = {\n accountId: string;\n};\n\nconst metadata = {\n conversionRates: { persist: true, anonymous: true },\n};\n\n/**\n * Controller that manages multichain token conversion rates.\n *\n * This controller polls for token conversion rates and updates its state.\n */\nexport class MultichainAssetsRatesController extends StaticIntervalPollingController<MultichainAssetsRatesPollingInput>()<\n typeof controllerName,\n MultichainAssetsRatesControllerState,\n MultichainAssetsRatesControllerMessenger\n> {\n readonly #mutex = new Mutex();\n\n #currentCurrency: CurrencyRateState['currentCurrency'];\n\n #accountsAssets: MultichainAssetsControllerState['accountsAssets'];\n\n #isUnlocked = true;\n\n /**\n * Creates an instance of MultichainAssetsRatesController.\n *\n * @param options - Constructor options.\n * @param options.interval - The polling interval in milliseconds.\n * @param options.state - The initial state.\n * @param options.messenger - A reference to the messaging system.\n */\n constructor({\n interval = 18000,\n state = {},\n messenger,\n }: {\n interval?: number;\n state?: Partial<MultichainAssetsRatesControllerState>;\n messenger: MultichainAssetsRatesControllerMessenger;\n }) {\n super({\n name: controllerName,\n messenger,\n state: {\n ...getDefaultMultichainAssetsRatesControllerState(),\n ...state,\n },\n metadata,\n });\n\n this.setIntervalLength(interval);\n\n // Subscribe to keyring lock/unlock events.\n this.messagingSystem.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n this.messagingSystem.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n });\n\n ({ accountsAssets: this.#accountsAssets } = this.messagingSystem.call(\n 'MultichainAssetsController:getState',\n ));\n\n ({ currentCurrency: this.#currentCurrency } = this.messagingSystem.call(\n 'CurrencyRateController:getState',\n ));\n\n this.messagingSystem.subscribe(\n 'CurrencyRateController:stateChange',\n async (currencyRatesState: CurrencyRateState) => {\n this.#currentCurrency = currencyRatesState.currentCurrency;\n await this.updateAssetsRates();\n },\n );\n\n this.messagingSystem.subscribe(\n 'MultichainAssetsController:stateChange',\n async (multichainAssetsState: MultichainAssetsControllerState) => {\n this.#accountsAssets = multichainAssetsState.accountsAssets;\n await this.updateAssetsRates();\n },\n );\n }\n\n /**\n * Executes a poll by updating token conversion rates for the current account.\n *\n * @returns A promise that resolves when the polling completes.\n */\n async _executePoll(): Promise<void> {\n await this.updateAssetsRates();\n }\n\n /**\n * Determines whether the controller is active.\n *\n * @returns True if the keyring is unlocked; otherwise, false.\n */\n get isActive(): boolean {\n return this.#isUnlocked;\n }\n\n /**\n * Checks if an account is a non-EVM account with a Snap.\n *\n * @param account - The account to check.\n * @returns True if the account is non-EVM and has Snap metadata; otherwise, false.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) && account.metadata.snap !== undefined\n );\n }\n\n /**\n * Retrieves all multichain accounts from the AccountsController.\n *\n * @returns An array of internal accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Filters and returns non-EVM accounts that should have balances.\n *\n * @returns An array of non-EVM internal accounts.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Updates token conversion rates for each non-EVM account.\n *\n * @returns A promise that resolves when the rates are updated.\n */\n async updateAssetsRates(): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n\n return (async () => {\n if (!this.isActive) {\n return;\n }\n const accounts = this.#listAccounts();\n\n for (const account of accounts) {\n const assets = this.#getAssetsForAccount(account.id);\n\n if (assets?.length === 0) {\n continue;\n }\n\n // Build the conversions array\n const conversions = this.#buildConversions(assets);\n\n // Retrieve rates from Snap\n const accountRates = await this.#handleSnapRequest({\n snapId: account?.metadata.snap?.id as SnapId,\n handler: HandlerType.OnAssetsConversion,\n params: conversions,\n });\n\n // Flatten nested rates if needed\n const flattenedRates = this.#flattenRates(accountRates);\n\n // Build the updatedRates object for these assets\n const updatedRates = this.#buildUpdatedRates(assets, flattenedRates);\n // Apply these updated rates to controller state\n this.#applyUpdatedRates(updatedRates);\n }\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Returns the array of CAIP-19 assets for the given account ID.\n * If none are found, returns an empty array.\n *\n * @param accountId - The account ID to get the assets for.\n * @returns An array of CAIP-19 assets.\n */\n #getAssetsForAccount(accountId: string): CaipAssetType[] {\n return this.#accountsAssets?.[accountId] ?? [];\n }\n\n /**\n * Builds a conversions array (from each asset → the current currency).\n *\n * @param assets - The assets to build the conversions for.\n * @returns A conversions array.\n */\n #buildConversions(assets: CaipAssetType[]): OnAssetsConversionArguments {\n const currency =\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd;\n return {\n conversions: assets.map((asset) => ({\n from: asset,\n to: currency,\n })),\n };\n }\n\n /**\n * Flattens any nested structure in the conversion rates returned by Snap.\n *\n * @param assetsConversionResponse - The conversion rates to flatten.\n * @returns A flattened rates object.\n */\n #flattenRates(\n assetsConversionResponse: OnAssetsConversionResponse,\n ): Record<CaipAssetType, AssetConversion | null> {\n const { conversionRates } = assetsConversionResponse;\n\n return Object.fromEntries(\n Object.entries(conversionRates).map(([asset, nestedObj]) => {\n // e.g., nestedObj might look like: { \"swift:0/iso4217:EUR\": { rate, conversionTime } }\n const singleValue = Object.values(nestedObj)[0];\n return [asset, singleValue];\n }),\n );\n }\n\n /**\n * Builds a rates object that covers all given assets, ensuring that\n * any asset not returned by Snap is set to null for both `rate` and `conversionTime`.\n *\n * @param assets - The assets to build the rates for.\n * @param flattenedRates - The rates to merge.\n * @returns A rates object that covers all given assets.\n */\n #buildUpdatedRates(\n assets: CaipAssetType[],\n flattenedRates: Record<CaipAssetType, AssetConversion | null>,\n ): Record<string, AssetConversion & { currency: CaipAssetType }> {\n const updatedRates: Record<\n CaipAssetType,\n AssetConversion & { currency: CaipAssetType }\n > = {};\n\n for (const asset of assets) {\n if (flattenedRates[asset]) {\n updatedRates[asset] = {\n ...(flattenedRates[asset] as AssetConversion),\n currency:\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ??\n MAP_CAIP_CURRENCIES.usd,\n };\n }\n }\n return updatedRates;\n }\n\n /**\n * Merges the new rates into the controller’s state.\n *\n * @param updatedRates - The new rates to merge.\n */\n #applyUpdatedRates(\n updatedRates: Record<\n string,\n { rate: string | null; conversionTime: number | null }\n >,\n ): void {\n this.update((state: Draft<MultichainAssetsRatesControllerState>) => {\n state.conversionRates = {\n ...state.conversionRates,\n ...updatedRates,\n };\n });\n }\n\n /**\n * Forwards a Snap request to the SnapController.\n *\n * @param args - The request parameters.\n * @param args.snapId - The ID of the Snap.\n * @param args.handler - The handler type.\n * @param args.params - The asset conversions.\n * @returns A promise that resolves with the account rates.\n */\n async #handleSnapRequest({\n snapId,\n handler,\n params,\n }: {\n snapId: SnapId;\n handler: HandlerType;\n params: OnAssetsConversionArguments;\n }): Promise<OnAssetsConversionResponse> {\n return this.messagingSystem.call('SnapController:handleRequest', {\n snapId,\n origin: 'metamask',\n handler,\n request: {\n jsonrpc: '2.0',\n method: handler,\n params,\n },\n }) as Promise<OnAssetsConversionResponse>;\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainAssetsRatesController.cjs","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountAddedEvent,\n AccountsControllerGetSelectedMultichainAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n RestrictedMessenger,\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n} from '@metamask/base-controller';\nimport { type CaipAssetType, isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type {\n SnapId,\n AssetConversion,\n OnAssetsConversionArguments,\n OnAssetsConversionResponse,\n OnAssetHistoricalPriceArguments,\n OnAssetHistoricalPriceResponse,\n HistoricalPriceIntervals,\n} from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Mutex } from 'async-mutex';\nimport type { Draft } from 'immer';\n\nimport { MAP_CAIP_CURRENCIES } from './constant';\nimport type {\n CurrencyRateState,\n CurrencyRateStateChange,\n GetCurrencyRateState,\n} from '../CurrencyRateController';\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerState,\n MultichainAssetsControllerStateChangeEvent,\n} from '../MultichainAssetsController';\n\n/**\n * The name of the MultichainAssetsRatesController.\n */\nconst controllerName = 'MultichainAssetsRatesController';\n\n// This is temporary until its exported from snap\ntype HistoricalPrice = {\n intervals: HistoricalPriceIntervals;\n // The UNIX timestamp of when the historical price was last updated.\n updateTime: number;\n // The UNIX timestamp of when the historical price will expire.\n expirationTime?: number;\n};\n\n/**\n * State used by the MultichainAssetsRatesController to cache token conversion rates.\n */\nexport type MultichainAssetsRatesControllerState = {\n conversionRates: Record<CaipAssetType, AssetConversion>;\n historicalPrices: Record<CaipAssetType, Record<string, HistoricalPrice>>; // string being the current currency we fetched historical prices for\n};\n\n/**\n * Returns the state of the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Action to update the rates of all supported tokens.\n */\nexport type MultichainAssetsRatesControllerUpdateRatesAction = {\n type: `${typeof controllerName}:updateAssetsRates`;\n handler: MultichainAssetsRatesController['updateAssetsRates'];\n};\n\n/**\n * Constructs the default {@link MultichainAssetsRatesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsRatesController} state.\n */\nexport function getDefaultMultichainAssetsRatesControllerState(): MultichainAssetsRatesControllerState {\n return { conversionRates: {}, historicalPrices: {} };\n}\n\n/**\n * Event emitted when the state of the MultichainAssetsRatesController changes.\n */\nexport type MultichainAssetsRatesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Actions exposed by the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerActions =\n | MultichainAssetsRatesControllerGetStateAction\n | MultichainAssetsRatesControllerUpdateRatesAction;\n\n/**\n * Events emitted by MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerEvents =\n MultichainAssetsRatesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\nexport type AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | GetCurrencyRateState\n | MultichainAssetsControllerGetStateAction\n | AccountsControllerGetSelectedMultichainAccountAction;\n\n/**\n * Events that this controller is allowed to subscribe to.\n */\nexport type AllowedEvents =\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | AccountsControllerAccountAddedEvent\n | CurrencyRateStateChange\n | MultichainAssetsControllerStateChangeEvent;\n\n/**\n * Messenger type for the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n MultichainAssetsRatesControllerActions | AllowedActions,\n MultichainAssetsRatesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * The input for starting polling in MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesPollingInput = {\n accountId: string;\n};\n\nconst metadata = {\n conversionRates: { persist: true, anonymous: true },\n historicalPrices: { persist: false, anonymous: true },\n};\n\n/**\n * Controller that manages multichain token conversion rates.\n *\n * This controller polls for token conversion rates and updates its state.\n */\nexport class MultichainAssetsRatesController extends StaticIntervalPollingController<MultichainAssetsRatesPollingInput>()<\n typeof controllerName,\n MultichainAssetsRatesControllerState,\n MultichainAssetsRatesControllerMessenger\n> {\n readonly #mutex = new Mutex();\n\n #currentCurrency: CurrencyRateState['currentCurrency'];\n\n #accountsAssets: MultichainAssetsControllerState['accountsAssets'];\n\n #isUnlocked = true;\n\n /**\n * Creates an instance of MultichainAssetsRatesController.\n *\n * @param options - Constructor options.\n * @param options.interval - The polling interval in milliseconds.\n * @param options.state - The initial state.\n * @param options.messenger - A reference to the messaging system.\n */\n constructor({\n interval = 18000,\n state = {},\n messenger,\n }: {\n interval?: number;\n state?: Partial<MultichainAssetsRatesControllerState>;\n messenger: MultichainAssetsRatesControllerMessenger;\n }) {\n super({\n name: controllerName,\n messenger,\n state: {\n ...getDefaultMultichainAssetsRatesControllerState(),\n ...state,\n },\n metadata,\n });\n\n this.setIntervalLength(interval);\n\n // Subscribe to keyring lock/unlock events.\n this.messagingSystem.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n this.messagingSystem.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n });\n\n ({ accountsAssets: this.#accountsAssets } = this.messagingSystem.call(\n 'MultichainAssetsController:getState',\n ));\n\n ({ currentCurrency: this.#currentCurrency } = this.messagingSystem.call(\n 'CurrencyRateController:getState',\n ));\n\n this.messagingSystem.subscribe(\n 'CurrencyRateController:stateChange',\n async (currencyRatesState: CurrencyRateState) => {\n this.#currentCurrency = currencyRatesState.currentCurrency;\n await this.updateAssetsRates();\n },\n );\n\n this.messagingSystem.subscribe(\n 'MultichainAssetsController:stateChange',\n async (multichainAssetsState: MultichainAssetsControllerState) => {\n this.#accountsAssets = multichainAssetsState.accountsAssets;\n await this.updateAssetsRates();\n },\n );\n }\n\n /**\n * Executes a poll by updating token conversion rates for the current account.\n *\n * @returns A promise that resolves when the polling completes.\n */\n async _executePoll(): Promise<void> {\n await this.updateAssetsRates();\n }\n\n /**\n * Determines whether the controller is active.\n *\n * @returns True if the keyring is unlocked; otherwise, false.\n */\n get isActive(): boolean {\n return this.#isUnlocked;\n }\n\n /**\n * Checks if an account is a non-EVM account with a Snap.\n *\n * @param account - The account to check.\n * @returns True if the account is non-EVM and has Snap metadata; otherwise, false.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) && account.metadata.snap !== undefined\n );\n }\n\n /**\n * Retrieves all multichain accounts from the AccountsController.\n *\n * @returns An array of internal accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Filters and returns non-EVM accounts that should have balances.\n *\n * @returns An array of non-EVM internal accounts.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Updates token conversion rates for each non-EVM account.\n *\n * @returns A promise that resolves when the rates are updated.\n */\n async updateAssetsRates(): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n\n return (async () => {\n if (!this.isActive) {\n return;\n }\n const accounts = this.#listAccounts();\n\n for (const account of accounts) {\n const assets = this.#getAssetsForAccount(account.id);\n\n if (assets?.length === 0) {\n continue;\n }\n\n // Build the conversions array\n const conversions = this.#buildConversions(assets);\n\n // Retrieve rates from Snap\n const accountRates: OnAssetsConversionResponse =\n (await this.#handleSnapRequest({\n snapId: account?.metadata.snap?.id as SnapId,\n handler: HandlerType.OnAssetsConversion,\n params: {\n ...conversions,\n includeMarketData: true,\n },\n })) as OnAssetsConversionResponse;\n\n // Flatten nested rates if needed\n const flattenedRates = this.#flattenRates(accountRates);\n\n // Build the updatedRates object for these assets\n const updatedRates = this.#buildUpdatedRates(assets, flattenedRates);\n // Apply these updated rates to controller state\n this.#applyUpdatedRates(updatedRates);\n }\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Fetches historical prices for the current account\n *\n * @param asset - The asset to fetch historical prices for.\n * @returns The historical prices.\n */\n async fetchHistoricalPricesForAsset(asset: CaipAssetType): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n return (async () => {\n const currentCaipCurrency =\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd;\n // Check if we already have historical prices for this asset and currency\n const historicalPriceExpirationTime =\n this.state.historicalPrices[asset]?.[this.#currentCurrency]\n ?.expirationTime;\n\n const historicalPriceHasExpired =\n historicalPriceExpirationTime &&\n historicalPriceExpirationTime < Date.now();\n\n if (historicalPriceHasExpired === false) {\n return;\n }\n\n const selectedAccount = this.messagingSystem.call(\n 'AccountsController:getSelectedMultichainAccount',\n );\n try {\n const historicalPricesResponse = await this.#handleSnapRequest({\n snapId: selectedAccount?.metadata.snap?.id as SnapId,\n handler: HandlerType.OnAssetHistoricalPrice,\n params: {\n from: asset,\n to: currentCaipCurrency,\n },\n });\n\n // skip state update if no historical prices are returned\n if (!historicalPricesResponse) {\n return;\n }\n\n this.update((state) => {\n state.historicalPrices = {\n ...state.historicalPrices,\n [asset]: {\n ...state.historicalPrices[asset],\n [this.#currentCurrency]: (\n historicalPricesResponse as OnAssetHistoricalPriceResponse\n )?.historicalPrice,\n },\n };\n });\n } catch {\n throw new Error(\n `Failed to fetch historical prices for asset: ${asset}`,\n );\n }\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Returns the array of CAIP-19 assets for the given account ID.\n * If none are found, returns an empty array.\n *\n * @param accountId - The account ID to get the assets for.\n * @returns An array of CAIP-19 assets.\n */\n #getAssetsForAccount(accountId: string): CaipAssetType[] {\n return this.#accountsAssets?.[accountId] ?? [];\n }\n\n /**\n * Builds a conversions array (from each asset → the current currency).\n *\n * @param assets - The assets to build the conversions for.\n * @returns A conversions array.\n */\n #buildConversions(assets: CaipAssetType[]): OnAssetsConversionArguments {\n const currency =\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd;\n return {\n conversions: assets.map((asset) => ({\n from: asset,\n to: currency,\n })),\n };\n }\n\n /**\n * Flattens any nested structure in the conversion rates returned by Snap.\n *\n * @param assetsConversionResponse - The conversion rates to flatten.\n * @returns A flattened rates object.\n */\n #flattenRates(\n assetsConversionResponse: OnAssetsConversionResponse,\n ): Record<CaipAssetType, AssetConversion | null> {\n const { conversionRates } = assetsConversionResponse;\n\n return Object.fromEntries(\n Object.entries(conversionRates).map(([asset, nestedObj]) => {\n // e.g., nestedObj might look like: { \"swift:0/iso4217:EUR\": { rate, conversionTime } }\n const singleValue = Object.values(nestedObj)[0];\n return [asset, singleValue];\n }),\n );\n }\n\n /**\n * Builds a rates object that covers all given assets, ensuring that\n * any asset not returned by Snap is set to null for both `rate` and `conversionTime`.\n *\n * @param assets - The assets to build the rates for.\n * @param flattenedRates - The rates to merge.\n * @returns A rates object that covers all given assets.\n */\n #buildUpdatedRates(\n assets: CaipAssetType[],\n flattenedRates: Record<CaipAssetType, AssetConversion | null>,\n ): Record<string, AssetConversion & { currency: CaipAssetType }> {\n const updatedRates: Record<\n CaipAssetType,\n AssetConversion & { currency: CaipAssetType }\n > = {};\n\n for (const asset of assets) {\n if (flattenedRates[asset]) {\n updatedRates[asset] = {\n ...(flattenedRates[asset] as AssetConversion),\n currency:\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ??\n MAP_CAIP_CURRENCIES.usd,\n };\n }\n }\n return updatedRates;\n }\n\n /**\n * Merges the new rates into the controller’s state.\n *\n * @param updatedRates - The new rates to merge.\n */\n #applyUpdatedRates(\n updatedRates: Record<\n string,\n { rate: string | null; conversionTime: number | null }\n >,\n ): void {\n this.update((state: Draft<MultichainAssetsRatesControllerState>) => {\n state.conversionRates = {\n ...state.conversionRates,\n ...updatedRates,\n };\n });\n }\n\n /**\n * Forwards a Snap request to the SnapController.\n *\n * @param args - The request parameters.\n * @param args.snapId - The ID of the Snap.\n * @param args.handler - The handler type.\n * @param args.params - The asset conversions.\n * @returns A promise that resolves with the account rates.\n */\n async #handleSnapRequest({\n snapId,\n handler,\n params,\n }: {\n snapId: SnapId;\n handler: HandlerType;\n params: OnAssetsConversionArguments | OnAssetHistoricalPriceArguments;\n }): Promise<OnAssetsConversionResponse | OnAssetHistoricalPriceResponse> {\n return this.messagingSystem.call('SnapController:handleRequest', {\n snapId,\n origin: 'metamask',\n handler,\n request: {\n jsonrpc: '2.0',\n method: handler,\n params,\n },\n }) as Promise<OnAssetsConversionResponse | OnAssetHistoricalPriceResponse>;\n }\n}\n"]}
@@ -1,20 +1,26 @@
1
- import type { AccountsControllerListMultichainAccountsAction, AccountsControllerAccountAddedEvent } from "@metamask/accounts-controller";
1
+ import type { AccountsControllerListMultichainAccountsAction, AccountsControllerAccountAddedEvent, AccountsControllerGetSelectedMultichainAccountAction } from "@metamask/accounts-controller";
2
2
  import type { RestrictedMessenger, ControllerStateChangeEvent, ControllerGetStateAction } from "@metamask/base-controller";
3
3
  import { type CaipAssetType } from "@metamask/keyring-api";
4
4
  import type { KeyringControllerLockEvent, KeyringControllerUnlockEvent } from "@metamask/keyring-controller";
5
5
  import type { HandleSnapRequest } from "@metamask/snaps-controllers";
6
- import type { AssetConversion } from "@metamask/snaps-sdk";
6
+ import type { AssetConversion, HistoricalPriceIntervals } from "@metamask/snaps-sdk";
7
7
  import type { CurrencyRateStateChange, GetCurrencyRateState } from "../CurrencyRateController.cjs";
8
8
  import type { MultichainAssetsControllerGetStateAction, MultichainAssetsControllerStateChangeEvent } from "../MultichainAssetsController/index.cjs";
9
9
  /**
10
10
  * The name of the MultichainAssetsRatesController.
11
11
  */
12
12
  declare const controllerName = "MultichainAssetsRatesController";
13
+ type HistoricalPrice = {
14
+ intervals: HistoricalPriceIntervals;
15
+ updateTime: number;
16
+ expirationTime?: number;
17
+ };
13
18
  /**
14
19
  * State used by the MultichainAssetsRatesController to cache token conversion rates.
15
20
  */
16
21
  export type MultichainAssetsRatesControllerState = {
17
22
  conversionRates: Record<CaipAssetType, AssetConversion>;
23
+ historicalPrices: Record<CaipAssetType, Record<string, HistoricalPrice>>;
18
24
  };
19
25
  /**
20
26
  * Returns the state of the MultichainAssetsRatesController.
@@ -51,7 +57,7 @@ export type MultichainAssetsRatesControllerEvents = MultichainAssetsRatesControl
51
57
  /**
52
58
  * Actions that this controller is allowed to call.
53
59
  */
54
- export type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | GetCurrencyRateState | MultichainAssetsControllerGetStateAction;
60
+ export type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | GetCurrencyRateState | MultichainAssetsControllerGetStateAction | AccountsControllerGetSelectedMultichainAccountAction;
55
61
  /**
56
62
  * Events that this controller is allowed to subscribe to.
57
63
  */
@@ -119,6 +125,13 @@ export declare class MultichainAssetsRatesController extends MultichainAssetsRat
119
125
  * @returns A promise that resolves when the rates are updated.
120
126
  */
121
127
  updateAssetsRates(): Promise<void>;
128
+ /**
129
+ * Fetches historical prices for the current account
130
+ *
131
+ * @param asset - The asset to fetch historical prices for.
132
+ * @returns The historical prices.
133
+ */
134
+ fetchHistoricalPricesForAsset(asset: CaipAssetType): Promise<void>;
122
135
  }
123
136
  export {};
124
137
  //# sourceMappingURL=MultichainAssetsRatesController.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainAssetsRatesController.d.cts","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8CAA8C,EAC9C,mCAAmC,EACpC,sCAAsC;AACvC,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACzB,kCAAkC;AACnC,OAAO,EAAE,KAAK,aAAa,EAAoB,8BAA8B;AAC7E,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,qCAAqC;AAGtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AACrE,OAAO,KAAK,EAEV,eAAe,EAGhB,4BAA4B;AAM7B,OAAO,KAAK,EAEV,uBAAuB,EACvB,oBAAoB,EACrB,sCAAkC;AACnC,OAAO,KAAK,EACV,wCAAwC,EAExC,0CAA0C,EAC3C,gDAAsC;AAEvC;;GAEG;AACH,QAAA,MAAM,cAAc,oCAAoC,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,eAAe,EAAE,MAAM,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;CACzD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GACvD,wBAAwB,CACtB,OAAO,cAAc,EACrB,oCAAoC,CACrC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,gDAAgD,GAAG;IAC7D,IAAI,EAAE,GAAG,OAAO,cAAc,oBAAoB,CAAC;IACnD,OAAO,EAAE,+BAA+B,CAAC,mBAAmB,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,8CAA8C,IAAI,oCAAoC,CAErG;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,0BAA0B,CACxB,OAAO,cAAc,EACrB,oCAAoC,CACrC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAC9C,6CAA6C,GAC7C,gDAAgD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAC/C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,8CAA8C,GAC9C,oBAAoB,GACpB,wCAAwC,CAAC;AAC7C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,0BAA0B,GAC1B,4BAA4B,GAC5B,mCAAmC,GACnC,uBAAuB,GACvB,0CAA0C,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,wCAAwC,GAAG,mBAAmB,CACxE,OAAO,cAAc,EACrB,sCAAsC,GAAG,cAAc,EACvD,qCAAqC,GAAG,aAAa,EACrD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;;;;;;;;;;;;;;;;AAMF;;;;GAIG;AACH,qBAAa,+BAAgC,SAAQ,qCACnD,OAAO,cAAc,EACrB,oCAAoC,EACpC,wCAAwC,CACzC;;IASC;;;;;;;OAOG;gBACS,EACV,QAAgB,EAChB,KAAU,EACV,SAAS,GACV,EAAE;QACD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC,oCAAoC,CAAC,CAAC;QACtD,SAAS,EAAE,wCAAwC,CAAC;KACrD;IA8CD;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC;;;;OAIG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAmCD;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;CAqKzC"}
1
+ {"version":3,"file":"MultichainAssetsRatesController.d.cts","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,26 @@
1
- import type { AccountsControllerListMultichainAccountsAction, AccountsControllerAccountAddedEvent } from "@metamask/accounts-controller";
1
+ import type { AccountsControllerListMultichainAccountsAction, AccountsControllerAccountAddedEvent, AccountsControllerGetSelectedMultichainAccountAction } from "@metamask/accounts-controller";
2
2
  import type { RestrictedMessenger, ControllerStateChangeEvent, ControllerGetStateAction } from "@metamask/base-controller";
3
3
  import { type CaipAssetType } from "@metamask/keyring-api";
4
4
  import type { KeyringControllerLockEvent, KeyringControllerUnlockEvent } from "@metamask/keyring-controller";
5
5
  import type { HandleSnapRequest } from "@metamask/snaps-controllers";
6
- import type { AssetConversion } from "@metamask/snaps-sdk";
6
+ import type { AssetConversion, HistoricalPriceIntervals } from "@metamask/snaps-sdk";
7
7
  import type { CurrencyRateStateChange, GetCurrencyRateState } from "../CurrencyRateController.mjs";
8
8
  import type { MultichainAssetsControllerGetStateAction, MultichainAssetsControllerStateChangeEvent } from "../MultichainAssetsController/index.mjs";
9
9
  /**
10
10
  * The name of the MultichainAssetsRatesController.
11
11
  */
12
12
  declare const controllerName = "MultichainAssetsRatesController";
13
+ type HistoricalPrice = {
14
+ intervals: HistoricalPriceIntervals;
15
+ updateTime: number;
16
+ expirationTime?: number;
17
+ };
13
18
  /**
14
19
  * State used by the MultichainAssetsRatesController to cache token conversion rates.
15
20
  */
16
21
  export type MultichainAssetsRatesControllerState = {
17
22
  conversionRates: Record<CaipAssetType, AssetConversion>;
23
+ historicalPrices: Record<CaipAssetType, Record<string, HistoricalPrice>>;
18
24
  };
19
25
  /**
20
26
  * Returns the state of the MultichainAssetsRatesController.
@@ -51,7 +57,7 @@ export type MultichainAssetsRatesControllerEvents = MultichainAssetsRatesControl
51
57
  /**
52
58
  * Actions that this controller is allowed to call.
53
59
  */
54
- export type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | GetCurrencyRateState | MultichainAssetsControllerGetStateAction;
60
+ export type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | GetCurrencyRateState | MultichainAssetsControllerGetStateAction | AccountsControllerGetSelectedMultichainAccountAction;
55
61
  /**
56
62
  * Events that this controller is allowed to subscribe to.
57
63
  */
@@ -119,6 +125,13 @@ export declare class MultichainAssetsRatesController extends MultichainAssetsRat
119
125
  * @returns A promise that resolves when the rates are updated.
120
126
  */
121
127
  updateAssetsRates(): Promise<void>;
128
+ /**
129
+ * Fetches historical prices for the current account
130
+ *
131
+ * @param asset - The asset to fetch historical prices for.
132
+ * @returns The historical prices.
133
+ */
134
+ fetchHistoricalPricesForAsset(asset: CaipAssetType): Promise<void>;
122
135
  }
123
136
  export {};
124
137
  //# sourceMappingURL=MultichainAssetsRatesController.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainAssetsRatesController.d.mts","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8CAA8C,EAC9C,mCAAmC,EACpC,sCAAsC;AACvC,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACzB,kCAAkC;AACnC,OAAO,EAAE,KAAK,aAAa,EAAoB,8BAA8B;AAC7E,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,qCAAqC;AAGtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AACrE,OAAO,KAAK,EAEV,eAAe,EAGhB,4BAA4B;AAM7B,OAAO,KAAK,EAEV,uBAAuB,EACvB,oBAAoB,EACrB,sCAAkC;AACnC,OAAO,KAAK,EACV,wCAAwC,EAExC,0CAA0C,EAC3C,gDAAsC;AAEvC;;GAEG;AACH,QAAA,MAAM,cAAc,oCAAoC,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,eAAe,EAAE,MAAM,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;CACzD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GACvD,wBAAwB,CACtB,OAAO,cAAc,EACrB,oCAAoC,CACrC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,gDAAgD,GAAG;IAC7D,IAAI,EAAE,GAAG,OAAO,cAAc,oBAAoB,CAAC;IACnD,OAAO,EAAE,+BAA+B,CAAC,mBAAmB,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,8CAA8C,IAAI,oCAAoC,CAErG;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,0BAA0B,CACxB,OAAO,cAAc,EACrB,oCAAoC,CACrC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAC9C,6CAA6C,GAC7C,gDAAgD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAC/C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,8CAA8C,GAC9C,oBAAoB,GACpB,wCAAwC,CAAC;AAC7C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,0BAA0B,GAC1B,4BAA4B,GAC5B,mCAAmC,GACnC,uBAAuB,GACvB,0CAA0C,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,wCAAwC,GAAG,mBAAmB,CACxE,OAAO,cAAc,EACrB,sCAAsC,GAAG,cAAc,EACvD,qCAAqC,GAAG,aAAa,EACrD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;;;;;;;;;;;;;;;;AAMF;;;;GAIG;AACH,qBAAa,+BAAgC,SAAQ,qCACnD,OAAO,cAAc,EACrB,oCAAoC,EACpC,wCAAwC,CACzC;;IASC;;;;;;;OAOG;gBACS,EACV,QAAgB,EAChB,KAAU,EACV,SAAS,GACV,EAAE;QACD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC,oCAAoC,CAAC,CAAC;QACtD,SAAS,EAAE,wCAAwC,CAAC;KACrD;IA8CD;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC;;;;OAIG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAmCD;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;CAqKzC"}
1
+ {"version":3,"file":"MultichainAssetsRatesController.d.mts","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"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"}
@@ -28,10 +28,11 @@ const controllerName = 'MultichainAssetsRatesController';
28
28
  * @returns The default {@link MultichainAssetsRatesController} state.
29
29
  */
30
30
  export function getDefaultMultichainAssetsRatesControllerState() {
31
- return { conversionRates: {} };
31
+ return { conversionRates: {}, historicalPrices: {} };
32
32
  }
33
33
  const metadata = {
34
34
  conversionRates: { persist: true, anonymous: true },
35
+ historicalPrices: { persist: false, anonymous: true },
35
36
  };
36
37
  /**
37
38
  * Controller that manages multichain token conversion rates.
@@ -118,11 +119,14 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro
118
119
  // Build the conversions array
119
120
  const conversions = __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_buildConversions).call(this, assets);
120
121
  // Retrieve rates from Snap
121
- const accountRates = await __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_handleSnapRequest).call(this, {
122
+ const accountRates = (await __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_handleSnapRequest).call(this, {
122
123
  snapId: account?.metadata.snap?.id,
123
124
  handler: HandlerType.OnAssetsConversion,
124
- params: conversions,
125
- });
125
+ params: {
126
+ ...conversions,
127
+ includeMarketData: true,
128
+ },
129
+ }));
126
130
  // Flatten nested rates if needed
127
131
  const flattenedRates = __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_flattenRates).call(this, accountRates);
128
132
  // Build the updatedRates object for these assets
@@ -134,6 +138,55 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro
134
138
  releaseLock();
135
139
  });
136
140
  }
141
+ /**
142
+ * Fetches historical prices for the current account
143
+ *
144
+ * @param asset - The asset to fetch historical prices for.
145
+ * @returns The historical prices.
146
+ */
147
+ async fetchHistoricalPricesForAsset(asset) {
148
+ const releaseLock = await __classPrivateFieldGet(this, _MultichainAssetsRatesController_mutex, "f").acquire();
149
+ return (async () => {
150
+ const currentCaipCurrency = MAP_CAIP_CURRENCIES[__classPrivateFieldGet(this, _MultichainAssetsRatesController_currentCurrency, "f")] ?? MAP_CAIP_CURRENCIES.usd;
151
+ // Check if we already have historical prices for this asset and currency
152
+ const historicalPriceExpirationTime = this.state.historicalPrices[asset]?.[__classPrivateFieldGet(this, _MultichainAssetsRatesController_currentCurrency, "f")]
153
+ ?.expirationTime;
154
+ const historicalPriceHasExpired = historicalPriceExpirationTime &&
155
+ historicalPriceExpirationTime < Date.now();
156
+ if (historicalPriceHasExpired === false) {
157
+ return;
158
+ }
159
+ const selectedAccount = this.messagingSystem.call('AccountsController:getSelectedMultichainAccount');
160
+ try {
161
+ const historicalPricesResponse = await __classPrivateFieldGet(this, _MultichainAssetsRatesController_instances, "m", _MultichainAssetsRatesController_handleSnapRequest).call(this, {
162
+ snapId: selectedAccount?.metadata.snap?.id,
163
+ handler: HandlerType.OnAssetHistoricalPrice,
164
+ params: {
165
+ from: asset,
166
+ to: currentCaipCurrency,
167
+ },
168
+ });
169
+ // skip state update if no historical prices are returned
170
+ if (!historicalPricesResponse) {
171
+ return;
172
+ }
173
+ this.update((state) => {
174
+ state.historicalPrices = {
175
+ ...state.historicalPrices,
176
+ [asset]: {
177
+ ...state.historicalPrices[asset],
178
+ [__classPrivateFieldGet(this, _MultichainAssetsRatesController_currentCurrency, "f")]: historicalPricesResponse?.historicalPrice,
179
+ },
180
+ };
181
+ });
182
+ }
183
+ catch {
184
+ throw new Error(`Failed to fetch historical prices for asset: ${asset}`);
185
+ }
186
+ })().finally(() => {
187
+ releaseLock();
188
+ });
189
+ }
137
190
  }
138
191
  _MultichainAssetsRatesController_mutex = new WeakMap(), _MultichainAssetsRatesController_currentCurrency = new WeakMap(), _MultichainAssetsRatesController_accountsAssets = new WeakMap(), _MultichainAssetsRatesController_isUnlocked = new WeakMap(), _MultichainAssetsRatesController_instances = new WeakSet(), _MultichainAssetsRatesController_isNonEvmAccount = function _MultichainAssetsRatesController_isNonEvmAccount(account) {
139
192
  return (!isEvmAccountType(account.type) && account.metadata.snap !== undefined);