@metamask/transaction-pay-controller 16.4.1 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/strategy/across/across-quotes.cjs +42 -8
  3. package/dist/strategy/across/across-quotes.cjs.map +1 -1
  4. package/dist/strategy/across/across-quotes.d.cts.map +1 -1
  5. package/dist/strategy/across/across-quotes.d.mts.map +1 -1
  6. package/dist/strategy/across/across-quotes.mjs +42 -8
  7. package/dist/strategy/across/across-quotes.mjs.map +1 -1
  8. package/dist/strategy/relay/constants.cjs +15 -1
  9. package/dist/strategy/relay/constants.cjs.map +1 -1
  10. package/dist/strategy/relay/constants.d.cts +5 -0
  11. package/dist/strategy/relay/constants.d.cts.map +1 -1
  12. package/dist/strategy/relay/constants.d.mts +5 -0
  13. package/dist/strategy/relay/constants.d.mts.map +1 -1
  14. package/dist/strategy/relay/constants.mjs +14 -0
  15. package/dist/strategy/relay/constants.mjs.map +1 -1
  16. package/dist/strategy/relay/gas-station.cjs +1 -2
  17. package/dist/strategy/relay/gas-station.cjs.map +1 -1
  18. package/dist/strategy/relay/gas-station.d.cts.map +1 -1
  19. package/dist/strategy/relay/gas-station.d.mts.map +1 -1
  20. package/dist/strategy/relay/gas-station.mjs +2 -3
  21. package/dist/strategy/relay/gas-station.mjs.map +1 -1
  22. package/dist/strategy/relay/relay-api.cjs +55 -0
  23. package/dist/strategy/relay/relay-api.cjs.map +1 -0
  24. package/dist/strategy/relay/relay-api.d.cts +26 -0
  25. package/dist/strategy/relay/relay-api.d.cts.map +1 -0
  26. package/dist/strategy/relay/relay-api.d.mts +26 -0
  27. package/dist/strategy/relay/relay-api.d.mts.map +1 -0
  28. package/dist/strategy/relay/relay-api.mjs +49 -0
  29. package/dist/strategy/relay/relay-api.mjs.map +1 -0
  30. package/dist/strategy/relay/relay-quotes.cjs +123 -31
  31. package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
  32. package/dist/strategy/relay/relay-quotes.d.cts.map +1 -1
  33. package/dist/strategy/relay/relay-quotes.d.mts.map +1 -1
  34. package/dist/strategy/relay/relay-quotes.mjs +125 -33
  35. package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
  36. package/dist/strategy/relay/relay-submit.cjs +144 -19
  37. package/dist/strategy/relay/relay-submit.cjs.map +1 -1
  38. package/dist/strategy/relay/relay-submit.d.cts.map +1 -1
  39. package/dist/strategy/relay/relay-submit.d.mts.map +1 -1
  40. package/dist/strategy/relay/relay-submit.mjs +147 -22
  41. package/dist/strategy/relay/relay-submit.mjs.map +1 -1
  42. package/dist/strategy/relay/types.cjs.map +1 -1
  43. package/dist/strategy/relay/types.d.cts +29 -1
  44. package/dist/strategy/relay/types.d.cts.map +1 -1
  45. package/dist/strategy/relay/types.d.mts +29 -1
  46. package/dist/strategy/relay/types.d.mts.map +1 -1
  47. package/dist/strategy/relay/types.mjs.map +1 -1
  48. package/dist/tests/messenger-mock.cjs +3 -0
  49. package/dist/tests/messenger-mock.cjs.map +1 -1
  50. package/dist/tests/messenger-mock.d.cts +9 -1
  51. package/dist/tests/messenger-mock.d.cts.map +1 -1
  52. package/dist/tests/messenger-mock.d.mts +9 -1
  53. package/dist/tests/messenger-mock.d.mts.map +1 -1
  54. package/dist/tests/messenger-mock.mjs +3 -0
  55. package/dist/tests/messenger-mock.mjs.map +1 -1
  56. package/dist/types.cjs.map +1 -1
  57. package/dist/types.d.cts +2 -1
  58. package/dist/types.d.cts.map +1 -1
  59. package/dist/types.d.mts +2 -1
  60. package/dist/types.d.mts.map +1 -1
  61. package/dist/types.mjs.map +1 -1
  62. package/dist/utils/feature-flags.cjs +75 -7
  63. package/dist/utils/feature-flags.cjs.map +1 -1
  64. package/dist/utils/feature-flags.d.cts +49 -3
  65. package/dist/utils/feature-flags.d.cts.map +1 -1
  66. package/dist/utils/feature-flags.d.mts +49 -3
  67. package/dist/utils/feature-flags.d.mts.map +1 -1
  68. package/dist/utils/feature-flags.mjs +69 -6
  69. package/dist/utils/feature-flags.mjs.map +1 -1
  70. package/dist/utils/token.cjs +39 -40
  71. package/dist/utils/token.cjs.map +1 -1
  72. package/dist/utils/token.d.cts +0 -12
  73. package/dist/utils/token.d.cts.map +1 -1
  74. package/dist/utils/token.d.mts +0 -12
  75. package/dist/utils/token.d.mts.map +1 -1
  76. package/dist/utils/token.mjs +38 -39
  77. package/dist/utils/token.mjs.map +1 -1
  78. package/dist/utils/transaction.cjs +16 -1
  79. package/dist/utils/transaction.cjs.map +1 -1
  80. package/dist/utils/transaction.d.cts +10 -0
  81. package/dist/utils/transaction.d.cts.map +1 -1
  82. package/dist/utils/transaction.d.mts +10 -0
  83. package/dist/utils/transaction.d.mts.map +1 -1
  84. package/dist/utils/transaction.mjs +15 -1
  85. package/dist/utils/transaction.mjs.map +1 -1
  86. package/package.json +6 -5
@@ -1,7 +1,12 @@
1
1
  import { TransactionType } from "@metamask/transaction-controller";
