@1llet.xyz/erc4337-gasless-sdk 0.4.70 → 0.4.72

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/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
- import { monad, unichain, arbitrum, polygon, bsc, avalanche, optimism, gnosis, baseSepolia, base, optimismSepolia, worldchain } from 'viem/chains';
1
+ import { parseAbi, createPublicClient, http, encodeFunctionData, createWalletClient, decodeErrorResult, getAddress, parseUnits, formatUnits, erc20Abi as erc20Abi$1, encodeAbiParameters, keccak256, maxUint256, padHex, toHex } from 'viem';
2
+ import { privateKeyToAccount } from 'viem/accounts';
3
+ import { monad, unichain, arbitrum, polygon, bsc, avalanche, optimism, gnosis, baseSepolia, base, optimismSepolia, mainnet, worldchain } from 'viem/chains';
2
4
  import * as StellarSdk from 'stellar-sdk';
3
5
  import { Networks } from 'stellar-sdk';
4
6
  import axios from 'axios';
5
- import { parseAbi, createPublicClient, http, encodeFunctionData, createWalletClient, decodeErrorResult, encodeAbiParameters, keccak256, maxUint256, padHex } from 'viem';
6
- import { privateKeyToAccount } from 'viem/accounts';
7
- import { OpenAPI, OneClickService, QuoteRequest } from '@defuse-protocol/one-click-sdk-typescript';
7
+ import { OpenAPI, QuoteRequest, OneClickService } from '@defuse-protocol/one-click-sdk-typescript';
8
8
 
9
9
  var __defProp = Object.defineProperty;
10
10
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -16,6 +16,858 @@ var __export = (target, all) => {
16
16
  __defProp(target, name, { get: all[name], enumerable: true });
17
17
  };
18
18
 
