@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.
- package/CHANGELOG.md +36 -1
- package/dist/TransactionController-method-action-types.cjs.map +1 -1
- package/dist/TransactionController-method-action-types.d.cts +12 -1
- package/dist/TransactionController-method-action-types.d.cts.map +1 -1
- package/dist/TransactionController-method-action-types.d.mts +12 -1
- package/dist/TransactionController-method-action-types.d.mts.map +1 -1
- package/dist/TransactionController-method-action-types.mjs.map +1 -1
- package/dist/TransactionController.cjs +33 -1
- package/dist/TransactionController.cjs.map +1 -1
- package/dist/TransactionController.d.cts +2 -2
- package/dist/TransactionController.d.cts.map +1 -1
- package/dist/TransactionController.d.mts +2 -2
- package/dist/TransactionController.d.mts.map +1 -1
- package/dist/TransactionController.mjs +33 -1
- package/dist/TransactionController.mjs.map +1 -1
- package/dist/api/simulation-api.cjs.map +1 -1
- package/dist/api/simulation-api.d.cts +2 -0
- package/dist/api/simulation-api.d.cts.map +1 -1
- package/dist/api/simulation-api.d.mts +2 -0
- package/dist/api/simulation-api.d.mts.map +1 -1
- package/dist/api/simulation-api.mjs.map +1 -1
- package/dist/helpers/PendingTransactionTracker.cjs +13 -2
- package/dist/helpers/PendingTransactionTracker.cjs.map +1 -1
- package/dist/helpers/PendingTransactionTracker.d.cts.map +1 -1
- package/dist/helpers/PendingTransactionTracker.d.mts.map +1 -1
- package/dist/helpers/PendingTransactionTracker.mjs +13 -2
- package/dist/helpers/PendingTransactionTracker.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +22 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +22 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/balance-changes.cjs +21 -1
- package/dist/utils/balance-changes.cjs.map +1 -1
- package/dist/utils/balance-changes.d.cts +2 -1
- package/dist/utils/balance-changes.d.cts.map +1 -1
- package/dist/utils/balance-changes.d.mts +2 -1
- package/dist/utils/balance-changes.d.mts.map +1 -1
- package/dist/utils/balance-changes.mjs +21 -1
- package/dist/utils/balance-changes.mjs.map +1 -1
- package/dist/utils/batch.cjs +52 -2
- package/dist/utils/batch.cjs.map +1 -1
- package/dist/utils/batch.d.cts.map +1 -1
- package/dist/utils/batch.d.mts.map +1 -1
- package/dist/utils/batch.mjs +53 -3
- package/dist/utils/batch.mjs.map +1 -1
- package/dist/utils/eip7702.cjs +56 -8
- package/dist/utils/eip7702.cjs.map +1 -1
- package/dist/utils/eip7702.d.cts +25 -0
- package/dist/utils/eip7702.d.cts.map +1 -1
- package/dist/utils/eip7702.d.mts +25 -0
- package/dist/utils/eip7702.d.mts.map +1 -1
- package/dist/utils/eip7702.mjs +53 -7
- package/dist/utils/eip7702.mjs.map +1 -1
- package/dist/utils/gas.cjs +16 -6
- package/dist/utils/gas.cjs.map +1 -1
- package/dist/utils/gas.d.cts +2 -1
- package/dist/utils/gas.d.cts.map +1 -1
- package/dist/utils/gas.d.mts +2 -1
- package/dist/utils/gas.d.mts.map +1 -1
- package/dist/utils/gas.mjs +17 -7
- package/dist/utils/gas.mjs.map +1 -1
- package/dist/utils/revert-reason.cjs +192 -0
- package/dist/utils/revert-reason.cjs.map +1 -0
- package/dist/utils/revert-reason.d.cts +57 -0
- package/dist/utils/revert-reason.d.cts.map +1 -0
- package/dist/utils/revert-reason.d.mts +57 -0
- package/dist/utils/revert-reason.d.mts.map +1 -0
- package/dist/utils/revert-reason.mjs +186 -0
- package/dist/utils/revert-reason.mjs.map +1 -0
- package/package.json +4 -4
package/dist/utils/eip7702.cjs
CHANGED
|
@@ -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
|
-
|
|
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"]}
|
package/dist/utils/eip7702.d.cts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/utils/eip7702.d.mts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/utils/eip7702.mjs
CHANGED
|
@@ -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
|
-
|
|
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"]}
|
package/dist/utils/gas.cjs
CHANGED
|
@@ -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,
|
|
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
|
|
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.
|