2
+ import type { RelayStatus } from "./types.mjs";
2
3
  export declare const RELAY_URL_BASE = "https://api.relay.link";
4
+ export declare const RELAY_EXECUTE_URL = "https://api.relay.link/execute";
5
+ export declare const RELAY_QUOTE_URL = "https://api.relay.link/quote";
3
6
  export declare const RELAY_STATUS_URL = "https://api.relay.link/intents/status/v3";
4
7
  export declare const RELAY_POLLING_INTERVAL = 1000;
5
8
  export declare const TOKEN_TRANSFER_FOUR_BYTE = "0xa9059cbb";
9
+ export declare const RELAY_FAILURE_STATUSES: RelayStatus[];
10
+ export declare const RELAY_PENDING_STATUSES: RelayStatus[];
6
11
  export declare const RELAY_DEPOSIT_TYPES: Record<string, TransactionType>;
7
12
  //# sourceMappingURL=constants.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,yCAAyC;AAEnE,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,gBAAgB,6CAAwC,CAAC;AACtE,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,wBAAwB,eAAe,CAAC;AAErD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAG/D,CAAC"}
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,yCAAyC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAgB;AAE3C,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,iBAAiB,mCAA8B,CAAC;AAC7D,eAAO,MAAM,eAAe,iCAA4B,CAAC;AACzD,eAAO,MAAM,gBAAgB,6CAAwC,CAAC;AACtE,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,wBAAwB,eAAe,CAAC;AAErD,eAAO,MAAM,sBAAsB,EAAE,WAAW,EAI/C,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,WAAW,EAM/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAG/D,CAAC"}
@@ -1,8 +1,22 @@
1
1
  import { TransactionType } from "@metamask/transaction-controller";
2
2
  export const RELAY_URL_BASE = 'https://api.relay.link';
3
+ export const RELAY_EXECUTE_URL = `${RELAY_URL_BASE}/execute`;
4
+ export const RELAY_QUOTE_URL = `${RELAY_URL_BASE}/quote`;
3
5
  export const RELAY_STATUS_URL = `${RELAY_URL_BASE}/intents/status/v3`;
4
6
  export const RELAY_POLLING_INTERVAL = 1000; // 1 Second
5
7
  export const TOKEN_TRANSFER_FOUR_BYTE = '0xa9059cbb';
