@metamask-previews/transaction-controller 45.1.0-preview-df91d059 → 45.1.0-preview-862b5dac
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 +21 -0
- package/dist/TransactionController.cjs +45 -4
- package/dist/TransactionController.cjs.map +1 -1
- package/dist/TransactionController.d.cts +20 -3
- package/dist/TransactionController.d.cts.map +1 -1
- package/dist/TransactionController.d.mts +20 -3
- package/dist/TransactionController.d.mts.map +1 -1
- package/dist/TransactionController.mjs +45 -4
- package/dist/TransactionController.mjs.map +1 -1
- package/dist/constants.cjs +20 -1
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +15 -0
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +15 -0
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +19 -0
- package/dist/constants.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs +5 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +51 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +51 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +5 -0
- package/dist/types.mjs.map +1 -1
- package/dist/utils/batch.cjs +84 -0
- package/dist/utils/batch.cjs.map +1 -0
- package/dist/utils/batch.d.cts +32 -0
- package/dist/utils/batch.d.cts.map +1 -0
- package/dist/utils/batch.d.mts +32 -0
- package/dist/utils/batch.d.mts.map +1 -0
- package/dist/utils/batch.mjs +79 -0
- package/dist/utils/batch.mjs.map +1 -0
- package/dist/utils/eip7702.cjs +76 -1
- package/dist/utils/eip7702.cjs.map +1 -1
- package/dist/utils/eip7702.d.cts +35 -1
- package/dist/utils/eip7702.d.cts.map +1 -1
- package/dist/utils/eip7702.d.mts +35 -1
- package/dist/utils/eip7702.d.mts.map +1 -1
- package/dist/utils/eip7702.mjs +74 -2
- package/dist/utils/eip7702.mjs.map +1 -1
- package/dist/utils/feature-flags.cjs +53 -0
- package/dist/utils/feature-flags.cjs.map +1 -0
- package/dist/utils/feature-flags.d.cts +34 -0
- package/dist/utils/feature-flags.d.cts.map +1 -0
- package/dist/utils/feature-flags.d.mts +34 -0
- package/dist/utils/feature-flags.d.mts.map +1 -0
- package/dist/utils/feature-flags.mjs +47 -0
- package/dist/utils/feature-flags.mjs.map +1 -0
- package/dist/utils/validation.cjs +15 -4
- package/dist/utils/validation.cjs.map +1 -1
- package/dist/utils/validation.d.cts +7 -3
- package/dist/utils/validation.d.cts.map +1 -1
- package/dist/utils/validation.d.mts +7 -3
- package/dist/utils/validation.d.mts.map +1 -1
- package/dist/utils/validation.mjs +16 -5
- package/dist/utils/validation.mjs.map +1 -1
- package/package.json +5 -3
package/dist/utils/eip7702.cjs
CHANGED
|
@@ -1,10 +1,85 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.signAuthorizationList = void 0;
|
|
3
|
+
exports.signAuthorizationList = exports.generateEIP7702BatchTransaction = exports.isAccountUpgradedToEIP7702 = exports.doesChainSupportEIP7702 = exports.CALLS_SIGNATURE = exports.BATCH_FUNCTION_NAME = exports.DELEGATION_PREFIX = void 0;
|
|
4
|
+
const abi_1 = require("@ethersproject/abi");
|
|
5
|
+
const contracts_1 = require("@ethersproject/contracts");
|
|
4
6
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
5
7
|
const utils_1 = require("@metamask/utils");
|
|
8
|
+
const feature_flags_1 = require("./feature-flags.cjs");
|
|
6
9
|
const logger_1 = require("../logger.cjs");
|
|
10
|
+
const constants_1 = require("../constants.cjs");
|
|
11
|
+
exports.DELEGATION_PREFIX = '0xef0100';
|
|
12
|
+
exports.BATCH_FUNCTION_NAME = 'execute';
|
|
13
|
+
exports.CALLS_SIGNATURE = '(address,uint256,bytes)[]';
|
|
7
14
|
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'eip-7702');
|
|
15
|
+
/**
|
|
16
|
+
* Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
|
|
17
|
+
*
|
|
18
|
+
* @param chainId - Hexadecimal ID of the chain.
|
|
19
|
+
* @param messenger - Messenger instance.
|
|
20
|
+
* @returns True if the chain supports EIP-7702.
|
|
21
|
+
*/
|
|
22
|
+
function doesChainSupportEIP7702(chainId, messenger) {
|
|
23
|
+
const supportedChains = (0, feature_flags_1.getEIP7702SupportedChains)(messenger);
|
|
24
|
+
return supportedChains.some((supportedChainId) => supportedChainId.toLowerCase() === chainId.toLowerCase());
|
|
25
|
+
}
|
|
26
|
+
exports.doesChainSupportEIP7702 = doesChainSupportEIP7702;
|
|
27
|
+
/**
|
|
28
|
+
* Determine if an account has been upgraded to a supported EIP-7702 contract.
|
|
29
|
+
*
|
|
30
|
+
* @param address - The EOA address to check.
|
|
31
|
+
* @param chainId - The chain ID.
|
|
32
|
+
* @param messenger - The messenger instance.
|
|
33
|
+
* @param ethQuery - The EthQuery instance to communicate with the blockchain.
|
|
34
|
+
* @returns An object with the results of the check.
|
|
35
|
+
*/
|
|
36
|
+
async function isAccountUpgradedToEIP7702(address, chainId, messenger, ethQuery) {
|
|
37
|
+
const contractAddresses = (0, feature_flags_1.getEIP7702ContractAddresses)(chainId, messenger);
|
|
38
|
+
const code = await (0, controller_utils_1.query)(ethQuery, 'eth_getCode', [address]);
|
|
39
|
+
const normalizedCode = (0, utils_1.add0x)(code?.toLowerCase?.() ?? '');
|
|
40
|
+
const hasDelegation = code?.length === 48 && normalizedCode.startsWith(exports.DELEGATION_PREFIX);
|
|
41
|
+
const delegationAddress = hasDelegation
|
|
42
|
+
? (0, utils_1.add0x)(normalizedCode.slice(exports.DELEGATION_PREFIX.length))
|
|
43
|
+
: undefined;
|
|
44
|
+
const isSupported = Boolean(delegationAddress &&
|
|
45
|
+
contractAddresses.some((contract) => contract.toLowerCase() === delegationAddress.toLowerCase()));
|
|
46
|
+
return {
|
|
47
|
+
delegationAddress,
|
|
48
|
+
isSupported,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
exports.isAccountUpgradedToEIP7702 = isAccountUpgradedToEIP7702;
|
|
52
|
+
/**
|
|
53
|
+
* Generate an EIP-7702 batch transaction.
|
|
54
|
+
*
|
|
55
|
+
* @param from - The sender address.
|
|
56
|
+
* @param transactions - The transactions to batch.
|
|
57
|
+
* @returns The batch transaction.
|
|
58
|
+
*/
|
|
59
|
+
function generateEIP7702BatchTransaction(from, transactions) {
|
|
60
|
+
const erc7821Contract = contracts_1.Contract.getInterface(constants_1.ABI_IERC7821);
|
|
61
|
+
const calls = transactions.map((transaction) => {
|
|
62
|
+
const { data, to, value } = transaction;
|
|
63
|
+
return [
|
|
64
|
+
to ?? '0x0000000000000000000000000000000000000000',
|
|
65
|
+
value ?? '0x0',
|
|
66
|
+
data ?? '0x',
|
|
67
|
+
];
|
|
68
|
+
});
|
|
69
|
+
// Single batch mode, no opData.
|
|
70
|
+
const mode = '0x01'.padEnd(66, '0');
|
|
71
|
+
const callData = abi_1.defaultAbiCoder.encode([exports.CALLS_SIGNATURE], [calls]);
|
|
72
|
+
const data = erc7821Contract.encodeFunctionData(exports.BATCH_FUNCTION_NAME, [
|
|
73
|
+
mode,
|
|
74
|
+
callData,
|
|
75
|
+
]);
|
|
76
|
+
log('Transaction data', data);
|
|
77
|
+
return {
|
|
78
|
+
data,
|
|
79
|
+
to: from,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
exports.generateEIP7702BatchTransaction = generateEIP7702BatchTransaction;
|
|
8
83
|
/**
|
|
9
84
|
* Sign an authorization list.
|
|
10
85
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip7702.cjs","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\n\nexport type KeyringControllerAuthorization = [\n chainId: number,\n contractAddress: string,\n nonce: number,\n];\n\nexport type KeyringControllerSignAuthorization = {\n type: 'KeyringController:signAuthorization';\n handler: (authorization: KeyringControllerAuthorization) => Promise<string>;\n};\n\nconst log = createModuleLogger(projectLogger, 'eip-7702');\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 { 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:signAuthorization',\n [chainIdDecimal, address, nonceDecimal],\n );\n\n const r = signature.slice(0, 66) as Hex;\n const s = `0x${signature.slice(66, 130)}` as Hex;\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = v - 27 === 0 ? '0x' : '0x1';\n const finalNonce = nonceDecimal === 0 ? '0x' : nonce;\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce: finalNonce,\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 if (nonce === undefined) {\n nonce = toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n }\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 { query, toHex } from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport { createModuleLogger, type Hex, add0x } from '@metamask/utils';\n\nimport {\n getEIP7702ContractAddresses,\n getEIP7702SupportedChains,\n} from './feature-flags';\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n BatchTransactionParams,\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\nimport { ABI_IERC7821 } from '../constants';\n\nexport type KeyringControllerAuthorization = [\n chainId: number,\n contractAddress: string,\n nonce: number,\n];\n\nexport type KeyringControllerSignAuthorization = {\n type: 'KeyringController:signAuthorization';\n handler: (authorization: KeyringControllerAuthorization) => Promise<string>;\n};\n\nexport const DELEGATION_PREFIX = '0xef0100';\nexport const BATCH_FUNCTION_NAME = 'execute';\nexport const CALLS_SIGNATURE = '(address,uint256,bytes)[]';\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) {\n const supportedChains = getEIP7702SupportedChains(messenger);\n\n return supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === chainId.toLowerCase(),\n );\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 messenger - The messenger instance.\n * @param ethQuery - The EthQuery instance to communicate with the blockchain.\n * @returns An object with the results of the check.\n */\nexport async function isAccountUpgradedToEIP7702(\n address: Hex,\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n ethQuery: EthQuery,\n) {\n const contractAddresses = getEIP7702ContractAddresses(chainId, messenger);\n const code = await query(ethQuery, 'eth_getCode', [address]);\n const normalizedCode = add0x(code?.toLowerCase?.() ?? '');\n\n const hasDelegation =\n code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);\n\n const delegationAddress = hasDelegation\n ? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))\n : undefined;\n\n const isSupported = Boolean(\n delegationAddress &&\n contractAddresses.some(\n (contract) =>\n 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 * @returns The batch transaction.\n */\nexport function generateEIP7702BatchTransaction(\n from: Hex,\n transactions: BatchTransactionParams[],\n): BatchTransactionParams {\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 // Single batch mode, no opData.\n const mode = '0x01'.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 { 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:signAuthorization',\n [chainIdDecimal, address, nonceDecimal],\n );\n\n const r = signature.slice(0, 66) as Hex;\n const s = `0x${signature.slice(66, 130)}` as Hex;\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = v - 27 === 0 ? '0x' : '0x1';\n const finalNonce = nonceDecimal === 0 ? '0x' : nonce;\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce: finalNonce,\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 if (nonce === undefined) {\n nonce = toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n }\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
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type EthQuery from "@metamask/eth-query";
|
|
2
|
+
import { type Hex } from "@metamask/utils";
|
|
1
3
|
import type { TransactionControllerMessenger } from "../TransactionController.cjs";
|
|
2
|
-
import type { AuthorizationList, TransactionMeta } from "../types.cjs";
|
|
4
|
+
import type { BatchTransactionParams, AuthorizationList, TransactionMeta } from "../types.cjs";
|
|
3
5
|
export type KeyringControllerAuthorization = [
|
|
4
6
|
chainId: number,
|
|
5
7
|
contractAddress: string,
|
|
@@ -9,6 +11,38 @@ export type KeyringControllerSignAuthorization = {
|
|
|
9
11
|
type: 'KeyringController:signAuthorization';
|
|
10
12
|
handler: (authorization: KeyringControllerAuthorization) => Promise<string>;
|
|
11
13
|
};
|
|
14
|
+
export declare const DELEGATION_PREFIX = "0xef0100";
|
|
15
|
+
export declare const BATCH_FUNCTION_NAME = "execute";
|
|
16
|
+
export declare const CALLS_SIGNATURE = "(address,uint256,bytes)[]";
|
|
17
|
+
/**
|
|
18
|
+
* Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
|
|
19
|
+
*
|
|
20
|
+
* @param chainId - Hexadecimal ID of the chain.
|
|
21
|
+
* @param messenger - Messenger instance.
|
|
22
|
+
* @returns True if the chain supports EIP-7702.
|
|
23
|
+
*/
|
|
24
|
+
export declare function doesChainSupportEIP7702(chainId: Hex, messenger: TransactionControllerMessenger): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Determine if an account has been upgraded to a supported EIP-7702 contract.
|
|
27
|
+
*
|
|
28
|
+
* @param address - The EOA address to check.
|
|
29
|
+
* @param chainId - The chain ID.
|
|
30
|
+
* @param messenger - The messenger instance.
|
|
31
|
+
* @param ethQuery - The EthQuery instance to communicate with the blockchain.
|
|
32
|
+
* @returns An object with the results of the check.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isAccountUpgradedToEIP7702(address: Hex, chainId: Hex, messenger: TransactionControllerMessenger, ethQuery: EthQuery): Promise<{
|
|
35
|
+
delegationAddress: `0x${string}` | undefined;
|
|
36
|
+
isSupported: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Generate an EIP-7702 batch transaction.
|
|
40
|
+
*
|
|
41
|
+
* @param from - The sender address.
|
|
42
|
+
* @param transactions - The transactions to batch.
|
|
43
|
+
* @returns The batch transaction.
|
|
44
|
+
*/
|
|
45
|
+
export declare function generateEIP7702BatchTransaction(from: Hex, transactions: BatchTransactionParams[]): BatchTransactionParams;
|
|
12
46
|
/**
|
|
13
47
|
* Sign an authorization list.
|
|
14
48
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip7702.d.cts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eip7702.d.cts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,QAAQ,4BAA4B;AAChD,OAAO,EAAsB,KAAK,GAAG,EAAS,wBAAwB;AAOtE,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,eAAe,EAChB,qBAAiB;AAGlB,MAAM,MAAM,8BAA8B,GAAG;IAC3C,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,MAAM;IACvB,KAAK,EAAE,MAAM;CACd,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,qCAAqC,CAAC;IAC5C,OAAO,EAAE,CAAC,aAAa,EAAE,8BAA8B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7E,CAAC;AAEF,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAI3D;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,WAQ1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,EACzC,QAAQ,EAAE,QAAQ;;;GAyBnB;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,sBAAsB,EAAE,GACrC,sBAAsB,CA6BxB;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"}
|
package/dist/utils/eip7702.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type EthQuery from "@metamask/eth-query";
|
|
2
|
+
import { type Hex } from "@metamask/utils";
|
|
1
3
|
import type { TransactionControllerMessenger } from "../TransactionController.mjs";
|
|
2
|
-
import type { AuthorizationList, TransactionMeta } from "../types.mjs";
|
|
4
|
+
import type { BatchTransactionParams, AuthorizationList, TransactionMeta } from "../types.mjs";
|
|
3
5
|
export type KeyringControllerAuthorization = [
|
|
4
6
|
chainId: number,
|
|
5
7
|
contractAddress: string,
|
|
@@ -9,6 +11,38 @@ export type KeyringControllerSignAuthorization = {
|
|
|
9
11
|
type: 'KeyringController:signAuthorization';
|
|
10
12
|
handler: (authorization: KeyringControllerAuthorization) => Promise<string>;
|
|
11
13
|
};
|
|
14
|
+
export declare const DELEGATION_PREFIX = "0xef0100";
|
|
15
|
+
export declare const BATCH_FUNCTION_NAME = "execute";
|
|
16
|
+
export declare const CALLS_SIGNATURE = "(address,uint256,bytes)[]";
|
|
17
|
+
/**
|
|
18
|
+
* Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
|
|
19
|
+
*
|
|
20
|
+
* @param chainId - Hexadecimal ID of the chain.
|
|
21
|
+
* @param messenger - Messenger instance.
|
|
22
|
+
* @returns True if the chain supports EIP-7702.
|
|
23
|
+
*/
|
|
24
|
+
export declare function doesChainSupportEIP7702(chainId: Hex, messenger: TransactionControllerMessenger): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Determine if an account has been upgraded to a supported EIP-7702 contract.
|
|
27
|
+
*
|
|
28
|
+
* @param address - The EOA address to check.
|
|
29
|
+
* @param chainId - The chain ID.
|
|
30
|
+
* @param messenger - The messenger instance.
|
|
31
|
+
* @param ethQuery - The EthQuery instance to communicate with the blockchain.
|
|
32
|
+
* @returns An object with the results of the check.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isAccountUpgradedToEIP7702(address: Hex, chainId: Hex, messenger: TransactionControllerMessenger, ethQuery: EthQuery): Promise<{
|
|
35
|
+
delegationAddress: `0x${string}` | undefined;
|
|
36
|
+
isSupported: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Generate an EIP-7702 batch transaction.
|
|
40
|
+
*
|
|
41
|
+
* @param from - The sender address.
|
|
42
|
+
* @param transactions - The transactions to batch.
|
|
43
|
+
* @returns The batch transaction.
|
|
44
|
+
*/
|
|
45
|
+
export declare function generateEIP7702BatchTransaction(from: Hex, transactions: BatchTransactionParams[]): BatchTransactionParams;
|
|
12
46
|
/**
|
|
13
47
|
* Sign an authorization list.
|
|
14
48
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip7702.d.mts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eip7702.d.mts","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,QAAQ,4BAA4B;AAChD,OAAO,EAAsB,KAAK,GAAG,EAAS,wBAAwB;AAOtE,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,eAAe,EAChB,qBAAiB;AAGlB,MAAM,MAAM,8BAA8B,GAAG;IAC3C,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,MAAM;IACvB,KAAK,EAAE,MAAM;CACd,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,qCAAqC,CAAC;IAC5C,OAAO,EAAE,CAAC,aAAa,EAAE,8BAA8B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7E,CAAC;AAEF,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAI3D;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,WAQ1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,EACzC,QAAQ,EAAE,QAAQ;;;GAyBnB;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,sBAAsB,EAAE,GACrC,sBAAsB,CA6BxB;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"}
|
package/dist/utils/eip7702.mjs
CHANGED
|
@@ -1,7 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { defaultAbiCoder } from "@ethersproject/abi";
|
|
2
|
+
import { Contract } from "@ethersproject/contracts";
|
|
3
|
+
import { query, toHex } from "@metamask/controller-utils";
|
|
4
|
+
import { createModuleLogger, add0x } from "@metamask/utils";
|
|
5
|
+
import { getEIP7702ContractAddresses, getEIP7702SupportedChains } from "./feature-flags.mjs";
|
|
3
6
|
import { projectLogger } from "../logger.mjs";
|
|
7
|
+
import { ABI_IERC7821 } from "../constants.mjs";
|
|
8
|
+
export const DELEGATION_PREFIX = '0xef0100';
|
|
9
|
+
export const BATCH_FUNCTION_NAME = 'execute';
|
|
10
|
+
export const CALLS_SIGNATURE = '(address,uint256,bytes)[]';
|
|
4
11
|
const log = createModuleLogger(projectLogger, 'eip-7702');
|
|
12
|
+
/**
|
|
13
|
+
* Determine if a chain supports EIP-7702 using LaunchDarkly feature flag.
|
|
14
|
+
*
|
|
15
|
+
* @param chainId - Hexadecimal ID of the chain.
|
|
16
|
+
* @param messenger - Messenger instance.
|
|
17
|
+
* @returns True if the chain supports EIP-7702.
|
|
18
|
+
*/
|
|
19
|
+
export function doesChainSupportEIP7702(chainId, messenger) {
|
|
20
|
+
const supportedChains = getEIP7702SupportedChains(messenger);
|
|
21
|
+
return supportedChains.some((supportedChainId) => supportedChainId.toLowerCase() === chainId.toLowerCase());
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Determine if an account has been upgraded to a supported EIP-7702 contract.
|
|
25
|
+
*
|
|
26
|
+
* @param address - The EOA address to check.
|
|
27
|
+
* @param chainId - The chain ID.
|
|
28
|
+
* @param messenger - The messenger instance.
|
|
29
|
+
* @param ethQuery - The EthQuery instance to communicate with the blockchain.
|
|
30
|
+
* @returns An object with the results of the check.
|
|
31
|
+
*/
|
|
32
|
+
export async function isAccountUpgradedToEIP7702(address, chainId, messenger, ethQuery) {
|
|
33
|
+
const contractAddresses = getEIP7702ContractAddresses(chainId, messenger);
|
|
34
|
+
const code = await query(ethQuery, 'eth_getCode', [address]);
|
|
35
|
+
const normalizedCode = add0x(code?.toLowerCase?.() ?? '');
|
|
36
|
+
const hasDelegation = code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);
|
|
37
|
+
const delegationAddress = hasDelegation
|
|
38
|
+
? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))
|
|
39
|
+
: undefined;
|
|
40
|
+
const isSupported = Boolean(delegationAddress &&
|
|
41
|
+
contractAddresses.some((contract) => contract.toLowerCase() === delegationAddress.toLowerCase()));
|
|
42
|
+
return {
|
|
43
|
+
delegationAddress,
|
|
44
|
+
isSupported,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate an EIP-7702 batch transaction.
|
|
49
|
+
*
|
|
50
|
+
* @param from - The sender address.
|
|
51
|
+
* @param transactions - The transactions to batch.
|
|
52
|
+
* @returns The batch transaction.
|
|
53
|
+
*/
|
|
54
|
+
export function generateEIP7702BatchTransaction(from, transactions) {
|
|
55
|
+
const erc7821Contract = Contract.getInterface(ABI_IERC7821);
|
|
56
|
+
const calls = transactions.map((transaction) => {
|
|
57
|
+
const { data, to, value } = transaction;
|
|
58
|
+
return [
|
|
59
|
+
to ?? '0x0000000000000000000000000000000000000000',
|
|
60
|
+
value ?? '0x0',
|
|
61
|
+
data ?? '0x',
|
|
62
|
+
];
|
|
63
|
+
});
|
|
64
|
+
// Single batch mode, no opData.
|
|
65
|
+
const mode = '0x01'.padEnd(66, '0');
|
|
66
|
+
const callData = defaultAbiCoder.encode([CALLS_SIGNATURE], [calls]);
|
|
67
|
+
const data = erc7821Contract.encodeFunctionData(BATCH_FUNCTION_NAME, [
|
|
68
|
+
mode,
|
|
69
|
+
callData,
|
|
70
|
+
]);
|
|
71
|
+
log('Transaction data', data);
|
|
72
|
+
return {
|
|
73
|
+
data,
|
|
74
|
+
to: from,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
5
77
|
/**
|
|
6
78
|
* Sign an authorization list.
|
|
7
79
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eip7702.mjs","sourceRoot":"","sources":["../../src/utils/eip7702.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\n\nexport type KeyringControllerAuthorization = [\n chainId: number,\n contractAddress: string,\n nonce: number,\n];\n\nexport type KeyringControllerSignAuthorization = {\n type: 'KeyringController:signAuthorization';\n handler: (authorization: KeyringControllerAuthorization) => Promise<string>;\n};\n\nconst log = createModuleLogger(projectLogger, 'eip-7702');\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 { 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:signAuthorization',\n [chainIdDecimal, address, nonceDecimal],\n );\n\n const r = signature.slice(0, 66) as Hex;\n const s = `0x${signature.slice(66, 130)}` as Hex;\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = v - 27 === 0 ? '0x' : '0x1';\n const finalNonce = nonceDecimal === 0 ? '0x' : nonce;\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce: finalNonce,\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 if (nonce === undefined) {\n nonce = toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n }\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 { query, toHex } from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport { createModuleLogger, type Hex, add0x } from '@metamask/utils';\n\nimport {\n getEIP7702ContractAddresses,\n getEIP7702SupportedChains,\n} from './feature-flags';\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n BatchTransactionParams,\n Authorization,\n AuthorizationList,\n TransactionMeta,\n} from '../types';\nimport { ABI_IERC7821 } from '../constants';\n\nexport type KeyringControllerAuthorization = [\n chainId: number,\n contractAddress: string,\n nonce: number,\n];\n\nexport type KeyringControllerSignAuthorization = {\n type: 'KeyringController:signAuthorization';\n handler: (authorization: KeyringControllerAuthorization) => Promise<string>;\n};\n\nexport const DELEGATION_PREFIX = '0xef0100';\nexport const BATCH_FUNCTION_NAME = 'execute';\nexport const CALLS_SIGNATURE = '(address,uint256,bytes)[]';\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) {\n const supportedChains = getEIP7702SupportedChains(messenger);\n\n return supportedChains.some(\n (supportedChainId) =>\n supportedChainId.toLowerCase() === chainId.toLowerCase(),\n );\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 messenger - The messenger instance.\n * @param ethQuery - The EthQuery instance to communicate with the blockchain.\n * @returns An object with the results of the check.\n */\nexport async function isAccountUpgradedToEIP7702(\n address: Hex,\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n ethQuery: EthQuery,\n) {\n const contractAddresses = getEIP7702ContractAddresses(chainId, messenger);\n const code = await query(ethQuery, 'eth_getCode', [address]);\n const normalizedCode = add0x(code?.toLowerCase?.() ?? '');\n\n const hasDelegation =\n code?.length === 48 && normalizedCode.startsWith(DELEGATION_PREFIX);\n\n const delegationAddress = hasDelegation\n ? add0x(normalizedCode.slice(DELEGATION_PREFIX.length))\n : undefined;\n\n const isSupported = Boolean(\n delegationAddress &&\n contractAddresses.some(\n (contract) =>\n 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 * @returns The batch transaction.\n */\nexport function generateEIP7702BatchTransaction(\n from: Hex,\n transactions: BatchTransactionParams[],\n): BatchTransactionParams {\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 // Single batch mode, no opData.\n const mode = '0x01'.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 { 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:signAuthorization',\n [chainIdDecimal, address, nonceDecimal],\n );\n\n const r = signature.slice(0, 66) as Hex;\n const s = `0x${signature.slice(66, 130)}` as Hex;\n const v = parseInt(signature.slice(130, 132), 16);\n const yParity = v - 27 === 0 ? '0x' : '0x1';\n const finalNonce = nonceDecimal === 0 ? '0x' : nonce;\n\n const result: Required<Authorization> = {\n address,\n chainId,\n nonce: finalNonce,\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 if (nonce === undefined) {\n nonce = toHex(parseInt(transactionNonce as string, 16) + 1 + index);\n }\n\n const result = {\n ...authorization,\n chainId,\n nonce,\n };\n\n log('Prepared authorization', result);\n\n return result;\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getEIP7702UpgradeContractAddress = exports.getEIP7702ContractAddresses = exports.getEIP7702SupportedChains = exports.FEATURE_FLAG_EIP_7702 = void 0;
|
|
4
|
+
const utils_1 = require("@metamask/utils");
|
|
5
|
+
const logger_1 = require("../logger.cjs");
|
|
6
|
+
exports.FEATURE_FLAG_EIP_7702 = 'confirmations-eip-7702';
|
|
7
|
+
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'feature-flags');
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves the supported EIP-7702 chains.
|
|
10
|
+
*
|
|
11
|
+
* @param messenger - The controller messenger instance.
|
|
12
|
+
* @returns The supported chains.
|
|
13
|
+
*/
|
|
14
|
+
function getEIP7702SupportedChains(messenger) {
|
|
15
|
+
const featureFlags = getFeatureFlags(messenger);
|
|
16
|
+
return featureFlags?.[exports.FEATURE_FLAG_EIP_7702]?.supportedChains ?? [];
|
|
17
|
+
}
|
|
18
|
+
exports.getEIP7702SupportedChains = getEIP7702SupportedChains;
|
|
19
|
+
/**
|
|
20
|
+
* Retrieves the supported EIP-7702 contract addresses for a given chain ID.
|
|
21
|
+
*
|
|
22
|
+
* @param chainId - The chain ID.
|
|
23
|
+
* @param messenger - The controller messenger instance.
|
|
24
|
+
* @returns The supported contract addresses.
|
|
25
|
+
*/
|
|
26
|
+
function getEIP7702ContractAddresses(chainId, messenger) {
|
|
27
|
+
const featureFlags = getFeatureFlags(messenger);
|
|
28
|
+
return (featureFlags?.[exports.FEATURE_FLAG_EIP_7702]?.contractAddresses?.[chainId.toLowerCase()] ?? []);
|
|
29
|
+
}
|
|
30
|
+
exports.getEIP7702ContractAddresses = getEIP7702ContractAddresses;
|
|
31
|
+
/**
|
|
32
|
+
* Retrieves the EIP-7702 upgrade contract address.
|
|
33
|
+
*
|
|
34
|
+
* @param chainId - The chain ID.
|
|
35
|
+
* @param messenger - The controller messenger instance.
|
|
36
|
+
* @returns The upgrade contract address.
|
|
37
|
+
*/
|
|
38
|
+
function getEIP7702UpgradeContractAddress(chainId, messenger) {
|
|
39
|
+
return getEIP7702ContractAddresses(chainId, messenger)?.[0];
|
|
40
|
+
}
|
|
41
|
+
exports.getEIP7702UpgradeContractAddress = getEIP7702UpgradeContractAddress;
|
|
42
|
+
/**
|
|
43
|
+
* Retrieves the relevant feature flags from the remote feature flag controller.
|
|
44
|
+
*
|
|
45
|
+
* @param messenger - The messenger instance.
|
|
46
|
+
* @returns The feature flags.
|
|
47
|
+
*/
|
|
48
|
+
function getFeatureFlags(messenger) {
|
|
49
|
+
const featureFlags = messenger.call('RemoteFeatureFlagController:getState').remoteFeatureFlags;
|
|
50
|
+
log('Retrieved feature flags', featureFlags);
|
|
51
|
+
return featureFlags;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=feature-flags.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flags.cjs","sourceRoot":"","sources":["../../src/utils/feature-flags.ts"],"names":[],"mappings":";;;AAAA,2CAA+D;AAE/D,0CAA0C;AAG7B,QAAA,qBAAqB,GAAG,wBAAwB,CAAC;AAU9D,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,eAAe,CAAC,CAAC;AAE/D;;;;;GAKG;AACH,SAAgB,yBAAyB,CACvC,SAAyC;IAEzC,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAChD,OAAO,YAAY,EAAE,CAAC,6BAAqB,CAAC,EAAE,eAAe,IAAI,EAAE,CAAC;AACtE,CAAC;AALD,8DAKC;AAED;;;;;;GAMG;AACH,SAAgB,2BAA2B,CACzC,OAAY,EACZ,SAAyC;IAEzC,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAEhD,OAAO,CACL,YAAY,EAAE,CAAC,6BAAqB,CAAC,EAAE,iBAAiB,EAAE,CACxD,OAAO,CAAC,WAAW,EAAS,CAC7B,IAAI,EAAE,CACR,CAAC;AACJ,CAAC;AAXD,kEAWC;AAED;;;;;;GAMG;AACH,SAAgB,gCAAgC,CAC9C,OAAY,EACZ,SAAyC;IAEzC,OAAO,2BAA2B,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AALD,4EAKC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CACtB,SAAyC;IAEzC,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,CACjC,sCAAsC,CACvC,CAAC,kBAAkB,CAAC;IAErB,GAAG,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;IAE7C,OAAO,YAAiD,CAAC;AAC3D,CAAC","sourcesContent":["import { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\n\nexport const FEATURE_FLAG_EIP_7702 = 'confirmations-eip-7702';\n\nexport type TransactionControllerFeatureFlags = {\n [FEATURE_FLAG_EIP_7702]: {\n contractAddresses: Record<Hex, Hex[]>;\n supportedChains: Hex[];\n upgradeContractAddress: Hex;\n };\n};\n\nconst log = createModuleLogger(projectLogger, 'feature-flags');\n\n/**\n * Retrieves the supported EIP-7702 chains.\n *\n * @param messenger - The controller messenger instance.\n * @returns The supported chains.\n */\nexport function getEIP7702SupportedChains(\n messenger: TransactionControllerMessenger,\n): Hex[] {\n const featureFlags = getFeatureFlags(messenger);\n return featureFlags?.[FEATURE_FLAG_EIP_7702]?.supportedChains ?? [];\n}\n\n/**\n * Retrieves the supported EIP-7702 contract addresses for a given chain ID.\n *\n * @param chainId - The chain ID.\n * @param messenger - The controller messenger instance.\n * @returns The supported contract addresses.\n */\nexport function getEIP7702ContractAddresses(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): Hex[] {\n const featureFlags = getFeatureFlags(messenger);\n\n return (\n featureFlags?.[FEATURE_FLAG_EIP_7702]?.contractAddresses?.[\n chainId.toLowerCase() as Hex\n ] ?? []\n );\n}\n\n/**\n * Retrieves the EIP-7702 upgrade contract address.\n *\n * @param chainId - The chain ID.\n * @param messenger - The controller messenger instance.\n * @returns The upgrade contract address.\n */\nexport function getEIP7702UpgradeContractAddress(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): Hex | undefined {\n return getEIP7702ContractAddresses(chainId, messenger)?.[0];\n}\n\n/**\n * Retrieves the relevant feature flags from the remote feature flag controller.\n *\n * @param messenger - The messenger instance.\n * @returns The feature flags.\n */\nfunction getFeatureFlags(\n messenger: TransactionControllerMessenger,\n): TransactionControllerFeatureFlags {\n const featureFlags = messenger.call(\n 'RemoteFeatureFlagController:getState',\n ).remoteFeatureFlags;\n\n log('Retrieved feature flags', featureFlags);\n\n return featureFlags as TransactionControllerFeatureFlags;\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Hex } from "@metamask/utils";
|
|
2
|
+
import type { TransactionControllerMessenger } from "../TransactionController.cjs";
|
|
3
|
+
export declare const FEATURE_FLAG_EIP_7702 = "confirmations-eip-7702";
|
|
4
|
+
export type TransactionControllerFeatureFlags = {
|
|
5
|
+
[FEATURE_FLAG_EIP_7702]: {
|
|
6
|
+
contractAddresses: Record<Hex, Hex[]>;
|
|
7
|
+
supportedChains: Hex[];
|
|
8
|
+
upgradeContractAddress: Hex;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Retrieves the supported EIP-7702 chains.
|
|
13
|
+
*
|
|
14
|
+
* @param messenger - The controller messenger instance.
|
|
15
|
+
* @returns The supported chains.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getEIP7702SupportedChains(messenger: TransactionControllerMessenger): Hex[];
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves the supported EIP-7702 contract addresses for a given chain ID.
|
|
20
|
+
*
|
|
21
|
+
* @param chainId - The chain ID.
|
|
22
|
+
* @param messenger - The controller messenger instance.
|
|
23
|
+
* @returns The supported contract addresses.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getEIP7702ContractAddresses(chainId: Hex, messenger: TransactionControllerMessenger): Hex[];
|
|
26
|
+
/**
|
|
27
|
+
* Retrieves the EIP-7702 upgrade contract address.
|
|
28
|
+
*
|
|
29
|
+
* @param chainId - The chain ID.
|
|
30
|
+
* @param messenger - The controller messenger instance.
|
|
31
|
+
* @returns The upgrade contract address.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getEIP7702UpgradeContractAddress(chainId: Hex, messenger: TransactionControllerMessenger): Hex | undefined;
|
|
34
|
+
//# sourceMappingURL=feature-flags.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flags.d.cts","sourceRoot":"","sources":["../../src/utils/feature-flags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,GAAG,EAAE,wBAAwB;AAG/D,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAE/E,eAAO,MAAM,qBAAqB,2BAA2B,CAAC;AAE9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,CAAC,qBAAqB,CAAC,EAAE;QACvB,iBAAiB,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACtC,eAAe,EAAE,GAAG,EAAE,CAAC;QACvB,sBAAsB,EAAE,GAAG,CAAC;KAC7B,CAAC;CACH,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,8BAA8B,GACxC,GAAG,EAAE,CAGP;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,GAAG,EAAE,CAQP;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,GAAG,GAAG,SAAS,CAEjB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Hex } from "@metamask/utils";
|
|
2
|
+
import type { TransactionControllerMessenger } from "../TransactionController.mjs";
|
|
3
|
+
export declare const FEATURE_FLAG_EIP_7702 = "confirmations-eip-7702";
|
|
4
|
+
export type TransactionControllerFeatureFlags = {
|
|
5
|
+
[FEATURE_FLAG_EIP_7702]: {
|
|
6
|
+
contractAddresses: Record<Hex, Hex[]>;
|
|
7
|
+
supportedChains: Hex[];
|
|
8
|
+
upgradeContractAddress: Hex;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Retrieves the supported EIP-7702 chains.
|
|
13
|
+
*
|
|
14
|
+
* @param messenger - The controller messenger instance.
|
|
15
|
+
* @returns The supported chains.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getEIP7702SupportedChains(messenger: TransactionControllerMessenger): Hex[];
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves the supported EIP-7702 contract addresses for a given chain ID.
|
|
20
|
+
*
|
|
21
|
+
* @param chainId - The chain ID.
|
|
22
|
+
* @param messenger - The controller messenger instance.
|
|
23
|
+
* @returns The supported contract addresses.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getEIP7702ContractAddresses(chainId: Hex, messenger: TransactionControllerMessenger): Hex[];
|
|
26
|
+
/**
|
|
27
|
+
* Retrieves the EIP-7702 upgrade contract address.
|
|
28
|
+
*
|
|
29
|
+
* @param chainId - The chain ID.
|
|
30
|
+
* @param messenger - The controller messenger instance.
|
|
31
|
+
* @returns The upgrade contract address.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getEIP7702UpgradeContractAddress(chainId: Hex, messenger: TransactionControllerMessenger): Hex | undefined;
|
|
34
|
+
//# sourceMappingURL=feature-flags.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flags.d.mts","sourceRoot":"","sources":["../../src/utils/feature-flags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,GAAG,EAAE,wBAAwB;AAG/D,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAE/E,eAAO,MAAM,qBAAqB,2BAA2B,CAAC;AAE9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,CAAC,qBAAqB,CAAC,EAAE;QACvB,iBAAiB,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACtC,eAAe,EAAE,GAAG,EAAE,CAAC;QACvB,sBAAsB,EAAE,GAAG,CAAC;KAC7B,CAAC;CACH,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,8BAA8B,GACxC,GAAG,EAAE,CAGP;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,GAAG,EAAE,CAQP;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,8BAA8B,GACxC,GAAG,GAAG,SAAS,CAEjB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createModuleLogger } from "@metamask/utils";
|
|
2
|
+
import { projectLogger } from "../logger.mjs";
|
|
3
|
+
export const FEATURE_FLAG_EIP_7702 = 'confirmations-eip-7702';
|
|
4
|
+
const log = createModuleLogger(projectLogger, 'feature-flags');
|
|
5
|
+
/**
|
|
6
|
+
* Retrieves the supported EIP-7702 chains.
|
|
7
|
+
*
|
|
8
|
+
* @param messenger - The controller messenger instance.
|
|
9
|
+
* @returns The supported chains.
|
|
10
|
+
*/
|
|
11
|
+
export function getEIP7702SupportedChains(messenger) {
|
|
12
|
+
const featureFlags = getFeatureFlags(messenger);
|
|
13
|
+
return featureFlags?.[FEATURE_FLAG_EIP_7702]?.supportedChains ?? [];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Retrieves the supported EIP-7702 contract addresses for a given chain ID.
|
|
17
|
+
*
|
|
18
|
+
* @param chainId - The chain ID.
|
|
19
|
+
* @param messenger - The controller messenger instance.
|
|
20
|
+
* @returns The supported contract addresses.
|
|
21
|
+
*/
|
|
22
|
+
export function getEIP7702ContractAddresses(chainId, messenger) {
|
|
23
|
+
const featureFlags = getFeatureFlags(messenger);
|
|
24
|
+
return (featureFlags?.[FEATURE_FLAG_EIP_7702]?.contractAddresses?.[chainId.toLowerCase()] ?? []);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Retrieves the EIP-7702 upgrade contract address.
|
|
28
|
+
*
|
|
29
|
+
* @param chainId - The chain ID.
|
|
30
|
+
* @param messenger - The controller messenger instance.
|
|
31
|
+
* @returns The upgrade contract address.
|
|
32
|
+
*/
|
|
33
|
+
export function getEIP7702UpgradeContractAddress(chainId, messenger) {
|
|
34
|
+
return getEIP7702ContractAddresses(chainId, messenger)?.[0];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves the relevant feature flags from the remote feature flag controller.
|
|
38
|
+
*
|
|
39
|
+
* @param messenger - The messenger instance.
|
|
40
|
+
* @returns The feature flags.
|
|
41
|
+
*/
|
|
42
|
+
function getFeatureFlags(messenger) {
|
|
43
|
+
const featureFlags = messenger.call('RemoteFeatureFlagController:getState').remoteFeatureFlags;
|
|
44
|
+
log('Retrieved feature flags', featureFlags);
|
|
45
|
+
return featureFlags;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=feature-flags.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flags.mjs","sourceRoot":"","sources":["../../src/utils/feature-flags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAY,wBAAwB;AAE/D,OAAO,EAAE,aAAa,EAAE,sBAAkB;AAG1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,wBAAwB,CAAC;AAU9D,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,SAAyC;IAEzC,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAChD,OAAO,YAAY,EAAE,CAAC,qBAAqB,CAAC,EAAE,eAAe,IAAI,EAAE,CAAC;AACtE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAY,EACZ,SAAyC;IAEzC,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAEhD,OAAO,CACL,YAAY,EAAE,CAAC,qBAAqB,CAAC,EAAE,iBAAiB,EAAE,CACxD,OAAO,CAAC,WAAW,EAAS,CAC7B,IAAI,EAAE,CACR,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC,CAC9C,OAAY,EACZ,SAAyC;IAEzC,OAAO,2BAA2B,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CACtB,SAAyC;IAEzC,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,CACjC,sCAAsC,CACvC,CAAC,kBAAkB,CAAC;IAErB,GAAG,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;IAE7C,OAAO,YAAiD,CAAC;AAC3D,CAAC","sourcesContent":["import { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\n\nexport const FEATURE_FLAG_EIP_7702 = 'confirmations-eip-7702';\n\nexport type TransactionControllerFeatureFlags = {\n [FEATURE_FLAG_EIP_7702]: {\n contractAddresses: Record<Hex, Hex[]>;\n supportedChains: Hex[];\n upgradeContractAddress: Hex;\n };\n};\n\nconst log = createModuleLogger(projectLogger, 'feature-flags');\n\n/**\n * Retrieves the supported EIP-7702 chains.\n *\n * @param messenger - The controller messenger instance.\n * @returns The supported chains.\n */\nexport function getEIP7702SupportedChains(\n messenger: TransactionControllerMessenger,\n): Hex[] {\n const featureFlags = getFeatureFlags(messenger);\n return featureFlags?.[FEATURE_FLAG_EIP_7702]?.supportedChains ?? [];\n}\n\n/**\n * Retrieves the supported EIP-7702 contract addresses for a given chain ID.\n *\n * @param chainId - The chain ID.\n * @param messenger - The controller messenger instance.\n * @returns The supported contract addresses.\n */\nexport function getEIP7702ContractAddresses(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): Hex[] {\n const featureFlags = getFeatureFlags(messenger);\n\n return (\n featureFlags?.[FEATURE_FLAG_EIP_7702]?.contractAddresses?.[\n chainId.toLowerCase() as Hex\n ] ?? []\n );\n}\n\n/**\n * Retrieves the EIP-7702 upgrade contract address.\n *\n * @param chainId - The chain ID.\n * @param messenger - The controller messenger instance.\n * @returns The upgrade contract address.\n */\nexport function getEIP7702UpgradeContractAddress(\n chainId: Hex,\n messenger: TransactionControllerMessenger,\n): Hex | undefined {\n return getEIP7702ContractAddresses(chainId, messenger)?.[0];\n}\n\n/**\n * Retrieves the relevant feature flags from the remote feature flag controller.\n *\n * @param messenger - The messenger instance.\n * @returns The feature flags.\n */\nfunction getFeatureFlags(\n messenger: TransactionControllerMessenger,\n): TransactionControllerFeatureFlags {\n const featureFlags = messenger.call(\n 'RemoteFeatureFlagController:getState',\n ).remoteFeatureFlags;\n\n log('Retrieved feature flags', featureFlags);\n\n return featureFlags as TransactionControllerFeatureFlags;\n}\n"]}
|
|
@@ -17,16 +17,18 @@ const TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [
|
|
|
17
17
|
*
|
|
18
18
|
* @param options - Options bag.
|
|
19
19
|
* @param options.from - The address from which the transaction is initiated.
|
|
20
|
+
* @param options.internalAccounts - The internal accounts added to the wallet.
|
|
20
21
|
* @param options.origin - The origin or source of the transaction.
|
|
21
22
|
* @param options.permittedAddresses - The permitted accounts for the given origin.
|
|
22
23
|
* @param options.selectedAddress - The currently selected Ethereum address in the wallet.
|
|
23
24
|
* @param options.txParams - The transaction parameters.
|
|
25
|
+
* @param options.type - The transaction type.
|
|
24
26
|
* @throws Throws an error if the transaction is not permitted.
|
|
25
27
|
*/
|
|
26
|
-
async function validateTransactionOrigin({ from, origin, permittedAddresses, selectedAddress, txParams, }) {
|
|
28
|
+
async function validateTransactionOrigin({ from, internalAccounts, origin, permittedAddresses, selectedAddress, txParams, type, }) {
|
|
27
29
|
const isInternal = origin === controller_utils_1.ORIGIN_METAMASK;
|
|
28
30
|
const isExternal = origin && origin !== controller_utils_1.ORIGIN_METAMASK;
|
|
29
|
-
const { authorizationList, type } = txParams;
|
|
31
|
+
const { authorizationList, to, type: envelopeType } = txParams;
|
|
30
32
|
if (isInternal && from !== selectedAddress) {
|
|
31
33
|
throw rpc_errors_1.rpcErrors.internal({
|
|
32
34
|
message: `Internally initiated transaction is using invalid account.`,
|
|
@@ -41,9 +43,14 @@ async function validateTransactionOrigin({ from, origin, permittedAddresses, sel
|
|
|
41
43
|
throw rpc_errors_1.providerErrors.unauthorized({ data: { origin } });
|
|
42
44
|
}
|
|
43
45
|
if (isExternal &&
|
|
44
|
-
(authorizationList ||
|
|
46
|
+
(authorizationList || envelopeType === types_1.TransactionEnvelopeType.setCode)) {
|
|
45
47
|
throw rpc_errors_1.rpcErrors.invalidParams('External EIP-7702 transactions are not supported');
|
|
46
48
|
}
|
|
49
|
+
if (isExternal &&
|
|
50
|
+
internalAccounts?.some((account) => account.toLowerCase() === to?.toLowerCase()) &&
|
|
51
|
+
type !== types_1.TransactionType.batch) {
|
|
52
|
+
throw rpc_errors_1.rpcErrors.invalidParams('External transactions to internal accounts are not supported');
|
|
53
|
+
}
|
|
47
54
|
}
|
|
48
55
|
exports.validateTransactionOrigin = validateTransactionOrigin;
|
|
49
56
|
/**
|
|
@@ -322,11 +329,15 @@ function validateAuthorizationList(txParams) {
|
|
|
322
329
|
function validateAuthorization(authorization) {
|
|
323
330
|
ensureFieldIsValidHex(authorization, 'address');
|
|
324
331
|
validateHexLength(authorization.address, 20, 'address');
|
|
325
|
-
for (const field of ['chainId', 'nonce', 'r', 's'
|
|
332
|
+
for (const field of ['chainId', 'nonce', 'r', 's']) {
|
|
326
333
|
if (authorization[field]) {
|
|
327
334
|
ensureFieldIsValidHex(authorization, field);
|
|
328
335
|
}
|
|
329
336
|
}
|
|
337
|
+
const { yParity } = authorization;
|
|
338
|
+
if (yParity && !['0x', '0x1'].includes(yParity)) {
|
|
339
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid transaction params: yParity must be '0x' or '0x1'. got: ${yParity}`);
|
|
340
|
+
}
|
|
330
341
|
}
|
|
331
342
|
/**
|
|
332
343
|
* Validate the number of bytes in a hex string.
|