@deserialize/multi-vm-wallet 1.2.293 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +12 -0
- package/SMART_WALLET_GUIDE.md +746 -0
- package/SMART_WALLET_IMPLEMENTATION.md +460 -0
- package/dist/IChainWallet.d.ts +4 -3
- package/dist/IChainWallet.js +5 -0
- package/dist/IChainWallet.js.map +1 -1
- package/dist/constant.js +17 -4
- package/dist/constant.js.map +1 -1
- package/dist/evm/SMART_WALLET_EXAMPLES.d.ts +20 -0
- package/dist/evm/SMART_WALLET_EXAMPLES.js +451 -0
- package/dist/evm/SMART_WALLET_EXAMPLES.js.map +1 -0
- package/dist/evm/aa-service/index.d.ts +16 -0
- package/dist/evm/aa-service/index.js +69 -0
- package/dist/evm/aa-service/index.js.map +1 -0
- package/dist/evm/aa-service/lib/account-adapter.d.ts +26 -0
- package/dist/evm/aa-service/lib/account-adapter.js +53 -0
- package/dist/evm/aa-service/lib/account-adapter.js.map +1 -0
- package/dist/evm/aa-service/lib/kernel-account.d.ts +91 -0
- package/dist/evm/aa-service/lib/kernel-account.js +251 -0
- package/dist/evm/aa-service/lib/kernel-account.js.map +1 -0
- package/dist/evm/aa-service/lib/kernel-modules.d.ts +240 -0
- package/dist/evm/aa-service/lib/kernel-modules.js +409 -0
- package/dist/evm/aa-service/lib/kernel-modules.js.map +1 -0
- package/dist/evm/aa-service/lib/session-keys.d.ts +170 -0
- package/dist/evm/aa-service/lib/session-keys.js +297 -0
- package/dist/evm/aa-service/lib/session-keys.js.map +1 -0
- package/dist/evm/aa-service/lib/type.d.ts +167 -0
- package/dist/evm/aa-service/lib/type.js +43 -0
- package/dist/evm/aa-service/lib/type.js.map +1 -0
- package/dist/evm/aa-service/services/account-abstraction.d.ts +614 -0
- package/dist/evm/aa-service/services/account-abstraction.js +754 -0
- package/dist/evm/aa-service/services/account-abstraction.js.map +1 -0
- package/dist/evm/aa-service/services/bundler.d.ts +29 -0
- package/dist/evm/aa-service/services/bundler.js +168 -0
- package/dist/evm/aa-service/services/bundler.js.map +1 -0
- package/dist/evm/evm.d.ts +68 -3
- package/dist/evm/evm.js +223 -8
- package/dist/evm/evm.js.map +1 -1
- package/dist/evm/index.d.ts +1 -0
- package/dist/evm/index.js +3 -0
- package/dist/evm/index.js.map +1 -1
- package/dist/evm/smartWallet.d.ts +265 -0
- package/dist/evm/smartWallet.js +675 -0
- package/dist/evm/smartWallet.js.map +1 -0
- package/dist/evm/smartWallet.types.d.ts +10 -0
- package/dist/evm/smartWallet.types.js +16 -0
- package/dist/evm/smartWallet.types.js.map +1 -0
- package/dist/evm/transaction.utils.d.ts +10 -10
- package/dist/evm/transaction.utils.js +12 -8
- package/dist/evm/transaction.utils.js.map +1 -1
- package/dist/evm/transactionParsing.js +123 -27
- package/dist/evm/transactionParsing.js.map +1 -1
- package/dist/evm/utils.d.ts +12 -1
- package/dist/evm/utils.js +138 -2
- package/dist/evm/utils.js.map +1 -1
- package/dist/helpers/index.d.ts +4 -1
- package/dist/helpers/index.js +25 -0
- package/dist/helpers/index.js.map +1 -1
- package/dist/helpers/routeScan.d.ts +191 -0
- package/dist/helpers/routeScan.js +114 -0
- package/dist/helpers/routeScan.js.map +1 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/svm/svm.d.ts +6 -4
- package/dist/svm/svm.js +33 -19
- package/dist/svm/svm.js.map +1 -1
- package/dist/svm/transactionSender.js +2 -2
- package/dist/svm/transactionSender.js.map +1 -1
- package/dist/svm/utils.d.ts +20 -4
- package/dist/svm/utils.js +232 -12
- package/dist/svm/utils.js.map +1 -1
- package/dist/test.d.ts +1 -6
- package/dist/test.js +47 -16
- package/dist/test.js.map +1 -1
- package/dist/types.d.ts +169 -2
- package/dist/types.js.map +1 -1
- package/dist/vm.js +9 -7
- package/dist/vm.js.map +1 -1
- package/package.json +2 -2
- package/tsconfig.json +4 -3
- package/utils/IChainWallet.ts +4 -3
- package/utils/constant.ts +18 -4
- package/utils/evm/SMART_WALLET_EXAMPLES.ts.bak +591 -0
- package/utils/evm/aa-service/index.ts +85 -0
- package/utils/evm/aa-service/lib/account-adapter.ts +60 -0
- package/utils/evm/aa-service/lib/kernel-account.ts +367 -0
- package/utils/evm/aa-service/lib/kernel-modules.ts +598 -0
- package/utils/evm/aa-service/lib/session-keys.ts +389 -0
- package/utils/evm/aa-service/lib/type.ts +236 -0
- package/utils/evm/aa-service/services/account-abstraction.ts +1015 -0
- package/utils/evm/aa-service/services/bundler.ts +217 -0
- package/utils/evm/evm.ts +281 -13
- package/utils/evm/index.ts +5 -1
- package/utils/evm/smartWallet.ts +797 -0
- package/utils/evm/smartWallet.types.ts +33 -0
- package/utils/evm/transaction.utils.ts +12 -10
- package/utils/evm/transactionParsing.ts +153 -63
- package/utils/evm/utils.ts +161 -2
- package/utils/helpers/index.ts +13 -1
- package/utils/helpers/routeScan.ts +397 -0
- package/utils/index.ts +0 -2
- package/utils/svm/svm.ts +61 -14
- package/utils/svm/utils.ts +317 -14
- package/utils/test.ts +54 -18
- package/utils/types.ts +223 -2
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account Adapter
|
|
3
|
+
*
|
|
4
|
+
* Adapts ZeroDev's account objects to work with our service layer.
|
|
5
|
+
* Normalizes the interface to match KernelAccountInstance.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Chain, Hex } from 'viem';
|
|
9
|
+
import { entryPoint07Address } from 'viem/account-abstraction';
|
|
10
|
+
import { KernelAccountInstance } from './kernel-account';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Adapt a ZeroDev account to our KernelAccountInstance interface
|
|
14
|
+
*
|
|
15
|
+
* ZeroDev's createKernelAccount returns a different structure than what
|
|
16
|
+
* our service expects. This adapter normalizes it.
|
|
17
|
+
*
|
|
18
|
+
* @param account - The account from createKernelAccount
|
|
19
|
+
* @param chain - The chain the account is on
|
|
20
|
+
* @returns Normalized account that works with our service
|
|
21
|
+
*/
|
|
22
|
+
export function adaptZeroDevAccount(
|
|
23
|
+
account: any,
|
|
24
|
+
chain: Chain
|
|
25
|
+
): KernelAccountInstance {
|
|
26
|
+
return {
|
|
27
|
+
...account,
|
|
28
|
+
chain,
|
|
29
|
+
entryPoint: account.entryPoint || {
|
|
30
|
+
address: entryPoint07Address,
|
|
31
|
+
version: '0.7'
|
|
32
|
+
}
|
|
33
|
+
} as KernelAccountInstance;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Adapt a session key account specifically
|
|
38
|
+
*
|
|
39
|
+
* Session key accounts need special handling to ensure all properties
|
|
40
|
+
* are properly set for transaction execution.
|
|
41
|
+
*/
|
|
42
|
+
export function adaptSessionKeyAccount(
|
|
43
|
+
sessionKeyAccount: any,
|
|
44
|
+
masterAccount: KernelAccountInstance
|
|
45
|
+
): KernelAccountInstance {
|
|
46
|
+
// Ensure entryPoint is properly defined
|
|
47
|
+
const entryPoint = sessionKeyAccount.entryPoint || masterAccount.entryPoint || {
|
|
48
|
+
address: entryPoint07Address,
|
|
49
|
+
version: '0.7'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
...sessionKeyAccount,
|
|
54
|
+
chain: masterAccount.chain,
|
|
55
|
+
entryPoint: {
|
|
56
|
+
address: entryPoint.address || entryPoint07Address,
|
|
57
|
+
version: entryPoint.version || '0.7'
|
|
58
|
+
}
|
|
59
|
+
} as KernelAccountInstance;
|
|
60
|
+
}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel Account Factory
|
|
3
|
+
*
|
|
4
|
+
* Modular factory for creating Kernel smart accounts with EIP-7702.
|
|
5
|
+
* Supports multiple bundlers, chains, and EntryPoint versions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Chain, Hex, parseEther, PublicClient, SignAuthorizationReturnType, createPublicClient, http } from 'viem';
|
|
9
|
+
import { PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts';
|
|
10
|
+
import { createKernelAccount } from '@zerodev/sdk';
|
|
11
|
+
import { KERNEL_V3_3, KernelVersionToAddressesMap } from '@zerodev/sdk/constants';
|
|
12
|
+
import { entryPoint07Address, entryPoint08Address } from 'viem/account-abstraction';
|
|
13
|
+
import { BundlerManager, createBundlerService } from '../services/bundler';
|
|
14
|
+
import { BatchTransactionConfig, EntryPointVersion, KernelAccountConfig, KernelAccountInstance, KernelVersion, SingleTransactionConfig, Call } from './type';
|
|
15
|
+
|
|
16
|
+
// Re-export types so other files can import from this module
|
|
17
|
+
export type {
|
|
18
|
+
Call,
|
|
19
|
+
KernelAccountInstance,
|
|
20
|
+
EntryPointVersion,
|
|
21
|
+
KernelVersion,
|
|
22
|
+
KernelAccountConfig,
|
|
23
|
+
BatchTransactionConfig,
|
|
24
|
+
SingleTransactionConfig
|
|
25
|
+
} from './type';
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
// ============================================
|
|
30
|
+
// EntryPoint Mapping
|
|
31
|
+
// ============================================
|
|
32
|
+
|
|
33
|
+
const ENTRYPOINT_MAP: Record<EntryPointVersion, Hex> = {
|
|
34
|
+
'0.6': entryPoint07Address, // Fallback to 0.7 for 0.6 requests
|
|
35
|
+
'0.7': entryPoint07Address
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// ============================================
|
|
39
|
+
// Kernel Account Factory
|
|
40
|
+
// ============================================
|
|
41
|
+
|
|
42
|
+
export async function createKernel7702Account(
|
|
43
|
+
config: KernelAccountConfig
|
|
44
|
+
): Promise<KernelAccountInstance> {
|
|
45
|
+
const {
|
|
46
|
+
chain,
|
|
47
|
+
owner,
|
|
48
|
+
bundlerManager,
|
|
49
|
+
entryPointVersion = '0.7',
|
|
50
|
+
kernelVersion = '0.3.3'
|
|
51
|
+
} = config;
|
|
52
|
+
|
|
53
|
+
// Create public client for standard RPC calls
|
|
54
|
+
// (Bundler clients don't support standard eth_* methods)
|
|
55
|
+
const publicClient = createPublicClient({
|
|
56
|
+
chain,
|
|
57
|
+
transport: http()
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Get EntryPoint address
|
|
61
|
+
const entryPointAddress = ENTRYPOINT_MAP[entryPointVersion];
|
|
62
|
+
|
|
63
|
+
if (!entryPointAddress) {
|
|
64
|
+
throw new Error(`Unsupported EntryPoint version: ${entryPointVersion}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create Kernel account with EIP-7702
|
|
68
|
+
// Use public client for account creation (needs eth_call, eth_getCode, etc.)
|
|
69
|
+
const kernelAccount = await createKernelAccount(
|
|
70
|
+
publicClient as any,
|
|
71
|
+
{
|
|
72
|
+
entryPoint: {
|
|
73
|
+
address: entryPointAddress,
|
|
74
|
+
version: entryPointVersion
|
|
75
|
+
},
|
|
76
|
+
kernelVersion: KERNEL_V3_3,
|
|
77
|
+
eip7702Account: owner as any
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
account: kernelAccount,
|
|
83
|
+
address: kernelAccount.address,
|
|
84
|
+
owner,
|
|
85
|
+
chain,
|
|
86
|
+
entryPoint: {
|
|
87
|
+
address: entryPointAddress,
|
|
88
|
+
version: entryPointVersion
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============================================
|
|
94
|
+
// EIP-7702 Authorization Helper
|
|
95
|
+
// ============================================
|
|
96
|
+
|
|
97
|
+
export async function createKernelAuthorization(
|
|
98
|
+
config: {
|
|
99
|
+
owner: PrivateKeyAccount;
|
|
100
|
+
chain: Chain;
|
|
101
|
+
bundlerManager: BundlerManager;
|
|
102
|
+
kernelVersion?: KernelVersion;
|
|
103
|
+
}
|
|
104
|
+
): Promise<SignAuthorizationReturnType | undefined> {
|
|
105
|
+
const { owner, chain, bundlerManager, kernelVersion = '0.3.3' } = config;
|
|
106
|
+
|
|
107
|
+
const bundlerClient = bundlerManager.getClient(chain);
|
|
108
|
+
|
|
109
|
+
// Create public client for eth_getCode (bundler clients don't support it)
|
|
110
|
+
const publicClient = createPublicClient({
|
|
111
|
+
chain,
|
|
112
|
+
transport: http()
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Get Kernel implementation address
|
|
116
|
+
const delegateAddress = KernelVersionToAddressesMap[KERNEL_V3_3].accountImplementationAddress;
|
|
117
|
+
|
|
118
|
+
// Check if already delegated
|
|
119
|
+
const code = await publicClient.getCode({ address: owner.address });
|
|
120
|
+
const expectedCode = `0xef0100${delegateAddress.toLowerCase().substring(2)}`;
|
|
121
|
+
|
|
122
|
+
if (code === expectedCode) {
|
|
123
|
+
console.log('Already delegated to Kernel, no authorization needed');
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Create authorization
|
|
128
|
+
console.log('Creating EIP-7702 authorization for Kernel...');
|
|
129
|
+
|
|
130
|
+
// Get nonce for authorization
|
|
131
|
+
const nonce = await publicClient.getTransactionCount({
|
|
132
|
+
address: owner.address,
|
|
133
|
+
blockTag: 'pending'
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Sign authorization using the account's signAuthorization method
|
|
137
|
+
const authorization = await owner.signAuthorization({
|
|
138
|
+
contractAddress: delegateAddress,
|
|
139
|
+
chainId: chain.id,
|
|
140
|
+
nonce: nonce
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return authorization;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ============================================
|
|
147
|
+
// Transaction Helpers
|
|
148
|
+
// ============================================
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Send batch transaction (RECOMMENDED for smart accounts)
|
|
152
|
+
*
|
|
153
|
+
* Sends multiple calls in a single UserOperation, paying gas only once.
|
|
154
|
+
* This is one of the main benefits of smart accounts over EOAs.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* // Send ETH to 3 recipients in one transaction
|
|
158
|
+
* await sendBatchTransaction({
|
|
159
|
+
* kernelAccount: account,
|
|
160
|
+
* bundlerManager,
|
|
161
|
+
* calls: [
|
|
162
|
+
* { to: '0xRecipient1', value: parseEther('0.01') },
|
|
163
|
+
* { to: '0xRecipient2', value: parseEther('0.02') },
|
|
164
|
+
* { to: '0xRecipient3', value: parseEther('0.03') }
|
|
165
|
+
* ]
|
|
166
|
+
* });
|
|
167
|
+
*/
|
|
168
|
+
export async function sendBatchTransaction(config: BatchTransactionConfig): Promise<Hex> {
|
|
169
|
+
const {
|
|
170
|
+
kernelAccount,
|
|
171
|
+
bundlerManager,
|
|
172
|
+
authorization,
|
|
173
|
+
calls
|
|
174
|
+
} = config;
|
|
175
|
+
|
|
176
|
+
if (calls.length === 0) {
|
|
177
|
+
throw new Error('Batch transaction must have at least one call');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const bundlerClient = bundlerManager.getClient(kernelAccount.chain);
|
|
181
|
+
|
|
182
|
+
// Normalize calls to ensure value and data are set
|
|
183
|
+
const normalizedCalls = calls.map(call => ({
|
|
184
|
+
to: call.to,
|
|
185
|
+
value: call.value ?? 0n,
|
|
186
|
+
data: call.data ?? '0x' as Hex
|
|
187
|
+
}));
|
|
188
|
+
|
|
189
|
+
const userOpHash = await bundlerClient.sendUserOperation({
|
|
190
|
+
account: kernelAccount.account,
|
|
191
|
+
authorization,
|
|
192
|
+
calls: normalizedCalls
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return userOpHash as Hex;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Send single transaction (convenience wrapper around sendBatchTransaction)
|
|
200
|
+
*
|
|
201
|
+
* For single operations, you can use this instead of sendBatchTransaction.
|
|
202
|
+
* Under the hood, it creates a batch with one call.
|
|
203
|
+
*/
|
|
204
|
+
export async function sendKernelTransaction(config: SingleTransactionConfig): Promise<Hex> {
|
|
205
|
+
const {
|
|
206
|
+
kernelAccount,
|
|
207
|
+
bundlerManager,
|
|
208
|
+
authorization,
|
|
209
|
+
to,
|
|
210
|
+
value = 0n,
|
|
211
|
+
data = '0x'
|
|
212
|
+
} = config;
|
|
213
|
+
|
|
214
|
+
// Use batch transaction with single call
|
|
215
|
+
return sendBatchTransaction({
|
|
216
|
+
kernelAccount,
|
|
217
|
+
bundlerManager,
|
|
218
|
+
authorization,
|
|
219
|
+
calls: [{
|
|
220
|
+
to,
|
|
221
|
+
value,
|
|
222
|
+
data
|
|
223
|
+
}]
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ============================================
|
|
228
|
+
// Wait for Receipt Helper
|
|
229
|
+
// ============================================
|
|
230
|
+
|
|
231
|
+
export async function waitForKernelReceipt(config: {
|
|
232
|
+
userOpHash: Hex;
|
|
233
|
+
chain: Chain;
|
|
234
|
+
bundlerManager: BundlerManager;
|
|
235
|
+
}): Promise<any> {
|
|
236
|
+
const { userOpHash, chain, bundlerManager } = config;
|
|
237
|
+
|
|
238
|
+
const bundlerClient = bundlerManager.getClient(chain);
|
|
239
|
+
|
|
240
|
+
const receipt = await bundlerClient.waitForUserOperationReceipt({
|
|
241
|
+
hash: userOpHash
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return receipt;
|
|
245
|
+
}
|
|
246
|
+
|
|
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
|
+
}
|