@metamask/transaction-pay-controller 22.5.0 → 22.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/dist/constants.cjs +10 -1
  3. package/dist/constants.cjs.map +1 -1
  4. package/dist/constants.d.cts +6 -0
  5. package/dist/constants.d.cts.map +1 -1
  6. package/dist/constants.d.mts +6 -0
  7. package/dist/constants.d.mts.map +1 -1
  8. package/dist/constants.mjs +9 -0
  9. package/dist/constants.mjs.map +1 -1
  10. package/dist/strategy/across/across-quotes.cjs +126 -18
  11. package/dist/strategy/across/across-quotes.cjs.map +1 -1
  12. package/dist/strategy/across/across-quotes.d.cts.map +1 -1
  13. package/dist/strategy/across/across-quotes.d.mts.map +1 -1
  14. package/dist/strategy/across/across-quotes.mjs +126 -18
  15. package/dist/strategy/across/across-quotes.mjs.map +1 -1
  16. package/dist/strategy/across/across-submit.cjs +2 -0
  17. package/dist/strategy/across/across-submit.cjs.map +1 -1
  18. package/dist/strategy/across/across-submit.mjs +2 -0
  19. package/dist/strategy/across/across-submit.mjs.map +1 -1
  20. package/dist/strategy/bridge/bridge-quotes.cjs +3 -3
  21. package/dist/strategy/bridge/bridge-quotes.cjs.map +1 -1
  22. package/dist/strategy/bridge/bridge-quotes.d.cts.map +1 -1
  23. package/dist/strategy/bridge/bridge-quotes.d.mts.map +1 -1
  24. package/dist/strategy/bridge/bridge-quotes.mjs +3 -3
  25. package/dist/strategy/bridge/bridge-quotes.mjs.map +1 -1
  26. package/dist/strategy/relay/constants.cjs +5 -1
  27. package/dist/strategy/relay/constants.cjs.map +1 -1
  28. package/dist/strategy/relay/constants.d.cts.map +1 -1
  29. package/dist/strategy/relay/constants.d.mts.map +1 -1
  30. package/dist/strategy/relay/constants.mjs +5 -1
  31. package/dist/strategy/relay/constants.mjs.map +1 -1
  32. package/dist/strategy/relay/relay-quotes.cjs +2 -2
  33. package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
  34. package/dist/strategy/relay/relay-quotes.mjs +3 -3
  35. package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
  36. package/dist/strategy/relay/relay-submit.cjs +2 -0
  37. package/dist/strategy/relay/relay-submit.cjs.map +1 -1
  38. package/dist/strategy/relay/relay-submit.mjs +2 -0
  39. package/dist/strategy/relay/relay-submit.mjs.map +1 -1
  40. package/dist/tests/messenger-mock.d.cts +23 -21
  41. package/dist/tests/messenger-mock.d.cts.map +1 -1
  42. package/dist/tests/messenger-mock.d.mts +23 -21
  43. package/dist/tests/messenger-mock.d.mts.map +1 -1
  44. package/dist/utils/gas-station.cjs +1 -1
  45. package/dist/utils/gas-station.cjs.map +1 -1
  46. package/dist/utils/gas-station.mjs +1 -1
  47. package/dist/utils/gas-station.mjs.map +1 -1
  48. package/dist/utils/source-amounts.cjs +2 -2
  49. package/dist/utils/source-amounts.cjs.map +1 -1
  50. package/dist/utils/source-amounts.d.cts.map +1 -1
  51. package/dist/utils/source-amounts.d.mts.map +1 -1
  52. package/dist/utils/source-amounts.mjs +3 -3
  53. package/dist/utils/source-amounts.mjs.map +1 -1
  54. package/dist/utils/token.cjs +4 -4
  55. package/dist/utils/token.cjs.map +1 -1
  56. package/dist/utils/token.mjs +4 -4
  57. package/dist/utils/token.mjs.map +1 -1
  58. package/package.json +5 -5
@@ -39,7 +39,7 @@ async function getGasStationCostInSourceTokenRaw({ firstStepData, messenger, req
39
39
  });
40
40
  return undefined;
41
41
  }
