@metamask/assets-controller 2.2.0 → 2.4.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 (74) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/dist/AssetsController-method-action-types.cjs.map +1 -1
  3. package/dist/AssetsController-method-action-types.d.cts +14 -3
  4. package/dist/AssetsController-method-action-types.d.cts.map +1 -1
  5. package/dist/AssetsController-method-action-types.d.mts +14 -3
  6. package/dist/AssetsController-method-action-types.d.mts.map +1 -1
  7. package/dist/AssetsController-method-action-types.mjs.map +1 -1
  8. package/dist/AssetsController.cjs +46 -5
  9. package/dist/AssetsController.cjs.map +1 -1
  10. package/dist/AssetsController.d.cts +12 -6
  11. package/dist/AssetsController.d.cts.map +1 -1
  12. package/dist/AssetsController.d.mts +12 -6
  13. package/dist/AssetsController.d.mts.map +1 -1
  14. package/dist/AssetsController.mjs +47 -6
  15. package/dist/AssetsController.mjs.map +1 -1
  16. package/dist/data-sources/PriceDataSource.cjs +48 -29
  17. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  18. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  19. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  20. package/dist/data-sources/PriceDataSource.mjs +48 -29
  21. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  22. package/dist/data-sources/RpcDataSource.cjs +102 -18
  23. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  24. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  25. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  26. package/dist/data-sources/RpcDataSource.mjs +102 -18
  27. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  28. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +1 -1
  29. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
  30. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +1 -1
  31. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
  32. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +1 -1
  33. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
  34. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +1 -1
  35. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
  36. package/dist/index.cjs +2 -1
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +3 -3
  39. package/dist/index.d.cts.map +1 -1
  40. package/dist/index.d.mts +3 -3
  41. package/dist/index.d.mts.map +1 -1
  42. package/dist/index.mjs +1 -1
  43. package/dist/index.mjs.map +1 -1
  44. package/dist/types.cjs.map +1 -1
  45. package/dist/types.d.cts +9 -11
  46. package/dist/types.d.cts.map +1 -1
  47. package/dist/types.d.mts +9 -11
  48. package/dist/types.d.mts.map +1 -1
  49. package/dist/types.mjs.map +1 -1
  50. package/dist/utils/formatExchangeRatesForBridge.cjs +67 -60
  51. package/dist/utils/formatExchangeRatesForBridge.cjs.map +1 -1
  52. package/dist/utils/formatExchangeRatesForBridge.d.cts +5 -35
  53. package/dist/utils/formatExchangeRatesForBridge.d.cts.map +1 -1
  54. package/dist/utils/formatExchangeRatesForBridge.d.mts +5 -35
  55. package/dist/utils/formatExchangeRatesForBridge.d.mts.map +1 -1
  56. package/dist/utils/formatExchangeRatesForBridge.mjs +68 -61
  57. package/dist/utils/formatExchangeRatesForBridge.mjs.map +1 -1
  58. package/dist/utils/formatStateForTransactionPay.cjs +125 -0
  59. package/dist/utils/formatStateForTransactionPay.cjs.map +1 -0
  60. package/dist/utils/formatStateForTransactionPay.d.cts +66 -0
  61. package/dist/utils/formatStateForTransactionPay.d.cts.map +1 -0
  62. package/dist/utils/formatStateForTransactionPay.d.mts +66 -0
  63. package/dist/utils/formatStateForTransactionPay.d.mts.map +1 -0
  64. package/dist/utils/formatStateForTransactionPay.mjs +121 -0
  65. package/dist/utils/formatStateForTransactionPay.mjs.map +1 -0
  66. package/dist/utils/index.cjs +3 -1
  67. package/dist/utils/index.cjs.map +1 -1
  68. package/dist/utils/index.d.cts +3 -1
  69. package/dist/utils/index.d.cts.map +1 -1
  70. package/dist/utils/index.d.mts +3 -1
  71. package/dist/utils/index.d.mts.map +1 -1
  72. package/dist/utils/index.mjs +1 -0
  73. package/dist/utils/index.mjs.map +1 -1
  74. package/package.json +8 -8
@@ -5,11 +5,6 @@ const util_1 = require("@ethereumjs/util");
5
5
  const assets_controllers_1 = require("@metamask/assets-controllers");
6
6
  const utils_1 = require("@metamask/utils");
7
7
  const utils_2 = require("@metamask/utils");
8
- function getPriceNumber(price) {
9
- return typeof price === 'object' && price !== null && 'price' in price
10
- ? Number(price.price)
11
- : Number.NaN;
12
- }
13
8
  /**
14
9
  * Converts AssetsController state (assetsPrice, selectedCurrency) into the
15
10
  * same format the bridge expects from MultichainAssetsRatesController,
@@ -17,62 +12,55 @@ function getPriceNumber(price) {
17
12
  * a single action when useAssetsControllerForRates is true.
18
13
  *
19
14
  * @param params - Conversion parameters.
20
- * @param params.assetsPrice - Map of CAIP-19 asset ID to price data. Prices are in USD.
15
+ * @param params.assetsPrice - Map of CAIP-19 asset ID to price data (must include both `price` and `usdPrice`).
21
16
  * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').
22
17
  * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.
23
18
  * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').
24
- * @param params.usdToSelectedCurrencyRate - Optional rate: 1 USD = this many units of selected currency. Required for correct bridge USD conversion when selectedCurrency is not 'usd'. When omitted and selectedCurrency !== 'usd', currencyRates will use the same value for conversionRate and usdConversionRate (ratio 1), which produces incorrect USD rates.
25
19
  * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.
26
20
  */
