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