@metamask/transaction-controller 64.4.0 → 65.1.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 (80) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/TransactionController-method-action-types.cjs.map +1 -1
  3. package/dist/TransactionController-method-action-types.d.cts +12 -1
  4. package/dist/TransactionController-method-action-types.d.cts.map +1 -1
  5. package/dist/TransactionController-method-action-types.d.mts +12 -1
  6. package/dist/TransactionController-method-action-types.d.mts.map +1 -1
  7. package/dist/TransactionController-method-action-types.mjs.map +1 -1
  8. package/dist/TransactionController.cjs +33 -1
  9. package/dist/TransactionController.cjs.map +1 -1
  10. package/dist/TransactionController.d.cts +2 -2
  11. package/dist/TransactionController.d.cts.map +1 -1
  12. package/dist/TransactionController.d.mts +2 -2
  13. package/dist/TransactionController.d.mts.map +1 -1
  14. package/dist/TransactionController.mjs +33 -1
  15. package/dist/TransactionController.mjs.map +1 -1
  16. package/dist/api/simulation-api.cjs.map +1 -1
  17. package/dist/api/simulation-api.d.cts +2 -0
  18. package/dist/api/simulation-api.d.cts.map +1 -1
  19. package/dist/api/simulation-api.d.mts +2 -0
  20. package/dist/api/simulation-api.d.mts.map +1 -1
  21. package/dist/api/simulation-api.mjs.map +1 -1
  22. package/dist/helpers/PendingTransactionTracker.cjs +13 -2
  23. package/dist/helpers/PendingTransactionTracker.cjs.map +1 -1
  24. package/dist/helpers/PendingTransactionTracker.d.cts.map +1 -1
  25. package/dist/helpers/PendingTransactionTracker.d.mts.map +1 -1
  26. package/dist/helpers/PendingTransactionTracker.mjs +13 -2
  27. package/dist/helpers/PendingTransactionTracker.mjs.map +1 -1
  28. package/dist/index.cjs +3 -1
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +2 -1
  31. package/dist/index.d.cts.map +1 -1
  32. package/dist/index.d.mts +2 -1
  33. package/dist/index.d.mts.map +1 -1
  34. package/dist/index.mjs +1 -0
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/types.cjs.map +1 -1
  37. package/dist/types.d.cts +22 -0
  38. package/dist/types.d.cts.map +1 -1
  39. package/dist/types.d.mts +22 -0
  40. package/dist/types.d.mts.map +1 -1
  41. package/dist/types.mjs.map +1 -1
  42. package/dist/utils/balance-changes.cjs +21 -1
  43. package/dist/utils/balance-changes.cjs.map +1 -1
  44. package/dist/utils/balance-changes.d.cts +2 -1
  45. package/dist/utils/balance-changes.d.cts.map +1 -1
  46. package/dist/utils/balance-changes.d.mts +2 -1
  47. package/dist/utils/balance-changes.d.mts.map +1 -1
  48. package/dist/utils/balance-changes.mjs +21 -1
  49. package/dist/utils/balance-changes.mjs.map +1 -1
  50. package/dist/utils/batch.cjs +52 -2
  51. package/dist/utils/batch.cjs.map +1 -1
  52. package/dist/utils/batch.d.cts.map +1 -1
  53. package/dist/utils/batch.d.mts.map +1 -1
  54. package/dist/utils/batch.mjs +53 -3
  55. package/dist/utils/batch.mjs.map +1 -1
  56. package/dist/utils/eip7702.cjs +56 -8
  57. package/dist/utils/eip7702.cjs.map +1 -1
  58. package/dist/utils/eip7702.d.cts +25 -0
  59. package/dist/utils/eip7702.d.cts.map +1 -1
  60. package/dist/utils/eip7702.d.mts +25 -0
  61. package/dist/utils/eip7702.d.mts.map +1 -1
  62. package/dist/utils/eip7702.mjs +53 -7
  63. package/dist/utils/eip7702.mjs.map +1 -1
  64. package/dist/utils/gas.cjs +16 -6
  65. package/dist/utils/gas.cjs.map +1 -1
  66. package/dist/utils/gas.d.cts +2 -1
  67. package/dist/utils/gas.d.cts.map +1 -1
  68. package/dist/utils/gas.d.mts +2 -1
  69. package/dist/utils/gas.d.mts.map +1 -1
  70. package/dist/utils/gas.mjs +17 -7
  71. package/dist/utils/gas.mjs.map +1 -1
  72. package/dist/utils/revert-reason.cjs +192 -0
  73. package/dist/utils/revert-reason.cjs.map +1 -0
  74. package/dist/utils/revert-reason.d.cts +57 -0
  75. package/dist/utils/revert-reason.d.cts.map +1 -0
  76. package/dist/utils/revert-reason.d.mts +57 -0
  77. package/dist/utils/revert-reason.d.mts.map +1 -0
  78. package/dist/utils/revert-reason.mjs +186 -0
  79. package/dist/utils/revert-reason.mjs.map +1 -0
  80. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.signAuthorizationList = exports.generateEIP7702BatchTransaction = exports.isAccountUpgradedToEIP7702 = exports.getDelegationAddress = exports.doesChainSupportEIP7702 = exports.ERROR_MESSGE_PUBLIC_KEY = exports.CALLS_SIGNATURE = exports.BATCH_FUNCTION_NAME = exports.DELEGATION_PREFIX = void 0;
3
+ exports.decodeAuthorizationSignature = exports.signAuthorizationList = exports.generateEIP7702BatchTransaction = exports.isAccountUpgradedToEIP7702 = exports.getDelegationAddress = exports.doesChainSupportEIP7702 = exports.doesAccountSupportEIP7702 = exports.ERROR_MESSGE_PUBLIC_KEY = exports.CALLS_SIGNATURE = exports.BATCH_FUNCTION_NAME = exports.DELEGATION_PREFIX = void 0;
4
4
  const abi_1 = require("@ethersproject/abi");
5
5
  const contracts_1 = require("@ethersproject/contracts");
6
6
  const controller_utils_1 = require("@metamask/controller-utils");
@@ -26,6 +26,29 @@ const ERC7579_CALL_TYPE_BATCH = '01';
26
26
  const ERC7579_EXEC_TYPE_DEFAULT = '00';
27
27
  const ERC7579_EXEC_TYPE_TRY = '01';
28
28
  const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'eip-7702');