8
+ export const RELAY_FAILURE_STATUSES = [
9
+ 'failure',
10
+ 'refund',
11
+ 'refunded',
12
+ ];
13
+ export const RELAY_PENDING_STATUSES = [
14
+ 'delayed',
15
+ 'depositing',
16
+ 'pending',
17
+ 'submitted',
18
+ 'waiting',
19
+ ];
6
20
  export const RELAY_DEPOSIT_TYPES = {
7
21
  [TransactionType.predictDeposit]: TransactionType.predictRelayDeposit,
8
22
  [TransactionType.perpsDeposit]: TransactionType.perpsRelayDeposit,
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,yCAAyC;AAEnE,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,cAAc,oBAAoB,CAAC;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC,CAAC,WAAW;AACvD,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC;AAErD,MAAM,CAAC,MAAM,mBAAmB,GAAoC;IAClE,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC,mBAAmB;IACrE,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC,iBAAiB;CAClE,CAAC","sourcesContent":["import { TransactionType } from '@metamask/transaction-controller';\n\nexport const RELAY_URL_BASE = 'https://api.relay.link';\nexport const RELAY_STATUS_URL = `${RELAY_URL_BASE}/intents/status/v3`;\nexport const RELAY_POLLING_INTERVAL = 1000; // 1 Second\nexport const TOKEN_TRANSFER_FOUR_BYTE = '0xa9059cbb';\n\nexport const RELAY_DEPOSIT_TYPES: Record<string, TransactionType> = {\n [TransactionType.predictDeposit]: TransactionType.predictRelayDeposit,\n [TransactionType.perpsDeposit]: TransactionType.perpsRelayDeposit,\n};\n"]}
1
+ {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,yCAAyC;AAInE,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,cAAc,UAAU,CAAC;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,cAAc,QAAQ,CAAC;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,cAAc,oBAAoB,CAAC;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC,CAAC,WAAW;AACvD,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC;AAErD,MAAM,CAAC,MAAM,sBAAsB,GAAkB;IACnD,SAAS;IACT,QAAQ;IACR,UAAU;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAkB;IACnD,SAAS;IACT,YAAY;IACZ,SAAS;IACT,WAAW;IACX,SAAS;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAoC;IAClE,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC,mBAAmB;IACrE,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC,iBAAiB;CAClE,CAAC","sourcesContent":["import { TransactionType } from '@metamask/transaction-controller';\n\nimport type { RelayStatus } from './types';\n\nexport const RELAY_URL_BASE = 'https://api.relay.link';\nexport const RELAY_EXECUTE_URL = `${RELAY_URL_BASE}/execute`;\nexport const RELAY_QUOTE_URL = `${RELAY_URL_BASE}/quote`;\nexport const RELAY_STATUS_URL = `${RELAY_URL_BASE}/intents/status/v3`;\nexport const RELAY_POLLING_INTERVAL = 1000; // 1 Second\nexport const TOKEN_TRANSFER_FOUR_BYTE = '0xa9059cbb';\n\nexport const RELAY_FAILURE_STATUSES: RelayStatus[] = [\n 'failure',\n 'refund',\n 'refunded',\n];\n\nexport const RELAY_PENDING_STATUSES: RelayStatus[] = [\n 'delayed',\n 'depositing',\n 'pending',\n 'submitted',\n 'waiting',\n];\n\nexport const RELAY_DEPOSIT_TYPES: Record<string, TransactionType> = {\n [TransactionType.predictDeposit]: TransactionType.predictRelayDeposit,\n [TransactionType.perpsDeposit]: TransactionType.perpsRelayDeposit,\n};\n"]}
@@ -10,8 +10,7 @@ const gas_1 = require("../../utils/gas.cjs");
10
10
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'relay-gas-station');
11
11
  function getGasStationEligibility(messenger, sourceChainId) {
12
12
  const { relayDisabledGasStationChains } = (0, feature_flags_1.getFeatureFlags)(messenger);
13
- const supportedChains = (0, feature_flags_1.getEIP7702SupportedChains)(messenger);
14
- const chainSupportsGasStation = supportedChains.some((supportedChainId) => supportedChainId.toLowerCase() === sourceChainId.toLowerCase());
13
+ const chainSupportsGasStation = (0, feature_flags_1.isEIP7702Chain)(messenger, sourceChainId);
15
14
  const isDisabledChain = relayDisabledGasStationChains.includes(sourceChainId);
16
15
  return {
17
16
  chainSupportsGasStation,
@@ -1 +1 @@
1
- {"version":3,"file":"gas-station.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/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 {\n getEIP7702SupportedChains,\n getFeatureFlags,\n} from '../../utils/feature-flags';\nimport { calculateGasFeeTokenCost } from '../../utils/gas';\n\nconst log = createModuleLogger(projectLogger, 'relay-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 supportedChains = getEIP7702SupportedChains(messenger);\n const chainSupportsGasStation = supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === sourceChainId.toLowerCase(),\n );\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/strategy/relay/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 '../../utils/feature-flags';\nimport { calculateGasFeeTokenCost } from '../../utils/gas';\n\nconst log = createModuleLogger(projectLogger, 'relay-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 +1 @@
1
- {"version":3,"file":"gas-station.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/gas-station.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,iCAAiC,EAClC,wBAAoB;AASrB,KAAK,oBAAoB,GAAG;IAC1B,aAAa,EAAE;QACb,IAAI,EAAE,GAAG,CAAC;QACV,EAAE,EAAE,GAAG,CAAC;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,EAAE,iCAAiC,CAAC;IAC7C,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,GAAG,oBAAoB,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,uBAAuB,EAAE,OAAO,CAAC;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,aAAa,EAAE,YAAY,CAAC,eAAe,CAAC,GAC3C,qBAAqB,CAevB;AAED,wBAAsB,iCAAiC,CAAC,EACtD,aAAa,EACb,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,cAAc,GACf,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuEpD"}
1
+ {"version":3,"file":"gas-station.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/gas-station.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,iCAAiC,EAClC,wBAAoB;AAMrB,KAAK,oBAAoB,GAAG;IAC1B,aAAa,EAAE;QACb,IAAI,EAAE,GAAG,CAAC;QACV,EAAE,EAAE,GAAG,CAAC;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,EAAE,iCAAiC,CAAC;IAC7C,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,GAAG,oBAAoB,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,uBAAuB,EAAE,OAAO,CAAC;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,aAAa,EAAE,YAAY,CAAC,eAAe,CAAC,GAC3C,qBAAqB,CAWvB;AAED,wBAAsB,iCAAiC,CAAC,EACtD,aAAa,EACb,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,cAAc,GACf,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuEpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"gas-station.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/gas-station.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,iCAAiC,EAClC,wBAAoB;AASrB,KAAK,oBAAoB,GAAG;IAC1B,aAAa,EAAE;QACb,IAAI,EAAE,GAAG,CAAC;QACV,EAAE,EAAE,GAAG,CAAC;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,EAAE,iCAAiC,CAAC;IAC7C,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,GAAG,oBAAoB,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,uBAAuB,EAAE,OAAO,CAAC;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,aAAa,EAAE,YAAY,CAAC,eAAe,CAAC,GAC3C,qBAAqB,CAevB;AAED,wBAAsB,iCAAiC,CAAC,EACtD,aAAa,EACb,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,cAAc,GACf,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuEpD"}
1
+ {"version":3,"file":"gas-station.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/gas-station.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,iCAAiC,EAClC,wBAAoB;AAMrB,KAAK,oBAAoB,GAAG;IAC1B,aAAa,EAAE;QACb,IAAI,EAAE,GAAG,CAAC;QACV,EAAE,EAAE,GAAG,CAAC;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,EAAE,iCAAiC,CAAC;IAC7C,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,GAAG,oBAAoB,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,uBAAuB,EAAE,OAAO,CAAC;IACjC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,aAAa,EAAE,YAAY,CAAC,eAAe,CAAC,GAC3C,qBAAqB,CAWvB;AAED,wBAAsB,iCAAiC,CAAC,EACtD,aAAa,EACb,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,cAAc,GACf,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuEpD"}
@@ -2,13 +2,12 @@ import { toHex } from "@metamask/controller-utils";
2
2
  import { createModuleLogger } from "@metamask/utils";
3
3
  import { BigNumber } from "bignumber.js";
4
4
  import { projectLogger } from "../../logger.mjs";
5
- import { getEIP7702SupportedChains, getFeatureFlags } from "../../utils/feature-flags.mjs";
5
+ import { getFeatureFlags, isEIP7702Chain } from "../../utils/feature-flags.mjs";
6
6
  import { calculateGasFeeTokenCost } from "../../utils/gas.mjs";
7
7
  const log = createModuleLogger(projectLogger, 'relay-gas-station');
8
8
  export function getGasStationEligibility(messenger, sourceChainId) {
9
9
  const { relayDisabledGasStationChains } = getFeatureFlags(messenger);
10
- const supportedChains = getEIP7702SupportedChains(messenger);
11
- const chainSupportsGasStation = supportedChains.some((supportedChainId) => supportedChainId.toLowerCase() === sourceChainId.toLowerCase());
10
+ const chainSupportsGasStation = isEIP7702Chain(messenger, sourceChainId);
12
11
  const isDisabledChain = relayDisabledGasStationChains.includes(sourceChainId);
13
12
  return {
14
13
  chainSupportsGasStation,
@@ -1 +1 @@
1
- {"version":3,"file":"gas-station.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/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 {\n getEIP7702SupportedChains,\n getFeatureFlags,\n} from '../../utils/feature-flags';\nimport { calculateGasFeeTokenCost } from '../../utils/gas';\n\nconst log = createModuleLogger(projectLogger, 'relay-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 supportedChains = getEIP7702SupportedChains(messenger);\n const chainSupportsGasStation = supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === sourceChainId.toLowerCase(),\n );\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/strategy/relay/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,yBAAqB;AAM7C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,sCAAkC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,4BAAwB;AAE3D,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC;AAoBnE,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 '../../utils/feature-flags';\nimport { calculateGasFeeTokenCost } from '../../utils/gas';\n\nconst log = createModuleLogger(projectLogger, 'relay-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"]}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRelayStatus = exports.submitRelayExecute = exports.fetchRelayQuote = void 0;
4
+ const controller_utils_1 = require("@metamask/controller-utils");
5
+ const constants_1 = require("./constants.cjs");
6
+ const feature_flags_1 = require("../../utils/feature-flags.cjs");
7
+ /**
8
+ * Fetch a quote from the Relay API.
9
+ *
10
+ * @param messenger - Controller messenger.
11
+ * @param body - Quote request parameters.
12
+ * @returns The Relay quote with the request attached.
13
+ */
14
+ async function fetchRelayQuote(messenger, body) {
15
+ const { relayQuoteUrl } = (0, feature_flags_1.getFeatureFlags)(messenger);
16
+ const response = await (0, controller_utils_1.successfulFetch)(relayQuoteUrl, {
17
+ method: 'POST',
18
+ headers: { 'Content-Type': 'application/json' },
19
+ body: JSON.stringify(body),
20
+ });
21
+ const quote = (await response.json());
22
+ quote.request = body;
23
+ return quote;
24
+ }
25
+ exports.fetchRelayQuote = fetchRelayQuote;
26
+ /**
27
+ * Submit a gasless transaction via the Relay /execute endpoint.
28
+ *
29
+ * @param messenger - Controller messenger.
30
+ * @param body - Execute request parameters.
31
+ * @returns The execute response containing the request ID.
32
+ */
33
+ async function submitRelayExecute(messenger, body) {
34
+ const { relayExecuteUrl } = (0, feature_flags_1.getFeatureFlags)(messenger);
35
+ const response = await (0, controller_utils_1.successfulFetch)(relayExecuteUrl, {
36
+ method: 'POST',
37
+ headers: { 'Content-Type': 'application/json' },
38
+ body: JSON.stringify(body),
39
+ });
40
+ return (await response.json());
41
+ }
42
+ exports.submitRelayExecute = submitRelayExecute;
43
+ /**
44
+ * Poll the Relay status endpoint for a given request ID.
45
+ *
46
+ * @param requestId - The Relay request ID to check.
47
+ * @returns The current status of the request.
48
+ */
49
+ async function getRelayStatus(requestId) {
50
+ const url = `${constants_1.RELAY_STATUS_URL}?requestId=${requestId}`;
51
+ const response = await (0, controller_utils_1.successfulFetch)(url, { method: 'GET' });
52
+ return (await response.json());
53
+ }
54
+ exports.getRelayStatus = getRelayStatus;
55
+ //# sourceMappingURL=relay-api.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-api.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-api.ts"],"names":[],"mappings":";;;AAAA,iEAA6D;AAE7D,+CAA+C;AAS/C,iEAA4D;AAE5D;;;;;;GAMG;AACI,KAAK,UAAU,eAAe,CACnC,SAA4C,EAC5C,IAAuB;IAEvB,MAAM,EAAE,aAAa,EAAE,GAAG,IAAA,+BAAe,EAAC,SAAS,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,IAAA,kCAAe,EAAC,aAAa,EAAE;QACpD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAe,CAAC;IACpD,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;IAErB,OAAO,KAAK,CAAC;AACf,CAAC;AAhBD,0CAgBC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,kBAAkB,CACtC,SAA4C,EAC5C,IAAyB;IAEzB,MAAM,EAAE,eAAe,EAAE,GAAG,IAAA,+BAAe,EAAC,SAAS,CAAC,CAAC;IAEvD,MAAM,QAAQ,GAAG,MAAM,IAAA,kCAAe,EAAC,eAAe,EAAE;QACtD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;AACzD,CAAC;AAbD,gDAaC;AAED;;;;;GAKG;AACI,KAAK,UAAU,cAAc,CAClC,SAAiB;IAEjB,MAAM,GAAG,GAAG,GAAG,4BAAgB,cAAc,SAAS,EAAE,CAAC;IAEzD,MAAM,QAAQ,GAAG,MAAM,IAAA,kCAAe,EAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAE/D,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;AACxD,CAAC;AARD,wCAQC","sourcesContent":["import { successfulFetch } from '@metamask/controller-utils';\n\nimport { RELAY_STATUS_URL } from './constants';\nimport type {\n RelayExecuteRequest,\n RelayExecuteResponse,\n RelayQuote,\n RelayQuoteRequest,\n RelayStatusResponse,\n} from './types';\nimport type { TransactionPayControllerMessenger } from '../../types';\nimport { getFeatureFlags } from '../../utils/feature-flags';\n\n/**\n * Fetch a quote from the Relay API.\n *\n * @param messenger - Controller messenger.\n * @param body - Quote request parameters.\n * @returns The Relay quote with the request attached.\n */\nexport async function fetchRelayQuote(\n messenger: TransactionPayControllerMessenger,\n body: RelayQuoteRequest,\n): Promise<RelayQuote> {\n const { relayQuoteUrl } = getFeatureFlags(messenger);\n\n const response = await successfulFetch(relayQuoteUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const quote = (await response.json()) as RelayQuote;\n quote.request = body;\n\n return quote;\n}\n\n/**\n * Submit a gasless transaction via the Relay /execute endpoint.\n *\n * @param messenger - Controller messenger.\n * @param body - Execute request parameters.\n * @returns The execute response containing the request ID.\n */\nexport async function submitRelayExecute(\n messenger: TransactionPayControllerMessenger,\n body: RelayExecuteRequest,\n): Promise<RelayExecuteResponse> {\n const { relayExecuteUrl } = getFeatureFlags(messenger);\n\n const response = await successfulFetch(relayExecuteUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n return (await response.json()) as RelayExecuteResponse;\n}\n\n/**\n * Poll the Relay status endpoint for a given request ID.\n *\n * @param requestId - The Relay request ID to check.\n * @returns The current status of the request.\n */\nexport async function getRelayStatus(\n requestId: string,\n): Promise<RelayStatusResponse> {\n const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;\n\n const response = await successfulFetch(url, { method: 'GET' });\n\n return (await response.json()) as RelayStatusResponse;\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import type { RelayExecuteRequest, RelayExecuteResponse, RelayQuote, RelayQuoteRequest, RelayStatusResponse } from "./types.cjs";
2
+ import type { TransactionPayControllerMessenger } from "../../types.cjs";
3
+ /**
4
+ * Fetch a quote from the Relay API.
5
+ *
6
+ * @param messenger - Controller messenger.
7
+ * @param body - Quote request parameters.
8
+ * @returns The Relay quote with the request attached.
9
+ */
10
+ export declare function fetchRelayQuote(messenger: TransactionPayControllerMessenger, body: RelayQuoteRequest): Promise<RelayQuote>;
11
+ /**
12
+ * Submit a gasless transaction via the Relay /execute endpoint.
13
+ *
14
+ * @param messenger - Controller messenger.
15
+ * @param body - Execute request parameters.
16
+ * @returns The execute response containing the request ID.
17
+ */
18
+ export declare function submitRelayExecute(messenger: TransactionPayControllerMessenger, body: RelayExecuteRequest): Promise<RelayExecuteResponse>;
19
+ /**
20
+ * Poll the Relay status endpoint for a given request ID.
21
+ *
22
+ * @param requestId - The Relay request ID to check.
23
+ * @returns The current status of the request.
24
+ */
25
+ export declare function getRelayStatus(requestId: string): Promise<RelayStatusResponse>;
26
+ //# sourceMappingURL=relay-api.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-api.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACpB,oBAAgB;AACjB,OAAO,KAAK,EAAE,iCAAiC,EAAE,wBAAoB;AAGrE;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,UAAU,CAAC,CAarB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAU/B;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC,CAM9B"}
@@ -0,0 +1,26 @@
1
+ import type { RelayExecuteRequest, RelayExecuteResponse, RelayQuote, RelayQuoteRequest, RelayStatusResponse } from "./types.mjs";
2
+ import type { TransactionPayControllerMessenger } from "../../types.mjs";
3
+ /**
4
+ * Fetch a quote from the Relay API.
5
+ *
6
+ * @param messenger - Controller messenger.
7
+ * @param body - Quote request parameters.
8
+ * @returns The Relay quote with the request attached.
9
+ */
10
+ export declare function fetchRelayQuote(messenger: TransactionPayControllerMessenger, body: RelayQuoteRequest): Promise<RelayQuote>;
11
+ /**
12
+ * Submit a gasless transaction via the Relay /execute endpoint.
13
+ *
14
+ * @param messenger - Controller messenger.
15
+ * @param body - Execute request parameters.
16
+ * @returns The execute response containing the request ID.
17
+ */
18
+ export declare function submitRelayExecute(messenger: TransactionPayControllerMessenger, body: RelayExecuteRequest): Promise<RelayExecuteResponse>;
19
+ /**
20
+ * Poll the Relay status endpoint for a given request ID.
21
+ *
22
+ * @param requestId - The Relay request ID to check.
23
+ * @returns The current status of the request.
24
+ */
25
+ export declare function getRelayStatus(requestId: string): Promise<RelayStatusResponse>;
26
+ //# sourceMappingURL=relay-api.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-api.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACpB,oBAAgB;AACjB,OAAO,KAAK,EAAE,iCAAiC,EAAE,wBAAoB;AAGrE;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,UAAU,CAAC,CAarB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAU/B;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC,CAM9B"}
@@ -0,0 +1,49 @@
1
+ import { successfulFetch } from "@metamask/controller-utils";
2
+ import { RELAY_STATUS_URL } from "./constants.mjs";
3
+ import { getFeatureFlags } from "../../utils/feature-flags.mjs";
4
+ /**
5
+ * Fetch a quote from the Relay API.
6
+ *
7
+ * @param messenger - Controller messenger.
8
+ * @param body - Quote request parameters.
9
+ * @returns The Relay quote with the request attached.
10
+ */
11
+ export async function fetchRelayQuote(messenger, body) {
12
+ const { relayQuoteUrl } = getFeatureFlags(messenger);
13
+ const response = await successfulFetch(relayQuoteUrl, {
14
+ method: 'POST',
15
+ headers: { 'Content-Type': 'application/json' },
16
+ body: JSON.stringify(body),
17
+ });
18
+ const quote = (await response.json());
19
+ quote.request = body;
20
+ return quote;
21
+ }
22
+ /**
23
+ * Submit a gasless transaction via the Relay /execute endpoint.
24
+ *
25
+ * @param messenger - Controller messenger.
26
+ * @param body - Execute request parameters.
27
+ * @returns The execute response containing the request ID.
28
+ */
29
+ export async function submitRelayExecute(messenger, body) {
30
+ const { relayExecuteUrl } = getFeatureFlags(messenger);
31
+ const response = await successfulFetch(relayExecuteUrl, {
32
+ method: 'POST',
33
+ headers: { 'Content-Type': 'application/json' },
34
+ body: JSON.stringify(body),
35
+ });
36
+ return (await response.json());
37
+ }
38
+ /**
39
+ * Poll the Relay status endpoint for a given request ID.
40
+ *
41
+ * @param requestId - The Relay request ID to check.
42
+ * @returns The current status of the request.
43
+ */
44
+ export async function getRelayStatus(requestId) {
45
+ const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;
46
+ const response = await successfulFetch(url, { method: 'GET' });
47
+ return (await response.json());
48
+ }
49
+ //# sourceMappingURL=relay-api.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-api.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mCAAmC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,wBAAoB;AAS/C,OAAO,EAAE,eAAe,EAAE,sCAAkC;AAE5D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAA4C,EAC5C,IAAuB;IAEvB,MAAM,EAAE,aAAa,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,aAAa,EAAE;QACpD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAe,CAAC;IACpD,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;IAErB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAA4C,EAC5C,IAAyB;IAEzB,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAEvD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,eAAe,EAAE;QACtD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB;IAEjB,MAAM,GAAG,GAAG,GAAG,gBAAgB,cAAc,SAAS,EAAE,CAAC;IAEzD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAE/D,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;AACxD,CAAC","sourcesContent":["import { successfulFetch } from '@metamask/controller-utils';\n\nimport { RELAY_STATUS_URL } from './constants';\nimport type {\n RelayExecuteRequest,\n RelayExecuteResponse,\n RelayQuote,\n RelayQuoteRequest,\n RelayStatusResponse,\n} from './types';\nimport type { TransactionPayControllerMessenger } from '../../types';\nimport { getFeatureFlags } from '../../utils/feature-flags';\n\n/**\n * Fetch a quote from the Relay API.\n *\n * @param messenger - Controller messenger.\n * @param body - Quote request parameters.\n * @returns The Relay quote with the request attached.\n */\nexport async function fetchRelayQuote(\n messenger: TransactionPayControllerMessenger,\n body: RelayQuoteRequest,\n): Promise<RelayQuote> {\n const { relayQuoteUrl } = getFeatureFlags(messenger);\n\n const response = await successfulFetch(relayQuoteUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const quote = (await response.json()) as RelayQuote;\n quote.request = body;\n\n return quote;\n}\n\n/**\n * Submit a gasless transaction via the Relay /execute endpoint.\n *\n * @param messenger - Controller messenger.\n * @param body - Execute request parameters.\n * @returns The execute response containing the request ID.\n */\nexport async function submitRelayExecute(\n messenger: TransactionPayControllerMessenger,\n body: RelayExecuteRequest,\n): Promise<RelayExecuteResponse> {\n const { relayExecuteUrl } = getFeatureFlags(messenger);\n\n const response = await successfulFetch(relayExecuteUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n return (await response.json()) as RelayExecuteResponse;\n}\n\n/**\n * Poll the Relay status endpoint for a given request ID.\n *\n * @param requestId - The Relay request ID to check.\n * @returns The current status of the request.\n */\nexport async function getRelayStatus(\n requestId: string,\n): Promise<RelayStatusResponse> {\n const url = `${RELAY_STATUS_URL}?requestId=${requestId}`;\n\n const response = await successfulFetch(url, { method: 'GET' });\n\n return (await response.json()) as RelayStatusResponse;\n}\n"]}
@@ -8,6 +8,7 @@ const utils_1 = require("@metamask/utils");
8
8
  const bignumber_js_1 = require("bignumber.js");
9
9
  const constants_1 = require("./constants.cjs");
10
10
  const gas_station_1 = require("./gas-station.cjs");
11
+ const relay_api_1 = require("./relay-api.cjs");
11
12
  const relay_max_gas_station_1 = require("./relay-max-gas-station.cjs");
12
13
  const __1 = require("../../index.cjs");
13
14
  const constants_2 = require("../../constants.cjs");
@@ -16,6 +17,7 @@ const amounts_1 = require("../../utils/amounts.cjs");
16
17
  const feature_flags_1 = require("../../utils/feature-flags.cjs");
17
18
  const gas_1 = require("../../utils/gas.cjs");
18
19
  const token_1 = require("../../utils/token.cjs");
20
+ const transaction_1 = require("../../utils/transaction.cjs");
19
21
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'relay-strategy');
20
22
  /**
21
23
  * Fetches Relay quotes.
@@ -45,10 +47,56 @@ exports.getRelayQuotes = getRelayQuotes;
45
47
  async function getQuoteWithMaxAmountHandling(request, fullRequest) {
46
48
  const { isMaxAmount } = request;
47
49
  if (!isMaxAmount) {
48
- return getSingleQuote(request, fullRequest);
50
+ return getQuoteWithPostQuoteGasHandling(request, fullRequest);
49
51
  }
50
52
  return (0, relay_max_gas_station_1.getRelayMaxGasStationQuote)(request, fullRequest, getSingleQuote);
51
53
  }
54
+ /**
55
+ * For post-quote flows, fetch an initial quote to compute gas cost in source
56
+ * token, then re-quote with the source amount reduced by the gas cost.
57
+ * This ensures Relay reserves enough for the gas fee token payment.
58
+ *
59
+ * For non-post-quote flows, just returns a single quote.
60
+ *
61
+ * @param request - Quote request.
62
+ * @param fullRequest - Full request context.
63
+ * @returns The final quote (phase 2 for post-quote, or phase 1 for normal).
64
+ */
65
+ async function getQuoteWithPostQuoteGasHandling(request, fullRequest) {
66
+ const phase1Quote = await getSingleQuote(request, fullRequest);
67
+ if (!request.isPostQuote || !phase1Quote.fees.isSourceGasFeeToken) {
68
+ return phase1Quote;
69
+ }
70
+ const gasCostRaw = phase1Quote.fees.sourceNetwork.max.raw;
71
+ const adjustedSourceAmount = new bignumber_js_1.BigNumber(request.sourceTokenAmount)
72
+ .minus(gasCostRaw)
73
+ .integerValue(bignumber_js_1.BigNumber.ROUND_DOWN);
74
+ log('Subtracting gas from source for post-quote two-call', {
75
+ originalSourceAmount: request.sourceTokenAmount,
76
+ gasCostRaw,
77
+ adjustedSourceAmount: adjustedSourceAmount.toString(10),
78
+ });
79
+ if (!adjustedSourceAmount.isGreaterThan(0)) {
80
+ log('Insufficient balance after gas subtraction for post-quote, using phase 1');
81
+ return phase1Quote;
82
+ }
83
+ try {
84
+ const phase2Quote = await getSingleQuote({
85
+ ...request,
86
+ sourceTokenAmount: adjustedSourceAmount.toFixed(0, bignumber_js_1.BigNumber.ROUND_DOWN),
87
+ }, fullRequest);
88
+ if (phase1Quote.fees.isSourceGasFeeToken &&
89
+ !phase2Quote.fees.isSourceGasFeeToken) {
90
+ log('Phase 2 lost gas fee token eligibility, falling back to phase 1');
91
+ return phase1Quote;
92
+ }
93
+ return phase2Quote;
94
+ }
95
+ catch (error) {
96
+ log('Phase 2 quote failed, falling back to phase 1', { error });
97
+ return phase1Quote;
98
+ }
99
+ }
52
100
  /**
53
101
  * Fetches a single Relay quote.
54
102
  *
@@ -67,12 +115,17 @@ async function getSingleQuote(request, fullRequest) {
67
115
  // For regular flows with a target amount, use EXPECTED_OUTPUT.
68
116
  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
69
117
  const useExactInput = isMaxAmount || request.isPostQuote;
118
+ const useExecute = (0, feature_flags_1.isRelayExecuteEnabled)(messenger) &&
119
+ (0, feature_flags_1.isEIP7702Chain)(messenger, sourceChainId);
70
120
  const body = {
71
121
  amount: useExactInput ? sourceTokenAmount : targetAmountMinimum,
72
122
  destinationChainId: Number(targetChainId),
73
123
  destinationCurrency: targetTokenAddress,
74
124
  originChainId: Number(sourceChainId),
75
125
  originCurrency: sourceTokenAddress,
126
+ ...(useExecute
127
+ ? { originGasOverhead: (0, feature_flags_1.getRelayOriginGasOverhead)(messenger) }
128
+ : {}),
76
129
  recipient: from,
77
130
  slippageTolerance,
78
131
  tradeType: useExactInput ? 'EXACT_INPUT' : 'EXPECTED_OUTPUT',
@@ -89,15 +142,8 @@ async function getSingleQuote(request, fullRequest) {
89
142
  // Safe proxy) rather than defaulting to the EOA.
90
143
  body.refundTo = request.refundTo;
91
144
  }
92
- const url = (0, feature_flags_1.getFeatureFlags)(messenger).relayQuoteUrl;
93
- log('Request body', { body, url });
94
- const response = await (0, controller_utils_1.successfulFetch)(url, {
95
- method: 'POST',
96
- headers: { 'Content-Type': 'application/json' },
97
- body: JSON.stringify(body),
98
- });
99
- const quote = (await response.json());
100
- quote.request = body;
145
+ log('Request body', body);
146
+ const quote = await (0, relay_api_1.fetchRelayQuote)(messenger, body);
101
147
  log('Fetched relay quote', quote);
102
148
  return await normalizeQuote(quote, request, fullRequest);
103
149
  }
@@ -239,6 +285,7 @@ async function normalizeQuote(quote, request, fullRequest) {
239
285
  const targetAmountUsd = baseTargetAmountUsd.plus(additionalTargetAmountUsd);
240
286
  const targetAmount = (0, amounts_1.getFiatValueFromUsd)(targetAmountUsd, usdToFiatRate);
241
287
  const metamask = {
288
+ ...quote.metamask,
242
289
  gasLimits,
243
290
  };
244
291
  return {
@@ -305,6 +352,9 @@ function getFiatRates(messenger, request) {
305
352
  * transaction's params so that gas estimation and gas-fee-token logic handle
306
353
  * both transactions together.
307
354
  *
355
+ * When the execute flow is active (indicated by `quote.metamask.isExecute`),
356
+ * network fees are zeroed because the relayer covers them.
357
+ *
308
358
  * @param quote - Relay quote.
309
359
  * @param messenger - Controller messenger.
310
360
  * @param request - Quote request.
@@ -313,11 +363,21 @@ function getFiatRates(messenger, request) {
313
363
  */
314
364
  async function calculateSourceNetworkCost(quote, messenger, request, transaction) {
315
365
  const { from, sourceChainId, sourceTokenAddress } = request;
366
+ if (quote.metamask?.isExecute) {
367
+ log('Zeroing network fees for execute flow');
368
+ const zeroAmount = { fiat: '0', human: '0', raw: '0', usd: '0' };
369
+ return { estimate: zeroAmount, max: zeroAmount, gasLimits: [] };
370
+ }
316
371
  const relayParams = quote.steps
317
372
  .flatMap((step) => step.items)
318
373
  .map((item) => item.data);
319
374
  const { chainId, data, maxFeePerGas, maxPriorityFeePerGas, to, value } = relayParams[0];
320
- const { totalGasEstimate, totalGasLimit, gasLimits } = await calculateSourceNetworkGasLimit(relayParams, messenger, request.isPostQuote ? transaction : undefined);
375
+ const isPredictWithdraw = request.isPostQuote && (0, transaction_1.isPredictWithdrawTransaction)(transaction);
376
+ const fromOverride = isPredictWithdraw ? request.refundTo : undefined;
377
+ const relayOnlyGas = await calculateSourceNetworkGasLimit(relayParams, messenger, fromOverride);
378
+ const { totalGasEstimate, totalGasLimit, gasLimits } = request.isPostQuote
379
+ ? combinePostQuoteGas(relayOnlyGas, transaction)
380
+ : relayOnlyGas;
321
381
  log('Gas limit', {
322
382
  totalGasEstimate,
323
383
  totalGasLimit,
@@ -360,6 +420,40 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
360
420
  nativeBalance,
361
421
  max: max.raw,
362
422
  });
423
+ if (isPredictWithdraw && request.refundTo) {
424
+ log('Using proxy address for predict withdraw gas station simulation', {
425
+ proxyAddress: request.refundTo,
426
+ sourceTokenAddress,
427
+ totalGasEstimate,
428
+ });
429
+ const gasFeeTokenCost = await (0, gas_station_1.getGasStationCostInSourceTokenRaw)({
430
+ firstStepData: {
431
+ data,
432
+ to,
433
+ value,
434
+ },
435
+ messenger,
436
+ request: {
437
+ from: request.refundTo,
438
+ sourceChainId,
439
+ sourceTokenAddress,
440
+ },
441
+ totalGasEstimate,
442
+ totalItemCount: relayParams.length + 1,
443
+ });
444
+ if (gasFeeTokenCost) {
445
+ log('Using predict withdraw gas fee token for source network', {
446
+ gasFeeTokenCost,
447
+ });
448
+ return {
449
+ isGasFeeToken: true,
450
+ estimate: gasFeeTokenCost,
451
+ max: gasFeeTokenCost,
452
+ gasLimits,
453
+ };
454
+ }
455
+ return result;
456
+ }
363
457
  const gasFeeTokenCost = await (0, gas_station_1.getGasStationCostInSourceTokenRaw)({
364
458
  firstStepData: {
365
459
  data,
@@ -391,24 +485,17 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
391
485
  /**
392
486
  * Calculate the total gas limit for the source network.
393
487
  *
394
- * For post-quote flows (e.g. predict withdrawals), the original transaction's
395
- * gas is combined with the relay gas so that source network cost accounts for
396
- * both the user's transaction and the relay transactions.
397
- *
398
488
  * @param params - Array of relay transaction parameters.
399
489
  * @param messenger - Controller messenger.
400
- * @param postQuoteTransaction - Original transaction for post-quote flows.
401
- * When provided, its gas is included in the returned totals.
490
+ * @param fromOverride - Optional address to use as `from` in gas estimation
491
+ * instead of the address in the relay params. Used in predict withdraw flows
492
+ * to estimate with the proxy/Safe address that holds the source token balance.
402
493
  * @returns Total gas estimates and per-transaction gas limits.
403
494
  */
404
- async function calculateSourceNetworkGasLimit(params, messenger, postQuoteTransaction) {
405
- const relayGas = params.length === 1
406
- ? await calculateSourceNetworkGasLimitSingle(params[0], messenger)
407
- : await calculateSourceNetworkGasLimitBatch(params, messenger);
408
- if (!postQuoteTransaction?.txParams.to) {
409
- return relayGas;
410
- }
411
- return combinePostQuoteGas(relayGas, postQuoteTransaction);
495
+ async function calculateSourceNetworkGasLimit(params, messenger, fromOverride) {
496
+ return params.length === 1
497
+ ? calculateSourceNetworkGasLimitSingle(params[0], messenger, fromOverride)
498
+ : calculateSourceNetworkGasLimitBatch(params, messenger, fromOverride);
412
499
  }
413
500
  /**
414
501
  * Combine the original transaction's gas with relay gas for post-quote flows.
@@ -486,11 +573,11 @@ function getTransferRecipient(data) {
486
573
  .decodeFunctionData('transfer', data)
487
574
  .to.toLowerCase();
488
575
  }
489
- async function calculateSourceNetworkGasLimitSingle(params, messenger) {
576
+ async function calculateSourceNetworkGasLimitSingle(params, messenger, fromOverride) {
490
577
  const paramGasLimit = params.gas
491
578
  ? new bignumber_js_1.BigNumber(params.gas).toNumber()
492
579
  : undefined;
493
- if (paramGasLimit) {
580
+ if (paramGasLimit && !fromOverride) {
494
581
  log('Using single gas limit from params', { paramGasLimit });
495
582
  return {
496
583
  totalGasEstimate: paramGasLimit,
@@ -499,7 +586,8 @@ async function calculateSourceNetworkGasLimitSingle(params, messenger) {
499
586
  };
500
587
  }
501
588
  try {
502
- const { chainId: chainIdNumber, data, from, to, value: valueString, } = params;
589
+ const { chainId: chainIdNumber, data, from: paramsFrom, to, value: valueString, } = params;
590
+ const from = fromOverride ?? paramsFrom;
503
591
  const chainId = (0, controller_utils_1.toHex)(chainIdNumber);
504
592
  const value = (0, controller_utils_1.toHex)(valueString ?? '0');
505
593
  const gasBuffer = (0, feature_flags_1.getGasBuffer)(messenger, chainId);
@@ -537,16 +625,20 @@ async function calculateSourceNetworkGasLimitSingle(params, messenger) {
537
625
  *
538
626
  * @param params - Array of transaction parameters.
539
627
  * @param messenger - Controller messenger.
628
+ * @param fromOverride - Optional address to use as `from` in gas estimation.
540
629
  * @returns - Gas limits.
541
630
  */
542
- async function calculateSourceNetworkGasLimitBatch(params, messenger) {
631
+ async function calculateSourceNetworkGasLimitBatch(params, messenger, fromOverride) {
543
632
  try {
544
- const { chainId: chainIdNumber, from } = params[0];
633
+ const { chainId: chainIdNumber, from: paramsFrom } = params[0];
634
+ const from = fromOverride ?? paramsFrom;
545
635
  const chainId = (0, controller_utils_1.toHex)(chainIdNumber);
546
636
  const gasBuffer = (0, feature_flags_1.getGasBuffer)(messenger, chainId);
547
637
  const transactions = params.map((singleParams) => ({
548
638
  ...singleParams,
549
- gas: singleParams.gas ? (0, controller_utils_1.toHex)(singleParams.gas) : undefined,
639
+ gas: !fromOverride && singleParams.gas
640
+ ? (0, controller_utils_1.toHex)(singleParams.gas)
641
+ : undefined,
550
642
  maxFeePerGas: undefined,
551
643
  maxPriorityFeePerGas: undefined,
552
644
  value: (0, controller_utils_1.toHex)(singleParams.value ?? '0'),