19
+ // src/constants.ts
20
+ var factoryAbi, entryPointAbi, smartAccountAbi, erc20Abi;
21
+ var init_constants = __esm({
22
+ "src/constants.ts"() {
23
+ factoryAbi = [
24
+ {
25
+ inputs: [
26
+ { name: "owner", type: "address" },
27
+ { name: "salt", type: "uint256" }
28
+ ],
29
+ name: "getAccountAddress",
30
+ outputs: [{ name: "", type: "address" }],
31
+ stateMutability: "view",
32
+ type: "function"
33
+ },
34
+ {
35
+ inputs: [
36
+ { name: "owner", type: "address" },
37
+ { name: "salt", type: "uint256" }
38
+ ],
39
+ name: "isAccountDeployed",
40
+ outputs: [{ name: "", type: "bool" }],
41
+ stateMutability: "view",
42
+ type: "function"
43
+ },
44
+ {
45
+ inputs: [
46
+ { name: "owner", type: "address" },
47
+ { name: "salt", type: "uint256" }
48
+ ],
49
+ name: "createAccount",
50
+ outputs: [{ name: "account", type: "address" }],
51
+ stateMutability: "nonpayable",
52
+ type: "function"
53
+ }
54
+ ];
55
+ entryPointAbi = [
56
+ {
57
+ inputs: [
58
+ { name: "sender", type: "address" },
59
+ { name: "key", type: "uint192" }
60
+ ],
61
+ name: "getNonce",
62
+ outputs: [{ name: "nonce", type: "uint256" }],
63
+ stateMutability: "view",
64
+ type: "function"
65
+ }
66
+ ];
67
+ smartAccountAbi = [
68
+ {
69
+ inputs: [
70
+ { name: "target", type: "address" },
71
+ { name: "value", type: "uint256" },
72
+ { name: "data", type: "bytes" }
73
+ ],
74
+ name: "execute",
75
+ outputs: [],
76
+ stateMutability: "nonpayable",
77
+ type: "function"
78
+ },
79
+ {
80
+ inputs: [
81
+ { name: "targets", type: "address[]" },
82
+ { name: "values", type: "uint256[]" },
83
+ { name: "datas", type: "bytes[]" }
84
+ ],
85
+ name: "executeBatch",
86
+ outputs: [],
87
+ stateMutability: "nonpayable",
88
+ type: "function"
89
+ }
90
+ ];
91
+ erc20Abi = [
92
+ {
93
+ inputs: [{ name: "account", type: "address" }],
94
+ name: "balanceOf",
95
+ outputs: [{ name: "", type: "uint256" }],
96
+ stateMutability: "view",
97
+ type: "function"
98
+ },
99
+ {
100
+ inputs: [
101
+ { name: "to", type: "address" },
102
+ { name: "amount", type: "uint256" }
103
+ ],
104
+ name: "transfer",
105
+ outputs: [{ name: "", type: "bool" }],
106
+ stateMutability: "nonpayable",
107
+ type: "function"
108
+ },
109
+ {
110
+ inputs: [
111
+ { name: "spender", type: "address" },
112
+ { name: "amount", type: "uint256" }
113
+ ],
114
+ name: "approve",
115
+ outputs: [{ name: "", type: "bool" }],
116
+ stateMutability: "nonpayable",
117
+ type: "function"
118
+ },
119
+ {
120
+ inputs: [
121
+ { name: "owner", type: "address" },
122
+ { name: "spender", type: "address" }
123
+ ],
124
+ name: "allowance",
125
+ outputs: [{ name: "", type: "uint256" }],
126
+ stateMutability: "view",
127
+ type: "function"
128
+ },
129
+ {
130
+ inputs: [
131
+ { name: "from", type: "address" },
132
+ { name: "to", type: "address" },
133
+ { name: "amount", type: "uint256" }
134
+ ],
135
+ name: "transferFrom",
136
+ outputs: [{ name: "", type: "bool" }],
137
+ stateMutability: "nonpayable",
138
+ type: "function"
139
+ },
140
+ {
141
+ inputs: [],
142
+ name: "decimals",
143
+ outputs: [{ name: "", type: "uint8" }],
144
+ stateMutability: "view",
145
+ type: "function"
146
+ }
147
+ ];
148
+ }
149
+ });
150
+
151
+ // src/BundlerClient.ts
152
+ var BundlerClient;
153
+ var init_BundlerClient = __esm({
154
+ "src/BundlerClient.ts"() {
155
+ BundlerClient = class {
156
+ constructor(config, entryPointAddress) {
157
+ this.bundlerUrl = config.bundlerUrl;
158
+ this.entryPointAddress = entryPointAddress;
159
+ }
160
+ async call(method, params) {
161
+ const response = await fetch(this.bundlerUrl, {
162
+ method: "POST",
163
+ headers: { "Content-Type": "application/json" },
164
+ body: JSON.stringify({
165
+ jsonrpc: "2.0",
166
+ id: 1,
167
+ method,
168
+ params
169
+ })
170
+ });
171
+ const result = await response.json();
172
+ if (result.error) {
173
+ throw new Error(result.error.message);
174
+ }
175
+ return result.result;
176
+ }
177
+ async estimateGas(userOp) {
178
+ const result = await this.call("eth_estimateUserOperationGas", [
179
+ {
180
+ sender: userOp.sender,
181
+ nonce: userOp.nonce ? "0x" + userOp.nonce.toString(16) : "0x0",
182
+ initCode: userOp.initCode || "0x",
183
+ callData: userOp.callData || "0x",
184
+ paymasterAndData: userOp.paymasterAndData || "0x",
185
+ signature: "0x"
186
+ },
187
+ this.entryPointAddress
188
+ ]);
189
+ console.log("DEBUG: estimateGas result:", result);
190
+ return {
191
+ callGasLimit: result.callGasLimit,
192
+ verificationGasLimit: result.verificationGasLimit,
193
+ preVerificationGas: result.preVerificationGas,
194
+ maxFeePerGas: result.maxFeePerGas,
195
+ maxPriorityFeePerGas: result.maxPriorityFeePerGas,
196
+ paymasterAndData: result.paymasterAndData
197
+ };
198
+ }
199
+ async sendUserOperation(userOp) {
200
+ return await this.call("eth_sendUserOperation", [
201
+ {
202
+ sender: userOp.sender,
203
+ nonce: "0x" + userOp.nonce.toString(16),
204
+ initCode: userOp.initCode,
205
+ callData: userOp.callData,
206
+ callGasLimit: "0x" + userOp.callGasLimit.toString(16),
207
+ verificationGasLimit: "0x" + userOp.verificationGasLimit.toString(16),
208
+ preVerificationGas: "0x" + userOp.preVerificationGas.toString(16),
209
+ maxFeePerGas: "0x" + userOp.maxFeePerGas.toString(16),
210
+ maxPriorityFeePerGas: "0x" + userOp.maxPriorityFeePerGas.toString(16),
211
+ paymasterAndData: userOp.paymasterAndData,
212
+ signature: userOp.signature
213
+ },
214
+ this.entryPointAddress
215
+ ]);
216
+ }
217
+ async waitForUserOperation(userOpHash, timeout = 6e4) {
218
+ const startTime = Date.now();
219
+ while (Date.now() - startTime < timeout) {
220
+ const result = await this.call("eth_getUserOperationReceipt", [userOpHash]);
221
+ if (result) {
222
+ return result;
223
+ }
224
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
225
+ }
226
+ throw new Error("Timeout waiting for UserOperation");
227
+ }
228
+ async requestApprovalSupport(token, owner, spender, amount) {
229
+ return await this.call("pm_requestApprovalSupport", [
230
+ token,
231
+ owner,
232
+ spender,
233
+ amount.toString()
234
+ ]);
235
+ }
236
+ async scheduleUserOp(userOp, condition) {
237
+ return await this.call("bundler_scheduleUserOp", [
238
+ {
239
+ sender: userOp.sender,
240
+ nonce: "0x" + userOp.nonce.toString(16),
241
+ initCode: userOp.initCode,
242
+ callData: userOp.callData,
243
+ callGasLimit: "0x" + userOp.callGasLimit.toString(16),
244
+ verificationGasLimit: "0x" + userOp.verificationGasLimit.toString(16),
245
+ preVerificationGas: "0x" + userOp.preVerificationGas.toString(16),
246
+ maxFeePerGas: "0x" + userOp.maxFeePerGas.toString(16),
247
+ maxPriorityFeePerGas: "0x" + userOp.maxPriorityFeePerGas.toString(16),
248
+ paymasterAndData: userOp.paymasterAndData,
249
+ signature: userOp.signature
250
+ },
251
+ condition
252
+ ]);
253
+ }
254
+ };
255
+ }
256
+ });
257
+ var TokenService;
258
+ var init_TokenService = __esm({
259
+ "src/TokenService.ts"() {
260
+ init_constants();
261
+ TokenService = class {
262
+ constructor(chainConfig, publicClient) {
263
+ this.tokens = /* @__PURE__ */ new Map();
264
+ this.publicClient = publicClient;
265
+ chainConfig.tokens.forEach((token) => {
266
+ this.tokens.set(token.symbol.toUpperCase(), token);
267
+ });
268
+ }
269
+ /**
270
+ * Resolve token address from symbol or return address if provided
271
+ */
272
+ getTokenAddress(token) {
273
+ if (token.startsWith("0x")) return token;
274
+ const info = this.tokens.get(token.toUpperCase());
275
+ if (!info) throw new Error(`Token ${token} not found in chain config`);
276
+ return info.address;
277
+ }
278
+ /**
279
+ * Get balance of a token for an account
280
+ */
281
+ async getBalance(token, account) {
282
+ const address = this.getTokenAddress(token);
283
+ if (address === "0x0000000000000000000000000000000000000000") {
284
+ return await this.publicClient.getBalance({ address: account });
285
+ }
286
+ return await this.publicClient.readContract({
287
+ address,
288
+ abi: erc20Abi,
289
+ functionName: "balanceOf",
290
+ args: [account]
291
+ });
292
+ }
293
+ /**
294
+ * Get allowance (ERC-20 only)
295
+ */
296
+ async getAllowance(token, owner, spender) {
297
+ const address = this.getTokenAddress(token);
298
+ if (address === "0x0000000000000000000000000000000000000000") {
299
+ return 0n;
300
+ }
301
+ return await this.publicClient.readContract({
302
+ address,
303
+ abi: erc20Abi,
304
+ functionName: "allowance",
305
+ args: [owner, spender]
306
+ });
307
+ }
308
+ /**
309
+ * Encode transfer data
310
+ */
311
+ encodeTransfer(recipient, amount) {
312
+ return encodeFunctionData({
313
+ abi: erc20Abi,
314
+ functionName: "transfer",
315
+ args: [recipient, amount]
316
+ });
317
+ }
318
+ /**
319
+ * Encode transferFrom data
320
+ */
321
+ encodeTransferFrom(sender, recipient, amount) {
322
+ return encodeFunctionData({
323
+ abi: erc20Abi,
324
+ functionName: "transferFrom",
325
+ args: [sender, recipient, amount]
326
+ });
327
+ }
328
+ /**
329
+ * Encode approve data
330
+ */
331
+ encodeApprove(spender, amount) {
332
+ return encodeFunctionData({
333
+ abi: erc20Abi,
334
+ functionName: "approve",
335
+ args: [spender, amount]
336
+ });
337
+ }
338
+ };
339
+ }
340
+ });
341
+ var UserOpBuilder;
342
+ var init_UserOpBuilder = __esm({
343
+ "src/UserOpBuilder.ts"() {
344
+ init_constants();
345
+ UserOpBuilder = class {
346
+ constructor(chainConfig, bundlerClient, publicClient) {
347
+ this.chainConfig = chainConfig;
348
+ this.bundlerClient = bundlerClient;
349
+ this.publicClient = publicClient;
350
+ this.entryPointAddress = chainConfig.entryPointAddress;
351
+ this.factoryAddress = chainConfig.factoryAddress;
352
+ }
353
+ async getNonce(smartAccountAddress) {
354
+ return await this.publicClient.readContract({
355
+ address: this.entryPointAddress,
356
+ abi: entryPointAbi,
357
+ functionName: "getNonce",
358
+ args: [smartAccountAddress, 0n]
359
+ });
360
+ }
361
+ buildInitCode(owner) {
362
+ const createAccountData = encodeFunctionData({
363
+ abi: factoryAbi,
364
+ functionName: "createAccount",
365
+ args: [owner, 0n]
366
+ });
367
+ return `${this.factoryAddress}${createAccountData.slice(2)}`;
368
+ }
369
+ async isAccountDeployed(smartAccountAddress) {
370
+ const code = await this.publicClient.getCode({
371
+ address: smartAccountAddress
372
+ });
373
+ return code !== void 0 && code !== "0x";
374
+ }
375
+ async buildUserOperationBatch(owner, smartAccountAddress, transactions) {
376
+ const isDeployed = await this.isAccountDeployed(smartAccountAddress);
377
+ const initCode = isDeployed ? "0x" : this.buildInitCode(owner);
378
+ const targets = transactions.map((tx) => tx.target);
379
+ const values = transactions.map((tx) => tx.value);
380
+ const datas = transactions.map((tx) => tx.data);
381
+ const callData = encodeFunctionData({
382
+ abi: smartAccountAbi,
383
+ functionName: "executeBatch",
384
+ args: [targets, values, datas]
385
+ });
386
+ const nonce = await this.getNonce(smartAccountAddress);
387
+ const partialOp = {
388
+ sender: smartAccountAddress,
389
+ nonce,
390
+ initCode,
391
+ callData,
392
+ paymasterAndData: this.chainConfig.paymasterAddress || "0x"
393
+ };
394
+ const gasEstimate = await this.bundlerClient.estimateGas(partialOp);
395
+ return {
396
+ ...partialOp,
397
+ callGasLimit: BigInt(gasEstimate.callGasLimit),
398
+ verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),
399
+ preVerificationGas: BigInt(gasEstimate.preVerificationGas),
400
+ maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
401
+ maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
402
+ paymasterAndData: gasEstimate.paymasterAndData || partialOp.paymasterAndData,
403
+ signature: "0x"
404
+ };
405
+ }
406
+ async buildDeployUserOp(owner, smartAccountAddress) {
407
+ const isDeployed = await this.isAccountDeployed(smartAccountAddress);
408
+ if (isDeployed) throw new Error("Account already deployed");
409
+ const initCode = this.buildInitCode(owner);
410
+ const callData = "0x";
411
+ const nonce = await this.getNonce(smartAccountAddress);
412
+ const partialOp = {
413
+ sender: smartAccountAddress,
414
+ nonce,
415
+ initCode,
416
+ callData,
417
+ paymasterAndData: this.chainConfig.paymasterAddress || "0x"
418
+ };
419
+ const gasEstimate = await this.bundlerClient.estimateGas(partialOp);
420
+ return {
421
+ ...partialOp,
422
+ callGasLimit: BigInt(gasEstimate.callGasLimit),
423
+ verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),
424
+ preVerificationGas: BigInt(gasEstimate.preVerificationGas),
425
+ maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
426
+ maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
427
+ paymasterAndData: gasEstimate.paymasterAndData || partialOp.paymasterAndData,
428
+ signature: "0x"
429
+ };
430
+ }
431
+ getUserOpHash(userOp) {
432
+ const packed = encodeAbiParameters(
433
+ [
434
+ { type: "address" },
435
+ { type: "uint256" },
436
+ { type: "bytes32" },
437
+ { type: "bytes32" },
438
+ { type: "uint256" },
439
+ { type: "uint256" },
440
+ { type: "uint256" },
441
+ { type: "uint256" },
442
+ { type: "uint256" },
443
+ { type: "bytes32" }
444
+ ],
445
+ [
446
+ userOp.sender,
447
+ userOp.nonce,
448
+ keccak256(userOp.initCode),
449
+ keccak256(userOp.callData),
450
+ userOp.callGasLimit,
451
+ userOp.verificationGasLimit,
452
+ userOp.preVerificationGas,
453
+ userOp.maxFeePerGas,
454
+ userOp.maxPriorityFeePerGas,
455
+ keccak256(userOp.paymasterAndData)
456
+ ]
457
+ );
458
+ const packedHash = keccak256(packed);
459
+ return keccak256(
460
+ encodeAbiParameters(
461
+ [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
462
+ [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]
463
+ )
464
+ );
465
+ }
466
+ };
467
+ }
468
+ });
469
+ var AccountAbstraction;
470
+ var init_AccountAbstraction = __esm({
471
+ "src/AccountAbstraction.ts"() {
472
+ init_constants();
473
+ init_BundlerClient();
474
+ init_TokenService();
475
+ init_UserOpBuilder();
476
+ AccountAbstraction = class {
477
+ constructor(chainConfig) {
478
+ this.owner = null;
479
+ this.smartAccountAddress = null;
480
+ this.walletClient = null;
481
+ this.chainConfig = chainConfig;
482
+ if (!chainConfig.entryPointAddress) throw new Error("EntryPoint address required");
483
+ this.entryPointAddress = chainConfig.entryPointAddress;
484
+ if (!chainConfig.factoryAddress) throw new Error("Factory address required");
485
+ this.factoryAddress = chainConfig.factoryAddress;
486
+ const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];
487
+ this.publicClient = createPublicClient({
488
+ chain: chainConfig.chain,
489
+ transport: http(rpcUrl)
490
+ });
491
+ this.bundlerClient = new BundlerClient(chainConfig, this.entryPointAddress);
492
+ this.tokenService = new TokenService(chainConfig, this.publicClient);
493
+ this.userOpBuilder = new UserOpBuilder(chainConfig, this.bundlerClient, this.publicClient);
494
+ }
495
+ getBundlerClient() {
496
+ return this.bundlerClient;
497
+ }
498
+ getChainId() {
499
+ return this.chainConfig.chain.id;
500
+ }
501
+ getPublicClient() {
502
+ return this.publicClient;
503
+ }
504
+ async buildUserOperation(transaction) {
505
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
506
+ return this.userOpBuilder.buildUserOperationBatch(this.owner, this.smartAccountAddress, [transaction]);
507
+ }
508
+ async buildBatchUserOperation(transactions) {
509
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
510
+ return this.userOpBuilder.buildUserOperationBatch(this.owner, this.smartAccountAddress, transactions);
511
+ }
512
+ async connect(signer) {
513
+ if (typeof signer === "string") {
514
+ const account = privateKeyToAccount(signer);
515
+ this.owner = account.address;
516
+ const rpcUrl = this.chainConfig.rpcUrl || this.chainConfig.chain.rpcUrls.default.http[0];
517
+ this.walletClient = createWalletClient({
518
+ account,
519
+ chain: this.chainConfig.chain,
520
+ transport: http(rpcUrl)
521
+ });
522
+ } else if (signer && typeof signer === "object") {
523
+ this.walletClient = signer;
524
+ if (!this.walletClient.account) throw new Error("WalletClient must have an account");
525
+ this.owner = this.walletClient.account.address;
526
+ } else {
527
+ if (typeof window === "undefined" || !window.ethereum) {
528
+ throw new Error("MetaMask is not installed and no private key provided");
529
+ }
530
+ const accounts = await window.ethereum.request({
531
+ method: "eth_requestAccounts"
532
+ });
533
+ if (!accounts || accounts.length === 0) throw new Error("No accounts found");
534
+ const chainId = await window.ethereum.request({
535
+ method: "eth_chainId"
536
+ });
537
+ const targetChainId = this.chainConfig.chain.id;
538
+ if (parseInt(chainId, 16) !== targetChainId) {
539
+ try {
540
+ await window.ethereum.request({
541
+ method: "wallet_switchEthereumChain",
542
+ params: [{ chainId: "0x" + targetChainId.toString(16) }]
543
+ });
544
+ } catch (switchError) {
545
+ const error = switchError;
546
+ if (error.code === 4902) {
547
+ await window.ethereum.request({
548
+ method: "wallet_addEthereumChain",
549
+ params: [
550
+ {
551
+ chainId: "0x" + targetChainId.toString(16),
552
+ chainName: this.chainConfig.chain.name,
553
+ nativeCurrency: this.chainConfig.chain.nativeCurrency,
554
+ rpcUrls: [this.chainConfig.rpcUrl || this.chainConfig.chain.rpcUrls.default.http[0]],
555
+ blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url ? [this.chainConfig.chain.blockExplorers.default.url] : []
556
+ }
557
+ ]
558
+ });
559
+ } else {
560
+ throw switchError;
561
+ }
562
+ }
563
+ }
564
+ this.owner = accounts[0];
565
+ }
566
+ this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);
567
+ return {
568
+ owner: this.owner,
569
+ smartAccount: this.smartAccountAddress
570
+ };
571
+ }
572
+ // --- Account Management ---
573
+ async isAccountDeployed() {
574
+ if (!this.smartAccountAddress) return false;
575
+ const code = await this.publicClient.getBytecode({ address: this.smartAccountAddress });
576
+ return code !== void 0;
577
+ }
578
+ async deployAccount() {
579
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
580
+ return this.sendTransaction({
581
+ target: this.smartAccountAddress,
582
+ value: 0n,
583
+ data: "0x"
584
+ });
585
+ }
586
+ /**
587
+ * Get the Smart Account address for an owner
588
+ */
589
+ async getSmartAccountAddress(owner) {
590
+ try {
591
+ const address = await this.publicClient.readContract({
592
+ address: this.factoryAddress,
593
+ abi: factoryAbi,
594
+ functionName: "getAccountAddress",
595
+ args: [owner, 0n]
596
+ });
597
+ return address;
598
+ } catch (e) {
599
+ try {
600
+ const { result } = await this.publicClient.simulateContract({
601
+ address: this.factoryAddress,
602
+ abi: factoryAbi,
603
+ functionName: "createAccount",
604
+ args: [owner, 0n],
605
+ account: "0x0000000000000000000000000000000000000000"
606
+ // Zero address or random for simulation
607
+ });
608
+ return result;
609
+ } catch (inner) {
610
+ throw e;
611
+ }
612
+ }
613
+ }
614
+ // --- Token Methods (Delegated) ---
615
+ getTokenAddress(token) {
616
+ return this.tokenService.getTokenAddress(token);
617
+ }
618
+ async getBalance(token) {
619
+ if (!this.smartAccountAddress) throw new Error("Not connected");
620
+ return this.tokenService.getBalance(token, this.smartAccountAddress);
621
+ }
622
+ async getEoaBalance(token) {
623
+ if (!this.owner) throw new Error("Not connected");
624
+ return this.tokenService.getBalance(token, this.owner);
625
+ }
626
+ async getAllowance(token = "USDC") {
627
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
628
+ return this.tokenService.getAllowance(token, this.owner, this.smartAccountAddress);
629
+ }
630
+ /**
631
+ * Get comprehensive state of the account for a specific token
632
+ * Useful for UI initialization
633
+ */
634
+ async getAccountState(token) {
635
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
636
+ const tokenAddress = this.getTokenAddress(token);
637
+ const isNative = tokenAddress === "0x0000000000000000000000000000000000000000";
638
+ const [balance, eoaBalance, allowance, isDeployed] = await Promise.all([
639
+ this.getBalance(token),
640
+ this.getEoaBalance(token),
641
+ isNative ? 0n : this.getAllowance(token).catch(() => 0n),
642
+ // Handle native/error gracefully
643
+ this.isAccountDeployed()
644
+ ]);
645
+ return {
646
+ owner: this.owner,
647
+ smartAccount: this.smartAccountAddress,
648
+ balance,
649
+ eoaBalance,
650
+ allowance,
651
+ isDeployed
652
+ };
653
+ }
654
+ // --- Transactions ---
655
+ async sendTransaction(tx) {
656
+ return this.sendBatchTransaction([tx]);
657
+ }
658
+ async sendBatchTransaction(txs) {
659
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
660
+ const transactions = txs.map((tx) => ({
661
+ target: tx.target,
662
+ value: tx.value ?? 0n,
663
+ data: tx.data ?? "0x"
664
+ }));
665
+ try {
666
+ const userOp = await this.userOpBuilder.buildUserOperationBatch(
667
+ this.owner,
668
+ this.smartAccountAddress,
669
+ transactions
670
+ );
671
+ const signed = await this.signUserOperation(userOp);
672
+ const hash = await this.sendUserOperation(signed);
673
+ return await this.waitForUserOperation(hash);
674
+ } catch (error) {
675
+ throw this.decodeError(error);
676
+ }
677
+ }
678
+ async deposit(amount) {
679
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
680
+ if (this.walletClient) {
681
+ return await this.walletClient.sendTransaction({
682
+ account: this.walletClient.account,
683
+ to: this.smartAccountAddress,
684
+ value: amount,
685
+ chain: this.chainConfig.chain
686
+ });
687
+ }
688
+ return await window.ethereum.request({
689
+ method: "eth_sendTransaction",
690
+ params: [{
691
+ from: this.owner,
692
+ to: this.smartAccountAddress,
693
+ value: "0x" + amount.toString(16)
694
+ }]
695
+ });
696
+ }
697
+ /**
698
+ * Smart Transfer: Automatically chooses best method (SA vs EOA) based on balances.
699
+ * Supports strict fee handling.
700
+ */
701
+ async smartTransfer(token, recipient, amount, fee) {
702
+ if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
703
+ const tokenAddress = this.getTokenAddress(token);
704
+ const isNative = tokenAddress === "0x0000000000000000000000000000000000000000";
705
+ const [saBal, eoaBal, allowance] = await Promise.all([
706
+ this.getBalance(token),
707
+ this.getEoaBalance(token),
708
+ isNative ? 0n : this.getAllowance(token).catch(() => 0n)
709
+ ]);
710
+ const totalNeeded = amount + (fee?.amount || 0n);
711
+ if (saBal >= totalNeeded) {
712
+ const txs = [];
713
+ if (isNative) {
714
+ txs.push({ target: recipient, value: amount, data: "0x" });
715
+ } else {
716
+ txs.push({ target: tokenAddress, value: 0n, data: this.tokenService.encodeTransfer(recipient, amount) });
717
+ }
718
+ if (fee && fee.amount > 0n) {
719
+ if (isNative) {
720
+ txs.push({ target: fee.recipient, value: fee.amount, data: "0x" });
721
+ } else {
722
+ txs.push({ target: tokenAddress, value: 0n, data: this.tokenService.encodeTransfer(fee.recipient, fee.amount) });
723
+ }
724
+ }
725
+ console.log("SmartTransfer: Using Smart Account");
726
+ return this.sendBatchTransaction(txs);
727
+ }
728
+ if (eoaBal >= totalNeeded) {
729
+ if (isNative) {
730
+ console.log("SmartTransfer: Using EOA (Native)");
731
+ if (this.walletClient) {
732
+ const hash2 = await this.walletClient.sendTransaction({
733
+ account: this.walletClient.account,
734
+ to: recipient,
735
+ value: amount,
736
+ chain: this.chainConfig.chain
737
+ });
738
+ return { receipt: { transactionHash: hash2 } };
739
+ }
740
+ const hash = await window.ethereum.request({
741
+ method: "eth_sendTransaction",
742
+ params: [{ from: this.owner, to: recipient, value: "0x" + amount.toString(16) }]
743
+ });
744
+ return { receipt: { transactionHash: hash } };
745
+ } else {
746
+ console.log("SmartTransfer: Using EOA (Pull)");
747
+ if (allowance < totalNeeded) {
748
+ throw new Error(`Approval required. Please approve ${token} usage.`);
749
+ }
750
+ const txs = [];
751
+ txs.push({
752
+ target: tokenAddress,
753
+ value: 0n,
754
+ data: this.tokenService.encodeTransferFrom(this.owner, recipient, amount)
755
+ });
756
+ if (fee && fee.amount > 0n) {
757
+ txs.push({
758
+ target: tokenAddress,
759
+ value: 0n,
760
+ data: this.tokenService.encodeTransferFrom(this.owner, fee.recipient, fee.amount)
761
+ });
762
+ }
763
+ return this.sendBatchTransaction(txs);
764
+ }
765
+ }
766
+ throw new Error(`Insufficient funds.`);
767
+ }
768
+ async transfer(token, recipient, amount) {
769
+ const tokenAddress = this.getTokenAddress(token);
770
+ if (tokenAddress === "0x0000000000000000000000000000000000000000") {
771
+ return this.sendTransaction({
772
+ target: recipient,
773
+ value: amount,
774
+ data: "0x"
775
+ });
776
+ }
777
+ const data = this.tokenService.encodeTransfer(recipient, amount);
778
+ return this.sendTransaction({
779
+ target: tokenAddress,
780
+ value: 0n,
781
+ data
782
+ });
783
+ }
784
+ /**
785
+ * Approve a token for the Smart Account
786
+ */
787
+ async approveToken(token, spender, amount = 115792089237316195423570985008687907853269984665640564039457584007913129639935n) {
788
+ if (!this.owner) throw new Error("Not connected");
789
+ const support = await this.requestApprovalSupport(token, spender, amount);
790
+ if (support.type === "approve") {
791
+ const data = this.tokenService.encodeApprove(spender, amount);
792
+ if (this.walletClient) {
793
+ return await this.walletClient.sendTransaction({
794
+ account: this.walletClient.account,
795
+ to: token,
796
+ data,
797
+ chain: this.chainConfig.chain
798
+ });
799
+ }
800
+ return await window.ethereum.request({
801
+ method: "eth_sendTransaction",
802
+ params: [{
803
+ from: this.owner,
804
+ to: token,
805
+ data
806
+ }]
807
+ });
808
+ }
809
+ if (support.type === "permit") throw new Error("Permit not yet supported");
810
+ return "NOT_NEEDED";
811
+ }
812
+ // --- Core Bridge to Bundler/UserOp ---
813
+ async signUserOperation(userOp) {
814
+ if (!this.owner) throw new Error("Not connected");
815
+ const userOpHash = this.userOpBuilder.getUserOpHash(userOp);
816
+ let signature;
817
+ if (this.walletClient) {
818
+ signature = await this.walletClient.signMessage({
819
+ account: this.walletClient.account,
820
+ message: { raw: userOpHash }
821
+ // Sign hash directly
822
+ });
823
+ } else {
824
+ signature = await window.ethereum.request({
825
+ method: "personal_sign",
826
+ params: [userOpHash, this.owner]
827
+ });
828
+ }
829
+ return { ...userOp, signature };
830
+ }
831
+ async sendUserOperation(userOp) {
832
+ return this.bundlerClient.sendUserOperation(userOp);
833
+ }
834
+ async waitForUserOperation(hash, timeout = 6e4) {
835
+ return this.bundlerClient.waitForUserOperation(hash, timeout);
836
+ }
837
+ // Internal but exposed via BundlerClient originally
838
+ async requestApprovalSupport(token, spender, amount) {
839
+ if (!this.owner) throw new Error("Not connected");
840
+ return this.bundlerClient.requestApprovalSupport(token, this.owner, spender, amount);
841
+ }
842
+ // Error Decoding (Private)
843
+ decodeError(error) {
844
+ const msg = error?.message || "";
845
+ const hexMatch = msg.match(/(0x[0-9a-fA-F]+)/);
846
+ if (hexMatch) {
847
+ try {
848
+ const decoded = decodeErrorResult({
849
+ abi: [{ inputs: [{ name: "message", type: "string" }], name: "Error", type: "error" }],
850
+ data: hexMatch[0]
851
+ });
852
+ if (decoded.errorName === "Error") return new Error(`Smart Account Error: ${decoded.args[0]}`);
853
+ } catch (e) {
854
+ }
855
+ }
856
+ if (msg.includes("AA21")) return new Error("Smart Account: Native transfer failed (ETH missing?)");
857
+ if (msg.includes("AA25")) return new Error("Smart Account: Invalid account nonce");
858
+ return error instanceof Error ? error : new Error(String(error));
859
+ }
860
+ // Getters
861
+ getOwner() {
862
+ return this.owner;
863
+ }
864
+ getSmartAccount() {
865
+ return this.smartAccountAddress;
866
+ }
867
+ };
868
+ }
869
+ });
870
+
19
871
  // src/constants/bundler.ts
