@deserialize/multi-vm-wallet 1.3.0 → 1.3.2
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/.claude/settings.local.json +8 -1
- package/dist/IChainWallet.d.ts +3 -3
- package/dist/evm/aa-service/index.d.ts +1 -1
- package/dist/evm/aa-service/index.js +1 -2
- package/dist/evm/aa-service/index.js.map +1 -1
- package/dist/evm/aa-service/lib/kernel-account.d.ts +1 -43
- package/dist/evm/aa-service/lib/kernel-account.js +21 -88
- package/dist/evm/aa-service/lib/kernel-account.js.map +1 -1
- package/dist/evm/aa-service/lib/type.d.ts +16 -0
- package/dist/evm/aa-service/lib/type.js.map +1 -1
- package/dist/evm/aa-service/services/account-abstraction.d.ts +4 -0
- package/dist/evm/aa-service/services/account-abstraction.js +12 -4
- package/dist/evm/aa-service/services/account-abstraction.js.map +1 -1
- package/dist/evm/aa-service/services/bundler.d.ts +4 -1
- package/dist/evm/aa-service/services/bundler.js +40 -7
- package/dist/evm/aa-service/services/bundler.js.map +1 -1
- package/dist/evm/evm.d.ts +3 -13
- package/dist/evm/evm.js +12 -80
- package/dist/evm/evm.js.map +1 -1
- package/dist/evm/smartWallet.d.ts +2 -19
- package/dist/evm/smartWallet.js +8 -68
- package/dist/evm/smartWallet.js.map +1 -1
- package/dist/evm/utils.js +2 -1
- package/dist/evm/utils.js.map +1 -1
- package/dist/helpers/index.d.ts +6 -1
- package/dist/helpers/index.js +116 -0
- package/dist/helpers/index.js.map +1 -1
- package/dist/svm/svm.d.ts +3 -3
- package/dist/svm/svm.js +6 -17
- package/dist/svm/svm.js.map +1 -1
- package/dist/svm/utils.d.ts +2 -2
- package/dist/svm/utils.js +4 -4
- package/dist/svm/utils.js.map +1 -1
- package/dist/test.d.ts +4 -0
- package/dist/test.js +66 -21
- package/dist/test.js.map +1 -1
- package/dist/types.d.ts +14 -16
- package/dist/types.js.map +1 -1
- package/package.json +7 -1
- package/utils/IChainWallet.ts +3 -3
- package/utils/evm/aa-service/index.ts +1 -2
- package/utils/evm/aa-service/lib/kernel-account.ts +22 -128
- package/utils/evm/aa-service/lib/type.ts +17 -0
- package/utils/evm/aa-service/services/account-abstraction.ts +18 -4
- package/utils/evm/aa-service/services/bundler.ts +53 -11
- package/utils/evm/evm.ts +13 -110
- package/utils/evm/smartWallet.ts +10 -88
- package/utils/evm/utils.ts +2 -1
- package/utils/helpers/index.ts +138 -1
- package/utils/svm/svm.ts +7 -25
- package/utils/svm/utils.ts +4 -10
- package/utils/test.ts +85 -21
- package/utils/types.ts +15 -17
- package/utils/evm/SMART_WALLET_EXAMPLES.ts.bak +0 -591
package/dist/types.d.ts
CHANGED
|
@@ -16,19 +16,20 @@ export interface ChainWalletConfig {
|
|
|
16
16
|
confirmationNo?: number;
|
|
17
17
|
testnet?: boolean;
|
|
18
18
|
vmType: vmTypes;
|
|
19
|
-
aaSupport?:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
aaSupport?: AA_SupportConfig;
|
|
20
|
+
}
|
|
21
|
+
export interface AA_SupportConfig {
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
entryPoints: {
|
|
24
|
+
address: string;
|
|
25
|
+
version: EntryPointVersion;
|
|
26
|
+
}[];
|
|
27
|
+
bundlerUrl: string;
|
|
28
|
+
paymasterUrl: string;
|
|
29
|
+
kernelImplementations: {
|
|
30
|
+
address: string;
|
|
31
|
+
version: number;
|
|
32
|
+
}[];
|
|
32
33
|
}
|
|
33
34
|
export interface TokenInfo {
|
|
34
35
|
address: string;
|
|
@@ -202,9 +203,6 @@ export interface TransactionResult {
|
|
|
202
203
|
success: boolean;
|
|
203
204
|
error?: string;
|
|
204
205
|
}
|
|
205
|
-
export interface FeePayerOptions {
|
|
206
|
-
privateKey: string;
|
|
207
|
-
}
|
|
208
206
|
export interface Balance {
|
|
209
207
|
balance: BN;
|
|
210
208
|
formatted: number;
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../utils/types.ts"],"names":[],"mappings":";;;AACA,+BAA8B;AAC9B,+BAA8B;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../utils/types.ts"],"names":[],"mappings":";;;AACA,+BAA8B;AAC9B,+BAA8B;AA+QjB,QAAA,YAAY,GAAG;IACxB,KAAK,EAAE,WAAK;IACZ,KAAK,EAAE,WAAK;CACN,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deserialize/multi-vm-wallet",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"devDependencies": {
|
|
5
5
|
"@types/bn.js": "^5.2.0",
|
|
6
6
|
"@types/crypto-js": "^4.2.2",
|
|
@@ -16,15 +16,21 @@
|
|
|
16
16
|
"@noble/hashes": "^1.3.3",
|
|
17
17
|
"@scure/bip32": "^2.0.1",
|
|
18
18
|
"@scure/bip39": "^2.0.1",
|
|
19
|
+
"@simplewebauthn/typescript-types": "^8.3.4",
|
|
19
20
|
"@solana/spl-token": "^0.4.13",
|
|
20
21
|
"@solana/web3.js": "^1.98.4",
|
|
22
|
+
"@zerodev/permissions": "^5.6.3",
|
|
23
|
+
"@zerodev/sdk": "^5.5.7",
|
|
24
|
+
"@zerodev/webauthn-key": "^5.5.0",
|
|
21
25
|
"bignumber.js": "^9.3.1",
|
|
22
26
|
"bn.js": "^5.2.2",
|
|
23
27
|
"bs58": "^6.0.0",
|
|
24
28
|
"crypto-js": "^4.2.0",
|
|
25
29
|
"debonk-evm-sever-sdk": "^1.4.0",
|
|
26
30
|
"ethers": "^6.15.0",
|
|
31
|
+
"permissionless": "^0.3.2",
|
|
27
32
|
"promise-retry": "^2.0.1",
|
|
33
|
+
"tslib": "^2.8.1",
|
|
28
34
|
"tweetnacl": "^1.0.3",
|
|
29
35
|
"viem": "^2.43.4"
|
|
30
36
|
},
|
package/utils/IChainWallet.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EVMTransactionHistoryItem } from "./evm/transactionParsing";
|
|
2
2
|
import { SVMTransactionHistoryItem } from "./svm/transactionParsing";
|
|
3
|
-
import { Balance, ChainWalletConfig, NFTInfo, TokenInfo, TransactionResult, UserTokenBalance, NFT
|
|
3
|
+
import { Balance, ChainWalletConfig, NFTInfo, TokenInfo, TransactionResult, UserTokenBalance, NFT } from "./types";
|
|
4
4
|
|
|
5
5
|
export abstract class ChainWallet<AddressType, PrivateKeyType, ConnectionType> {
|
|
6
6
|
protected privateKey: PrivateKeyType;
|
|
@@ -20,8 +20,8 @@ export abstract class ChainWallet<AddressType, PrivateKeyType, ConnectionType> {
|
|
|
20
20
|
abstract generateAddress(privateKey: PrivateKeyType): AddressType;
|
|
21
21
|
abstract getNativeBalance(): Promise<Balance>;
|
|
22
22
|
abstract getTokenBalance(tokenAddress: AddressType): Promise<Balance>;
|
|
23
|
-
abstract transferNative(to: AddressType, amount: number
|
|
24
|
-
abstract transferToken(tokenAddress: TokenInfo, to: AddressType, amount: number
|
|
23
|
+
abstract transferNative(to: AddressType, amount: number): Promise<TransactionResult>;
|
|
24
|
+
abstract transferToken(tokenAddress: TokenInfo, to: AddressType, amount: number): Promise<TransactionResult>;
|
|
25
25
|
abstract swap(tokenAddress: TokenInfo, to: AddressType, amount: number, slippage?: number): Promise<TransactionResult>;
|
|
26
26
|
abstract discoverToken(): Promise<UserTokenBalance<AddressType>[]>;
|
|
27
27
|
abstract discoverNFT(): Promise<NFT[]>;
|
|
@@ -9,7 +9,7 @@ import { Chain, Hex, parseEther, PublicClient, SignAuthorizationReturnType, crea
|
|
|
9
9
|
import { PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts';
|
|
10
10
|
import { createKernelAccount } from '@zerodev/sdk';
|
|
11
11
|
import { KERNEL_V3_3, KernelVersionToAddressesMap } from '@zerodev/sdk/constants';
|
|
12
|
-
import { entryPoint07Address, entryPoint08Address } from 'viem/account-abstraction';
|
|
12
|
+
import { createBundlerClient, entryPoint07Address, entryPoint08Address } from 'viem/account-abstraction';
|
|
13
13
|
import { BundlerManager, createBundlerService } from '../services/bundler';
|
|
14
14
|
import { BatchTransactionConfig, EntryPointVersion, KernelAccountConfig, KernelAccountInstance, KernelVersion, SingleTransactionConfig, Call } from './type';
|
|
15
15
|
|
|
@@ -47,7 +47,8 @@ export async function createKernel7702Account(
|
|
|
47
47
|
owner,
|
|
48
48
|
bundlerManager,
|
|
49
49
|
entryPointVersion = '0.7',
|
|
50
|
-
kernelVersion = '0.3.3'
|
|
50
|
+
kernelVersion = '0.3.3',
|
|
51
|
+
aaConfig
|
|
51
52
|
} = config;
|
|
52
53
|
|
|
53
54
|
// Create public client for standard RPC calls
|
|
@@ -57,11 +58,25 @@ export async function createKernel7702Account(
|
|
|
57
58
|
transport: http()
|
|
58
59
|
});
|
|
59
60
|
|
|
60
|
-
// Get EntryPoint address
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
61
|
+
// Get EntryPoint address from aaConfig or fallback to default
|
|
62
|
+
let entryPointAddress: Hex;
|
|
63
|
+
|
|
64
|
+
if (aaConfig && aaConfig.entryPoints.length > 0) {
|
|
65
|
+
// Find matching entry point from config
|
|
66
|
+
const entryPoint = aaConfig.entryPoints.find(ep => ep.version === entryPointVersion);
|
|
67
|
+
if (entryPoint) {
|
|
68
|
+
entryPointAddress = entryPoint.address as Hex;
|
|
69
|
+
} else {
|
|
70
|
+
// Fallback to first entry point if version not found
|
|
71
|
+
console.warn(`EntryPoint version ${entryPointVersion} not found in aaConfig, using first available`);
|
|
72
|
+
entryPointAddress = aaConfig.entryPoints[0].address as Hex;
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
// Fallback to hardcoded map if no config
|
|
76
|
+
entryPointAddress = ENTRYPOINT_MAP[entryPointVersion];
|
|
77
|
+
if (!entryPointAddress) {
|
|
78
|
+
throw new Error(`Unsupported EntryPoint version: ${entryPointVersion}`);
|
|
79
|
+
}
|
|
65
80
|
}
|
|
66
81
|
|
|
67
82
|
// Create Kernel account with EIP-7702
|
|
@@ -244,124 +259,3 @@ export async function waitForKernelReceipt(config: {
|
|
|
244
259
|
return receipt;
|
|
245
260
|
}
|
|
246
261
|
|
|
247
|
-
// ============================================
|
|
248
|
-
// Sponsored Transactions (EIP-7702)
|
|
249
|
-
// ============================================
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Configuration for sponsored batch transaction
|
|
253
|
-
*/
|
|
254
|
-
export interface SponsoredBatchTransactionConfig {
|
|
255
|
-
ownerAuthorization: SignAuthorizationReturnType;
|
|
256
|
-
calls: Call[];
|
|
257
|
-
feePayerPrivateKey: Hex;
|
|
258
|
-
bundlerUrl: string;
|
|
259
|
-
paymasterUrl?: string;
|
|
260
|
-
chain: Chain;
|
|
261
|
-
entryPointVersion?: EntryPointVersion;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Send sponsored batch transaction using EIP-7702
|
|
266
|
-
*
|
|
267
|
-
* Allows a feePayer wallet to pay gas fees for another wallet's transaction.
|
|
268
|
-
* The transaction executes from the owner's address, but gas is paid by the feePayer.
|
|
269
|
-
*
|
|
270
|
-
* @param config - Sponsored transaction configuration
|
|
271
|
-
* @returns UserOperation hash and transaction hash
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* // Owner creates authorization
|
|
275
|
-
* const authorization = await createKernelAuthorization({
|
|
276
|
-
* owner: ownerAccount,
|
|
277
|
-
* chain,
|
|
278
|
-
* bundlerManager
|
|
279
|
-
* });
|
|
280
|
-
*
|
|
281
|
-
* // FeePayer sends transaction
|
|
282
|
-
* const result = await sendSponsoredBatchTransaction({
|
|
283
|
-
* ownerAuthorization: authorization,
|
|
284
|
-
* calls: [{ to: recipient, value: parseEther('0.1') }],
|
|
285
|
-
* feePayerPrivateKey: sponsorPrivateKey,
|
|
286
|
-
* bundlerUrl,
|
|
287
|
-
* chain
|
|
288
|
-
* });
|
|
289
|
-
*/
|
|
290
|
-
export async function sendSponsoredBatchTransaction(
|
|
291
|
-
config: SponsoredBatchTransactionConfig
|
|
292
|
-
): Promise<{ userOpHash: Hex; transactionHash?: string }> {
|
|
293
|
-
const {
|
|
294
|
-
ownerAuthorization,
|
|
295
|
-
calls,
|
|
296
|
-
feePayerPrivateKey,
|
|
297
|
-
bundlerUrl,
|
|
298
|
-
paymasterUrl,
|
|
299
|
-
chain,
|
|
300
|
-
entryPointVersion = '0.7'
|
|
301
|
-
} = config;
|
|
302
|
-
|
|
303
|
-
if (calls.length === 0) {
|
|
304
|
-
throw new Error('Sponsored transaction must have at least one call');
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Create feePayer account
|
|
308
|
-
const feePayerAccount = privateKeyToAccount(feePayerPrivateKey);
|
|
309
|
-
|
|
310
|
-
// Create bundler service for feePayer
|
|
311
|
-
const feePayerBundlerService = createBundlerService({
|
|
312
|
-
provider: "custom",
|
|
313
|
-
customUrl: bundlerUrl,
|
|
314
|
-
chain
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
// Get bundler client (uses feePayer account internally)
|
|
318
|
-
const bundlerClient = feePayerBundlerService.getClient(chain);
|
|
319
|
-
|
|
320
|
-
// Create kernel account for feePayer (needed for sendUserOperation)
|
|
321
|
-
const publicClient = createPublicClient({
|
|
322
|
-
chain,
|
|
323
|
-
transport: http(chain.rpcUrls.default.http[0])
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
const entryPointAddress = ENTRYPOINT_MAP[entryPointVersion];
|
|
327
|
-
if (!entryPointAddress) {
|
|
328
|
-
throw new Error(`Unsupported EntryPoint version: ${entryPointVersion}`);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const feePayerKernelAccount = await createKernelAccount(
|
|
332
|
-
publicClient as any,
|
|
333
|
-
{
|
|
334
|
-
entryPoint: {
|
|
335
|
-
address: entryPointAddress,
|
|
336
|
-
version: entryPointVersion
|
|
337
|
-
},
|
|
338
|
-
kernelVersion: KERNEL_V3_3,
|
|
339
|
-
eip7702Account: feePayerAccount as any
|
|
340
|
-
}
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
// Normalize calls
|
|
344
|
-
const normalizedCalls = calls.map(call => ({
|
|
345
|
-
to: call.to,
|
|
346
|
-
value: call.value ?? 0n,
|
|
347
|
-
data: call.data ?? '0x' as Hex
|
|
348
|
-
}));
|
|
349
|
-
|
|
350
|
-
// Send UserOperation with owner's authorization
|
|
351
|
-
// The transaction executes from owner's address, but feePayer pays gas
|
|
352
|
-
const userOpHash = await bundlerClient.sendUserOperation({
|
|
353
|
-
account: feePayerKernelAccount,
|
|
354
|
-
authorization: ownerAuthorization,
|
|
355
|
-
calls: normalizedCalls
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
// Wait for receipt
|
|
359
|
-
const receipt = await bundlerClient.waitForUserOperationReceipt({
|
|
360
|
-
hash: userOpHash
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
return {
|
|
364
|
-
userOpHash: userOpHash as Hex,
|
|
365
|
-
transactionHash: receipt?.receipt?.transactionHash
|
|
366
|
-
};
|
|
367
|
-
}
|
|
@@ -59,6 +59,7 @@ export interface KernelAccountConfig {
|
|
|
59
59
|
bundlerManager: BundlerManager;
|
|
60
60
|
entryPointVersion?: EntryPointVersion;
|
|
61
61
|
kernelVersion?: KernelVersion;
|
|
62
|
+
aaConfig?: AA_SupportConfig;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export interface KernelAccountInstance {
|
|
@@ -79,7 +80,23 @@ export interface KernelAccountInstance {
|
|
|
79
80
|
|
|
80
81
|
|
|
81
82
|
|
|
83
|
+
export interface AA_SupportConfig {
|
|
84
|
+
enabled: boolean;
|
|
85
|
+
entryPoints: {
|
|
86
|
+
address: string;
|
|
87
|
+
version: EntryPointVersion;
|
|
88
|
+
}[]
|
|
89
|
+
bundlerUrl: string;
|
|
90
|
+
paymasterUrl: string;
|
|
91
|
+
kernelImplementations: {
|
|
92
|
+
address: string;
|
|
93
|
+
version: number;
|
|
94
|
+
}[];
|
|
95
|
+
}
|
|
96
|
+
|
|
82
97
|
export interface SmartWalletOptions {
|
|
98
|
+
/** Full AA support configuration from chain config */
|
|
99
|
+
aaConfig?: AA_SupportConfig;
|
|
83
100
|
/** Bundler URL for submitting UserOperations */
|
|
84
101
|
bundlerUrl?: string;
|
|
85
102
|
/** Paymaster URL for gas sponsorship (optional) */
|
|
@@ -60,16 +60,20 @@ import { ModularSigner } from '@zerodev/permissions';
|
|
|
60
60
|
// Types
|
|
61
61
|
// ============================================
|
|
62
62
|
|
|
63
|
+
import { AA_SupportConfig } from '../lib/type';
|
|
64
|
+
|
|
63
65
|
export interface AAServiceConfig {
|
|
64
66
|
bundlerProvider: 'pimlico' | 'etherspot' | 'custom';
|
|
65
67
|
apiKey?: string;
|
|
66
68
|
customBundlerUrl?: string;
|
|
69
|
+
aaConfig?: AA_SupportConfig;
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
export interface CreateAccountOptions {
|
|
70
73
|
chain: Chain;
|
|
71
74
|
owner: PrivateKeyAccount;
|
|
72
75
|
entryPointVersion?: EntryPointVersion;
|
|
76
|
+
aaConfig?: AA_SupportConfig;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
export interface SendTransactionOptions {
|
|
@@ -98,6 +102,7 @@ export interface WaitForReceiptOptions {
|
|
|
98
102
|
export class AccountAbstractionService {
|
|
99
103
|
private static instance: AccountAbstractionService | null = null;
|
|
100
104
|
private bundlerManager: BundlerManager;
|
|
105
|
+
private aaConfig: AA_SupportConfig | undefined;
|
|
101
106
|
private accountCache: Map<string, KernelAccountInstance> = new Map();
|
|
102
107
|
private authorizationCache: Map<string, SignAuthorizationReturnType> = new Map();
|
|
103
108
|
private publicClientCache: Map<number, PublicClient> = new Map();
|
|
@@ -109,9 +114,11 @@ export class AccountAbstractionService {
|
|
|
109
114
|
const bundlerConfig: BundlerConfig = {
|
|
110
115
|
provider: config.bundlerProvider,
|
|
111
116
|
apiKey: config.apiKey,
|
|
112
|
-
customUrl: config.customBundlerUrl
|
|
117
|
+
customUrl: config.customBundlerUrl,
|
|
118
|
+
aaConfig: config.aaConfig
|
|
113
119
|
};
|
|
114
120
|
this.bundlerManager = createBundlerManager(bundlerConfig);
|
|
121
|
+
this.aaConfig = config.aaConfig;
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
/**
|
|
@@ -142,10 +149,12 @@ export class AccountAbstractionService {
|
|
|
142
149
|
const bundlerConfig: BundlerConfig = {
|
|
143
150
|
provider: config.bundlerProvider,
|
|
144
151
|
apiKey: config.apiKey,
|
|
145
|
-
customUrl: config.customBundlerUrl
|
|
152
|
+
customUrl: config.customBundlerUrl,
|
|
153
|
+
aaConfig: config.aaConfig
|
|
146
154
|
};
|
|
147
155
|
|
|
148
156
|
this.bundlerManager = createBundlerManager(bundlerConfig);
|
|
157
|
+
this.aaConfig = config.aaConfig;
|
|
149
158
|
this.clearCache();
|
|
150
159
|
}
|
|
151
160
|
|
|
@@ -160,7 +169,8 @@ export class AccountAbstractionService {
|
|
|
160
169
|
const {
|
|
161
170
|
chain,
|
|
162
171
|
owner,
|
|
163
|
-
entryPointVersion = '0.7'
|
|
172
|
+
entryPointVersion = '0.7',
|
|
173
|
+
aaConfig
|
|
164
174
|
} = options;
|
|
165
175
|
|
|
166
176
|
const cacheKey = this.getAccountCacheKey(chain, owner, entryPointVersion);
|
|
@@ -170,12 +180,16 @@ export class AccountAbstractionService {
|
|
|
170
180
|
return this.accountCache.get(cacheKey)!;
|
|
171
181
|
}
|
|
172
182
|
|
|
183
|
+
// Use aaConfig from options or fallback to service-level config
|
|
184
|
+
const config = aaConfig || this.aaConfig;
|
|
185
|
+
|
|
173
186
|
// Create new account
|
|
174
187
|
const account = await createKernel7702Account({
|
|
175
188
|
chain,
|
|
176
189
|
owner,
|
|
177
190
|
bundlerManager: this.bundlerManager,
|
|
178
|
-
entryPointVersion
|
|
191
|
+
entryPointVersion,
|
|
192
|
+
aaConfig: config
|
|
179
193
|
});
|
|
180
194
|
|
|
181
195
|
// Cache and return
|
|
@@ -6,23 +6,26 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Chain, createPublicClient, http, publicActions, walletActions } from 'viem';
|
|
9
|
-
import { createBundlerClient, entryPoint07Address, entryPoint08Address } from 'viem/account-abstraction';
|
|
10
|
-
|
|
9
|
+
import { BundlerClient, createBundlerClient, entryPoint07Address, entryPoint08Address } from 'viem/account-abstraction';
|
|
10
|
+
import { createPimlicoClient } from 'permissionless/clients/pimlico';
|
|
11
11
|
// ============================================
|
|
12
12
|
// Types
|
|
13
13
|
// ============================================
|
|
14
14
|
|
|
15
15
|
export type BundlerProvider = 'pimlico' | 'etherspot' | 'custom';
|
|
16
16
|
|
|
17
|
+
import type { AA_SupportConfig } from '../lib/type';
|
|
18
|
+
|
|
17
19
|
export interface BundlerConfig {
|
|
18
20
|
provider: BundlerProvider;
|
|
19
21
|
apiKey?: string;
|
|
20
22
|
customUrl?: string;
|
|
21
23
|
chain?: Chain;
|
|
24
|
+
aaConfig?: AA_SupportConfig;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export interface BundlerService {
|
|
25
|
-
getClient(chain: Chain):
|
|
28
|
+
getClient(chain: Chain): BundlerClient;
|
|
26
29
|
getBundlerUrl(chain: Chain): string;
|
|
27
30
|
getProvider(): string;
|
|
28
31
|
}
|
|
@@ -34,26 +37,61 @@ export interface BundlerService {
|
|
|
34
37
|
class PimlicoBundler implements BundlerService {
|
|
35
38
|
private apiKey: string;
|
|
36
39
|
private clientCache: Map<number, any> = new Map();
|
|
40
|
+
private url: string;
|
|
41
|
+
private aaConfig?: AA_SupportConfig;
|
|
37
42
|
|
|
38
|
-
constructor(apiKey: string) {
|
|
39
|
-
|
|
40
|
-
throw new Error('Pimlico API key is required');
|
|
41
|
-
}
|
|
43
|
+
constructor(apiKey: string, url: string, aaConfig?: AA_SupportConfig) {
|
|
44
|
+
this.url = url;
|
|
42
45
|
this.apiKey = apiKey;
|
|
46
|
+
this.aaConfig = aaConfig;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
getBundlerUrl(chain: Chain): string {
|
|
50
|
+
if (!this.apiKey) {
|
|
51
|
+
return this.url
|
|
52
|
+
}
|
|
46
53
|
return `https://api.pimlico.io/v2/${chain.id}/rpc?apikey=${this.apiKey}`;
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
getClient(chain: Chain):
|
|
56
|
+
getClient(chain: Chain): BundlerClient {
|
|
50
57
|
if (this.clientCache.has(chain.id)) {
|
|
51
58
|
return this.clientCache.get(chain.id);
|
|
52
59
|
}
|
|
60
|
+
const bundlerUrl = this.getBundlerUrl(chain);
|
|
61
|
+
|
|
62
|
+
// Get entryPoint from aaConfig or fallback to default
|
|
63
|
+
let entryPointAddress: `0x${string}`;
|
|
64
|
+
let entryPointVersion: '0.6' | '0.7' = '0.7';
|
|
65
|
+
|
|
66
|
+
if (this.aaConfig && this.aaConfig.entryPoints.length > 0) {
|
|
67
|
+
// Use first entry point from config (could be enhanced to select by version)
|
|
68
|
+
const ep = this.aaConfig.entryPoints[0];
|
|
69
|
+
entryPointAddress = ep.address as `0x${string}`;
|
|
70
|
+
entryPointVersion = ep.version;
|
|
71
|
+
} else {
|
|
72
|
+
// Fallback to hardcoded default
|
|
73
|
+
entryPointAddress = entryPoint07Address;
|
|
74
|
+
entryPointVersion = '0.7';
|
|
75
|
+
}
|
|
53
76
|
|
|
77
|
+
// Create Pimlico client for Pimlico-specific features (gas estimation)
|
|
78
|
+
const entryPoint = {
|
|
79
|
+
address: entryPointAddress,
|
|
80
|
+
version: entryPointVersion
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const paymasterClient = createPimlicoClient({
|
|
84
|
+
transport: http(bundlerUrl),
|
|
85
|
+
entryPoint
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Create bundler client with Pimlico gas estimation
|
|
54
89
|
const client = createBundlerClient({
|
|
55
|
-
transport: http(
|
|
56
|
-
chain
|
|
90
|
+
transport: http(bundlerUrl),
|
|
91
|
+
chain,
|
|
92
|
+
userOperation: {
|
|
93
|
+
estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast,
|
|
94
|
+
}
|
|
57
95
|
});
|
|
58
96
|
|
|
59
97
|
this.clientCache.set(chain.id, client);
|
|
@@ -155,7 +193,11 @@ export class BundlerManager {
|
|
|
155
193
|
constructor(config: BundlerConfig) {
|
|
156
194
|
switch (config.provider) {
|
|
157
195
|
case 'pimlico':
|
|
158
|
-
this.bundlerService = new PimlicoBundler(
|
|
196
|
+
this.bundlerService = new PimlicoBundler(
|
|
197
|
+
config.apiKey ? config.apiKey : '',
|
|
198
|
+
config.customUrl ? config.customUrl : '',
|
|
199
|
+
config.aaConfig
|
|
200
|
+
);
|
|
159
201
|
break;
|
|
160
202
|
// case 'etherspot':
|
|
161
203
|
// this.bundlerService = new EtherspotBundler();
|
package/utils/evm/evm.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { EVMDeriveChildPrivateKey } from "../walletBip32";
|
|
8
8
|
import { ChainWallet } from "../IChainWallet";
|
|
9
|
-
import { Balance, ChainWalletConfig, NFTInfo, UserTokenBalance, TokenInfo, TransactionResult, NFT
|
|
9
|
+
import { Balance, ChainWalletConfig, NFTInfo, UserTokenBalance, TokenInfo, TransactionResult, NFT } from "../types";
|
|
10
10
|
import { VM } from "../vm";
|
|
11
11
|
import { ethers, JsonRpcProvider, Wallet, formatUnits, Interface } from "ethers";
|
|
12
12
|
import BN from "bn.js";
|
|
@@ -225,25 +225,17 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
225
225
|
*/
|
|
226
226
|
async extend(options: SmartWalletOptions = {}): Promise<EVMSmartWallet> {
|
|
227
227
|
if (!this.smartWallet) {
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
paymasterUrl = paymasterUrl || this.config.aaSupport.paymasterUrl;
|
|
237
|
-
|
|
238
|
-
// Use the first entry point version if not specified
|
|
239
|
-
if (!entryPointVersion && this.config.aaSupport.entryPoints.length > 0) {
|
|
240
|
-
const version = this.config.aaSupport.entryPoints[0].version;
|
|
241
|
-
entryPointVersion = version
|
|
242
|
-
}
|
|
243
|
-
}
|
|
228
|
+
// Merge options with aaSupport config (options take priority)
|
|
229
|
+
const mergedOptions: SmartWalletOptions = {
|
|
230
|
+
...options,
|
|
231
|
+
aaConfig: this.config.aaSupport,
|
|
232
|
+
bundlerUrl: options.bundlerUrl || this.config.aaSupport?.bundlerUrl,
|
|
233
|
+
paymasterUrl: options.paymasterUrl || this.config.aaSupport?.paymasterUrl,
|
|
234
|
+
entryPointVersion: options.entryPointVersion || this.config.aaSupport?.entryPoints?.[0]?.version
|
|
235
|
+
};
|
|
244
236
|
|
|
245
237
|
// Validate bundlerUrl is available
|
|
246
|
-
if (!bundlerUrl) {
|
|
238
|
+
if (!mergedOptions.bundlerUrl) {
|
|
247
239
|
throw new Error(
|
|
248
240
|
'bundlerUrl is required to enable smart wallet features.\n' +
|
|
249
241
|
'Provide it via:\n' +
|
|
@@ -278,12 +270,7 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
278
270
|
this.smartWallet = new EVMSmartWallet(
|
|
279
271
|
this.privateKey,
|
|
280
272
|
chain,
|
|
281
|
-
|
|
282
|
-
{
|
|
283
|
-
paymasterUrl,
|
|
284
|
-
entryPointVersion,
|
|
285
|
-
autoInitialize: options.autoInitialize
|
|
286
|
-
}
|
|
273
|
+
mergedOptions
|
|
287
274
|
);
|
|
288
275
|
|
|
289
276
|
// Auto-initialize if option is set (default: true)
|
|
@@ -329,76 +316,6 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
329
316
|
}
|
|
330
317
|
}
|
|
331
318
|
|
|
332
|
-
// ============================================
|
|
333
|
-
// Sponsored Transaction Helpers (EIP-7702)
|
|
334
|
-
// ============================================
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Transfer native tokens with sponsored gas (internal method)
|
|
338
|
-
* Requires smart wallet to be initialized via extend()
|
|
339
|
-
*/
|
|
340
|
-
private async transferNativeSponsored(
|
|
341
|
-
to: string,
|
|
342
|
-
amount: number,
|
|
343
|
-
feePayerOptions: FeePayerOptions
|
|
344
|
-
): Promise<TransactionResult> {
|
|
345
|
-
// Smart wallet is guaranteed to exist because validateAAAvailability() was called
|
|
346
|
-
const call: Call = {
|
|
347
|
-
to: to as Hex,
|
|
348
|
-
value: parseEther(amount.toString()),
|
|
349
|
-
data: '0x' as Hex
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
const result = await this.smartWallet!.sendSponsoredBatchTransaction(
|
|
353
|
-
[call],
|
|
354
|
-
feePayerOptions.privateKey as Hex
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
return {
|
|
358
|
-
success: result.success,
|
|
359
|
-
hash: result.transactionHash || '',
|
|
360
|
-
error: result.error
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Transfer tokens with sponsored gas (internal method)
|
|
366
|
-
* Requires smart wallet to be initialized via extend()
|
|
367
|
-
*/
|
|
368
|
-
private async transferTokenSponsored(
|
|
369
|
-
tokenAddress: TokenInfo,
|
|
370
|
-
to: string,
|
|
371
|
-
amount: number,
|
|
372
|
-
feePayerOptions: FeePayerOptions
|
|
373
|
-
): Promise<TransactionResult> {
|
|
374
|
-
// Create ERC20 transfer call data
|
|
375
|
-
const erc20Interface = new Interface([
|
|
376
|
-
'function transfer(address to, uint256 amount) returns (bool)'
|
|
377
|
-
]);
|
|
378
|
-
|
|
379
|
-
const data = erc20Interface.encodeFunctionData('transfer', [
|
|
380
|
-
to,
|
|
381
|
-
parseUnits(amount.toString(), tokenAddress.decimals)
|
|
382
|
-
]);
|
|
383
|
-
|
|
384
|
-
const call: Call = {
|
|
385
|
-
to: tokenAddress.address as Hex,
|
|
386
|
-
value: 0n,
|
|
387
|
-
data: data as Hex
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
const result = await this.smartWallet!.sendSponsoredBatchTransaction(
|
|
391
|
-
[call],
|
|
392
|
-
feePayerOptions.privateKey as Hex
|
|
393
|
-
);
|
|
394
|
-
|
|
395
|
-
return {
|
|
396
|
-
success: result.success,
|
|
397
|
-
hash: result.transactionHash || '',
|
|
398
|
-
error: result.error
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
319
|
// ============================================
|
|
403
320
|
// Existing Wallet Methods
|
|
404
321
|
// ============================================
|
|
@@ -435,26 +352,12 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
435
352
|
return await discoverNFTs(this.address, this.config)
|
|
436
353
|
}
|
|
437
354
|
|
|
438
|
-
async transferNative(to: string, amount: number
|
|
439
|
-
// If feePayer is provided, use sponsored transaction (requires AA)
|
|
440
|
-
if (feePayerOptions) {
|
|
441
|
-
this.validateAAAvailability();
|
|
442
|
-
return await this.transferNativeSponsored(to, amount, feePayerOptions);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Regular transfer (existing implementation)
|
|
355
|
+
async transferNative(to: string, amount: number): Promise<TransactionResult> {
|
|
446
356
|
const wallet = this.getWallet();
|
|
447
357
|
return await sendNativeToken(wallet, to, amount.toString(), undefined, this.config.confirmationNo || 5);
|
|
448
358
|
}
|
|
449
359
|
|
|
450
|
-
async transferToken(tokenAddress: TokenInfo, to: string, amount: number
|
|
451
|
-
// If feePayer is provided, use sponsored transaction (requires AA)
|
|
452
|
-
if (feePayerOptions) {
|
|
453
|
-
this.validateAAAvailability();
|
|
454
|
-
return await this.transferTokenSponsored(tokenAddress, to, amount, feePayerOptions);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Regular transfer (existing implementation)
|
|
360
|
+
async transferToken(tokenAddress: TokenInfo, to: string, amount: number): Promise<TransactionResult> {
|
|
458
361
|
const wallet = this.getWallet();
|
|
459
362
|
return await sendERC20Token(wallet, tokenAddress.address, to, amount.toString(), undefined, this.config.confirmationNo || 5);
|
|
460
363
|
}
|