@metamask/assets-controllers 90.0.0 → 92.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 (90) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/dist/CurrencyRateController.cjs +3 -3
  3. package/dist/CurrencyRateController.cjs.map +1 -1
  4. package/dist/CurrencyRateController.d.cts.map +1 -1
  5. package/dist/CurrencyRateController.d.mts.map +1 -1
  6. package/dist/CurrencyRateController.mjs +3 -3
  7. package/dist/CurrencyRateController.mjs.map +1 -1
  8. package/dist/TokenBalancesController.cjs +48 -10
  9. package/dist/TokenBalancesController.cjs.map +1 -1
  10. package/dist/TokenBalancesController.d.cts +2 -1
  11. package/dist/TokenBalancesController.d.cts.map +1 -1
  12. package/dist/TokenBalancesController.d.mts +2 -1
  13. package/dist/TokenBalancesController.d.mts.map +1 -1
  14. package/dist/TokenBalancesController.mjs +49 -11
  15. package/dist/TokenBalancesController.mjs.map +1 -1
  16. package/dist/TokenDetectionController.cjs +12 -7
  17. package/dist/TokenDetectionController.cjs.map +1 -1
  18. package/dist/TokenDetectionController.d.cts +2 -1
  19. package/dist/TokenDetectionController.d.cts.map +1 -1
  20. package/dist/TokenDetectionController.d.mts +2 -1
  21. package/dist/TokenDetectionController.d.mts.map +1 -1
  22. package/dist/TokenDetectionController.mjs +12 -7
  23. package/dist/TokenDetectionController.mjs.map +1 -1
  24. package/dist/TokenRatesController.cjs +82 -278
  25. package/dist/TokenRatesController.cjs.map +1 -1
  26. package/dist/TokenRatesController.d.cts +9 -35
  27. package/dist/TokenRatesController.d.cts.map +1 -1
  28. package/dist/TokenRatesController.d.mts +9 -35
  29. package/dist/TokenRatesController.d.mts.map +1 -1
  30. package/dist/TokenRatesController.mjs +83 -279
  31. package/dist/TokenRatesController.mjs.map +1 -1
  32. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.cjs +2 -3
  33. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.cjs.map +1 -1
  34. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.d.cts.map +1 -1
  35. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.d.mts.map +1 -1
  36. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.mjs +2 -3
  37. package/dist/TokenSearchDiscoveryDataController/TokenSearchDiscoveryDataController.mjs.map +1 -1
  38. package/dist/TokenSearchDiscoveryDataController/types.cjs.map +1 -1
  39. package/dist/TokenSearchDiscoveryDataController/types.d.cts +2 -2
  40. package/dist/TokenSearchDiscoveryDataController/types.d.cts.map +1 -1
  41. package/dist/TokenSearchDiscoveryDataController/types.d.mts +2 -2
  42. package/dist/TokenSearchDiscoveryDataController/types.d.mts.map +1 -1
  43. package/dist/TokenSearchDiscoveryDataController/types.mjs.map +1 -1
  44. package/dist/assetsUtil.cjs +11 -5
  45. package/dist/assetsUtil.cjs.map +1 -1
  46. package/dist/assetsUtil.d.cts +2 -2
  47. package/dist/assetsUtil.d.cts.map +1 -1
  48. package/dist/assetsUtil.d.mts +2 -2
  49. package/dist/assetsUtil.d.mts.map +1 -1
  50. package/dist/assetsUtil.mjs +11 -5
  51. package/dist/assetsUtil.mjs.map +1 -1
  52. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +8 -8
  53. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
  54. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts +2 -1
  55. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
  56. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts +2 -1
  57. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
  58. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +8 -8
  59. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
  60. package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs +18 -8
  61. package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs.map +1 -1
  62. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts +4 -2
  63. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts.map +1 -1
  64. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts +4 -2
  65. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts.map +1 -1
  66. package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs +18 -8
  67. package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs.map +1 -1
  68. package/dist/token-prices-service/abstract-token-prices-service.cjs.map +1 -1
  69. package/dist/token-prices-service/abstract-token-prices-service.d.cts +17 -43
  70. package/dist/token-prices-service/abstract-token-prices-service.d.cts.map +1 -1
  71. package/dist/token-prices-service/abstract-token-prices-service.d.mts +17 -43
  72. package/dist/token-prices-service/abstract-token-prices-service.d.mts.map +1 -1
  73. package/dist/token-prices-service/abstract-token-prices-service.mjs.map +1 -1
  74. package/dist/token-prices-service/codefi-v2.cjs +177 -109
  75. package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
  76. package/dist/token-prices-service/codefi-v2.d.cts +47 -10
  77. package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
  78. package/dist/token-prices-service/codefi-v2.d.mts +47 -10
  79. package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
  80. package/dist/token-prices-service/codefi-v2.mjs +177 -109
  81. package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
  82. package/dist/token-service.cjs +6 -4
  83. package/dist/token-service.cjs.map +1 -1
  84. package/dist/token-service.d.cts +3 -1
  85. package/dist/token-service.d.cts.map +1 -1
  86. package/dist/token-service.d.mts +3 -1
  87. package/dist/token-service.d.mts.map +1 -1
  88. package/dist/token-service.mjs +6 -4
  89. package/dist/token-service.mjs.map +1 -1
  90. package/package.json +14 -24