20
872
  var DEFAULT_BUNDLER_URL, BUNDLER_URL;
21
873
  var init_bundler = __esm({
@@ -48,7 +900,7 @@ var init_Base = __esm({
48
900
  chain: base,
49
901
  rpcUrl: "https://base-mainnet.g.alchemy.com/v2/49fUGmuW05ynCui0VEvDN",
50
902
  supports7702: true,
51
- erc4337: false,
903
+ erc4337: true,
52
904
  bundlerUrl: `${BUNDLER_URL}/rpc?chain=base`,
53
905
  entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
54
906
  factoryAddress: "0xe2584152891E4769025807DEa0cD611F135aDC68",
@@ -86,103 +938,74 @@ var init_Base = __esm({
86
938
  };
87
939
  }
88
940
  });
89
- var GNOSIS;
90
- var init_Gnosis = __esm({
91
- "src/chains/Evm/Gnosis.ts"() {
941
+ var AVALANCHE;
942
+ var init_Avalanche = __esm({
943
+ "src/chains/Evm/Avalanche.ts"() {
92
944
  init_bundler();
93
- GNOSIS = {
945
+ AVALANCHE = {
94
946
  assets: [
95
947
  {
96
948
  name: "USDC",
97
949
  decimals: 6,
98
- address: "0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0",
99
- coingeckoId: "usd-coin"
100
- },
101
- {
102
- name: "USDT",
103
- decimals: 6,
104
- address: "0x4ECaBa5870353805a9F068101A40E0f32ed605C6",
105
- coingeckoId: "tether"
106
- },
107
- {
108
- name: "EURe",
109
- decimals: 18,
110
- address: "0x420CA0f9B9b604cE0fd9C18EF134C705e5Fa3430",
111
- coingeckoId: "monerium-eur-money"
112
- },
113
- {
114
- name: "GNO",
115
- decimals: 18,
116
- address: "0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb",
117
- coingeckoId: "gnosis"
950
+ address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
951
+ coingeckoId: "usd-coin",
952
+ supportsStargate: true
118
953
  },
119
954
  {
120
- name: "WETH",
955
+ name: "AVAX",
121
956
  decimals: 18,
122
- address: "0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1",
123
- coingeckoId: "ethereum"
957
+ address: "0x0000000000000000000000000000000000000000",
958
+ coingeckoId: "avalanche-2"
124
959
  },
125
960
  {
126
- name: "XDAI",
127
- decimals: 18,
128
- address: "0x0000000000000000000000000000000000000000",
129
- coingeckoId: "xdai"
961
+ name: "USDT",
962
+ decimals: 6,
963
+ address: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7",
964
+ coingeckoId: "tether"
130
965
  }
131
966
  ],
132
967
  evm: {
133
- chain: gnosis,
134
- rpcUrl: gnosis.rpcUrls.default.http[0],
135
- supports7702: true,
136
- erc4337: true,
137
- bundlerUrl: `${BUNDLER_URL}/rpc?chain=gnosis`,
968
+ chain: avalanche,
969
+ rpcUrl: avalanche.rpcUrls.default.http[0],
970
+ supports7702: false,
971
+ bundlerUrl: `${BUNDLER_URL}/rpc?chain=avalanche`,
972
+ erc4337: false,
138
973
  entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
139
- factoryAddress: "0xC8a2Fb1f2E686417A131E09be3320cb5431CcD90",
140
- paymasterAddress: "0x4C36C70d68a7c26326711e8268bb163E3784fA96"
974
+ factoryAddress: "0x5D1D71FE2De5D1C52c7c11311332eC7f0CBf88aF",
975
+ paymasterAddress: "0x6c0de464F2203FE089FF719Acf425dFfE6ac1EE5"
141
976
  },
142
977
  crossChainInformation: {
143
978
  circleInformation: {
144
- supportCirclePaymaster: false,
145
- aproxFromFee: 0,
979
+ supportCirclePaymaster: true,
146
980
  cCTPInformation: {
147
- supportCCTP: false,
148
- domain: 0
149
- }
981
+ supportCCTP: true,
982
+ domain: 1
983
+ },
984
+ aproxFromFee: 0
150
985
  },
151
986
  nearIntentInformation: {
152
987
  support: true,
153
988
  assetsId: [
154
989
  {
155
- assetId: "nep141:gnosis-0x2a22f9c3b484c3629090feed35f17ff8f88f76f0.omft.near",
990
+ assetId: "nep245:v2_1.omni.hot.tg:43114_3atVJH3r5c4GqiSYmg9fECvjc47o",
156
991
  name: "USDC",
157
992
  decimals: 6
158
993
  },
159
994
  {
160
- assetId: "nep141:gnosis-0x4ecaba5870353805a9f068101a40e0f32ed605c6.omft.near",
161
- name: "USDT",
162
- decimals: 6
163
- },
164
- {
165
- assetId: "nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near",
166
- name: "EURe",
167
- decimals: 18
168
- },
169
- {
170
- assetId: "nep141:gnosis-0x9c58bacc331c9aa871afd802db6379a98e80cedb.omft.near",
171
- name: "GNO",
172
- decimals: 18
173
- },
174
- {
175
- assetId: "nep141:gnosis-0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1.omft.near",
176
- name: "WETH",
995
+ assetId: "nep245:v2_1.omni.hot.tg:43114_11111111111111111111",
996
+ name: "AVAX",
177
997
  decimals: 18
178
998
  },
179
999
  {
180
- assetId: "nep141:gnosis.omft.near",
181
- name: "XDAI",
182
- decimals: 18
1000
+ assetId: "nep245:v2_1.omni.hot.tg:43114_372BeH7ENZieCaabwkbWkBiTTgXp",
1001
+ name: "USDT",
1002
+ decimals: 6
183
1003
  }
184
1004
  ],
185
1005
  needMemo: false
1006
+ },
1007
+ stargateInformation: {
1008
+ support: true
186
1009
  }
187
1010
  }
188
1011
  };
@@ -221,7 +1044,7 @@ var init_Optimism = __esm({
221
1044
  ],
222
1045
  evm: {
223
1046
  chain: optimism,
224
- rpcUrl: "https://opt-mainnet.g.alchemy.com/v2/49fUGmuW05ynCui0VEvDN",
1047
+ rpcUrl: "https://mainnet.optimism.io",
225
1048
  supports7702: false,
226
1049
  erc4337: false,
227
1050
  bundlerUrl: `${BUNDLER_URL}/rpc?chain=optimism`,
@@ -268,74 +1091,103 @@ var init_Optimism = __esm({
268
1091
  };
269
1092
  }
270
1093
  });
271
- var AVALANCHE;
272
- var init_Avalanche = __esm({
273
- "src/chains/Evm/Avalanche.ts"() {
1094
+ var GNOSIS;
1095
+ var init_Gnosis = __esm({
1096
+ "src/chains/Evm/Gnosis.ts"() {
274
1097
  init_bundler();
275
- AVALANCHE = {
1098
+ GNOSIS = {
276
1099
  assets: [
277
1100
  {
278
1101
  name: "USDC",
279
1102
  decimals: 6,
280
- address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
281
- coingeckoId: "usd-coin",
282
- supportsStargate: true
283
- },
284
- {
285
- name: "AVAX",
286
- decimals: 18,
287
- address: "0x0000000000000000000000000000000000000000",
288
- coingeckoId: "avalanche-2"
1103
+ address: "0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0",
1104
+ coingeckoId: "usd-coin"
289
1105
  },
290
1106
  {
291
1107
  name: "USDT",
292
1108
  decimals: 6,
293
- address: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7",
1109
+ address: "0x4ECaBa5870353805a9F068101A40E0f32ed605C6",
294
1110
  coingeckoId: "tether"
1111
+ },
1112
+ {
1113
+ name: "EURe",
1114
+ decimals: 18,
1115
+ address: "0x420CA0f9B9b604cE0fd9C18EF134C705e5Fa3430",
1116
+ coingeckoId: "monerium-eur-money"
1117
+ },
1118
+ {
1119
+ name: "GNO",
1120
+ decimals: 18,
1121
+ address: "0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb",
1122
+ coingeckoId: "gnosis"
1123
+ },
1124
+ {
1125
+ name: "WETH",
1126
+ decimals: 18,
1127
+ address: "0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1",
1128
+ coingeckoId: "ethereum"
1129
+ },
1130
+ {
1131
+ name: "XDAI",
1132
+ decimals: 18,
1133
+ address: "0x0000000000000000000000000000000000000000",
1134
+ coingeckoId: "xdai"
295
1135
  }
296
1136
  ],
297
1137
  evm: {
298
- chain: avalanche,
299
- rpcUrl: avalanche.rpcUrls.default.http[0],
300
- supports7702: false,
301
- bundlerUrl: `${BUNDLER_URL}/rpc?chain=avalanche`,
302
- erc4337: false,
1138
+ chain: gnosis,
1139
+ rpcUrl: gnosis.rpcUrls.default.http[0],
1140
+ supports7702: true,
1141
+ erc4337: true,
1142
+ bundlerUrl: `${BUNDLER_URL}/rpc?chain=gnosis`,
303
1143
  entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
304
- factoryAddress: "0x5D1D71FE2De5D1C52c7c11311332eC7f0CBf88aF",
305
- paymasterAddress: "0x6c0de464F2203FE089FF719Acf425dFfE6ac1EE5"
1144
+ factoryAddress: "0xC8a2Fb1f2E686417A131E09be3320cb5431CcD90",
1145
+ paymasterAddress: "0x4C36C70d68a7c26326711e8268bb163E3784fA96"
306
1146
  },
307
1147
  crossChainInformation: {
308
1148
  circleInformation: {
309
- supportCirclePaymaster: true,
1149
+ supportCirclePaymaster: false,
1150
+ aproxFromFee: 0,
310
1151
  cCTPInformation: {
311
- supportCCTP: true,
312
- domain: 1
313
- },
314
- aproxFromFee: 0
1152
+ supportCCTP: false,
1153
+ domain: 0
1154
+ }
315
1155
  },
316
1156
  nearIntentInformation: {
317
1157
  support: true,
318
1158
  assetsId: [
319
1159
  {
320
- assetId: "nep245:v2_1.omni.hot.tg:43114_3atVJH3r5c4GqiSYmg9fECvjc47o",
1160
+ assetId: "nep141:gnosis-0x2a22f9c3b484c3629090feed35f17ff8f88f76f0.omft.near",
321
1161
  name: "USDC",
322
1162
  decimals: 6
323
1163
  },
324
1164
  {
325
- assetId: "nep245:v2_1.omni.hot.tg:43114_11111111111111111111",
326
- name: "AVAX",
1165
+ assetId: "nep141:gnosis-0x4ecaba5870353805a9f068101a40e0f32ed605c6.omft.near",
1166
+ name: "USDT",
1167
+ decimals: 6
1168
+ },
1169
+ {
1170
+ assetId: "nep141:gnosis-0x420ca0f9b9b604ce0fd9c18ef134c705e5fa3430.omft.near",
1171
+ name: "EURe",
327
1172
  decimals: 18
328
1173
  },
329
1174
  {
330
- assetId: "nep245:v2_1.omni.hot.tg:43114_372BeH7ENZieCaabwkbWkBiTTgXp",
331
- name: "USDT",
332
- decimals: 6
1175
+ assetId: "nep141:gnosis-0x9c58bacc331c9aa871afd802db6379a98e80cedb.omft.near",
1176
+ name: "GNO",
1177
+ decimals: 18
1178
+ },
1179
+ {
1180
+ assetId: "nep141:gnosis-0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1.omft.near",
1181
+ name: "WETH",
1182
+ decimals: 18
1183
+ },
1184
+ {
1185
+ assetId: "nep141:gnosis.omft.near",
1186
+ name: "XDAI",
1187
+ decimals: 18
333
1188
  }
334
1189
  ],
335
1190
  needMemo: false
336
- },
337
- stargateInformation: {
338
- support: true
339
1191
  }
340
1192
  }
341
1193
  };
@@ -835,6 +1687,17 @@ var init_facilitator = __esm({
835
1687
  return isDev ? PlatformFees.DEV : PlatformFees.DEFAULT;
836
1688
  };
837
1689
  FACILITATOR_NETWORKS = {
1690
+ Ethereum: {
1691
+ chainId: mainnet.id,
1692
+ chain: mainnet,
1693
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
1694
+ usdcName: "USD Coin",
1695
+ usdcVersion: "2",
1696
+ domain: 0,
1697
+ tokenMessenger: "0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d",
1698
+ messageTransmitter: "0x81D40F21F12A8F0E3252Bccb954D722d4c464B64",
1699
+ rpcUrl: mainnet.rpcUrls.default.http[0]
1700
+ },
838
1701
  Base: {
839
1702
  chainId: 8453,
840
1703
  chain: base,
@@ -1103,6 +1966,68 @@ var init_WorldChain = __esm({
1103
1966
  };
1104
1967
  }
1105
1968
  });
1969
+ var ETHEREUM;
1970
+ var init_Ethereum = __esm({
1971
+ "src/chains/Evm/Ethereum.ts"() {
1972
+ init_bundler();
1973
+ ETHEREUM = {
1974
+ assets: [
1975
+ {
1976
+ name: "USDC",
1977
+ decimals: 6,
1978
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
1979
+ coingeckoId: "usd-coin",
1980
+ supportsStargate: true
1981
+ },
1982
+ {
1983
+ name: "ETH",
1984
+ decimals: 18,
1985
+ address: "0x0000000000000000000000000000000000000000",
1986
+ coingeckoId: "ethereum"
1987
+ }
1988
+ ],
1989
+ evm: {
1990
+ chain: mainnet,
1991
+ rpcUrl: mainnet.rpcUrls.default.http[0],
1992
+ supports7702: true,
1993
+ erc4337: true,
1994
+ bundlerUrl: `${BUNDLER_URL}/rpc?chain=ethereum`,
1995
+ entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
1996
+ factoryAddress: "0xe2584152891E4769025807DEa0cD611F135aDC68",
1997
+ paymasterAddress: "0x1e13Eb16C565E3f3FDe49A011755e50410bb1F95"
1998
+ },
1999
+ crossChainInformation: {
2000
+ circleInformation: {
2001
+ supportCirclePaymaster: true,
2002
+ cCTPInformation: {
2003
+ supportCCTP: true,
2004
+ domain: 0
2005
+ },
2006
+ aproxFromFee: 0
2007
+ },
2008
+ nearIntentInformation: {
2009
+ support: true,
2010
+ assetsId: [
2011
+ {
2012
+ assetId: "nep141:eth-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.omft.near",
2013
+ name: "USDC",
2014
+ decimals: 6
2015
+ },
2016
+ {
2017
+ assetId: "nep141:eth.omft.near",
2018
+ name: "ETH",
2019
+ decimals: 18
2020
+ }
2021
+ ],
2022
+ needMemo: false
2023
+ },
2024
+ stargateInformation: {
2025
+ support: false
2026
+ }
2027
+ }
2028
+ };
2029
+ }
2030
+ });
1106
2031
 
1107
2032
  // src/chains/index.ts
1108
2033
  var init_chains = __esm({
@@ -1118,6 +2043,7 @@ var init_chains = __esm({
1118
2043
  init_Monad();
1119
2044
  init_Binance();
1120
2045
  init_Gnosis();
2046
+ init_Ethereum();
1121
2047
  }
1122
2048
  });
1123
2049
 
@@ -1137,7 +2063,8 @@ var init_chainsInformation = __esm({
1137
2063
  Stellar: STELLAR,
1138
2064
  Monad,
1139
2065
  BNB,
1140
- Gnosis: GNOSIS
2066
+ Gnosis: GNOSIS,
2067
+ Ethereum: ETHEREUM
1141
2068
  };
1142
2069
  }
1143
2070
  });
@@ -1447,6 +2374,14 @@ var init_cctp2 = __esm({
1447
2374
  };
1448
2375
  }
1449
2376
  });
2377
+
2378
+ // src/services/near.ts
2379
+ var near_exports = {};
2380
+ __export(near_exports, {
2381
+ NearStrategy: () => NearStrategy,
2382
+ getNearQuote: () => getNearQuote,
2383
+ getNearSimulation: () => getNearSimulation
2384
+ });
1450
2385
  async function getNearQuote(sourceChain, destChain, amount, destToken, sourceToken, recipient, senderAddress, options) {
1451
2386
  const sourceConfig = NETWORKS[sourceChain];
1452
2387
  const destConfig = NETWORKS[destChain];
@@ -1650,15 +2585,15 @@ var init_near = __esm({
1650
2585
  return { success: false, errorReason: `Stellar Verification Failed: ${e.message}` };
1651
2586
  }
1652
2587
  }
1653
- const { createPublicClient: createPublicClient4, http: http4 } = await import('viem');
2588
+ const { createPublicClient: createPublicClient5, http: http5 } = await import('viem');
1654
2589
  const { FACILITATOR_NETWORKS: FACILITATOR_NETWORKS2 } = await Promise.resolve().then(() => (init_facilitator(), facilitator_exports));
1655
2590
  const networkConfig = FACILITATOR_NETWORKS2[sourceChain];
1656
2591
  if (!networkConfig) {
1657
2592
  return { success: false, errorReason: `Unsupported source chain for verification: ${sourceChain}` };
1658
2593
  }
1659
- const publicClient = createPublicClient4({
2594
+ const publicClient = createPublicClient5({
1660
2595
  chain: networkConfig.chain,
1661
- transport: http4(networkConfig.rpcUrl)
2596
+ transport: http5(networkConfig.rpcUrl)
1662
2597
  });
1663
2598
  try {
1664
2599
  console.log(`[NearStrategy] Waiting for receipt...`);
@@ -1859,6 +2794,7 @@ var init_stargate = __esm({
1859
2794
  success: true,
1860
2795
  transactionHash: "PENDING_USER_SIGNATURE",
1861
2796
  netAmount: amount,
2797
+ estimatedReceived: selectedQuote.dstAmount,
1862
2798
  data: {
1863
2799
  strategy: "Stargate",
1864
2800
  quote: selectedQuote,
@@ -1875,11 +2811,306 @@ var init_stargate = __esm({
1875
2811
  }
1876
2812
  };
1877
2813
  } catch (e) {
1878
- console.error("[StargateStrategy] Execution Error:", e);
1879
- return { success: false, errorReason: e.message };
2814
+ console.error("[StargateStrategy] Execution Error:", e);
2815
+ return { success: false, errorReason: e.message };
2816
+ }
2817
+ }
2818
+ };
2819
+ }
2820
+ });
2821
+ var STACKS_BRIDGE_ADDRESS_ETH, stacksBridgeAbi, StacksStrategy;
2822
+ var init_stacks = __esm({
2823
+ "src/services/stacks.ts"() {
2824
+ init_chainsInformation();
2825
+ STACKS_BRIDGE_ADDRESS_ETH = "0x8888888199b2Df864bf678259607d6D5EBb4e3Ce";
2826
+ stacksBridgeAbi = [
2827
+ {
2828
+ "inputs": [
2829
+ { "internalType": "uint256", "name": "value", "type": "uint256" },
2830
+ { "internalType": "uint32", "name": "remoteDomain", "type": "uint32" },
2831
+ { "internalType": "bytes32", "name": "remoteRecipient", "type": "bytes32" },
2832
+ { "internalType": "address", "name": "localToken", "type": "address" },
2833
+ { "internalType": "uint256", "name": "maxFee", "type": "uint256" }
2834
+ ],
2835
+ "name": "depositToRemote",
2836
+ "outputs": [],
2837
+ "stateMutability": "nonpayable",
2838
+ "type": "function"
2839
+ }
2840
+ ];
2841
+ StacksStrategy = class {
2842
+ constructor() {
2843
+ this.name = "Stacks";
2844
+ }
2845
+ canHandle(context) {
2846
+ return context.sourceChain === "Ethereum" && context.destChain === "Stacks";
2847
+ }
2848
+ async execute(context) {
2849
+ const { amount, recipient, facilitatorPrivateKey, sourceChain } = context;
2850
+ if (sourceChain !== "Ethereum") {
2851
+ return { success: false, errorReason: "Stacks Strategy only supports financing from Ethereum" };
2852
+ }
2853
+ if (!facilitatorPrivateKey) {
2854
+ return { success: false, errorReason: "Private Key required for Stacks Bridge execution" };
2855
+ }
2856
+ const networkConfig = NETWORKS[sourceChain];
2857
+ if (!networkConfig || !networkConfig.evm) {
2858
+ return { success: false, errorReason: `Unsupported chain or missing EVM config: ${sourceChain}` };
2859
+ }
2860
+ try {
2861
+ const account = privateKeyToAccount(facilitatorPrivateKey);
2862
+ const client = createWalletClient({
2863
+ account,
2864
+ chain: networkConfig.evm.chain,
2865
+ transport: http(networkConfig.evm.rpcUrl)
2866
+ });
2867
+ const publicClient = createPublicClient({
2868
+ chain: networkConfig.evm.chain,
2869
+ transport: http(networkConfig.evm.rpcUrl)
2870
+ });
2871
+ const usdcAddress = getAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
2872
+ const amountBigInt = parseUnits(amount, 6);
2873
+ const allowance = await publicClient.readContract({
2874
+ address: usdcAddress,
2875
+ abi: erc20Abi$1,
2876
+ functionName: "allowance",
2877
+ args: [account.address, STACKS_BRIDGE_ADDRESS_ETH]
2878
+ });
2879
+ if (allowance < amountBigInt) {
2880
+ console.log("[Stacks] Approving bridge...");
2881
+ const approveHash = await client.writeContract({
2882
+ address: usdcAddress,
2883
+ abi: erc20Abi$1,
2884
+ functionName: "approve",
2885
+ args: [STACKS_BRIDGE_ADDRESS_ETH, amountBigInt],
2886
+ chain: networkConfig.evm.chain
2887
+ });
2888
+ await publicClient.waitForTransactionReceipt({ hash: approveHash });
2889
+ console.log("[Stacks] Approved.");
2890
+ }
2891
+ const REMOTE_DOMAIN_STACKS = 10003;
2892
+ let recipientBytes32;
2893
+ if (recipient.startsWith("0x")) {
2894
+ recipientBytes32 = padHex(recipient, { size: 32 });
2895
+ } else {
2896
+ try {
2897
+ recipientBytes32 = padHex(toHex(recipient), { size: 32 });
2898
+ } catch (e) {
2899
+ throw new Error("Invalid Stacks Recipient Format. Must be Hex or convertible.");
2900
+ }
2901
+ }
2902
+ console.log(`[Stacks] Depositing ${amount} USDC to ${recipient} (Domain ${REMOTE_DOMAIN_STACKS})...`);
2903
+ const hash = await client.writeContract({
2904
+ address: STACKS_BRIDGE_ADDRESS_ETH,
2905
+ abi: stacksBridgeAbi,
2906
+ functionName: "depositToRemote",
2907
+ args: [
2908
+ amountBigInt,
2909
+ REMOTE_DOMAIN_STACKS,
2910
+ recipientBytes32,
2911
+ usdcAddress,
2912
+ 0n
2913
+ // maxFee (0 for now, or estimated)
2914
+ ],
2915
+ chain: networkConfig.evm.chain
2916
+ });
2917
+ console.log(`[Stacks] Deposit Tx: ${hash}`);
2918
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
2919
+ if (receipt.status === "success") {
2920
+ return {
2921
+ success: true,
2922
+ transactionHash: hash,
2923
+ netAmount: amountBigInt.toString()
2924
+ };
2925
+ } else {
2926
+ return {
2927
+ success: false,
2928
+ transactionHash: hash,
2929
+ errorReason: "Stacks Deposit Transaction Reverted"
2930
+ };
2931
+ }
2932
+ } catch (error) {
2933
+ return {
2934
+ success: false,
2935
+ errorReason: error instanceof Error ? error.message : "Using Stacks Bridge failed"
2936
+ };
2937
+ }
2938
+ }
2939
+ };
2940
+ }
2941
+ });
2942
+
2943
+ // src/services/Router.ts
2944
+ var RouterService;
2945
+ var init_Router = __esm({
2946
+ "src/services/Router.ts"() {
2947
+ RouterService = class {
2948
+ /**
2949
+ * Orchestrates a Multi-Hop transfer by signing ALL UserOps upfront (Reverse Order),
2950
+ * and then executing them sequentially (Forward Order) with polling support.
2951
+ *
2952
+ * @param steps Array of MultiHopStep ordered by execution (Source -> Intermediate -> Dest)
2953
+ * @param onLog Optional callback for logging progress
2954
+ */
2955
+ async executeMultiHop(steps, onLog = console.log) {
2956
+ onLog("[Router] Orchestrating Multi-Hop Sequence...");
2957
+ const signedOps = [];
2958
+ onLog("[Router] Phase 1: Preparation & Upfront Signing (Reverse Order)...");
2959
+ for (let i = steps.length - 1; i >= 0; i--) {
2960
+ const step = steps[i];
2961
+ onLog(`[Router] Preparing Step ${i + 1}: ${step.description}...`);
2962
+ try {
2963
+ const userOp = await step.buildUserOp();
2964
+ onLog(`[Router] Please sign Step ${i + 1} (${step.description})...`);
2965
+ const signedOp = await step.aa.signUserOperation(userOp);
2966
+ signedOps.unshift({ stepIndex: i, signedOp });
2967
+ onLog(`[Router] Step ${i + 1} Signed Successfully.`);
2968
+ } catch (err) {
2969
+ onLog(`[Router] Error preparing Step ${i + 1}: ${err.message}`);
2970
+ throw err;
2971
+ }
2972
+ }
2973
+ onLog("[Router] Phase 2: Sequential Execution (Forward Order)...");
2974
+ for (let i = 0; i < steps.length; i++) {
2975
+ const step = steps[i];
2976
+ const signedOp = signedOps[i].signedOp;
2977
+ if (step.waitCondition) {
2978
+ onLog(`[Router] Step ${i + 1} requires waiting (e.g. for funds)...`);
2979
+ const success = await this.pollCondition(step.waitCondition, onLog);
2980
+ if (!success) throw new Error(`Timeout waiting for condition at Step ${i + 1}`);
2981
+ }
2982
+ onLog(`[Router] Executing Step ${i + 1}...`);
2983
+ try {
2984
+ const hash = await step.aa.sendUserOperation(signedOp);
2985
+ onLog(`[Router] Step ${i + 1} Sent! Hash: ${hash}`);
2986
+ onLog(`[Router] Waiting for Step ${i + 1} confirmation...`);
2987
+ const receipt = await step.aa.waitForUserOperation(hash);
2988
+ if (!receipt.success) {
2989
+ throw new Error(`Step ${i + 1} Failed on-chain!`);
2990
+ }
2991
+ onLog(`[Router] Step ${i + 1} Confirmed.`);
2992
+ } catch (err) {
2993
+ onLog(`[Router] Execution Failed at Step ${i + 1}: ${err.message}`);
2994
+ throw err;
2995
+ }
2996
+ }
2997
+ onLog("[Router] Multi-Hop Sequence Completed Successfully! \u{1F680}");
2998
+ return true;
2999
+ }
3000
+ async pollCondition(condition, onLog) {
3001
+ const timeout = 6e4 * 10;
3002
+ const interval = 5e3;
3003
+ let elapsed = 0;
3004
+ while (elapsed < timeout) {
3005
+ try {
3006
+ const passed = await condition();
3007
+ if (passed) return true;
3008
+ } catch (e) {
3009
+ onLog(`[Router] Polling check failed (retrying): ${e.message}`);
3010
+ }
3011
+ await new Promise((r) => setTimeout(r, interval));
3012
+ elapsed += interval;
3013
+ if (elapsed % 2e4 === 0) onLog(`[Router] Still waiting... (${Math.floor(elapsed / 1e3)}s)`);
3014
+ }
3015
+ return false;
3016
+ }
3017
+ };
3018
+ }
3019
+ });
3020
+
3021
+ // src/services/uniswap.ts
3022
+ var uniswap_exports = {};
3023
+ __export(uniswap_exports, {
3024
+ UniswapService: () => UniswapService,
3025
+ uniswapService: () => uniswapService
3026
+ });
3027
+ var UNISWAP_V3_ROUTER, UNISWAP_V3_QUOTER, USDC_ADDRESS, WETH_ADDRESS, QUOTER_ABI, ROUTER_ABI, UniswapService, uniswapService;
3028
+ var init_uniswap = __esm({
3029
+ "src/services/uniswap.ts"() {
3030
+ UNISWAP_V3_ROUTER = "0x2626664c2603336E57B271c5C0b26F421741e481";
3031
+ UNISWAP_V3_QUOTER = "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a";
3032
+ USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
3033
+ WETH_ADDRESS = "0x4200000000000000000000000000000000000006";
3034
+ QUOTER_ABI = parseAbi([
3035
+ "function quoteExactOutputSingle((address tokenIn, address tokenOut, uint256 amount, uint24 fee, uint160 sqrtPriceLimitX96) params) external returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
3036
+ ]);
3037
+ ROUTER_ABI = parseAbi([
3038
+ "function exactOutputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 amountOut, uint256 amountInMaximum, uint160 sqrtPriceLimitX96) params) external payable returns (uint256 amountIn)"
3039
+ ]);
3040
+ UniswapService = class {
3041
+ constructor() {
3042
+ this.publicClient = createPublicClient({
3043
+ chain: base,
3044
+ transport: http("https://mainnet.base.org")
3045
+ // Default public RPC
3046
+ });
3047
+ }
3048
+ /**
3049
+ * Get amount of USDC needed to buy exact amount of ETH
3050
+ * @param amountETHWei Amount of ETH (Wei) needed
3051
+ */
3052
+ async quoteUSDCForETH(amountETHWei) {
3053
+ try {
3054
+ const params = {
3055
+ tokenIn: USDC_ADDRESS,
3056
+ tokenOut: WETH_ADDRESS,
3057
+ amount: amountETHWei,
3058
+ fee: 500,
3059
+ sqrtPriceLimitX96: 0n
3060
+ };
3061
+ const result = await this.publicClient.readContract({
3062
+ address: UNISWAP_V3_QUOTER,
3063
+ abi: QUOTER_ABI,
3064
+ functionName: "quoteExactOutputSingle",
3065
+ args: [params]
3066
+ });
3067
+ const amountIn = result[0];
3068
+ return amountIn * 105n / 100n;
3069
+ } catch (e) {
3070
+ console.error("Quote failed", e);
3071
+ throw new Error("Failed to quote USDC for ETH swap");
1880
3072
  }
1881
3073
  }
3074
+ /**
3075
+ * Build tx data for swapping USDC -> ETH
3076
+ * Uses SwapRouter02.exactOutputSingle + unwrapWETH9
3077
+ */
3078
+ buildSwapData(recipient, amountOutETH, maxAmountInUSDC) {
3079
+ const swapParams = {
3080
+ tokenIn: USDC_ADDRESS,
3081
+ tokenOut: WETH_ADDRESS,
3082
+ fee: 500,
3083
+ recipient: UNISWAP_V3_ROUTER,
3084
+ // Router must hold WETH to unwrap it
3085
+ amountOut: amountOutETH,
3086
+ amountInMaximum: maxAmountInUSDC,
3087
+ sqrtPriceLimitX96: 0n
3088
+ };
3089
+ const swapCalldata = encodeFunctionData({
3090
+ abi: ROUTER_ABI,
3091
+ functionName: "exactOutputSingle",
3092
+ args: [swapParams]
3093
+ });
3094
+ const unwrapCalldata = encodeFunctionData({
3095
+ abi: parseAbi(["function unwrapWETH9(uint256 amountMinimum, address recipient) payable"]),
3096
+ functionName: "unwrapWETH9",
3097
+ args: [amountOutETH, recipient]
3098
+ });
3099
+ const multicallCalldata = encodeFunctionData({
3100
+ abi: parseAbi(["function multicall(bytes[] data) payable returns (bytes[])"]),
3101
+ functionName: "multicall",
3102
+ args: [[swapCalldata, unwrapCalldata]]
3103
+ });
3104
+ return multicallCalldata;
3105
+ }
3106
+ getRouterAddress() {
3107
+ return UNISWAP_V3_ROUTER;
3108
+ }
3109
+ getUSDCAddress() {
3110
+ return USDC_ADDRESS;
3111
+ }
1882
3112
  };
3113
+ uniswapService = new UniswapService();
1883
3114
  }
1884
3115
  });
1885
3116
 
@@ -1888,23 +3119,46 @@ var TransferManager_exports = {};
1888
3119
  __export(TransferManager_exports, {
1889
3120
  TransferManager: () => TransferManager
1890
3121
  });
1891
- var TransferManager;
3122
+ var OP_SEPOLIA_CONFIG, TransferManager;
1892
3123
  var init_TransferManager = __esm({
1893
3124
  "src/services/TransferManager.ts"() {
1894
3125
  init_cctp2();
1895
3126
  init_near();
1896
3127
  init_stargate();
3128
+ init_stacks();
3129
+ init_Router();
3130
+ init_AccountAbstraction();
3131
+ init_Optimism();
3132
+ OP_SEPOLIA_CONFIG = {
3133
+ chain: {
3134
+ id: 11155420,
3135
+ name: "Optimism Sepolia",
3136
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
3137
+ rpcUrls: { default: { http: ["https://sepolia.optimism.io"] } },
3138
+ testnet: true
3139
+ },
3140
+ rpcUrl: "https://sepolia.optimism.io",
3141
+ // bundlerUrl will be constructed dynamically
3142
+ entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
3143
+ factoryAddress: "0xe2584152891E4769025807DEa0cD611F135aDC68",
3144
+ paymasterAddress: OPTIMISM.evm?.paymasterAddress,
3145
+ tokens: []
3146
+ };
1897
3147
  TransferManager = class {
1898
3148
  constructor() {
1899
3149
  this.strategies = [
1900
3150
  new CCTPStrategy(),
1901
3151
  new StargateStrategy(),
1902
- new NearStrategy()
3152
+ new StargateStrategy(),
3153
+ new NearStrategy(),
3154
+ new StacksStrategy()
1903
3155
  ];
3156
+ this.router = new RouterService();
1904
3157
  }
1905
- async execute(context) {
3158
+ async execute(context, logCallback) {
3159
+ const log = logCallback || console.log;
1906
3160
  if (context.sourceChain === context.destChain && context.sourceToken === context.destToken) {
1907
- console.log(`[TransferManager] Same Chain detected. Signal Direct Transfer.`);
3161
+ log(`[TransferManager] Same Chain detected. Signal Direct Transfer.`);
1908
3162
  return {
1909
3163
  success: true,
1910
3164
  transactionHash: "DIRECT_TRANSFER_REQUIRED",
@@ -1919,17 +3173,17 @@ var init_TransferManager = __esm({
1919
3173
  const strategies = this.strategies;
1920
3174
  const stargateStrategy = strategies.find((s) => s instanceof StargateStrategy);
1921
3175
  if (stargateStrategy && stargateStrategy.canHandle(context)) {
1922
- console.log(`[TransferManager] Routing to: ${stargateStrategy.name} (Stargate)`);
3176
+ log(`[TransferManager] Routing to: ${stargateStrategy.name} (Stargate)`);
1923
3177
  return stargateStrategy.execute(context);
1924
3178
  }
1925
3179
  const cctpStrategy = strategies.find((s) => s instanceof CCTPStrategy);
1926
3180
  if (cctpStrategy && cctpStrategy.canHandle(context)) {
1927
- console.log(`[TransferManager] Routing to: ${cctpStrategy.name} (CCTP)`);
3181
+ log(`[TransferManager] Routing to: ${cctpStrategy.name} (CCTP)`);
1928
3182
  return cctpStrategy.execute(context);
1929
3183
  }
1930
3184
  const nearStrategy = strategies.find((s) => s instanceof NearStrategy);
1931
3185
  if (nearStrategy && nearStrategy.canHandle(context)) {
1932
- console.log(`[TransferManager] Routing to: ${nearStrategy.name} (Near)`);
3186
+ log(`[TransferManager] Routing to: ${nearStrategy.name} (Near)`);
1933
3187
  return nearStrategy.execute(context);
1934
3188
  }
1935
3189
  return {
@@ -1937,781 +3191,218 @@ var init_TransferManager = __esm({
1937
3191
  errorReason: `No suitable transfer strategy found for ${context.sourceChain} -> ${context.destChain}`
1938
3192
  };
1939
3193
  }
1940
- };
1941
- }
1942
- });
1943
-
1944
- // src/constants.ts
1945
- var factoryAbi = [
1946
- {
1947
- inputs: [
1948
- { name: "owner", type: "address" },
1949
- { name: "salt", type: "uint256" }
1950
- ],
1951
- name: "getAccountAddress",
1952
- outputs: [{ name: "", type: "address" }],
1953
- stateMutability: "view",
1954
- type: "function"
1955
- },
1956
- {
1957
- inputs: [
1958
- { name: "owner", type: "address" },
1959
- { name: "salt", type: "uint256" }
1960
- ],
1961
- name: "isAccountDeployed",
1962
- outputs: [{ name: "", type: "bool" }],
1963
- stateMutability: "view",
1964
- type: "function"
1965
- },
1966
- {
1967
- inputs: [
1968
- { name: "owner", type: "address" },
1969
- { name: "salt", type: "uint256" }
1970
- ],
1971
- name: "createAccount",
1972
- outputs: [{ name: "account", type: "address" }],
1973
- stateMutability: "nonpayable",
1974
- type: "function"
1975
- }
1976
- ];
1977
- var entryPointAbi = [
1978
- {
1979
- inputs: [
1980
- { name: "sender", type: "address" },
1981
- { name: "key", type: "uint192" }
1982
- ],
1983
- name: "getNonce",
1984
- outputs: [{ name: "nonce", type: "uint256" }],
1985
- stateMutability: "view",
1986
- type: "function"
1987
- }
1988
- ];
1989
- var smartAccountAbi = [
1990
- {
1991
- inputs: [
1992
- { name: "target", type: "address" },
1993
- { name: "value", type: "uint256" },
1994
- { name: "data", type: "bytes" }
1995
- ],
1996
- name: "execute",
1997
- outputs: [],
1998
- stateMutability: "nonpayable",
1999
- type: "function"
2000
- },
2001
- {
2002
- inputs: [
2003
- { name: "targets", type: "address[]" },
2004
- { name: "values", type: "uint256[]" },
2005
- { name: "datas", type: "bytes[]" }
2006
- ],
2007
- name: "executeBatch",
2008
- outputs: [],
2009
- stateMutability: "nonpayable",
2010
- type: "function"
2011
- }
2012
- ];
2013
- var erc20Abi = [
2014
- {
2015
- inputs: [{ name: "account", type: "address" }],
2016
- name: "balanceOf",
2017
- outputs: [{ name: "", type: "uint256" }],
2018
- stateMutability: "view",
2019
- type: "function"
2020
- },
2021
- {
2022
- inputs: [
2023
- { name: "to", type: "address" },
2024
- { name: "amount", type: "uint256" }
2025
- ],
2026
- name: "transfer",
2027
- outputs: [{ name: "", type: "bool" }],
2028
- stateMutability: "nonpayable",
2029
- type: "function"
2030
- },
2031
- {
2032
- inputs: [
2033
- { name: "spender", type: "address" },
2034
- { name: "amount", type: "uint256" }
2035
- ],
2036
- name: "approve",
2037
- outputs: [{ name: "", type: "bool" }],
2038
- stateMutability: "nonpayable",
2039
- type: "function"
2040
- },
2041
- {
2042
- inputs: [
2043
- { name: "owner", type: "address" },
2044
- { name: "spender", type: "address" }
2045
- ],
2046
- name: "allowance",
2047
- outputs: [{ name: "", type: "uint256" }],
2048
- stateMutability: "view",
2049
- type: "function"
2050
- },
2051
- {
2052
- inputs: [
2053
- { name: "from", type: "address" },
2054
- { name: "to", type: "address" },
2055
- { name: "amount", type: "uint256" }
2056
- ],
2057
- name: "transferFrom",
2058
- outputs: [{ name: "", type: "bool" }],
2059
- stateMutability: "nonpayable",
2060
- type: "function"
2061
- },
2062
- {
2063
- inputs: [],
2064
- name: "decimals",
2065
- outputs: [{ name: "", type: "uint8" }],
2066
- stateMutability: "view",
2067
- type: "function"
2068
- }
2069
- ];
2070
-
2071
- // src/BundlerClient.ts
2072
- var BundlerClient = class {
2073
- constructor(config, entryPointAddress) {
2074
- this.bundlerUrl = config.bundlerUrl;
2075
- this.entryPointAddress = entryPointAddress;
2076
- }
2077
- async call(method, params) {
2078
- const response = await fetch(this.bundlerUrl, {
2079
- method: "POST",
2080
- headers: { "Content-Type": "application/json" },
2081
- body: JSON.stringify({
2082
- jsonrpc: "2.0",
2083
- id: 1,
2084
- method,
2085
- params
2086
- })
2087
- });
2088
- const result = await response.json();
2089
- if (result.error) {
2090
- throw new Error(result.error.message);
2091
- }
2092
- return result.result;
2093
- }
2094
- async estimateGas(userOp) {
2095
- const result = await this.call("eth_estimateUserOperationGas", [
2096
- {
2097
- sender: userOp.sender,
2098
- nonce: userOp.nonce ? "0x" + userOp.nonce.toString(16) : "0x0",
2099
- initCode: userOp.initCode || "0x",
2100
- callData: userOp.callData || "0x",
2101
- paymasterAndData: userOp.paymasterAndData || "0x",
2102
- signature: "0x"
2103
- },
2104
- this.entryPointAddress
2105
- ]);
2106
- console.log("DEBUG: estimateGas result:", result);
2107
- return {
2108
- callGasLimit: result.callGasLimit,
2109
- verificationGasLimit: result.verificationGasLimit,
2110
- preVerificationGas: result.preVerificationGas,
2111
- maxFeePerGas: result.maxFeePerGas,
2112
- maxPriorityFeePerGas: result.maxPriorityFeePerGas,
2113
- paymasterAndData: result.paymasterAndData
2114
- };
2115
- }
2116
- async sendUserOperation(userOp) {
2117
- return await this.call("eth_sendUserOperation", [
2118
- {
2119
- sender: userOp.sender,
2120
- nonce: "0x" + userOp.nonce.toString(16),
2121
- initCode: userOp.initCode,
2122
- callData: userOp.callData,
2123
- callGasLimit: "0x" + userOp.callGasLimit.toString(16),
2124
- verificationGasLimit: "0x" + userOp.verificationGasLimit.toString(16),
2125
- preVerificationGas: "0x" + userOp.preVerificationGas.toString(16),
2126
- maxFeePerGas: "0x" + userOp.maxFeePerGas.toString(16),
2127
- maxPriorityFeePerGas: "0x" + userOp.maxPriorityFeePerGas.toString(16),
2128
- paymasterAndData: userOp.paymasterAndData,
2129
- signature: userOp.signature
2130
- },
2131
- this.entryPointAddress
2132
- ]);
2133
- }
2134
- async waitForUserOperation(userOpHash, timeout = 6e4) {
2135
- const startTime = Date.now();
2136
- while (Date.now() - startTime < timeout) {
2137
- const result = await this.call("eth_getUserOperationReceipt", [userOpHash]);
2138
- if (result) {
2139
- return result;
2140
- }
2141
- await new Promise((resolve) => setTimeout(resolve, 2e3));
2142
- }
2143
- throw new Error("Timeout waiting for UserOperation");
2144
- }
2145
- async requestApprovalSupport(token, owner, spender, amount) {
2146
- return await this.call("pm_requestApprovalSupport", [
2147
- token,
2148
- owner,
2149
- spender,
2150
- amount.toString()
2151
- ]);
2152
- }
2153
- };
2154
- var TokenService = class {
2155
- constructor(chainConfig, publicClient) {
2156
- this.tokens = /* @__PURE__ */ new Map();
2157
- this.publicClient = publicClient;
2158
- chainConfig.tokens.forEach((token) => {
2159
- this.tokens.set(token.symbol.toUpperCase(), token);
2160
- });
2161
- }
2162
- /**
2163
- * Resolve token address from symbol or return address if provided
2164
- */
2165
- getTokenAddress(token) {
2166
- if (token.startsWith("0x")) return token;
2167
- const info = this.tokens.get(token.toUpperCase());
2168
- if (!info) throw new Error(`Token ${token} not found in chain config`);
2169
- return info.address;
2170
- }
2171
- /**
2172
- * Get balance of a token for an account
2173
- */
2174
- async getBalance(token, account) {
2175
- const address = this.getTokenAddress(token);
2176
- if (address === "0x0000000000000000000000000000000000000000") {
2177
- return await this.publicClient.getBalance({ address: account });
2178
- }
2179
- return await this.publicClient.readContract({
2180
- address,
2181
- abi: erc20Abi,
2182
- functionName: "balanceOf",
2183
- args: [account]
2184
- });
2185
- }
2186
- /**
2187
- * Get allowance (ERC-20 only)
2188
- */
2189
- async getAllowance(token, owner, spender) {
2190
- const address = this.getTokenAddress(token);
2191
- if (address === "0x0000000000000000000000000000000000000000") {
2192
- return 0n;
2193
- }
2194
- return await this.publicClient.readContract({
2195
- address,
2196
- abi: erc20Abi,
2197
- functionName: "allowance",
2198
- args: [owner, spender]
2199
- });
2200
- }
2201
- /**
2202
- * Encode transfer data
2203
- */
2204
- encodeTransfer(recipient, amount) {
2205
- return encodeFunctionData({
2206
- abi: erc20Abi,
2207
- functionName: "transfer",
2208
- args: [recipient, amount]
2209
- });
2210
- }
2211
- /**
2212
- * Encode transferFrom data
2213
- */
2214
- encodeTransferFrom(sender, recipient, amount) {
2215
- return encodeFunctionData({
2216
- abi: erc20Abi,
2217
- functionName: "transferFrom",
2218
- args: [sender, recipient, amount]
2219
- });
2220
- }
2221
- /**
2222
- * Encode approve data
2223
- */
2224
- encodeApprove(spender, amount) {
2225
- return encodeFunctionData({
2226
- abi: erc20Abi,
2227
- functionName: "approve",
2228
- args: [spender, amount]
2229
- });
2230
- }
2231
- };
2232
- var UserOpBuilder = class {
2233
- constructor(chainConfig, bundlerClient, publicClient) {
2234
- this.chainConfig = chainConfig;
2235
- this.bundlerClient = bundlerClient;
2236
- this.publicClient = publicClient;
2237
- this.entryPointAddress = chainConfig.entryPointAddress;
2238
- this.factoryAddress = chainConfig.factoryAddress;
2239
- }
2240
- async getNonce(smartAccountAddress) {
2241
- return await this.publicClient.readContract({
2242
- address: this.entryPointAddress,
2243
- abi: entryPointAbi,
2244
- functionName: "getNonce",
2245
- args: [smartAccountAddress, 0n]
2246
- });
2247
- }
2248
- buildInitCode(owner) {
2249
- const createAccountData = encodeFunctionData({
2250
- abi: factoryAbi,
2251
- functionName: "createAccount",
2252
- args: [owner, 0n]
2253
- });
2254
- return `${this.factoryAddress}${createAccountData.slice(2)}`;
2255
- }
2256
- async isAccountDeployed(smartAccountAddress) {
2257
- const code = await this.publicClient.getCode({
2258
- address: smartAccountAddress
2259
- });
2260
- return code !== void 0 && code !== "0x";
2261
- }
2262
- async buildUserOperationBatch(owner, smartAccountAddress, transactions) {
2263
- const isDeployed = await this.isAccountDeployed(smartAccountAddress);
2264
- const initCode = isDeployed ? "0x" : this.buildInitCode(owner);
2265
- const targets = transactions.map((tx) => tx.target);
2266
- const values = transactions.map((tx) => tx.value);
2267
- const datas = transactions.map((tx) => tx.data);
2268
- const callData = encodeFunctionData({
2269
- abi: smartAccountAbi,
2270
- functionName: "executeBatch",
2271
- args: [targets, values, datas]
2272
- });
2273
- const nonce = await this.getNonce(smartAccountAddress);
2274
- const partialOp = {
2275
- sender: smartAccountAddress,
2276
- nonce,
2277
- initCode,
2278
- callData,
2279
- paymasterAndData: this.chainConfig.paymasterAddress || "0x"
2280
- };
2281
- const gasEstimate = await this.bundlerClient.estimateGas(partialOp);
2282
- return {
2283
- ...partialOp,
2284
- callGasLimit: BigInt(gasEstimate.callGasLimit),
2285
- verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),
2286
- preVerificationGas: BigInt(gasEstimate.preVerificationGas),
2287
- maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
2288
- maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
2289
- paymasterAndData: gasEstimate.paymasterAndData || partialOp.paymasterAndData,
2290
- signature: "0x"
2291
- };
2292
- }
2293
- async buildDeployUserOp(owner, smartAccountAddress) {
2294
- const isDeployed = await this.isAccountDeployed(smartAccountAddress);
2295
- if (isDeployed) throw new Error("Account already deployed");
2296
- const initCode = this.buildInitCode(owner);
2297
- const callData = "0x";
2298
- const nonce = await this.getNonce(smartAccountAddress);
2299
- const partialOp = {
2300
- sender: smartAccountAddress,
2301
- nonce,
2302
- initCode,
2303
- callData,
2304
- paymasterAndData: this.chainConfig.paymasterAddress || "0x"
2305
- };
2306
- const gasEstimate = await this.bundlerClient.estimateGas(partialOp);
2307
- return {
2308
- ...partialOp,
2309
- callGasLimit: BigInt(gasEstimate.callGasLimit),
2310
- verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),
2311
- preVerificationGas: BigInt(gasEstimate.preVerificationGas),
2312
- maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
2313
- maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
2314
- paymasterAndData: gasEstimate.paymasterAndData || partialOp.paymasterAndData,
2315
- signature: "0x"
2316
- };
2317
- }
2318
- getUserOpHash(userOp) {
2319
- const packed = encodeAbiParameters(
2320
- [
2321
- { type: "address" },
2322
- { type: "uint256" },
2323
- { type: "bytes32" },
2324
- { type: "bytes32" },
2325
- { type: "uint256" },
2326
- { type: "uint256" },
2327
- { type: "uint256" },
2328
- { type: "uint256" },
2329
- { type: "uint256" },
2330
- { type: "bytes32" }
2331
- ],
2332
- [
2333
- userOp.sender,
2334
- userOp.nonce,
2335
- keccak256(userOp.initCode),
2336
- keccak256(userOp.callData),
2337
- userOp.callGasLimit,
2338
- userOp.verificationGasLimit,
2339
- userOp.preVerificationGas,
2340
- userOp.maxFeePerGas,
2341
- userOp.maxPriorityFeePerGas,
2342
- keccak256(userOp.paymasterAndData)
2343
- ]
2344
- );
2345
- const packedHash = keccak256(packed);
2346
- return keccak256(
2347
- encodeAbiParameters(
2348
- [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
2349
- [packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]
2350
- )
2351
- );
2352
- }
2353
- };
2354
-
2355
- // src/AccountAbstraction.ts
2356
- var AccountAbstraction = class {
2357
- constructor(chainConfig) {
2358
- this.owner = null;
2359
- this.smartAccountAddress = null;
2360
- this.walletClient = null;
2361
- this.chainConfig = chainConfig;
2362
- if (!chainConfig.entryPointAddress) throw new Error("EntryPoint address required");
2363
- this.entryPointAddress = chainConfig.entryPointAddress;
2364
- if (!chainConfig.factoryAddress) throw new Error("Factory address required");
2365
- this.factoryAddress = chainConfig.factoryAddress;
2366
- const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];
2367
- this.publicClient = createPublicClient({
2368
- chain: chainConfig.chain,
2369
- transport: http(rpcUrl)
2370
- });
2371
- this.bundlerClient = new BundlerClient(chainConfig, this.entryPointAddress);
2372
- this.tokenService = new TokenService(chainConfig, this.publicClient);
2373
- this.userOpBuilder = new UserOpBuilder(chainConfig, this.bundlerClient, this.publicClient);
2374
- }
2375
- async connect(signer) {
2376
- if (typeof signer === "string") {
2377
- const account = privateKeyToAccount(signer);
2378
- this.owner = account.address;
2379
- const rpcUrl = this.chainConfig.rpcUrl || this.chainConfig.chain.rpcUrls.default.http[0];
2380
- this.walletClient = createWalletClient({
2381
- account,
2382
- chain: this.chainConfig.chain,
2383
- transport: http(rpcUrl)
2384
- });
2385
- } else if (signer && typeof signer === "object") {
2386
- this.walletClient = signer;
2387
- if (!this.walletClient.account) throw new Error("WalletClient must have an account");
2388
- this.owner = this.walletClient.account.address;
2389
- } else {
2390
- if (typeof window === "undefined" || !window.ethereum) {
2391
- throw new Error("MetaMask is not installed and no private key provided");
2392
- }
2393
- const accounts = await window.ethereum.request({
2394
- method: "eth_requestAccounts"
2395
- });
2396
- if (!accounts || accounts.length === 0) throw new Error("No accounts found");
2397
- const chainId = await window.ethereum.request({
2398
- method: "eth_chainId"
2399
- });
2400
- const targetChainId = this.chainConfig.chain.id;
2401
- if (parseInt(chainId, 16) !== targetChainId) {
2402
- try {
2403
- await window.ethereum.request({
2404
- method: "wallet_switchEthereumChain",
2405
- params: [{ chainId: "0x" + targetChainId.toString(16) }]
2406
- });
2407
- } catch (switchError) {
2408
- const error = switchError;
2409
- if (error.code === 4902) {
2410
- await window.ethereum.request({
2411
- method: "wallet_addEthereumChain",
2412
- params: [
2413
- {
2414
- chainId: "0x" + targetChainId.toString(16),
2415
- chainName: this.chainConfig.chain.name,
2416
- nativeCurrency: this.chainConfig.chain.nativeCurrency,
2417
- rpcUrls: [this.chainConfig.rpcUrl || this.chainConfig.chain.rpcUrls.default.http[0]],
2418
- blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url ? [this.chainConfig.chain.blockExplorers.default.url] : []
2419
- }
2420
- ]
2421
- });
2422
- } else {
2423
- throw switchError;
2424
- }
2425
- }
2426
- }
2427
- this.owner = accounts[0];
2428
- }
2429
- this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);
2430
- return {
2431
- owner: this.owner,
2432
- smartAccount: this.smartAccountAddress
2433
- };
2434
- }
2435
- // --- Account Management ---
2436
- async isAccountDeployed() {
2437
- if (!this.smartAccountAddress) return false;
2438
- const code = await this.publicClient.getBytecode({ address: this.smartAccountAddress });
2439
- return code !== void 0;
2440
- }
2441
- async deployAccount() {
2442
- if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
2443
- return this.sendTransaction({
2444
- target: this.smartAccountAddress,
2445
- value: 0n,
2446
- data: "0x"
2447
- });
2448
- }
2449
- /**
2450
- * Get the Smart Account address for an owner
2451
- */
2452
- async getSmartAccountAddress(owner) {
2453
- const address = await this.publicClient.readContract({
2454
- address: this.factoryAddress,
2455
- abi: factoryAbi,
2456
- functionName: "getAccountAddress",
2457
- args: [owner, 0n]
2458
- });
2459
- return address;
2460
- }
2461
- // --- Token Methods (Delegated) ---
2462
- getTokenAddress(token) {
2463
- return this.tokenService.getTokenAddress(token);
2464
- }
2465
- async getBalance(token) {
2466
- if (!this.smartAccountAddress) throw new Error("Not connected");
2467
- return this.tokenService.getBalance(token, this.smartAccountAddress);
2468
- }
2469
- async getEoaBalance(token) {
2470
- if (!this.owner) throw new Error("Not connected");
2471
- return this.tokenService.getBalance(token, this.owner);
2472
- }
2473
- async getAllowance(token = "USDC") {
2474
- if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
2475
- return this.tokenService.getAllowance(token, this.owner, this.smartAccountAddress);
2476
- }
2477
- /**
2478
- * Get comprehensive state of the account for a specific token
2479
- * Useful for UI initialization
2480
- */
2481
- async getAccountState(token) {
2482
- if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
2483
- const tokenAddress = this.getTokenAddress(token);
2484
- const isNative = tokenAddress === "0x0000000000000000000000000000000000000000";
2485
- const [balance, eoaBalance, allowance, isDeployed] = await Promise.all([
2486
- this.getBalance(token),
2487
- this.getEoaBalance(token),
2488
- isNative ? 0n : this.getAllowance(token).catch(() => 0n),
2489
- // Handle native/error gracefully
2490
- this.isAccountDeployed()
2491
- ]);
2492
- return {
2493
- owner: this.owner,
2494
- smartAccount: this.smartAccountAddress,
2495
- balance,
2496
- eoaBalance,
2497
- allowance,
2498
- isDeployed
2499
- };
2500
- }
2501
- // --- Transactions ---
2502
- async sendTransaction(tx) {
2503
- return this.sendBatchTransaction([tx]);
2504
- }
2505
- async sendBatchTransaction(txs) {
2506
- if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
2507
- const transactions = txs.map((tx) => ({
2508
- target: tx.target,
2509
- value: tx.value ?? 0n,
2510
- data: tx.data ?? "0x"
2511
- }));
2512
- try {
2513
- const userOp = await this.userOpBuilder.buildUserOperationBatch(
2514
- this.owner,
2515
- this.smartAccountAddress,
2516
- transactions
2517
- );
2518
- const signed = await this.signUserOperation(userOp);
2519
- const hash = await this.sendUserOperation(signed);
2520
- return await this.waitForUserOperation(hash);
2521
- } catch (error) {
2522
- throw this.decodeError(error);
2523
- }
2524
- }
2525
- async deposit(amount) {
2526
- if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
2527
- if (this.walletClient) {
2528
- return await this.walletClient.sendTransaction({
2529
- account: this.walletClient.account,
2530
- to: this.smartAccountAddress,
2531
- value: amount,
2532
- chain: this.chainConfig.chain
2533
- });
2534
- }
2535
- return await window.ethereum.request({
2536
- method: "eth_sendTransaction",
2537
- params: [{
2538
- from: this.owner,
2539
- to: this.smartAccountAddress,
2540
- value: "0x" + amount.toString(16)
2541
- }]
2542
- });
2543
- }
2544
- /**
2545
- * Smart Transfer: Automatically chooses best method (SA vs EOA) based on balances.
2546
- * Supports strict fee handling.
2547
- */
2548
- async smartTransfer(token, recipient, amount, fee) {
2549
- if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
2550
- const tokenAddress = this.getTokenAddress(token);
2551
- const isNative = tokenAddress === "0x0000000000000000000000000000000000000000";
2552
- const [saBal, eoaBal, allowance] = await Promise.all([
2553
- this.getBalance(token),
2554
- this.getEoaBalance(token),
2555
- isNative ? 0n : this.getAllowance(token).catch(() => 0n)
2556
- ]);
2557
- const totalNeeded = amount + (fee?.amount || 0n);
2558
- if (saBal >= totalNeeded) {
2559
- const txs = [];
2560
- if (isNative) {
2561
- txs.push({ target: recipient, value: amount, data: "0x" });
2562
- } else {
2563
- txs.push({ target: tokenAddress, value: 0n, data: this.tokenService.encodeTransfer(recipient, amount) });
2564
- }
2565
- if (fee && fee.amount > 0n) {
2566
- if (isNative) {
2567
- txs.push({ target: fee.recipient, value: fee.amount, data: "0x" });
3194
+ /**
3195
+ * Special method to orchestrate the Base -> Optimism -> Base demo flow
3196
+ * entirely within the SDK.
3197
+ */
3198
+ async executeMultiHopDemo(context, sourceAA, logCallback, overrides) {
3199
+ const log = logCallback || console.log;
3200
+ log("[TransferManager] Calculating Multi-Hop Route...");
3201
+ context.sourceChain === "Base" && (sourceAA.getChainId() === 84532 || context.sourceChainId === 84532);
3202
+ const sourceChainId = await sourceAA.getPublicClient().getChainId();
3203
+ const isSepolia = sourceChainId === 84532;
3204
+ const baseUrl = overrides?.bundlerUrl || "https://bundler.1llet.xyz";
3205
+ let intermediateConfig;
3206
+ if (isSepolia) {
3207
+ log(`[TransferManager] Detected Testnet (Base Sepolia). Using Optimism Sepolia.`);
3208
+ intermediateConfig = {
3209
+ tokens: [],
3210
+ ...OP_SEPOLIA_CONFIG,
3211
+ bundlerUrl: `${baseUrl}/rpc?chain=optimismSepolia`
3212
+ };
3213
+ getAddress("0x5fd84259d66Cd46123540766Be93DFE6D43130D7");
2568
3214
  } else {
2569
- txs.push({ target: tokenAddress, value: 0n, data: this.tokenService.encodeTransfer(fee.recipient, fee.amount) });
3215
+ log(`[TransferManager] Detected Mainnet (Base). Using Optimism Mainnet.`);
3216
+ intermediateConfig = {
3217
+ tokens: [],
3218
+ // Default empty
3219
+ ...OPTIMISM.evm,
3220
+ bundlerUrl: `${baseUrl}/rpc?chain=optimism`
3221
+ };
3222
+ if (!intermediateConfig.tokens) intermediateConfig.tokens = [];
3223
+ getAddress("0x0b2C639c533813f4Aa9D7837CAf992c92bdE5162");
2570
3224
  }
3225
+ const intermediateAA = new AccountAbstraction(intermediateConfig);
3226
+ await intermediateAA.connect();
3227
+ const interAddress = await intermediateAA.getSmartAccount();
3228
+ log(`[TransferManager] Refund Address (Intermediate SA): ${interAddress}`);
3229
+ const stargate = new StargateStrategy();
3230
+ const { getNearQuote: getNearQuote2 } = await Promise.resolve().then(() => (init_near(), near_exports));
3231
+ const { uniswapService: uniswapService2 } = await Promise.resolve().then(() => (init_uniswap(), uniswap_exports));
3232
+ const parsedInputAmount = parseUnits(context.amount, 6);
3233
+ const estimatedOpAmount = parsedInputAmount * 99n / 100n;
3234
+ const humanEstimatedOpAmount = formatUnits(estimatedOpAmount, 6);
3235
+ log(`[TransferManager] Planning Optimism -> Base (Near) for ~${humanEstimatedOpAmount} USDC...`);
3236
+ const nearQuote = await getNearQuote2(
3237
+ "Optimism",
3238
+ "Base",
3239
+ humanEstimatedOpAmount,
3240
+ "USDC",
3241
+ "USDC",
3242
+ context.recipient || context.senderAddress || await sourceAA.getSmartAccount(),
3243
+ // Final Recipient on Base
3244
+ interAddress
3245
+ // Refund Address on Optimism (Intermediate SA)
3246
+ );
3247
+ if (!nearQuote?.depositAddress) throw new Error("Planning Failed (No Near Deposit Address)");
3248
+ log(`[TransferManager] Near Deposit Address: ${nearQuote.depositAddress}`);
3249
+ log("[TransferManager] Planning Base -> Optimism (Stargate Direct)...");
3250
+ const sgResult = await stargate.execute({
3251
+ ...context,
3252
+ destChain: "Optimism",
3253
+ recipient: nearQuote.depositAddress
3254
+ // DIRECTLY to Near
3255
+ });
3256
+ if (!sgResult.success) throw new Error(`Step 1 Planning Failed: ${sgResult.errorReason}`);
3257
+ const { txTarget, txData, txValue, approvalRequired } = sgResult.data;
3258
+ const buildStep1 = async () => {
3259
+ const requiredValue = BigInt(txValue || 0);
3260
+ let autoSwapTxs = [];
3261
+ if (requiredValue > 0n) {
3262
+ const nativeBalance = await sourceAA.getBalance("0x0000000000000000000000000000000000000000");
3263
+ if (nativeBalance < requiredValue) {
3264
+ log(`[TransferManager] Auto-Swap: Need ETH for fee.`);
3265
+ const missingETH = requiredValue * 110n / 100n - nativeBalance;
3266
+ const usdcNeeded = await uniswapService2.quoteUSDCForETH(missingETH);
3267
+ const routerAddress = uniswapService2.getRouterAddress();
3268
+ if (!routerAddress) throw new Error("Uniswap Router not found");
3269
+ const tokenAddr = getAddress(context.sourceToken === "USDC" ? "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" : "0x0");
3270
+ const parsedTransferAmount = parseUnits(context.amount, 6);
3271
+ const tokenBalance = await sourceAA.getBalance(tokenAddr);
3272
+ const totalRequiredUSDC = parsedTransferAmount + usdcNeeded;
3273
+ const amountToPull = totalRequiredUSDC > tokenBalance ? totalRequiredUSDC - tokenBalance : 0n;
3274
+ if (amountToPull > 0n) {
3275
+ const owner = sourceAA.getOwner();
3276
+ const smartAccount = await sourceAA.getSmartAccount();
3277
+ if (!owner || !smartAccount) throw new Error("Owner/SA not found for Pull");
3278
+ const allowance = await sourceAA.getAllowance(tokenAddr);
3279
+ if (allowance < amountToPull) throw new Error(`Auto-Swap: Approval needed (${formatUnits(amountToPull, 6)} USDC).`);
3280
+ log(`[TransferManager] Auto-Swap: Pulling ${formatUnits(amountToPull, 6)} USDC...`);
3281
+ autoSwapTxs.push({
3282
+ target: tokenAddr,
3283
+ data: encodeFunctionData({
3284
+ abi: erc20Abi$1,
3285
+ functionName: "transferFrom",
3286
+ args: [owner, smartAccount, amountToPull]
3287
+ }),
3288
+ value: 0n
3289
+ });
3290
+ }
3291
+ const swapData = uniswapService2.buildSwapData(await sourceAA.getSmartAccount(), missingETH, usdcNeeded);
3292
+ const approveSwapData = encodeFunctionData({
3293
+ abi: erc20Abi$1,
3294
+ functionName: "approve",
3295
+ args: [routerAddress, usdcNeeded]
3296
+ });
3297
+ autoSwapTxs.push({ target: tokenAddr, data: approveSwapData, value: 0n });
3298
+ autoSwapTxs.push({ target: routerAddress, data: swapData, value: 0n });
3299
+ }
3300
+ }
3301
+ const batch = [...autoSwapTxs];
3302
+ if (approvalRequired) {
3303
+ batch.push({
3304
+ target: approvalRequired.target,
3305
+ data: approvalRequired.data,
3306
+ value: BigInt(approvalRequired.value || 0)
3307
+ });
3308
+ }
3309
+ batch.push({
3310
+ target: txTarget,
3311
+ data: txData,
3312
+ value: BigInt(txValue || 0)
3313
+ });
3314
+ return sourceAA.buildBatchUserOperation(batch);
3315
+ };
3316
+ const steps = [
3317
+ {
3318
+ aa: sourceAA,
3319
+ buildUserOp: buildStep1,
3320
+ description: "Base -> Optimism (Stargate -> Near Direct)"
3321
+ }
3322
+ ];
3323
+ return this.router.executeMultiHop(steps, log);
2571
3324
  }
2572
- console.log("SmartTransfer: Using Smart Account");
2573
- return this.sendBatchTransaction(txs);
2574
- }
2575
- if (eoaBal >= totalNeeded) {
2576
- if (isNative) {
2577
- console.log("SmartTransfer: Using EOA (Native)");
2578
- if (this.walletClient) {
2579
- const hash2 = await this.walletClient.sendTransaction({
2580
- account: this.walletClient.account,
2581
- to: recipient,
2582
- value: amount,
2583
- chain: this.chainConfig.chain
3325
+ /**
3326
+ * Specialized method for Unichain -> Stacks flow.
3327
+ * 1. Unichain -> Ethereum (CCTP)
3328
+ * 2. Ethereum -> Stacks (Stacks Bridge)
3329
+ */
3330
+ async executeUnichainToStacks(context, sourceAA, ethPrivateKey, logCallback) {
3331
+ const log = logCallback || console.log;
3332
+ log("[TransferManager] Starting Unichain -> Stacks Flow...");
3333
+ const cctpStrategy = this.strategies.find((s) => s instanceof CCTPStrategy);
3334
+ const stacksStrategy = this.strategies.find((s) => s instanceof StacksStrategy);
3335
+ if (context.sourceChain === "Ethereum") {
3336
+ log("[TransferManager] Source is Ethereum. Executing Stacks Bridge Step...");
3337
+ return stacksStrategy.execute({
3338
+ ...context,
3339
+ facilitatorPrivateKey: ethPrivateKey
2584
3340
  });
2585
- return { receipt: { transactionHash: hash2 } };
2586
3341
  }
2587
- const hash = await window.ethereum.request({
2588
- method: "eth_sendTransaction",
2589
- params: [{ from: this.owner, to: recipient, value: "0x" + amount.toString(16) }]
2590
- });
2591
- return { receipt: { transactionHash: hash } };
2592
- } else {
2593
- console.log("SmartTransfer: Using EOA (Pull)");
2594
- if (allowance < totalNeeded) {
2595
- throw new Error(`Approval required. Please approve ${token} usage.`);
2596
- }
2597
- const txs = [];
2598
- txs.push({
2599
- target: tokenAddress,
2600
- value: 0n,
2601
- data: this.tokenService.encodeTransferFrom(this.owner, recipient, amount)
2602
- });
2603
- if (fee && fee.amount > 0n) {
2604
- txs.push({
2605
- target: tokenAddress,
2606
- value: 0n,
2607
- data: this.tokenService.encodeTransferFrom(this.owner, fee.recipient, fee.amount)
3342
+ if (context.sourceChain === "Unichain") {
3343
+ log("[TransferManager] Step 1: Unichain -> Ethereum (via CCTP)");
3344
+ const ethAccount = privateKeyToAccount(ethPrivateKey);
3345
+ const ethAddress = ethAccount.address;
3346
+ const cctpResult = await cctpStrategy.execute({
3347
+ ...context,
3348
+ destChain: "Ethereum",
3349
+ destToken: "USDC",
3350
+ recipient: ethAddress,
3351
+ // Send to Facilitator's ETH Wallet
3352
+ facilitatorPrivateKey: ethPrivateKey
3353
+ // Using same key for Unichain CCTP signing if compatible
2608
3354
  });
3355
+ if (!cctpResult.success) {
3356
+ return cctpResult;
3357
+ }
3358
+ log("[TransferManager] CCTP Step Initiated.");
3359
+ if (cctpResult.mintTransactionHash) {
3360
+ log("[TransferManager] CCTP Complete (Funds on Ethereum). Proceeding to Stacks Step...");
3361
+ const stacksResult = await stacksStrategy.execute({
3362
+ ...context,
3363
+ sourceChain: "Ethereum",
3364
+ // Context update for next leg
3365
+ amount: cctpResult.netAmount || context.amount,
3366
+ // Use actual net amount received
3367
+ facilitatorPrivateKey: ethPrivateKey
3368
+ });
3369
+ return {
3370
+ success: stacksResult.success,
3371
+ transactionHash: stacksResult.transactionHash,
3372
+ // The final Stacks Tx
3373
+ data: {
3374
+ cctpStep: cctpResult,
3375
+ stacksStep: stacksResult
3376
+ },
3377
+ netAmount: stacksResult.netAmount,
3378
+ errorReason: stacksResult.errorReason
3379
+ };
3380
+ } else {
3381
+ log("[TransferManager] CCTP Pending (Attestation/Mint not final yet). Please resume later.");
3382
+ return {
3383
+ ...cctpResult,
3384
+ attestation: {
3385
+ message: "CCTP Initiated but not finalized (Timeout or Pending). Resume with sourceChain='Ethereum' once funds arrive.",
3386
+ attestation: cctpResult.attestation?.attestation || ""
3387
+ }
3388
+ };
3389
+ }
2609
3390
  }
2610
- return this.sendBatchTransaction(txs);
2611
- }
2612
- }
2613
- throw new Error(`Insufficient funds.`);
2614
- }
2615
- async transfer(token, recipient, amount) {
2616
- const tokenAddress = this.getTokenAddress(token);
2617
- if (tokenAddress === "0x0000000000000000000000000000000000000000") {
2618
- return this.sendTransaction({
2619
- target: recipient,
2620
- value: amount,
2621
- data: "0x"
2622
- });
2623
- }
2624
- const data = this.tokenService.encodeTransfer(recipient, amount);
2625
- return this.sendTransaction({
2626
- target: tokenAddress,
2627
- value: 0n,
2628
- data
2629
- });
2630
- }
2631
- /**
2632
- * Approve a token for the Smart Account
2633
- */
2634
- async approveToken(token, spender, amount = 115792089237316195423570985008687907853269984665640564039457584007913129639935n) {
2635
- if (!this.owner) throw new Error("Not connected");
2636
- const support = await this.requestApprovalSupport(token, spender, amount);
2637
- if (support.type === "approve") {
2638
- const data = this.tokenService.encodeApprove(spender, amount);
2639
- if (this.walletClient) {
2640
- return await this.walletClient.sendTransaction({
2641
- account: this.walletClient.account,
2642
- to: token,
2643
- data,
2644
- chain: this.chainConfig.chain
2645
- });
2646
- }
2647
- return await window.ethereum.request({
2648
- method: "eth_sendTransaction",
2649
- params: [{
2650
- from: this.owner,
2651
- to: token,
2652
- data
2653
- }]
2654
- });
2655
- }
2656
- if (support.type === "permit") throw new Error("Permit not yet supported");
2657
- return "NOT_NEEDED";
2658
- }
2659
- // --- Core Bridge to Bundler/UserOp ---
2660
- async signUserOperation(userOp) {
2661
- if (!this.owner) throw new Error("Not connected");
2662
- const userOpHash = this.userOpBuilder.getUserOpHash(userOp);
2663
- let signature;
2664
- if (this.walletClient) {
2665
- signature = await this.walletClient.signMessage({
2666
- account: this.walletClient.account,
2667
- message: { raw: userOpHash }
2668
- // Sign hash directly
2669
- });
2670
- } else {
2671
- signature = await window.ethereum.request({
2672
- method: "personal_sign",
2673
- params: [userOpHash, this.owner]
2674
- });
2675
- }
2676
- return { ...userOp, signature };
2677
- }
2678
- async sendUserOperation(userOp) {
2679
- return this.bundlerClient.sendUserOperation(userOp);
2680
- }
2681
- async waitForUserOperation(hash, timeout = 6e4) {
2682
- return this.bundlerClient.waitForUserOperation(hash, timeout);
2683
- }
2684
- // Internal but exposed via BundlerClient originally
2685
- async requestApprovalSupport(token, spender, amount) {
2686
- if (!this.owner) throw new Error("Not connected");
2687
- return this.bundlerClient.requestApprovalSupport(token, this.owner, spender, amount);
2688
- }
2689
- // Error Decoding (Private)
2690
- decodeError(error) {
2691
- const msg = error?.message || "";
2692
- const hexMatch = msg.match(/(0x[0-9a-fA-F]+)/);
2693
- if (hexMatch) {
2694
- try {
2695
- const decoded = decodeErrorResult({
2696
- abi: [{ inputs: [{ name: "message", type: "string" }], name: "Error", type: "error" }],
2697
- data: hexMatch[0]
2698
- });
2699
- if (decoded.errorName === "Error") return new Error(`Smart Account Error: ${decoded.args[0]}`);
2700
- } catch (e) {
3391
+ return {
3392
+ success: false,
3393
+ errorReason: "Unsupported Route for Unichain->Stacks Helper"
3394
+ };
2701
3395
  }
2702
- }
2703
- if (msg.includes("AA21")) return new Error("Smart Account: Native transfer failed (ETH missing?)");
2704
- if (msg.includes("AA25")) return new Error("Smart Account: Invalid account nonce");
2705
- return error instanceof Error ? error : new Error(String(error));
2706
- }
2707
- // Getters
2708
- getOwner() {
2709
- return this.owner;
2710
- }
2711
- getSmartAccount() {
2712
- return this.smartAccountAddress;
3396
+ };
2713
3397
  }
2714
- };
3398
+ });
3399
+
3400
+ // src/index.ts
3401
+ init_AccountAbstraction();
3402
+ init_BundlerClient();
3403
+ init_Base();
3404
+ init_Avalanche();
3405
+ init_Optimism();
2715
3406
 
2716
3407
  // src/chains.ts
2717
3408
  init_Base();
@@ -2805,7 +3496,11 @@ var CHAIN_CONFIGS = {
2805
3496
  [monad.id]: MONAD_MAINNET,
2806
3497
  9e3: STELLAR_MAINNET
2807
3498
  };
3499
+
3500
+ // src/index.ts
3501
+ init_constants();
2808
3502
  var CHAIN_ID_TO_KEY = {
3503
+ [mainnet.id]: "Ethereum",
2809
3504
  [base.id]: "Base",
2810
3505
  [baseSepolia.id]: "Base",
2811
3506
  [gnosis.id]: "Gnosis",
@@ -2827,75 +3522,9 @@ init_TransferManager();
2827
3522
  init_near();
2828
3523
  init_cctp2();
2829
3524
  init_stargate();
2830
- var SWAP_ROUTER_02 = "0x2626664c2603336E57B271c5C0b26F421741e481";
2831
- var QUOTER_V2 = "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a";
2832
- var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
2833
- var WETH_ADDRESS = "0x4200000000000000000000000000000000000006";
2834
- var QUOTER_ABI = parseAbi([
2835
- "function quoteExactOutputSingle((address tokenIn, address tokenOut, uint256 amount, uint24 fee, uint160 sqrtPriceLimitX96) params) external returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
2836
- ]);
2837
- var ROUTER_ABI = parseAbi([
2838
- "function exactOutputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 amountOut, uint256 amountInMaximum, uint160 sqrtPriceLimitX96) params) external payable returns (uint256 amountIn)"
2839
- ]);
2840
- var UniswapService = class {
2841
- constructor(rpcUrl) {
2842
- this.publicClient = createPublicClient({
2843
- transport: http(rpcUrl)
2844
- });
2845
- }
2846
- /**
2847
- * Quote USDC needed for exact ETH output using Uniswap V3
2848
- */
2849
- async quoteUSDCForETH(amountOutETH) {
2850
- try {
2851
- const result = await this.publicClient.readContract({
2852
- address: QUOTER_V2,
2853
- abi: QUOTER_ABI,
2854
- functionName: "quoteExactOutputSingle",
2855
- args: [{
2856
- tokenIn: USDC_ADDRESS,
2857
- tokenOut: WETH_ADDRESS,
2858
- amount: amountOutETH,
2859
- fee: 500,
2860
- // 0.05%
2861
- sqrtPriceLimitX96: 0n
2862
- }]
2863
- });
2864
- const amountIn = result[0];
2865
- return amountIn * 105n / 100n;
2866
- } catch (error) {
2867
- console.error("Failed to quote USDC for ETH swap on Uniswap V3", error);
2868
- throw new Error(`Failed to quote USDC for ETH swap on Uniswap V3`);
2869
- }
2870
- }
2871
- /**
2872
- * Build tx data for swapping USDC -> ETH using Uniswap V3 SwapRouter02
2873
- */
2874
- buildSwapData(recipient, amountInMax, amountOutETH) {
2875
- return encodeFunctionData({
2876
- abi: ROUTER_ABI,
2877
- functionName: "exactOutputSingle",
2878
- args: [{
2879
- tokenIn: USDC_ADDRESS,
2880
- tokenOut: WETH_ADDRESS,
2881
- fee: 500,
2882
- // 0.05%
2883
- recipient,
2884
- amountOut: amountOutETH,
2885
- amountInMaximum: amountInMax,
2886
- sqrtPriceLimitX96: 0n
2887
- }]
2888
- });
2889
- }
2890
- getRouterAddress() {
2891
- return SWAP_ROUTER_02;
2892
- }
2893
- getUSDCAddress() {
2894
- return USDC_ADDRESS;
2895
- }
2896
- };
2897
- var uniswapService = new UniswapService("https://mainnet.base.org");
3525
+ init_uniswap();
3526
+ init_Router();
2898
3527
 
2899
- export { AccountAbstraction, BASE_MAINNET, BASE_SEPOLIA2 as BASE_SEPOLIA, BundlerClient, CCTPStrategy, CHAIN_CONFIGS, CHAIN_ID_TO_KEY, GNOSIS_MAINNET, NearStrategy, OPTIMISM_MAINNET, STELLAR, STELLAR_MAINNET, StargateStrategy, StellarService, TransferManager, UniswapService, entryPointAbi, erc20Abi, getNearSimulation, getStargateSimulation, smartAccountAbi, uniswapService };
3528
+ export { ARBITRUM_MAINNET, AVALANCHE, AVALANCHE_MAINNET, AccountAbstraction, BASE, BASE_MAINNET, BASE_SEPOLIA2 as BASE_SEPOLIA, BSC_MAINNET, BundlerClient, CCTPStrategy, CHAIN_CONFIGS, CHAIN_ID_TO_KEY, GNOSIS_MAINNET, MONAD_MAINNET, NearStrategy, OPTIMISM, OPTIMISM_MAINNET, POLYGON_MAINNET, RouterService, STELLAR, STELLAR_MAINNET, StargateStrategy, StellarService, TransferManager, UNICHAIN_MAINNET, UniswapService, entryPointAbi, erc20Abi, getNearQuote, getNearSimulation, getStargateSimulation, smartAccountAbi, uniswapService };
2900
3529
  //# sourceMappingURL=index.mjs.map
2901
3530
  //# sourceMappingURL=index.mjs.map