42
- const gasFeeToken = gasFeeTokens.find((singleGasFeeToken) => singleGasFeeToken.tokenAddress.toLowerCase() ===
42
+ const gasFeeToken = gasFeeTokens?.find((singleGasFeeToken) => singleGasFeeToken.tokenAddress.toLowerCase() ===
43
43
  sourceTokenAddress.toLowerCase());
44
44
  if (!gasFeeToken) {
45
45
  log('No matching source token in gas fee token estimate', {
@@ -1 +1 @@
1
- {"version":3,"file":"gas-station.cjs","sourceRoot":"","sources":["../../src/utils/gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type { GasFeeToken } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../logger';\nimport type {\n Amount,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../types';\nimport { getFeatureFlags, isEIP7702Chain } from './feature-flags';\nimport { calculateGasFeeTokenCost } from './gas';\n\nconst log = createModuleLogger(projectLogger, 'gas-station');\n\ntype GasStationCostParams = {\n firstStepData: {\n data: Hex;\n to: Hex;\n value?: string;\n };\n messenger: TransactionPayControllerMessenger;\n request: Pick<QuoteRequest, 'from' | 'sourceChainId' | 'sourceTokenAddress'>;\n totalGasEstimate: number;\n totalItemCount: number;\n};\n\nexport type GasStationEligibility = {\n chainSupportsGasStation: boolean;\n isDisabledChain: boolean;\n isEligible: boolean;\n};\n\nexport function getGasStationEligibility(\n messenger: TransactionPayControllerMessenger,\n sourceChainId: QuoteRequest['sourceChainId'],\n): GasStationEligibility {\n const { relayDisabledGasStationChains } = getFeatureFlags(messenger);\n const chainSupportsGasStation = isEIP7702Chain(messenger, sourceChainId);\n\n const isDisabledChain = relayDisabledGasStationChains.includes(sourceChainId);\n\n return {\n chainSupportsGasStation,\n isDisabledChain,\n isEligible: !isDisabledChain && chainSupportsGasStation,\n };\n}\n\nexport async function getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request,\n totalGasEstimate,\n totalItemCount,\n}: GasStationCostParams): Promise<Amount | undefined> {\n const { data, to, value } = firstStepData;\n const { from, sourceChainId, sourceTokenAddress } = request;\n\n let gasFeeTokens: GasFeeToken[];\n\n try {\n gasFeeTokens = await messenger.call(\n 'TransactionController:getGasFeeTokens',\n {\n chainId: sourceChainId,\n data,\n from,\n to,\n value: toHex(value ?? '0'),\n },\n );\n } catch (error) {\n log('Failed to estimate gas fee tokens', {\n error,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeToken = gasFeeTokens.find(\n (singleGasFeeToken) =>\n singleGasFeeToken.tokenAddress.toLowerCase() ===\n sourceTokenAddress.toLowerCase(),\n );\n\n if (!gasFeeToken) {\n log('No matching source token in gas fee token estimate', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeTokenWithNormalizedAmount = {\n ...gasFeeToken,\n amount: toHex(\n getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n }),\n ),\n };\n\n const gasFeeTokenCost = calculateGasFeeTokenCost({\n chainId: sourceChainId,\n gasFeeToken: gasFeeTokenWithNormalizedAmount,\n messenger,\n });\n\n if (!gasFeeTokenCost) {\n log('Unable to calculate gas fee token cost using fiat rates', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n log('Estimated gas station cost for source token', {\n amount: gasFeeTokenCost.raw,\n sourceTokenAddress,\n sourceChainId,\n });\n\n return gasFeeTokenCost;\n}\n\nfunction getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n}: {\n gasFeeToken: GasFeeToken;\n totalGasEstimate: number;\n totalItemCount: number;\n}): string {\n let amount = new BigNumber(gasFeeToken.amount);\n\n if (totalItemCount > 1) {\n const gas = new BigNumber(gasFeeToken.gas);\n const gasFeeAmount = new BigNumber(gasFeeToken.amount);\n\n if (totalGasEstimate > 0 && gas.isGreaterThan(0)) {\n const gasRate = gasFeeAmount.dividedBy(gas);\n amount = gasRate.multipliedBy(totalGasEstimate);\n }\n }\n\n return amount.integerValue(BigNumber.ROUND_CEIL).toFixed(0);\n}\n"]}
1
+ {"version":3,"file":"gas-station.cjs","sourceRoot":"","sources":["../../src/utils/gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type { GasFeeToken } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../logger';\nimport type {\n Amount,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../types';\nimport { getFeatureFlags, isEIP7702Chain } from './feature-flags';\nimport { calculateGasFeeTokenCost } from './gas';\n\nconst log = createModuleLogger(projectLogger, 'gas-station');\n\ntype GasStationCostParams = {\n firstStepData: {\n data: Hex;\n to: Hex;\n value?: string;\n };\n messenger: TransactionPayControllerMessenger;\n request: Pick<QuoteRequest, 'from' | 'sourceChainId' | 'sourceTokenAddress'>;\n totalGasEstimate: number;\n totalItemCount: number;\n};\n\nexport type GasStationEligibility = {\n chainSupportsGasStation: boolean;\n isDisabledChain: boolean;\n isEligible: boolean;\n};\n\nexport function getGasStationEligibility(\n messenger: TransactionPayControllerMessenger,\n sourceChainId: QuoteRequest['sourceChainId'],\n): GasStationEligibility {\n const { relayDisabledGasStationChains } = getFeatureFlags(messenger);\n const chainSupportsGasStation = isEIP7702Chain(messenger, sourceChainId);\n\n const isDisabledChain = relayDisabledGasStationChains.includes(sourceChainId);\n\n return {\n chainSupportsGasStation,\n isDisabledChain,\n isEligible: !isDisabledChain && chainSupportsGasStation,\n };\n}\n\nexport async function getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request,\n totalGasEstimate,\n totalItemCount,\n}: GasStationCostParams): Promise<Amount | undefined> {\n const { data, to, value } = firstStepData;\n const { from, sourceChainId, sourceTokenAddress } = request;\n\n let gasFeeTokens: GasFeeToken[] | undefined;\n\n try {\n gasFeeTokens = await messenger.call(\n 'TransactionController:getGasFeeTokens',\n {\n chainId: sourceChainId,\n data,\n from,\n to,\n value: toHex(value ?? '0'),\n },\n );\n } catch (error) {\n log('Failed to estimate gas fee tokens', {\n error,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeToken = gasFeeTokens?.find(\n (singleGasFeeToken) =>\n singleGasFeeToken.tokenAddress.toLowerCase() ===\n sourceTokenAddress.toLowerCase(),\n );\n\n if (!gasFeeToken) {\n log('No matching source token in gas fee token estimate', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeTokenWithNormalizedAmount = {\n ...gasFeeToken,\n amount: toHex(\n getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n }),\n ),\n };\n\n const gasFeeTokenCost = calculateGasFeeTokenCost({\n chainId: sourceChainId,\n gasFeeToken: gasFeeTokenWithNormalizedAmount,\n messenger,\n });\n\n if (!gasFeeTokenCost) {\n log('Unable to calculate gas fee token cost using fiat rates', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n log('Estimated gas station cost for source token', {\n amount: gasFeeTokenCost.raw,\n sourceTokenAddress,\n sourceChainId,\n });\n\n return gasFeeTokenCost;\n}\n\nfunction getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n}: {\n gasFeeToken: GasFeeToken;\n totalGasEstimate: number;\n totalItemCount: number;\n}): string {\n let amount = new BigNumber(gasFeeToken.amount);\n\n if (totalItemCount > 1) {\n const gas = new BigNumber(gasFeeToken.gas);\n const gasFeeAmount = new BigNumber(gasFeeToken.amount);\n\n if (totalGasEstimate > 0 && gas.isGreaterThan(0)) {\n const gasRate = gasFeeAmount.dividedBy(gas);\n amount = gasRate.multipliedBy(totalGasEstimate);\n }\n }\n\n return amount.integerValue(BigNumber.ROUND_CEIL).toFixed(0);\n}\n"]}
@@ -35,7 +35,7 @@ export async function getGasStationCostInSourceTokenRaw({ firstStepData, messeng
35
35
  });
36
36
  return undefined;
37
37
  }
38
- const gasFeeToken = gasFeeTokens.find((singleGasFeeToken) => singleGasFeeToken.tokenAddress.toLowerCase() ===
38
+ const gasFeeToken = gasFeeTokens?.find((singleGasFeeToken) => singleGasFeeToken.tokenAddress.toLowerCase() ===
39
39
  sourceTokenAddress.toLowerCase());
40
40
  if (!gasFeeToken) {
41
41
  log('No matching source token in gas fee token estimate', {
@@ -1 +1 @@
1
- {"version":3,"file":"gas-station.mjs","sourceRoot":"","sources":["../../src/utils/gas-station.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,mCAAmC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB;AACrD,OAAO,EAAE,SAAS,EAAE,qBAAqB;AAEzC,OAAO,EAAE,aAAa,EAAE,sBAAkB;AAM1C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,4BAAwB;AAClE,OAAO,EAAE,wBAAwB,EAAE,kBAAc;AAEjD,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAoB7D,MAAM,UAAU,wBAAwB,CACtC,SAA4C,EAC5C,aAA4C;IAE5C,MAAM,EAAE,6BAA6B,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACrE,MAAM,uBAAuB,GAAG,cAAc,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAEzE,MAAM,eAAe,GAAG,6BAA6B,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAE9E,OAAO;QACL,uBAAuB;QACvB,eAAe;QACf,UAAU,EAAE,CAAC,eAAe,IAAI,uBAAuB;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CAAC,EACtD,aAAa,EACb,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,cAAc,GACO;IACrB,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,aAAa,CAAC;IAC1C,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC;IAE5D,IAAI,YAA2B,CAAC;IAEhC,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,SAAS,CAAC,IAAI,CACjC,uCAAuC,EACvC;YACE,OAAO,EAAE,aAAa;YACtB,IAAI;YACJ,IAAI;YACJ,EAAE;YACF,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC;SAC3B,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,mCAAmC,EAAE;YACvC,KAAK;YACL,aAAa;SACd,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CACnC,CAAC,iBAAiB,EAAE,EAAE,CACpB,iBAAiB,CAAC,YAAY,CAAC,WAAW,EAAE;QAC5C,kBAAkB,CAAC,WAAW,EAAE,CACnC,CAAC;IAEF,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,GAAG,CAAC,oDAAoD,EAAE;YACxD,kBAAkB;YAClB,aAAa;SACd,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,+BAA+B,GAAG;QACtC,GAAG,WAAW;QACd,MAAM,EAAE,KAAK,CACX,8BAA8B,CAAC;YAC7B,WAAW;YACX,gBAAgB;YAChB,cAAc;SACf,CAAC,CACH;KACF,CAAC;IAEF,MAAM,eAAe,GAAG,wBAAwB,CAAC;QAC/C,OAAO,EAAE,aAAa;QACtB,WAAW,EAAE,+BAA+B;QAC5C,SAAS;KACV,CAAC,CAAC;IAEH,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,GAAG,CAAC,yDAAyD,EAAE;YAC7D,kBAAkB;YAClB,aAAa;SACd,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,GAAG,CAAC,6CAA6C,EAAE;QACjD,MAAM,EAAE,eAAe,CAAC,GAAG;QAC3B,kBAAkB;QAClB,aAAa;KACd,CAAC,CAAC;IAEH,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,SAAS,8BAA8B,CAAC,EACtC,WAAW,EACX,gBAAgB,EAChB,cAAc,GAKf;IACC,IAAI,MAAM,GAAG,IAAI,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAE/C,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,IAAI,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAEvD,IAAI,gBAAgB,GAAG,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC5C,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type { GasFeeToken } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../logger';\nimport type {\n Amount,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../types';\nimport { getFeatureFlags, isEIP7702Chain } from './feature-flags';\nimport { calculateGasFeeTokenCost } from './gas';\n\nconst log = createModuleLogger(projectLogger, 'gas-station');\n\ntype GasStationCostParams = {\n firstStepData: {\n data: Hex;\n to: Hex;\n value?: string;\n };\n messenger: TransactionPayControllerMessenger;\n request: Pick<QuoteRequest, 'from' | 'sourceChainId' | 'sourceTokenAddress'>;\n totalGasEstimate: number;\n totalItemCount: number;\n};\n\nexport type GasStationEligibility = {\n chainSupportsGasStation: boolean;\n isDisabledChain: boolean;\n isEligible: boolean;\n};\n\nexport function getGasStationEligibility(\n messenger: TransactionPayControllerMessenger,\n sourceChainId: QuoteRequest['sourceChainId'],\n): GasStationEligibility {\n const { relayDisabledGasStationChains } = getFeatureFlags(messenger);\n const chainSupportsGasStation = isEIP7702Chain(messenger, sourceChainId);\n\n const isDisabledChain = relayDisabledGasStationChains.includes(sourceChainId);\n\n return {\n chainSupportsGasStation,\n isDisabledChain,\n isEligible: !isDisabledChain && chainSupportsGasStation,\n };\n}\n\nexport async function getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request,\n totalGasEstimate,\n totalItemCount,\n}: GasStationCostParams): Promise<Amount | undefined> {\n const { data, to, value } = firstStepData;\n const { from, sourceChainId, sourceTokenAddress } = request;\n\n let gasFeeTokens: GasFeeToken[];\n\n try {\n gasFeeTokens = await messenger.call(\n 'TransactionController:getGasFeeTokens',\n {\n chainId: sourceChainId,\n data,\n from,\n to,\n value: toHex(value ?? '0'),\n },\n );\n } catch (error) {\n log('Failed to estimate gas fee tokens', {\n error,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeToken = gasFeeTokens.find(\n (singleGasFeeToken) =>\n singleGasFeeToken.tokenAddress.toLowerCase() ===\n sourceTokenAddress.toLowerCase(),\n );\n\n if (!gasFeeToken) {\n log('No matching source token in gas fee token estimate', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeTokenWithNormalizedAmount = {\n ...gasFeeToken,\n amount: toHex(\n getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n }),\n ),\n };\n\n const gasFeeTokenCost = calculateGasFeeTokenCost({\n chainId: sourceChainId,\n gasFeeToken: gasFeeTokenWithNormalizedAmount,\n messenger,\n });\n\n if (!gasFeeTokenCost) {\n log('Unable to calculate gas fee token cost using fiat rates', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n log('Estimated gas station cost for source token', {\n amount: gasFeeTokenCost.raw,\n sourceTokenAddress,\n sourceChainId,\n });\n\n return gasFeeTokenCost;\n}\n\nfunction getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n}: {\n gasFeeToken: GasFeeToken;\n totalGasEstimate: number;\n totalItemCount: number;\n}): string {\n let amount = new BigNumber(gasFeeToken.amount);\n\n if (totalItemCount > 1) {\n const gas = new BigNumber(gasFeeToken.gas);\n const gasFeeAmount = new BigNumber(gasFeeToken.amount);\n\n if (totalGasEstimate > 0 && gas.isGreaterThan(0)) {\n const gasRate = gasFeeAmount.dividedBy(gas);\n amount = gasRate.multipliedBy(totalGasEstimate);\n }\n }\n\n return amount.integerValue(BigNumber.ROUND_CEIL).toFixed(0);\n}\n"]}
1
+ {"version":3,"file":"gas-station.mjs","sourceRoot":"","sources":["../../src/utils/gas-station.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type { GasFeeToken } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../logger';\nimport type {\n Amount,\n QuoteRequest,\n TransactionPayControllerMessenger,\n} from '../types';\nimport { getFeatureFlags, isEIP7702Chain } from './feature-flags';\nimport { calculateGasFeeTokenCost } from './gas';\n\nconst log = createModuleLogger(projectLogger, 'gas-station');\n\ntype GasStationCostParams = {\n firstStepData: {\n data: Hex;\n to: Hex;\n value?: string;\n };\n messenger: TransactionPayControllerMessenger;\n request: Pick<QuoteRequest, 'from' | 'sourceChainId' | 'sourceTokenAddress'>;\n totalGasEstimate: number;\n totalItemCount: number;\n};\n\nexport type GasStationEligibility = {\n chainSupportsGasStation: boolean;\n isDisabledChain: boolean;\n isEligible: boolean;\n};\n\nexport function getGasStationEligibility(\n messenger: TransactionPayControllerMessenger,\n sourceChainId: QuoteRequest['sourceChainId'],\n): GasStationEligibility {\n const { relayDisabledGasStationChains } = getFeatureFlags(messenger);\n const chainSupportsGasStation = isEIP7702Chain(messenger, sourceChainId);\n\n const isDisabledChain = relayDisabledGasStationChains.includes(sourceChainId);\n\n return {\n chainSupportsGasStation,\n isDisabledChain,\n isEligible: !isDisabledChain && chainSupportsGasStation,\n };\n}\n\nexport async function getGasStationCostInSourceTokenRaw({\n firstStepData,\n messenger,\n request,\n totalGasEstimate,\n totalItemCount,\n}: GasStationCostParams): Promise<Amount | undefined> {\n const { data, to, value } = firstStepData;\n const { from, sourceChainId, sourceTokenAddress } = request;\n\n let gasFeeTokens: GasFeeToken[] | undefined;\n\n try {\n gasFeeTokens = await messenger.call(\n 'TransactionController:getGasFeeTokens',\n {\n chainId: sourceChainId,\n data,\n from,\n to,\n value: toHex(value ?? '0'),\n },\n );\n } catch (error) {\n log('Failed to estimate gas fee tokens', {\n error,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeToken = gasFeeTokens?.find(\n (singleGasFeeToken) =>\n singleGasFeeToken.tokenAddress.toLowerCase() ===\n sourceTokenAddress.toLowerCase(),\n );\n\n if (!gasFeeToken) {\n log('No matching source token in gas fee token estimate', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n const gasFeeTokenWithNormalizedAmount = {\n ...gasFeeToken,\n amount: toHex(\n getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n }),\n ),\n };\n\n const gasFeeTokenCost = calculateGasFeeTokenCost({\n chainId: sourceChainId,\n gasFeeToken: gasFeeTokenWithNormalizedAmount,\n messenger,\n });\n\n if (!gasFeeTokenCost) {\n log('Unable to calculate gas fee token cost using fiat rates', {\n sourceTokenAddress,\n sourceChainId,\n });\n return undefined;\n }\n\n log('Estimated gas station cost for source token', {\n amount: gasFeeTokenCost.raw,\n sourceTokenAddress,\n sourceChainId,\n });\n\n return gasFeeTokenCost;\n}\n\nfunction getNormalizedGasFeeTokenAmount({\n gasFeeToken,\n totalGasEstimate,\n totalItemCount,\n}: {\n gasFeeToken: GasFeeToken;\n totalGasEstimate: number;\n totalItemCount: number;\n}): string {\n let amount = new BigNumber(gasFeeToken.amount);\n\n if (totalItemCount > 1) {\n const gas = new BigNumber(gasFeeToken.gas);\n const gasFeeAmount = new BigNumber(gasFeeToken.amount);\n\n if (totalGasEstimate > 0 && gas.isGreaterThan(0)) {\n const gasRate = gasFeeAmount.dividedBy(gas);\n amount = gasRate.multipliedBy(totalGasEstimate);\n }\n }\n\n return amount.integerValue(BigNumber.ROUND_CEIL).toFixed(0);\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.updateSourceAmounts = void 0;
4
- const transaction_controller_1 = require("@metamask/transaction-controller");
5
4
  const utils_1 = require("@metamask/utils");
6
5
  const bignumber_js_1 = require("bignumber.js");
7
6
  const __1 = require("../index.cjs");
@@ -148,7 +147,8 @@ function isQuoteAlwaysRequired(token, strategy, parentTransactionType) {
148
147
  return (isHyperliquidDeposit &&
149
148
  (strategy === __1.TransactionPayStrategy.Relay ||
150
149
  (strategy === __1.TransactionPayStrategy.Across &&
151
- parentTransactionType === transaction_controller_1.TransactionType.perpsDeposit)));
150
+ parentTransactionType !== undefined &&
151
+ constants_1.PERPS_DEPOSIT_TYPES.includes(parentTransactionType))));
152
152
  }
153
153
  function getStrategyContext(transactionId, messenger) {
154
154
  const transaction = (0, transaction_1.getTransaction)(transactionId, messenger);
@@ -1 +1 @@
1
- {"version":3,"file":"source-amounts.cjs","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { TransactionType } from '@metamask/transaction-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type {\n TransactionPayControllerMessenger,\n TransactionPaymentToken,\n} from '..';\nimport { TransactionPayStrategy } from '..';\nimport { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM } from '../constants';\nimport { projectLogger } from '../logger';\nimport type {\n TransactionPaySourceAmount,\n TransactionData,\n TransactionPayRequiredToken,\n} from '../types';\nimport { getTokenFiatRate, isSameToken } from './token';\nimport { getTransaction } from './transaction';\n\nconst log = createModuleLogger(projectLogger, 'source-amounts');\n\n/**\n * Update the source amounts for a transaction.\n *\n * @param transactionId - ID of the transaction to update.\n * @param transactionData - Existing transaction data.\n * @param messenger - Controller messenger.\n */\nexport function updateSourceAmounts(\n transactionId: string,\n transactionData: TransactionData | undefined,\n messenger: TransactionPayControllerMessenger,\n): void {\n if (!transactionData) {\n return;\n }\n\n const { isMaxAmount, isPostQuote, paymentToken, tokens } = transactionData;\n\n if (!tokens.length || !paymentToken) {\n return;\n }\n\n // For post-quote flows, source amounts are calculated differently\n // The source is the transaction's required token, not the selected token\n if (isPostQuote) {\n const { isHyperliquidSource, isPolymarketDepositWallet } = transactionData;\n const sourceAmounts = calculatePostQuoteSourceAmounts(\n tokens,\n paymentToken,\n isMaxAmount ?? false,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n );\n log('Updated post-quote source amounts', { transactionId, sourceAmounts });\n transactionData.sourceAmounts = sourceAmounts;\n return;\n }\n\n const sourceAmounts = tokens\n .map((singleToken) =>\n calculateSourceAmount(\n paymentToken,\n singleToken,\n messenger,\n transactionId,\n isMaxAmount ?? false,\n ),\n )\n .filter(Boolean) as TransactionPaySourceAmount[];\n\n log('Updated source amounts', { transactionId, sourceAmounts });\n\n transactionData.sourceAmounts = sourceAmounts;\n}\n\n/**\n * Calculate source amounts for post-quote flows.\n * In this flow, the required tokens ARE the source tokens,\n * and the payment token is the target (destination).\n *\n * @param tokens - Required tokens from the transaction.\n * @param paymentToken - Selected payment/destination token.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param isHyperliquidSource - Whether the source is HyperLiquid (perps withdrawal).\n * @param isPolymarketDepositWallet - Whether the source is a Polymarket deposit wallet.\n * @returns Array of source amounts.\n */\nfunction calculatePostQuoteSourceAmounts(\n tokens: TransactionPayRequiredToken[],\n paymentToken: TransactionPaymentToken,\n isMaxAmount: boolean,\n isHyperliquidSource?: boolean,\n isPolymarketDepositWallet?: boolean,\n): TransactionPaySourceAmount[] {\n return tokens\n .filter((token) => {\n if (token.skipIfBalance) {\n return false;\n }\n\n // Skip zero amounts (unless max amount, where we use balance)\n if (token.amountRaw === '0' && !isMaxAmount) {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return false;\n }\n\n // Skip same token on same chain, unless the source is a synthetic\n // upstream (HyperLiquid HyperCore or Polymarket deposit wallet) that\n // the strategy renormalizes to a different effective source.\n if (\n isSameToken(token, paymentToken) &&\n !isHyperliquidSource &&\n !isPolymarketDepositWallet\n ) {\n log('Skipping token as same as destination token');\n return false;\n }\n\n return true;\n })\n .map((token) => ({\n sourceAmountHuman: isMaxAmount ? token.balanceHuman : token.amountHuman,\n sourceAmountRaw: isMaxAmount ? token.balanceRaw : token.amountRaw,\n sourceBalanceRaw: token.balanceRaw,\n sourceChainId: token.chainId,\n sourceTokenAddress: token.address,\n targetTokenAddress: paymentToken.address,\n }));\n}\n\n/**\n * Calculate the required source amount for a payment token to cover a target token.\n *\n * @param paymentToken - Selected payment token.\n * @param token - Target token to cover.\n * @param messenger - Controller messenger.\n * @param transactionId - ID of the transaction.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @returns The source amount or undefined if calculation failed.\n */\nfunction calculateSourceAmount(\n paymentToken: TransactionPaymentToken,\n token: TransactionPayRequiredToken,\n messenger: TransactionPayControllerMessenger,\n transactionId: string,\n isMaxAmount: boolean,\n): TransactionPaySourceAmount | undefined {\n const paymentTokenFiatRate = getTokenFiatRate(\n messenger,\n paymentToken.address,\n paymentToken.chainId,\n );\n\n if (!paymentTokenFiatRate) {\n return undefined;\n }\n\n const hasBalance = new BigNumber(token.balanceRaw).gte(token.amountRaw);\n\n if (token.skipIfBalance && hasBalance) {\n log('Skipping token as sufficient balance', {\n tokenAddress: token.address,\n });\n return undefined;\n }\n\n const { parentTransactionType, strategy } = getStrategyContext(\n transactionId,\n messenger,\n );\n const isAlwaysRequired = isQuoteAlwaysRequired(\n token,\n strategy,\n parentTransactionType,\n );\n\n if (isSameToken(token, paymentToken) && !isAlwaysRequired) {\n log('Skipping token as same as payment token');\n return undefined;\n }\n\n const sourceAmountHumanValue = new BigNumber(token.amountUsd).div(\n paymentTokenFiatRate.usdRate,\n );\n\n const sourceAmountHuman = sourceAmountHumanValue.toString(10);\n\n const sourceAmountRaw = sourceAmountHumanValue\n .shiftedBy(paymentToken.decimals)\n .toFixed(0);\n\n if (token.amountRaw === '0') {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return undefined;\n }\n\n if (isMaxAmount) {\n return {\n sourceAmountHuman: paymentToken.balanceHuman,\n sourceAmountRaw: paymentToken.balanceRaw,\n targetTokenAddress: token.address,\n };\n }\n\n return {\n sourceAmountHuman,\n sourceAmountRaw,\n targetTokenAddress: token.address,\n };\n}\n\n/**\n * Determine if a quote is always required for a token and strategy.\n *\n * @param token - Target token.\n * @param strategy - Payment strategy.\n * @param parentTransactionType - Parent transaction type, if available.\n * @returns True if a quote is always required, false otherwise.\n */\nfunction isQuoteAlwaysRequired(\n token: TransactionPayRequiredToken,\n strategy: TransactionPayStrategy,\n parentTransactionType?: TransactionType,\n): boolean {\n const isHyperliquidDeposit =\n token.chainId === CHAIN_ID_ARBITRUM &&\n token.address.toLowerCase() === ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n return (\n isHyperliquidDeposit &&\n (strategy === TransactionPayStrategy.Relay ||\n (strategy === TransactionPayStrategy.Across &&\n parentTransactionType === TransactionType.perpsDeposit))\n );\n}\n\nfunction getStrategyContext(\n transactionId: string,\n messenger: TransactionPayControllerMessenger,\n): {\n parentTransactionType?: TransactionType;\n strategy: TransactionPayStrategy;\n} {\n const transaction = getTransaction(\n transactionId,\n messenger,\n ) as TransactionMeta;\n\n return {\n parentTransactionType: transaction.type,\n strategy: messenger.call(\n 'TransactionPayController:getStrategy',\n transaction,\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"source-amounts.cjs","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n TransactionMeta,\n TransactionType,\n} from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type {\n TransactionPayControllerMessenger,\n TransactionPaymentToken,\n} from '..';\nimport { TransactionPayStrategy } from '..';\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n PERPS_DEPOSIT_TYPES,\n} from '../constants';\nimport { projectLogger } from '../logger';\nimport type {\n TransactionPaySourceAmount,\n TransactionData,\n TransactionPayRequiredToken,\n} from '../types';\nimport { getTokenFiatRate, isSameToken } from './token';\nimport { getTransaction } from './transaction';\n\nconst log = createModuleLogger(projectLogger, 'source-amounts');\n\n/**\n * Update the source amounts for a transaction.\n *\n * @param transactionId - ID of the transaction to update.\n * @param transactionData - Existing transaction data.\n * @param messenger - Controller messenger.\n */\nexport function updateSourceAmounts(\n transactionId: string,\n transactionData: TransactionData | undefined,\n messenger: TransactionPayControllerMessenger,\n): void {\n if (!transactionData) {\n return;\n }\n\n const { isMaxAmount, isPostQuote, paymentToken, tokens } = transactionData;\n\n if (!tokens.length || !paymentToken) {\n return;\n }\n\n // For post-quote flows, source amounts are calculated differently\n // The source is the transaction's required token, not the selected token\n if (isPostQuote) {\n const { isHyperliquidSource, isPolymarketDepositWallet } = transactionData;\n const sourceAmounts = calculatePostQuoteSourceAmounts(\n tokens,\n paymentToken,\n isMaxAmount ?? false,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n );\n log('Updated post-quote source amounts', { transactionId, sourceAmounts });\n transactionData.sourceAmounts = sourceAmounts;\n return;\n }\n\n const sourceAmounts = tokens\n .map((singleToken) =>\n calculateSourceAmount(\n paymentToken,\n singleToken,\n messenger,\n transactionId,\n isMaxAmount ?? false,\n ),\n )\n .filter(Boolean) as TransactionPaySourceAmount[];\n\n log('Updated source amounts', { transactionId, sourceAmounts });\n\n transactionData.sourceAmounts = sourceAmounts;\n}\n\n/**\n * Calculate source amounts for post-quote flows.\n * In this flow, the required tokens ARE the source tokens,\n * and the payment token is the target (destination).\n *\n * @param tokens - Required tokens from the transaction.\n * @param paymentToken - Selected payment/destination token.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param isHyperliquidSource - Whether the source is HyperLiquid (perps withdrawal).\n * @param isPolymarketDepositWallet - Whether the source is a Polymarket deposit wallet.\n * @returns Array of source amounts.\n */\nfunction calculatePostQuoteSourceAmounts(\n tokens: TransactionPayRequiredToken[],\n paymentToken: TransactionPaymentToken,\n isMaxAmount: boolean,\n isHyperliquidSource?: boolean,\n isPolymarketDepositWallet?: boolean,\n): TransactionPaySourceAmount[] {\n return tokens\n .filter((token) => {\n if (token.skipIfBalance) {\n return false;\n }\n\n // Skip zero amounts (unless max amount, where we use balance)\n if (token.amountRaw === '0' && !isMaxAmount) {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return false;\n }\n\n // Skip same token on same chain, unless the source is a synthetic\n // upstream (HyperLiquid HyperCore or Polymarket deposit wallet) that\n // the strategy renormalizes to a different effective source.\n if (\n isSameToken(token, paymentToken) &&\n !isHyperliquidSource &&\n !isPolymarketDepositWallet\n ) {\n log('Skipping token as same as destination token');\n return false;\n }\n\n return true;\n })\n .map((token) => ({\n sourceAmountHuman: isMaxAmount ? token.balanceHuman : token.amountHuman,\n sourceAmountRaw: isMaxAmount ? token.balanceRaw : token.amountRaw,\n sourceBalanceRaw: token.balanceRaw,\n sourceChainId: token.chainId,\n sourceTokenAddress: token.address,\n targetTokenAddress: paymentToken.address,\n }));\n}\n\n/**\n * Calculate the required source amount for a payment token to cover a target token.\n *\n * @param paymentToken - Selected payment token.\n * @param token - Target token to cover.\n * @param messenger - Controller messenger.\n * @param transactionId - ID of the transaction.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @returns The source amount or undefined if calculation failed.\n */\nfunction calculateSourceAmount(\n paymentToken: TransactionPaymentToken,\n token: TransactionPayRequiredToken,\n messenger: TransactionPayControllerMessenger,\n transactionId: string,\n isMaxAmount: boolean,\n): TransactionPaySourceAmount | undefined {\n const paymentTokenFiatRate = getTokenFiatRate(\n messenger,\n paymentToken.address,\n paymentToken.chainId,\n );\n\n if (!paymentTokenFiatRate) {\n return undefined;\n }\n\n const hasBalance = new BigNumber(token.balanceRaw).gte(token.amountRaw);\n\n if (token.skipIfBalance && hasBalance) {\n log('Skipping token as sufficient balance', {\n tokenAddress: token.address,\n });\n return undefined;\n }\n\n const { parentTransactionType, strategy } = getStrategyContext(\n transactionId,\n messenger,\n );\n const isAlwaysRequired = isQuoteAlwaysRequired(\n token,\n strategy,\n parentTransactionType,\n );\n\n if (isSameToken(token, paymentToken) && !isAlwaysRequired) {\n log('Skipping token as same as payment token');\n return undefined;\n }\n\n const sourceAmountHumanValue = new BigNumber(token.amountUsd).div(\n paymentTokenFiatRate.usdRate,\n );\n\n const sourceAmountHuman = sourceAmountHumanValue.toString(10);\n\n const sourceAmountRaw = sourceAmountHumanValue\n .shiftedBy(paymentToken.decimals)\n .toFixed(0);\n\n if (token.amountRaw === '0') {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return undefined;\n }\n\n if (isMaxAmount) {\n return {\n sourceAmountHuman: paymentToken.balanceHuman,\n sourceAmountRaw: paymentToken.balanceRaw,\n targetTokenAddress: token.address,\n };\n }\n\n return {\n sourceAmountHuman,\n sourceAmountRaw,\n targetTokenAddress: token.address,\n };\n}\n\n/**\n * Determine if a quote is always required for a token and strategy.\n *\n * @param token - Target token.\n * @param strategy - Payment strategy.\n * @param parentTransactionType - Parent transaction type, if available.\n * @returns True if a quote is always required, false otherwise.\n */\nfunction isQuoteAlwaysRequired(\n token: TransactionPayRequiredToken,\n strategy: TransactionPayStrategy,\n parentTransactionType?: TransactionType,\n): boolean {\n const isHyperliquidDeposit =\n token.chainId === CHAIN_ID_ARBITRUM &&\n token.address.toLowerCase() === ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n return (\n isHyperliquidDeposit &&\n (strategy === TransactionPayStrategy.Relay ||\n (strategy === TransactionPayStrategy.Across &&\n parentTransactionType !== undefined &&\n PERPS_DEPOSIT_TYPES.includes(parentTransactionType)))\n );\n}\n\nfunction getStrategyContext(\n transactionId: string,\n messenger: TransactionPayControllerMessenger,\n): {\n parentTransactionType?: TransactionType;\n strategy: TransactionPayStrategy;\n} {\n const transaction = getTransaction(\n transactionId,\n messenger,\n ) as TransactionMeta;\n\n return {\n parentTransactionType: transaction.type,\n strategy: messenger.call(\n 'TransactionPayController:getStrategy',\n transaction,\n ),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"source-amounts.d.cts","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,iCAAiC,EAElC,qBAAW;AAIZ,OAAO,KAAK,EAEV,eAAe,EAEhB,qBAAiB;AAMlB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,eAAe,GAAG,SAAS,EAC5C,SAAS,EAAE,iCAAiC,GAC3C,IAAI,CA0CN"}
1
+ {"version":3,"file":"source-amounts.d.cts","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,iCAAiC,EAElC,qBAAW;AAQZ,OAAO,KAAK,EAEV,eAAe,EAEhB,qBAAiB;AAMlB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,eAAe,GAAG,SAAS,EAC5C,SAAS,EAAE,iCAAiC,GAC3C,IAAI,CA0CN"}
@@ -1 +1 @@
1
- {"version":3,"file":"source-amounts.d.mts","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,iCAAiC,EAElC,qBAAW;AAIZ,OAAO,KAAK,EAEV,eAAe,EAEhB,qBAAiB;AAMlB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,eAAe,GAAG,SAAS,EAC5C,SAAS,EAAE,iCAAiC,GAC3C,IAAI,CA0CN"}
1
+ {"version":3,"file":"source-amounts.d.mts","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,iCAAiC,EAElC,qBAAW;AAQZ,OAAO,KAAK,EAEV,eAAe,EAEhB,qBAAiB;AAMlB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,eAAe,GAAG,SAAS,EAC5C,SAAS,EAAE,iCAAiC,GAC3C,IAAI,CA0CN"}
@@ -1,8 +1,7 @@
1
- import { TransactionType } from "@metamask/transaction-controller";
2
1
  import { createModuleLogger } from "@metamask/utils";
3
2
  import { BigNumber } from "bignumber.js";
4
3
  import { TransactionPayStrategy } from "../index.mjs";
5
- import { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM } from "../constants.mjs";
4
+ import { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM, PERPS_DEPOSIT_TYPES } from "../constants.mjs";
6
5
  import { projectLogger } from "../logger.mjs";
7
6
  import { getTokenFiatRate, isSameToken } from "./token.mjs";
8
7
  import { getTransaction } from "./transaction.mjs";
@@ -144,7 +143,8 @@ function isQuoteAlwaysRequired(token, strategy, parentTransactionType) {
144
143
  return (isHyperliquidDeposit &&
145
144
  (strategy === TransactionPayStrategy.Relay ||
146
145
  (strategy === TransactionPayStrategy.Across &&
147
- parentTransactionType === TransactionType.perpsDeposit)));
146
+ parentTransactionType !== undefined &&
147
+ PERPS_DEPOSIT_TYPES.includes(parentTransactionType))));
148
148
  }
149
149
  function getStrategyContext(transactionId, messenger) {
150
150
  const transaction = getTransaction(transactionId, messenger);
@@ -1 +1 @@
1
- {"version":3,"file":"source-amounts.mjs","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { TransactionType } from '@metamask/transaction-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type {\n TransactionPayControllerMessenger,\n TransactionPaymentToken,\n} from '..';\nimport { TransactionPayStrategy } from '..';\nimport { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM } from '../constants';\nimport { projectLogger } from '../logger';\nimport type {\n TransactionPaySourceAmount,\n TransactionData,\n TransactionPayRequiredToken,\n} from '../types';\nimport { getTokenFiatRate, isSameToken } from './token';\nimport { getTransaction } from './transaction';\n\nconst log = createModuleLogger(projectLogger, 'source-amounts');\n\n/**\n * Update the source amounts for a transaction.\n *\n * @param transactionId - ID of the transaction to update.\n * @param transactionData - Existing transaction data.\n * @param messenger - Controller messenger.\n */\nexport function updateSourceAmounts(\n transactionId: string,\n transactionData: TransactionData | undefined,\n messenger: TransactionPayControllerMessenger,\n): void {\n if (!transactionData) {\n return;\n }\n\n const { isMaxAmount, isPostQuote, paymentToken, tokens } = transactionData;\n\n if (!tokens.length || !paymentToken) {\n return;\n }\n\n // For post-quote flows, source amounts are calculated differently\n // The source is the transaction's required token, not the selected token\n if (isPostQuote) {\n const { isHyperliquidSource, isPolymarketDepositWallet } = transactionData;\n const sourceAmounts = calculatePostQuoteSourceAmounts(\n tokens,\n paymentToken,\n isMaxAmount ?? false,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n );\n log('Updated post-quote source amounts', { transactionId, sourceAmounts });\n transactionData.sourceAmounts = sourceAmounts;\n return;\n }\n\n const sourceAmounts = tokens\n .map((singleToken) =>\n calculateSourceAmount(\n paymentToken,\n singleToken,\n messenger,\n transactionId,\n isMaxAmount ?? false,\n ),\n )\n .filter(Boolean) as TransactionPaySourceAmount[];\n\n log('Updated source amounts', { transactionId, sourceAmounts });\n\n transactionData.sourceAmounts = sourceAmounts;\n}\n\n/**\n * Calculate source amounts for post-quote flows.\n * In this flow, the required tokens ARE the source tokens,\n * and the payment token is the target (destination).\n *\n * @param tokens - Required tokens from the transaction.\n * @param paymentToken - Selected payment/destination token.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param isHyperliquidSource - Whether the source is HyperLiquid (perps withdrawal).\n * @param isPolymarketDepositWallet - Whether the source is a Polymarket deposit wallet.\n * @returns Array of source amounts.\n */\nfunction calculatePostQuoteSourceAmounts(\n tokens: TransactionPayRequiredToken[],\n paymentToken: TransactionPaymentToken,\n isMaxAmount: boolean,\n isHyperliquidSource?: boolean,\n isPolymarketDepositWallet?: boolean,\n): TransactionPaySourceAmount[] {\n return tokens\n .filter((token) => {\n if (token.skipIfBalance) {\n return false;\n }\n\n // Skip zero amounts (unless max amount, where we use balance)\n if (token.amountRaw === '0' && !isMaxAmount) {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return false;\n }\n\n // Skip same token on same chain, unless the source is a synthetic\n // upstream (HyperLiquid HyperCore or Polymarket deposit wallet) that\n // the strategy renormalizes to a different effective source.\n if (\n isSameToken(token, paymentToken) &&\n !isHyperliquidSource &&\n !isPolymarketDepositWallet\n ) {\n log('Skipping token as same as destination token');\n return false;\n }\n\n return true;\n })\n .map((token) => ({\n sourceAmountHuman: isMaxAmount ? token.balanceHuman : token.amountHuman,\n sourceAmountRaw: isMaxAmount ? token.balanceRaw : token.amountRaw,\n sourceBalanceRaw: token.balanceRaw,\n sourceChainId: token.chainId,\n sourceTokenAddress: token.address,\n targetTokenAddress: paymentToken.address,\n }));\n}\n\n/**\n * Calculate the required source amount for a payment token to cover a target token.\n *\n * @param paymentToken - Selected payment token.\n * @param token - Target token to cover.\n * @param messenger - Controller messenger.\n * @param transactionId - ID of the transaction.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @returns The source amount or undefined if calculation failed.\n */\nfunction calculateSourceAmount(\n paymentToken: TransactionPaymentToken,\n token: TransactionPayRequiredToken,\n messenger: TransactionPayControllerMessenger,\n transactionId: string,\n isMaxAmount: boolean,\n): TransactionPaySourceAmount | undefined {\n const paymentTokenFiatRate = getTokenFiatRate(\n messenger,\n paymentToken.address,\n paymentToken.chainId,\n );\n\n if (!paymentTokenFiatRate) {\n return undefined;\n }\n\n const hasBalance = new BigNumber(token.balanceRaw).gte(token.amountRaw);\n\n if (token.skipIfBalance && hasBalance) {\n log('Skipping token as sufficient balance', {\n tokenAddress: token.address,\n });\n return undefined;\n }\n\n const { parentTransactionType, strategy } = getStrategyContext(\n transactionId,\n messenger,\n );\n const isAlwaysRequired = isQuoteAlwaysRequired(\n token,\n strategy,\n parentTransactionType,\n );\n\n if (isSameToken(token, paymentToken) && !isAlwaysRequired) {\n log('Skipping token as same as payment token');\n return undefined;\n }\n\n const sourceAmountHumanValue = new BigNumber(token.amountUsd).div(\n paymentTokenFiatRate.usdRate,\n );\n\n const sourceAmountHuman = sourceAmountHumanValue.toString(10);\n\n const sourceAmountRaw = sourceAmountHumanValue\n .shiftedBy(paymentToken.decimals)\n .toFixed(0);\n\n if (token.amountRaw === '0') {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return undefined;\n }\n\n if (isMaxAmount) {\n return {\n sourceAmountHuman: paymentToken.balanceHuman,\n sourceAmountRaw: paymentToken.balanceRaw,\n targetTokenAddress: token.address,\n };\n }\n\n return {\n sourceAmountHuman,\n sourceAmountRaw,\n targetTokenAddress: token.address,\n };\n}\n\n/**\n * Determine if a quote is always required for a token and strategy.\n *\n * @param token - Target token.\n * @param strategy - Payment strategy.\n * @param parentTransactionType - Parent transaction type, if available.\n * @returns True if a quote is always required, false otherwise.\n */\nfunction isQuoteAlwaysRequired(\n token: TransactionPayRequiredToken,\n strategy: TransactionPayStrategy,\n parentTransactionType?: TransactionType,\n): boolean {\n const isHyperliquidDeposit =\n token.chainId === CHAIN_ID_ARBITRUM &&\n token.address.toLowerCase() === ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n return (\n isHyperliquidDeposit &&\n (strategy === TransactionPayStrategy.Relay ||\n (strategy === TransactionPayStrategy.Across &&\n parentTransactionType === TransactionType.perpsDeposit))\n );\n}\n\nfunction getStrategyContext(\n transactionId: string,\n messenger: TransactionPayControllerMessenger,\n): {\n parentTransactionType?: TransactionType;\n strategy: TransactionPayStrategy;\n} {\n const transaction = getTransaction(\n transactionId,\n messenger,\n ) as TransactionMeta;\n\n return {\n parentTransactionType: transaction.type,\n strategy: messenger.call(\n 'TransactionPayController:getStrategy',\n transaction,\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"source-amounts.mjs","sourceRoot":"","sources":["../../src/utils/source-amounts.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n TransactionMeta,\n TransactionType,\n} from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type {\n TransactionPayControllerMessenger,\n TransactionPaymentToken,\n} from '..';\nimport { TransactionPayStrategy } from '..';\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n PERPS_DEPOSIT_TYPES,\n} from '../constants';\nimport { projectLogger } from '../logger';\nimport type {\n TransactionPaySourceAmount,\n TransactionData,\n TransactionPayRequiredToken,\n} from '../types';\nimport { getTokenFiatRate, isSameToken } from './token';\nimport { getTransaction } from './transaction';\n\nconst log = createModuleLogger(projectLogger, 'source-amounts');\n\n/**\n * Update the source amounts for a transaction.\n *\n * @param transactionId - ID of the transaction to update.\n * @param transactionData - Existing transaction data.\n * @param messenger - Controller messenger.\n */\nexport function updateSourceAmounts(\n transactionId: string,\n transactionData: TransactionData | undefined,\n messenger: TransactionPayControllerMessenger,\n): void {\n if (!transactionData) {\n return;\n }\n\n const { isMaxAmount, isPostQuote, paymentToken, tokens } = transactionData;\n\n if (!tokens.length || !paymentToken) {\n return;\n }\n\n // For post-quote flows, source amounts are calculated differently\n // The source is the transaction's required token, not the selected token\n if (isPostQuote) {\n const { isHyperliquidSource, isPolymarketDepositWallet } = transactionData;\n const sourceAmounts = calculatePostQuoteSourceAmounts(\n tokens,\n paymentToken,\n isMaxAmount ?? false,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n );\n log('Updated post-quote source amounts', { transactionId, sourceAmounts });\n transactionData.sourceAmounts = sourceAmounts;\n return;\n }\n\n const sourceAmounts = tokens\n .map((singleToken) =>\n calculateSourceAmount(\n paymentToken,\n singleToken,\n messenger,\n transactionId,\n isMaxAmount ?? false,\n ),\n )\n .filter(Boolean) as TransactionPaySourceAmount[];\n\n log('Updated source amounts', { transactionId, sourceAmounts });\n\n transactionData.sourceAmounts = sourceAmounts;\n}\n\n/**\n * Calculate source amounts for post-quote flows.\n * In this flow, the required tokens ARE the source tokens,\n * and the payment token is the target (destination).\n *\n * @param tokens - Required tokens from the transaction.\n * @param paymentToken - Selected payment/destination token.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param isHyperliquidSource - Whether the source is HyperLiquid (perps withdrawal).\n * @param isPolymarketDepositWallet - Whether the source is a Polymarket deposit wallet.\n * @returns Array of source amounts.\n */\nfunction calculatePostQuoteSourceAmounts(\n tokens: TransactionPayRequiredToken[],\n paymentToken: TransactionPaymentToken,\n isMaxAmount: boolean,\n isHyperliquidSource?: boolean,\n isPolymarketDepositWallet?: boolean,\n): TransactionPaySourceAmount[] {\n return tokens\n .filter((token) => {\n if (token.skipIfBalance) {\n return false;\n }\n\n // Skip zero amounts (unless max amount, where we use balance)\n if (token.amountRaw === '0' && !isMaxAmount) {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return false;\n }\n\n // Skip same token on same chain, unless the source is a synthetic\n // upstream (HyperLiquid HyperCore or Polymarket deposit wallet) that\n // the strategy renormalizes to a different effective source.\n if (\n isSameToken(token, paymentToken) &&\n !isHyperliquidSource &&\n !isPolymarketDepositWallet\n ) {\n log('Skipping token as same as destination token');\n return false;\n }\n\n return true;\n })\n .map((token) => ({\n sourceAmountHuman: isMaxAmount ? token.balanceHuman : token.amountHuman,\n sourceAmountRaw: isMaxAmount ? token.balanceRaw : token.amountRaw,\n sourceBalanceRaw: token.balanceRaw,\n sourceChainId: token.chainId,\n sourceTokenAddress: token.address,\n targetTokenAddress: paymentToken.address,\n }));\n}\n\n/**\n * Calculate the required source amount for a payment token to cover a target token.\n *\n * @param paymentToken - Selected payment token.\n * @param token - Target token to cover.\n * @param messenger - Controller messenger.\n * @param transactionId - ID of the transaction.\n * @param isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @returns The source amount or undefined if calculation failed.\n */\nfunction calculateSourceAmount(\n paymentToken: TransactionPaymentToken,\n token: TransactionPayRequiredToken,\n messenger: TransactionPayControllerMessenger,\n transactionId: string,\n isMaxAmount: boolean,\n): TransactionPaySourceAmount | undefined {\n const paymentTokenFiatRate = getTokenFiatRate(\n messenger,\n paymentToken.address,\n paymentToken.chainId,\n );\n\n if (!paymentTokenFiatRate) {\n return undefined;\n }\n\n const hasBalance = new BigNumber(token.balanceRaw).gte(token.amountRaw);\n\n if (token.skipIfBalance && hasBalance) {\n log('Skipping token as sufficient balance', {\n tokenAddress: token.address,\n });\n return undefined;\n }\n\n const { parentTransactionType, strategy } = getStrategyContext(\n transactionId,\n messenger,\n );\n const isAlwaysRequired = isQuoteAlwaysRequired(\n token,\n strategy,\n parentTransactionType,\n );\n\n if (isSameToken(token, paymentToken) && !isAlwaysRequired) {\n log('Skipping token as same as payment token');\n return undefined;\n }\n\n const sourceAmountHumanValue = new BigNumber(token.amountUsd).div(\n paymentTokenFiatRate.usdRate,\n );\n\n const sourceAmountHuman = sourceAmountHumanValue.toString(10);\n\n const sourceAmountRaw = sourceAmountHumanValue\n .shiftedBy(paymentToken.decimals)\n .toFixed(0);\n\n if (token.amountRaw === '0') {\n log('Skipping token as zero amount', { tokenAddress: token.address });\n return undefined;\n }\n\n if (isMaxAmount) {\n return {\n sourceAmountHuman: paymentToken.balanceHuman,\n sourceAmountRaw: paymentToken.balanceRaw,\n targetTokenAddress: token.address,\n };\n }\n\n return {\n sourceAmountHuman,\n sourceAmountRaw,\n targetTokenAddress: token.address,\n };\n}\n\n/**\n * Determine if a quote is always required for a token and strategy.\n *\n * @param token - Target token.\n * @param strategy - Payment strategy.\n * @param parentTransactionType - Parent transaction type, if available.\n * @returns True if a quote is always required, false otherwise.\n */\nfunction isQuoteAlwaysRequired(\n token: TransactionPayRequiredToken,\n strategy: TransactionPayStrategy,\n parentTransactionType?: TransactionType,\n): boolean {\n const isHyperliquidDeposit =\n token.chainId === CHAIN_ID_ARBITRUM &&\n token.address.toLowerCase() === ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n return (\n isHyperliquidDeposit &&\n (strategy === TransactionPayStrategy.Relay ||\n (strategy === TransactionPayStrategy.Across &&\n parentTransactionType !== undefined &&\n PERPS_DEPOSIT_TYPES.includes(parentTransactionType)))\n );\n}\n\nfunction getStrategyContext(\n transactionId: string,\n messenger: TransactionPayControllerMessenger,\n): {\n parentTransactionType?: TransactionType;\n strategy: TransactionPayStrategy;\n} {\n const transaction = getTransaction(\n transactionId,\n messenger,\n ) as TransactionMeta;\n\n return {\n parentTransactionType: transaction.type,\n strategy: messenger.call(\n 'TransactionPayController:getStrategy',\n transaction,\n ),\n };\n}\n"]}
@@ -139,11 +139,11 @@ function getTokenFiatRate(messenger, tokenAddress, chainId) {
139
139
  const isStablecoin = constants_1.STABLECOINS[chainId]?.includes(tokenAddress.toLowerCase());
140
140
  const usdRate = isStablecoin
141
141
  ? '1'
142
- : new bignumber_js_1.BigNumber(tokenToNativeRate ?? 1)
143
- .multipliedBy(nativeToUsdRate)
142
+ : new bignumber_js_1.BigNumber(String(tokenToNativeRate ?? 1))
143
+ .multipliedBy(String(nativeToUsdRate))
144
144
  .toString(10);
145
- const fiatRate = new bignumber_js_1.BigNumber(tokenToNativeRate ?? 1)
146
- .multipliedBy(nativeToFiatRate)
145
+ const fiatRate = new bignumber_js_1.BigNumber(String(tokenToNativeRate ?? 1))
146
+ .multipliedBy(String(nativeToFiatRate))
147
147
  .toString(10);
148
148
  return { usdRate, fiatRate };
149
149
  }
@@ -1 +1 @@
1
- {"version":3,"file":"token.cjs","sourceRoot":"","sources":["../../src/utils/token.ts"],"names":[],"mappings":";;;AAAA,wDAAoD;AACpD,wDAAwD;AAExD,iEAAkE;AAClE,mEAAuD;AAEvD,2CAA+D;AAC/D,+CAAyC;AAEzC,gDAKsB;AAEtB,uDAA6D;AAE7D;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CACzB,MAAsC,EACtC,MAAsC;IAEtC,OAAO,CACL,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE;QAC7D,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,CAClC,CAAC;AACJ,CAAC;AARD,kCAQC;AAED;;;;;;;;GAQG;AACH,SAAgB,eAAe,CAC7B,SAA4C,EAC5C,OAAY,EACZ,OAAY,EACZ,YAAiB;IAEjB,MAAM,8BAA8B,GAAG,IAAA,0CAA0B,EAAC,SAAS,CAAC,CAAC;IAE7E,IAAI,aAAa,CAAC;IAClB,IAAI,iBAAiB,CAAC;IACtB,IAAI,8BAA8B,EAAE,CAAC;QACnC,MAAM,qBAAqB,GAAG,SAAS,CAAC,IAAI,CAC1C,4CAA4C,CAC7C,CAAC;QAEF,aAAa,GAAG,qBAAqB,EAAE,aAAa,CAAC;QACrD,iBAAiB,GAAG,qBAAqB,EAAE,iBAAiB,CAAC;IAC/D,CAAC;SAAM,CAAC;QACN,aAAa,GAAG,SAAS,CAAC,IAAI,CAC5B,kCAAkC,CACnC,EAAE,aAAa,CAAC;QACjB,iBAAiB,GAAG,SAAS,CAAC,IAAI,CAChC,mCAAmC,CACpC,EAAE,iBAAiB,CAAC;IACvB,CAAC;IAED,MAAM,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAS,CAAC;IACvD,MAAM,sBAAsB,GAAG,IAAA,uCAAoB,EAAC,YAAY,CAAQ,CAAC;IACzE,MAAM,QAAQ,GAAG,sBAAsB,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC;IAEpE,MAAM,UAAU,GACd,aAAa,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC;IAE1E,IAAI,CAAC,QAAQ,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,UAAU,EAAE,CAAC;QAC5B,OAAO,IAAI,wBAAS,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,aAAa,GAAG,iBAAiB,EAAE,CAAC,OAAO,CAAC,CAAC;IAEnD,MAAM,eAAe,GAAG,IAAA,uCAAoB,EAAC,iBAAiB,CAAQ,CAAC;IACvE,MAAM,gBAAgB,GAAG,aAAa,EAAE,CAAC,eAAe,CAAC,EAAE,OAAc,CAAC;IAE1E,OAAO,IAAI,wBAAS,CAAC,gBAAgB,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnE,CAAC;AA/CD,0CA+CC;AAED;;;;;;;GAOG;AACH,SAAgB,YAAY,CAC1B,SAA4C,EAC5C,YAAiB,EACjB,OAAY;IAEZ,MAAM,8BAA8B,GAAG,IAAA,0CAA0B,EAAC,SAAS,CAAC,CAAC;IAE7E,IAAI,SAA6C,CAAC;IAClD,IAAI,8BAA8B,EAAE,CAAC;QACnC,SAAS,GAAG,SAAS,CAAC,IAAI,CACxB,4CAA4C,CAC7C,EAAE,SAAS,CAAC;IACf,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,2BAA2B,CAAC,EAAE,SAAS,CAAC;IACrE,CAAC;IAED,MAAM,sBAAsB,GAAG,YAAY,CAAC,WAAW,EAAS,CAAC;IAEjE,MAAM,QAAQ,GACZ,sBAAsB,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAEnE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;SACpD,IAAI,EAAE;SACN,IAAI,CACH,CAAC,WAAW,EAAE,EAAE,CACd,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,sBAAsB,CAC/D,CAAC;IAEJ,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IACpE,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC1C,CAAC;AA3CD,oCA2CC;AAED;;;;;;;GAOG;AACH,SAAgB,gBAAgB,CAC9B,SAA4C,EAC5C,YAAiB,EACjB,OAAY;IAEZ,MAAM,8BAA8B,GAAG,IAAA,0CAA0B,EAAC,SAAS,CAAC,CAAC;IAE7E,IAAI,UAAU,CAAC;IACf,IAAI,aAAa,CAAC;IAClB,IAAI,8BAA8B,EAAE,CAAC;QACnC,MAAM,qBAAqB,GAAG,SAAS,CAAC,IAAI,CAC1C,4CAA4C,CAC7C,CAAC;QAEF,UAAU,GAAG,qBAAqB,EAAE,UAAU,CAAC;QAC/C,aAAa,GAAG,qBAAqB,EAAE,aAAa,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,+BAA+B,CAAC,EAAE,UAAU,CAAC;QACzE,aAAa,GAAG,SAAS,CAAC,IAAI,CAC5B,iCAAiC,CAClC,EAAE,aAAa,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,sBAAsB,GAAG,IAAA,uCAAoB,EAAC,YAAY,CAAQ,CAAC;IACzE,MAAM,QAAQ,GAAG,sBAAsB,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC;IAEpE,MAAM,iBAAiB,GACrB,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,sBAAsB,CAAC,EAAE,KAAK,CAAC;IAEzD,IAAI,iBAAiB,KAAK,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,EACJ,cAAc,EAAE,gBAAgB,EAChC,iBAAiB,EAAE,eAAe,GACnC,GAAG,aAAa,EAAE,CAAC,MAAM,CAAC,IAAI;QAC7B,cAAc,EAAE,IAAI;QACpB,iBAAiB,EAAE,IAAI;KACxB,CAAC;IAEF,IAAI,gBAAgB,KAAK,IAAI,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;QAC1D,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,YAAY,GAAG,uBAAW,CAAC,OAAO,CAAC,EAAE,QAAQ,CACjD,YAAY,CAAC,WAAW,EAAS,CAClC,CAAC;IAEF,MAAM,OAAO,GAAG,YAAY;QAC1B,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,IAAI,wBAAS,CAAC,iBAAiB,IAAI,CAAC,CAAC;aAClC,YAAY,CAAC,eAAe,CAAC;aAC7B,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEpB,MAAM,QAAQ,GAAG,IAAI,wBAAS,CAAC,iBAAiB,IAAI,CAAC,CAAC;SACnD,YAAY,CAAC,gBAAgB,CAAC;SAC9B,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEhB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC;AAjED,4CAiEC;AAED;;;;;;;GAOG;AACH,SAAgB,mBAAmB,CACjC,QAAyB,EACzB,QAAgB,EAChB,SAAoB;IAOpB,MAAM,QAAQ,GAAG,IAAI,wBAAS,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEjD,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACxB,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,GAAG,EAAE,UAAU,CAAC,YAAY,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5D,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAnBD,kDAmBC;AAED;;;;;;;;GAQG;AACH,SAAgB,wBAAwB,CACtC,UAA2B,EAC3B,QAAgB,EAChB,OAAwB;IAExB,MAAM,IAAI,GAAG,IAAI,wBAAS,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,wBAAS,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9D,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,GAAG,GAAG,WAAW;SACpB,SAAS,CAAC,QAAQ,CAAC;SACnB,aAAa,CAAC,CAAC,EAAE,wBAAS,CAAC,UAAU,CAAC;SACtC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd,OAAO,IAAI,wBAAS,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AArBD,4DAqBC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,OAAY;IACzC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,4CAA4C,CAAC;QACtD;YACE,OAAO,gCAAoB,CAAC;IAChC,CAAC;AACH,CAAC;AAPD,wCAOC;AAED;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,mBAAmB,CACvC,SAA4C,EAC5C,OAAY,EACZ,OAAY,EACZ,YAAiB;IAEjB,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CACpC,gDAAgD,EAChD,OAAO,CACR,CAAC;IAEF,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,IAAI,CACjC,wCAAwC,EACxC,eAAe,CAChB,CAAC;IAEF,MAAM,cAAc,GAAG,IAAI,wBAAY,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,QAAQ,GACZ,YAAY,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAEvE,6EAA6E;IAC7E,0EAA0E;IAC1E,gBAAgB;IAChB,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACpE,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,oBAAQ,CAAC,YAAY,EAAE,4BAAQ,EAAE,cAAc,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3E,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC;AA/BD,kDA+BC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,kBAAkB,CAChC,OAAY,EACZ,YAAiB,EACjB,cAAuB;IAEvB,MAAM,cAAc,GAAG,MAAM,CAAC,IAAA,mBAAW,EAAC,OAAO,CAAC,CAAC,CAAC;IACpD,MAAM,QAAQ,GACZ,YAAY,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAEvE,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,cAAc,IAAI,qCAAyB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAE5E,OAAO,IAAA,uBAAe,EACpB,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,MAAM,CAAC,QAAQ,CAAC,CACjB,CAAC;IACJ,CAAC;IAED,OAAO,IAAA,uBAAe,EAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;AAC1E,CAAC;AArBD,gDAqBC;AAED,SAAS,SAAS,CAChB,OAAY,EACZ,SAA4C;IAE5C,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CACpC,gDAAgD,EAChD,OAAO,CACR,CAAC;QAEF,MAAM,oBAAoB,GAAG,SAAS,CAAC,IAAI,CACzC,wCAAwC,EACxC,eAAe,CAChB,CAAC;QAEF,OAAO,oBAAoB,CAAC,aAAa,CAAC,MAAM,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,IAAY,kBAGX;AAHD,WAAY,kBAAkB;IAC5B,qCAAe,CAAA;IACf,2CAAqB,CAAA;AACvB,CAAC,EAHW,kBAAkB,kCAAlB,kBAAkB,QAG7B;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,qBAAqB,CACnC,YAAiB,EACjB,OAAY,EACZ,MAA2B;IAE3B,IAAI,OAAO,KAAK,4BAAgB,EAAE,CAAC;QACjC,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,WAAW,EAAS,CAAC;IACxE,MAAM,sBAAsB,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;IAE1D,IACE,MAAM,KAAK,kBAAkB,CAAC,KAAK;QACnC,sBAAsB,KAAK,kBAAkB,EAC7C,CAAC;QACD,OAAO,gCAAoB,CAAC;IAC9B,CAAC;IAED,IACE,MAAM,KAAK,kBAAkB,CAAC,QAAQ;QACtC,sBAAsB,KAAK,gCAAoB,CAAC,WAAW,EAAE,EAC7D,CAAC;QACD,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AA3BD,sDA2BC","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { TokensControllerState } from '@metamask/assets-controllers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { CaipAssetType, Hex } from '@metamask/utils';\nimport { hexToBigInt, toCaipAssetType } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n CHAIN_ID_POLYGON,\n NATIVE_TOKEN_ADDRESS,\n SLIP44_COIN_TYPE_BY_CHAIN,\n STABLECOINS,\n} from '../constants';\nimport type { FiatRates, TransactionPayControllerMessenger } from '../types';\nimport { getAssetsUnifyStateFeature } from './feature-flags';\n\n/**\n * Check if two tokens are the same (same address and chain).\n *\n * @param token1 - First token identifier.\n * @param token1.address - Token address.\n * @param token1.chainId - Token chain ID.\n * @param token2 - Second token identifier.\n * @param token2.address - Token address.\n * @param token2.chainId - Token chain ID.\n * @returns True if tokens are the same, false otherwise.\n */\nexport function isSameToken(\n token1: { address: Hex; chainId: Hex },\n token2: { address: Hex; chainId: Hex },\n): boolean {\n return (\n token1.address.toLowerCase() === token2.address.toLowerCase() &&\n token1.chainId === token2.chainId\n );\n}\n\n/**\n * Get the token balance for a specific account and token.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Id of the chain.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport function getTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): string {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let tokenBalances;\n let accountsByChainId;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n tokenBalances = assetsControllerState?.tokenBalances;\n accountsByChainId = assetsControllerState?.accountsByChainId;\n } else {\n tokenBalances = messenger.call(\n 'TokenBalancesController:getState',\n )?.tokenBalances;\n accountsByChainId = messenger.call(\n 'AccountTrackerController:getState',\n )?.accountsByChainId;\n }\n\n const normalizedAccount = account.toLowerCase() as Hex;\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const balanceHex =\n tokenBalances?.[normalizedAccount]?.[chainId]?.[normalizedTokenAddress];\n\n if (!isNative && balanceHex === undefined) {\n return '0';\n }\n\n if (!isNative && balanceHex) {\n return new BigNumber(balanceHex, 16).toString(10);\n }\n\n const chainAccounts = accountsByChainId?.[chainId];\n\n const checksumAccount = toChecksumHexAddress(normalizedAccount) as Hex;\n const nativeBalanceHex = chainAccounts?.[checksumAccount]?.balance as Hex;\n\n return new BigNumber(nativeBalanceHex ?? '0x0', 16).toString(10);\n}\n\n/**\n * Get the token decimals for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns The token decimals or undefined if the token is not found.\n */\nexport function getTokenInfo(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): { decimals: number; symbol: string } | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let allTokens: TokensControllerState['allTokens'];\n if (assetsUnifyStateFeatureEnabled) {\n allTokens = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n )?.allTokens;\n } else {\n allTokens = messenger.call('TokensController:getState')?.allTokens;\n }\n\n const normalizedTokenAddress = tokenAddress.toLowerCase() as Hex;\n\n const isNative =\n normalizedTokenAddress === getNativeToken(chainId).toLowerCase();\n\n const token = Object.values(allTokens?.[chainId] ?? {})\n .flat()\n .find(\n (singleToken) =>\n singleToken.address.toLowerCase() === normalizedTokenAddress,\n );\n\n if (!token && !isNative) {\n return undefined;\n }\n\n if (token && !isNative) {\n return { decimals: Number(token.decimals), symbol: token.symbol };\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n return { decimals: 18, symbol: ticker };\n}\n\n/**\n * Calculate fiat rates for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns An object containing the USD and fiat rates, or undefined if rates are not available.\n */\nexport function getTokenFiatRate(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): FiatRates | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let marketData;\n let currencyRates;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n marketData = assetsControllerState?.marketData;\n currencyRates = assetsControllerState?.currencyRates;\n } else {\n marketData = messenger.call('TokenRatesController:getState')?.marketData;\n currencyRates = messenger.call(\n 'CurrencyRateController:getState',\n )?.currencyRates;\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const tokenToNativeRate =\n marketData?.[chainId]?.[normalizedTokenAddress]?.price;\n\n if (tokenToNativeRate === undefined && !isNative) {\n return undefined;\n }\n\n const {\n conversionRate: nativeToFiatRate,\n usdConversionRate: nativeToUsdRate,\n } = currencyRates?.[ticker] ?? {\n conversionRate: null,\n usdConversionRate: null,\n };\n\n if (nativeToFiatRate === null || nativeToUsdRate === null) {\n return undefined;\n }\n const isStablecoin = STABLECOINS[chainId]?.includes(\n tokenAddress.toLowerCase() as Hex,\n );\n\n const usdRate = isStablecoin\n ? '1'\n : new BigNumber(tokenToNativeRate ?? 1)\n .multipliedBy(nativeToUsdRate)\n .toString(10);\n\n const fiatRate = new BigNumber(tokenToNativeRate ?? 1)\n .multipliedBy(nativeToFiatRate)\n .toString(10);\n\n return { usdRate, fiatRate };\n}\n\n/**\n * Calculate the human-readable, raw, USD, and fiat representations of a token amount.\n *\n * @param rawInput - Raw token amount (decimal string, hex, or BigNumber).\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing the amount in raw, human-readable, USD, and fiat formats.\n */\nexport function computeTokenAmounts(\n rawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n raw: string;\n human: string;\n usd: string;\n fiat: string;\n} {\n const rawValue = new BigNumber(rawInput);\n const humanValue = rawValue.shiftedBy(-decimals);\n\n return {\n raw: rawValue.toFixed(0),\n human: humanValue.toString(10),\n usd: humanValue.multipliedBy(fiatRates.usdRate).toString(10),\n fiat: humanValue.multipliedBy(fiatRates.fiatRate).toString(10),\n };\n}\n\n/**\n * Compute a raw token amount from a fiat (USD) amount.\n * This is the inverse of `computeTokenAmounts` — it goes from USD to raw.\n *\n * @param fiatAmount - Amount in fiat/USD.\n * @param decimals - Token decimals.\n * @param usdRate - USD rate for the token (price per one unit of the token).\n * @returns Raw token amount string, or undefined if the conversion produces an invalid result.\n */\nexport function computeRawFromFiatAmount(\n fiatAmount: BigNumber.Value,\n decimals: number,\n usdRate: BigNumber.Value,\n): string | undefined {\n const rate = new BigNumber(usdRate);\n if (!rate.isFinite() || !rate.gt(0)) {\n return undefined;\n }\n\n const humanAmount = new BigNumber(fiatAmount).dividedBy(rate);\n if (!humanAmount.isFinite() || !humanAmount.gt(0)) {\n return undefined;\n }\n\n const raw = humanAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n return new BigNumber(raw).gt(0) ? raw : undefined;\n}\n\n/**\n * Get the native token address for a given chain ID.\n *\n * @param chainId - Chain ID.\n * @returns - Native token address for the given chain ID.\n */\nexport function getNativeToken(chainId: Hex): Hex {\n switch (chainId) {\n case '0x89':\n return '0x0000000000000000000000000000000000001010';\n default:\n return NATIVE_TOKEN_ADDRESS;\n }\n}\n\n/**\n * Get the live on-chain token balance via an RPC `eth_call` to the ERC-20\n * `balanceOf` function, or `eth_getBalance` for native tokens.\n *\n * Unlike {@link getTokenBalance}, this bypasses the cached state in\n * `TokenBalancesController` and reads directly from the chain.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Chain ID.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport async function getLiveTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): Promise<string> {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const { provider } = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n const ethersProvider = new Web3Provider(provider);\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n // Use `pending` blockTag to bypass the RPC block-cache middleware so callers\n // always observe the latest balance instead of a value pinned to the last\n // polled block.\n if (isNative) {\n const balance = await ethersProvider.getBalance(account, 'pending');\n return balance.toString();\n }\n\n const contract = new Contract(tokenAddress, abiERC20, ethersProvider);\n const balance = await contract.balanceOf(account, { blockTag: 'pending' });\n return balance.toString();\n}\n\n/**\n * Build a CAIP-19 asset type identifier for an EVM token.\n *\n * For native tokens the SLIP-44 coin type is resolved automatically from\n * a built-in chain→coin-type map, falling back to 60 (ETH). Callers can\n * override via the optional third parameter.\n *\n * @param chainId - Hex chain ID (e.g. `0x1`).\n * @param tokenAddress - Token contract address, or the native token address.\n * @param slip44CoinType - Optional SLIP-44 coin type override for native tokens.\n * @returns CAIP-19 asset type string.\n */\nexport function buildCaipAssetType(\n chainId: Hex,\n tokenAddress: Hex,\n slip44CoinType?: number,\n): CaipAssetType {\n const chainReference = String(hexToBigInt(chainId));\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n if (isNative) {\n const coinType = slip44CoinType ?? SLIP44_COIN_TYPE_BY_CHAIN[chainId] ?? 60;\n\n return toCaipAssetType(\n 'eip155',\n chainReference,\n 'slip44',\n String(coinType),\n );\n }\n\n return toCaipAssetType('eip155', chainReference, 'erc20', tokenAddress);\n}\n\nfunction getTicker(\n chainId: Hex,\n messenger: TransactionPayControllerMessenger,\n): string | undefined {\n try {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const networkConfiguration = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n return networkConfiguration.configuration.ticker;\n } catch {\n return undefined;\n }\n}\n\nexport enum TokenAddressTarget {\n Relay = 'relay',\n MetaMask = 'metamask',\n}\n\n/**\n * Normalize token address formats between MetaMask and Relay for Polygon native\n * token handling.\n *\n * MetaMask uses Polygon's native token contract-like address (`0x...1010`),\n * while Relay expects the zero address for native tokens.\n *\n * @param tokenAddress - Token address to normalize.\n * @param chainId - Chain ID for the token.\n * @param target - Optional target system format.\n * @returns Normalized token address for the target system, or the original\n * address if no target is provided.\n */\nexport function normalizeTokenAddress(\n tokenAddress: Hex,\n chainId: Hex,\n target?: TokenAddressTarget,\n): Hex {\n if (chainId !== CHAIN_ID_POLYGON) {\n return tokenAddress;\n }\n\n const nativeTokenAddress = getNativeToken(chainId).toLowerCase() as Hex;\n const normalizedTokenAddress = tokenAddress.toLowerCase();\n\n if (\n target === TokenAddressTarget.Relay &&\n normalizedTokenAddress === nativeTokenAddress\n ) {\n return NATIVE_TOKEN_ADDRESS;\n }\n\n if (\n target === TokenAddressTarget.MetaMask &&\n normalizedTokenAddress === NATIVE_TOKEN_ADDRESS.toLowerCase()\n ) {\n return nativeTokenAddress;\n }\n\n return tokenAddress;\n}\n"]}
1
+ {"version":3,"file":"token.cjs","sourceRoot":"","sources":["../../src/utils/token.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { TokensControllerState } from '@metamask/assets-controllers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { CaipAssetType, Hex } from '@metamask/utils';\nimport { hexToBigInt, toCaipAssetType } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n CHAIN_ID_POLYGON,\n NATIVE_TOKEN_ADDRESS,\n SLIP44_COIN_TYPE_BY_CHAIN,\n STABLECOINS,\n} from '../constants';\nimport type { FiatRates, TransactionPayControllerMessenger } from '../types';\nimport { getAssetsUnifyStateFeature } from './feature-flags';\n\n/**\n * Check if two tokens are the same (same address and chain).\n *\n * @param token1 - First token identifier.\n * @param token1.address - Token address.\n * @param token1.chainId - Token chain ID.\n * @param token2 - Second token identifier.\n * @param token2.address - Token address.\n * @param token2.chainId - Token chain ID.\n * @returns True if tokens are the same, false otherwise.\n */\nexport function isSameToken(\n token1: { address: Hex; chainId: Hex },\n token2: { address: Hex; chainId: Hex },\n): boolean {\n return (\n token1.address.toLowerCase() === token2.address.toLowerCase() &&\n token1.chainId === token2.chainId\n );\n}\n\n/**\n * Get the token balance for a specific account and token.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Id of the chain.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport function getTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): string {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let tokenBalances;\n let accountsByChainId;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n tokenBalances = assetsControllerState?.tokenBalances;\n accountsByChainId = assetsControllerState?.accountsByChainId;\n } else {\n tokenBalances = messenger.call(\n 'TokenBalancesController:getState',\n )?.tokenBalances;\n accountsByChainId = messenger.call(\n 'AccountTrackerController:getState',\n )?.accountsByChainId;\n }\n\n const normalizedAccount = account.toLowerCase() as Hex;\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const balanceHex =\n tokenBalances?.[normalizedAccount]?.[chainId]?.[normalizedTokenAddress];\n\n if (!isNative && balanceHex === undefined) {\n return '0';\n }\n\n if (!isNative && balanceHex) {\n return new BigNumber(balanceHex, 16).toString(10);\n }\n\n const chainAccounts = accountsByChainId?.[chainId];\n\n const checksumAccount = toChecksumHexAddress(normalizedAccount) as Hex;\n const nativeBalanceHex = chainAccounts?.[checksumAccount]?.balance as Hex;\n\n return new BigNumber(nativeBalanceHex ?? '0x0', 16).toString(10);\n}\n\n/**\n * Get the token decimals for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns The token decimals or undefined if the token is not found.\n */\nexport function getTokenInfo(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): { decimals: number; symbol: string } | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let allTokens: TokensControllerState['allTokens'];\n if (assetsUnifyStateFeatureEnabled) {\n allTokens = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n )?.allTokens;\n } else {\n allTokens = messenger.call('TokensController:getState')?.allTokens;\n }\n\n const normalizedTokenAddress = tokenAddress.toLowerCase() as Hex;\n\n const isNative =\n normalizedTokenAddress === getNativeToken(chainId).toLowerCase();\n\n const token = Object.values(allTokens?.[chainId] ?? {})\n .flat()\n .find(\n (singleToken) =>\n singleToken.address.toLowerCase() === normalizedTokenAddress,\n );\n\n if (!token && !isNative) {\n return undefined;\n }\n\n if (token && !isNative) {\n return { decimals: Number(token.decimals), symbol: token.symbol };\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n return { decimals: 18, symbol: ticker };\n}\n\n/**\n * Calculate fiat rates for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns An object containing the USD and fiat rates, or undefined if rates are not available.\n */\nexport function getTokenFiatRate(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): FiatRates | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let marketData;\n let currencyRates;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n marketData = assetsControllerState?.marketData;\n currencyRates = assetsControllerState?.currencyRates;\n } else {\n marketData = messenger.call('TokenRatesController:getState')?.marketData;\n currencyRates = messenger.call(\n 'CurrencyRateController:getState',\n )?.currencyRates;\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const tokenToNativeRate =\n marketData?.[chainId]?.[normalizedTokenAddress]?.price;\n\n if (tokenToNativeRate === undefined && !isNative) {\n return undefined;\n }\n\n const {\n conversionRate: nativeToFiatRate,\n usdConversionRate: nativeToUsdRate,\n } = currencyRates?.[ticker] ?? {\n conversionRate: null,\n usdConversionRate: null,\n };\n\n if (nativeToFiatRate === null || nativeToUsdRate === null) {\n return undefined;\n }\n const isStablecoin = STABLECOINS[chainId]?.includes(\n tokenAddress.toLowerCase() as Hex,\n );\n\n const usdRate = isStablecoin\n ? '1'\n : new BigNumber(String(tokenToNativeRate ?? 1))\n .multipliedBy(String(nativeToUsdRate))\n .toString(10);\n\n const fiatRate = new BigNumber(String(tokenToNativeRate ?? 1))\n .multipliedBy(String(nativeToFiatRate))\n .toString(10);\n\n return { usdRate, fiatRate };\n}\n\n/**\n * Calculate the human-readable, raw, USD, and fiat representations of a token amount.\n *\n * @param rawInput - Raw token amount (decimal string, hex, or BigNumber).\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing the amount in raw, human-readable, USD, and fiat formats.\n */\nexport function computeTokenAmounts(\n rawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n raw: string;\n human: string;\n usd: string;\n fiat: string;\n} {\n const rawValue = new BigNumber(rawInput);\n const humanValue = rawValue.shiftedBy(-decimals);\n\n return {\n raw: rawValue.toFixed(0),\n human: humanValue.toString(10),\n usd: humanValue.multipliedBy(fiatRates.usdRate).toString(10),\n fiat: humanValue.multipliedBy(fiatRates.fiatRate).toString(10),\n };\n}\n\n/**\n * Compute a raw token amount from a fiat (USD) amount.\n * This is the inverse of `computeTokenAmounts` — it goes from USD to raw.\n *\n * @param fiatAmount - Amount in fiat/USD.\n * @param decimals - Token decimals.\n * @param usdRate - USD rate for the token (price per one unit of the token).\n * @returns Raw token amount string, or undefined if the conversion produces an invalid result.\n */\nexport function computeRawFromFiatAmount(\n fiatAmount: BigNumber.Value,\n decimals: number,\n usdRate: BigNumber.Value,\n): string | undefined {\n const rate = new BigNumber(usdRate);\n if (!rate.isFinite() || !rate.gt(0)) {\n return undefined;\n }\n\n const humanAmount = new BigNumber(fiatAmount).dividedBy(rate);\n if (!humanAmount.isFinite() || !humanAmount.gt(0)) {\n return undefined;\n }\n\n const raw = humanAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n return new BigNumber(raw).gt(0) ? raw : undefined;\n}\n\n/**\n * Get the native token address for a given chain ID.\n *\n * @param chainId - Chain ID.\n * @returns - Native token address for the given chain ID.\n */\nexport function getNativeToken(chainId: Hex): Hex {\n switch (chainId) {\n case '0x89':\n return '0x0000000000000000000000000000000000001010';\n default:\n return NATIVE_TOKEN_ADDRESS;\n }\n}\n\n/**\n * Get the live on-chain token balance via an RPC `eth_call` to the ERC-20\n * `balanceOf` function, or `eth_getBalance` for native tokens.\n *\n * Unlike {@link getTokenBalance}, this bypasses the cached state in\n * `TokenBalancesController` and reads directly from the chain.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Chain ID.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport async function getLiveTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): Promise<string> {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const { provider } = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n const ethersProvider = new Web3Provider(provider);\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n // Use `pending` blockTag to bypass the RPC block-cache middleware so callers\n // always observe the latest balance instead of a value pinned to the last\n // polled block.\n if (isNative) {\n const balance = await ethersProvider.getBalance(account, 'pending');\n return balance.toString();\n }\n\n const contract = new Contract(tokenAddress, abiERC20, ethersProvider);\n const balance = await contract.balanceOf(account, { blockTag: 'pending' });\n return balance.toString();\n}\n\n/**\n * Build a CAIP-19 asset type identifier for an EVM token.\n *\n * For native tokens the SLIP-44 coin type is resolved automatically from\n * a built-in chain→coin-type map, falling back to 60 (ETH). Callers can\n * override via the optional third parameter.\n *\n * @param chainId - Hex chain ID (e.g. `0x1`).\n * @param tokenAddress - Token contract address, or the native token address.\n * @param slip44CoinType - Optional SLIP-44 coin type override for native tokens.\n * @returns CAIP-19 asset type string.\n */\nexport function buildCaipAssetType(\n chainId: Hex,\n tokenAddress: Hex,\n slip44CoinType?: number,\n): CaipAssetType {\n const chainReference = String(hexToBigInt(chainId));\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n if (isNative) {\n const coinType = slip44CoinType ?? SLIP44_COIN_TYPE_BY_CHAIN[chainId] ?? 60;\n\n return toCaipAssetType(\n 'eip155',\n chainReference,\n 'slip44',\n String(coinType),\n );\n }\n\n return toCaipAssetType('eip155', chainReference, 'erc20', tokenAddress);\n}\n\nfunction getTicker(\n chainId: Hex,\n messenger: TransactionPayControllerMessenger,\n): string | undefined {\n try {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const networkConfiguration = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n return networkConfiguration.configuration.ticker;\n } catch {\n return undefined;\n }\n}\n\nexport enum TokenAddressTarget {\n Relay = 'relay',\n MetaMask = 'metamask',\n}\n\n/**\n * Normalize token address formats between MetaMask and Relay for Polygon native\n * token handling.\n *\n * MetaMask uses Polygon's native token contract-like address (`0x...1010`),\n * while Relay expects the zero address for native tokens.\n *\n * @param tokenAddress - Token address to normalize.\n * @param chainId - Chain ID for the token.\n * @param target - Optional target system format.\n * @returns Normalized token address for the target system, or the original\n * address if no target is provided.\n */\nexport function normalizeTokenAddress(\n tokenAddress: Hex,\n chainId: Hex,\n target?: TokenAddressTarget,\n): Hex {\n if (chainId !== CHAIN_ID_POLYGON) {\n return tokenAddress;\n }\n\n const nativeTokenAddress = getNativeToken(chainId).toLowerCase() as Hex;\n const normalizedTokenAddress = tokenAddress.toLowerCase();\n\n if (\n target === TokenAddressTarget.Relay &&\n normalizedTokenAddress === nativeTokenAddress\n ) {\n return NATIVE_TOKEN_ADDRESS;\n }\n\n if (\n target === TokenAddressTarget.MetaMask &&\n normalizedTokenAddress === NATIVE_TOKEN_ADDRESS.toLowerCase()\n ) {\n return nativeTokenAddress;\n }\n\n return tokenAddress;\n}\n"]}
@@ -133,11 +133,11 @@ export function getTokenFiatRate(messenger, tokenAddress, chainId) {
133
133
  const isStablecoin = STABLECOINS[chainId]?.includes(tokenAddress.toLowerCase());
134
134
  const usdRate = isStablecoin
135
135
  ? '1'
136
- : new BigNumber(tokenToNativeRate ?? 1)
137
- .multipliedBy(nativeToUsdRate)
136
+ : new BigNumber(String(tokenToNativeRate ?? 1))
137
+ .multipliedBy(String(nativeToUsdRate))
138
138
  .toString(10);
139
- const fiatRate = new BigNumber(tokenToNativeRate ?? 1)
140
- .multipliedBy(nativeToFiatRate)
139
+ const fiatRate = new BigNumber(String(tokenToNativeRate ?? 1))
140
+ .multipliedBy(String(nativeToFiatRate))
141
141
  .toString(10);
142
142
  return { usdRate, fiatRate };
143
143
  }
@@ -1 +1 @@
1
- {"version":3,"file":"token.mjs","sourceRoot":"","sources":["../../src/utils/token.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { TokensControllerState } from '@metamask/assets-controllers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { CaipAssetType, Hex } from '@metamask/utils';\nimport { hexToBigInt, toCaipAssetType } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n CHAIN_ID_POLYGON,\n NATIVE_TOKEN_ADDRESS,\n SLIP44_COIN_TYPE_BY_CHAIN,\n STABLECOINS,\n} from '../constants';\nimport type { FiatRates, TransactionPayControllerMessenger } from '../types';\nimport { getAssetsUnifyStateFeature } from './feature-flags';\n\n/**\n * Check if two tokens are the same (same address and chain).\n *\n * @param token1 - First token identifier.\n * @param token1.address - Token address.\n * @param token1.chainId - Token chain ID.\n * @param token2 - Second token identifier.\n * @param token2.address - Token address.\n * @param token2.chainId - Token chain ID.\n * @returns True if tokens are the same, false otherwise.\n */\nexport function isSameToken(\n token1: { address: Hex; chainId: Hex },\n token2: { address: Hex; chainId: Hex },\n): boolean {\n return (\n token1.address.toLowerCase() === token2.address.toLowerCase() &&\n token1.chainId === token2.chainId\n );\n}\n\n/**\n * Get the token balance for a specific account and token.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Id of the chain.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport function getTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): string {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let tokenBalances;\n let accountsByChainId;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n tokenBalances = assetsControllerState?.tokenBalances;\n accountsByChainId = assetsControllerState?.accountsByChainId;\n } else {\n tokenBalances = messenger.call(\n 'TokenBalancesController:getState',\n )?.tokenBalances;\n accountsByChainId = messenger.call(\n 'AccountTrackerController:getState',\n )?.accountsByChainId;\n }\n\n const normalizedAccount = account.toLowerCase() as Hex;\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const balanceHex =\n tokenBalances?.[normalizedAccount]?.[chainId]?.[normalizedTokenAddress];\n\n if (!isNative && balanceHex === undefined) {\n return '0';\n }\n\n if (!isNative && balanceHex) {\n return new BigNumber(balanceHex, 16).toString(10);\n }\n\n const chainAccounts = accountsByChainId?.[chainId];\n\n const checksumAccount = toChecksumHexAddress(normalizedAccount) as Hex;\n const nativeBalanceHex = chainAccounts?.[checksumAccount]?.balance as Hex;\n\n return new BigNumber(nativeBalanceHex ?? '0x0', 16).toString(10);\n}\n\n/**\n * Get the token decimals for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns The token decimals or undefined if the token is not found.\n */\nexport function getTokenInfo(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): { decimals: number; symbol: string } | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let allTokens: TokensControllerState['allTokens'];\n if (assetsUnifyStateFeatureEnabled) {\n allTokens = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n )?.allTokens;\n } else {\n allTokens = messenger.call('TokensController:getState')?.allTokens;\n }\n\n const normalizedTokenAddress = tokenAddress.toLowerCase() as Hex;\n\n const isNative =\n normalizedTokenAddress === getNativeToken(chainId).toLowerCase();\n\n const token = Object.values(allTokens?.[chainId] ?? {})\n .flat()\n .find(\n (singleToken) =>\n singleToken.address.toLowerCase() === normalizedTokenAddress,\n );\n\n if (!token && !isNative) {\n return undefined;\n }\n\n if (token && !isNative) {\n return { decimals: Number(token.decimals), symbol: token.symbol };\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n return { decimals: 18, symbol: ticker };\n}\n\n/**\n * Calculate fiat rates for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns An object containing the USD and fiat rates, or undefined if rates are not available.\n */\nexport function getTokenFiatRate(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): FiatRates | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let marketData;\n let currencyRates;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n marketData = assetsControllerState?.marketData;\n currencyRates = assetsControllerState?.currencyRates;\n } else {\n marketData = messenger.call('TokenRatesController:getState')?.marketData;\n currencyRates = messenger.call(\n 'CurrencyRateController:getState',\n )?.currencyRates;\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const tokenToNativeRate =\n marketData?.[chainId]?.[normalizedTokenAddress]?.price;\n\n if (tokenToNativeRate === undefined && !isNative) {\n return undefined;\n }\n\n const {\n conversionRate: nativeToFiatRate,\n usdConversionRate: nativeToUsdRate,\n } = currencyRates?.[ticker] ?? {\n conversionRate: null,\n usdConversionRate: null,\n };\n\n if (nativeToFiatRate === null || nativeToUsdRate === null) {\n return undefined;\n }\n const isStablecoin = STABLECOINS[chainId]?.includes(\n tokenAddress.toLowerCase() as Hex,\n );\n\n const usdRate = isStablecoin\n ? '1'\n : new BigNumber(tokenToNativeRate ?? 1)\n .multipliedBy(nativeToUsdRate)\n .toString(10);\n\n const fiatRate = new BigNumber(tokenToNativeRate ?? 1)\n .multipliedBy(nativeToFiatRate)\n .toString(10);\n\n return { usdRate, fiatRate };\n}\n\n/**\n * Calculate the human-readable, raw, USD, and fiat representations of a token amount.\n *\n * @param rawInput - Raw token amount (decimal string, hex, or BigNumber).\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing the amount in raw, human-readable, USD, and fiat formats.\n */\nexport function computeTokenAmounts(\n rawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n raw: string;\n human: string;\n usd: string;\n fiat: string;\n} {\n const rawValue = new BigNumber(rawInput);\n const humanValue = rawValue.shiftedBy(-decimals);\n\n return {\n raw: rawValue.toFixed(0),\n human: humanValue.toString(10),\n usd: humanValue.multipliedBy(fiatRates.usdRate).toString(10),\n fiat: humanValue.multipliedBy(fiatRates.fiatRate).toString(10),\n };\n}\n\n/**\n * Compute a raw token amount from a fiat (USD) amount.\n * This is the inverse of `computeTokenAmounts` — it goes from USD to raw.\n *\n * @param fiatAmount - Amount in fiat/USD.\n * @param decimals - Token decimals.\n * @param usdRate - USD rate for the token (price per one unit of the token).\n * @returns Raw token amount string, or undefined if the conversion produces an invalid result.\n */\nexport function computeRawFromFiatAmount(\n fiatAmount: BigNumber.Value,\n decimals: number,\n usdRate: BigNumber.Value,\n): string | undefined {\n const rate = new BigNumber(usdRate);\n if (!rate.isFinite() || !rate.gt(0)) {\n return undefined;\n }\n\n const humanAmount = new BigNumber(fiatAmount).dividedBy(rate);\n if (!humanAmount.isFinite() || !humanAmount.gt(0)) {\n return undefined;\n }\n\n const raw = humanAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n return new BigNumber(raw).gt(0) ? raw : undefined;\n}\n\n/**\n * Get the native token address for a given chain ID.\n *\n * @param chainId - Chain ID.\n * @returns - Native token address for the given chain ID.\n */\nexport function getNativeToken(chainId: Hex): Hex {\n switch (chainId) {\n case '0x89':\n return '0x0000000000000000000000000000000000001010';\n default:\n return NATIVE_TOKEN_ADDRESS;\n }\n}\n\n/**\n * Get the live on-chain token balance via an RPC `eth_call` to the ERC-20\n * `balanceOf` function, or `eth_getBalance` for native tokens.\n *\n * Unlike {@link getTokenBalance}, this bypasses the cached state in\n * `TokenBalancesController` and reads directly from the chain.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Chain ID.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport async function getLiveTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): Promise<string> {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const { provider } = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n const ethersProvider = new Web3Provider(provider);\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n // Use `pending` blockTag to bypass the RPC block-cache middleware so callers\n // always observe the latest balance instead of a value pinned to the last\n // polled block.\n if (isNative) {\n const balance = await ethersProvider.getBalance(account, 'pending');\n return balance.toString();\n }\n\n const contract = new Contract(tokenAddress, abiERC20, ethersProvider);\n const balance = await contract.balanceOf(account, { blockTag: 'pending' });\n return balance.toString();\n}\n\n/**\n * Build a CAIP-19 asset type identifier for an EVM token.\n *\n * For native tokens the SLIP-44 coin type is resolved automatically from\n * a built-in chain→coin-type map, falling back to 60 (ETH). Callers can\n * override via the optional third parameter.\n *\n * @param chainId - Hex chain ID (e.g. `0x1`).\n * @param tokenAddress - Token contract address, or the native token address.\n * @param slip44CoinType - Optional SLIP-44 coin type override for native tokens.\n * @returns CAIP-19 asset type string.\n */\nexport function buildCaipAssetType(\n chainId: Hex,\n tokenAddress: Hex,\n slip44CoinType?: number,\n): CaipAssetType {\n const chainReference = String(hexToBigInt(chainId));\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n if (isNative) {\n const coinType = slip44CoinType ?? SLIP44_COIN_TYPE_BY_CHAIN[chainId] ?? 60;\n\n return toCaipAssetType(\n 'eip155',\n chainReference,\n 'slip44',\n String(coinType),\n );\n }\n\n return toCaipAssetType('eip155', chainReference, 'erc20', tokenAddress);\n}\n\nfunction getTicker(\n chainId: Hex,\n messenger: TransactionPayControllerMessenger,\n): string | undefined {\n try {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const networkConfiguration = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n return networkConfiguration.configuration.ticker;\n } catch {\n return undefined;\n }\n}\n\nexport enum TokenAddressTarget {\n Relay = 'relay',\n MetaMask = 'metamask',\n}\n\n/**\n * Normalize token address formats between MetaMask and Relay for Polygon native\n * token handling.\n *\n * MetaMask uses Polygon's native token contract-like address (`0x...1010`),\n * while Relay expects the zero address for native tokens.\n *\n * @param tokenAddress - Token address to normalize.\n * @param chainId - Chain ID for the token.\n * @param target - Optional target system format.\n * @returns Normalized token address for the target system, or the original\n * address if no target is provided.\n */\nexport function normalizeTokenAddress(\n tokenAddress: Hex,\n chainId: Hex,\n target?: TokenAddressTarget,\n): Hex {\n if (chainId !== CHAIN_ID_POLYGON) {\n return tokenAddress;\n }\n\n const nativeTokenAddress = getNativeToken(chainId).toLowerCase() as Hex;\n const normalizedTokenAddress = tokenAddress.toLowerCase();\n\n if (\n target === TokenAddressTarget.Relay &&\n normalizedTokenAddress === nativeTokenAddress\n ) {\n return NATIVE_TOKEN_ADDRESS;\n }\n\n if (\n target === TokenAddressTarget.MetaMask &&\n normalizedTokenAddress === NATIVE_TOKEN_ADDRESS.toLowerCase()\n ) {\n return nativeTokenAddress;\n }\n\n return tokenAddress;\n}\n"]}
1
+ {"version":3,"file":"token.mjs","sourceRoot":"","sources":["../../src/utils/token.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { TokensControllerState } from '@metamask/assets-controllers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport type { CaipAssetType, Hex } from '@metamask/utils';\nimport { hexToBigInt, toCaipAssetType } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n CHAIN_ID_POLYGON,\n NATIVE_TOKEN_ADDRESS,\n SLIP44_COIN_TYPE_BY_CHAIN,\n STABLECOINS,\n} from '../constants';\nimport type { FiatRates, TransactionPayControllerMessenger } from '../types';\nimport { getAssetsUnifyStateFeature } from './feature-flags';\n\n/**\n * Check if two tokens are the same (same address and chain).\n *\n * @param token1 - First token identifier.\n * @param token1.address - Token address.\n * @param token1.chainId - Token chain ID.\n * @param token2 - Second token identifier.\n * @param token2.address - Token address.\n * @param token2.chainId - Token chain ID.\n * @returns True if tokens are the same, false otherwise.\n */\nexport function isSameToken(\n token1: { address: Hex; chainId: Hex },\n token2: { address: Hex; chainId: Hex },\n): boolean {\n return (\n token1.address.toLowerCase() === token2.address.toLowerCase() &&\n token1.chainId === token2.chainId\n );\n}\n\n/**\n * Get the token balance for a specific account and token.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Id of the chain.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport function getTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): string {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let tokenBalances;\n let accountsByChainId;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n tokenBalances = assetsControllerState?.tokenBalances;\n accountsByChainId = assetsControllerState?.accountsByChainId;\n } else {\n tokenBalances = messenger.call(\n 'TokenBalancesController:getState',\n )?.tokenBalances;\n accountsByChainId = messenger.call(\n 'AccountTrackerController:getState',\n )?.accountsByChainId;\n }\n\n const normalizedAccount = account.toLowerCase() as Hex;\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const balanceHex =\n tokenBalances?.[normalizedAccount]?.[chainId]?.[normalizedTokenAddress];\n\n if (!isNative && balanceHex === undefined) {\n return '0';\n }\n\n if (!isNative && balanceHex) {\n return new BigNumber(balanceHex, 16).toString(10);\n }\n\n const chainAccounts = accountsByChainId?.[chainId];\n\n const checksumAccount = toChecksumHexAddress(normalizedAccount) as Hex;\n const nativeBalanceHex = chainAccounts?.[checksumAccount]?.balance as Hex;\n\n return new BigNumber(nativeBalanceHex ?? '0x0', 16).toString(10);\n}\n\n/**\n * Get the token decimals for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns The token decimals or undefined if the token is not found.\n */\nexport function getTokenInfo(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): { decimals: number; symbol: string } | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let allTokens: TokensControllerState['allTokens'];\n if (assetsUnifyStateFeatureEnabled) {\n allTokens = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n )?.allTokens;\n } else {\n allTokens = messenger.call('TokensController:getState')?.allTokens;\n }\n\n const normalizedTokenAddress = tokenAddress.toLowerCase() as Hex;\n\n const isNative =\n normalizedTokenAddress === getNativeToken(chainId).toLowerCase();\n\n const token = Object.values(allTokens?.[chainId] ?? {})\n .flat()\n .find(\n (singleToken) =>\n singleToken.address.toLowerCase() === normalizedTokenAddress,\n );\n\n if (!token && !isNative) {\n return undefined;\n }\n\n if (token && !isNative) {\n return { decimals: Number(token.decimals), symbol: token.symbol };\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n return { decimals: 18, symbol: ticker };\n}\n\n/**\n * Calculate fiat rates for a specific token.\n *\n * @param messenger - Controller messenger.\n * @param tokenAddress - Address of the token contract.\n * @param chainId - Id of the chain.\n * @returns An object containing the USD and fiat rates, or undefined if rates are not available.\n */\nexport function getTokenFiatRate(\n messenger: TransactionPayControllerMessenger,\n tokenAddress: Hex,\n chainId: Hex,\n): FiatRates | undefined {\n const assetsUnifyStateFeatureEnabled = getAssetsUnifyStateFeature(messenger);\n\n let marketData;\n let currencyRates;\n if (assetsUnifyStateFeatureEnabled) {\n const assetsControllerState = messenger.call(\n 'AssetsController:getStateForTransactionPay',\n );\n\n marketData = assetsControllerState?.marketData;\n currencyRates = assetsControllerState?.currencyRates;\n } else {\n marketData = messenger.call('TokenRatesController:getState')?.marketData;\n currencyRates = messenger.call(\n 'CurrencyRateController:getState',\n )?.currencyRates;\n }\n\n const ticker = getTicker(chainId, messenger);\n\n if (!ticker) {\n return undefined;\n }\n\n const normalizedTokenAddress = toChecksumHexAddress(tokenAddress) as Hex;\n const isNative = normalizedTokenAddress === getNativeToken(chainId);\n\n const tokenToNativeRate =\n marketData?.[chainId]?.[normalizedTokenAddress]?.price;\n\n if (tokenToNativeRate === undefined && !isNative) {\n return undefined;\n }\n\n const {\n conversionRate: nativeToFiatRate,\n usdConversionRate: nativeToUsdRate,\n } = currencyRates?.[ticker] ?? {\n conversionRate: null,\n usdConversionRate: null,\n };\n\n if (nativeToFiatRate === null || nativeToUsdRate === null) {\n return undefined;\n }\n const isStablecoin = STABLECOINS[chainId]?.includes(\n tokenAddress.toLowerCase() as Hex,\n );\n\n const usdRate = isStablecoin\n ? '1'\n : new BigNumber(String(tokenToNativeRate ?? 1))\n .multipliedBy(String(nativeToUsdRate))\n .toString(10);\n\n const fiatRate = new BigNumber(String(tokenToNativeRate ?? 1))\n .multipliedBy(String(nativeToFiatRate))\n .toString(10);\n\n return { usdRate, fiatRate };\n}\n\n/**\n * Calculate the human-readable, raw, USD, and fiat representations of a token amount.\n *\n * @param rawInput - Raw token amount (decimal string, hex, or BigNumber).\n * @param decimals - Number of decimals for the token.\n * @param fiatRates - Fiat rates for the token.\n * @returns Object containing the amount in raw, human-readable, USD, and fiat formats.\n */\nexport function computeTokenAmounts(\n rawInput: BigNumber.Value,\n decimals: number,\n fiatRates: FiatRates,\n): {\n raw: string;\n human: string;\n usd: string;\n fiat: string;\n} {\n const rawValue = new BigNumber(rawInput);\n const humanValue = rawValue.shiftedBy(-decimals);\n\n return {\n raw: rawValue.toFixed(0),\n human: humanValue.toString(10),\n usd: humanValue.multipliedBy(fiatRates.usdRate).toString(10),\n fiat: humanValue.multipliedBy(fiatRates.fiatRate).toString(10),\n };\n}\n\n/**\n * Compute a raw token amount from a fiat (USD) amount.\n * This is the inverse of `computeTokenAmounts` — it goes from USD to raw.\n *\n * @param fiatAmount - Amount in fiat/USD.\n * @param decimals - Token decimals.\n * @param usdRate - USD rate for the token (price per one unit of the token).\n * @returns Raw token amount string, or undefined if the conversion produces an invalid result.\n */\nexport function computeRawFromFiatAmount(\n fiatAmount: BigNumber.Value,\n decimals: number,\n usdRate: BigNumber.Value,\n): string | undefined {\n const rate = new BigNumber(usdRate);\n if (!rate.isFinite() || !rate.gt(0)) {\n return undefined;\n }\n\n const humanAmount = new BigNumber(fiatAmount).dividedBy(rate);\n if (!humanAmount.isFinite() || !humanAmount.gt(0)) {\n return undefined;\n }\n\n const raw = humanAmount\n .shiftedBy(decimals)\n .decimalPlaces(0, BigNumber.ROUND_DOWN)\n .toFixed(0);\n\n return new BigNumber(raw).gt(0) ? raw : undefined;\n}\n\n/**\n * Get the native token address for a given chain ID.\n *\n * @param chainId - Chain ID.\n * @returns - Native token address for the given chain ID.\n */\nexport function getNativeToken(chainId: Hex): Hex {\n switch (chainId) {\n case '0x89':\n return '0x0000000000000000000000000000000000001010';\n default:\n return NATIVE_TOKEN_ADDRESS;\n }\n}\n\n/**\n * Get the live on-chain token balance via an RPC `eth_call` to the ERC-20\n * `balanceOf` function, or `eth_getBalance` for native tokens.\n *\n * Unlike {@link getTokenBalance}, this bypasses the cached state in\n * `TokenBalancesController` and reads directly from the chain.\n *\n * @param messenger - Controller messenger.\n * @param account - Address of the account.\n * @param chainId - Chain ID.\n * @param tokenAddress - Address of the token contract.\n * @returns Raw token balance as a decimal string.\n */\nexport async function getLiveTokenBalance(\n messenger: TransactionPayControllerMessenger,\n account: Hex,\n chainId: Hex,\n tokenAddress: Hex,\n): Promise<string> {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const { provider } = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n const ethersProvider = new Web3Provider(provider);\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n // Use `pending` blockTag to bypass the RPC block-cache middleware so callers\n // always observe the latest balance instead of a value pinned to the last\n // polled block.\n if (isNative) {\n const balance = await ethersProvider.getBalance(account, 'pending');\n return balance.toString();\n }\n\n const contract = new Contract(tokenAddress, abiERC20, ethersProvider);\n const balance = await contract.balanceOf(account, { blockTag: 'pending' });\n return balance.toString();\n}\n\n/**\n * Build a CAIP-19 asset type identifier for an EVM token.\n *\n * For native tokens the SLIP-44 coin type is resolved automatically from\n * a built-in chain→coin-type map, falling back to 60 (ETH). Callers can\n * override via the optional third parameter.\n *\n * @param chainId - Hex chain ID (e.g. `0x1`).\n * @param tokenAddress - Token contract address, or the native token address.\n * @param slip44CoinType - Optional SLIP-44 coin type override for native tokens.\n * @returns CAIP-19 asset type string.\n */\nexport function buildCaipAssetType(\n chainId: Hex,\n tokenAddress: Hex,\n slip44CoinType?: number,\n): CaipAssetType {\n const chainReference = String(hexToBigInt(chainId));\n const isNative =\n tokenAddress.toLowerCase() === getNativeToken(chainId).toLowerCase();\n\n if (isNative) {\n const coinType = slip44CoinType ?? SLIP44_COIN_TYPE_BY_CHAIN[chainId] ?? 60;\n\n return toCaipAssetType(\n 'eip155',\n chainReference,\n 'slip44',\n String(coinType),\n );\n }\n\n return toCaipAssetType('eip155', chainReference, 'erc20', tokenAddress);\n}\n\nfunction getTicker(\n chainId: Hex,\n messenger: TransactionPayControllerMessenger,\n): string | undefined {\n try {\n const networkClientId = messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n chainId,\n );\n\n const networkConfiguration = messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n\n return networkConfiguration.configuration.ticker;\n } catch {\n return undefined;\n }\n}\n\nexport enum TokenAddressTarget {\n Relay = 'relay',\n MetaMask = 'metamask',\n}\n\n/**\n * Normalize token address formats between MetaMask and Relay for Polygon native\n * token handling.\n *\n * MetaMask uses Polygon's native token contract-like address (`0x...1010`),\n * while Relay expects the zero address for native tokens.\n *\n * @param tokenAddress - Token address to normalize.\n * @param chainId - Chain ID for the token.\n * @param target - Optional target system format.\n * @returns Normalized token address for the target system, or the original\n * address if no target is provided.\n */\nexport function normalizeTokenAddress(\n tokenAddress: Hex,\n chainId: Hex,\n target?: TokenAddressTarget,\n): Hex {\n if (chainId !== CHAIN_ID_POLYGON) {\n return tokenAddress;\n }\n\n const nativeTokenAddress = getNativeToken(chainId).toLowerCase() as Hex;\n const normalizedTokenAddress = tokenAddress.toLowerCase();\n\n if (\n target === TokenAddressTarget.Relay &&\n normalizedTokenAddress === nativeTokenAddress\n ) {\n return NATIVE_TOKEN_ADDRESS;\n }\n\n if (\n target === TokenAddressTarget.MetaMask &&\n normalizedTokenAddress === NATIVE_TOKEN_ADDRESS.toLowerCase()\n ) {\n return nativeTokenAddress;\n }\n\n return tokenAddress;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/transaction-pay-controller",
3
- "version": "22.5.0",
3
+ "version": "22.6.1",
4
4
  "description": "Manages alternate payment strategies to provide required funds for transactions in MetaMask",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -60,16 +60,16 @@
60
60
  "@metamask/assets-controller": "^7.1.2",
61
61
  "@metamask/assets-controllers": "^108.1.0",
62
62
  "@metamask/base-controller": "^9.1.0",
63
- "@metamask/bridge-controller": "^72.0.4",
64
- "@metamask/bridge-status-controller": "^71.1.4",
63
+ "@metamask/bridge-controller": "^73.0.0",
64
+ "@metamask/bridge-status-controller": "^71.2.0",
65
65
  "@metamask/controller-utils": "^12.1.0",
66
- "@metamask/gas-fee-controller": "^26.2.1",
66
+ "@metamask/gas-fee-controller": "^26.2.2",
67
67
  "@metamask/messenger": "^1.2.0",
68
68
  "@metamask/metamask-eth-abis": "^3.1.1",
69
69
  "@metamask/network-controller": "^32.0.0",
70
70
  "@metamask/ramps-controller": "^13.3.1",
71
71
  "@metamask/remote-feature-flag-controller": "^4.2.1",
72
- "@metamask/transaction-controller": "^65.4.0",
72
+ "@metamask/transaction-controller": "^66.0.0",
73
73
  "@metamask/utils": "^11.9.0",
74
74
  "bignumber.js": "^9.1.2",
75
75
  "bn.js": "^5.2.1",