@metamask-previews/transaction-pay-controller 26.1.0-preview-d2f661012 → 26.1.1-preview-5a03e1b92

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 (34) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/dist/strategy/relay/relay-validation.cjs +36 -23
  3. package/dist/strategy/relay/relay-validation.cjs.map +1 -1
  4. package/dist/strategy/relay/relay-validation.d.cts.map +1 -1
  5. package/dist/strategy/relay/relay-validation.d.mts.map +1 -1
  6. package/dist/strategy/relay/relay-validation.mjs +37 -24
  7. package/dist/strategy/relay/relay-validation.mjs.map +1 -1
  8. package/dist/utils/feature-flags.cjs +16 -1
  9. package/dist/utils/feature-flags.cjs.map +1 -1
  10. package/dist/utils/feature-flags.d.cts +9 -0
  11. package/dist/utils/feature-flags.d.cts.map +1 -1
  12. package/dist/utils/feature-flags.d.mts +9 -0
  13. package/dist/utils/feature-flags.d.mts.map +1 -1
  14. package/dist/utils/feature-flags.mjs +14 -0
  15. package/dist/utils/feature-flags.mjs.map +1 -1
  16. package/dist/utils/quotes.cjs +14 -1
  17. package/dist/utils/quotes.cjs.map +1 -1
  18. package/dist/utils/quotes.mjs +14 -1
  19. package/dist/utils/quotes.mjs.map +1 -1
  20. package/dist/utils/simulation.cjs +40 -1
  21. package/dist/utils/simulation.cjs.map +1 -1
  22. package/dist/utils/simulation.d.cts.map +1 -1
  23. package/dist/utils/simulation.d.mts.map +1 -1
  24. package/dist/utils/simulation.mjs +40 -1
  25. package/dist/utils/simulation.mjs.map +1 -1
  26. package/dist/utils/validation.cjs +2 -1
  27. package/dist/utils/validation.cjs.map +1 -1
  28. package/dist/utils/validation.d.cts +2 -1
  29. package/dist/utils/validation.d.cts.map +1 -1
  30. package/dist/utils/validation.d.mts +2 -1
  31. package/dist/utils/validation.d.mts.map +1 -1
  32. package/dist/utils/validation.mjs +2 -1
  33. package/dist/utils/validation.mjs.map +1 -1
  34. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Changed