package/CHANGELOG.md CHANGED
@@ -7,6 +7,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [92.0.0]
11
+
12
+ ### Added
13
+
14
+ - Support for optionally fetching market data when calling searchTokens ([#7226](https://github.com/MetaMask/core/pull/7226))
15
+ - **BREAKING:** Add optional JWT token authentication to multi-chain accounts API calls ([#7165](https://github.com/MetaMask/core/pull/7165))
16
+ - `fetchMultiChainBalances` and `fetchMultiChainBalancesV4` now accept an optional `jwtToken` parameter
17
+ - `TokenDetectionController` fetches and passes JWT token from `AuthenticationController` when using Accounts API
18
+ - `TokenBalancesController` fetches and passes JWT token through balance fetcher chain
19
+ - JWT token is included in `Authorization: Bearer <token>` header when provided
20
+ - Backward compatible: token parameter is optional and APIs work without authentication
21
+
22
+ ### Changed
23
+
24
+ - Move peer dependencies for controller and service packages to direct dependencies ([#7209](https://github.com/MetaMask/core/pull/7209), [#7220](https://github.com/MetaMask/core/pull/7220), [#7236](https://github.com/MetaMask/core/pull/7236))
25
+ - The dependencies moved are:
26
+ - `@metamask/account-tree-controller` (^4.0.0)
27
+ - `@metamask/accounts-controller` (^35.0.0)
28
+ - `@metamask/approval-controller` (^8.0.0)
29
+ - `@metamask/core-backend` (^5.0.0)
30
+ - `@metamask/keyring-controller` (^25.0.0)
31
+ - `@metamask/multichain-account-service` (^4.0.0)
32
+ - `@metamask/network-controller` (^26.0.0)
33
+ - `@metamask/permission-controller` (^12.1.1)
34
+ - `@metamask/phishing-controller` (^16.1.0)
35
+ - `@metamask/preferences-controller` (^22.0.0)
36
+ - `@metamask/profile-sync-controller` (^27.0.0)
37
+ - `@metamask/snaps-controllers` (^14.0.1)
38
+ - `@metamask/transaction-controller` (^62.3.0)
39
+ - In clients, it is now possible for multiple versions of these packages to exist in the dependency tree.
40
+ - For example, this scenario would be valid: a client relies on `@metamask/controller-a` 1.0.0 and `@metamask/controller-b` 1.0.0, and `@metamask/controller-b` depends on `@metamask/controller-a` 1.1.0.
41
+ - Note, however, that the versions specified in the client's `package.json` always "win", and you are expected to keep them up to date so as not to break controller and service intercommunication.
42
+
43
+ ### Fixed
44
+
45
+ - Fix `TokenBalancesController` state that store both lowercase and checksum account addresses ([#7217](https://github.com/MetaMask/core/pull/7217))
46
+ - `TokenBalancesController`: state inconsistency by ensuring all account addresses are stored in lowercase format ([#7216](https://github.com/MetaMask/core/pull/7216))
47
+ - Add MON (Monad) to supported currencies list in token prices service ([#7250](https://github.com/MetaMask/core/pull/7250))
48
+
49
+ ## [91.0.0]
50
+
51
+ ### Changed
52
+
53
+ - **BREAKING:** Update `spot-prices` endpoint to use Price API v3 ([#7119](https://github.com/MetaMask/core/pull/7119))
54
+ - Update `AbstractTokenPricesService.fetchTokenPrices` arguments and return type
55
+ - Update `CodefiTokenPricesServiceV2` list of supported currencies
56
+ - Update `TokenRatesController` to fetch prices by native currency instead of by chain
57
+ - Remove legacy polling code and unused events from `TokenRatesController`
58
+
10
59
  ## [90.0.0]
11
60
 
12
61
  ### Added
@@ -2306,7 +2355,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2306
2355
 
2307
2356
  - Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
2308
2357
 
2309
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@90.0.0...HEAD
2358
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@92.0.0...HEAD
2359
+ [92.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@91.0.0...@metamask/assets-controllers@92.0.0
2360
+ [91.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@90.0.0...@metamask/assets-controllers@91.0.0
2310
2361
  [90.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@89.0.1...@metamask/assets-controllers@90.0.0
2311
2362
  [89.0.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@89.0.0...@metamask/assets-controllers@89.0.1
2312
2363
  [89.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@88.0.0...@metamask/assets-controllers@89.0.0
@@ -207,11 +207,11 @@ _CurrencyRateController_tokenPricesService = new WeakMap(), _CurrencyRateControl
207
207
  const nativeTokenAddress = (0, codefi_v2_1.getNativeTokenAddress)(chainId);
208
208
  // Pass empty array as fetchTokenPrices automatically includes the native token address
209
209
  const tokenPrices = await __classPrivateFieldGet(this, _CurrencyRateController_tokenPricesService, "f").fetchTokenPrices({
210
- chainId,
211
- tokenAddresses: [],
210
+ assets: [{ chainId, tokenAddress: nativeTokenAddress }],
212
211
  currency: currentCurrency,
213
212
  });
214
- const tokenPrice = tokenPrices[nativeTokenAddress];
213
+ const tokenPrice = tokenPrices.find((item) => item.tokenAddress.toLowerCase() ===
214
+ nativeTokenAddress.toLowerCase());
215
215
  return {
216
216
  nativeCurrency,
217
217
  conversionDate: tokenPrice ? Date.now() / 1000 : null,
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.cjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly includeUsdRate;\n\n private readonly useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\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.updateExchangeRate(nativeCurrencies);\n }\n\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n try {\n const priceApiExchangeRatesResponse =\n await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.includeUsdRate,\n cryptocurrencies: [\n ...new Set(Object.values(nativeCurrenciesToFetch)),\n ],\n });\n\n const ratesPriceApi = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n const rate =\n priceApiExchangeRatesResponse[fetchedCurrency.toLowerCase()];\n\n acc[nativeCurrency] = {\n conversionDate: rate !== undefined ? Date.now() / 1000 : null,\n conversionRate: rate?.value\n ? Number((1 / rate?.value).toFixed(2))\n : null,\n usdConversionRate: rate?.usd\n ? Number((1 / rate?.usd).toFixed(2))\n : null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n return ratesPriceApi;\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n }\n\n // fallback using spot price from token prices service\n try {\n // Step 1: Get all network configurations to find matching chainIds for native currencies\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Step 2: Build a map of nativeCurrency -> chainId(s)\n const currencyToChainIds = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n // Find the first chainId that has this native currency\n const matchingEntry = (\n Object.entries(networkConfigurations) as [\n Hex,\n NetworkConfiguration,\n ][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = {\n fetchedCurrency,\n chainId: matchingEntry[0],\n };\n }\n\n return acc;\n },\n {} as Record<string, { fetchedCurrency: string; chainId: Hex }>,\n );\n\n // Step 3: Fetch token prices for each chainId\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n // Pass empty array as fetchTokenPrices automatically includes the native token address\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n chainId,\n tokenAddresses: [],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices[nativeTokenAddress];\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price ?? null,\n usdConversionRate: null, // Token prices service doesn't provide USD rate in this context\n };\n }),\n );\n const ratesFromTokenPrices = ratesResults.map((result, index) => {\n const [nativeCurrency, { chainId }] = currencyToChainIdsEntries[index];\n if (result.status === 'fulfilled') {\n return result.value;\n }\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n return {\n nativeCurrency,\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n });\n\n // Step 4: Convert to the expected format\n const ratesFromTokenPricesService = ratesFromTokenPrices.reduce(\n (acc, rate) => {\n acc[rate.nativeCurrency] = {\n conversionDate: rate.conversionDate,\n conversionRate: rate.conversionRate,\n usdConversionRate: rate.usdConversionRate,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n\n return ratesFromTokenPricesService;\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return null state for all requested currencies\n return Object.keys(nativeCurrenciesToFetch).reduce(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n }\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (!this.useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce(\n (acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n },\n {} as Record<string, string>,\n );\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
1
+ {"version":3,"file":"CurrencyRateController.cjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly includeUsdRate;\n\n private readonly useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\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.updateExchangeRate(nativeCurrencies);\n }\n\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n try {\n const priceApiExchangeRatesResponse =\n await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.includeUsdRate,\n cryptocurrencies: [\n ...new Set(Object.values(nativeCurrenciesToFetch)),\n ],\n });\n\n const ratesPriceApi = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n const rate =\n priceApiExchangeRatesResponse[fetchedCurrency.toLowerCase()];\n\n acc[nativeCurrency] = {\n conversionDate: rate !== undefined ? Date.now() / 1000 : null,\n conversionRate: rate?.value\n ? Number((1 / rate?.value).toFixed(2))\n : null,\n usdConversionRate: rate?.usd\n ? Number((1 / rate?.usd).toFixed(2))\n : null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n return ratesPriceApi;\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n }\n\n // fallback using spot price from token prices service\n try {\n // Step 1: Get all network configurations to find matching chainIds for native currencies\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Step 2: Build a map of nativeCurrency -> chainId(s)\n const currencyToChainIds = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n // Find the first chainId that has this native currency\n const matchingEntry = (\n Object.entries(networkConfigurations) as [\n Hex,\n NetworkConfiguration,\n ][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = {\n fetchedCurrency,\n chainId: matchingEntry[0],\n };\n }\n\n return acc;\n },\n {} as Record<string, { fetchedCurrency: string; chainId: Hex }>,\n );\n\n // Step 3: Fetch token prices for each chainId\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n // Pass empty array as fetchTokenPrices automatically includes the native token address\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n assets: [{ chainId, tokenAddress: nativeTokenAddress }],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices.find(\n (item) =>\n item.tokenAddress.toLowerCase() ===\n nativeTokenAddress.toLowerCase(),\n );\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price ?? null,\n usdConversionRate: null, // Token prices service doesn't provide USD rate in this context\n };\n }),\n );\n const ratesFromTokenPrices = ratesResults.map((result, index) => {\n const [nativeCurrency, { chainId }] = currencyToChainIdsEntries[index];\n if (result.status === 'fulfilled') {\n return result.value;\n }\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n return {\n nativeCurrency,\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n });\n\n // Step 4: Convert to the expected format\n const ratesFromTokenPricesService = ratesFromTokenPrices.reduce(\n (acc, rate) => {\n acc[rate.nativeCurrency] = {\n conversionDate: rate.conversionDate,\n conversionRate: rate.conversionRate,\n usdConversionRate: rate.usdConversionRate,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n\n return ratesFromTokenPricesService;\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return null state for all requested currencies\n return Object.keys(nativeCurrenciesToFetch).reduce(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n }\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (!this.useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce(\n (acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n },\n {} as Record<string, string>,\n );\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.d.cts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAgB;IAIpD;;;;;;;;;;OAUG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,mBAAgC,EAChC,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;QACpC,kBAAkB,EAAE,0BAA0B,CAAC;KAChD;IAaD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAqKhD;;;;OAIG;IACG,kBAAkB,CACtB,gBAAgB,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACvC,OAAO,CAAC,IAAI,CAAC;IA0ChB;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"CurrencyRateController.d.cts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAgB;IAIpD;;;;;;;;;;OAUG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,mBAAgC,EAChC,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;QACpC,kBAAkB,EAAE,0BAA0B,CAAC;KAChD;IAaD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAwKhD;;;;OAIG;IACG,kBAAkB,CACtB,gBAAgB,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACvC,OAAO,CAAC,IAAI,CAAC;IA0ChB;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.d.mts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAgB;IAIpD;;;;;;;;;;OAUG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,mBAAgC,EAChC,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;QACpC,kBAAkB,EAAE,0BAA0B,CAAC;KAChD;IAaD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAqKhD;;;;OAIG;IACG,kBAAkB,CACtB,gBAAgB,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACvC,OAAO,CAAC,IAAI,CAAC;IA0ChB;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"CurrencyRateController.d.mts","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AAKnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,qCAAqC;AAKtC,OAAO,KAAK,EAAE,0BAA0B,EAAE,iEAA6D;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CACnB,MAAM,EACN;QACE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CACF,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,IAAI,2BAA2B,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG,0BAA0B,CAC9D,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,uBAAuB,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAAG,wBAAwB,CACzD,OAAO,IAAI,EACX,iBAAiB,CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAEjE,KAAK,cAAc,GACf,2CAA2C,GAC3C,+BAA+B,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAC3C,OAAO,IAAI,EACX,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,CAC7B,CAAC;AA4BF,wEAAwE;AACxE,KAAK,wBAAwB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;;;;;;;;;;;;;;;;AAEF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,IAAI,EACX,iBAAiB,EACjB,qBAAqB,CACtB;;IACC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IAErC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAgB;IAIpD;;;;;;;;;;OAUG;gBACS,EACV,cAAsB,EACtB,QAAiB,EACjB,mBAAgC,EAChC,SAAS,EACT,KAAK,EACL,kBAAkB,GACnB,EAAE;QACD,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,qBAAqB,CAAC;QACjC,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;QACpC,kBAAkB,EAAE,0BAA0B,CAAC;KAChD;IAaD;;;;OAIG;IACG,kBAAkB,CAAC,eAAe,EAAE,MAAM;IAwKhD;;;;OAIG;IACG,kBAAkB,CACtB,gBAAgB,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACvC,OAAO,CAAC,IAAI,CAAC;IA0ChB;;;;OAIG;IACM,OAAO;IAKhB;;;;;OAKG;IACG,YAAY,CAAC,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C;AAED,eAAe,sBAAsB,CAAC"}
@@ -203,11 +203,11 @@ _CurrencyRateController_tokenPricesService = new WeakMap(), _CurrencyRateControl
203
203
  const nativeTokenAddress = getNativeTokenAddress(chainId);
204
204
  // Pass empty array as fetchTokenPrices automatically includes the native token address
205
205
  const tokenPrices = await __classPrivateFieldGet(this, _CurrencyRateController_tokenPricesService, "f").fetchTokenPrices({
206
- chainId,
207
- tokenAddresses: [],
206
+ assets: [{ chainId, tokenAddress: nativeTokenAddress }],
208
207
  currency: currentCurrency,
209
208
  });
210
- const tokenPrice = tokenPrices[nativeTokenAddress];
209
+ const tokenPrice = tokenPrices.find((item) => item.tokenAddress.toLowerCase() ===
210
+ nativeTokenAddress.toLowerCase());
211
211
  return {
212
212
  nativeCurrency,
213
213
  conversionDate: tokenPrice ? Date.now() / 1000 : null,
@@ -1 +1 @@
1
- {"version":3,"file":"CurrencyRateController.mjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly includeUsdRate;\n\n private readonly useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\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.updateExchangeRate(nativeCurrencies);\n }\n\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n try {\n const priceApiExchangeRatesResponse =\n await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.includeUsdRate,\n cryptocurrencies: [\n ...new Set(Object.values(nativeCurrenciesToFetch)),\n ],\n });\n\n const ratesPriceApi = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n const rate =\n priceApiExchangeRatesResponse[fetchedCurrency.toLowerCase()];\n\n acc[nativeCurrency] = {\n conversionDate: rate !== undefined ? Date.now() / 1000 : null,\n conversionRate: rate?.value\n ? Number((1 / rate?.value).toFixed(2))\n : null,\n usdConversionRate: rate?.usd\n ? Number((1 / rate?.usd).toFixed(2))\n : null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n return ratesPriceApi;\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n }\n\n // fallback using spot price from token prices service\n try {\n // Step 1: Get all network configurations to find matching chainIds for native currencies\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Step 2: Build a map of nativeCurrency -> chainId(s)\n const currencyToChainIds = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n // Find the first chainId that has this native currency\n const matchingEntry = (\n Object.entries(networkConfigurations) as [\n Hex,\n NetworkConfiguration,\n ][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = {\n fetchedCurrency,\n chainId: matchingEntry[0],\n };\n }\n\n return acc;\n },\n {} as Record<string, { fetchedCurrency: string; chainId: Hex }>,\n );\n\n // Step 3: Fetch token prices for each chainId\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n // Pass empty array as fetchTokenPrices automatically includes the native token address\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n chainId,\n tokenAddresses: [],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices[nativeTokenAddress];\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price ?? null,\n usdConversionRate: null, // Token prices service doesn't provide USD rate in this context\n };\n }),\n );\n const ratesFromTokenPrices = ratesResults.map((result, index) => {\n const [nativeCurrency, { chainId }] = currencyToChainIdsEntries[index];\n if (result.status === 'fulfilled') {\n return result.value;\n }\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n return {\n nativeCurrency,\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n });\n\n // Step 4: Convert to the expected format\n const ratesFromTokenPricesService = ratesFromTokenPrices.reduce(\n (acc, rate) => {\n acc[rate.nativeCurrency] = {\n conversionDate: rate.conversionDate,\n conversionRate: rate.conversionRate,\n usdConversionRate: rate.usdConversionRate,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n\n return ratesFromTokenPricesService;\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return null state for all requested currencies\n return Object.keys(nativeCurrenciesToFetch).reduce(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n }\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (!this.useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce(\n (acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n },\n {} as Record<string, string>,\n );\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
1
+ {"version":3,"file":"CurrencyRateController.mjs","sourceRoot":"","sources":["../src/CurrencyRateController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n TESTNET_TICKER_SYMBOLS,\n FALL_BACK_VS_CURRENCY,\n} from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkConfiguration,\n} from '@metamask/network-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { AbstractTokenPricesService } from './token-prices-service/abstract-token-prices-service';\nimport { getNativeTokenAddress } from './token-prices-service/codefi-v2';\n\n/**\n * currencyRates - Object keyed by native currency\n *\n * currencyRates.conversionDate - Timestamp of conversion rate expressed in ms since UNIX epoch\n *\n * currencyRates.conversionRate - Conversion rate from current base asset to the current currency\n *\n * currentCurrency - Currently-active ISO 4217 currency code\n *\n * usdConversionRate - Conversion rate from usd to the current currency\n */\nexport type CurrencyRateState = {\n currentCurrency: string;\n currencyRates: Record<\n string,\n {\n conversionDate: number | null;\n conversionRate: number | null;\n usdConversionRate: number | null;\n }\n >;\n};\n\nconst name = 'CurrencyRateController';\n\nexport type CurrencyRateStateChange = ControllerStateChangeEvent<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerEvents = CurrencyRateStateChange;\n\nexport type GetCurrencyRateState = ControllerGetStateAction<\n typeof name,\n CurrencyRateState\n>;\n\nexport type CurrencyRateControllerActions = GetCurrencyRateState;\n\ntype AllowedActions =\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerGetStateAction;\n\nexport type CurrencyRateMessenger = Messenger<\n typeof name,\n CurrencyRateControllerActions | AllowedActions,\n CurrencyRateControllerEvents\n>;\n\nconst metadata: StateMetadata<CurrencyRateState> = {\n currentCurrency: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n currencyRates: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nconst defaultState = {\n currentCurrency: 'usd',\n currencyRates: {\n ETH: {\n conversionDate: 0,\n conversionRate: 0,\n usdConversionRate: null,\n },\n },\n};\n\n/** The input to start polling for the {@link CurrencyRateController} */\ntype CurrencyRatePollingInput = {\n nativeCurrencies: string[];\n};\n\n/**\n * Controller that passively polls on a set interval for an exchange rate from the current network\n * asset to the user's preferred currency.\n */\nexport class CurrencyRateController extends StaticIntervalPollingController<CurrencyRatePollingInput>()<\n typeof name,\n CurrencyRateState,\n CurrencyRateMessenger\n> {\n private readonly mutex = new Mutex();\n\n private readonly includeUsdRate;\n\n private readonly useExternalServices: () => boolean;\n\n readonly #tokenPricesService: AbstractTokenPricesService;\n\n /**\n * Creates a CurrencyRateController instance.\n *\n * @param options - Constructor options.\n * @param options.includeUsdRate - Keep track of the USD rate in addition to the current currency rate.\n * @param options.interval - The polling interval, in milliseconds.\n * @param options.messenger - A reference to the messenger.\n * @param options.state - Initial state to set on this controller.\n * @param options.useExternalServices - Feature Switch for using external services (default: true)\n * @param options.tokenPricesService - An object in charge of retrieving token prices\n */\n constructor({\n includeUsdRate = false,\n interval = 180000,\n useExternalServices = () => true,\n messenger,\n state,\n tokenPricesService,\n }: {\n includeUsdRate?: boolean;\n interval?: number;\n messenger: CurrencyRateMessenger;\n state?: Partial<CurrencyRateState>;\n useExternalServices?: () => boolean;\n tokenPricesService: AbstractTokenPricesService;\n }) {\n super({\n name,\n metadata,\n messenger,\n state: { ...defaultState, ...state },\n });\n this.includeUsdRate = includeUsdRate;\n this.useExternalServices = useExternalServices;\n this.setIntervalLength(interval);\n this.#tokenPricesService = tokenPricesService;\n }\n\n /**\n * Sets a currency to track.\n *\n * @param currentCurrency - ISO 4217 currency code.\n */\n async setCurrentCurrency(currentCurrency: string) {\n const releaseLock = await this.mutex.acquire();\n const nativeCurrencies = Object.keys(this.state.currencyRates);\n try {\n this.update(() => {\n return {\n ...defaultState,\n currentCurrency,\n };\n });\n } finally {\n releaseLock();\n }\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.updateExchangeRate(nativeCurrencies);\n }\n\n async #fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch: Record<string, string>,\n ): Promise<CurrencyRateState['currencyRates']> {\n const { currentCurrency } = this.state;\n\n try {\n const priceApiExchangeRatesResponse =\n await this.#tokenPricesService.fetchExchangeRates({\n baseCurrency: currentCurrency,\n includeUsdRate: this.includeUsdRate,\n cryptocurrencies: [\n ...new Set(Object.values(nativeCurrenciesToFetch)),\n ],\n });\n\n const ratesPriceApi = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n const rate =\n priceApiExchangeRatesResponse[fetchedCurrency.toLowerCase()];\n\n acc[nativeCurrency] = {\n conversionDate: rate !== undefined ? Date.now() / 1000 : null,\n conversionRate: rate?.value\n ? Number((1 / rate?.value).toFixed(2))\n : null,\n usdConversionRate: rate?.usd\n ? Number((1 / rate?.usd).toFixed(2))\n : null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n return ratesPriceApi;\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n }\n\n // fallback using spot price from token prices service\n try {\n // Step 1: Get all network configurations to find matching chainIds for native currencies\n const networkControllerState = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfigurations =\n networkControllerState.networkConfigurationsByChainId;\n\n // Step 2: Build a map of nativeCurrency -> chainId(s)\n const currencyToChainIds = Object.entries(nativeCurrenciesToFetch).reduce(\n (acc, [nativeCurrency, fetchedCurrency]) => {\n // Find the first chainId that has this native currency\n const matchingEntry = (\n Object.entries(networkConfigurations) as [\n Hex,\n NetworkConfiguration,\n ][]\n ).find(\n ([, config]) =>\n config.nativeCurrency.toUpperCase() ===\n fetchedCurrency.toUpperCase(),\n );\n\n if (matchingEntry) {\n acc[nativeCurrency] = {\n fetchedCurrency,\n chainId: matchingEntry[0],\n };\n }\n\n return acc;\n },\n {} as Record<string, { fetchedCurrency: string; chainId: Hex }>,\n );\n\n // Step 3: Fetch token prices for each chainId\n const currencyToChainIdsEntries = Object.entries(currencyToChainIds);\n const ratesResults = await Promise.allSettled(\n currencyToChainIdsEntries.map(async ([nativeCurrency, { chainId }]) => {\n const nativeTokenAddress = getNativeTokenAddress(chainId);\n // Pass empty array as fetchTokenPrices automatically includes the native token address\n const tokenPrices = await this.#tokenPricesService.fetchTokenPrices({\n assets: [{ chainId, tokenAddress: nativeTokenAddress }],\n currency: currentCurrency,\n });\n\n const tokenPrice = tokenPrices.find(\n (item) =>\n item.tokenAddress.toLowerCase() ===\n nativeTokenAddress.toLowerCase(),\n );\n\n return {\n nativeCurrency,\n conversionDate: tokenPrice ? Date.now() / 1000 : null,\n conversionRate: tokenPrice?.price ?? null,\n usdConversionRate: null, // Token prices service doesn't provide USD rate in this context\n };\n }),\n );\n const ratesFromTokenPrices = ratesResults.map((result, index) => {\n const [nativeCurrency, { chainId }] = currencyToChainIdsEntries[index];\n if (result.status === 'fulfilled') {\n return result.value;\n }\n console.error(\n `Failed to fetch token price for ${nativeCurrency} on chain ${chainId}`,\n result.reason,\n );\n return {\n nativeCurrency,\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n });\n\n // Step 4: Convert to the expected format\n const ratesFromTokenPricesService = ratesFromTokenPrices.reduce(\n (acc, rate) => {\n acc[rate.nativeCurrency] = {\n conversionDate: rate.conversionDate,\n conversionRate: rate.conversionRate,\n usdConversionRate: rate.usdConversionRate,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n\n return ratesFromTokenPricesService;\n } catch (error) {\n console.error(\n 'Failed to fetch exchange rates from token prices service.',\n error,\n );\n // Return null state for all requested currencies\n return Object.keys(nativeCurrenciesToFetch).reduce(\n (acc, nativeCurrency) => {\n acc[nativeCurrency] = {\n conversionDate: null,\n conversionRate: null,\n usdConversionRate: null,\n };\n return acc;\n },\n {} as CurrencyRateState['currencyRates'],\n );\n }\n }\n\n /**\n * Updates the exchange rate for the current currency and native currency pairs.\n *\n * @param nativeCurrencies - The native currency symbols to fetch exchange rates for.\n */\n async updateExchangeRate(\n nativeCurrencies: (string | undefined)[],\n ): Promise<void> {\n if (!this.useExternalServices()) {\n return;\n }\n\n const releaseLock = await this.mutex.acquire();\n try {\n // For preloaded testnets (Goerli, Sepolia) we want to fetch exchange rate for real ETH.\n // Map each native currency to the symbol we want to fetch for it.\n const testnetSymbols = Object.values(TESTNET_TICKER_SYMBOLS);\n const nativeCurrenciesToFetch = nativeCurrencies.reduce(\n (acc, nativeCurrency) => {\n if (!nativeCurrency) {\n return acc;\n }\n\n acc[nativeCurrency] = testnetSymbols.includes(nativeCurrency)\n ? FALL_BACK_VS_CURRENCY\n : nativeCurrency;\n return acc;\n },\n {} as Record<string, string>,\n );\n\n const rates = await this.#fetchExchangeRatesWithFallback(\n nativeCurrenciesToFetch,\n );\n\n this.update((state) => {\n state.currencyRates = {\n ...state.currencyRates,\n ...rates,\n };\n });\n } catch (error) {\n console.error('Failed to fetch exchange rates.', error);\n throw error;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Prepare to discard this controller.\n *\n * This stops any active polling.\n */\n override destroy() {\n super.destroy();\n this.stopAllPolling();\n }\n\n /**\n * Updates exchange rate for the current currency.\n *\n * @param input - The input for the poll.\n * @param input.nativeCurrencies - The native currency symbols to poll prices for.\n */\n async _executePoll({\n nativeCurrencies,\n }: CurrencyRatePollingInput): Promise<void> {\n await this.updateExchangeRate(nativeCurrencies);\n }\n}\n\nexport default CurrencyRateController;\n"]}
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
2
7
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
8
  if (kind === "m") throw new TypeError("Private method is not writable");
4
9
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
12
  };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _TokenBalancesController_instances, _TokenBalancesController_platform, _TokenBalancesController_queryAllAccounts, _TokenBalancesController_accountsApiChainIds, _TokenBalancesController_balanceFetchers, _TokenBalancesController_allTokens, _TokenBalancesController_detectedTokens, _TokenBalancesController_allIgnoredTokens, _TokenBalancesController_defaultInterval, _TokenBalancesController_websocketActivePollingInterval, _TokenBalancesController_chainPollingConfig, _TokenBalancesController_intervalPollingTimers, _TokenBalancesController_isControllerPollingActive, _TokenBalancesController_requestedChainIds, _TokenBalancesController_statusChangeDebouncer, _TokenBalancesController_chainIdsWithTokens, _TokenBalancesController_getProvider, _TokenBalancesController_getNetworkClient, _TokenBalancesController_createAccountsApiFetcher, _TokenBalancesController_startIntervalGroupPolling, _TokenBalancesController_startPollingForInterval, _TokenBalancesController_setPollingTimer, _TokenBalancesController_isTokenTracked, _TokenBalancesController_onTokensChanged, _TokenBalancesController_onNetworkChanged, _TokenBalancesController_onAccountRemoved, _TokenBalancesController_prepareBalanceUpdates, _TokenBalancesController_onAccountActivityBalanceUpdate, _TokenBalancesController_onAccountActivityStatusChanged, _TokenBalancesController_processAccumulatedStatusChanges;
13
+ var _TokenBalancesController_instances, _TokenBalancesController_platform, _TokenBalancesController_queryAllAccounts, _TokenBalancesController_accountsApiChainIds, _TokenBalancesController_balanceFetchers, _TokenBalancesController_allTokens, _TokenBalancesController_detectedTokens, _TokenBalancesController_allIgnoredTokens, _TokenBalancesController_defaultInterval, _TokenBalancesController_websocketActivePollingInterval, _TokenBalancesController_chainPollingConfig, _TokenBalancesController_intervalPollingTimers, _TokenBalancesController_isControllerPollingActive, _TokenBalancesController_requestedChainIds, _TokenBalancesController_statusChangeDebouncer, _TokenBalancesController_normalizeAccountAddresses, _TokenBalancesController_chainIdsWithTokens, _TokenBalancesController_getProvider, _TokenBalancesController_getNetworkClient, _TokenBalancesController_createAccountsApiFetcher, _TokenBalancesController_startIntervalGroupPolling, _TokenBalancesController_startPollingForInterval, _TokenBalancesController_setPollingTimer, _TokenBalancesController_isTokenTracked, _TokenBalancesController_onTokensChanged, _TokenBalancesController_onNetworkChanged, _TokenBalancesController_onAccountRemoved, _TokenBalancesController_prepareBalanceUpdates, _TokenBalancesController_onAccountActivityBalanceUpdate, _TokenBalancesController_onAccountActivityStatusChanged, _TokenBalancesController_processAccumulatedStatusChanges;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.TokenBalancesController = exports.parseAssetType = exports.caipChainIdToHex = void 0;
16
16
  const providers_1 = require("@ethersproject/providers");
@@ -337,6 +337,8 @@ class TokenBalancesController extends (0, polling_controller_1.StaticIntervalPol
337
337
  __classPrivateFieldGet(this, _TokenBalancesController_instances, "m", _TokenBalancesController_processAccumulatedStatusChanges).call(this);
338
338
  }, 5000); // 5-second debounce window
339
339
  });
340
+ // Normalize all account addresses to lowercase in existing state
341
+ __classPrivateFieldGet(this, _TokenBalancesController_instances, "m", _TokenBalancesController_normalizeAccountAddresses).call(this);
340
342
  __classPrivateFieldSet(this, _TokenBalancesController_platform, platform ?? 'extension', "f");
341
343
  __classPrivateFieldSet(this, _TokenBalancesController_queryAllAccounts, queryMultipleAccounts, "f");
342
344
  __classPrivateFieldSet(this, _TokenBalancesController_accountsApiChainIds, accountsApiChainIds, "f");
@@ -457,6 +459,9 @@ class TokenBalancesController extends (0, polling_controller_1.StaticIntervalPol
457
459
  }
458
460
  const { address: selected } = this.messenger.call('AccountsController:getSelectedAccount');
459
461
  const allAccounts = this.messenger.call('AccountsController:listAccounts');
462
+ const jwtToken = await (0, controller_utils_1.safelyExecuteWithTimeout)(() => {
463
+ return this.messenger.call('AuthenticationController:getBearerToken');
464
+ }, false, 5000);
460
465
  const aggregated = [];
461
466
  let remainingChains = [...targetChains];
462
467
  // Try each fetcher in order, removing successfully processed chains
@@ -471,6 +476,7 @@ class TokenBalancesController extends (0, polling_controller_1.StaticIntervalPol
471
476
  queryAllAccounts: queryAllAccounts ?? __classPrivateFieldGet(this, _TokenBalancesController_queryAllAccounts, "f"),
472
477
  selectedAccount: selected,
473
478
  allAccounts,
479
+ jwtToken,
474
480
  });
475
481
  if (result.balances && result.balances.length > 0) {
476
482
  aggregated.push(...result.balances);
@@ -535,14 +541,16 @@ class TokenBalancesController extends (0, polling_controller_1.StaticIntervalPol
535
541
  }
536
542
  // Update with actual fetched balances only if the value has changed
537
543
  aggregated.forEach(({ success, value, account, token, chainId }) => {
538
- var _a, _b, _c;
544
+ var _a, _b;
539
545
  if (success && value !== undefined) {
546
+ // Ensure all accounts we add/update are in lower-case
547
+ const lowerCaseAccount = account.toLowerCase();
540
548
  const newBalance = (0, controller_utils_1.toHex)(value);
541
549
  const tokenAddress = checksum(token);
542
- const currentBalance = d.tokenBalances[account]?.[chainId]?.[tokenAddress];
550
+ const currentBalance = d.tokenBalances[lowerCaseAccount]?.[chainId]?.[tokenAddress];
543
551
  // Only update if the balance has actually changed
544
552
  if (currentBalance !== newBalance) {
545
- ((_c = ((_a = d.tokenBalances)[_b = account] ?? (_a[_b] = {})))[chainId] ?? (_c[chainId] = {}))[tokenAddress] = newBalance;
553
+ ((_b = ((_a = d.tokenBalances)[lowerCaseAccount] ?? (_a[lowerCaseAccount] = {})))[chainId] ?? (_b[chainId] = {}))[tokenAddress] = newBalance;
546
554
  }
547
555
  }
548
556
  });
@@ -619,7 +627,37 @@ class TokenBalancesController extends (0, polling_controller_1.StaticIntervalPol
619
627
  }
620
628
  }
621
629
  exports.TokenBalancesController = TokenBalancesController;
622
- _TokenBalancesController_platform = new WeakMap(), _TokenBalancesController_queryAllAccounts = new WeakMap(), _TokenBalancesController_accountsApiChainIds = new WeakMap(), _TokenBalancesController_balanceFetchers = new WeakMap(), _TokenBalancesController_allTokens = new WeakMap(), _TokenBalancesController_detectedTokens = new WeakMap(), _TokenBalancesController_allIgnoredTokens = new WeakMap(), _TokenBalancesController_defaultInterval = new WeakMap(), _TokenBalancesController_websocketActivePollingInterval = new WeakMap(), _TokenBalancesController_chainPollingConfig = new WeakMap(), _TokenBalancesController_intervalPollingTimers = new WeakMap(), _TokenBalancesController_isControllerPollingActive = new WeakMap(), _TokenBalancesController_requestedChainIds = new WeakMap(), _TokenBalancesController_statusChangeDebouncer = new WeakMap(), _TokenBalancesController_getProvider = new WeakMap(), _TokenBalancesController_getNetworkClient = new WeakMap(), _TokenBalancesController_createAccountsApiFetcher = new WeakMap(), _TokenBalancesController_onTokensChanged = new WeakMap(), _TokenBalancesController_onNetworkChanged = new WeakMap(), _TokenBalancesController_onAccountRemoved = new WeakMap(), _TokenBalancesController_onAccountActivityBalanceUpdate = new WeakMap(), _TokenBalancesController_onAccountActivityStatusChanged = new WeakMap(), _TokenBalancesController_instances = new WeakSet(), _TokenBalancesController_chainIdsWithTokens = function _TokenBalancesController_chainIdsWithTokens() {
630
+ _TokenBalancesController_platform = new WeakMap(), _TokenBalancesController_queryAllAccounts = new WeakMap(), _TokenBalancesController_accountsApiChainIds = new WeakMap(), _TokenBalancesController_balanceFetchers = new WeakMap(), _TokenBalancesController_allTokens = new WeakMap(), _TokenBalancesController_detectedTokens = new WeakMap(), _TokenBalancesController_allIgnoredTokens = new WeakMap(), _TokenBalancesController_defaultInterval = new WeakMap(), _TokenBalancesController_websocketActivePollingInterval = new WeakMap(), _TokenBalancesController_chainPollingConfig = new WeakMap(), _TokenBalancesController_intervalPollingTimers = new WeakMap(), _TokenBalancesController_isControllerPollingActive = new WeakMap(), _TokenBalancesController_requestedChainIds = new WeakMap(), _TokenBalancesController_statusChangeDebouncer = new WeakMap(), _TokenBalancesController_getProvider = new WeakMap(), _TokenBalancesController_getNetworkClient = new WeakMap(), _TokenBalancesController_createAccountsApiFetcher = new WeakMap(), _TokenBalancesController_onTokensChanged = new WeakMap(), _TokenBalancesController_onNetworkChanged = new WeakMap(), _TokenBalancesController_onAccountRemoved = new WeakMap(), _TokenBalancesController_onAccountActivityBalanceUpdate = new WeakMap(), _TokenBalancesController_onAccountActivityStatusChanged = new WeakMap(), _TokenBalancesController_instances = new WeakSet(), _TokenBalancesController_normalizeAccountAddresses = function _TokenBalancesController_normalizeAccountAddresses() {
631
+ const currentState = this.state.tokenBalances;
632
+ const normalizedBalances = {};
633
+ // Iterate through all accounts and normalize to lowercase
634
+ for (const address of Object.keys(currentState)) {
635
+ const lowercaseAddress = address.toLowerCase();
636
+ const accountBalances = currentState[address];
637
+ if (!accountBalances) {
638
+ continue;
639
+ }
640
+ // If this lowercase address doesn't exist yet, create it
641
+ if (!normalizedBalances[lowercaseAddress]) {
642
+ normalizedBalances[lowercaseAddress] = {};
643
+ }
644
+ // Merge chain data
645
+ for (const chainId of Object.keys(accountBalances)) {
646
+ const chainIdKey = chainId;
647
+ if (!normalizedBalances[lowercaseAddress][chainIdKey]) {
648
+ normalizedBalances[lowercaseAddress][chainIdKey] = {};
649
+ }
650
+ // Merge token balances (later values override earlier ones if duplicates exist)
651
+ Object.assign(normalizedBalances[lowercaseAddress][chainIdKey], accountBalances[chainIdKey]);
652
+ }
653
+ }
654
+ // Only update if there were changes
655
+ if (Object.keys(currentState).length !==
656
+ Object.keys(normalizedBalances).length ||
657
+ Object.keys(currentState).some((addr) => addr !== addr.toLowerCase())) {
658
+ this.update(() => ({ tokenBalances: normalizedBalances }));
659
+ }
660
+ }, _TokenBalancesController_chainIdsWithTokens = function _TokenBalancesController_chainIdsWithTokens() {
623
661
  return [
624
662
  ...new Set([
625
663
  ...Object.keys(__classPrivateFieldGet(this, _TokenBalancesController_allTokens, "f")),