29
+ const KEYRING_TYPES_SUPPORTING_7702 = [
30
+ 'HD Key Tree',
31
+ 'Simple Key Pair',
32
+ 'Money Keyring',
33
+ ];
34
+ /**
35
+ * Check whether a given account's keyring supports EIP-7702 authorization
36
+ * signing.
37
+ *
38
+ * Looks up the account's keyring via `KeyringController:getState` and returns
39
+ * `true` only when the keyring type is in the supported list.
40
+ * Returns `false` when the keyring cannot be resolved.
41
+ *
42
+ * @param messenger - Controller messenger.
43
+ * @param account - The account address to check.
44
+ * @returns Whether the account supports EIP-7702.
45
+ */
46
+ function doesAccountSupportEIP7702(messenger, account) {
47
+ const { keyrings } = messenger.call('KeyringController:getState');
48
+ return keyrings.some((k) => KEYRING_TYPES_SUPPORTING_7702.includes(k.type) &&
49
+ k.accounts.some((a) => a.toLowerCase() === account.toLowerCase()));
50
+ }
51
+ exports.doesAccountSupportEIP7702 = doesAccountSupportEIP7702;
29
52
  /**
30
53
  * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
31
54
  *
@@ -140,6 +163,37 @@ async function signAuthorizationList({ authorizationList, messenger, transaction
140
163
  return signedAuthorizationList;
141
164
  }
142
165
  exports.signAuthorizationList = signAuthorizationList;
166
+ /**
167
+ * Decode a 65-byte EIP-7702 authorization signature into RLP-canonical
168
+ * `r`, `s`, and `yParity` (no leading zero nibbles, `0x0` for zero).
169
+ *
170
+ * @param signature - The 65-byte signature.
171
+ * @returns The decoded authorization fields.
172
+ */
173
+ function decodeAuthorizationSignature(signature) {
174
+ // eslint-disable-next-line id-length
175
+ const r = toCanonicalHex(signature.slice(0, 66));
176
+ // eslint-disable-next-line id-length
177
+ const s = toCanonicalHex(signature.slice(66, 130));
178
+ // eslint-disable-next-line id-length
179
+ const v = parseInt(signature.slice(130, 132), 16);
180
+ const yParity = toCanonicalHex((0, controller_utils_1.toHex)(v - 27 === 0 ? 0 : 1));
181
+ return { r, s, yParity };
182
+ }
183
+ exports.decodeAuthorizationSignature = decodeAuthorizationSignature;
184
+ /**
185
+ * Strip leading zero nibbles from a hex string to produce its RLP-canonical
186
+ * form. Accepts input with or without a `0x` prefix; always returns
187
+ * `0x`-prefixed. An all-zero input is preserved as `0x0`.
188
+ *
189
+ * @param value - Hex string with or without a `0x` prefix.
190
+ * @returns The canonical `0x`-prefixed hex string.
191
+ */
192
+ function toCanonicalHex(value) {
193
+ const raw = value.startsWith('0x') ? value.slice(2) : value;
194
+ const stripped = raw.replace(/^0+/u, '');
195
+ return stripped.length === 0 ? '0x0' : `0x${stripped}`;
196
+ }
143
197
  /**
144
198
  * Signs an authorization.
145
199
  *
@@ -162,13 +216,7 @@ async function signAuthorization(authorization, transactionMeta, messenger, inde
162
216
  from,
163
217
  nonce: nonceDecimal,
164
218
  });
165
- // eslint-disable-next-line id-length
166
- const r = signature.slice(0, 66);
167
- // eslint-disable-next-line id-length
168
- const s = (0, utils_1.add0x)(signature.slice(66, 130));
169
- // eslint-disable-next-line id-length
170
- const v = parseInt(signature.slice(130, 132), 16);
171
- const yParity = (0, controller_utils_1.toHex)(v - 27 === 0 ? 0 : 1);
219
+ const { r, s, yParity } = decodeAuthorizationSignature(signature);
172
220
  const result = {
173
221
  address,
174
222
  chainId,
@@ -1 +1 @@
1
- {"version":3,"file":"eip7702.cjs","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultAbiCoder } from '@ethersproject/abi';\nimport { Contract } from '@ethersproject/contracts';\nimport { toHex } from '@metamask/controller-utils';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { createModuleLogger, add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { ABI_IERC7821 } from '../constants';\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n BatchTransactionParams,\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\nimport {\n getEIP7702ContractAddresses,\n getEIP7702SupportedChains,\n} from './feature-flags';\nimport { rpcRequest } from './provider';\n\nexport const DELEGATION_PREFIX = '0xef0100';\nexport const BATCH_FUNCTION_NAME = 'execute';\nexport const CALLS_SIGNATURE = '(address,uint256,bytes)[]';\nexport const ERROR_MESSGE_PUBLIC_KEY = 'EIP-7702 public key not specified';\n\n/**\n * ERC-7579 ModeCode encoding for the ERC-7821 `execute` function.\n *\n * Layout: | CallType (1 byte) | ExecType (1 byte) | Unused (4 bytes) | ModeSelector (4 bytes) | ModePayload (22 bytes) |\n *\n * - CallType 0x01 = batch\n * - ExecType 0x00 = default (revert on failure)\n * - ExecType 0x01 = try (skip on failure)\n */\nconst ERC7579_CALL_TYPE_BATCH = '01';\nconst ERC7579_EXEC_TYPE_DEFAULT = '00';\nconst ERC7579_EXEC_TYPE_TRY = '01';\n\nconst log = createModuleLogger(projectLogger, 'eip-7702');\n\n/**\n * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.\n *\n * @param chainId - Hexadecimal ID of the chain.\n * @param messenger - Messenger instance.\n * @returns True if the chain supports EIP-7702.\n */\nexport function doesChainSupportEIP7702(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): boolean {\n const supportedChains = getEIP7702SupportedChains(messenger);\n\n return supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * Retrieve the delegation address for an account.\n *\n * @param address - The address to check.\n * @param messenger - The TransactionController messenger.\n * @param networkClientId - The network client ID to use.\n * @returns The delegation address if it exists.\n */\nexport async function getDelegationAddress(\n address: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<Hex | undefined> {\n const code = (await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_getCode',\n params: [address, 'latest'],\n })) as string;\n const normalizedCode = add0x(code?.toLowerCase?.() ?? '');\n\n const hasDelegation =\n code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);\n\n return hasDelegation\n ? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))\n : undefined;\n}\n\n/**\n * Determine if an account has been upgraded to a supported EIP-7702 contract.\n *\n * @param address - The EOA address to check.\n * @param chainId - The chain ID.\n * @param publicKey - Public key used to validate EIP-7702 contract signatures in feature flags.\n * @param messenger - The messenger instance.\n * @param networkClientId - The network client ID to use.\n * @returns An object with the results of the check.\n */\nexport async function isAccountUpgradedToEIP7702(\n address: Hex,\n chainId: Hex,\n publicKey: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<{\n delegationAddress: Hex | undefined;\n isSupported: boolean;\n}> {\n const contractAddresses = getEIP7702ContractAddresses(\n chainId,\n messenger,\n publicKey,\n );\n\n const delegationAddress = await getDelegationAddress(\n address,\n messenger,\n networkClientId,\n );\n\n const isSupported = Boolean(\n delegationAddress &&\n contractAddresses.some(\n (contract) => contract.toLowerCase() === delegationAddress.toLowerCase(),\n ),\n );\n\n return {\n delegationAddress,\n isSupported,\n };\n}\n\n/**\n * Generate an EIP-7702 batch transaction.\n *\n * @param from - The sender address.\n * @param transactions - The transactions to batch.\n * @param options - Options bag.\n * @param options.atomic - Whether the batch should be atomic. Defaults to `true`.\n * When `true`, uses ERC-7579 ExecType `default` and all calls revert together.\n * When `false`, uses ERC-7579 ExecType `try` and individual calls can fail independently.\n * @returns The batch transaction.\n */\nexport function generateEIP7702BatchTransaction(\n from: Hex,\n transactions: BatchTransactionParams[],\n options?: { atomic?: boolean },\n): BatchTransactionParams {\n const atomic = options?.atomic ?? true;\n const erc7821Contract = Contract.getInterface(ABI_IERC7821);\n\n const calls = transactions.map((transaction) => {\n const { data, to, value } = transaction;\n\n return [\n to ?? '0x0000000000000000000000000000000000000000',\n value ?? '0x0',\n data ?? '0x',\n ];\n });\n\n const execType = atomic ? ERC7579_EXEC_TYPE_DEFAULT : ERC7579_EXEC_TYPE_TRY;\n const mode = `0x${ERC7579_CALL_TYPE_BATCH}${execType}`.padEnd(66, '0');\n\n const callData = defaultAbiCoder.encode([CALLS_SIGNATURE], [calls]);\n\n const data = erc7821Contract.encodeFunctionData(BATCH_FUNCTION_NAME, [\n mode,\n callData,\n ]) as Hex;\n\n log('Transaction data', data);\n\n return {\n data,\n to: from,\n };\n}\n\n/**\n * Sign an authorization list.\n *\n * @param options - Options bag.\n * @param options.authorizationList - The authorization list to sign.\n * @param options.messenger - The controller messenger.\n * @param options.transactionMeta - The transaction metadata.\n * @returns The signed authorization list.\n */\nexport async function signAuthorizationList({\n authorizationList,\n messenger,\n transactionMeta,\n}: {\n authorizationList?: AuthorizationList;\n messenger: TransactionControllerMessenger;\n transactionMeta: TransactionMeta;\n}): Promise<Required<AuthorizationList | undefined>> {\n if (!authorizationList) {\n return undefined;\n }\n\n const signedAuthorizationList: Required<AuthorizationList> = [];\n let index = 0;\n\n for (const authorization of authorizationList) {\n const signedAuthorization = await signAuthorization(\n authorization,\n transactionMeta,\n messenger,\n index,\n );\n\n signedAuthorizationList.push(signedAuthorization);\n index += 1;\n }\n\n return signedAuthorizationList;\n}\n\n/**\n * Signs an authorization.\n *\n * @param authorization - The authorization to sign.\n * @param transactionMeta - The associated transaction metadata.\n * @param messenger - The messenger to use for signing.\n * @param index - The index of the authorization in the list.\n * @returns The signed authorization.\n */\nasync function signAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n messenger: TransactionControllerMessenger,\n index: number,\n): Promise<Required<Authorization>> {\n const finalAuthorization = prepareAuthorization(\n authorization,\n transactionMeta,\n index,\n );\n\n const { txParams } = transactionMeta;\n const { from } = txParams;\n const { address, chainId, nonce } = finalAuthorization;\n const chainIdDecimal = parseInt(chainId, 16);\n const nonceDecimal = parseInt(nonce, 16);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: address,\n from,\n nonce: nonceDecimal,\n },\n );\n\n // eslint-disable-next-line id-length\n const r = signature.slice(0, 66) as Hex;\n // eslint-disable-next-line id-length\n const s = add0x(signature.slice(66, 130));\n // eslint-disable-next-line id-length\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = toHex(v - 27 === 0 ? 0 : 1);\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce,\n r,\n s,\n yParity,\n };\n\n log('Signed authorization', result);\n\n return result;\n}\n\n/**\n * Prepares an authorization for signing by populating the chainId and nonce.\n *\n * @param authorization - The authorization to prepare.\n * @param transactionMeta - The associated transaction metadata.\n * @param index - The index of the authorization in the list.\n * @returns The prepared authorization.\n */\nfunction prepareAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n index: number,\n): Authorization & { chainId: Hex; nonce: Hex } {\n const { chainId: existingChainId, nonce: existingNonce } = authorization;\n const { txParams, chainId: transactionChainId } = transactionMeta;\n const { nonce: transactionNonce } = txParams;\n\n const chainId = existingChainId ?? transactionChainId;\n let nonce = existingNonce;\n\n nonce ??= toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n\n const result = {\n ...authorization,\n chainId,\n nonce,\n };\n\n log('Prepared authorization', result);\n\n return result;\n}\n"]}
1
+ {"version":3,"file":"eip7702.cjs","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultAbiCoder } from '@ethersproject/abi';\nimport { Contract } from '@ethersproject/contracts';\nimport { toHex } from '@metamask/controller-utils';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { createModuleLogger, add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { ABI_IERC7821 } from '../constants';\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n BatchTransactionParams,\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\nimport {\n getEIP7702ContractAddresses,\n getEIP7702SupportedChains,\n} from './feature-flags';\nimport { rpcRequest } from './provider';\n\nexport const DELEGATION_PREFIX = '0xef0100';\nexport const BATCH_FUNCTION_NAME = 'execute';\nexport const CALLS_SIGNATURE = '(address,uint256,bytes)[]';\nexport const ERROR_MESSGE_PUBLIC_KEY = 'EIP-7702 public key not specified';\n\n/**\n * ERC-7579 ModeCode encoding for the ERC-7821 `execute` function.\n *\n * Layout: | CallType (1 byte) | ExecType (1 byte) | Unused (4 bytes) | ModeSelector (4 bytes) | ModePayload (22 bytes) |\n *\n * - CallType 0x01 = batch\n * - ExecType 0x00 = default (revert on failure)\n * - ExecType 0x01 = try (skip on failure)\n */\nconst ERC7579_CALL_TYPE_BATCH = '01';\nconst ERC7579_EXEC_TYPE_DEFAULT = '00';\nconst ERC7579_EXEC_TYPE_TRY = '01';\n\nconst log = createModuleLogger(projectLogger, 'eip-7702');\n\nconst KEYRING_TYPES_SUPPORTING_7702 = [\n 'HD Key Tree',\n 'Simple Key Pair',\n 'Money Keyring',\n];\n\n/**\n * Check whether a given account's keyring supports EIP-7702 authorization\n * signing.\n *\n * Looks up the account's keyring via `KeyringController:getState` and returns\n * `true` only when the keyring type is in the supported list.\n * Returns `false` when the keyring cannot be resolved.\n *\n * @param messenger - Controller messenger.\n * @param account - The account address to check.\n * @returns Whether the account supports EIP-7702.\n */\nexport function doesAccountSupportEIP7702(\n messenger: TransactionControllerMessenger,\n account: string,\n): boolean {\n const { keyrings } = messenger.call('KeyringController:getState');\n\n return keyrings.some(\n (k: { type: string; accounts: string[] }) =>\n KEYRING_TYPES_SUPPORTING_7702.includes(k.type) &&\n k.accounts.some((a: string) => a.toLowerCase() === account.toLowerCase()),\n );\n}\n\n/**\n * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.\n *\n * @param chainId - Hexadecimal ID of the chain.\n * @param messenger - Messenger instance.\n * @returns True if the chain supports EIP-7702.\n */\nexport function doesChainSupportEIP7702(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): boolean {\n const supportedChains = getEIP7702SupportedChains(messenger);\n\n return supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * Retrieve the delegation address for an account.\n *\n * @param address - The address to check.\n * @param messenger - The TransactionController messenger.\n * @param networkClientId - The network client ID to use.\n * @returns The delegation address if it exists.\n */\nexport async function getDelegationAddress(\n address: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<Hex | undefined> {\n const code = (await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_getCode',\n params: [address, 'latest'],\n })) as string;\n const normalizedCode = add0x(code?.toLowerCase?.() ?? '');\n\n const hasDelegation =\n code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);\n\n return hasDelegation\n ? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))\n : undefined;\n}\n\n/**\n * Determine if an account has been upgraded to a supported EIP-7702 contract.\n *\n * @param address - The EOA address to check.\n * @param chainId - The chain ID.\n * @param publicKey - Public key used to validate EIP-7702 contract signatures in feature flags.\n * @param messenger - The messenger instance.\n * @param networkClientId - The network client ID to use.\n * @returns An object with the results of the check.\n */\nexport async function isAccountUpgradedToEIP7702(\n address: Hex,\n chainId: Hex,\n publicKey: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<{\n delegationAddress: Hex | undefined;\n isSupported: boolean;\n}> {\n const contractAddresses = getEIP7702ContractAddresses(\n chainId,\n messenger,\n publicKey,\n );\n\n const delegationAddress = await getDelegationAddress(\n address,\n messenger,\n networkClientId,\n );\n\n const isSupported = Boolean(\n delegationAddress &&\n contractAddresses.some(\n (contract) => contract.toLowerCase() === delegationAddress.toLowerCase(),\n ),\n );\n\n return {\n delegationAddress,\n isSupported,\n };\n}\n\n/**\n * Generate an EIP-7702 batch transaction.\n *\n * @param from - The sender address.\n * @param transactions - The transactions to batch.\n * @param options - Options bag.\n * @param options.atomic - Whether the batch should be atomic. Defaults to `true`.\n * When `true`, uses ERC-7579 ExecType `default` and all calls revert together.\n * When `false`, uses ERC-7579 ExecType `try` and individual calls can fail independently.\n * @returns The batch transaction.\n */\nexport function generateEIP7702BatchTransaction(\n from: Hex,\n transactions: BatchTransactionParams[],\n options?: { atomic?: boolean },\n): BatchTransactionParams {\n const atomic = options?.atomic ?? true;\n const erc7821Contract = Contract.getInterface(ABI_IERC7821);\n\n const calls = transactions.map((transaction) => {\n const { data, to, value } = transaction;\n\n return [\n to ?? '0x0000000000000000000000000000000000000000',\n value ?? '0x0',\n data ?? '0x',\n ];\n });\n\n const execType = atomic ? ERC7579_EXEC_TYPE_DEFAULT : ERC7579_EXEC_TYPE_TRY;\n const mode = `0x${ERC7579_CALL_TYPE_BATCH}${execType}`.padEnd(66, '0');\n\n const callData = defaultAbiCoder.encode([CALLS_SIGNATURE], [calls]);\n\n const data = erc7821Contract.encodeFunctionData(BATCH_FUNCTION_NAME, [\n mode,\n callData,\n ]) as Hex;\n\n log('Transaction data', data);\n\n return {\n data,\n to: from,\n };\n}\n\n/**\n * Sign an authorization list.\n *\n * @param options - Options bag.\n * @param options.authorizationList - The authorization list to sign.\n * @param options.messenger - The controller messenger.\n * @param options.transactionMeta - The transaction metadata.\n * @returns The signed authorization list.\n */\nexport async function signAuthorizationList({\n authorizationList,\n messenger,\n transactionMeta,\n}: {\n authorizationList?: AuthorizationList;\n messenger: TransactionControllerMessenger;\n transactionMeta: TransactionMeta;\n}): Promise<Required<AuthorizationList | undefined>> {\n if (!authorizationList) {\n return undefined;\n }\n\n const signedAuthorizationList: Required<AuthorizationList> = [];\n let index = 0;\n\n for (const authorization of authorizationList) {\n const signedAuthorization = await signAuthorization(\n authorization,\n transactionMeta,\n messenger,\n index,\n );\n\n signedAuthorizationList.push(signedAuthorization);\n index += 1;\n }\n\n return signedAuthorizationList;\n}\n\n/**\n * Decode a 65-byte EIP-7702 authorization signature into RLP-canonical\n * `r`, `s`, and `yParity` (no leading zero nibbles, `0x0` for zero).\n *\n * @param signature - The 65-byte signature.\n * @returns The decoded authorization fields.\n */\nexport function decodeAuthorizationSignature(signature: Hex): {\n r: Hex;\n s: Hex;\n yParity: Hex;\n} {\n // eslint-disable-next-line id-length\n const r = toCanonicalHex(signature.slice(0, 66));\n // eslint-disable-next-line id-length\n const s = toCanonicalHex(signature.slice(66, 130));\n // eslint-disable-next-line id-length\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = toCanonicalHex(toHex(v - 27 === 0 ? 0 : 1));\n\n return { r, s, yParity };\n}\n\n/**\n * Strip leading zero nibbles from a hex string to produce its RLP-canonical\n * form. Accepts input with or without a `0x` prefix; always returns\n * `0x`-prefixed. An all-zero input is preserved as `0x0`.\n *\n * @param value - Hex string with or without a `0x` prefix.\n * @returns The canonical `0x`-prefixed hex string.\n */\nfunction toCanonicalHex(value: string): Hex {\n const raw = value.startsWith('0x') ? value.slice(2) : value;\n const stripped = raw.replace(/^0+/u, '');\n return stripped.length === 0 ? '0x0' : `0x${stripped}`;\n}\n\n/**\n * Signs an authorization.\n *\n * @param authorization - The authorization to sign.\n * @param transactionMeta - The associated transaction metadata.\n * @param messenger - The messenger to use for signing.\n * @param index - The index of the authorization in the list.\n * @returns The signed authorization.\n */\nasync function signAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n messenger: TransactionControllerMessenger,\n index: number,\n): Promise<Required<Authorization>> {\n const finalAuthorization = prepareAuthorization(\n authorization,\n transactionMeta,\n index,\n );\n\n const { txParams } = transactionMeta;\n const { from } = txParams;\n const { address, chainId, nonce } = finalAuthorization;\n const chainIdDecimal = parseInt(chainId, 16);\n const nonceDecimal = parseInt(nonce, 16);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: address,\n from,\n nonce: nonceDecimal,\n },\n );\n\n const { r, s, yParity } = decodeAuthorizationSignature(signature as Hex);\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce,\n r,\n s,\n yParity,\n };\n\n log('Signed authorization', result);\n\n return result;\n}\n\n/**\n * Prepares an authorization for signing by populating the chainId and nonce.\n *\n * @param authorization - The authorization to prepare.\n * @param transactionMeta - The associated transaction metadata.\n * @param index - The index of the authorization in the list.\n * @returns The prepared authorization.\n */\nfunction prepareAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n index: number,\n): Authorization & { chainId: Hex; nonce: Hex } {\n const { chainId: existingChainId, nonce: existingNonce } = authorization;\n const { txParams, chainId: transactionChainId } = transactionMeta;\n const { nonce: transactionNonce } = txParams;\n\n const chainId = existingChainId ?? transactionChainId;\n let nonce = existingNonce;\n\n nonce ??= toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n\n const result = {\n ...authorization,\n chainId,\n nonce,\n };\n\n log('Prepared authorization', result);\n\n return result;\n}\n"]}
@@ -6,6 +6,19 @@ export declare const DELEGATION_PREFIX = "0xef0100";
6
6
  export declare const BATCH_FUNCTION_NAME = "execute";
7
7
  export declare const CALLS_SIGNATURE = "(address,uint256,bytes)[]";
8
8
  export declare const ERROR_MESSGE_PUBLIC_KEY = "EIP-7702 public key not specified";
9
+ /**
10
+ * Check whether a given account's keyring supports EIP-7702 authorization
11
+ * signing.
12
+ *
13
+ * Looks up the account's keyring via `KeyringController:getState` and returns
14
+ * `true` only when the keyring type is in the supported list.
15
+ * Returns `false` when the keyring cannot be resolved.
16
+ *
17
+ * @param messenger - Controller messenger.
18
+ * @param account - The account address to check.
19
+ * @returns Whether the account supports EIP-7702.
20
+ */
21
+ export declare function doesAccountSupportEIP7702(messenger: TransactionControllerMessenger, account: string): boolean;
9
22
  /**
10
23
  * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
11
24
  *
@@ -65,4 +78,16 @@ export declare function signAuthorizationList({ authorizationList, messenger, tr
65
78
  messenger: TransactionControllerMessenger;
66
79
  transactionMeta: TransactionMeta;
67
80
  }): Promise<Required<AuthorizationList | undefined>>;
81
+ /**
82
+ * Decode a 65-byte EIP-7702 authorization signature into RLP-canonical
83
+ * `r`, `s`, and `yParity` (no leading zero nibbles, `0x0` for zero).
84
+ *
85
+ * @param signature - The 65-byte signature.
86
+ * @returns The decoded authorization fields.
87
+ */
88
+ export declare function decodeAuthorizationSignature(signature: Hex): {
89
+ r: Hex;
90
+ s: Hex;
91
+ yParity: Hex;
92
+ };
68
93
  //# sourceMappingURL=eip7702.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eip7702.d.cts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAI3C,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,eAAe,EAChB,qBAAiB;AAOlB,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAiB3E;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAe1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC;IACT,iBAAiB,EAAE,GAAG,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAwBD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,sBAAsB,EAAE,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,sBAAsB,CA8BxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,iBAAiB,EACjB,SAAS,EACT,eAAe,GAChB,EAAE;IACD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC,CAqBnD"}
1
+ {"version":3,"file":"eip7702.d.cts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAI3C,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,eAAe,EAChB,qBAAiB;AAOlB,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAuB3E;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,8BAA8B,EACzC,OAAO,EAAE,MAAM,GACd,OAAO,CAQT;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAe1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC;IACT,iBAAiB,EAAE,GAAG,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAwBD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,sBAAsB,EAAE,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,sBAAsB,CA8BxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,iBAAiB,EACjB,SAAS,EACT,eAAe,GAChB,EAAE;IACD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC,CAqBnD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,GAAG,GAAG;IAC5D,CAAC,EAAE,GAAG,CAAC;IACP,CAAC,EAAE,GAAG,CAAC;IACP,OAAO,EAAE,GAAG,CAAC;CACd,CAUA"}
@@ -6,6 +6,19 @@ export declare const DELEGATION_PREFIX = "0xef0100";
6
6
  export declare const BATCH_FUNCTION_NAME = "execute";
7
7
  export declare const CALLS_SIGNATURE = "(address,uint256,bytes)[]";
8
8
  export declare const ERROR_MESSGE_PUBLIC_KEY = "EIP-7702 public key not specified";
9
+ /**
10
+ * Check whether a given account's keyring supports EIP-7702 authorization
11
+ * signing.
12
+ *
13
+ * Looks up the account's keyring via `KeyringController:getState` and returns
14
+ * `true` only when the keyring type is in the supported list.
15
+ * Returns `false` when the keyring cannot be resolved.
16
+ *
17
+ * @param messenger - Controller messenger.
18
+ * @param account - The account address to check.
19
+ * @returns Whether the account supports EIP-7702.
20
+ */
21
+ export declare function doesAccountSupportEIP7702(messenger: TransactionControllerMessenger, account: string): boolean;
9
22
  /**
10
23
  * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
11
24
  *
@@ -65,4 +78,16 @@ export declare function signAuthorizationList({ authorizationList, messenger, tr
65
78
  messenger: TransactionControllerMessenger;
66
79
  transactionMeta: TransactionMeta;
67
80
  }): Promise<Required<AuthorizationList | undefined>>;
81
+ /**
82
+ * Decode a 65-byte EIP-7702 authorization signature into RLP-canonical
83
+ * `r`, `s`, and `yParity` (no leading zero nibbles, `0x0` for zero).
84
+ *
85
+ * @param signature - The 65-byte signature.
86
+ * @returns The decoded authorization fields.
87
+ */
88
+ export declare function decodeAuthorizationSignature(signature: Hex): {
89
+ r: Hex;
90
+ s: Hex;
91
+ yParity: Hex;
92
+ };
68
93
  //# sourceMappingURL=eip7702.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eip7702.d.mts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAI3C,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,eAAe,EAChB,qBAAiB;AAOlB,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAiB3E;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAe1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC;IACT,iBAAiB,EAAE,GAAG,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAwBD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,sBAAsB,EAAE,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,sBAAsB,CA8BxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,iBAAiB,EACjB,SAAS,EACT,eAAe,GAChB,EAAE;IACD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC,CAqBnD"}
1
+ {"version":3,"file":"eip7702.d.mts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAI3C,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,eAAe,EAChB,qBAAiB;AAOlB,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,sCAAsC,CAAC;AAuB3E;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,8BAA8B,EACzC,OAAO,EAAE,MAAM,GACd,OAAO,CAQT;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAe1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,8BAA8B,EACzC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC;IACT,iBAAiB,EAAE,GAAG,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAwBD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,sBAAsB,EAAE,EACtC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,sBAAsB,CA8BxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,iBAAiB,EACjB,SAAS,EACT,eAAe,GAChB,EAAE;IACD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC,CAqBnD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,GAAG,GAAG;IAC5D,CAAC,EAAE,GAAG,CAAC;IACP,CAAC,EAAE,GAAG,CAAC;IACP,OAAO,EAAE,GAAG,CAAC;CACd,CAUA"}
@@ -23,6 +23,28 @@ const ERC7579_CALL_TYPE_BATCH = '01';
23
23
  const ERC7579_EXEC_TYPE_DEFAULT = '00';
24
24
  const ERC7579_EXEC_TYPE_TRY = '01';
25
25
  const log = createModuleLogger(projectLogger, 'eip-7702');
26
+ const KEYRING_TYPES_SUPPORTING_7702 = [
27
+ 'HD Key Tree',
28
+ 'Simple Key Pair',
29
+ 'Money Keyring',
30
+ ];
31
+ /**
32
+ * Check whether a given account's keyring supports EIP-7702 authorization
33
+ * signing.
34
+ *
35
+ * Looks up the account's keyring via `KeyringController:getState` and returns
36
+ * `true` only when the keyring type is in the supported list.
37
+ * Returns `false` when the keyring cannot be resolved.
38
+ *
39
+ * @param messenger - Controller messenger.
40
+ * @param account - The account address to check.
41
+ * @returns Whether the account supports EIP-7702.
42
+ */
43
+ export function doesAccountSupportEIP7702(messenger, account) {
44
+ const { keyrings } = messenger.call('KeyringController:getState');
45
+ return keyrings.some((k) => KEYRING_TYPES_SUPPORTING_7702.includes(k.type) &&
46
+ k.accounts.some((a) => a.toLowerCase() === account.toLowerCase()));
47
+ }
26
48
  /**
27
49
  * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
28
50
  *
@@ -132,6 +154,36 @@ export async function signAuthorizationList({ authorizationList, messenger, tran
132
154
  }
133
155
  return signedAuthorizationList;
134
156
  }
157
+ /**
158
+ * Decode a 65-byte EIP-7702 authorization signature into RLP-canonical
159
+ * `r`, `s`, and `yParity` (no leading zero nibbles, `0x0` for zero).
160
+ *
161
+ * @param signature - The 65-byte signature.
162
+ * @returns The decoded authorization fields.
163
+ */
164
+ export function decodeAuthorizationSignature(signature) {
165
+ // eslint-disable-next-line id-length
166
+ const r = toCanonicalHex(signature.slice(0, 66));
167
+ // eslint-disable-next-line id-length
168
+ const s = toCanonicalHex(signature.slice(66, 130));
169
+ // eslint-disable-next-line id-length
170
+ const v = parseInt(signature.slice(130, 132), 16);
171
+ const yParity = toCanonicalHex(toHex(v - 27 === 0 ? 0 : 1));
172
+ return { r, s, yParity };
173
+ }
174
+ /**
175
+ * Strip leading zero nibbles from a hex string to produce its RLP-canonical
176
+ * form. Accepts input with or without a `0x` prefix; always returns
177
+ * `0x`-prefixed. An all-zero input is preserved as `0x0`.
178
+ *
179
+ * @param value - Hex string with or without a `0x` prefix.
180
+ * @returns The canonical `0x`-prefixed hex string.
181
+ */
182
+ function toCanonicalHex(value) {
183
+ const raw = value.startsWith('0x') ? value.slice(2) : value;
184
+ const stripped = raw.replace(/^0+/u, '');
185
+ return stripped.length === 0 ? '0x0' : `0x${stripped}`;
186
+ }
135
187
  /**
136
188
  * Signs an authorization.
137
189
  *
@@ -154,13 +206,7 @@ async function signAuthorization(authorization, transactionMeta, messenger, inde
154
206
  from,
155
207
  nonce: nonceDecimal,
156
208
  });
157
- // eslint-disable-next-line id-length
158
- const r = signature.slice(0, 66);
159
- // eslint-disable-next-line id-length
160
- const s = add0x(signature.slice(66, 130));
161
- // eslint-disable-next-line id-length
162
- const v = parseInt(signature.slice(130, 132), 16);
163
- const yParity = toHex(v - 27 === 0 ? 0 : 1);
209
+ const { r, s, yParity } = decodeAuthorizationSignature(signature);
164
210
  const result = {
165
211
  address,
166
212
  chainId,
@@ -1 +1 @@
1
- {"version":3,"file":"eip7702.mjs","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultAbiCoder } from '@ethersproject/abi';\nimport { Contract } from '@ethersproject/contracts';\nimport { toHex } from '@metamask/controller-utils';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { createModuleLogger, add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { ABI_IERC7821 } from '../constants';\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n BatchTransactionParams,\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\nimport {\n getEIP7702ContractAddresses,\n getEIP7702SupportedChains,\n} from './feature-flags';\nimport { rpcRequest } from './provider';\n\nexport const DELEGATION_PREFIX = '0xef0100';\nexport const BATCH_FUNCTION_NAME = 'execute';\nexport const CALLS_SIGNATURE = '(address,uint256,bytes)[]';\nexport const ERROR_MESSGE_PUBLIC_KEY = 'EIP-7702 public key not specified';\n\n/**\n * ERC-7579 ModeCode encoding for the ERC-7821 `execute` function.\n *\n * Layout: | CallType (1 byte) | ExecType (1 byte) | Unused (4 bytes) | ModeSelector (4 bytes) | ModePayload (22 bytes) |\n *\n * - CallType 0x01 = batch\n * - ExecType 0x00 = default (revert on failure)\n * - ExecType 0x01 = try (skip on failure)\n */\nconst ERC7579_CALL_TYPE_BATCH = '01';\nconst ERC7579_EXEC_TYPE_DEFAULT = '00';\nconst ERC7579_EXEC_TYPE_TRY = '01';\n\nconst log = createModuleLogger(projectLogger, 'eip-7702');\n\n/**\n * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.\n *\n * @param chainId - Hexadecimal ID of the chain.\n * @param messenger - Messenger instance.\n * @returns True if the chain supports EIP-7702.\n */\nexport function doesChainSupportEIP7702(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): boolean {\n const supportedChains = getEIP7702SupportedChains(messenger);\n\n return supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * Retrieve the delegation address for an account.\n *\n * @param address - The address to check.\n * @param messenger - The TransactionController messenger.\n * @param networkClientId - The network client ID to use.\n * @returns The delegation address if it exists.\n */\nexport async function getDelegationAddress(\n address: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<Hex | undefined> {\n const code = (await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_getCode',\n params: [address, 'latest'],\n })) as string;\n const normalizedCode = add0x(code?.toLowerCase?.() ?? '');\n\n const hasDelegation =\n code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);\n\n return hasDelegation\n ? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))\n : undefined;\n}\n\n/**\n * Determine if an account has been upgraded to a supported EIP-7702 contract.\n *\n * @param address - The EOA address to check.\n * @param chainId - The chain ID.\n * @param publicKey - Public key used to validate EIP-7702 contract signatures in feature flags.\n * @param messenger - The messenger instance.\n * @param networkClientId - The network client ID to use.\n * @returns An object with the results of the check.\n */\nexport async function isAccountUpgradedToEIP7702(\n address: Hex,\n chainId: Hex,\n publicKey: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<{\n delegationAddress: Hex | undefined;\n isSupported: boolean;\n}> {\n const contractAddresses = getEIP7702ContractAddresses(\n chainId,\n messenger,\n publicKey,\n );\n\n const delegationAddress = await getDelegationAddress(\n address,\n messenger,\n networkClientId,\n );\n\n const isSupported = Boolean(\n delegationAddress &&\n contractAddresses.some(\n (contract) => contract.toLowerCase() === delegationAddress.toLowerCase(),\n ),\n );\n\n return {\n delegationAddress,\n isSupported,\n };\n}\n\n/**\n * Generate an EIP-7702 batch transaction.\n *\n * @param from - The sender address.\n * @param transactions - The transactions to batch.\n * @param options - Options bag.\n * @param options.atomic - Whether the batch should be atomic. Defaults to `true`.\n * When `true`, uses ERC-7579 ExecType `default` and all calls revert together.\n * When `false`, uses ERC-7579 ExecType `try` and individual calls can fail independently.\n * @returns The batch transaction.\n */\nexport function generateEIP7702BatchTransaction(\n from: Hex,\n transactions: BatchTransactionParams[],\n options?: { atomic?: boolean },\n): BatchTransactionParams {\n const atomic = options?.atomic ?? true;\n const erc7821Contract = Contract.getInterface(ABI_IERC7821);\n\n const calls = transactions.map((transaction) => {\n const { data, to, value } = transaction;\n\n return [\n to ?? '0x0000000000000000000000000000000000000000',\n value ?? '0x0',\n data ?? '0x',\n ];\n });\n\n const execType = atomic ? ERC7579_EXEC_TYPE_DEFAULT : ERC7579_EXEC_TYPE_TRY;\n const mode = `0x${ERC7579_CALL_TYPE_BATCH}${execType}`.padEnd(66, '0');\n\n const callData = defaultAbiCoder.encode([CALLS_SIGNATURE], [calls]);\n\n const data = erc7821Contract.encodeFunctionData(BATCH_FUNCTION_NAME, [\n mode,\n callData,\n ]) as Hex;\n\n log('Transaction data', data);\n\n return {\n data,\n to: from,\n };\n}\n\n/**\n * Sign an authorization list.\n *\n * @param options - Options bag.\n * @param options.authorizationList - The authorization list to sign.\n * @param options.messenger - The controller messenger.\n * @param options.transactionMeta - The transaction metadata.\n * @returns The signed authorization list.\n */\nexport async function signAuthorizationList({\n authorizationList,\n messenger,\n transactionMeta,\n}: {\n authorizationList?: AuthorizationList;\n messenger: TransactionControllerMessenger;\n transactionMeta: TransactionMeta;\n}): Promise<Required<AuthorizationList | undefined>> {\n if (!authorizationList) {\n return undefined;\n }\n\n const signedAuthorizationList: Required<AuthorizationList> = [];\n let index = 0;\n\n for (const authorization of authorizationList) {\n const signedAuthorization = await signAuthorization(\n authorization,\n transactionMeta,\n messenger,\n index,\n );\n\n signedAuthorizationList.push(signedAuthorization);\n index += 1;\n }\n\n return signedAuthorizationList;\n}\n\n/**\n * Signs an authorization.\n *\n * @param authorization - The authorization to sign.\n * @param transactionMeta - The associated transaction metadata.\n * @param messenger - The messenger to use for signing.\n * @param index - The index of the authorization in the list.\n * @returns The signed authorization.\n */\nasync function signAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n messenger: TransactionControllerMessenger,\n index: number,\n): Promise<Required<Authorization>> {\n const finalAuthorization = prepareAuthorization(\n authorization,\n transactionMeta,\n index,\n );\n\n const { txParams } = transactionMeta;\n const { from } = txParams;\n const { address, chainId, nonce } = finalAuthorization;\n const chainIdDecimal = parseInt(chainId, 16);\n const nonceDecimal = parseInt(nonce, 16);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: address,\n from,\n nonce: nonceDecimal,\n },\n );\n\n // eslint-disable-next-line id-length\n const r = signature.slice(0, 66) as Hex;\n // eslint-disable-next-line id-length\n const s = add0x(signature.slice(66, 130));\n // eslint-disable-next-line id-length\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = toHex(v - 27 === 0 ? 0 : 1);\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce,\n r,\n s,\n yParity,\n };\n\n log('Signed authorization', result);\n\n return result;\n}\n\n/**\n * Prepares an authorization for signing by populating the chainId and nonce.\n *\n * @param authorization - The authorization to prepare.\n * @param transactionMeta - The associated transaction metadata.\n * @param index - The index of the authorization in the list.\n * @returns The prepared authorization.\n */\nfunction prepareAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n index: number,\n): Authorization & { chainId: Hex; nonce: Hex } {\n const { chainId: existingChainId, nonce: existingNonce } = authorization;\n const { txParams, chainId: transactionChainId } = transactionMeta;\n const { nonce: transactionNonce } = txParams;\n\n const chainId = existingChainId ?? transactionChainId;\n let nonce = existingNonce;\n\n nonce ??= toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n\n const result = {\n ...authorization,\n chainId,\n nonce,\n };\n\n log('Prepared authorization', result);\n\n return result;\n}\n"]}
1
+ {"version":3,"file":"eip7702.mjs","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultAbiCoder } from '@ethersproject/abi';\nimport { Contract } from '@ethersproject/contracts';\nimport { toHex } from '@metamask/controller-utils';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { createModuleLogger, add0x } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { ABI_IERC7821 } from '../constants';\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n BatchTransactionParams,\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\nimport {\n getEIP7702ContractAddresses,\n getEIP7702SupportedChains,\n} from './feature-flags';\nimport { rpcRequest } from './provider';\n\nexport const DELEGATION_PREFIX = '0xef0100';\nexport const BATCH_FUNCTION_NAME = 'execute';\nexport const CALLS_SIGNATURE = '(address,uint256,bytes)[]';\nexport const ERROR_MESSGE_PUBLIC_KEY = 'EIP-7702 public key not specified';\n\n/**\n * ERC-7579 ModeCode encoding for the ERC-7821 `execute` function.\n *\n * Layout: | CallType (1 byte) | ExecType (1 byte) | Unused (4 bytes) | ModeSelector (4 bytes) | ModePayload (22 bytes) |\n *\n * - CallType 0x01 = batch\n * - ExecType 0x00 = default (revert on failure)\n * - ExecType 0x01 = try (skip on failure)\n */\nconst ERC7579_CALL_TYPE_BATCH = '01';\nconst ERC7579_EXEC_TYPE_DEFAULT = '00';\nconst ERC7579_EXEC_TYPE_TRY = '01';\n\nconst log = createModuleLogger(projectLogger, 'eip-7702');\n\nconst KEYRING_TYPES_SUPPORTING_7702 = [\n 'HD Key Tree',\n 'Simple Key Pair',\n 'Money Keyring',\n];\n\n/**\n * Check whether a given account's keyring supports EIP-7702 authorization\n * signing.\n *\n * Looks up the account's keyring via `KeyringController:getState` and returns\n * `true` only when the keyring type is in the supported list.\n * Returns `false` when the keyring cannot be resolved.\n *\n * @param messenger - Controller messenger.\n * @param account - The account address to check.\n * @returns Whether the account supports EIP-7702.\n */\nexport function doesAccountSupportEIP7702(\n messenger: TransactionControllerMessenger,\n account: string,\n): boolean {\n const { keyrings } = messenger.call('KeyringController:getState');\n\n return keyrings.some(\n (k: { type: string; accounts: string[] }) =>\n KEYRING_TYPES_SUPPORTING_7702.includes(k.type) &&\n k.accounts.some((a: string) => a.toLowerCase() === account.toLowerCase()),\n );\n}\n\n/**\n * Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.\n *\n * @param chainId - Hexadecimal ID of the chain.\n * @param messenger - Messenger instance.\n * @returns True if the chain supports EIP-7702.\n */\nexport function doesChainSupportEIP7702(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): boolean {\n const supportedChains = getEIP7702SupportedChains(messenger);\n\n return supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * Retrieve the delegation address for an account.\n *\n * @param address - The address to check.\n * @param messenger - The TransactionController messenger.\n * @param networkClientId - The network client ID to use.\n * @returns The delegation address if it exists.\n */\nexport async function getDelegationAddress(\n address: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<Hex | undefined> {\n const code = (await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_getCode',\n params: [address, 'latest'],\n })) as string;\n const normalizedCode = add0x(code?.toLowerCase?.() ?? '');\n\n const hasDelegation =\n code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);\n\n return hasDelegation\n ? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))\n : undefined;\n}\n\n/**\n * Determine if an account has been upgraded to a supported EIP-7702 contract.\n *\n * @param address - The EOA address to check.\n * @param chainId - The chain ID.\n * @param publicKey - Public key used to validate EIP-7702 contract signatures in feature flags.\n * @param messenger - The messenger instance.\n * @param networkClientId - The network client ID to use.\n * @returns An object with the results of the check.\n */\nexport async function isAccountUpgradedToEIP7702(\n address: Hex,\n chainId: Hex,\n publicKey: Hex,\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n): Promise<{\n delegationAddress: Hex | undefined;\n isSupported: boolean;\n}> {\n const contractAddresses = getEIP7702ContractAddresses(\n chainId,\n messenger,\n publicKey,\n );\n\n const delegationAddress = await getDelegationAddress(\n address,\n messenger,\n networkClientId,\n );\n\n const isSupported = Boolean(\n delegationAddress &&\n contractAddresses.some(\n (contract) => contract.toLowerCase() === delegationAddress.toLowerCase(),\n ),\n );\n\n return {\n delegationAddress,\n isSupported,\n };\n}\n\n/**\n * Generate an EIP-7702 batch transaction.\n *\n * @param from - The sender address.\n * @param transactions - The transactions to batch.\n * @param options - Options bag.\n * @param options.atomic - Whether the batch should be atomic. Defaults to `true`.\n * When `true`, uses ERC-7579 ExecType `default` and all calls revert together.\n * When `false`, uses ERC-7579 ExecType `try` and individual calls can fail independently.\n * @returns The batch transaction.\n */\nexport function generateEIP7702BatchTransaction(\n from: Hex,\n transactions: BatchTransactionParams[],\n options?: { atomic?: boolean },\n): BatchTransactionParams {\n const atomic = options?.atomic ?? true;\n const erc7821Contract = Contract.getInterface(ABI_IERC7821);\n\n const calls = transactions.map((transaction) => {\n const { data, to, value } = transaction;\n\n return [\n to ?? '0x0000000000000000000000000000000000000000',\n value ?? '0x0',\n data ?? '0x',\n ];\n });\n\n const execType = atomic ? ERC7579_EXEC_TYPE_DEFAULT : ERC7579_EXEC_TYPE_TRY;\n const mode = `0x${ERC7579_CALL_TYPE_BATCH}${execType}`.padEnd(66, '0');\n\n const callData = defaultAbiCoder.encode([CALLS_SIGNATURE], [calls]);\n\n const data = erc7821Contract.encodeFunctionData(BATCH_FUNCTION_NAME, [\n mode,\n callData,\n ]) as Hex;\n\n log('Transaction data', data);\n\n return {\n data,\n to: from,\n };\n}\n\n/**\n * Sign an authorization list.\n *\n * @param options - Options bag.\n * @param options.authorizationList - The authorization list to sign.\n * @param options.messenger - The controller messenger.\n * @param options.transactionMeta - The transaction metadata.\n * @returns The signed authorization list.\n */\nexport async function signAuthorizationList({\n authorizationList,\n messenger,\n transactionMeta,\n}: {\n authorizationList?: AuthorizationList;\n messenger: TransactionControllerMessenger;\n transactionMeta: TransactionMeta;\n}): Promise<Required<AuthorizationList | undefined>> {\n if (!authorizationList) {\n return undefined;\n }\n\n const signedAuthorizationList: Required<AuthorizationList> = [];\n let index = 0;\n\n for (const authorization of authorizationList) {\n const signedAuthorization = await signAuthorization(\n authorization,\n transactionMeta,\n messenger,\n index,\n );\n\n signedAuthorizationList.push(signedAuthorization);\n index += 1;\n }\n\n return signedAuthorizationList;\n}\n\n/**\n * Decode a 65-byte EIP-7702 authorization signature into RLP-canonical\n * `r`, `s`, and `yParity` (no leading zero nibbles, `0x0` for zero).\n *\n * @param signature - The 65-byte signature.\n * @returns The decoded authorization fields.\n */\nexport function decodeAuthorizationSignature(signature: Hex): {\n r: Hex;\n s: Hex;\n yParity: Hex;\n} {\n // eslint-disable-next-line id-length\n const r = toCanonicalHex(signature.slice(0, 66));\n // eslint-disable-next-line id-length\n const s = toCanonicalHex(signature.slice(66, 130));\n // eslint-disable-next-line id-length\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = toCanonicalHex(toHex(v - 27 === 0 ? 0 : 1));\n\n return { r, s, yParity };\n}\n\n/**\n * Strip leading zero nibbles from a hex string to produce its RLP-canonical\n * form. Accepts input with or without a `0x` prefix; always returns\n * `0x`-prefixed. An all-zero input is preserved as `0x0`.\n *\n * @param value - Hex string with or without a `0x` prefix.\n * @returns The canonical `0x`-prefixed hex string.\n */\nfunction toCanonicalHex(value: string): Hex {\n const raw = value.startsWith('0x') ? value.slice(2) : value;\n const stripped = raw.replace(/^0+/u, '');\n return stripped.length === 0 ? '0x0' : `0x${stripped}`;\n}\n\n/**\n * Signs an authorization.\n *\n * @param authorization - The authorization to sign.\n * @param transactionMeta - The associated transaction metadata.\n * @param messenger - The messenger to use for signing.\n * @param index - The index of the authorization in the list.\n * @returns The signed authorization.\n */\nasync function signAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n messenger: TransactionControllerMessenger,\n index: number,\n): Promise<Required<Authorization>> {\n const finalAuthorization = prepareAuthorization(\n authorization,\n transactionMeta,\n index,\n );\n\n const { txParams } = transactionMeta;\n const { from } = txParams;\n const { address, chainId, nonce } = finalAuthorization;\n const chainIdDecimal = parseInt(chainId, 16);\n const nonceDecimal = parseInt(nonce, 16);\n\n const signature = await messenger.call(\n 'KeyringController:signEip7702Authorization',\n {\n chainId: chainIdDecimal,\n contractAddress: address,\n from,\n nonce: nonceDecimal,\n },\n );\n\n const { r, s, yParity } = decodeAuthorizationSignature(signature as Hex);\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce,\n r,\n s,\n yParity,\n };\n\n log('Signed authorization', result);\n\n return result;\n}\n\n/**\n * Prepares an authorization for signing by populating the chainId and nonce.\n *\n * @param authorization - The authorization to prepare.\n * @param transactionMeta - The associated transaction metadata.\n * @param index - The index of the authorization in the list.\n * @returns The prepared authorization.\n */\nfunction prepareAuthorization(\n authorization: Authorization,\n transactionMeta: TransactionMeta,\n index: number,\n): Authorization & { chainId: Hex; nonce: Hex } {\n const { chainId: existingChainId, nonce: existingNonce } = authorization;\n const { txParams, chainId: transactionChainId } = transactionMeta;\n const { nonce: transactionNonce } = txParams;\n\n const chainId = existingChainId ?? transactionChainId;\n let nonce = existingNonce;\n\n nonce ??= toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n\n const result = {\n ...authorization,\n chainId,\n nonce,\n };\n\n log('Prepared authorization', result);\n\n return result;\n}\n"]}
@@ -10,6 +10,7 @@ const types_1 = require("../types.cjs");
10
10
  const eip7702_1 = require("./eip7702.cjs");
11
11
  const feature_flags_1 = require("./feature-flags.cjs");
12
12
  const provider_1 = require("./provider.cjs");
13
+ const revert_reason_1 = require("./revert-reason.cjs");
13
14
  exports.log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'gas');
14
15
  exports.FIXED_GAS = '0x5208';
15
16
  exports.DEFAULT_GAS_MULTIPLIER = 1.5;
@@ -24,10 +25,13 @@ exports.DUMMY_AUTHORIZATION_SIGNATURE = '0x1111111111111111111111111111111111111
24
25
  async function updateGas(request) {
25
26
  const { txMeta } = request;
26
27
  const initialParams = { ...txMeta.txParams };
27
- const [gas, simulationFails, gasLimitNoBuffer] = await getGas(request);
28
+ const [gas, simulationFails, gasLimitNoBuffer, gasRevert] = await getGas(request);
28
29
  txMeta.txParams.gas = gas;
29
30
  txMeta.simulationFails = simulationFails;
30
31
  txMeta.gasLimitNoBuffer = gasLimitNoBuffer;
32
+ if (gasRevert) {
33
+ txMeta.revert = { ...txMeta.revert, gas: gasRevert };
34
+ }
31
35
  if (!initialParams.gas) {
32
36
  txMeta.originalGasEstimate = txMeta.txParams.gas;
33
37
  }
@@ -70,6 +74,7 @@ async function estimateGas({ ignoreDelegationSignatures, isSimulationEnabled, ge
70
74
  delete request.maxPriorityFeePerGas;
71
75
  let estimatedGas = fallback;
72
76
  let simulationFails;
77
+ let gasRevert;
73
78
  const isUpgradeWithData = txParams.type === types_1.TransactionEnvelopeType.setCode &&
74
79
  Boolean(authorizationList?.length) &&
75
80
  Boolean(data) &&
@@ -99,11 +104,13 @@ async function estimateGas({ ignoreDelegationSignatures, isSimulationEnabled, ge
99
104
  blockGasLimit,
100
105
  },
101
106
  };
102
- (0, exports.log)('Estimation failed', { ...simulationFails, fallback });
107
+ gasRevert = (0, revert_reason_1.decodeRevert)(error, 'gas');
108
+ (0, exports.log)('Estimation failed', { ...simulationFails, fallback, gasRevert });
103
109
  }
104
110
  return {
105
111
  blockGasLimit,
106
112
  estimatedGas,
113
+ gasRevert,
107
114
  isUpgradeWithData,
108
115
  simulationFails,
109
116
  };
@@ -115,7 +122,10 @@ async function estimateGasBatch({ from, getSimulationConfig, isAtomicBatchSuppor
115
122
  address: from,
116
123
  chainIds: [chainId],
117
124
  });
118
- const chainResult = is7702Result.find((result) => result.chainId === chainId);
125
+ const accountSupports7702 = (0, eip7702_1.doesAccountSupportEIP7702)(messenger, from);
126
+ const chainResult = accountSupports7702
127
+ ? is7702Result.find((result) => result.chainId === chainId)
128
+ : undefined;
119
129
  const isUpgradeRequired = Boolean(chainResult && !chainResult.isSupported);
120
130
  if (isUpgradeRequired && !chainResult?.upgradeContractAddress) {
121
131
  throw new Error('Upgrade contract address not found');
@@ -259,7 +269,7 @@ async function getGas(request) {
259
269
  (0, exports.log)('Using fixed value', exports.FIXED_GAS);
260
270
  return [exports.FIXED_GAS, undefined, exports.FIXED_GAS];
261
271
  }
262
- const { blockGasLimit, estimatedGas, isUpgradeWithData, simulationFails } = await estimateGas({
272
+ const { blockGasLimit, estimatedGas, gasRevert, isUpgradeWithData, simulationFails, } = await estimateGas({
263
273
  isSimulationEnabled,
264
274
  getSimulationConfig,
265
275
  messenger,
@@ -274,7 +284,7 @@ async function getGas(request) {
274
284
  (0, exports.log)('Gas buffer disabled');
275
285
  }
276
286
  if (simulationFails || disableGasBuffer) {
277
- return [estimatedGas, simulationFails, estimatedGas];
287
+ return [estimatedGas, simulationFails, estimatedGas, gasRevert];
278
288
  }
279
289
  const bufferMultiplier = (0, feature_flags_1.getGasEstimateBuffer)({
280
290
  chainId,
@@ -285,7 +295,7 @@ async function getGas(request) {
285
295
  (0, exports.log)('Buffer', bufferMultiplier);
286
296
  const bufferedGas = addGasBuffer(estimatedGas, blockGasLimit, bufferMultiplier);
287
297
  (0, exports.log)('Buffered gas', bufferedGas);
288
- return [bufferedGas, simulationFails, estimatedGas];
298
+ return [bufferedGas, simulationFails, estimatedGas, gasRevert];
289
299
  }
290
300
  /**
291
301
  * Determine if the gas for the provided request should be fixed.