27
21
  function formatExchangeRatesForBridge(params) {
28
- const { assetsPrice, selectedCurrency, nativeAssetIdentifiers = {}, networkConfigurationsByChainId = {}, usdToSelectedCurrencyRate, } = params;
22
+ const { assetsPrice, selectedCurrency, nativeAssetIdentifiers = {}, networkConfigurationsByChainId = {}, } = params;
29
23
  const conversionRates = {};
30
24
  const currencyRates = {};
31
25
  const marketData = {};
32
- // Same as MultichainAssetsRatesController: resolve CAIP currency from selectedCurrency, default to USD
33
- const currencyCaip = assets_controllers_1.MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()] ??
34
- assets_controllers_1.MAP_CAIP_CURRENCIES.usd;
35
- const expirationOffset = 60;
36
- // Price in assetsPrice is in USD. For bridge: conversionRate = in user's currency, usdConversionRate = in USD.
37
- const isUsd = selectedCurrency.toLowerCase() === 'usd';
38
- const rateUserCurrencyPerUsd = isUsd ? 1 : (usdToSelectedCurrencyRate ?? 1);
39
- for (const [assetId, priceData] of Object.entries(assetsPrice)) {
40
- const price = getPriceNumber(priceData);
41
- if (Number.isNaN(price) || price < 0) {
26
+ const currencyCaip = assets_controllers_1.MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()];
27
+ if (!currencyCaip) {
28
+ return {
29
+ conversionRates: {},
30
+ currencyRates: {},
31
+ marketData: {},
32
+ currentCurrency: selectedCurrency,
33
+ };
34
+ }
35
+ const fungibleAssetsPrice = Object.entries(assetsPrice).reduce((acc, [assetId, priceData]) => {
36
+ if (priceData.assetPriceType === 'fungible') {
37
+ acc[assetId] = priceData;
38
+ }
39
+ return acc;
40
+ }, {});
41
+ for (const [assetId, priceData] of Object.entries(fungibleAssetsPrice)) {
42
+ const { price, usdPrice, lastUpdated } = priceData;
43
+ if (price < 0) {
42
44
  continue;
43
45
  }
44
- const lastUpdated = typeof priceData === 'object' &&
45
- priceData !== null &&
46
- 'lastUpdated' in priceData
47
- ? Number(priceData.lastUpdated)
48
- : Date.now();
49
- const conversionTime = lastUpdated > 1e12 ? lastUpdated / 1000 : lastUpdated;
50
- const expirationTime = conversionTime + expirationOffset;
46
+ const lastUpdatedInSeconds = lastUpdated / 1000;
47
+ const expirationOffsetInSeconds = 60;
48
+ const expirationTime = lastUpdatedInSeconds + expirationOffsetInSeconds;
51
49
  try {
52
50
  const parsed = (0, utils_2.parseCaipAssetType)(assetId);
53
51
  const chainIdParsed = (0, utils_2.parseCaipChainId)(parsed.chainId);
54
- const chainRef = chainIdParsed.reference;
55
- // conversionRates: only non-EVM assets (bridge uses this for non-EVM chains). Rate in selected currency.
56
- if (chainIdParsed.namespace !== 'eip155') {
57
- const priceInUserCurrency = price * rateUserCurrencyPerUsd;
58
- conversionRates[assetId] = {
59
- rate: String(priceInUserCurrency),
60
- currency: currencyCaip,
61
- conversionTime,
62
- expirationTime,
63
- marketData: typeof priceData === 'object' && priceData !== null
64
- ? priceData
65
- : undefined,
66
- };
67
- }
68
- if (chainIdParsed.namespace === 'eip155') {
69
- const chainIdHex = (0, utils_1.numberToHex)(parseInt(chainRef, 10));
70
- const nativeAssetId = nativeAssetIdentifiers[parsed.chainId] ?? null;
71
- const symbol = networkConfigurationsByChainId[chainIdHex]?.nativeCurrency ?? 'ETH';
72
- const nativePrice = nativeAssetId && assetsPrice[nativeAssetId]
73
- ? getPriceNumber(assetsPrice[nativeAssetId])
74
- : Number.NaN;
75
- let tokenAddress = null;
52
+ if (chainIdParsed.namespace === utils_1.KnownCaipNamespace.Eip155) {
53
+ const chainIdHex = (0, utils_1.numberToHex)(parseInt(chainIdParsed.reference, 10));
54
+ const nativeAssetId = nativeAssetIdentifiers[parsed.chainId];
55
+ const nativeCurrencySymbol = networkConfigurationsByChainId[chainIdHex]?.nativeCurrency;
56
+ const nativeAssetUsdPrice = nativeAssetId && fungibleAssetsPrice[nativeAssetId]?.usdPrice;
57
+ if (!nativeAssetId ||
58
+ !nativeCurrencySymbol ||
59
+ nativeAssetUsdPrice === undefined) {
60
+ // If we do not have a native asset for that chain or a price for it, the asset needs to be skipped
61
+ continue;
62
+ }
63
+ let tokenAddress;
76
64
  if (parsed.assetNamespace === 'erc20') {
77
65
  tokenAddress = (0, util_1.toChecksumAddress)(String(parsed.assetReference));
78
66
  }
@@ -80,33 +68,52 @@ function formatExchangeRatesForBridge(params) {
80
68
  tokenAddress = '0x0000000000000000000000000000000000000000';
81
69
  }
82
70
  if (tokenAddress && nativeAssetId) {
83
- const priceInNative = !Number.isNaN(nativePrice) && nativePrice > 0
84
- ? price / nativePrice
85
- : price;
71
+ const priceInNative = nativeAssetUsdPrice > 0 ? usdPrice / nativeAssetUsdPrice : usdPrice;
86
72
  if (!marketData[chainIdHex]) {
87
73
  marketData[chainIdHex] = {};
88
74
  }
89
- const baseMarketData = typeof priceData === 'object' && priceData !== null
90
- ? priceData
91
- : {};
92
75
  marketData[chainIdHex][tokenAddress] = {
93
- ...baseMarketData,
76
+ ...priceData,
94
77
  price: priceInNative,
95
- currency: symbol,
78
+ currency: nativeCurrencySymbol,
96
79
  assetId,
97
80
  chainId: chainIdHex,
98
81
  tokenAddress,
99
82
  };
100
83
  }
101
84
  if (parsed.assetNamespace === 'slip44' && nativeAssetId) {
102
- // conversionRate = native price in user's currency; usdConversionRate = native price in USD (bridge uses ratio for USD conversion)
103
- currencyRates[symbol] = {
104
- conversionDate: conversionTime,
105
- conversionRate: price * rateUserCurrencyPerUsd,
106
- usdConversionRate: price,
85
+ currencyRates[nativeCurrencySymbol] = {
86
+ conversionDate: lastUpdatedInSeconds,
87
+ conversionRate: price,
88
+ usdConversionRate: usdPrice,
107
89
  };
108
90
  }
109
91
  }
92
+ else {
93
+ conversionRates[assetId] = {
94
+ rate: String(price),
95
+ currency: currencyCaip,
96
+ conversionTime: lastUpdatedInSeconds,
97
+ expirationTime,
98
+ marketData: {
99
+ fungible: true,
100
+ allTimeHigh: `${priceData.allTimeHigh}`,
101
+ allTimeLow: `${priceData.allTimeLow}`,
102
+ circulatingSupply: `${priceData.circulatingSupply}`,
103
+ marketCap: `${priceData.marketCap}`,
104
+ totalVolume: `${priceData.totalVolume}`,
105
+ pricePercentChange: {
106
+ PT1H: priceData.pricePercentChange1h,
107
+ P1D: priceData.pricePercentChange1d,
108
+ P7D: priceData.pricePercentChange7d,
109
+ P14D: priceData.pricePercentChange14d,
110
+ P30D: priceData.pricePercentChange30d,
111
+ P200D: priceData.pricePercentChange200d,
112
+ P1Y: priceData.pricePercentChange1y,
113
+ },
114
+ },
115
+ };
116
+ }
110
117
  }
111
118
  catch {
112
119
  // Skip malformed asset IDs
@@ -1 +1 @@
1
- {"version":3,"file":"formatExchangeRatesForBridge.cjs","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { toChecksumAddress } from '@ethereumjs/util';\nimport { MAP_CAIP_CURRENCIES } from '@metamask/assets-controllers';\nimport { numberToHex } from '@metamask/utils';\nimport { parseCaipAssetType, parseCaipChainId } from '@metamask/utils';\n\nimport type { AssetPrice, Caip19AssetId } from '../types';\n\n/**\n * Bridge-compatible conversion rate entry (MultichainAssetsRatesController shape).\n */\nexport type BridgeConversionRateEntry = {\n rate: string;\n currency?: string;\n conversionTime?: number;\n expirationTime?: number;\n marketData?: Record<string, unknown>;\n};\n\n/**\n * Bridge-compatible currency rate entry (CurrencyRateController shape).\n */\nexport type BridgeCurrencyRateEntry = {\n conversionDate: number;\n conversionRate: number;\n usdConversionRate: number;\n};\n\n/**\n * Bridge-compatible market data entry (TokenRatesController marketData shape).\n */\nexport type BridgeMarketDataEntry = {\n price: number;\n currency: string;\n assetId?: string;\n chainId?: string;\n tokenAddress?: string;\n [key: string]: unknown;\n};\n\n/**\n * Exchange rates in the format expected by the bridge controller:\n * conversionRates (MultichainAssetsRatesController) + currencyRates (CurrencyRateController)\n * + marketData (TokenRatesController) + currentCurrency.\n */\nexport type BridgeExchangeRatesFormat = {\n conversionRates: Record<string, BridgeConversionRateEntry>;\n currencyRates: Record<string, BridgeCurrencyRateEntry>;\n marketData: Record<string, Record<string, BridgeMarketDataEntry>>;\n currentCurrency: string;\n};\n\nfunction getPriceNumber(price: AssetPrice): number {\n return typeof price === 'object' && price !== null && 'price' in price\n ? Number((price as { price: number }).price)\n : Number.NaN;\n}\n\n/**\n * Converts AssetsController state (assetsPrice, selectedCurrency) into the\n * same format the bridge expects from MultichainAssetsRatesController,\n * CurrencyRateController, and TokenRatesController so the bridge can use\n * a single action when useAssetsControllerForRates is true.\n *\n * @param params - Conversion parameters.\n * @param params.assetsPrice - Map of CAIP-19 asset ID to price data. Prices are in USD.\n * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').\n * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.\n * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').\n * @param params.usdToSelectedCurrencyRate - Optional rate: 1 USD = this many units of selected currency. Required for correct bridge USD conversion when selectedCurrency is not 'usd'. When omitted and selectedCurrency !== 'usd', currencyRates will use the same value for conversionRate and usdConversionRate (ratio 1), which produces incorrect USD rates.\n * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.\n */\nexport function formatExchangeRatesForBridge(params: {\n assetsPrice: Record<string, AssetPrice>;\n selectedCurrency: string;\n nativeAssetIdentifiers?: Record<string, string>;\n networkConfigurationsByChainId?: Record<string, { nativeCurrency?: string }>;\n usdToSelectedCurrencyRate?: number;\n}): BridgeExchangeRatesFormat {\n const {\n assetsPrice,\n selectedCurrency,\n nativeAssetIdentifiers = {},\n networkConfigurationsByChainId = {},\n usdToSelectedCurrencyRate,\n } = params;\n const conversionRates: Record<string, BridgeConversionRateEntry> = {};\n const currencyRates: Record<string, BridgeCurrencyRateEntry> = {};\n const marketData: Record<string, Record<string, BridgeMarketDataEntry>> = {};\n\n // Same as MultichainAssetsRatesController: resolve CAIP currency from selectedCurrency, default to USD\n const currencyCaip =\n MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()] ??\n MAP_CAIP_CURRENCIES.usd;\n\n const expirationOffset = 60;\n\n // Price in assetsPrice is in USD. For bridge: conversionRate = in user's currency, usdConversionRate = in USD.\n const isUsd = selectedCurrency.toLowerCase() === 'usd';\n const rateUserCurrencyPerUsd = isUsd ? 1 : (usdToSelectedCurrencyRate ?? 1);\n\n for (const [assetId, priceData] of Object.entries(assetsPrice)) {\n const price = getPriceNumber(priceData);\n if (Number.isNaN(price) || price < 0) {\n continue;\n }\n\n const lastUpdated =\n typeof priceData === 'object' &&\n priceData !== null &&\n 'lastUpdated' in priceData\n ? Number((priceData as { lastUpdated: number }).lastUpdated)\n : Date.now();\n const conversionTime =\n lastUpdated > 1e12 ? lastUpdated / 1000 : lastUpdated;\n const expirationTime = conversionTime + expirationOffset;\n\n try {\n const parsed = parseCaipAssetType(assetId as Caip19AssetId);\n const chainIdParsed = parseCaipChainId(parsed.chainId);\n const chainRef = chainIdParsed.reference;\n\n // conversionRates: only non-EVM assets (bridge uses this for non-EVM chains). Rate in selected currency.\n if (chainIdParsed.namespace !== 'eip155') {\n const priceInUserCurrency = price * rateUserCurrencyPerUsd;\n conversionRates[assetId] = {\n rate: String(priceInUserCurrency),\n currency: currencyCaip,\n conversionTime,\n expirationTime,\n marketData:\n typeof priceData === 'object' && priceData !== null\n ? (priceData as Record<string, unknown>)\n : undefined,\n };\n }\n\n if (chainIdParsed.namespace === 'eip155') {\n const chainIdHex = numberToHex(parseInt(chainRef, 10));\n const nativeAssetId = nativeAssetIdentifiers[parsed.chainId] ?? null;\n const symbol =\n networkConfigurationsByChainId[chainIdHex]?.nativeCurrency ?? 'ETH';\n const nativePrice =\n nativeAssetId && assetsPrice[nativeAssetId]\n ? getPriceNumber(assetsPrice[nativeAssetId])\n : Number.NaN;\n\n let tokenAddress: string | null = null;\n if (parsed.assetNamespace === 'erc20') {\n tokenAddress = toChecksumAddress(String(parsed.assetReference));\n } else if (parsed.assetNamespace === 'slip44') {\n tokenAddress = '0x0000000000000000000000000000000000000000';\n }\n\n if (tokenAddress && nativeAssetId) {\n const priceInNative =\n !Number.isNaN(nativePrice) && nativePrice > 0\n ? price / nativePrice\n : price;\n if (!marketData[chainIdHex]) {\n marketData[chainIdHex] = {};\n }\n const baseMarketData =\n typeof priceData === 'object' && priceData !== null\n ? (priceData as Record<string, unknown>)\n : {};\n marketData[chainIdHex][tokenAddress] = {\n ...baseMarketData,\n price: priceInNative,\n currency: symbol,\n assetId,\n chainId: chainIdHex,\n tokenAddress,\n };\n }\n\n if (parsed.assetNamespace === 'slip44' && nativeAssetId) {\n // conversionRate = native price in user's currency; usdConversionRate = native price in USD (bridge uses ratio for USD conversion)\n currencyRates[symbol] = {\n conversionDate: conversionTime,\n conversionRate: price * rateUserCurrencyPerUsd,\n usdConversionRate: price,\n };\n }\n }\n } catch {\n // Skip malformed asset IDs\n }\n }\n\n return {\n conversionRates,\n currencyRates,\n marketData,\n currentCurrency: selectedCurrency,\n };\n}\n"]}
1
+ {"version":3,"file":"formatExchangeRatesForBridge.cjs","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { toChecksumAddress } from '@ethereumjs/util';\nimport {\n CurrencyRateState,\n MAP_CAIP_CURRENCIES,\n MarketDataDetails,\n MultichainAssetsRatesControllerState,\n TokenRatesControllerState,\n} from '@metamask/assets-controllers';\nimport { Hex, KnownCaipNamespace, numberToHex } from '@metamask/utils';\nimport { parseCaipAssetType, parseCaipChainId } from '@metamask/utils';\n\nimport type { AssetPrice, FungibleAssetPrice, Caip19AssetId } from '../types';\n\n/**\n * Exchange rates in the format expected by the bridge controller:\n * conversionRates (MultichainAssetsRatesController) + currencyRates (CurrencyRateController)\n * + marketData (TokenRatesController) + currentCurrency.\n */\nexport type BridgeExchangeRatesFormat = {\n conversionRates: MultichainAssetsRatesControllerState['conversionRates'];\n currencyRates: CurrencyRateState['currencyRates'];\n marketData: TokenRatesControllerState['marketData'];\n currentCurrency: string;\n};\n\n/**\n * Converts AssetsController state (assetsPrice, selectedCurrency) into the\n * same format the bridge expects from MultichainAssetsRatesController,\n * CurrencyRateController, and TokenRatesController so the bridge can use\n * a single action when useAssetsControllerForRates is true.\n *\n * @param params - Conversion parameters.\n * @param params.assetsPrice - Map of CAIP-19 asset ID to price data (must include both `price` and `usdPrice`).\n * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').\n * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.\n * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').\n * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.\n */\nexport function formatExchangeRatesForBridge(params: {\n assetsPrice: Record<string, AssetPrice>;\n selectedCurrency: string;\n nativeAssetIdentifiers?: Record<string, string>;\n networkConfigurationsByChainId?: Record<string, { nativeCurrency?: string }>;\n}): BridgeExchangeRatesFormat {\n const {\n assetsPrice,\n selectedCurrency,\n nativeAssetIdentifiers = {},\n networkConfigurationsByChainId = {},\n } = params;\n const conversionRates: MultichainAssetsRatesControllerState['conversionRates'] =\n {};\n const currencyRates: CurrencyRateState['currencyRates'] = {};\n const marketData: TokenRatesControllerState['marketData'] = {};\n\n const currencyCaip = MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()];\n if (!currencyCaip) {\n return {\n conversionRates: {},\n currencyRates: {},\n marketData: {},\n currentCurrency: selectedCurrency,\n };\n }\n\n const fungibleAssetsPrice = Object.entries(assetsPrice).reduce<\n Record<Caip19AssetId, FungibleAssetPrice>\n >((acc, [assetId, priceData]) => {\n if (priceData.assetPriceType === 'fungible') {\n acc[assetId as Caip19AssetId] = priceData;\n }\n return acc;\n }, {});\n\n for (const [assetId, priceData] of Object.entries(fungibleAssetsPrice)) {\n const { price, usdPrice, lastUpdated } = priceData;\n if (price < 0) {\n continue;\n }\n\n const lastUpdatedInSeconds = lastUpdated / 1000;\n const expirationOffsetInSeconds = 60;\n const expirationTime = lastUpdatedInSeconds + expirationOffsetInSeconds;\n\n try {\n const parsed = parseCaipAssetType(assetId as Caip19AssetId);\n const chainIdParsed = parseCaipChainId(parsed.chainId);\n\n if (chainIdParsed.namespace === KnownCaipNamespace.Eip155) {\n const chainIdHex = numberToHex(parseInt(chainIdParsed.reference, 10));\n\n const nativeAssetId = nativeAssetIdentifiers[parsed.chainId] as\n | Caip19AssetId\n | undefined;\n\n const nativeCurrencySymbol =\n networkConfigurationsByChainId[chainIdHex]?.nativeCurrency;\n\n const nativeAssetUsdPrice =\n nativeAssetId && fungibleAssetsPrice[nativeAssetId]?.usdPrice;\n\n if (\n !nativeAssetId ||\n !nativeCurrencySymbol ||\n nativeAssetUsdPrice === undefined\n ) {\n // If we do not have a native asset for that chain or a price for it, the asset needs to be skipped\n continue;\n }\n\n let tokenAddress: Hex | undefined;\n if (parsed.assetNamespace === 'erc20') {\n tokenAddress = toChecksumAddress(String(parsed.assetReference));\n } else if (parsed.assetNamespace === 'slip44') {\n tokenAddress = '0x0000000000000000000000000000000000000000';\n }\n\n if (tokenAddress && nativeAssetId) {\n const priceInNative =\n nativeAssetUsdPrice > 0 ? usdPrice / nativeAssetUsdPrice : usdPrice;\n if (!marketData[chainIdHex]) {\n marketData[chainIdHex] = {};\n }\n marketData[chainIdHex][tokenAddress] = {\n ...priceData,\n price: priceInNative,\n currency: nativeCurrencySymbol,\n assetId,\n chainId: chainIdHex,\n tokenAddress,\n } as MarketDataDetails;\n }\n\n if (parsed.assetNamespace === 'slip44' && nativeAssetId) {\n currencyRates[nativeCurrencySymbol] = {\n conversionDate: lastUpdatedInSeconds,\n conversionRate: price,\n usdConversionRate: usdPrice,\n };\n }\n } else {\n conversionRates[assetId as Caip19AssetId] = {\n rate: String(price),\n currency: currencyCaip,\n conversionTime: lastUpdatedInSeconds,\n expirationTime,\n marketData: {\n fungible: true,\n allTimeHigh: `${priceData.allTimeHigh}`,\n allTimeLow: `${priceData.allTimeLow}`,\n circulatingSupply: `${priceData.circulatingSupply}`,\n marketCap: `${priceData.marketCap}`,\n totalVolume: `${priceData.totalVolume}`,\n pricePercentChange: {\n PT1H: priceData.pricePercentChange1h as number,\n P1D: priceData.pricePercentChange1d as number,\n P7D: priceData.pricePercentChange7d as number,\n P14D: priceData.pricePercentChange14d as number,\n P30D: priceData.pricePercentChange30d as number,\n P200D: priceData.pricePercentChange200d as number,\n P1Y: priceData.pricePercentChange1y as number,\n },\n },\n } as MultichainAssetsRatesControllerState['conversionRates'][Caip19AssetId];\n }\n } catch {\n // Skip malformed asset IDs\n }\n }\n\n return {\n conversionRates,\n currencyRates,\n marketData,\n currentCurrency: selectedCurrency,\n };\n}\n"]}
@@ -1,42 +1,14 @@
1
+ import { CurrencyRateState, MultichainAssetsRatesControllerState, TokenRatesControllerState } from "@metamask/assets-controllers";
1
2
  import type { AssetPrice } from "../types.cjs";
2
- /**
3
- * Bridge-compatible conversion rate entry (MultichainAssetsRatesController shape).
4
- */
5
- export type BridgeConversionRateEntry = {
6
- rate: string;
7
- currency?: string;
8
- conversionTime?: number;
9
- expirationTime?: number;
10
- marketData?: Record<string, unknown>;
11
- };
12
- /**
13
- * Bridge-compatible currency rate entry (CurrencyRateController shape).
14
- */
15
- export type BridgeCurrencyRateEntry = {
16
- conversionDate: number;
17
- conversionRate: number;
18
- usdConversionRate: number;
19
- };
20
- /**
21
- * Bridge-compatible market data entry (TokenRatesController marketData shape).
22
- */
23
- export type BridgeMarketDataEntry = {
24
- price: number;
25
- currency: string;
26
- assetId?: string;
27
- chainId?: string;
28
- tokenAddress?: string;
29
- [key: string]: unknown;
30
- };
31
3
  /**
32
4
  * Exchange rates in the format expected by the bridge controller:
33
5
  * conversionRates (MultichainAssetsRatesController) + currencyRates (CurrencyRateController)
34
6
  * + marketData (TokenRatesController) + currentCurrency.
35
7
  */
36
8
  export type BridgeExchangeRatesFormat = {
37
- conversionRates: Record<string, BridgeConversionRateEntry>;
38
- currencyRates: Record<string, BridgeCurrencyRateEntry>;
39
- marketData: Record<string, Record<string, BridgeMarketDataEntry>>;
9
+ conversionRates: MultichainAssetsRatesControllerState['conversionRates'];
10
+ currencyRates: CurrencyRateState['currencyRates'];
11
+ marketData: TokenRatesControllerState['marketData'];
40
12
  currentCurrency: string;
41
13
  };
42
14
  /**
@@ -46,11 +18,10 @@ export type BridgeExchangeRatesFormat = {
46
18
  * a single action when useAssetsControllerForRates is true.
47
19
  *
48
20
  * @param params - Conversion parameters.
49
- * @param params.assetsPrice - Map of CAIP-19 asset ID to price data. Prices are in USD.
21
+ * @param params.assetsPrice - Map of CAIP-19 asset ID to price data (must include both `price` and `usdPrice`).
50
22
  * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').
51
23
  * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.
52
24
  * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').
53
- * @param params.usdToSelectedCurrencyRate - Optional rate: 1 USD = this many units of selected currency. Required for correct bridge USD conversion when selectedCurrency is not 'usd'. When omitted and selectedCurrency !== 'usd', currencyRates will use the same value for conversionRate and usdConversionRate (ratio 1), which produces incorrect USD rates.
54
25
  * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.
55
26
  */
56
27
  export declare function formatExchangeRatesForBridge(params: {
@@ -60,6 +31,5 @@ export declare function formatExchangeRatesForBridge(params: {
60
31
  networkConfigurationsByChainId?: Record<string, {
61
32
  nativeCurrency?: string;
62
33
  }>;
63
- usdToSelectedCurrencyRate?: number;
64
34
  }): BridgeExchangeRatesFormat;
65
35
  //# sourceMappingURL=formatExchangeRatesForBridge.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatExchangeRatesForBridge.d.cts","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAiB,qBAAiB;AAE1D;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;IAC3D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAClE,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAQF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,8BAA8B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7E,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC,GAAG,yBAAyB,CAsH5B"}
1
+ {"version":3,"file":"formatExchangeRatesForBridge.d.cts","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EAGjB,oCAAoC,EACpC,yBAAyB,EAC1B,qCAAqC;AAItC,OAAO,KAAK,EAAE,UAAU,EAAqC,qBAAiB;AAE9E;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,eAAe,EAAE,oCAAoC,CAAC,iBAAiB,CAAC,CAAC;IACzE,aAAa,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAClD,UAAU,EAAE,yBAAyB,CAAC,YAAY,CAAC,CAAC;IACpD,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,8BAA8B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E,GAAG,yBAAyB,CAqI5B"}
@@ -1,42 +1,14 @@
1
+ import { CurrencyRateState, MultichainAssetsRatesControllerState, TokenRatesControllerState } from "@metamask/assets-controllers";
1
2
  import type { AssetPrice } from "../types.mjs";
2
- /**
3
- * Bridge-compatible conversion rate entry (MultichainAssetsRatesController shape).
4
- */
5
- export type BridgeConversionRateEntry = {
6
- rate: string;
7
- currency?: string;
8
- conversionTime?: number;
9
- expirationTime?: number;
10
- marketData?: Record<string, unknown>;
11
- };
12
- /**
13
- * Bridge-compatible currency rate entry (CurrencyRateController shape).
14
- */
15
- export type BridgeCurrencyRateEntry = {
16
- conversionDate: number;
17
- conversionRate: number;
18
- usdConversionRate: number;
19
- };
20
- /**
21
- * Bridge-compatible market data entry (TokenRatesController marketData shape).
22
- */
23
- export type BridgeMarketDataEntry = {
24
- price: number;
25
- currency: string;
26
- assetId?: string;
27
- chainId?: string;
28
- tokenAddress?: string;
29
- [key: string]: unknown;
30
- };
31
3
  /**
32
4
  * Exchange rates in the format expected by the bridge controller:
33
5
  * conversionRates (MultichainAssetsRatesController) + currencyRates (CurrencyRateController)
34
6
  * + marketData (TokenRatesController) + currentCurrency.
35
7
  */
36
8
  export type BridgeExchangeRatesFormat = {
37
- conversionRates: Record<string, BridgeConversionRateEntry>;
38
- currencyRates: Record<string, BridgeCurrencyRateEntry>;
39
- marketData: Record<string, Record<string, BridgeMarketDataEntry>>;
9
+ conversionRates: MultichainAssetsRatesControllerState['conversionRates'];
10
+ currencyRates: CurrencyRateState['currencyRates'];
11
+ marketData: TokenRatesControllerState['marketData'];
40
12
  currentCurrency: string;
41
13
  };
42
14
  /**
@@ -46,11 +18,10 @@ export type BridgeExchangeRatesFormat = {
46
18
  * a single action when useAssetsControllerForRates is true.
47
19
  *
48
20
  * @param params - Conversion parameters.
49
- * @param params.assetsPrice - Map of CAIP-19 asset ID to price data. Prices are in USD.
21
+ * @param params.assetsPrice - Map of CAIP-19 asset ID to price data (must include both `price` and `usdPrice`).
50
22
  * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').
51
23
  * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.
52
24
  * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').
53
- * @param params.usdToSelectedCurrencyRate - Optional rate: 1 USD = this many units of selected currency. Required for correct bridge USD conversion when selectedCurrency is not 'usd'. When omitted and selectedCurrency !== 'usd', currencyRates will use the same value for conversionRate and usdConversionRate (ratio 1), which produces incorrect USD rates.
54
25
  * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.
55
26
  */
56
27
  export declare function formatExchangeRatesForBridge(params: {
@@ -60,6 +31,5 @@ export declare function formatExchangeRatesForBridge(params: {
60
31
  networkConfigurationsByChainId?: Record<string, {
61
32
  nativeCurrency?: string;
62
33
  }>;
63
- usdToSelectedCurrencyRate?: number;
64
34
  }): BridgeExchangeRatesFormat;
65
35
  //# sourceMappingURL=formatExchangeRatesForBridge.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatExchangeRatesForBridge.d.mts","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAiB,qBAAiB;AAE1D;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;IAC3D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAClE,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAQF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,8BAA8B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7E,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC,GAAG,yBAAyB,CAsH5B"}
1
+ {"version":3,"file":"formatExchangeRatesForBridge.d.mts","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EAGjB,oCAAoC,EACpC,yBAAyB,EAC1B,qCAAqC;AAItC,OAAO,KAAK,EAAE,UAAU,EAAqC,qBAAiB;AAE9E;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,eAAe,EAAE,oCAAoC,CAAC,iBAAiB,CAAC,CAAC;IACzE,aAAa,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAClD,UAAU,EAAE,yBAAyB,CAAC,YAAY,CAAC,CAAC;IACpD,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,8BAA8B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E,GAAG,yBAAyB,CAqI5B"}
@@ -1,12 +1,7 @@
1
1
  import { toChecksumAddress } from "@ethereumjs/util";
2
2
  import { MAP_CAIP_CURRENCIES } from "@metamask/assets-controllers";
3
- import { numberToHex } from "@metamask/utils";
3
+ import { KnownCaipNamespace, numberToHex } from "@metamask/utils";
4
4
  import { parseCaipAssetType, parseCaipChainId } from "@metamask/utils";
5
- function getPriceNumber(price) {
6
- return typeof price === 'object' && price !== null && 'price' in price
7
- ? Number(price.price)
8
- : Number.NaN;
9
- }
10
5
  /**
11
6
  * Converts AssetsController state (assetsPrice, selectedCurrency) into the
12
7
  * same format the bridge expects from MultichainAssetsRatesController,
@@ -14,62 +9,55 @@ function getPriceNumber(price) {
14
9
  * a single action when useAssetsControllerForRates is true.
15
10
  *
16
11
  * @param params - Conversion parameters.
17
- * @param params.assetsPrice - Map of CAIP-19 asset ID to price data. Prices are in USD.
12
+ * @param params.assetsPrice - Map of CAIP-19 asset ID to price data (must include both `price` and `usdPrice`).
18
13
  * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').
19
14
  * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.
20
15
  * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').
21
- * @param params.usdToSelectedCurrencyRate - Optional rate: 1 USD = this many units of selected currency. Required for correct bridge USD conversion when selectedCurrency is not 'usd'. When omitted and selectedCurrency !== 'usd', currencyRates will use the same value for conversionRate and usdConversionRate (ratio 1), which produces incorrect USD rates.
22
16
  * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.
23
17
  */
24
18
  export function formatExchangeRatesForBridge(params) {
25
- const { assetsPrice, selectedCurrency, nativeAssetIdentifiers = {}, networkConfigurationsByChainId = {}, usdToSelectedCurrencyRate, } = params;
19
+ const { assetsPrice, selectedCurrency, nativeAssetIdentifiers = {}, networkConfigurationsByChainId = {}, } = params;
26
20
  const conversionRates = {};
27
21
  const currencyRates = {};
28
22
  const marketData = {};
29
- // Same as MultichainAssetsRatesController: resolve CAIP currency from selectedCurrency, default to USD
30
- const currencyCaip = MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()] ??
31
- MAP_CAIP_CURRENCIES.usd;
32
- const expirationOffset = 60;
33
- // Price in assetsPrice is in USD. For bridge: conversionRate = in user's currency, usdConversionRate = in USD.
34
- const isUsd = selectedCurrency.toLowerCase() === 'usd';
35
- const rateUserCurrencyPerUsd = isUsd ? 1 : (usdToSelectedCurrencyRate ?? 1);
36
- for (const [assetId, priceData] of Object.entries(assetsPrice)) {
37
- const price = getPriceNumber(priceData);
38
- if (Number.isNaN(price) || price < 0) {
23
+ const currencyCaip = MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()];
24
+ if (!currencyCaip) {
25
+ return {
26
+ conversionRates: {},
27
+ currencyRates: {},
28
+ marketData: {},
29
+ currentCurrency: selectedCurrency,
30
+ };
31
+ }
32
+ const fungibleAssetsPrice = Object.entries(assetsPrice).reduce((acc, [assetId, priceData]) => {
33
+ if (priceData.assetPriceType === 'fungible') {
34
+ acc[assetId] = priceData;
35
+ }
36
+ return acc;
37
+ }, {});
38
+ for (const [assetId, priceData] of Object.entries(fungibleAssetsPrice)) {
39
+ const { price, usdPrice, lastUpdated } = priceData;
40
+ if (price < 0) {
39
41
  continue;
40
42
  }
41
- const lastUpdated = typeof priceData === 'object' &&
42
- priceData !== null &&
43
- 'lastUpdated' in priceData
44
- ? Number(priceData.lastUpdated)
45
- : Date.now();
46
- const conversionTime = lastUpdated > 1e12 ? lastUpdated / 1000 : lastUpdated;
47
- const expirationTime = conversionTime + expirationOffset;
43
+ const lastUpdatedInSeconds = lastUpdated / 1000;
44
+ const expirationOffsetInSeconds = 60;
45
+ const expirationTime = lastUpdatedInSeconds + expirationOffsetInSeconds;
48
46
  try {
49
47
  const parsed = parseCaipAssetType(assetId);
50
48
  const chainIdParsed = parseCaipChainId(parsed.chainId);
51
- const chainRef = chainIdParsed.reference;
52
- // conversionRates: only non-EVM assets (bridge uses this for non-EVM chains). Rate in selected currency.
53
- if (chainIdParsed.namespace !== 'eip155') {
54
- const priceInUserCurrency = price * rateUserCurrencyPerUsd;
55
- conversionRates[assetId] = {
56
- rate: String(priceInUserCurrency),
57
- currency: currencyCaip,
58
- conversionTime,
59
- expirationTime,
60
- marketData: typeof priceData === 'object' && priceData !== null
61
- ? priceData
62
- : undefined,
63
- };
64
- }
65
- if (chainIdParsed.namespace === 'eip155') {
66
- const chainIdHex = numberToHex(parseInt(chainRef, 10));
67
- const nativeAssetId = nativeAssetIdentifiers[parsed.chainId] ?? null;
68
- const symbol = networkConfigurationsByChainId[chainIdHex]?.nativeCurrency ?? 'ETH';
69
- const nativePrice = nativeAssetId && assetsPrice[nativeAssetId]
70
- ? getPriceNumber(assetsPrice[nativeAssetId])
71
- : Number.NaN;
72
- let tokenAddress = null;
49
+ if (chainIdParsed.namespace === KnownCaipNamespace.Eip155) {
50
+ const chainIdHex = numberToHex(parseInt(chainIdParsed.reference, 10));
51
+ const nativeAssetId = nativeAssetIdentifiers[parsed.chainId];
52
+ const nativeCurrencySymbol = networkConfigurationsByChainId[chainIdHex]?.nativeCurrency;
53
+ const nativeAssetUsdPrice = nativeAssetId && fungibleAssetsPrice[nativeAssetId]?.usdPrice;
54
+ if (!nativeAssetId ||
55
+ !nativeCurrencySymbol ||
56
+ nativeAssetUsdPrice === undefined) {
57
+ // If we do not have a native asset for that chain or a price for it, the asset needs to be skipped
58
+ continue;
59
+ }
60
+ let tokenAddress;
73
61
  if (parsed.assetNamespace === 'erc20') {
74
62
  tokenAddress = toChecksumAddress(String(parsed.assetReference));
75
63
  }
@@ -77,33 +65,52 @@ export function formatExchangeRatesForBridge(params) {
77
65
  tokenAddress = '0x0000000000000000000000000000000000000000';
78
66
  }
79
67
  if (tokenAddress && nativeAssetId) {
80
- const priceInNative = !Number.isNaN(nativePrice) && nativePrice > 0
81
- ? price / nativePrice
82
- : price;
68
+ const priceInNative = nativeAssetUsdPrice > 0 ? usdPrice / nativeAssetUsdPrice : usdPrice;
83
69
  if (!marketData[chainIdHex]) {
84
70
  marketData[chainIdHex] = {};
85
71
  }
86
- const baseMarketData = typeof priceData === 'object' && priceData !== null
87
- ? priceData
88
- : {};
89
72
  marketData[chainIdHex][tokenAddress] = {
90
- ...baseMarketData,
73
+ ...priceData,
91
74
  price: priceInNative,
92
- currency: symbol,
75
+ currency: nativeCurrencySymbol,
93
76
  assetId,
94
77
  chainId: chainIdHex,
95
78
  tokenAddress,
96
79
  };
97
80
  }
98
81
  if (parsed.assetNamespace === 'slip44' && nativeAssetId) {
99
- // conversionRate = native price in user's currency; usdConversionRate = native price in USD (bridge uses ratio for USD conversion)
100
- currencyRates[symbol] = {
101
- conversionDate: conversionTime,
102
- conversionRate: price * rateUserCurrencyPerUsd,
103
- usdConversionRate: price,
82
+ currencyRates[nativeCurrencySymbol] = {
83
+ conversionDate: lastUpdatedInSeconds,
84
+ conversionRate: price,
85
+ usdConversionRate: usdPrice,
104
86
  };
105
87
  }
106
88
  }
89
+ else {
90
+ conversionRates[assetId] = {
91
+ rate: String(price),
92
+ currency: currencyCaip,
93
+ conversionTime: lastUpdatedInSeconds,
94
+ expirationTime,
95
+ marketData: {
96
+ fungible: true,
97
+ allTimeHigh: `${priceData.allTimeHigh}`,
98
+ allTimeLow: `${priceData.allTimeLow}`,
99
+ circulatingSupply: `${priceData.circulatingSupply}`,
100
+ marketCap: `${priceData.marketCap}`,
101
+ totalVolume: `${priceData.totalVolume}`,
102
+ pricePercentChange: {
103
+ PT1H: priceData.pricePercentChange1h,
104
+ P1D: priceData.pricePercentChange1d,
105
+ P7D: priceData.pricePercentChange7d,
106
+ P14D: priceData.pricePercentChange14d,
107
+ P30D: priceData.pricePercentChange30d,
108
+ P200D: priceData.pricePercentChange200d,
109
+ P1Y: priceData.pricePercentChange1y,
110
+ },
111
+ },
112
+ };
113
+ }
107
114
  }
108
115
  catch {
109
116
  // Skip malformed asset IDs
@@ -1 +1 @@
1
- {"version":3,"file":"formatExchangeRatesForBridge.mjs","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { toChecksumAddress } from '@ethereumjs/util';\nimport { MAP_CAIP_CURRENCIES } from '@metamask/assets-controllers';\nimport { numberToHex } from '@metamask/utils';\nimport { parseCaipAssetType, parseCaipChainId } from '@metamask/utils';\n\nimport type { AssetPrice, Caip19AssetId } from '../types';\n\n/**\n * Bridge-compatible conversion rate entry (MultichainAssetsRatesController shape).\n */\nexport type BridgeConversionRateEntry = {\n rate: string;\n currency?: string;\n conversionTime?: number;\n expirationTime?: number;\n marketData?: Record<string, unknown>;\n};\n\n/**\n * Bridge-compatible currency rate entry (CurrencyRateController shape).\n */\nexport type BridgeCurrencyRateEntry = {\n conversionDate: number;\n conversionRate: number;\n usdConversionRate: number;\n};\n\n/**\n * Bridge-compatible market data entry (TokenRatesController marketData shape).\n */\nexport type BridgeMarketDataEntry = {\n price: number;\n currency: string;\n assetId?: string;\n chainId?: string;\n tokenAddress?: string;\n [key: string]: unknown;\n};\n\n/**\n * Exchange rates in the format expected by the bridge controller:\n * conversionRates (MultichainAssetsRatesController) + currencyRates (CurrencyRateController)\n * + marketData (TokenRatesController) + currentCurrency.\n */\nexport type BridgeExchangeRatesFormat = {\n conversionRates: Record<string, BridgeConversionRateEntry>;\n currencyRates: Record<string, BridgeCurrencyRateEntry>;\n marketData: Record<string, Record<string, BridgeMarketDataEntry>>;\n currentCurrency: string;\n};\n\nfunction getPriceNumber(price: AssetPrice): number {\n return typeof price === 'object' && price !== null && 'price' in price\n ? Number((price as { price: number }).price)\n : Number.NaN;\n}\n\n/**\n * Converts AssetsController state (assetsPrice, selectedCurrency) into the\n * same format the bridge expects from MultichainAssetsRatesController,\n * CurrencyRateController, and TokenRatesController so the bridge can use\n * a single action when useAssetsControllerForRates is true.\n *\n * @param params - Conversion parameters.\n * @param params.assetsPrice - Map of CAIP-19 asset ID to price data. Prices are in USD.\n * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').\n * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.\n * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').\n * @param params.usdToSelectedCurrencyRate - Optional rate: 1 USD = this many units of selected currency. Required for correct bridge USD conversion when selectedCurrency is not 'usd'. When omitted and selectedCurrency !== 'usd', currencyRates will use the same value for conversionRate and usdConversionRate (ratio 1), which produces incorrect USD rates.\n * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.\n */\nexport function formatExchangeRatesForBridge(params: {\n assetsPrice: Record<string, AssetPrice>;\n selectedCurrency: string;\n nativeAssetIdentifiers?: Record<string, string>;\n networkConfigurationsByChainId?: Record<string, { nativeCurrency?: string }>;\n usdToSelectedCurrencyRate?: number;\n}): BridgeExchangeRatesFormat {\n const {\n assetsPrice,\n selectedCurrency,\n nativeAssetIdentifiers = {},\n networkConfigurationsByChainId = {},\n usdToSelectedCurrencyRate,\n } = params;\n const conversionRates: Record<string, BridgeConversionRateEntry> = {};\n const currencyRates: Record<string, BridgeCurrencyRateEntry> = {};\n const marketData: Record<string, Record<string, BridgeMarketDataEntry>> = {};\n\n // Same as MultichainAssetsRatesController: resolve CAIP currency from selectedCurrency, default to USD\n const currencyCaip =\n MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()] ??\n MAP_CAIP_CURRENCIES.usd;\n\n const expirationOffset = 60;\n\n // Price in assetsPrice is in USD. For bridge: conversionRate = in user's currency, usdConversionRate = in USD.\n const isUsd = selectedCurrency.toLowerCase() === 'usd';\n const rateUserCurrencyPerUsd = isUsd ? 1 : (usdToSelectedCurrencyRate ?? 1);\n\n for (const [assetId, priceData] of Object.entries(assetsPrice)) {\n const price = getPriceNumber(priceData);\n if (Number.isNaN(price) || price < 0) {\n continue;\n }\n\n const lastUpdated =\n typeof priceData === 'object' &&\n priceData !== null &&\n 'lastUpdated' in priceData\n ? Number((priceData as { lastUpdated: number }).lastUpdated)\n : Date.now();\n const conversionTime =\n lastUpdated > 1e12 ? lastUpdated / 1000 : lastUpdated;\n const expirationTime = conversionTime + expirationOffset;\n\n try {\n const parsed = parseCaipAssetType(assetId as Caip19AssetId);\n const chainIdParsed = parseCaipChainId(parsed.chainId);\n const chainRef = chainIdParsed.reference;\n\n // conversionRates: only non-EVM assets (bridge uses this for non-EVM chains). Rate in selected currency.\n if (chainIdParsed.namespace !== 'eip155') {\n const priceInUserCurrency = price * rateUserCurrencyPerUsd;\n conversionRates[assetId] = {\n rate: String(priceInUserCurrency),\n currency: currencyCaip,\n conversionTime,\n expirationTime,\n marketData:\n typeof priceData === 'object' && priceData !== null\n ? (priceData as Record<string, unknown>)\n : undefined,\n };\n }\n\n if (chainIdParsed.namespace === 'eip155') {\n const chainIdHex = numberToHex(parseInt(chainRef, 10));\n const nativeAssetId = nativeAssetIdentifiers[parsed.chainId] ?? null;\n const symbol =\n networkConfigurationsByChainId[chainIdHex]?.nativeCurrency ?? 'ETH';\n const nativePrice =\n nativeAssetId && assetsPrice[nativeAssetId]\n ? getPriceNumber(assetsPrice[nativeAssetId])\n : Number.NaN;\n\n let tokenAddress: string | null = null;\n if (parsed.assetNamespace === 'erc20') {\n tokenAddress = toChecksumAddress(String(parsed.assetReference));\n } else if (parsed.assetNamespace === 'slip44') {\n tokenAddress = '0x0000000000000000000000000000000000000000';\n }\n\n if (tokenAddress && nativeAssetId) {\n const priceInNative =\n !Number.isNaN(nativePrice) && nativePrice > 0\n ? price / nativePrice\n : price;\n if (!marketData[chainIdHex]) {\n marketData[chainIdHex] = {};\n }\n const baseMarketData =\n typeof priceData === 'object' && priceData !== null\n ? (priceData as Record<string, unknown>)\n : {};\n marketData[chainIdHex][tokenAddress] = {\n ...baseMarketData,\n price: priceInNative,\n currency: symbol,\n assetId,\n chainId: chainIdHex,\n tokenAddress,\n };\n }\n\n if (parsed.assetNamespace === 'slip44' && nativeAssetId) {\n // conversionRate = native price in user's currency; usdConversionRate = native price in USD (bridge uses ratio for USD conversion)\n currencyRates[symbol] = {\n conversionDate: conversionTime,\n conversionRate: price * rateUserCurrencyPerUsd,\n usdConversionRate: price,\n };\n }\n }\n } catch {\n // Skip malformed asset IDs\n }\n }\n\n return {\n conversionRates,\n currencyRates,\n marketData,\n currentCurrency: selectedCurrency,\n };\n}\n"]}
1
+ {"version":3,"file":"formatExchangeRatesForBridge.mjs","sourceRoot":"","sources":["../../src/utils/formatExchangeRatesForBridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { toChecksumAddress } from '@ethereumjs/util';\nimport {\n CurrencyRateState,\n MAP_CAIP_CURRENCIES,\n MarketDataDetails,\n MultichainAssetsRatesControllerState,\n TokenRatesControllerState,\n} from '@metamask/assets-controllers';\nimport { Hex, KnownCaipNamespace, numberToHex } from '@metamask/utils';\nimport { parseCaipAssetType, parseCaipChainId } from '@metamask/utils';\n\nimport type { AssetPrice, FungibleAssetPrice, Caip19AssetId } from '../types';\n\n/**\n * Exchange rates in the format expected by the bridge controller:\n * conversionRates (MultichainAssetsRatesController) + currencyRates (CurrencyRateController)\n * + marketData (TokenRatesController) + currentCurrency.\n */\nexport type BridgeExchangeRatesFormat = {\n conversionRates: MultichainAssetsRatesControllerState['conversionRates'];\n currencyRates: CurrencyRateState['currencyRates'];\n marketData: TokenRatesControllerState['marketData'];\n currentCurrency: string;\n};\n\n/**\n * Converts AssetsController state (assetsPrice, selectedCurrency) into the\n * same format the bridge expects from MultichainAssetsRatesController,\n * CurrencyRateController, and TokenRatesController so the bridge can use\n * a single action when useAssetsControllerForRates is true.\n *\n * @param params - Conversion parameters.\n * @param params.assetsPrice - Map of CAIP-19 asset ID to price data (must include both `price` and `usdPrice`).\n * @param params.selectedCurrency - ISO 4217 currency code (e.g. 'usd').\n * @param params.nativeAssetIdentifiers - Optional map of CAIP-2 chain ID to native asset ID (e.g. from NetworkEnablementController state). When provided, used for EVM native lookups.\n * @param params.networkConfigurationsByChainId - Optional map of Hex chain ID to network config (e.g. from NetworkController state). Used to resolve native currency symbol via `nativeCurrency`; keys are Hex (e.g. '0x1').\n * @returns Bridge-compatible conversionRates, currencyRates, marketData, currentCurrency.\n */\nexport function formatExchangeRatesForBridge(params: {\n assetsPrice: Record<string, AssetPrice>;\n selectedCurrency: string;\n nativeAssetIdentifiers?: Record<string, string>;\n networkConfigurationsByChainId?: Record<string, { nativeCurrency?: string }>;\n}): BridgeExchangeRatesFormat {\n const {\n assetsPrice,\n selectedCurrency,\n nativeAssetIdentifiers = {},\n networkConfigurationsByChainId = {},\n } = params;\n const conversionRates: MultichainAssetsRatesControllerState['conversionRates'] =\n {};\n const currencyRates: CurrencyRateState['currencyRates'] = {};\n const marketData: TokenRatesControllerState['marketData'] = {};\n\n const currencyCaip = MAP_CAIP_CURRENCIES[selectedCurrency.toLowerCase()];\n if (!currencyCaip) {\n return {\n conversionRates: {},\n currencyRates: {},\n marketData: {},\n currentCurrency: selectedCurrency,\n };\n }\n\n const fungibleAssetsPrice = Object.entries(assetsPrice).reduce<\n Record<Caip19AssetId, FungibleAssetPrice>\n >((acc, [assetId, priceData]) => {\n if (priceData.assetPriceType === 'fungible') {\n acc[assetId as Caip19AssetId] = priceData;\n }\n return acc;\n }, {});\n\n for (const [assetId, priceData] of Object.entries(fungibleAssetsPrice)) {\n const { price, usdPrice, lastUpdated } = priceData;\n if (price < 0) {\n continue;\n }\n\n const lastUpdatedInSeconds = lastUpdated / 1000;\n const expirationOffsetInSeconds = 60;\n const expirationTime = lastUpdatedInSeconds + expirationOffsetInSeconds;\n\n try {\n const parsed = parseCaipAssetType(assetId as Caip19AssetId);\n const chainIdParsed = parseCaipChainId(parsed.chainId);\n\n if (chainIdParsed.namespace === KnownCaipNamespace.Eip155) {\n const chainIdHex = numberToHex(parseInt(chainIdParsed.reference, 10));\n\n const nativeAssetId = nativeAssetIdentifiers[parsed.chainId] as\n | Caip19AssetId\n | undefined;\n\n const nativeCurrencySymbol =\n networkConfigurationsByChainId[chainIdHex]?.nativeCurrency;\n\n const nativeAssetUsdPrice =\n nativeAssetId && fungibleAssetsPrice[nativeAssetId]?.usdPrice;\n\n if (\n !nativeAssetId ||\n !nativeCurrencySymbol ||\n nativeAssetUsdPrice === undefined\n ) {\n // If we do not have a native asset for that chain or a price for it, the asset needs to be skipped\n continue;\n }\n\n let tokenAddress: Hex | undefined;\n if (parsed.assetNamespace === 'erc20') {\n tokenAddress = toChecksumAddress(String(parsed.assetReference));\n } else if (parsed.assetNamespace === 'slip44') {\n tokenAddress = '0x0000000000000000000000000000000000000000';\n }\n\n if (tokenAddress && nativeAssetId) {\n const priceInNative =\n nativeAssetUsdPrice > 0 ? usdPrice / nativeAssetUsdPrice : usdPrice;\n if (!marketData[chainIdHex]) {\n marketData[chainIdHex] = {};\n }\n marketData[chainIdHex][tokenAddress] = {\n ...priceData,\n price: priceInNative,\n currency: nativeCurrencySymbol,\n assetId,\n chainId: chainIdHex,\n tokenAddress,\n } as MarketDataDetails;\n }\n\n if (parsed.assetNamespace === 'slip44' && nativeAssetId) {\n currencyRates[nativeCurrencySymbol] = {\n conversionDate: lastUpdatedInSeconds,\n conversionRate: price,\n usdConversionRate: usdPrice,\n };\n }\n } else {\n conversionRates[assetId as Caip19AssetId] = {\n rate: String(price),\n currency: currencyCaip,\n conversionTime: lastUpdatedInSeconds,\n expirationTime,\n marketData: {\n fungible: true,\n allTimeHigh: `${priceData.allTimeHigh}`,\n allTimeLow: `${priceData.allTimeLow}`,\n circulatingSupply: `${priceData.circulatingSupply}`,\n marketCap: `${priceData.marketCap}`,\n totalVolume: `${priceData.totalVolume}`,\n pricePercentChange: {\n PT1H: priceData.pricePercentChange1h as number,\n P1D: priceData.pricePercentChange1d as number,\n P7D: priceData.pricePercentChange7d as number,\n P14D: priceData.pricePercentChange14d as number,\n P30D: priceData.pricePercentChange30d as number,\n P200D: priceData.pricePercentChange200d as number,\n P1Y: priceData.pricePercentChange1y as number,\n },\n },\n } as MultichainAssetsRatesControllerState['conversionRates'][Caip19AssetId];\n }\n } catch {\n // Skip malformed asset IDs\n }\n }\n\n return {\n conversionRates,\n currencyRates,\n marketData,\n currentCurrency: selectedCurrency,\n };\n}\n"]}