11
+
12
+ - Bump `@metamask/assets-controller` from `^13.0.0` to `^13.1.0` ([#9743](https://github.com/MetaMask/core/pull/9743))
13
+ - Bump `@metamask/assets-controllers` from `^110.0.3` to `^110.1.0` ([#9743](https://github.com/MetaMask/core/pull/9743))
14
+
15
+ ### Fixed
16
+
17
+ - Fix Relay quote validation ([#9723](https://github.com/MetaMask/core/pull/9723))
18
+ - Keep the quote when validation fails with reason `insufficient-source-balance`, while still surfacing `quoteError`; all other validation-failure reasons continue to remove the quote.
19
+ - Exclude a zero `gas` value from the simulated transaction.
20
+ - Always include an EIP-7702 authorization in the batch simulation so a not-yet-upgraded account is simulated as delegated, using the quote authorization address when present and otherwise the configured EIP-7702 upgrade contract for the chain.
21
+ - Surface the revert return data as `Custom Error - <return>` when a Sentinel simulation reverts with `execution reverted` and non-empty return data, falling back to `Reverted - Unknown Error` when the return data is empty, instead of the implied `execution reverted` message.
22
+
23
+ ## [26.1.1]
24
+
25
+ ### Changed
26
+
27
+ - Bump `@metamask/assets-controller` from `^12.0.0` to `^13.0.0` ([#9740](https://github.com/MetaMask/core/pull/9740))
28
+
10
29
  ## [26.1.0]
11
30
 
12
31
  ### Added
@@ -1362,7 +1381,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1362
1381
 
1363
1382
  - Initial release ([#6820](https://github.com/MetaMask/core/pull/6820))
1364
1383
 
1365
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@26.1.0...HEAD
1384
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@26.1.1...HEAD
1385
+ [26.1.1]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@26.1.0...@metamask/transaction-pay-controller@26.1.1
1366
1386
  [26.1.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@26.0.1...@metamask/transaction-pay-controller@26.1.0
1367
1387
  [26.0.1]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@26.0.0...@metamask/transaction-pay-controller@26.0.1
1368
1388
  [26.0.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@25.1.1...@metamask/transaction-pay-controller@26.0.0
@@ -38,14 +38,21 @@ async function validateRelayQuotes(request) {
38
38
  messenger: request.messenger,
39
39
  quote,
40
40
  signal: request.signal,
41
- simulation: buildRelayValidationSimulation(quote, calls, executeRequest),
41
+ simulation: buildRelayValidationSimulation(request.messenger, quote, calls, executeRequest),
42
42
  });
43
43
  }
44
44
  catch (error) {
45
45
  if (request.signal?.aborted) {
46
46
  throw error;
47
47
  }
48
- throw toQuoteError(error);
48
+ const quoteError = toQuoteError(error);
49
+ if (quoteError.info.reason === 'insufficient-source-balance') {
50
+ // Backwards compatibility: keep the entire quote batch (including
51
+ // quotes that may have passed or not yet been validated) so that
52
+ // clients can still show quote details alongside the balance error.
53
+ throw new validation_js_1.QuoteError(quoteError.info, request.quotes);
54
+ }
55
+ throw quoteError;
49
56
  }
50
57
  }
51
58
  }
@@ -64,7 +71,7 @@ function toQuoteError(error) {
64
71
  detail: [error.message],
65
72
  });
66
73
  }
67
- function buildRelayValidationSimulation(quote, calls, executeRequest) {
74
+ function buildRelayValidationSimulation(messenger, quote, calls, executeRequest) {
68
75
  const { from, sourceChainId, targetChainId } = quote.request;
69
76
  const context = { from, sourceChainId, targetChainId };
70
77
  if (executeRequest) {
@@ -73,7 +80,7 @@ function buildRelayValidationSimulation(quote, calls, executeRequest) {
73
80
  }
74
81
  if (quote.original.metamask.is7702) {
75
82
  log('Building 7702 batch simulation', context);
76
- return buildRelay7702BatchSimulation(quote, calls);
83
+ return buildRelay7702BatchSimulation(messenger, quote, calls);
77
84
  }
78
85
  log('Building normal simulation', context);
79
86
  return buildRelayNormalSimulation(calls);
@@ -97,27 +104,30 @@ function buildRelayExecuteSimulation(quote, executeRequest) {
97
104
  ],
98
105
  };
99
106
  }
100
- function buildRelay7702BatchSimulation(quote, calls) {
101
- const { from } = quote.request;
107
+ function buildRelay7702BatchSimulation(messenger, quote, calls) {
108
+ const { from, sourceChainId } = quote.request;
102
109
  const gas = quote.original.metamask.gasLimits[0];
103
110
  const batchTx = (0, transaction_controller_1.generateEIP7702BatchTransaction)(from, calls.map((params) => ({
104
111
  to: params.to,
105
112
  data: params.data,
106
113
  value: params.value,
107
114
  })));
108
- const authList = quote.original.request.authorizationList?.length
109
- ? quote.original.request.authorizationList.map((auth) => ({
110
- address: auth.address,
111
- from,
112
- }))
113
- : undefined;
115
+ // The batch call is an ERC-7821 `execute` on the sender's own account, so the
116
+ // account must appear upgraded for the simulation to succeed. The quote does
117
+ // not always carry an authorization, and there is no fast way to check the
118
+ // live upgrade state, so an authorization is always included: the delegator
119
+ // address comes from the quote when present, otherwise from the configured
120
+ // EIP-7702 upgrade contract for the chain.
121
+ const address = quote.original.request.authorizationList?.[0]?.address ??
122
+ (0, feature_flags_js_1.getEIP7702UpgradeContractAddress)(messenger, sourceChainId);
123
+ const authorizationList = address ? [{ address, from }] : undefined;
114
124
  return {
115
125
  transactions: [
116
126
  {
117
- ...(authList ? { authorizationList: authList } : {}),
127
+ ...(authorizationList ? { authorizationList } : {}),
118
128
  data: batchTx.data,
119
129
  from,
120
- ...(gas === undefined ? {} : { gas: (0, controller_utils_1.toHex)(gas) }),
130
+ ...(gas === undefined || gas === 0 ? {} : { gas: (0, controller_utils_1.toHex)(gas) }),
121
131
  to: batchTx.to,
122
132
  value: '0x0',
123
133
  },
@@ -126,15 +136,18 @@ function buildRelay7702BatchSimulation(quote, calls) {
126
136
  }
127
137
  function buildRelayNormalSimulation(calls) {
128
138
  return {
129
- transactions: calls.map((params) => ({
130
- data: params.data,
131
- from: params.from,
132
- gas: params.gas,
133
- maxFeePerGas: params.maxFeePerGas,
134
- maxPriorityFeePerGas: params.maxPriorityFeePerGas,
135
- to: params.to,
136
- value: params.value,
137
- })),
139
+ transactions: calls.map((params) => {
140
+ const gas = params.gas;
141
+ return {
142
+ data: params.data,
143
+ from: params.from,
144
+ ...(gas === undefined || new bignumber_js_1.BigNumber(gas).isZero() ? {} : { gas }),
145
+ maxFeePerGas: params.maxFeePerGas,
146
+ maxPriorityFeePerGas: params.maxPriorityFeePerGas,
147
+ to: params.to,
148
+ value: params.value,
149
+ };
150
+ }),
138
151
  };
139
152
  }
140
153
  //# sourceMappingURL=relay-validation.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"relay-validation.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { generateEIP7702BatchTransaction } from '@metamask/transaction-controller';\nimport type {\n TransactionMeta,\n TransactionParams,\n} from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger.js';\nimport type {\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types.js';\nimport { isRelayValidationEnabled } from '../../utils/feature-flags.js';\nimport {\n validateQuoteExecution,\n QuoteError,\n isQuoteError,\n} from '../../utils/validation.js';\nimport type { QuoteSimulation } from '../../utils/validation.js';\nimport { getRelayExecuteRequest } from './relay-submit-execute.js';\nimport { getRelaySubmitCalls } from './relay-submit.js';\nimport type { RelayExecuteRequest, RelayQuote } from './types.js';\n\nconst log = createModuleLogger(projectLogger, 'relay-validation');\n\nexport type ValidateRelayQuotesRequest = {\n messenger: TransactionPayControllerMessenger;\n quotes: TransactionPayQuote<RelayQuote>[];\n signal?: AbortSignal;\n transaction: TransactionMeta;\n};\n\nexport async function validateRelayQuotes(\n request: ValidateRelayQuotesRequest,\n): Promise<void> {\n if (!isRelayValidationEnabled(request.messenger)) {\n return;\n }\n\n for (const quote of request.quotes) {\n if (shouldSkipValidation(quote)) {\n continue;\n }\n\n try {\n const { calls } = await getRelaySubmitCalls({\n messenger: request.messenger,\n quote,\n transaction: request.transaction,\n });\n\n const executeRequest = quote.original.metamask.isExecute\n ? await getRelayExecuteRequest({\n allParams: calls,\n messenger: request.messenger,\n quote,\n requestId: quote.original.steps[0].requestId,\n transaction: request.transaction,\n })\n : undefined;\n\n await validateQuoteExecution({\n messenger: request.messenger,\n quote,\n signal: request.signal,\n simulation: buildRelayValidationSimulation(\n quote,\n calls,\n executeRequest,\n ),\n });\n } catch (error) {\n if (request.signal?.aborted) {\n throw error;\n }\n throw toQuoteError(error);\n }\n }\n}\n\nfunction shouldSkipValidation(quote: TransactionPayQuote<RelayQuote>): boolean {\n const { request } = quote;\n return Boolean(\n request.isHyperliquidSource ?? request.isPolymarketDepositWallet ?? false,\n );\n}\n\nfunction toQuoteError(error: unknown): QuoteError {\n if (isQuoteError(error)) {\n return error;\n }\n return new QuoteError({\n message: 'Quote simulation failed',\n reason: 'simulation-failed',\n detail: [(error as Error).message],\n });\n}\n\nfunction buildRelayValidationSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n executeRequest?: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { from, sourceChainId, targetChainId } = quote.request;\n const context = { from, sourceChainId, targetChainId };\n\n if (executeRequest) {\n log('Building execute simulation', context);\n return buildRelayExecuteSimulation(quote, executeRequest);\n }\n if (quote.original.metamask.is7702) {\n log('Building 7702 batch simulation', context);\n return buildRelay7702BatchSimulation(quote, calls);\n }\n log('Building normal simulation', context);\n return buildRelayNormalSimulation(calls);\n}\n\nfunction buildRelayExecuteSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n executeRequest: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { value } = executeRequest.data;\n const valueHex = new BigNumber(value).toString(16).replace(/^/u, '0x') as Hex;\n return {\n transactions: [\n {\n ...(executeRequest.data.authorizationList?.length\n ? {\n authorizationList: executeRequest.data.authorizationList.map(\n (auth) => ({ address: auth.address, from: quote.request.from }),\n ),\n }\n : {}),\n data: executeRequest.data.data,\n from: quote.request.from,\n to: executeRequest.data.to,\n value: valueHex,\n },\n ],\n };\n}\n\nfunction buildRelay7702BatchSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n): QuoteSimulation {\n const { from } = quote.request;\n const gas = quote.original.metamask.gasLimits[0];\n\n const batchTx = generateEIP7702BatchTransaction(\n from,\n calls.map((params) => ({\n to: params.to as Hex,\n data: params.data as Hex,\n value: params.value as Hex,\n })),\n );\n\n const authList = quote.original.request.authorizationList?.length\n ? quote.original.request.authorizationList.map((auth) => ({\n address: auth.address,\n from,\n }))\n : undefined;\n\n return {\n transactions: [\n {\n ...(authList ? { authorizationList: authList } : {}),\n data: batchTx.data,\n from,\n ...(gas === undefined ? {} : { gas: toHex(gas) }),\n to: batchTx.to as Hex,\n value: '0x0',\n },\n ],\n };\n}\n\nfunction buildRelayNormalSimulation(\n calls: TransactionParams[],\n): QuoteSimulation {\n return {\n transactions: calls.map((params) => ({\n data: params.data as Hex | undefined,\n from: params.from as Hex,\n gas: params.gas as Hex | undefined,\n maxFeePerGas: params.maxFeePerGas as Hex | undefined,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas as Hex | undefined,\n to: params.to as Hex | undefined,\n value: params.value as Hex,\n })),\n };\n}\n"]}
1
+ {"version":3,"file":"relay-validation.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { generateEIP7702BatchTransaction } from '@metamask/transaction-controller';\nimport type {\n TransactionMeta,\n TransactionParams,\n} from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger.js';\nimport type {\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types.js';\nimport {\n getEIP7702UpgradeContractAddress,\n isRelayValidationEnabled,\n} from '../../utils/feature-flags.js';\nimport {\n validateQuoteExecution,\n QuoteError,\n isQuoteError,\n} from '../../utils/validation.js';\nimport type { QuoteSimulation } from '../../utils/validation.js';\nimport { getRelayExecuteRequest } from './relay-submit-execute.js';\nimport { getRelaySubmitCalls } from './relay-submit.js';\nimport type { RelayExecuteRequest, RelayQuote } from './types.js';\n\nconst log = createModuleLogger(projectLogger, 'relay-validation');\n\nexport type ValidateRelayQuotesRequest = {\n messenger: TransactionPayControllerMessenger;\n quotes: TransactionPayQuote<RelayQuote>[];\n signal?: AbortSignal;\n transaction: TransactionMeta;\n};\n\nexport async function validateRelayQuotes(\n request: ValidateRelayQuotesRequest,\n): Promise<void> {\n if (!isRelayValidationEnabled(request.messenger)) {\n return;\n }\n\n for (const quote of request.quotes) {\n if (shouldSkipValidation(quote)) {\n continue;\n }\n\n try {\n const { calls } = await getRelaySubmitCalls({\n messenger: request.messenger,\n quote,\n transaction: request.transaction,\n });\n\n const executeRequest = quote.original.metamask.isExecute\n ? await getRelayExecuteRequest({\n allParams: calls,\n messenger: request.messenger,\n quote,\n requestId: quote.original.steps[0].requestId,\n transaction: request.transaction,\n })\n : undefined;\n\n await validateQuoteExecution({\n messenger: request.messenger,\n quote,\n signal: request.signal,\n simulation: buildRelayValidationSimulation(\n request.messenger,\n quote,\n calls,\n executeRequest,\n ),\n });\n } catch (error) {\n if (request.signal?.aborted) {\n throw error;\n }\n const quoteError = toQuoteError(error);\n if (quoteError.info.reason === 'insufficient-source-balance') {\n // Backwards compatibility: keep the entire quote batch (including\n // quotes that may have passed or not yet been validated) so that\n // clients can still show quote details alongside the balance error.\n throw new QuoteError(\n quoteError.info,\n request.quotes as TransactionPayQuote<unknown>[],\n );\n }\n throw quoteError;\n }\n }\n}\n\nfunction shouldSkipValidation(quote: TransactionPayQuote<RelayQuote>): boolean {\n const { request } = quote;\n return Boolean(\n request.isHyperliquidSource ?? request.isPolymarketDepositWallet ?? false,\n );\n}\n\nfunction toQuoteError(error: unknown): QuoteError {\n if (isQuoteError(error)) {\n return error;\n }\n return new QuoteError({\n message: 'Quote simulation failed',\n reason: 'simulation-failed',\n detail: [(error as Error).message],\n });\n}\n\nfunction buildRelayValidationSimulation(\n messenger: TransactionPayControllerMessenger,\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n executeRequest?: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { from, sourceChainId, targetChainId } = quote.request;\n const context = { from, sourceChainId, targetChainId };\n\n if (executeRequest) {\n log('Building execute simulation', context);\n return buildRelayExecuteSimulation(quote, executeRequest);\n }\n if (quote.original.metamask.is7702) {\n log('Building 7702 batch simulation', context);\n return buildRelay7702BatchSimulation(messenger, quote, calls);\n }\n log('Building normal simulation', context);\n return buildRelayNormalSimulation(calls);\n}\n\nfunction buildRelayExecuteSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n executeRequest: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { value } = executeRequest.data;\n const valueHex = new BigNumber(value).toString(16).replace(/^/u, '0x') as Hex;\n return {\n transactions: [\n {\n ...(executeRequest.data.authorizationList?.length\n ? {\n authorizationList: executeRequest.data.authorizationList.map(\n (auth) => ({ address: auth.address, from: quote.request.from }),\n ),\n }\n : {}),\n data: executeRequest.data.data,\n from: quote.request.from,\n to: executeRequest.data.to,\n value: valueHex,\n },\n ],\n };\n}\n\nfunction buildRelay7702BatchSimulation(\n messenger: TransactionPayControllerMessenger,\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n): QuoteSimulation {\n const { from, sourceChainId } = quote.request;\n const gas = quote.original.metamask.gasLimits[0];\n\n const batchTx = generateEIP7702BatchTransaction(\n from,\n calls.map((params) => ({\n to: params.to as Hex,\n data: params.data as Hex,\n value: params.value as Hex,\n })),\n );\n\n // The batch call is an ERC-7821 `execute` on the sender's own account, so the\n // account must appear upgraded for the simulation to succeed. The quote does\n // not always carry an authorization, and there is no fast way to check the\n // live upgrade state, so an authorization is always included: the delegator\n // address comes from the quote when present, otherwise from the configured\n // EIP-7702 upgrade contract for the chain.\n const address =\n quote.original.request.authorizationList?.[0]?.address ??\n getEIP7702UpgradeContractAddress(messenger, sourceChainId);\n\n const authorizationList = address ? [{ address, from }] : undefined;\n\n return {\n transactions: [\n {\n ...(authorizationList ? { authorizationList } : {}),\n data: batchTx.data,\n from,\n ...(gas === undefined || gas === 0 ? {} : { gas: toHex(gas) }),\n to: batchTx.to as Hex,\n value: '0x0',\n },\n ],\n };\n}\n\nfunction buildRelayNormalSimulation(\n calls: TransactionParams[],\n): QuoteSimulation {\n return {\n transactions: calls.map((params) => {\n const gas = params.gas as Hex | undefined;\n return {\n data: params.data as Hex | undefined,\n from: params.from as Hex,\n ...(gas === undefined || new BigNumber(gas).isZero() ? {} : { gas }),\n maxFeePerGas: params.maxFeePerGas as Hex | undefined,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas as Hex | undefined,\n to: params.to as Hex | undefined,\n value: params.value as Hex,\n };\n }),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"relay-validation.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAEhB,yCAAyC;AAM1C,OAAO,KAAK,EACV,iCAAiC,EACjC,mBAAmB,EACpB,wBAAuB;AAUxB,OAAO,KAAK,EAAuB,UAAU,EAAE,oBAAmB;AAIlE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,iCAAiC,CAAC;IAC7C,MAAM,EAAE,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
1
+ {"version":3,"file":"relay-validation.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAEhB,yCAAyC;AAM1C,OAAO,KAAK,EACV,iCAAiC,EACjC,mBAAmB,EACpB,wBAAuB;AAaxB,OAAO,KAAK,EAAuB,UAAU,EAAE,oBAAmB;AAIlE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,iCAAiC,CAAC;IAC7C,MAAM,EAAE,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAuDf"}
@@ -1 +1 @@
1
- {"version":3,"file":"relay-validation.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAEhB,yCAAyC;AAM1C,OAAO,KAAK,EACV,iCAAiC,EACjC,mBAAmB,EACpB,wBAAuB;AAUxB,OAAO,KAAK,EAAuB,UAAU,EAAE,oBAAmB;AAIlE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,iCAAiC,CAAC;IAC7C,MAAM,EAAE,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
1
+ {"version":3,"file":"relay-validation.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAEhB,yCAAyC;AAM1C,OAAO,KAAK,EACV,iCAAiC,EACjC,mBAAmB,EACpB,wBAAuB;AAaxB,OAAO,KAAK,EAAuB,UAAU,EAAE,oBAAmB;AAIlE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,iCAAiC,CAAC;IAC7C,MAAM,EAAE,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAuDf"}
@@ -3,7 +3,7 @@ import { generateEIP7702BatchTransaction } from "@metamask/transaction-controlle
3
3
  import { createModuleLogger } from "@metamask/utils";
4
4
  import { BigNumber } from "bignumber.js";
5
5
  import { projectLogger } from "../../logger.mjs";
6
- import { isRelayValidationEnabled } from "../../utils/feature-flags.mjs";
6
+ import { getEIP7702UpgradeContractAddress, isRelayValidationEnabled } from "../../utils/feature-flags.mjs";
7
7
  import { validateQuoteExecution, QuoteError, isQuoteError } from "../../utils/validation.mjs";
8
8
  import { getRelayExecuteRequest } from "./relay-submit-execute.mjs";
9
9
  import { getRelaySubmitCalls } from "./relay-submit.mjs";
@@ -35,14 +35,21 @@ export async function validateRelayQuotes(request) {
35
35
  messenger: request.messenger,
36
36
  quote,
37
37
  signal: request.signal,
38
- simulation: buildRelayValidationSimulation(quote, calls, executeRequest),
38
+ simulation: buildRelayValidationSimulation(request.messenger, quote, calls, executeRequest),
39
39
  });
40
40
  }
41
41
  catch (error) {
42
42
  if (request.signal?.aborted) {
43
43
  throw error;
44
44
  }
45
- throw toQuoteError(error);
45
+ const quoteError = toQuoteError(error);
46
+ if (quoteError.info.reason === 'insufficient-source-balance') {
47
+ // Backwards compatibility: keep the entire quote batch (including
48
+ // quotes that may have passed or not yet been validated) so that
49
+ // clients can still show quote details alongside the balance error.
50
+ throw new QuoteError(quoteError.info, request.quotes);
51
+ }
52
+ throw quoteError;
46
53
  }
47
54
  }
48
55
  }
@@ -60,7 +67,7 @@ function toQuoteError(error) {
60
67
  detail: [error.message],
61
68
  });
62
69
  }
63
- function buildRelayValidationSimulation(quote, calls, executeRequest) {
70
+ function buildRelayValidationSimulation(messenger, quote, calls, executeRequest) {
64
71
  const { from, sourceChainId, targetChainId } = quote.request;
65
72
  const context = { from, sourceChainId, targetChainId };
66
73
  if (executeRequest) {
@@ -69,7 +76,7 @@ function buildRelayValidationSimulation(quote, calls, executeRequest) {
69
76
  }
70
77
  if (quote.original.metamask.is7702) {
71
78
  log('Building 7702 batch simulation', context);
72
- return buildRelay7702BatchSimulation(quote, calls);
79
+ return buildRelay7702BatchSimulation(messenger, quote, calls);
73
80
  }
74
81
  log('Building normal simulation', context);
75
82
  return buildRelayNormalSimulation(calls);
@@ -93,27 +100,30 @@ function buildRelayExecuteSimulation(quote, executeRequest) {
93
100
  ],
94
101
  };
95
102
  }
96
- function buildRelay7702BatchSimulation(quote, calls) {
97
- const { from } = quote.request;
103
+ function buildRelay7702BatchSimulation(messenger, quote, calls) {
104
+ const { from, sourceChainId } = quote.request;
98
105
  const gas = quote.original.metamask.gasLimits[0];
99
106
  const batchTx = generateEIP7702BatchTransaction(from, calls.map((params) => ({
100
107
  to: params.to,
101
108
  data: params.data,
102
109
  value: params.value,
103
110
  })));
104
- const authList = quote.original.request.authorizationList?.length
105
- ? quote.original.request.authorizationList.map((auth) => ({
106
- address: auth.address,
107
- from,
108
- }))
109
- : undefined;
111
+ // The batch call is an ERC-7821 `execute` on the sender's own account, so the
112
+ // account must appear upgraded for the simulation to succeed. The quote does
113
+ // not always carry an authorization, and there is no fast way to check the
114
+ // live upgrade state, so an authorization is always included: the delegator
115
+ // address comes from the quote when present, otherwise from the configured
116
+ // EIP-7702 upgrade contract for the chain.
117
+ const address = quote.original.request.authorizationList?.[0]?.address ??
118
+ getEIP7702UpgradeContractAddress(messenger, sourceChainId);
119
+ const authorizationList = address ? [{ address, from }] : undefined;
110
120
  return {
111
121
  transactions: [
112
122
  {
113
- ...(authList ? { authorizationList: authList } : {}),
123
+ ...(authorizationList ? { authorizationList } : {}),
114
124
  data: batchTx.data,
115
125
  from,
116
- ...(gas === undefined ? {} : { gas: toHex(gas) }),
126
+ ...(gas === undefined || gas === 0 ? {} : { gas: toHex(gas) }),
117
127
  to: batchTx.to,
118
128
  value: '0x0',
119
129
  },
@@ -122,15 +132,18 @@ function buildRelay7702BatchSimulation(quote, calls) {
122
132
  }
123
133
  function buildRelayNormalSimulation(calls) {
124
134
  return {
125
- transactions: calls.map((params) => ({
126
- data: params.data,
127
- from: params.from,
128
- gas: params.gas,
129
- maxFeePerGas: params.maxFeePerGas,
130
- maxPriorityFeePerGas: params.maxPriorityFeePerGas,
131
- to: params.to,
132
- value: params.value,
133
- })),
135
+ transactions: calls.map((params) => {
136
+ const gas = params.gas;
137
+ return {
138
+ data: params.data,
139
+ from: params.from,
140
+ ...(gas === undefined || new BigNumber(gas).isZero() ? {} : { gas }),
141
+ maxFeePerGas: params.maxFeePerGas,
142
+ maxPriorityFeePerGas: params.maxPriorityFeePerGas,
143
+ to: params.to,
144
+ value: params.value,
145
+ };
146
+ }),
134
147
  };
135
148
  }
136
149
  //# sourceMappingURL=relay-validation.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"relay-validation.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { generateEIP7702BatchTransaction } from '@metamask/transaction-controller';\nimport type {\n TransactionMeta,\n TransactionParams,\n} from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger.js';\nimport type {\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types.js';\nimport { isRelayValidationEnabled } from '../../utils/feature-flags.js';\nimport {\n validateQuoteExecution,\n QuoteError,\n isQuoteError,\n} from '../../utils/validation.js';\nimport type { QuoteSimulation } from '../../utils/validation.js';\nimport { getRelayExecuteRequest } from './relay-submit-execute.js';\nimport { getRelaySubmitCalls } from './relay-submit.js';\nimport type { RelayExecuteRequest, RelayQuote } from './types.js';\n\nconst log = createModuleLogger(projectLogger, 'relay-validation');\n\nexport type ValidateRelayQuotesRequest = {\n messenger: TransactionPayControllerMessenger;\n quotes: TransactionPayQuote<RelayQuote>[];\n signal?: AbortSignal;\n transaction: TransactionMeta;\n};\n\nexport async function validateRelayQuotes(\n request: ValidateRelayQuotesRequest,\n): Promise<void> {\n if (!isRelayValidationEnabled(request.messenger)) {\n return;\n }\n\n for (const quote of request.quotes) {\n if (shouldSkipValidation(quote)) {\n continue;\n }\n\n try {\n const { calls } = await getRelaySubmitCalls({\n messenger: request.messenger,\n quote,\n transaction: request.transaction,\n });\n\n const executeRequest = quote.original.metamask.isExecute\n ? await getRelayExecuteRequest({\n allParams: calls,\n messenger: request.messenger,\n quote,\n requestId: quote.original.steps[0].requestId,\n transaction: request.transaction,\n })\n : undefined;\n\n await validateQuoteExecution({\n messenger: request.messenger,\n quote,\n signal: request.signal,\n simulation: buildRelayValidationSimulation(\n quote,\n calls,\n executeRequest,\n ),\n });\n } catch (error) {\n if (request.signal?.aborted) {\n throw error;\n }\n throw toQuoteError(error);\n }\n }\n}\n\nfunction shouldSkipValidation(quote: TransactionPayQuote<RelayQuote>): boolean {\n const { request } = quote;\n return Boolean(\n request.isHyperliquidSource ?? request.isPolymarketDepositWallet ?? false,\n );\n}\n\nfunction toQuoteError(error: unknown): QuoteError {\n if (isQuoteError(error)) {\n return error;\n }\n return new QuoteError({\n message: 'Quote simulation failed',\n reason: 'simulation-failed',\n detail: [(error as Error).message],\n });\n}\n\nfunction buildRelayValidationSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n executeRequest?: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { from, sourceChainId, targetChainId } = quote.request;\n const context = { from, sourceChainId, targetChainId };\n\n if (executeRequest) {\n log('Building execute simulation', context);\n return buildRelayExecuteSimulation(quote, executeRequest);\n }\n if (quote.original.metamask.is7702) {\n log('Building 7702 batch simulation', context);\n return buildRelay7702BatchSimulation(quote, calls);\n }\n log('Building normal simulation', context);\n return buildRelayNormalSimulation(calls);\n}\n\nfunction buildRelayExecuteSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n executeRequest: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { value } = executeRequest.data;\n const valueHex = new BigNumber(value).toString(16).replace(/^/u, '0x') as Hex;\n return {\n transactions: [\n {\n ...(executeRequest.data.authorizationList?.length\n ? {\n authorizationList: executeRequest.data.authorizationList.map(\n (auth) => ({ address: auth.address, from: quote.request.from }),\n ),\n }\n : {}),\n data: executeRequest.data.data,\n from: quote.request.from,\n to: executeRequest.data.to,\n value: valueHex,\n },\n ],\n };\n}\n\nfunction buildRelay7702BatchSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n): QuoteSimulation {\n const { from } = quote.request;\n const gas = quote.original.metamask.gasLimits[0];\n\n const batchTx = generateEIP7702BatchTransaction(\n from,\n calls.map((params) => ({\n to: params.to as Hex,\n data: params.data as Hex,\n value: params.value as Hex,\n })),\n );\n\n const authList = quote.original.request.authorizationList?.length\n ? quote.original.request.authorizationList.map((auth) => ({\n address: auth.address,\n from,\n }))\n : undefined;\n\n return {\n transactions: [\n {\n ...(authList ? { authorizationList: authList } : {}),\n data: batchTx.data,\n from,\n ...(gas === undefined ? {} : { gas: toHex(gas) }),\n to: batchTx.to as Hex,\n value: '0x0',\n },\n ],\n };\n}\n\nfunction buildRelayNormalSimulation(\n calls: TransactionParams[],\n): QuoteSimulation {\n return {\n transactions: calls.map((params) => ({\n data: params.data as Hex | undefined,\n from: params.from as Hex,\n gas: params.gas as Hex | undefined,\n maxFeePerGas: params.maxFeePerGas as Hex | undefined,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas as Hex | undefined,\n to: params.to as Hex | undefined,\n value: params.value as Hex,\n })),\n };\n}\n"]}
1
+ {"version":3,"file":"relay-validation.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { generateEIP7702BatchTransaction } from '@metamask/transaction-controller';\nimport type {\n TransactionMeta,\n TransactionParams,\n} from '@metamask/transaction-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { projectLogger } from '../../logger.js';\nimport type {\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types.js';\nimport {\n getEIP7702UpgradeContractAddress,\n isRelayValidationEnabled,\n} from '../../utils/feature-flags.js';\nimport {\n validateQuoteExecution,\n QuoteError,\n isQuoteError,\n} from '../../utils/validation.js';\nimport type { QuoteSimulation } from '../../utils/validation.js';\nimport { getRelayExecuteRequest } from './relay-submit-execute.js';\nimport { getRelaySubmitCalls } from './relay-submit.js';\nimport type { RelayExecuteRequest, RelayQuote } from './types.js';\n\nconst log = createModuleLogger(projectLogger, 'relay-validation');\n\nexport type ValidateRelayQuotesRequest = {\n messenger: TransactionPayControllerMessenger;\n quotes: TransactionPayQuote<RelayQuote>[];\n signal?: AbortSignal;\n transaction: TransactionMeta;\n};\n\nexport async function validateRelayQuotes(\n request: ValidateRelayQuotesRequest,\n): Promise<void> {\n if (!isRelayValidationEnabled(request.messenger)) {\n return;\n }\n\n for (const quote of request.quotes) {\n if (shouldSkipValidation(quote)) {\n continue;\n }\n\n try {\n const { calls } = await getRelaySubmitCalls({\n messenger: request.messenger,\n quote,\n transaction: request.transaction,\n });\n\n const executeRequest = quote.original.metamask.isExecute\n ? await getRelayExecuteRequest({\n allParams: calls,\n messenger: request.messenger,\n quote,\n requestId: quote.original.steps[0].requestId,\n transaction: request.transaction,\n })\n : undefined;\n\n await validateQuoteExecution({\n messenger: request.messenger,\n quote,\n signal: request.signal,\n simulation: buildRelayValidationSimulation(\n request.messenger,\n quote,\n calls,\n executeRequest,\n ),\n });\n } catch (error) {\n if (request.signal?.aborted) {\n throw error;\n }\n const quoteError = toQuoteError(error);\n if (quoteError.info.reason === 'insufficient-source-balance') {\n // Backwards compatibility: keep the entire quote batch (including\n // quotes that may have passed or not yet been validated) so that\n // clients can still show quote details alongside the balance error.\n throw new QuoteError(\n quoteError.info,\n request.quotes as TransactionPayQuote<unknown>[],\n );\n }\n throw quoteError;\n }\n }\n}\n\nfunction shouldSkipValidation(quote: TransactionPayQuote<RelayQuote>): boolean {\n const { request } = quote;\n return Boolean(\n request.isHyperliquidSource ?? request.isPolymarketDepositWallet ?? false,\n );\n}\n\nfunction toQuoteError(error: unknown): QuoteError {\n if (isQuoteError(error)) {\n return error;\n }\n return new QuoteError({\n message: 'Quote simulation failed',\n reason: 'simulation-failed',\n detail: [(error as Error).message],\n });\n}\n\nfunction buildRelayValidationSimulation(\n messenger: TransactionPayControllerMessenger,\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n executeRequest?: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { from, sourceChainId, targetChainId } = quote.request;\n const context = { from, sourceChainId, targetChainId };\n\n if (executeRequest) {\n log('Building execute simulation', context);\n return buildRelayExecuteSimulation(quote, executeRequest);\n }\n if (quote.original.metamask.is7702) {\n log('Building 7702 batch simulation', context);\n return buildRelay7702BatchSimulation(messenger, quote, calls);\n }\n log('Building normal simulation', context);\n return buildRelayNormalSimulation(calls);\n}\n\nfunction buildRelayExecuteSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n executeRequest: Omit<RelayExecuteRequest, 'metamask'>,\n): QuoteSimulation {\n const { value } = executeRequest.data;\n const valueHex = new BigNumber(value).toString(16).replace(/^/u, '0x') as Hex;\n return {\n transactions: [\n {\n ...(executeRequest.data.authorizationList?.length\n ? {\n authorizationList: executeRequest.data.authorizationList.map(\n (auth) => ({ address: auth.address, from: quote.request.from }),\n ),\n }\n : {}),\n data: executeRequest.data.data,\n from: quote.request.from,\n to: executeRequest.data.to,\n value: valueHex,\n },\n ],\n };\n}\n\nfunction buildRelay7702BatchSimulation(\n messenger: TransactionPayControllerMessenger,\n quote: TransactionPayQuote<RelayQuote>,\n calls: TransactionParams[],\n): QuoteSimulation {\n const { from, sourceChainId } = quote.request;\n const gas = quote.original.metamask.gasLimits[0];\n\n const batchTx = generateEIP7702BatchTransaction(\n from,\n calls.map((params) => ({\n to: params.to as Hex,\n data: params.data as Hex,\n value: params.value as Hex,\n })),\n );\n\n // The batch call is an ERC-7821 `execute` on the sender's own account, so the\n // account must appear upgraded for the simulation to succeed. The quote does\n // not always carry an authorization, and there is no fast way to check the\n // live upgrade state, so an authorization is always included: the delegator\n // address comes from the quote when present, otherwise from the configured\n // EIP-7702 upgrade contract for the chain.\n const address =\n quote.original.request.authorizationList?.[0]?.address ??\n getEIP7702UpgradeContractAddress(messenger, sourceChainId);\n\n const authorizationList = address ? [{ address, from }] : undefined;\n\n return {\n transactions: [\n {\n ...(authorizationList ? { authorizationList } : {}),\n data: batchTx.data,\n from,\n ...(gas === undefined || gas === 0 ? {} : { gas: toHex(gas) }),\n to: batchTx.to as Hex,\n value: '0x0',\n },\n ],\n };\n}\n\nfunction buildRelayNormalSimulation(\n calls: TransactionParams[],\n): QuoteSimulation {\n return {\n transactions: calls.map((params) => {\n const gas = params.gas as Hex | undefined;\n return {\n data: params.data as Hex | undefined,\n from: params.from as Hex,\n ...(gas === undefined || new BigNumber(gas).isZero() ? {} : { gas }),\n maxFeePerGas: params.maxFeePerGas as Hex | undefined,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas as Hex | undefined,\n to: params.to as Hex | undefined,\n value: params.value as Hex,\n };\n }),\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isEIP7702Chain = exports.getHyperliquidActivationFeeConfig = exports.getFiatOrderPollTimeoutMs = exports.getFiatOrderPollIntervalMs = exports.getFiatVaultDisabled = exports.getDirectMoneyMusdEnabled = exports.getFiatMaxRateDriftPercent = exports.getFiatFeeReserveMultiplier = exports.getFiatEnabledTypes = exports.getFiatAssetPerTransactionType = exports.getAssetsUnifyStateFeature = exports.getSlippage = exports.getGasBuffer = exports.getFallbackGas = exports.getServerPollingTimeout = exports.getServerPollingInterval = exports.getRelayPollingTimeout = exports.getRelayPollingInterval = exports.getRelayOriginGasOverhead = exports.isChainExcludedFromInfura = exports.isRelayValidationEnabled = exports.isRelayExecuteEnabled = exports.getPayStrategiesConfig = exports.getStablecoins = exports.getFeatureFlags = exports.getStrategy = exports.getStrategyOrder = exports.DEFAULT_STRATEGY_ORDER = exports.DEFAULT_SERVER_BASE_URL = exports.DEFAULT_ACROSS_API_BASE = exports.DEFAULT_HYPERLIQUID_ACTIVATION_FEE_USD = exports.DEFAULT_SLIPPAGE = exports.DEFAULT_RELAY_ORIGIN_GAS_OVERHEAD = exports.DEFAULT_RELAY_QUOTE_URL = exports.DEFAULT_RELAY_EXECUTE_URL = exports.DEFAULT_FALLBACK_GAS_MAX = exports.DEFAULT_FALLBACK_GAS_ESTIMATE = exports.DEFAULT_GAS_BUFFER = exports.DEFAULT_ORDER_POLL_TIMEOUT_MS = exports.DEFAULT_ORDER_POLL_INTERVAL_MS = exports.DEFAULT_MAX_RATE_DRIFT_PERCENT = exports.DEFAULT_FEE_RESERVE_MULTIPLIER = void 0;
3
+ exports.getEIP7702UpgradeContractAddress = exports.isEIP7702Chain = exports.getHyperliquidActivationFeeConfig = exports.getFiatOrderPollTimeoutMs = exports.getFiatOrderPollIntervalMs = exports.getFiatVaultDisabled = exports.getDirectMoneyMusdEnabled = exports.getFiatMaxRateDriftPercent = exports.getFiatFeeReserveMultiplier = exports.getFiatEnabledTypes = exports.getFiatAssetPerTransactionType = exports.getAssetsUnifyStateFeature = exports.getSlippage = exports.getGasBuffer = exports.getFallbackGas = exports.getServerPollingTimeout = exports.getServerPollingInterval = exports.getRelayPollingTimeout = exports.getRelayPollingInterval = exports.getRelayOriginGasOverhead = exports.isChainExcludedFromInfura = exports.isRelayValidationEnabled = exports.isRelayExecuteEnabled = exports.getPayStrategiesConfig = exports.getStablecoins = exports.getFeatureFlags = exports.getStrategy = exports.getStrategyOrder = exports.DEFAULT_STRATEGY_ORDER = exports.DEFAULT_SERVER_BASE_URL = exports.DEFAULT_ACROSS_API_BASE = exports.DEFAULT_HYPERLIQUID_ACTIVATION_FEE_USD = exports.DEFAULT_SLIPPAGE = exports.DEFAULT_RELAY_ORIGIN_GAS_OVERHEAD = exports.DEFAULT_RELAY_QUOTE_URL = exports.DEFAULT_RELAY_EXECUTE_URL = exports.DEFAULT_FALLBACK_GAS_MAX = exports.DEFAULT_FALLBACK_GAS_ESTIMATE = exports.DEFAULT_GAS_BUFFER = exports.DEFAULT_ORDER_POLL_TIMEOUT_MS = exports.DEFAULT_ORDER_POLL_INTERVAL_MS = exports.DEFAULT_MAX_RATE_DRIFT_PERCENT = exports.DEFAULT_FEE_RESERVE_MULTIPLIER = void 0;
4
4
  const utils_1 = require("@metamask/utils");
5
5
  const bignumber_js_1 = require("bignumber.js");
6
6
  const lodash_1 = require("lodash");
@@ -639,4 +639,19 @@ function isEIP7702Chain(messenger, chainId) {
639
639
  return supportedChains.some((supported) => supported.toLowerCase() === chainId.toLowerCase());
640
640
  }
641
641
  exports.isEIP7702Chain = isEIP7702Chain;
642
+ /**
643
+ * Get the EIP-7702 upgrade contract address for a chain from the
644
+ * `confirmations_eip_7702.contracts` feature flag, if any.
645
+ *
646
+ * @param messenger - Controller messenger.
647
+ * @param chainId - Chain ID to resolve the upgrade contract for.
648
+ * @returns The upgrade contract address, or `undefined` when none is set.
649
+ */
650
+ function getEIP7702UpgradeContractAddress(messenger, chainId) {
651
+ const state = messenger.call('RemoteFeatureFlagController:getState');
652
+ const eip7702Flags = state.remoteFeatureFlags.confirmations_eip_7702;
653
+ const contracts = getCaseInsensitive(eip7702Flags?.contracts, chainId);
654
+ return contracts?.[0]?.address;
655
+ }
656
+ exports.getEIP7702UpgradeContractAddress = getEIP7702UpgradeContractAddress;
642
657
  //# sourceMappingURL=feature-flags.cjs.map