@toruslabs/ethereum-controllers 8.16.0 → 8.17.1
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/dist/ethereumControllers.umd.min.js +1 -1
- package/dist/lib.cjs/Eip5792/walletGetCallsStatus.js +75 -0
- package/dist/lib.cjs/Eip5792/walletGetCapabilities.js +64 -0
- package/dist/lib.cjs/Eip5792/walletSendCalls.js +163 -0
- package/dist/lib.cjs/Eip7702/eip7702Utils.js +82 -0
- package/dist/lib.cjs/Eip7702/walletGetUpgradeStatus.js +35 -0
- package/dist/lib.cjs/Eip7702/walletUpgradeAccount.js +58 -0
- package/dist/lib.cjs/Keyring/KeyringController.js +50 -14
- package/dist/lib.cjs/Network/createEthereumMiddleware.js +114 -1
- package/dist/lib.cjs/Transaction/TransactionController.js +117 -6
- package/dist/lib.cjs/Transaction/TransactionGasUtil.js +13 -0
- package/dist/lib.cjs/Transaction/TransactionStateManager.js +9 -0
- package/dist/lib.cjs/Transaction/TransactionUtils.js +103 -10
- package/dist/lib.cjs/index.js +35 -0
- package/dist/lib.cjs/types/Eip5792/index.d.ts +3 -0
- package/dist/lib.cjs/types/Eip5792/walletGetCallsStatus.d.ts +19 -0
- package/dist/lib.cjs/types/Eip5792/walletGetCapabilities.d.ts +17 -0
- package/dist/lib.cjs/types/Eip5792/walletSendCalls.d.ts +45 -0
- package/dist/lib.cjs/types/Eip7702/eip7702Utils.d.ts +27 -0
- package/dist/lib.cjs/types/Eip7702/walletGetUpgradeStatus.d.ts +11 -0
- package/dist/lib.cjs/types/Eip7702/walletUpgradeAccount.d.ts +13 -0
- package/dist/lib.cjs/types/Keyring/KeyringController.d.ts +2 -0
- package/dist/lib.cjs/types/Network/createEthereumMiddleware.d.ts +53 -1
- package/dist/lib.cjs/types/Transaction/TransactionController.d.ts +9 -1
- package/dist/lib.cjs/types/Transaction/TransactionStateManager.d.ts +1 -0
- package/dist/lib.cjs/types/Transaction/TransactionUtils.d.ts +38 -1
- package/dist/lib.cjs/types/index.d.ts +4 -0
- package/dist/lib.cjs/types/utils/abis.d.ts +15 -0
- package/dist/lib.cjs/types/utils/constants.d.ts +2 -0
- package/dist/lib.cjs/types/utils/eip5792Types.d.ts +154 -0
- package/dist/lib.cjs/types/utils/eip7702Types.d.ts +60 -0
- package/dist/lib.cjs/types/utils/interfaces.d.ts +22 -2
- package/dist/lib.cjs/utils/abis.js +30 -0
- package/dist/lib.cjs/utils/constants.js +4 -1
- package/dist/lib.cjs/utils/eip5792Types.js +39 -0
- package/dist/lib.cjs/utils/eip7702Types.js +14 -0
- package/dist/lib.cjs/utils/interfaces.js +8 -0
- package/dist/lib.esm/Eip5792/walletGetCallsStatus.js +76 -0
- package/dist/lib.esm/Eip5792/walletGetCapabilities.js +63 -0
- package/dist/lib.esm/Eip5792/walletSendCalls.js +168 -0
- package/dist/lib.esm/Eip7702/eip7702Utils.js +81 -0
- package/dist/lib.esm/Eip7702/walletGetUpgradeStatus.js +33 -0
- package/dist/lib.esm/Eip7702/walletUpgradeAccount.js +56 -0
- package/dist/lib.esm/Keyring/KeyringController.js +53 -15
- package/dist/lib.esm/Message/utils.js +1 -1
- package/dist/lib.esm/Network/createEthereumMiddleware.js +119 -4
- package/dist/lib.esm/Transaction/TransactionController.js +124 -10
- package/dist/lib.esm/Transaction/TransactionGasUtil.js +13 -0
- package/dist/lib.esm/Transaction/TransactionStateManager.js +9 -0
- package/dist/lib.esm/Transaction/TransactionUtils.js +106 -14
- package/dist/lib.esm/index.js +11 -4
- package/dist/lib.esm/utils/abis.js +30 -1
- package/dist/lib.esm/utils/constants.js +4 -2
- package/dist/lib.esm/utils/eip5792Types.js +104 -0
- package/dist/lib.esm/utils/eip7702Types.js +15 -0
- package/dist/lib.esm/utils/helpers.js +2 -2
- package/dist/lib.esm/utils/interfaces.js +28 -0
- package/package.json +7 -4
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Hex } from "viem";
|
|
2
|
+
import { TransactionParams } from "./interfaces";
|
|
3
|
+
export declare const EIP_7702_METHODS: {
|
|
4
|
+
readonly WALLET_UPGRADE_ACCOUNT: "wallet_upgradeAccount";
|
|
5
|
+
readonly WALLET_GET_ACCOUNT_UPGRADE_STATUS: "wallet_getAccountUpgradeStatus";
|
|
6
|
+
};
|
|
7
|
+
export declare const EIP_7702_PREFIX = "0xef0100";
|
|
8
|
+
export declare const EIP_7702_REVOKE_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
|
+
export declare const DUMMY_AUTHORIZATION_SIGNATURE = "0x1111111111111111111111111111111111111111111111111111111111111111";
|
|
10
|
+
/**
|
|
11
|
+
* An authorization to be included in a `setCode` transaction.
|
|
12
|
+
* Specifies code to be added to the authorization signer's EOA account.
|
|
13
|
+
* Introduced in EIP-7702.
|
|
14
|
+
*/
|
|
15
|
+
export type Authorization = {
|
|
16
|
+
/** Address of a smart contract that contains the code to be set. */
|
|
17
|
+
address: Hex;
|
|
18
|
+
/**
|
|
19
|
+
* Specific chain the authorization applies to.
|
|
20
|
+
* If not provided, defaults to the chain ID of the transaction.
|
|
21
|
+
*/
|
|
22
|
+
chainId: Hex;
|
|
23
|
+
/**
|
|
24
|
+
* Nonce at which the authorization will be valid.
|
|
25
|
+
* If not provided, defaults to the nonce following the transaction's nonce.
|
|
26
|
+
*/
|
|
27
|
+
nonce?: Hex;
|
|
28
|
+
/** R component of the signature. */
|
|
29
|
+
r?: Hex;
|
|
30
|
+
/** S component of the signature. */
|
|
31
|
+
s?: Hex;
|
|
32
|
+
/** Y parity generated from the signature. */
|
|
33
|
+
yParity?: Hex;
|
|
34
|
+
};
|
|
35
|
+
export type UnsignedAuthorization = Omit<Required<Authorization>, "r" | "s" | "yParity">;
|
|
36
|
+
export type SignedAuthorization = Required<Authorization>;
|
|
37
|
+
export interface Eip7702Params extends TransactionParams {
|
|
38
|
+
/**
|
|
39
|
+
* Address of the account to upgrade or get upgrade status for.
|
|
40
|
+
*/
|
|
41
|
+
account: Hex;
|
|
42
|
+
/**
|
|
43
|
+
* Chain ID of the account to upgrade.
|
|
44
|
+
*/
|
|
45
|
+
chainId: Hex;
|
|
46
|
+
/**
|
|
47
|
+
* Optional contract address for delegation.
|
|
48
|
+
*/
|
|
49
|
+
implementation?: Hex;
|
|
50
|
+
}
|
|
51
|
+
export interface Eip7702WalletGetUpgradeStatusResponse {
|
|
52
|
+
/**
|
|
53
|
+
* Whether the account is upgraded.
|
|
54
|
+
*/
|
|
55
|
+
isUpgraded: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* The implementation address of the contract that the account is delegated to.
|
|
58
|
+
*/
|
|
59
|
+
implementation: Hex;
|
|
60
|
+
}
|
|
@@ -7,6 +7,10 @@ import { ToBiconomySmartAccountParameters, toEcdsaKernelSmartAccount, ToLightSma
|
|
|
7
7
|
import { Client, Hex, WalletClient } from "viem";
|
|
8
8
|
import { createBundlerClient, createPaymasterClient, SmartAccount, UserOperationReceipt, WebAuthnAccount } from "viem/account-abstraction";
|
|
9
9
|
import { METHOD_TYPES, SMART_ACCOUNT, TRANSACTION_ENVELOPE_TYPES } from "./constants";
|
|
10
|
+
import { NestedTransactionMetadata } from "./eip5792Types";
|
|
11
|
+
import { Authorization } from "./eip7702Types";
|
|
12
|
+
export type { BatchTransactionParams, NestedTransactionMetadata, TransactionBatchRequest, TransactionBatchSingleRequest } from "./eip5792Types";
|
|
13
|
+
export type { Authorization, Eip7702Params, Eip7702WalletGetUpgradeStatusResponse, SignedAuthorization } from "./eip7702Types";
|
|
10
14
|
export type CustomTokenInfo = BaseTokenInfo & {
|
|
11
15
|
erc20: boolean;
|
|
12
16
|
customTokenId?: string;
|
|
@@ -167,6 +171,12 @@ export interface TransactionParams extends BaseRequestParams {
|
|
|
167
171
|
* The amount of gas to allocate for the Paymaster post-operation code
|
|
168
172
|
*/
|
|
169
173
|
paymasterPostOpGasLimit?: string;
|
|
174
|
+
/**
|
|
175
|
+
* Array of authorizations to set code on EOA accounts.
|
|
176
|
+
* Only supported in `setCode` transactions.
|
|
177
|
+
* Introduced in EIP-7702.
|
|
178
|
+
*/
|
|
179
|
+
authorizationList?: Authorization[];
|
|
170
180
|
}
|
|
171
181
|
export type Nonce = {
|
|
172
182
|
name: string;
|
|
@@ -275,6 +285,11 @@ export interface DappSuggestedGasFees {
|
|
|
275
285
|
maxFeePerGas?: string;
|
|
276
286
|
gas?: string;
|
|
277
287
|
}
|
|
288
|
+
export declare const TRANSACTION_CATEGORY_EIP7702: {
|
|
289
|
+
readonly BATCH: "batch";
|
|
290
|
+
readonly REVOKE_DELEGATION: "revokeDelegation";
|
|
291
|
+
};
|
|
292
|
+
export type TransactionCategoryWithBatch = TRANSACTION_TYPE | (typeof TRANSACTION_CATEGORY_EIP7702)[keyof typeof TRANSACTION_CATEGORY_EIP7702];
|
|
278
293
|
export interface EthereumTransactionMeta extends TransactionMeta<TransactionParams> {
|
|
279
294
|
r?: string;
|
|
280
295
|
s?: string;
|
|
@@ -287,7 +302,7 @@ export interface EthereumTransactionMeta extends TransactionMeta<TransactionPara
|
|
|
287
302
|
retryCount?: number;
|
|
288
303
|
simulationFails?: Record<string, unknown>;
|
|
289
304
|
loadingDefaults?: boolean;
|
|
290
|
-
transactionCategory?:
|
|
305
|
+
transactionCategory?: TransactionCategoryWithBatch;
|
|
291
306
|
contractType?: string;
|
|
292
307
|
nonceDetails?: NonceDetails;
|
|
293
308
|
methodParams?: unknown[];
|
|
@@ -295,6 +310,8 @@ export interface EthereumTransactionMeta extends TransactionMeta<TransactionPara
|
|
|
295
310
|
isUserOperation?: boolean;
|
|
296
311
|
userOpHash?: string;
|
|
297
312
|
userOpReceipt?: UserOperationReceipt;
|
|
313
|
+
batchId?: string;
|
|
314
|
+
nestedTransactions?: NestedTransactionMetadata[];
|
|
298
315
|
}
|
|
299
316
|
export interface TransactionPayload {
|
|
300
317
|
created_at: Date;
|
|
@@ -483,4 +500,7 @@ export interface UserOperationGas {
|
|
|
483
500
|
paymasterVerificationGasLimit?: string;
|
|
484
501
|
paymasterPostOpGasLimit?: string;
|
|
485
502
|
}
|
|
486
|
-
|
|
503
|
+
/**
|
|
504
|
+
* Type Def for function to query the deployment bytecode of an address. (eth_getCode)
|
|
505
|
+
*/
|
|
506
|
+
export type GetEthCodeFn = (address: `0x${string}`, chainId: `0x${string}`) => Promise<`0x${string}`>;
|
|
@@ -503,8 +503,38 @@ const singleBalanceCheckerAbi = [{
|
|
|
503
503
|
stateMutability: "view",
|
|
504
504
|
type: "function"
|
|
505
505
|
}];
|
|
506
|
+
const erc7821Abi = [{
|
|
507
|
+
type: "function",
|
|
508
|
+
name: "execute",
|
|
509
|
+
inputs: [{
|
|
510
|
+
name: "mode",
|
|
511
|
+
type: "bytes32",
|
|
512
|
+
internalType: "ModeCode"
|
|
513
|
+
}, {
|
|
514
|
+
name: "executionData",
|
|
515
|
+
type: "bytes",
|
|
516
|
+
internalType: "bytes"
|
|
517
|
+
}],
|
|
518
|
+
outputs: [],
|
|
519
|
+
stateMutability: "payable"
|
|
520
|
+
}, {
|
|
521
|
+
type: "function",
|
|
522
|
+
name: "supportsExecutionMode",
|
|
523
|
+
inputs: [{
|
|
524
|
+
name: "mode",
|
|
525
|
+
type: "bytes32",
|
|
526
|
+
internalType: "ModeCode"
|
|
527
|
+
}],
|
|
528
|
+
outputs: [{
|
|
529
|
+
name: "",
|
|
530
|
+
type: "bool",
|
|
531
|
+
internalType: "bool"
|
|
532
|
+
}],
|
|
533
|
+
stateMutability: "view"
|
|
534
|
+
}];
|
|
506
535
|
|
|
507
536
|
exports.erc1155Abi = erc1155Abi;
|
|
508
537
|
exports.erc20Abi = erc20Abi;
|
|
509
538
|
exports.erc721Abi = erc721Abi;
|
|
539
|
+
exports.erc7821Abi = erc7821Abi;
|
|
510
540
|
exports.singleBalanceCheckerAbi = singleBalanceCheckerAbi;
|
|
@@ -7,6 +7,7 @@ const CONTRACT_TYPE_ETH = "eth";
|
|
|
7
7
|
const CONTRACT_TYPE_ERC20 = "erc20";
|
|
8
8
|
const CONTRACT_TYPE_ERC721 = "erc721";
|
|
9
9
|
const CONTRACT_TYPE_ERC1155 = "erc1155";
|
|
10
|
+
const CONTRACT_TYPE_ERC7821 = "erc7821";
|
|
10
11
|
const ERC1155_INTERFACE_ID = "0xd9b67a26";
|
|
11
12
|
const ERC721_INTERFACE_ID = "0x80ac58cd";
|
|
12
13
|
const ERC721_METADATA_INTERFACE_ID = "0x5b5e139f";
|
|
@@ -278,7 +279,8 @@ const PAYMASTER_METHOD_TYPES = [METHOD_TYPES.ETH_GET_PAYMASTER_DATA, METHOD_TYPE
|
|
|
278
279
|
const TRANSACTION_ENVELOPE_TYPES = {
|
|
279
280
|
LEGACY: "0x0",
|
|
280
281
|
ACCESS_LIST: "0x1",
|
|
281
|
-
FEE_MARKET: "0x2"
|
|
282
|
+
FEE_MARKET: "0x2",
|
|
283
|
+
SET_CODE: "0x4" // Type 4 transaction
|
|
282
284
|
};
|
|
283
285
|
const GAS_ESTIMATE_TYPES = {
|
|
284
286
|
// Fee Market describes the way gas is set after the london hardfork, and was
|
|
@@ -381,6 +383,7 @@ exports.COINGECKO_SUPPORTED_CURRENCIES = COINGECKO_SUPPORTED_CURRENCIES;
|
|
|
381
383
|
exports.CONTRACT_TYPE_ERC1155 = CONTRACT_TYPE_ERC1155;
|
|
382
384
|
exports.CONTRACT_TYPE_ERC20 = CONTRACT_TYPE_ERC20;
|
|
383
385
|
exports.CONTRACT_TYPE_ERC721 = CONTRACT_TYPE_ERC721;
|
|
386
|
+
exports.CONTRACT_TYPE_ERC7821 = CONTRACT_TYPE_ERC7821;
|
|
384
387
|
exports.CONTRACT_TYPE_ETH = CONTRACT_TYPE_ETH;
|
|
385
388
|
exports.ERC1155_INTERFACE_ID = ERC1155_INTERFACE_ID;
|
|
386
389
|
exports.ERC721_ENUMERABLE_INTERFACE_ID = ERC721_ENUMERABLE_INTERFACE_ID;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// EIP-5792 Method Names
|
|
5
|
+
// ============================================================================
|
|
6
|
+
const EIP_5792_METHODS = {
|
|
7
|
+
WALLET_GET_CAPABILITIES: "wallet_getCapabilities",
|
|
8
|
+
WALLET_SEND_CALLS: "wallet_sendCalls",
|
|
9
|
+
WALLET_GET_CALLS_STATUS: "wallet_getCallsStatus",
|
|
10
|
+
WALLET_SHOW_CALLS_STATUS: "wallet_showCallsStatus"
|
|
11
|
+
};
|
|
12
|
+
const EIP5792ErrorCode = {
|
|
13
|
+
UnsupportedNonOptionalCapability: 5700,
|
|
14
|
+
UnsupportedChainId: 5710,
|
|
15
|
+
UnknownBundleId: 5730,
|
|
16
|
+
RejectedUpgrade: 5750
|
|
17
|
+
};
|
|
18
|
+
const GetCallsStatusCode = {
|
|
19
|
+
PENDING: 100,
|
|
20
|
+
CONFIRMED: 200,
|
|
21
|
+
FAILED_OFFCHAIN: 400,
|
|
22
|
+
REVERTED: 500,
|
|
23
|
+
REVERTED_PARTIAL: 600
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* EIP-5792 atomic status (EIP-5792)
|
|
27
|
+
*
|
|
28
|
+
* Reference: https://eips.ethereum.org/EIPS/eip-5792#wallet_getcapabilities
|
|
29
|
+
*/
|
|
30
|
+
const Eip5792AtomicStatus = {
|
|
31
|
+
SUPPORTED: "supported",
|
|
32
|
+
READY: "ready",
|
|
33
|
+
UNSUPPORTED: "unsupported"
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
exports.EIP5792ErrorCode = EIP5792ErrorCode;
|
|
37
|
+
exports.EIP_5792_METHODS = EIP_5792_METHODS;
|
|
38
|
+
exports.Eip5792AtomicStatus = Eip5792AtomicStatus;
|
|
39
|
+
exports.GetCallsStatusCode = GetCallsStatusCode;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EIP_7702_METHODS = {
|
|
4
|
+
WALLET_UPGRADE_ACCOUNT: "wallet_upgradeAccount",
|
|
5
|
+
WALLET_GET_ACCOUNT_UPGRADE_STATUS: "wallet_getAccountUpgradeStatus"
|
|
6
|
+
};
|
|
7
|
+
const EIP_7702_PREFIX = "0xef0100";
|
|
8
|
+
const EIP_7702_REVOKE_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
|
+
const DUMMY_AUTHORIZATION_SIGNATURE = "0x1111111111111111111111111111111111111111111111111111111111111111";
|
|
10
|
+
|
|
11
|
+
exports.DUMMY_AUTHORIZATION_SIGNATURE = DUMMY_AUTHORIZATION_SIGNATURE;
|
|
12
|
+
exports.EIP_7702_METHODS = EIP_7702_METHODS;
|
|
13
|
+
exports.EIP_7702_PREFIX = EIP_7702_PREFIX;
|
|
14
|
+
exports.EIP_7702_REVOKE_ADDRESS = EIP_7702_REVOKE_ADDRESS;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { addHexPrefix } from '@ethereumjs/util';
|
|
2
|
+
import { TransactionStatus } from '@toruslabs/base-controllers';
|
|
3
|
+
import { rpcErrors, JsonRpcError } from '@web3auth/auth';
|
|
4
|
+
import { GetCallsStatusCode, EIP_5792_METHODS, EIP5792ErrorCode } from '../utils/eip5792Types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maps a TransactionStatus to an EIP-5792 GetCallsStatusCode.
|
|
8
|
+
* @param status - The transaction status.
|
|
9
|
+
* @returns The corresponding EIP-5792 status code.
|
|
10
|
+
*/
|
|
11
|
+
function mapTransactionStatusToEip5792Status(status) {
|
|
12
|
+
switch (status) {
|
|
13
|
+
// Pending states - batch is still being processed
|
|
14
|
+
case TransactionStatus.unapproved:
|
|
15
|
+
case TransactionStatus.approved:
|
|
16
|
+
case TransactionStatus.signed:
|
|
17
|
+
case TransactionStatus.submitted:
|
|
18
|
+
case TransactionStatus.pending:
|
|
19
|
+
case TransactionStatus.cancelling:
|
|
20
|
+
return GetCallsStatusCode.PENDING;
|
|
21
|
+
|
|
22
|
+
// Confirmed states - batch completed successfully
|
|
23
|
+
case TransactionStatus.confirmed:
|
|
24
|
+
case TransactionStatus.finalized:
|
|
25
|
+
case TransactionStatus.processed:
|
|
26
|
+
return GetCallsStatusCode.CONFIRMED;
|
|
27
|
+
|
|
28
|
+
// Failed offchain - rejected/cancelled before reaching the chain
|
|
29
|
+
case TransactionStatus.rejected:
|
|
30
|
+
case TransactionStatus.cancelled:
|
|
31
|
+
case TransactionStatus.expired:
|
|
32
|
+
case TransactionStatus.dropped:
|
|
33
|
+
return GetCallsStatusCode.FAILED_OFFCHAIN;
|
|
34
|
+
|
|
35
|
+
// Reverted - transaction was submitted but failed on chain
|
|
36
|
+
case TransactionStatus.failed:
|
|
37
|
+
return GetCallsStatusCode.REVERTED;
|
|
38
|
+
default:
|
|
39
|
+
return GetCallsStatusCode.PENDING;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Handler for wallet_getCallsStatus (EIP-5792).
|
|
45
|
+
* Returns the status of a batch of calls.
|
|
46
|
+
*
|
|
47
|
+
* @param request - The JRPC request with batch ID parameter.
|
|
48
|
+
* @param context - Context containing required functions.
|
|
49
|
+
* @returns The batch status and receipts.
|
|
50
|
+
*/
|
|
51
|
+
function walletGetCallsStatus(request, getTransactionByBatchId) {
|
|
52
|
+
const {
|
|
53
|
+
method,
|
|
54
|
+
params
|
|
55
|
+
} = request;
|
|
56
|
+
if (method !== EIP_5792_METHODS.WALLET_GET_CALLS_STATUS) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const batchId = Array.isArray(params) ? params[0] : params;
|
|
60
|
+
if (!batchId) {
|
|
61
|
+
throw rpcErrors.invalidParams("wallet_getCallsStatus: batch ID is required");
|
|
62
|
+
}
|
|
63
|
+
const batchTx = getTransactionByBatchId(batchId);
|
|
64
|
+
if (!batchTx) {
|
|
65
|
+
throw new JsonRpcError(EIP5792ErrorCode.UnknownBundleId, `wallet_getCallsStatus: Batch not found: ${batchId}`);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
status: mapTransactionStatusToEip5792Status(batchTx.status),
|
|
69
|
+
id: batchId,
|
|
70
|
+
chainId: addHexPrefix(batchTx.chainId),
|
|
71
|
+
atomic: true,
|
|
72
|
+
receipts: batchTx.txReceipt ? [batchTx.txReceipt] : []
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { mapTransactionStatusToEip5792Status, walletGetCallsStatus };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { rpcErrors } from '@web3auth/auth';
|
|
2
|
+
import { getIsEip7702UpgradeSupported } from '../Eip7702/eip7702Utils.js';
|
|
3
|
+
import { EIP_5792_METHODS, Eip5792AtomicStatus } from '../utils/eip5792Types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Handler for wallet_getCapabilities (EIP-5792).
|
|
7
|
+
* Returns capabilities per chain, indicating atomicBatch support for upgraded accounts.
|
|
8
|
+
*
|
|
9
|
+
* @param request - The JRPC request with wallet address parameter.
|
|
10
|
+
* @param context - Context containing required functions.
|
|
11
|
+
* @returns Capabilities per chain.
|
|
12
|
+
*/
|
|
13
|
+
async function walletGetCapabilities(request, getEthCode, context) {
|
|
14
|
+
var _context$getCachedDel;
|
|
15
|
+
const {
|
|
16
|
+
method,
|
|
17
|
+
params
|
|
18
|
+
} = request;
|
|
19
|
+
if (method !== EIP_5792_METHODS.WALLET_GET_CAPABILITIES) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(params)) {
|
|
23
|
+
throw rpcErrors.invalidParams("wallet_getCapabilities: parameters are required");
|
|
24
|
+
}
|
|
25
|
+
const walletAddress = params[0];
|
|
26
|
+
if (!walletAddress) {
|
|
27
|
+
throw rpcErrors.invalidParams("wallet_getCapabilities: wallet address is required");
|
|
28
|
+
}
|
|
29
|
+
const chainsOverride = params[1];
|
|
30
|
+
const supportedChains = chainsOverride || context.getSupportedChains();
|
|
31
|
+
const cachedDelegations = ((_context$getCachedDel = context.getCachedDelegations) === null || _context$getCachedDel === void 0 ? void 0 : _context$getCachedDel.call(context)) || {};
|
|
32
|
+
const capabilities = {};
|
|
33
|
+
for (const chainId of supportedChains) {
|
|
34
|
+
const cacheKey = `${walletAddress.toLowerCase()}-${chainId.toLowerCase()}`;
|
|
35
|
+
let delegationAddress = cachedDelegations[cacheKey];
|
|
36
|
+
let atomicStatus = Eip5792AtomicStatus.SUPPORTED;
|
|
37
|
+
|
|
38
|
+
// If not cached, try to fetch
|
|
39
|
+
if (delegationAddress === undefined && getEthCode) {
|
|
40
|
+
try {
|
|
41
|
+
const eip7702UpgradeSupported = await getIsEip7702UpgradeSupported(walletAddress, chainId, getEthCode);
|
|
42
|
+
delegationAddress = eip7702UpgradeSupported.delegationAddress;
|
|
43
|
+
if (delegationAddress === null) {
|
|
44
|
+
atomicStatus = eip7702UpgradeSupported.isSupported ? Eip5792AtomicStatus.READY : Eip5792AtomicStatus.UNSUPPORTED;
|
|
45
|
+
} else {
|
|
46
|
+
var _context$updateDelega;
|
|
47
|
+
// account already upgraded, update the cache
|
|
48
|
+
(_context$updateDelega = context.updateDelegationCache) === null || _context$updateDelega === void 0 || _context$updateDelega.call(context, walletAddress, chainId, delegationAddress);
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
atomicStatus = Eip5792AtomicStatus.UNSUPPORTED;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
capabilities[chainId] = {
|
|
55
|
+
atomic: {
|
|
56
|
+
status: atomicStatus
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return capabilities;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { walletGetCapabilities };
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { isValidAddress } from '@ethereumjs/util';
|
|
2
|
+
import { rpcErrors } from '@web3auth/auth';
|
|
3
|
+
import { isHexString } from 'ethers';
|
|
4
|
+
import { v4, parse } from 'uuid';
|
|
5
|
+
import { getIsEip7702UpgradeSupported } from '../Eip7702/eip7702Utils.js';
|
|
6
|
+
import { EIP_5792_METHODS } from '../utils/eip5792Types.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generates a unique batch ID for EIP-5792 calls.
|
|
10
|
+
* @returns A unique hex string batch ID.
|
|
11
|
+
*/
|
|
12
|
+
function generateBatchId() {
|
|
13
|
+
const idString = v4();
|
|
14
|
+
const idBytes = new Uint8Array(parse(idString));
|
|
15
|
+
const hexString = Array.from(idBytes).map(byte => byte.toString(16).padStart(2, "0")).join("");
|
|
16
|
+
return `0x${hexString}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validates a single call in the batch.
|
|
21
|
+
* @param call - The call to validate.
|
|
22
|
+
* @param index - The index of the call in the batch (for error messages).
|
|
23
|
+
*/
|
|
24
|
+
function validateCall(call, index) {
|
|
25
|
+
// Validate 'to' address
|
|
26
|
+
if (!call.to || !isHexString(call.to) || !isValidAddress(call.to)) {
|
|
27
|
+
throw rpcErrors.invalidParams(`Invalid 'to' address in call at index ${index}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Validate 'value' if present
|
|
31
|
+
if (call.value !== undefined) {
|
|
32
|
+
if (!isHexString(call.value)) {
|
|
33
|
+
throw rpcErrors.invalidParams(`Invalid 'value' in call at index ${index}: must be a valid non-negative hex string`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validate 'data' if present
|
|
38
|
+
if (call.data !== undefined) {
|
|
39
|
+
if (!isHexString(call.data)) {
|
|
40
|
+
throw rpcErrors.invalidParams(`Invalid 'data' in call at index ${index}: must be a valid hex string`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Validates the parameters for wallet_sendCalls (EIP-5792).
|
|
47
|
+
* @param sendCallsParams - The parameters to validate.
|
|
48
|
+
*/
|
|
49
|
+
function validateSendCallsParams(sendCallsParams) {
|
|
50
|
+
// Basic structure validation
|
|
51
|
+
if (!sendCallsParams) {
|
|
52
|
+
throw rpcErrors.invalidParams("Missing send calls parameters");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Validate version format
|
|
56
|
+
if (!sendCallsParams.version || typeof sendCallsParams.version !== "string") {
|
|
57
|
+
throw rpcErrors.invalidParams(`Invalid version: expected a string, got "${sendCallsParams.version || "undefined"}"`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Validate chainId format
|
|
61
|
+
if (!sendCallsParams.chainId || !isHexString(sendCallsParams.chainId)) {
|
|
62
|
+
throw rpcErrors.invalidParams("Invalid chainId: must be a valid hex string");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate 'from' address
|
|
66
|
+
if (!sendCallsParams.from) {
|
|
67
|
+
throw rpcErrors.invalidParams("Missing 'from' address");
|
|
68
|
+
}
|
|
69
|
+
if (!isHexString(sendCallsParams.from) || !isValidAddress(sendCallsParams.from)) {
|
|
70
|
+
throw rpcErrors.invalidParams("Invalid 'from' address: must be a valid hex address");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Validate calls array
|
|
74
|
+
if (!Array.isArray(sendCallsParams.calls) || sendCallsParams.calls.length === 0) {
|
|
75
|
+
throw rpcErrors.invalidParams("Invalid calls: must be a non-empty array");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Validate each call
|
|
79
|
+
sendCallsParams.calls.forEach((call, index) => {
|
|
80
|
+
validateCall(call, index);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async function processMultipleTransactions({
|
|
84
|
+
from,
|
|
85
|
+
transactions,
|
|
86
|
+
request,
|
|
87
|
+
chainId,
|
|
88
|
+
getEthCode,
|
|
89
|
+
processTransactionBatch
|
|
90
|
+
}) {
|
|
91
|
+
// check if the account is upgraded with EIP-7702 for the given chain
|
|
92
|
+
const {
|
|
93
|
+
isSupported,
|
|
94
|
+
upgradeContractAddress,
|
|
95
|
+
delegationAddress
|
|
96
|
+
} = await getIsEip7702UpgradeSupported(from, chainId, getEthCode);
|
|
97
|
+
if (!isSupported) {
|
|
98
|
+
throw rpcErrors.methodNotSupported(`EIP-7702 upgrade is not supported for the given chain, ${chainId}`);
|
|
99
|
+
}
|
|
100
|
+
const hasAccountAlreadyUpgraded = Boolean(delegationAddress);
|
|
101
|
+
const batchRequest = {
|
|
102
|
+
batchId: generateBatchId(),
|
|
103
|
+
transactions,
|
|
104
|
+
eip7702UpgradeContractAddress: upgradeContractAddress,
|
|
105
|
+
requiredEip7702Upgrade: !hasAccountAlreadyUpgraded
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// prepare batch transactions
|
|
109
|
+
return processTransactionBatch(batchRequest, request);
|
|
110
|
+
}
|
|
111
|
+
async function processSingleTransaction({
|
|
112
|
+
transactions,
|
|
113
|
+
request,
|
|
114
|
+
processTransactionBatch
|
|
115
|
+
}) {
|
|
116
|
+
const batchRequestWithSingleCall = {
|
|
117
|
+
batchId: generateBatchId(),
|
|
118
|
+
transactions
|
|
119
|
+
};
|
|
120
|
+
return processTransactionBatch(batchRequestWithSingleCall, request);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handler for wallet_sendCalls (EIP-5792).
|
|
125
|
+
* Sends a batch of calls for an EIP-7702 upgraded account.
|
|
126
|
+
*
|
|
127
|
+
* @param request - The JRPC request with send calls parameters.
|
|
128
|
+
* @param getEthCode - Function to get the code at an address.
|
|
129
|
+
* @param context - Context containing required functions.
|
|
130
|
+
* @returns The batch ID.
|
|
131
|
+
*/
|
|
132
|
+
async function walletSendCalls(request, getEthCode, context) {
|
|
133
|
+
const {
|
|
134
|
+
method,
|
|
135
|
+
params
|
|
136
|
+
} = request;
|
|
137
|
+
if (method !== EIP_5792_METHODS.WALLET_SEND_CALLS) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const sendCallsParams = Array.isArray(params) ? params[0] : params;
|
|
141
|
+
validateSendCallsParams(sendCallsParams);
|
|
142
|
+
const {
|
|
143
|
+
chainId,
|
|
144
|
+
from,
|
|
145
|
+
calls
|
|
146
|
+
} = sendCallsParams;
|
|
147
|
+
const transactions = calls.map(call => ({
|
|
148
|
+
params: call
|
|
149
|
+
}));
|
|
150
|
+
const isBatchCalls = Object.keys(transactions).length > 1;
|
|
151
|
+
if (!isBatchCalls) {
|
|
152
|
+
return processSingleTransaction({
|
|
153
|
+
transactions,
|
|
154
|
+
request,
|
|
155
|
+
processTransactionBatch: context.processTransactionBatch
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return processMultipleTransactions({
|
|
159
|
+
from: from,
|
|
160
|
+
transactions,
|
|
161
|
+
request,
|
|
162
|
+
chainId,
|
|
163
|
+
getEthCode,
|
|
164
|
+
processTransactionBatch: context.processTransactionBatch
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export { generateBatchId, processMultipleTransactions, processSingleTransaction, validateSendCallsParams, walletSendCalls };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { addHexPrefix } from '@ethereumjs/util';
|
|
2
|
+
import { zeroAddress, encodeAbiParameters, parseAbiParameters, encodeFunctionData } from 'viem';
|
|
3
|
+
import { erc7821Abi } from '../utils/abis.js';
|
|
4
|
+
import { SUPPORTED_NETWORKS } from '../utils/constants.js';
|
|
5
|
+
import { EIP_7702_PREFIX } from '../utils/eip7702Types.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The MetaMask EIP-7702 Stateless Delegator contract address.
|
|
9
|
+
* Used as the delegation target for all supported networks.
|
|
10
|
+
*/
|
|
11
|
+
const MetaMask_EIP7702_Stateless_Delegator = "0x63c0c19a282a1B52b07dD5a65b58948A07DAE32B";
|
|
12
|
+
async function getDelegationAddress(walletAddress, chainId, getEthCode) {
|
|
13
|
+
// query eth_getCode
|
|
14
|
+
const code = await getEthCode(walletAddress, chainId);
|
|
15
|
+
const normalizedCode = code ? addHexPrefix(code).toLowerCase() : "0x0";
|
|
16
|
+
const hasDelegation = normalizedCode.length === 48 && normalizedCode.startsWith(EIP_7702_PREFIX);
|
|
17
|
+
if (hasDelegation) {
|
|
18
|
+
const delegationAddress = addHexPrefix(normalizedCode.slice(EIP_7702_PREFIX.length));
|
|
19
|
+
return delegationAddress;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Check if the wallet is supported for EIP-7702 on provided chain.
|
|
26
|
+
*/
|
|
27
|
+
async function getIsEip7702UpgradeSupported(address, chainId, getEthCode) {
|
|
28
|
+
if (!SUPPORTED_NETWORKS[chainId]) {
|
|
29
|
+
return {
|
|
30
|
+
isSupported: false,
|
|
31
|
+
delegationAddress: null
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const delegationAddress = await getDelegationAddress(address, chainId, getEthCode);
|
|
35
|
+
return {
|
|
36
|
+
isSupported: true,
|
|
37
|
+
upgradeContractAddress: MetaMask_EIP7702_Stateless_Delegator,
|
|
38
|
+
delegationAddress
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generate an EIP-7702 batch transaction.
|
|
44
|
+
*
|
|
45
|
+
* Reference: {@link https://github.com/MetaMask/core/blob/main/packages/transaction-controller/src/utils/eip7702.ts#L119}
|
|
46
|
+
*
|
|
47
|
+
* @param from - The sender address.
|
|
48
|
+
* @param transactions - The transactions to batch.
|
|
49
|
+
* @returns The batch transaction.
|
|
50
|
+
*/
|
|
51
|
+
function generateEIP7702BatchTransaction(from, transactions) {
|
|
52
|
+
const calls = transactions.map(transaction => {
|
|
53
|
+
const {
|
|
54
|
+
data,
|
|
55
|
+
to,
|
|
56
|
+
value
|
|
57
|
+
} = transaction;
|
|
58
|
+
return {
|
|
59
|
+
target: to !== null && to !== void 0 ? to : zeroAddress,
|
|
60
|
+
value: BigInt(value !== null && value !== void 0 ? value : "0x0"),
|
|
61
|
+
callData: data !== null && data !== void 0 ? data : "0x"
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Single batch mode, no opData.
|
|
66
|
+
const mode = "0x01".padEnd(66, "0");
|
|
67
|
+
|
|
68
|
+
// Encode the calls array as (address target, uint256 value, bytes callData)[]
|
|
69
|
+
const executionData = encodeAbiParameters(parseAbiParameters("(address target, uint256 value, bytes callData)[]"), [calls]);
|
|
70
|
+
const data = encodeFunctionData({
|
|
71
|
+
abi: erc7821Abi,
|
|
72
|
+
functionName: "execute",
|
|
73
|
+
args: [mode, executionData]
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
data,
|
|
77
|
+
to: from
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { MetaMask_EIP7702_Stateless_Delegator, generateEIP7702BatchTransaction, getDelegationAddress, getIsEip7702UpgradeSupported };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { rpcErrors } from '@web3auth/auth';
|
|
2
|
+
import { getDelegationAddress } from './eip7702Utils.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get the EIP7702 upgrade status of an EOA.
|
|
6
|
+
*
|
|
7
|
+
* @param request - The request object.
|
|
8
|
+
* @param getEthCode - The function to get the code of an account.
|
|
9
|
+
* @returns The upgrade status.
|
|
10
|
+
*/
|
|
11
|
+
async function walletGetUpgradeStatus(request, getEthCode) {
|
|
12
|
+
const {
|
|
13
|
+
method,
|
|
14
|
+
params
|
|
15
|
+
} = request;
|
|
16
|
+
if (method !== "wallet_getAccountUpgradeStatus") {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const getUpgradeStatusParam = Array.isArray(params) ? params[0] : params;
|
|
20
|
+
const account = getUpgradeStatusParam.account;
|
|
21
|
+
const chainId = getUpgradeStatusParam.chainId;
|
|
22
|
+
if (!account || !chainId) {
|
|
23
|
+
throw rpcErrors.invalidParams("wallet_getAccountUpgradeStatus: account and chainId are required");
|
|
24
|
+
}
|
|
25
|
+
const delegationAddress = await getDelegationAddress(account, chainId, getEthCode);
|
|
26
|
+
const isUpgraded = delegationAddress !== null;
|
|
27
|
+
return {
|
|
28
|
+
isUpgraded,
|
|
29
|
+
implementation: delegationAddress !== null && delegationAddress !== void 0 ? delegationAddress : "0x0"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { walletGetUpgradeStatus };
|