@1llet.xyz/erc4337-gasless-sdk 0.4.72 → 0.4.73
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 +8 -13
- package/dist/index.d.ts +8 -13
- package/dist/index.js +1130 -1213
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1121 -1212
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var viem = require('viem');
|
|
4
|
-
var accounts = require('viem/accounts');
|
|
5
3
|
var chains = require('viem/chains');
|
|
6
4
|
var StellarSdk = require('stellar-sdk');
|
|
7
5
|
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
|
+
var c32check = require('c32check');
|
|
9
10
|
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
12
|
|
|
@@ -40,858 +41,6 @@ var __export = (target, all) => {
|
|
|
40
41
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
41
42
|
};
|
|
42
43
|
|
|
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
|
-
|
|
895
44
|
// src/constants/bundler.ts
|
|
896
45
|
var DEFAULT_BUNDLER_URL, BUNDLER_URL;
|
|
897
46
|
var init_bundler = __esm({
|
|
@@ -1115,6 +264,43 @@ var init_Optimism = __esm({
|
|
|
1115
264
|
};
|
|
1116
265
|
}
|
|
1117
266
|
});
|
|
267
|
+
exports.UNICHAIN = void 0;
|
|
268
|
+
var init_Unichain = __esm({
|
|
269
|
+
"src/chains/Evm/Unichain.ts"() {
|
|
270
|
+
init_bundler();
|
|
271
|
+
exports.UNICHAIN = {
|
|
272
|
+
assets: [
|
|
273
|
+
{
|
|
274
|
+
name: "USDC",
|
|
275
|
+
decimals: 6,
|
|
276
|
+
address: "0x078D782b760474a361dDA0AF3839290b0EF57AD6",
|
|
277
|
+
coingeckoId: "usd-coin"
|
|
278
|
+
}
|
|
279
|
+
],
|
|
280
|
+
evm: {
|
|
281
|
+
chain: chains.unichain,
|
|
282
|
+
rpcUrl: "https://unichain-mainnet.g.alchemy.com/v2/49fUGmuW05ynCui0VEvDN",
|
|
283
|
+
bundlerUrl: `${BUNDLER_URL}/rpc?chain=unichain`,
|
|
284
|
+
supports7702: true,
|
|
285
|
+
erc4337: false,
|
|
286
|
+
entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
287
|
+
factoryAddress: "0xB2E45aCbB68f3e98C87B6df16625f22e11728556",
|
|
288
|
+
paymasterAddress: "0x7A92b3Fee017E3E181a51D9045AACE30eC2B387D"
|
|
289
|
+
},
|
|
290
|
+
crossChainInformation: {
|
|
291
|
+
circleInformation: {
|
|
292
|
+
supportCirclePaymaster: true,
|
|
293
|
+
cCTPInformation: {
|
|
294
|
+
supportCCTP: true,
|
|
295
|
+
domain: 10
|
|
296
|
+
},
|
|
297
|
+
aproxFromFee: 0
|
|
298
|
+
},
|
|
299
|
+
nearIntentInformation: null
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
});
|
|
1118
304
|
var GNOSIS;
|
|
1119
305
|
var init_Gnosis = __esm({
|
|
1120
306
|
"src/chains/Evm/Gnosis.ts"() {
|
|
@@ -1438,43 +624,6 @@ var init_Arbitrum = __esm({
|
|
|
1438
624
|
};
|
|
1439
625
|
}
|
|
1440
626
|
});
|
|
1441
|
-
var UNICHAIN;
|
|
1442
|
-
var init_Unichain = __esm({
|
|
1443
|
-
"src/chains/Evm/Unichain.ts"() {
|
|
1444
|
-
init_bundler();
|
|
1445
|
-
UNICHAIN = {
|
|
1446
|
-
assets: [
|
|
1447
|
-
{
|
|
1448
|
-
name: "USDC",
|
|
1449
|
-
decimals: 6,
|
|
1450
|
-
address: "0x078D782b760474a361dDA0AF3839290b0EF57AD6",
|
|
1451
|
-
coingeckoId: "usd-coin"
|
|
1452
|
-
}
|
|
1453
|
-
],
|
|
1454
|
-
evm: {
|
|
1455
|
-
chain: chains.unichain,
|
|
1456
|
-
rpcUrl: "https://unichain-mainnet.g.alchemy.com/v2/49fUGmuW05ynCui0VEvDN",
|
|
1457
|
-
bundlerUrl: `${BUNDLER_URL}/rpc?chain=unichain`,
|
|
1458
|
-
supports7702: true,
|
|
1459
|
-
erc4337: false,
|
|
1460
|
-
entryPointAddress: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
1461
|
-
factoryAddress: "0xB2E45aCbB68f3e98C87B6df16625f22e11728556",
|
|
1462
|
-
paymasterAddress: "0x7A92b3Fee017E3E181a51D9045AACE30eC2B387D"
|
|
1463
|
-
},
|
|
1464
|
-
crossChainInformation: {
|
|
1465
|
-
circleInformation: {
|
|
1466
|
-
supportCirclePaymaster: true,
|
|
1467
|
-
cCTPInformation: {
|
|
1468
|
-
supportCCTP: true,
|
|
1469
|
-
domain: 10
|
|
1470
|
-
},
|
|
1471
|
-
aproxFromFee: 0
|
|
1472
|
-
},
|
|
1473
|
-
nearIntentInformation: null
|
|
1474
|
-
}
|
|
1475
|
-
};
|
|
1476
|
-
}
|
|
1477
|
-
});
|
|
1478
627
|
var Monad;
|
|
1479
628
|
var init_Monad = __esm({
|
|
1480
629
|
"src/chains/Evm/Monad.ts"() {
|
|
@@ -1592,6 +741,34 @@ var init_Stellar = __esm({
|
|
|
1592
741
|
}
|
|
1593
742
|
});
|
|
1594
743
|
|
|
744
|
+
// src/chains/NoEvm/Stacks.ts
|
|
745
|
+
var STACKS;
|
|
746
|
+
var init_Stacks = __esm({
|
|
747
|
+
"src/chains/NoEvm/Stacks.ts"() {
|
|
748
|
+
STACKS = {
|
|
749
|
+
assets: [
|
|
750
|
+
{
|
|
751
|
+
name: "USDC",
|
|
752
|
+
decimals: 6,
|
|
753
|
+
address: "SP2ZNGJ15SD91GWW54B2Q1V31749666c2Q01",
|
|
754
|
+
// Placeholder or real Stacks token ID
|
|
755
|
+
coingeckoId: "usd-coin"
|
|
756
|
+
}
|
|
757
|
+
],
|
|
758
|
+
nonEvm: {
|
|
759
|
+
serverURL: "https://api.mainnet.hiro.so"
|
|
760
|
+
},
|
|
761
|
+
crossChainInformation: {
|
|
762
|
+
circleInformation: {
|
|
763
|
+
supportCirclePaymaster: false,
|
|
764
|
+
aproxFromFee: 0
|
|
765
|
+
},
|
|
766
|
+
nearIntentInformation: null
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
|
|
1595
772
|
// src/services/StellarService.ts
|
|
1596
773
|
var StellarService_exports = {};
|
|
1597
774
|
__export(StellarService_exports, {
|
|
@@ -2068,6 +1245,7 @@ var init_chains = __esm({
|
|
|
2068
1245
|
init_Binance();
|
|
2069
1246
|
init_Gnosis();
|
|
2070
1247
|
init_Ethereum();
|
|
1248
|
+
init_Stacks();
|
|
2071
1249
|
}
|
|
2072
1250
|
});
|
|
2073
1251
|
|
|
@@ -2080,7 +1258,7 @@ var init_chainsInformation = __esm({
|
|
|
2080
1258
|
Optimism: exports.OPTIMISM,
|
|
2081
1259
|
Arbitrum: ARBITRUM,
|
|
2082
1260
|
Base: exports.BASE,
|
|
2083
|
-
Unichain: UNICHAIN,
|
|
1261
|
+
Unichain: exports.UNICHAIN,
|
|
2084
1262
|
Polygon: POLYGON,
|
|
2085
1263
|
Avalanche: exports.AVALANCHE,
|
|
2086
1264
|
WorldChain: WORLD_CHAIN,
|
|
@@ -2335,7 +1513,7 @@ async function executeCCTPBridge(sourceChain, amount, crossChainConfig, facilita
|
|
|
2335
1513
|
mintTransactionHash: mintHash,
|
|
2336
1514
|
payer: payerAddress,
|
|
2337
1515
|
fee: fee.toString(),
|
|
2338
|
-
netAmount: amountBigInt.toString(),
|
|
1516
|
+
netAmount: (amountBigInt - fee).toString(),
|
|
2339
1517
|
attestation: {
|
|
2340
1518
|
message: attestationResponse.message,
|
|
2341
1519
|
attestation: attestationResponse.attestation
|
|
@@ -2398,14 +1576,6 @@ var init_cctp2 = __esm({
|
|
|
2398
1576
|
};
|
|
2399
1577
|
}
|
|
2400
1578
|
});
|
|
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
|
-
});
|
|
2409
1579
|
async function getNearQuote(sourceChain, destChain, amount, destToken, sourceToken, recipient, senderAddress, options) {
|
|
2410
1580
|
const sourceConfig = NETWORKS[sourceChain];
|
|
2411
1581
|
const destConfig = NETWORKS[destChain];
|
|
@@ -2854,7 +2024,8 @@ var init_stacks = __esm({
|
|
|
2854
2024
|
{ "internalType": "uint32", "name": "remoteDomain", "type": "uint32" },
|
|
2855
2025
|
{ "internalType": "bytes32", "name": "remoteRecipient", "type": "bytes32" },
|
|
2856
2026
|
{ "internalType": "address", "name": "localToken", "type": "address" },
|
|
2857
|
-
{ "internalType": "uint256", "name": "maxFee", "type": "uint256" }
|
|
2027
|
+
{ "internalType": "uint256", "name": "maxFee", "type": "uint256" },
|
|
2028
|
+
{ "internalType": "bytes", "name": "hookData", "type": "bytes" }
|
|
2858
2029
|
],
|
|
2859
2030
|
"name": "depositToRemote",
|
|
2860
2031
|
"outputs": [],
|
|
@@ -2892,8 +2063,20 @@ var init_stacks = __esm({
|
|
|
2892
2063
|
chain: networkConfig.evm.chain,
|
|
2893
2064
|
transport: viem.http(networkConfig.evm.rpcUrl)
|
|
2894
2065
|
});
|
|
2895
|
-
const
|
|
2066
|
+
const ethAssets = NETWORKS["Ethereum"].assets;
|
|
2067
|
+
const usdcToken = ethAssets.find((a) => a.name === "USDC");
|
|
2068
|
+
if (!usdcToken || !usdcToken.address) throw new Error("USDC config/address not found for Ethereum");
|
|
2069
|
+
const usdcAddress = viem.getAddress(usdcToken.address);
|
|
2896
2070
|
const amountBigInt = viem.parseUnits(amount, 6);
|
|
2071
|
+
const balance = await publicClient.readContract({
|
|
2072
|
+
address: usdcAddress,
|
|
2073
|
+
abi: viem.erc20Abi,
|
|
2074
|
+
functionName: "balanceOf",
|
|
2075
|
+
args: [account.address]
|
|
2076
|
+
});
|
|
2077
|
+
if (balance < amountBigInt) {
|
|
2078
|
+
throw new Error(`Insufficient USDC balance on Ethereum (Facilitator). Has: ${balance}, Needed: ${amountBigInt}`);
|
|
2079
|
+
}
|
|
2897
2080
|
const allowance = await publicClient.readContract({
|
|
2898
2081
|
address: usdcAddress,
|
|
2899
2082
|
abi: viem.erc20Abi,
|
|
@@ -2918,9 +2101,10 @@ var init_stacks = __esm({
|
|
|
2918
2101
|
recipientBytes32 = viem.padHex(recipient, { size: 32 });
|
|
2919
2102
|
} else {
|
|
2920
2103
|
try {
|
|
2921
|
-
|
|
2104
|
+
const [version, hash2] = c32check.c32addressDecode(recipient);
|
|
2105
|
+
recipientBytes32 = viem.padHex(`0x${hash2}`, { size: 32 });
|
|
2922
2106
|
} catch (e) {
|
|
2923
|
-
throw new Error(
|
|
2107
|
+
throw new Error(`Invalid Stacks Recipient: ${e.message}`);
|
|
2924
2108
|
}
|
|
2925
2109
|
}
|
|
2926
2110
|
console.log(`[Stacks] Depositing ${amount} USDC to ${recipient} (Domain ${REMOTE_DOMAIN_STACKS})...`);
|
|
@@ -2933,8 +2117,10 @@ var init_stacks = __esm({
|
|
|
2933
2117
|
REMOTE_DOMAIN_STACKS,
|
|
2934
2118
|
recipientBytes32,
|
|
2935
2119
|
usdcAddress,
|
|
2936
|
-
0n
|
|
2937
|
-
// maxFee
|
|
2120
|
+
0n,
|
|
2121
|
+
// maxFee
|
|
2122
|
+
"0x"
|
|
2123
|
+
// hookData
|
|
2938
2124
|
],
|
|
2939
2125
|
chain: networkConfig.evm.chain
|
|
2940
2126
|
});
|
|
@@ -3032,109 +2218,13 @@ var init_Router = __esm({
|
|
|
3032
2218
|
} catch (e) {
|
|
3033
2219
|
onLog(`[Router] Polling check failed (retrying): ${e.message}`);
|
|
3034
2220
|
}
|
|
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");
|
|
2221
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
2222
|
+
elapsed += interval;
|
|
2223
|
+
if (elapsed % 2e4 === 0) onLog(`[Router] Still waiting... (${Math.floor(elapsed / 1e3)}s)`);
|
|
3096
2224
|
}
|
|
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;
|
|
2225
|
+
return false;
|
|
3135
2226
|
}
|
|
3136
2227
|
};
|
|
3137
|
-
exports.uniswapService = new exports.UniswapService();
|
|
3138
2228
|
}
|
|
3139
2229
|
});
|
|
3140
2230
|
|
|
@@ -3143,7 +2233,7 @@ var TransferManager_exports = {};
|
|
|
3143
2233
|
__export(TransferManager_exports, {
|
|
3144
2234
|
TransferManager: () => exports.TransferManager
|
|
3145
2235
|
});
|
|
3146
|
-
|
|
2236
|
+
exports.TransferManager = void 0;
|
|
3147
2237
|
var init_TransferManager = __esm({
|
|
3148
2238
|
"src/services/TransferManager.ts"() {
|
|
3149
2239
|
init_cctp2();
|
|
@@ -3151,23 +2241,7 @@ var init_TransferManager = __esm({
|
|
|
3151
2241
|
init_stargate();
|
|
3152
2242
|
init_stacks();
|
|
3153
2243
|
init_Router();
|
|
3154
|
-
|
|
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
|
-
};
|
|
2244
|
+
init_chainsInformation();
|
|
3171
2245
|
exports.TransferManager = class {
|
|
3172
2246
|
constructor() {
|
|
3173
2247
|
this.strategies = [
|
|
@@ -3194,6 +2268,24 @@ var init_TransferManager = __esm({
|
|
|
3194
2268
|
}
|
|
3195
2269
|
};
|
|
3196
2270
|
}
|
|
2271
|
+
if (context.destChain === "Stacks" && context.sourceChain !== "Ethereum") {
|
|
2272
|
+
const networkConfig = NETWORKS[context.sourceChain];
|
|
2273
|
+
if (networkConfig?.crossChainInformation?.circleInformation?.cCTPInformation?.supportCCTP) {
|
|
2274
|
+
log(`[TransferManager] Auto-Routing to Stacks via CCTP (${context.sourceChain} -> Ethereum -> Stacks)`);
|
|
2275
|
+
if (!context.sourceAA || !context.facilitatorPrivateKey) {
|
|
2276
|
+
return {
|
|
2277
|
+
success: false,
|
|
2278
|
+
errorReason: "Source AA and Facilitator Private Key required for Stacks Multi-Hop"
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
return this.executeEVMToStacks(
|
|
2282
|
+
context,
|
|
2283
|
+
context.sourceAA,
|
|
2284
|
+
context.facilitatorPrivateKey,
|
|
2285
|
+
logCallback
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
3197
2289
|
const strategies = this.strategies;
|
|
3198
2290
|
const stargateStrategy = strategies.find((s) => s instanceof exports.StargateStrategy);
|
|
3199
2291
|
if (stargateStrategy && stargateStrategy.canHandle(context)) {
|
|
@@ -3216,144 +2308,13 @@ var init_TransferManager = __esm({
|
|
|
3216
2308
|
};
|
|
3217
2309
|
}
|
|
3218
2310
|
/**
|
|
3219
|
-
*
|
|
3220
|
-
*
|
|
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");
|
|
3238
|
-
} else {
|
|
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");
|
|
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);
|
|
3348
|
-
}
|
|
3349
|
-
/**
|
|
3350
|
-
* Specialized method for Unichain -> Stacks flow.
|
|
3351
|
-
* 1. Unichain -> Ethereum (CCTP)
|
|
2311
|
+
* Specialized method for Base/Unichain -> Stacks flow.
|
|
2312
|
+
* 1. EVM (Base/Unichain) -> Ethereum (CCTP)
|
|
3352
2313
|
* 2. Ethereum -> Stacks (Stacks Bridge)
|
|
3353
2314
|
*/
|
|
3354
|
-
async
|
|
2315
|
+
async executeEVMToStacks(context, sourceAA, ethPrivateKey, logCallback) {
|
|
3355
2316
|
const log = logCallback || console.log;
|
|
3356
|
-
log(
|
|
2317
|
+
log(`[TransferManager] Starting ${context.sourceChain} -> Stacks Flow...`);
|
|
3357
2318
|
const cctpStrategy = this.strategies.find((s) => s instanceof exports.CCTPStrategy);
|
|
3358
2319
|
const stacksStrategy = this.strategies.find((s) => s instanceof StacksStrategy);
|
|
3359
2320
|
if (context.sourceChain === "Ethereum") {
|
|
@@ -3363,70 +2324,930 @@ var init_TransferManager = __esm({
|
|
|
3363
2324
|
facilitatorPrivateKey: ethPrivateKey
|
|
3364
2325
|
});
|
|
3365
2326
|
}
|
|
3366
|
-
|
|
3367
|
-
|
|
2327
|
+
const sourceConfig = NETWORKS[context.sourceChain];
|
|
2328
|
+
const supportsCCTP = sourceConfig?.crossChainInformation?.circleInformation?.cCTPInformation?.supportCCTP;
|
|
2329
|
+
if (supportsCCTP) {
|
|
2330
|
+
log(`[TransferManager] Step 1: ${context.sourceChain} -> Ethereum (via CCTP)`);
|
|
3368
2331
|
const ethAccount = accounts.privateKeyToAccount(ethPrivateKey);
|
|
3369
2332
|
const ethAddress = ethAccount.address;
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
2333
|
+
log(`[TransferManager] Funding Facilitator (${ethAddress})...`);
|
|
2334
|
+
try {
|
|
2335
|
+
const amountBigInt = viem.parseUnits(context.amount, 6);
|
|
2336
|
+
const executeFunding = async () => {
|
|
2337
|
+
try {
|
|
2338
|
+
return await sourceAA.smartTransfer(
|
|
2339
|
+
"USDC",
|
|
2340
|
+
ethAddress,
|
|
2341
|
+
amountBigInt
|
|
2342
|
+
);
|
|
2343
|
+
} catch (e) {
|
|
2344
|
+
const msg = e.message || String(e);
|
|
2345
|
+
if (msg.includes("Approval required")) {
|
|
2346
|
+
log("[TransferManager] Approval Required. Approving USDC...");
|
|
2347
|
+
const saAddress = await sourceAA.getSmartAccount();
|
|
2348
|
+
if (!saAddress) throw new Error("SA Address missing for approval");
|
|
2349
|
+
await sourceAA.approveToken(sourceAA.getTokenAddress("USDC"), saAddress, amountBigInt);
|
|
2350
|
+
log("[TransferManager] Approved. Retrying Transfer...");
|
|
2351
|
+
return await sourceAA.smartTransfer(
|
|
2352
|
+
"USDC",
|
|
2353
|
+
ethAddress,
|
|
2354
|
+
amountBigInt
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
throw e;
|
|
2358
|
+
}
|
|
2359
|
+
};
|
|
2360
|
+
const transferResult = await executeFunding();
|
|
2361
|
+
if ("success" in transferResult && !transferResult.success) {
|
|
2362
|
+
throw new Error("Funding Transfer Failed");
|
|
2363
|
+
}
|
|
2364
|
+
const fundingHash = transferResult.receipt.transactionHash;
|
|
2365
|
+
log(`[TransferManager] Funds Sent. Hash: ${fundingHash}`);
|
|
2366
|
+
const cctpResult = await cctpStrategy.execute({
|
|
3386
2367
|
...context,
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
2368
|
+
destChain: "Ethereum",
|
|
2369
|
+
destToken: "USDC",
|
|
2370
|
+
recipient: ethAddress,
|
|
2371
|
+
facilitatorPrivateKey: ethPrivateKey,
|
|
2372
|
+
depositTxHash: fundingHash
|
|
3392
2373
|
});
|
|
2374
|
+
if (!cctpResult.success) {
|
|
2375
|
+
return cctpResult;
|
|
2376
|
+
}
|
|
2377
|
+
log("[TransferManager] CCTP Step Initiated.");
|
|
2378
|
+
if (cctpResult.mintTransactionHash) {
|
|
2379
|
+
log("[TransferManager] CCTP Complete (Funds on Ethereum). Proceeding to Stacks Step...");
|
|
2380
|
+
const stacksResult = await stacksStrategy.execute({
|
|
2381
|
+
...context,
|
|
2382
|
+
sourceChain: "Ethereum",
|
|
2383
|
+
amount: cctpResult.netAmount ? viem.formatUnits(BigInt(cctpResult.netAmount), 6) : context.amount,
|
|
2384
|
+
facilitatorPrivateKey: ethPrivateKey
|
|
2385
|
+
});
|
|
2386
|
+
return {
|
|
2387
|
+
success: stacksResult.success,
|
|
2388
|
+
transactionHash: stacksResult.transactionHash,
|
|
2389
|
+
data: {
|
|
2390
|
+
fundingStep: { transactionHash: fundingHash },
|
|
2391
|
+
cctpStep: cctpResult,
|
|
2392
|
+
stacksStep: stacksResult
|
|
2393
|
+
},
|
|
2394
|
+
netAmount: stacksResult.netAmount,
|
|
2395
|
+
errorReason: stacksResult.errorReason
|
|
2396
|
+
};
|
|
2397
|
+
} else {
|
|
2398
|
+
log("[TransferManager] CCTP Pending. Please resume later.");
|
|
2399
|
+
return {
|
|
2400
|
+
...cctpResult,
|
|
2401
|
+
attestation: {
|
|
2402
|
+
message: "CCTP Initiated but not finalized.",
|
|
2403
|
+
attestation: cctpResult.attestation?.attestation || ""
|
|
2404
|
+
}
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
} catch (err) {
|
|
3393
2408
|
return {
|
|
3394
|
-
success:
|
|
3395
|
-
|
|
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
|
-
}
|
|
2409
|
+
success: false,
|
|
2410
|
+
errorReason: `Funding/CCTP Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
3412
2411
|
};
|
|
3413
2412
|
}
|
|
3414
2413
|
}
|
|
3415
2414
|
return {
|
|
3416
2415
|
success: false,
|
|
3417
|
-
errorReason:
|
|
2416
|
+
errorReason: `Unsupported Route for ${context.sourceChain}->Stacks Helper`
|
|
3418
2417
|
};
|
|
3419
2418
|
}
|
|
3420
2419
|
};
|
|
3421
2420
|
}
|
|
3422
2421
|
});
|
|
3423
2422
|
|
|
2423
|
+
// src/constants.ts
|
|
2424
|
+
var factoryAbi = [
|
|
2425
|
+
{
|
|
2426
|
+
inputs: [
|
|
2427
|
+
{ name: "owner", type: "address" },
|
|
2428
|
+
{ name: "salt", type: "uint256" }
|
|
2429
|
+
],
|
|
2430
|
+
name: "getAccountAddress",
|
|
2431
|
+
outputs: [{ name: "", type: "address" }],
|
|
2432
|
+
stateMutability: "view",
|
|
2433
|
+
type: "function"
|
|
2434
|
+
},
|
|
2435
|
+
{
|
|
2436
|
+
inputs: [
|
|
2437
|
+
{ name: "owner", type: "address" },
|
|
2438
|
+
{ name: "salt", type: "uint256" }
|
|
2439
|
+
],
|
|
2440
|
+
name: "isAccountDeployed",
|
|
2441
|
+
outputs: [{ name: "", type: "bool" }],
|
|
2442
|
+
stateMutability: "view",
|
|
2443
|
+
type: "function"
|
|
2444
|
+
},
|
|
2445
|
+
{
|
|
2446
|
+
inputs: [
|
|
2447
|
+
{ name: "owner", type: "address" },
|
|
2448
|
+
{ name: "salt", type: "uint256" }
|
|
2449
|
+
],
|
|
2450
|
+
name: "createAccount",
|
|
2451
|
+
outputs: [{ name: "account", type: "address" }],
|
|
2452
|
+
stateMutability: "nonpayable",
|
|
2453
|
+
type: "function"
|
|
2454
|
+
}
|
|
2455
|
+
];
|
|
2456
|
+
var entryPointAbi = [
|
|
2457
|
+
{
|
|
2458
|
+
inputs: [
|
|
2459
|
+
{ name: "sender", type: "address" },
|
|
2460
|
+
{ name: "key", type: "uint192" }
|
|
2461
|
+
],
|
|
2462
|
+
name: "getNonce",
|
|
2463
|
+
outputs: [{ name: "nonce", type: "uint256" }],
|
|
2464
|
+
stateMutability: "view",
|
|
2465
|
+
type: "function"
|
|
2466
|
+
}
|
|
2467
|
+
];
|
|
2468
|
+
var smartAccountAbi = [
|
|
2469
|
+
{
|
|
2470
|
+
inputs: [
|
|
2471
|
+
{ name: "target", type: "address" },
|
|
2472
|
+
{ name: "value", type: "uint256" },
|
|
2473
|
+
{ name: "data", type: "bytes" }
|
|
2474
|
+
],
|
|
2475
|
+
name: "execute",
|
|
2476
|
+
outputs: [],
|
|
2477
|
+
stateMutability: "nonpayable",
|
|
2478
|
+
type: "function"
|
|
2479
|
+
},
|
|
2480
|
+
{
|
|
2481
|
+
inputs: [
|
|
2482
|
+
{ name: "targets", type: "address[]" },
|
|
2483
|
+
{ name: "values", type: "uint256[]" },
|
|
2484
|
+
{ name: "datas", type: "bytes[]" }
|
|
2485
|
+
],
|
|
2486
|
+
name: "executeBatch",
|
|
2487
|
+
outputs: [],
|
|
2488
|
+
stateMutability: "nonpayable",
|
|
2489
|
+
type: "function"
|
|
2490
|
+
}
|
|
2491
|
+
];
|
|
2492
|
+
var erc20Abi = [
|
|
2493
|
+
{
|
|
2494
|
+
inputs: [{ name: "account", type: "address" }],
|
|
2495
|
+
name: "balanceOf",
|
|
2496
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
2497
|
+
stateMutability: "view",
|
|
2498
|
+
type: "function"
|
|
2499
|
+
},
|
|
2500
|
+
{
|
|
2501
|
+
inputs: [
|
|
2502
|
+
{ name: "to", type: "address" },
|
|
2503
|
+
{ name: "amount", type: "uint256" }
|
|
2504
|
+
],
|
|
2505
|
+
name: "transfer",
|
|
2506
|
+
outputs: [{ name: "", type: "bool" }],
|
|
2507
|
+
stateMutability: "nonpayable",
|
|
2508
|
+
type: "function"
|
|
2509
|
+
},
|
|
2510
|
+
{
|
|
2511
|
+
inputs: [
|
|
2512
|
+
{ name: "spender", type: "address" },
|
|
2513
|
+
{ name: "amount", type: "uint256" }
|
|
2514
|
+
],
|
|
2515
|
+
name: "approve",
|
|
2516
|
+
outputs: [{ name: "", type: "bool" }],
|
|
2517
|
+
stateMutability: "nonpayable",
|
|
2518
|
+
type: "function"
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
inputs: [
|
|
2522
|
+
{ name: "owner", type: "address" },
|
|
2523
|
+
{ name: "spender", type: "address" }
|
|
2524
|
+
],
|
|
2525
|
+
name: "allowance",
|
|
2526
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
2527
|
+
stateMutability: "view",
|
|
2528
|
+
type: "function"
|
|
2529
|
+
},
|
|
2530
|
+
{
|
|
2531
|
+
inputs: [
|
|
2532
|
+
{ name: "from", type: "address" },
|
|
2533
|
+
{ name: "to", type: "address" },
|
|
2534
|
+
{ name: "amount", type: "uint256" }
|
|
2535
|
+
],
|
|
2536
|
+
name: "transferFrom",
|
|
2537
|
+
outputs: [{ name: "", type: "bool" }],
|
|
2538
|
+
stateMutability: "nonpayable",
|
|
2539
|
+
type: "function"
|
|
2540
|
+
},
|
|
2541
|
+
{
|
|
2542
|
+
inputs: [],
|
|
2543
|
+
name: "decimals",
|
|
2544
|
+
outputs: [{ name: "", type: "uint8" }],
|
|
2545
|
+
stateMutability: "view",
|
|
2546
|
+
type: "function"
|
|
2547
|
+
}
|
|
2548
|
+
];
|
|
2549
|
+
|
|
2550
|
+
// src/BundlerClient.ts
|
|
2551
|
+
var BundlerClient = class {
|
|
2552
|
+
constructor(config, entryPointAddress) {
|
|
2553
|
+
this.bundlerUrl = config.bundlerUrl;
|
|
2554
|
+
this.entryPointAddress = entryPointAddress;
|
|
2555
|
+
}
|
|
2556
|
+
async call(method, params) {
|
|
2557
|
+
const response = await fetch(this.bundlerUrl, {
|
|
2558
|
+
method: "POST",
|
|
2559
|
+
headers: { "Content-Type": "application/json" },
|
|
2560
|
+
body: JSON.stringify({
|
|
2561
|
+
jsonrpc: "2.0",
|
|
2562
|
+
id: 1,
|
|
2563
|
+
method,
|
|
2564
|
+
params
|
|
2565
|
+
})
|
|
2566
|
+
});
|
|
2567
|
+
const result = await response.json();
|
|
2568
|
+
if (result.error) {
|
|
2569
|
+
throw new Error(result.error.message);
|
|
2570
|
+
}
|
|
2571
|
+
return result.result;
|
|
2572
|
+
}
|
|
2573
|
+
async estimateGas(userOp) {
|
|
2574
|
+
const result = await this.call("eth_estimateUserOperationGas", [
|
|
2575
|
+
{
|
|
2576
|
+
sender: userOp.sender,
|
|
2577
|
+
nonce: userOp.nonce ? "0x" + userOp.nonce.toString(16) : "0x0",
|
|
2578
|
+
initCode: userOp.initCode || "0x",
|
|
2579
|
+
callData: userOp.callData || "0x",
|
|
2580
|
+
paymasterAndData: userOp.paymasterAndData || "0x",
|
|
2581
|
+
signature: "0x"
|
|
2582
|
+
},
|
|
2583
|
+
this.entryPointAddress
|
|
2584
|
+
]);
|
|
2585
|
+
console.log("DEBUG: estimateGas result:", result);
|
|
2586
|
+
return {
|
|
2587
|
+
callGasLimit: result.callGasLimit,
|
|
2588
|
+
verificationGasLimit: result.verificationGasLimit,
|
|
2589
|
+
preVerificationGas: result.preVerificationGas,
|
|
2590
|
+
maxFeePerGas: result.maxFeePerGas,
|
|
2591
|
+
maxPriorityFeePerGas: result.maxPriorityFeePerGas,
|
|
2592
|
+
paymasterAndData: result.paymasterAndData
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
async sendUserOperation(userOp) {
|
|
2596
|
+
return await this.call("eth_sendUserOperation", [
|
|
2597
|
+
{
|
|
2598
|
+
sender: userOp.sender,
|
|
2599
|
+
nonce: "0x" + userOp.nonce.toString(16),
|
|
2600
|
+
initCode: userOp.initCode,
|
|
2601
|
+
callData: userOp.callData,
|
|
2602
|
+
callGasLimit: "0x" + userOp.callGasLimit.toString(16),
|
|
2603
|
+
verificationGasLimit: "0x" + userOp.verificationGasLimit.toString(16),
|
|
2604
|
+
preVerificationGas: "0x" + userOp.preVerificationGas.toString(16),
|
|
2605
|
+
maxFeePerGas: "0x" + userOp.maxFeePerGas.toString(16),
|
|
2606
|
+
maxPriorityFeePerGas: "0x" + userOp.maxPriorityFeePerGas.toString(16),
|
|
2607
|
+
paymasterAndData: userOp.paymasterAndData,
|
|
2608
|
+
signature: userOp.signature
|
|
2609
|
+
},
|
|
2610
|
+
this.entryPointAddress
|
|
2611
|
+
]);
|
|
2612
|
+
}
|
|
2613
|
+
async waitForUserOperation(userOpHash, timeout = 6e4) {
|
|
2614
|
+
const startTime = Date.now();
|
|
2615
|
+
while (Date.now() - startTime < timeout) {
|
|
2616
|
+
const result = await this.call("eth_getUserOperationReceipt", [userOpHash]);
|
|
2617
|
+
if (result) {
|
|
2618
|
+
return result;
|
|
2619
|
+
}
|
|
2620
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
2621
|
+
}
|
|
2622
|
+
throw new Error("Timeout waiting for UserOperation");
|
|
2623
|
+
}
|
|
2624
|
+
async requestApprovalSupport(token, owner, spender, amount) {
|
|
2625
|
+
return await this.call("pm_requestApprovalSupport", [
|
|
2626
|
+
token,
|
|
2627
|
+
owner,
|
|
2628
|
+
spender,
|
|
2629
|
+
amount.toString()
|
|
2630
|
+
]);
|
|
2631
|
+
}
|
|
2632
|
+
async scheduleUserOp(userOp, condition) {
|
|
2633
|
+
return await this.call("bundler_scheduleUserOp", [
|
|
2634
|
+
{
|
|
2635
|
+
sender: userOp.sender,
|
|
2636
|
+
nonce: "0x" + userOp.nonce.toString(16),
|
|
2637
|
+
initCode: userOp.initCode,
|
|
2638
|
+
callData: userOp.callData,
|
|
2639
|
+
callGasLimit: "0x" + userOp.callGasLimit.toString(16),
|
|
2640
|
+
verificationGasLimit: "0x" + userOp.verificationGasLimit.toString(16),
|
|
2641
|
+
preVerificationGas: "0x" + userOp.preVerificationGas.toString(16),
|
|
2642
|
+
maxFeePerGas: "0x" + userOp.maxFeePerGas.toString(16),
|
|
2643
|
+
maxPriorityFeePerGas: "0x" + userOp.maxPriorityFeePerGas.toString(16),
|
|
2644
|
+
paymasterAndData: userOp.paymasterAndData,
|
|
2645
|
+
signature: userOp.signature
|
|
2646
|
+
},
|
|
2647
|
+
condition
|
|
2648
|
+
]);
|
|
2649
|
+
}
|
|
2650
|
+
};
|
|
2651
|
+
var TokenService = class {
|
|
2652
|
+
constructor(chainConfig, publicClient) {
|
|
2653
|
+
this.tokens = /* @__PURE__ */ new Map();
|
|
2654
|
+
this.publicClient = publicClient;
|
|
2655
|
+
chainConfig.tokens.forEach((token) => {
|
|
2656
|
+
this.tokens.set(token.symbol.toUpperCase(), token);
|
|
2657
|
+
});
|
|
2658
|
+
}
|
|
2659
|
+
/**
|
|
2660
|
+
* Resolve token address from symbol or return address if provided
|
|
2661
|
+
*/
|
|
2662
|
+
getTokenAddress(token) {
|
|
2663
|
+
if (token.startsWith("0x")) return token;
|
|
2664
|
+
const info = this.tokens.get(token.toUpperCase());
|
|
2665
|
+
if (!info) throw new Error(`Token ${token} not found in chain config`);
|
|
2666
|
+
return info.address;
|
|
2667
|
+
}
|
|
2668
|
+
/**
|
|
2669
|
+
* Get balance of a token for an account
|
|
2670
|
+
*/
|
|
2671
|
+
async getBalance(token, account) {
|
|
2672
|
+
const address = this.getTokenAddress(token);
|
|
2673
|
+
if (address === "0x0000000000000000000000000000000000000000") {
|
|
2674
|
+
return await this.publicClient.getBalance({ address: account });
|
|
2675
|
+
}
|
|
2676
|
+
return await this.publicClient.readContract({
|
|
2677
|
+
address,
|
|
2678
|
+
abi: erc20Abi,
|
|
2679
|
+
functionName: "balanceOf",
|
|
2680
|
+
args: [account]
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
/**
|
|
2684
|
+
* Get allowance (ERC-20 only)
|
|
2685
|
+
*/
|
|
2686
|
+
async getAllowance(token, owner, spender) {
|
|
2687
|
+
const address = this.getTokenAddress(token);
|
|
2688
|
+
if (address === "0x0000000000000000000000000000000000000000") {
|
|
2689
|
+
return 0n;
|
|
2690
|
+
}
|
|
2691
|
+
return await this.publicClient.readContract({
|
|
2692
|
+
address,
|
|
2693
|
+
abi: erc20Abi,
|
|
2694
|
+
functionName: "allowance",
|
|
2695
|
+
args: [owner, spender]
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Encode transfer data
|
|
2700
|
+
*/
|
|
2701
|
+
encodeTransfer(recipient, amount) {
|
|
2702
|
+
return viem.encodeFunctionData({
|
|
2703
|
+
abi: erc20Abi,
|
|
2704
|
+
functionName: "transfer",
|
|
2705
|
+
args: [recipient, amount]
|
|
2706
|
+
});
|
|
2707
|
+
}
|
|
2708
|
+
/**
|
|
2709
|
+
* Encode transferFrom data
|
|
2710
|
+
*/
|
|
2711
|
+
encodeTransferFrom(sender, recipient, amount) {
|
|
2712
|
+
return viem.encodeFunctionData({
|
|
2713
|
+
abi: erc20Abi,
|
|
2714
|
+
functionName: "transferFrom",
|
|
2715
|
+
args: [sender, recipient, amount]
|
|
2716
|
+
});
|
|
2717
|
+
}
|
|
2718
|
+
/**
|
|
2719
|
+
* Encode approve data
|
|
2720
|
+
*/
|
|
2721
|
+
encodeApprove(spender, amount) {
|
|
2722
|
+
return viem.encodeFunctionData({
|
|
2723
|
+
abi: erc20Abi,
|
|
2724
|
+
functionName: "approve",
|
|
2725
|
+
args: [spender, amount]
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
var UserOpBuilder = class {
|
|
2730
|
+
constructor(chainConfig, bundlerClient, publicClient) {
|
|
2731
|
+
this.chainConfig = chainConfig;
|
|
2732
|
+
this.bundlerClient = bundlerClient;
|
|
2733
|
+
this.publicClient = publicClient;
|
|
2734
|
+
this.entryPointAddress = chainConfig.entryPointAddress;
|
|
2735
|
+
this.factoryAddress = chainConfig.factoryAddress;
|
|
2736
|
+
}
|
|
2737
|
+
async getNonce(smartAccountAddress) {
|
|
2738
|
+
return await this.publicClient.readContract({
|
|
2739
|
+
address: this.entryPointAddress,
|
|
2740
|
+
abi: entryPointAbi,
|
|
2741
|
+
functionName: "getNonce",
|
|
2742
|
+
args: [smartAccountAddress, 0n]
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
buildInitCode(owner) {
|
|
2746
|
+
const createAccountData = viem.encodeFunctionData({
|
|
2747
|
+
abi: factoryAbi,
|
|
2748
|
+
functionName: "createAccount",
|
|
2749
|
+
args: [owner, 0n]
|
|
2750
|
+
});
|
|
2751
|
+
return `${this.factoryAddress}${createAccountData.slice(2)}`;
|
|
2752
|
+
}
|
|
2753
|
+
async isAccountDeployed(smartAccountAddress) {
|
|
2754
|
+
const code = await this.publicClient.getCode({
|
|
2755
|
+
address: smartAccountAddress
|
|
2756
|
+
});
|
|
2757
|
+
return code !== void 0 && code !== "0x";
|
|
2758
|
+
}
|
|
2759
|
+
async buildUserOperationBatch(owner, smartAccountAddress, transactions) {
|
|
2760
|
+
const isDeployed = await this.isAccountDeployed(smartAccountAddress);
|
|
2761
|
+
const initCode = isDeployed ? "0x" : this.buildInitCode(owner);
|
|
2762
|
+
const targets = transactions.map((tx) => tx.target);
|
|
2763
|
+
const values = transactions.map((tx) => tx.value);
|
|
2764
|
+
const datas = transactions.map((tx) => tx.data);
|
|
2765
|
+
const callData = viem.encodeFunctionData({
|
|
2766
|
+
abi: smartAccountAbi,
|
|
2767
|
+
functionName: "executeBatch",
|
|
2768
|
+
args: [targets, values, datas]
|
|
2769
|
+
});
|
|
2770
|
+
const nonce = await this.getNonce(smartAccountAddress);
|
|
2771
|
+
const partialOp = {
|
|
2772
|
+
sender: smartAccountAddress,
|
|
2773
|
+
nonce,
|
|
2774
|
+
initCode,
|
|
2775
|
+
callData,
|
|
2776
|
+
paymasterAndData: this.chainConfig.paymasterAddress || "0x"
|
|
2777
|
+
};
|
|
2778
|
+
const gasEstimate = await this.bundlerClient.estimateGas(partialOp);
|
|
2779
|
+
return {
|
|
2780
|
+
...partialOp,
|
|
2781
|
+
callGasLimit: BigInt(gasEstimate.callGasLimit),
|
|
2782
|
+
verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),
|
|
2783
|
+
preVerificationGas: BigInt(gasEstimate.preVerificationGas),
|
|
2784
|
+
maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
|
|
2785
|
+
maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
|
|
2786
|
+
paymasterAndData: gasEstimate.paymasterAndData || partialOp.paymasterAndData,
|
|
2787
|
+
signature: "0x"
|
|
2788
|
+
};
|
|
2789
|
+
}
|
|
2790
|
+
async buildDeployUserOp(owner, smartAccountAddress) {
|
|
2791
|
+
const isDeployed = await this.isAccountDeployed(smartAccountAddress);
|
|
2792
|
+
if (isDeployed) throw new Error("Account already deployed");
|
|
2793
|
+
const initCode = this.buildInitCode(owner);
|
|
2794
|
+
const callData = "0x";
|
|
2795
|
+
const nonce = await this.getNonce(smartAccountAddress);
|
|
2796
|
+
const partialOp = {
|
|
2797
|
+
sender: smartAccountAddress,
|
|
2798
|
+
nonce,
|
|
2799
|
+
initCode,
|
|
2800
|
+
callData,
|
|
2801
|
+
paymasterAndData: this.chainConfig.paymasterAddress || "0x"
|
|
2802
|
+
};
|
|
2803
|
+
const gasEstimate = await this.bundlerClient.estimateGas(partialOp);
|
|
2804
|
+
return {
|
|
2805
|
+
...partialOp,
|
|
2806
|
+
callGasLimit: BigInt(gasEstimate.callGasLimit),
|
|
2807
|
+
verificationGasLimit: BigInt(gasEstimate.verificationGasLimit),
|
|
2808
|
+
preVerificationGas: BigInt(gasEstimate.preVerificationGas),
|
|
2809
|
+
maxFeePerGas: BigInt(gasEstimate.maxFeePerGas),
|
|
2810
|
+
maxPriorityFeePerGas: BigInt(gasEstimate.maxPriorityFeePerGas),
|
|
2811
|
+
paymasterAndData: gasEstimate.paymasterAndData || partialOp.paymasterAndData,
|
|
2812
|
+
signature: "0x"
|
|
2813
|
+
};
|
|
2814
|
+
}
|
|
2815
|
+
getUserOpHash(userOp) {
|
|
2816
|
+
const packed = viem.encodeAbiParameters(
|
|
2817
|
+
[
|
|
2818
|
+
{ type: "address" },
|
|
2819
|
+
{ type: "uint256" },
|
|
2820
|
+
{ type: "bytes32" },
|
|
2821
|
+
{ type: "bytes32" },
|
|
2822
|
+
{ type: "uint256" },
|
|
2823
|
+
{ type: "uint256" },
|
|
2824
|
+
{ type: "uint256" },
|
|
2825
|
+
{ type: "uint256" },
|
|
2826
|
+
{ type: "uint256" },
|
|
2827
|
+
{ type: "bytes32" }
|
|
2828
|
+
],
|
|
2829
|
+
[
|
|
2830
|
+
userOp.sender,
|
|
2831
|
+
userOp.nonce,
|
|
2832
|
+
viem.keccak256(userOp.initCode),
|
|
2833
|
+
viem.keccak256(userOp.callData),
|
|
2834
|
+
userOp.callGasLimit,
|
|
2835
|
+
userOp.verificationGasLimit,
|
|
2836
|
+
userOp.preVerificationGas,
|
|
2837
|
+
userOp.maxFeePerGas,
|
|
2838
|
+
userOp.maxPriorityFeePerGas,
|
|
2839
|
+
viem.keccak256(userOp.paymasterAndData)
|
|
2840
|
+
]
|
|
2841
|
+
);
|
|
2842
|
+
const packedHash = viem.keccak256(packed);
|
|
2843
|
+
return viem.keccak256(
|
|
2844
|
+
viem.encodeAbiParameters(
|
|
2845
|
+
[{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
|
|
2846
|
+
[packedHash, this.entryPointAddress, BigInt(this.chainConfig.chain.id)]
|
|
2847
|
+
)
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
|
|
2852
|
+
// src/AccountAbstraction.ts
|
|
2853
|
+
var AccountAbstraction = class {
|
|
2854
|
+
constructor(chainConfig) {
|
|
2855
|
+
this.owner = null;
|
|
2856
|
+
this.smartAccountAddress = null;
|
|
2857
|
+
this.walletClient = null;
|
|
2858
|
+
this.chainConfig = chainConfig;
|
|
2859
|
+
if (!chainConfig.entryPointAddress) throw new Error("EntryPoint address required");
|
|
2860
|
+
this.entryPointAddress = chainConfig.entryPointAddress;
|
|
2861
|
+
if (!chainConfig.factoryAddress) throw new Error("Factory address required");
|
|
2862
|
+
this.factoryAddress = chainConfig.factoryAddress;
|
|
2863
|
+
const rpcUrl = chainConfig.rpcUrl || chainConfig.chain.rpcUrls.default.http[0];
|
|
2864
|
+
this.publicClient = viem.createPublicClient({
|
|
2865
|
+
chain: chainConfig.chain,
|
|
2866
|
+
transport: viem.http(rpcUrl)
|
|
2867
|
+
});
|
|
2868
|
+
this.bundlerClient = new BundlerClient(chainConfig, this.entryPointAddress);
|
|
2869
|
+
this.tokenService = new TokenService(chainConfig, this.publicClient);
|
|
2870
|
+
this.userOpBuilder = new UserOpBuilder(chainConfig, this.bundlerClient, this.publicClient);
|
|
2871
|
+
}
|
|
2872
|
+
getBundlerClient() {
|
|
2873
|
+
return this.bundlerClient;
|
|
2874
|
+
}
|
|
2875
|
+
getChainId() {
|
|
2876
|
+
return this.chainConfig.chain.id;
|
|
2877
|
+
}
|
|
2878
|
+
getPublicClient() {
|
|
2879
|
+
return this.publicClient;
|
|
2880
|
+
}
|
|
2881
|
+
async buildUserOperation(transaction) {
|
|
2882
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
2883
|
+
return this.userOpBuilder.buildUserOperationBatch(this.owner, this.smartAccountAddress, [transaction]);
|
|
2884
|
+
}
|
|
2885
|
+
async buildBatchUserOperation(transactions) {
|
|
2886
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
2887
|
+
return this.userOpBuilder.buildUserOperationBatch(this.owner, this.smartAccountAddress, transactions);
|
|
2888
|
+
}
|
|
2889
|
+
async connect(signer) {
|
|
2890
|
+
if (typeof signer === "string") {
|
|
2891
|
+
const account = accounts.privateKeyToAccount(signer);
|
|
2892
|
+
this.owner = account.address;
|
|
2893
|
+
const rpcUrl = this.chainConfig.rpcUrl || this.chainConfig.chain.rpcUrls.default.http[0];
|
|
2894
|
+
this.walletClient = viem.createWalletClient({
|
|
2895
|
+
account,
|
|
2896
|
+
chain: this.chainConfig.chain,
|
|
2897
|
+
transport: viem.http(rpcUrl)
|
|
2898
|
+
});
|
|
2899
|
+
} else if (signer && typeof signer === "object") {
|
|
2900
|
+
this.walletClient = signer;
|
|
2901
|
+
if (!this.walletClient.account) throw new Error("WalletClient must have an account");
|
|
2902
|
+
this.owner = this.walletClient.account.address;
|
|
2903
|
+
} else {
|
|
2904
|
+
if (typeof window === "undefined" || !window.ethereum) {
|
|
2905
|
+
throw new Error("MetaMask is not installed and no private key provided");
|
|
2906
|
+
}
|
|
2907
|
+
const accounts = await window.ethereum.request({
|
|
2908
|
+
method: "eth_requestAccounts"
|
|
2909
|
+
});
|
|
2910
|
+
if (!accounts || accounts.length === 0) throw new Error("No accounts found");
|
|
2911
|
+
const chainId = await window.ethereum.request({
|
|
2912
|
+
method: "eth_chainId"
|
|
2913
|
+
});
|
|
2914
|
+
const targetChainId = this.chainConfig.chain.id;
|
|
2915
|
+
if (parseInt(chainId, 16) !== targetChainId) {
|
|
2916
|
+
try {
|
|
2917
|
+
await window.ethereum.request({
|
|
2918
|
+
method: "wallet_switchEthereumChain",
|
|
2919
|
+
params: [{ chainId: "0x" + targetChainId.toString(16) }]
|
|
2920
|
+
});
|
|
2921
|
+
} catch (switchError) {
|
|
2922
|
+
const error = switchError;
|
|
2923
|
+
if (error.code === 4902) {
|
|
2924
|
+
await window.ethereum.request({
|
|
2925
|
+
method: "wallet_addEthereumChain",
|
|
2926
|
+
params: [
|
|
2927
|
+
{
|
|
2928
|
+
chainId: "0x" + targetChainId.toString(16),
|
|
2929
|
+
chainName: this.chainConfig.chain.name,
|
|
2930
|
+
nativeCurrency: this.chainConfig.chain.nativeCurrency,
|
|
2931
|
+
rpcUrls: [this.chainConfig.rpcUrl || this.chainConfig.chain.rpcUrls.default.http[0]],
|
|
2932
|
+
blockExplorerUrls: this.chainConfig.chain.blockExplorers?.default?.url ? [this.chainConfig.chain.blockExplorers.default.url] : []
|
|
2933
|
+
}
|
|
2934
|
+
]
|
|
2935
|
+
});
|
|
2936
|
+
} else {
|
|
2937
|
+
throw switchError;
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
this.owner = accounts[0];
|
|
2942
|
+
}
|
|
2943
|
+
this.smartAccountAddress = await this.getSmartAccountAddress(this.owner);
|
|
2944
|
+
return {
|
|
2945
|
+
owner: this.owner,
|
|
2946
|
+
smartAccount: this.smartAccountAddress
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
// --- Account Management ---
|
|
2950
|
+
async isAccountDeployed() {
|
|
2951
|
+
if (!this.smartAccountAddress) return false;
|
|
2952
|
+
const code = await this.publicClient.getBytecode({ address: this.smartAccountAddress });
|
|
2953
|
+
return code !== void 0;
|
|
2954
|
+
}
|
|
2955
|
+
async deployAccount() {
|
|
2956
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
2957
|
+
return this.sendTransaction({
|
|
2958
|
+
target: this.smartAccountAddress,
|
|
2959
|
+
value: 0n,
|
|
2960
|
+
data: "0x"
|
|
2961
|
+
});
|
|
2962
|
+
}
|
|
2963
|
+
/**
|
|
2964
|
+
* Get the Smart Account address for an owner
|
|
2965
|
+
*/
|
|
2966
|
+
async getSmartAccountAddress(owner) {
|
|
2967
|
+
try {
|
|
2968
|
+
const address = await this.publicClient.readContract({
|
|
2969
|
+
address: this.factoryAddress,
|
|
2970
|
+
abi: factoryAbi,
|
|
2971
|
+
functionName: "getAccountAddress",
|
|
2972
|
+
args: [owner, 0n]
|
|
2973
|
+
});
|
|
2974
|
+
return address;
|
|
2975
|
+
} catch (e) {
|
|
2976
|
+
try {
|
|
2977
|
+
const { result } = await this.publicClient.simulateContract({
|
|
2978
|
+
address: this.factoryAddress,
|
|
2979
|
+
abi: factoryAbi,
|
|
2980
|
+
functionName: "createAccount",
|
|
2981
|
+
args: [owner, 0n],
|
|
2982
|
+
account: "0x0000000000000000000000000000000000000000"
|
|
2983
|
+
// Zero address or random for simulation
|
|
2984
|
+
});
|
|
2985
|
+
return result;
|
|
2986
|
+
} catch (inner) {
|
|
2987
|
+
throw e;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
// --- Token Methods (Delegated) ---
|
|
2992
|
+
getTokenAddress(token) {
|
|
2993
|
+
return this.tokenService.getTokenAddress(token);
|
|
2994
|
+
}
|
|
2995
|
+
async getBalance(token) {
|
|
2996
|
+
if (!this.smartAccountAddress) throw new Error("Not connected");
|
|
2997
|
+
return this.tokenService.getBalance(token, this.smartAccountAddress);
|
|
2998
|
+
}
|
|
2999
|
+
async getEoaBalance(token) {
|
|
3000
|
+
if (!this.owner) throw new Error("Not connected");
|
|
3001
|
+
return this.tokenService.getBalance(token, this.owner);
|
|
3002
|
+
}
|
|
3003
|
+
async getAllowance(token = "USDC") {
|
|
3004
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
3005
|
+
return this.tokenService.getAllowance(token, this.owner, this.smartAccountAddress);
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Get comprehensive state of the account for a specific token
|
|
3009
|
+
* Useful for UI initialization
|
|
3010
|
+
*/
|
|
3011
|
+
async getAccountState(token) {
|
|
3012
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
3013
|
+
const tokenAddress = this.getTokenAddress(token);
|
|
3014
|
+
const isNative = tokenAddress === "0x0000000000000000000000000000000000000000";
|
|
3015
|
+
const [balance, eoaBalance, allowance, isDeployed] = await Promise.all([
|
|
3016
|
+
this.getBalance(token),
|
|
3017
|
+
this.getEoaBalance(token),
|
|
3018
|
+
isNative ? 0n : this.getAllowance(token).catch(() => 0n),
|
|
3019
|
+
// Handle native/error gracefully
|
|
3020
|
+
this.isAccountDeployed()
|
|
3021
|
+
]);
|
|
3022
|
+
return {
|
|
3023
|
+
owner: this.owner,
|
|
3024
|
+
smartAccount: this.smartAccountAddress,
|
|
3025
|
+
balance,
|
|
3026
|
+
eoaBalance,
|
|
3027
|
+
allowance,
|
|
3028
|
+
isDeployed
|
|
3029
|
+
};
|
|
3030
|
+
}
|
|
3031
|
+
// --- Transactions ---
|
|
3032
|
+
async sendTransaction(tx) {
|
|
3033
|
+
return this.sendBatchTransaction([tx]);
|
|
3034
|
+
}
|
|
3035
|
+
async sendBatchTransaction(txs) {
|
|
3036
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
3037
|
+
const transactions = txs.map((tx) => ({
|
|
3038
|
+
target: tx.target,
|
|
3039
|
+
value: tx.value ?? 0n,
|
|
3040
|
+
data: tx.data ?? "0x"
|
|
3041
|
+
}));
|
|
3042
|
+
try {
|
|
3043
|
+
const userOp = await this.userOpBuilder.buildUserOperationBatch(
|
|
3044
|
+
this.owner,
|
|
3045
|
+
this.smartAccountAddress,
|
|
3046
|
+
transactions
|
|
3047
|
+
);
|
|
3048
|
+
const signed = await this.signUserOperation(userOp);
|
|
3049
|
+
const hash = await this.sendUserOperation(signed);
|
|
3050
|
+
return await this.waitForUserOperation(hash);
|
|
3051
|
+
} catch (error) {
|
|
3052
|
+
throw this.decodeError(error);
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
async deposit(amount) {
|
|
3056
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
3057
|
+
if (this.walletClient) {
|
|
3058
|
+
return await this.walletClient.sendTransaction({
|
|
3059
|
+
account: this.walletClient.account,
|
|
3060
|
+
to: this.smartAccountAddress,
|
|
3061
|
+
value: amount,
|
|
3062
|
+
chain: this.chainConfig.chain
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
return await window.ethereum.request({
|
|
3066
|
+
method: "eth_sendTransaction",
|
|
3067
|
+
params: [{
|
|
3068
|
+
from: this.owner,
|
|
3069
|
+
to: this.smartAccountAddress,
|
|
3070
|
+
value: "0x" + amount.toString(16)
|
|
3071
|
+
}]
|
|
3072
|
+
});
|
|
3073
|
+
}
|
|
3074
|
+
/**
|
|
3075
|
+
* Smart Transfer: Automatically chooses best method (SA vs EOA) based on balances.
|
|
3076
|
+
* Supports strict fee handling.
|
|
3077
|
+
*/
|
|
3078
|
+
async smartTransfer(token, recipient, amount, fee) {
|
|
3079
|
+
if (!this.owner || !this.smartAccountAddress) throw new Error("Not connected");
|
|
3080
|
+
const tokenAddress = this.getTokenAddress(token);
|
|
3081
|
+
const isNative = tokenAddress === "0x0000000000000000000000000000000000000000";
|
|
3082
|
+
const [saBal, eoaBal, allowance] = await Promise.all([
|
|
3083
|
+
this.getBalance(token),
|
|
3084
|
+
this.getEoaBalance(token),
|
|
3085
|
+
isNative ? 0n : this.getAllowance(token).catch(() => 0n)
|
|
3086
|
+
]);
|
|
3087
|
+
const totalNeeded = amount + (fee?.amount || 0n);
|
|
3088
|
+
if (saBal >= totalNeeded) {
|
|
3089
|
+
const txs = [];
|
|
3090
|
+
if (isNative) {
|
|
3091
|
+
txs.push({ target: recipient, value: amount, data: "0x" });
|
|
3092
|
+
} else {
|
|
3093
|
+
txs.push({ target: tokenAddress, value: 0n, data: this.tokenService.encodeTransfer(recipient, amount) });
|
|
3094
|
+
}
|
|
3095
|
+
if (fee && fee.amount > 0n) {
|
|
3096
|
+
if (isNative) {
|
|
3097
|
+
txs.push({ target: fee.recipient, value: fee.amount, data: "0x" });
|
|
3098
|
+
} else {
|
|
3099
|
+
txs.push({ target: tokenAddress, value: 0n, data: this.tokenService.encodeTransfer(fee.recipient, fee.amount) });
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
console.log("SmartTransfer: Using Smart Account");
|
|
3103
|
+
return this.sendBatchTransaction(txs);
|
|
3104
|
+
}
|
|
3105
|
+
if (eoaBal >= totalNeeded) {
|
|
3106
|
+
if (isNative) {
|
|
3107
|
+
console.log("SmartTransfer: Using EOA (Native)");
|
|
3108
|
+
if (this.walletClient) {
|
|
3109
|
+
const hash2 = await this.walletClient.sendTransaction({
|
|
3110
|
+
account: this.walletClient.account,
|
|
3111
|
+
to: recipient,
|
|
3112
|
+
value: amount,
|
|
3113
|
+
chain: this.chainConfig.chain
|
|
3114
|
+
});
|
|
3115
|
+
return { receipt: { transactionHash: hash2 } };
|
|
3116
|
+
}
|
|
3117
|
+
const hash = await window.ethereum.request({
|
|
3118
|
+
method: "eth_sendTransaction",
|
|
3119
|
+
params: [{ from: this.owner, to: recipient, value: "0x" + amount.toString(16) }]
|
|
3120
|
+
});
|
|
3121
|
+
return { receipt: { transactionHash: hash } };
|
|
3122
|
+
} else {
|
|
3123
|
+
console.log("SmartTransfer: Using EOA (Pull)");
|
|
3124
|
+
if (allowance < totalNeeded) {
|
|
3125
|
+
throw new Error(`Approval required. Please approve ${token} usage.`);
|
|
3126
|
+
}
|
|
3127
|
+
const txs = [];
|
|
3128
|
+
txs.push({
|
|
3129
|
+
target: tokenAddress,
|
|
3130
|
+
value: 0n,
|
|
3131
|
+
data: this.tokenService.encodeTransferFrom(this.owner, recipient, amount)
|
|
3132
|
+
});
|
|
3133
|
+
if (fee && fee.amount > 0n) {
|
|
3134
|
+
txs.push({
|
|
3135
|
+
target: tokenAddress,
|
|
3136
|
+
value: 0n,
|
|
3137
|
+
data: this.tokenService.encodeTransferFrom(this.owner, fee.recipient, fee.amount)
|
|
3138
|
+
});
|
|
3139
|
+
}
|
|
3140
|
+
return this.sendBatchTransaction(txs);
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
throw new Error(`Insufficient funds.`);
|
|
3144
|
+
}
|
|
3145
|
+
async transfer(token, recipient, amount) {
|
|
3146
|
+
const tokenAddress = this.getTokenAddress(token);
|
|
3147
|
+
if (tokenAddress === "0x0000000000000000000000000000000000000000") {
|
|
3148
|
+
return this.sendTransaction({
|
|
3149
|
+
target: recipient,
|
|
3150
|
+
value: amount,
|
|
3151
|
+
data: "0x"
|
|
3152
|
+
});
|
|
3153
|
+
}
|
|
3154
|
+
const data = this.tokenService.encodeTransfer(recipient, amount);
|
|
3155
|
+
return this.sendTransaction({
|
|
3156
|
+
target: tokenAddress,
|
|
3157
|
+
value: 0n,
|
|
3158
|
+
data
|
|
3159
|
+
});
|
|
3160
|
+
}
|
|
3161
|
+
/**
|
|
3162
|
+
* Approve a token for the Smart Account
|
|
3163
|
+
*/
|
|
3164
|
+
async approveToken(token, spender, amount = 115792089237316195423570985008687907853269984665640564039457584007913129639935n) {
|
|
3165
|
+
if (!this.owner) throw new Error("Not connected");
|
|
3166
|
+
const support = await this.requestApprovalSupport(token, spender, amount);
|
|
3167
|
+
if (support.type === "approve") {
|
|
3168
|
+
const data = this.tokenService.encodeApprove(spender, amount);
|
|
3169
|
+
if (this.walletClient) {
|
|
3170
|
+
return await this.walletClient.sendTransaction({
|
|
3171
|
+
account: this.walletClient.account,
|
|
3172
|
+
to: token,
|
|
3173
|
+
data,
|
|
3174
|
+
chain: this.chainConfig.chain
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
return await window.ethereum.request({
|
|
3178
|
+
method: "eth_sendTransaction",
|
|
3179
|
+
params: [{
|
|
3180
|
+
from: this.owner,
|
|
3181
|
+
to: token,
|
|
3182
|
+
data
|
|
3183
|
+
}]
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
3186
|
+
if (support.type === "permit") throw new Error("Permit not yet supported");
|
|
3187
|
+
return "NOT_NEEDED";
|
|
3188
|
+
}
|
|
3189
|
+
// --- Core Bridge to Bundler/UserOp ---
|
|
3190
|
+
async signUserOperation(userOp) {
|
|
3191
|
+
if (!this.owner) throw new Error("Not connected");
|
|
3192
|
+
const userOpHash = this.userOpBuilder.getUserOpHash(userOp);
|
|
3193
|
+
let signature;
|
|
3194
|
+
if (this.walletClient) {
|
|
3195
|
+
signature = await this.walletClient.signMessage({
|
|
3196
|
+
account: this.walletClient.account,
|
|
3197
|
+
message: { raw: userOpHash }
|
|
3198
|
+
// Sign hash directly
|
|
3199
|
+
});
|
|
3200
|
+
} else {
|
|
3201
|
+
signature = await window.ethereum.request({
|
|
3202
|
+
method: "personal_sign",
|
|
3203
|
+
params: [userOpHash, this.owner]
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
return { ...userOp, signature };
|
|
3207
|
+
}
|
|
3208
|
+
async sendUserOperation(userOp) {
|
|
3209
|
+
return this.bundlerClient.sendUserOperation(userOp);
|
|
3210
|
+
}
|
|
3211
|
+
async waitForUserOperation(hash, timeout = 6e4) {
|
|
3212
|
+
return this.bundlerClient.waitForUserOperation(hash, timeout);
|
|
3213
|
+
}
|
|
3214
|
+
// Internal but exposed via BundlerClient originally
|
|
3215
|
+
async requestApprovalSupport(token, spender, amount) {
|
|
3216
|
+
if (!this.owner) throw new Error("Not connected");
|
|
3217
|
+
return this.bundlerClient.requestApprovalSupport(token, this.owner, spender, amount);
|
|
3218
|
+
}
|
|
3219
|
+
// Error Decoding (Private)
|
|
3220
|
+
decodeError(error) {
|
|
3221
|
+
const msg = error?.message || "";
|
|
3222
|
+
const hexMatch = msg.match(/(0x[0-9a-fA-F]+)/);
|
|
3223
|
+
if (hexMatch) {
|
|
3224
|
+
try {
|
|
3225
|
+
const decoded = viem.decodeErrorResult({
|
|
3226
|
+
abi: [{ inputs: [{ name: "message", type: "string" }], name: "Error", type: "error" }],
|
|
3227
|
+
data: hexMatch[0]
|
|
3228
|
+
});
|
|
3229
|
+
if (decoded.errorName === "Error") return new Error(`Smart Account Error: ${decoded.args[0]}`);
|
|
3230
|
+
} catch (e) {
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
if (msg.includes("AA21")) return new Error("Smart Account: Native transfer failed (ETH missing?)");
|
|
3234
|
+
if (msg.includes("AA25")) return new Error("Smart Account: Invalid account nonce");
|
|
3235
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
3236
|
+
}
|
|
3237
|
+
// Getters
|
|
3238
|
+
getOwner() {
|
|
3239
|
+
return this.owner;
|
|
3240
|
+
}
|
|
3241
|
+
getSmartAccount() {
|
|
3242
|
+
return this.smartAccountAddress;
|
|
3243
|
+
}
|
|
3244
|
+
};
|
|
3245
|
+
|
|
3424
3246
|
// src/index.ts
|
|
3425
|
-
init_AccountAbstraction();
|
|
3426
|
-
init_BundlerClient();
|
|
3427
3247
|
init_Base();
|
|
3428
3248
|
init_Avalanche();
|
|
3429
3249
|
init_Optimism();
|
|
3250
|
+
init_Unichain();
|
|
3430
3251
|
|
|
3431
3252
|
// src/chains.ts
|
|
3432
3253
|
init_Base();
|
|
@@ -3469,11 +3290,14 @@ init_Arbitrum();
|
|
|
3469
3290
|
init_Unichain();
|
|
3470
3291
|
init_Monad();
|
|
3471
3292
|
init_Stellar();
|
|
3293
|
+
init_Stacks();
|
|
3472
3294
|
function mapToSDKConfig(data) {
|
|
3473
3295
|
if (data.nonEvm) {
|
|
3296
|
+
const isStacks = data.assets[0].address?.toString().startsWith("SP") || data.nonEvm.serverURL?.includes("hiro");
|
|
3297
|
+
const chainId = isStacks ? 5e3 : 9e3;
|
|
3298
|
+
const chainName = isStacks ? "Stacks" : "Stellar";
|
|
3474
3299
|
return {
|
|
3475
|
-
chain: { id:
|
|
3476
|
-
// Custom ID for Stellar
|
|
3300
|
+
chain: { id: chainId, name: chainName },
|
|
3477
3301
|
tokens: data.assets.map((a) => ({
|
|
3478
3302
|
symbol: a.name,
|
|
3479
3303
|
decimals: a.decimals,
|
|
@@ -3504,9 +3328,10 @@ var AVALANCHE_MAINNET = mapToSDKConfig(exports.AVALANCHE);
|
|
|
3504
3328
|
var BSC_MAINNET = mapToSDKConfig(BNB);
|
|
3505
3329
|
var POLYGON_MAINNET = mapToSDKConfig(POLYGON);
|
|
3506
3330
|
var ARBITRUM_MAINNET = mapToSDKConfig(ARBITRUM);
|
|
3507
|
-
var UNICHAIN_MAINNET = mapToSDKConfig(UNICHAIN);
|
|
3331
|
+
var UNICHAIN_MAINNET = mapToSDKConfig(exports.UNICHAIN);
|
|
3508
3332
|
var MONAD_MAINNET = mapToSDKConfig(Monad);
|
|
3509
3333
|
var STELLAR_MAINNET = mapToSDKConfig(exports.STELLAR);
|
|
3334
|
+
var STACKS_MAINNET = mapToSDKConfig(STACKS);
|
|
3510
3335
|
var CHAIN_CONFIGS = {
|
|
3511
3336
|
[chains.base.id]: BASE_MAINNET,
|
|
3512
3337
|
[chains.baseSepolia.id]: BASE_SEPOLIA2,
|
|
@@ -3518,11 +3343,9 @@ var CHAIN_CONFIGS = {
|
|
|
3518
3343
|
[chains.arbitrum.id]: ARBITRUM_MAINNET,
|
|
3519
3344
|
[chains.unichain.id]: UNICHAIN_MAINNET,
|
|
3520
3345
|
[chains.monad.id]: MONAD_MAINNET,
|
|
3521
|
-
9e3: STELLAR_MAINNET
|
|
3346
|
+
9e3: STELLAR_MAINNET,
|
|
3347
|
+
5e3: STACKS_MAINNET
|
|
3522
3348
|
};
|
|
3523
|
-
|
|
3524
|
-
// src/index.ts
|
|
3525
|
-
init_constants();
|
|
3526
3349
|
var CHAIN_ID_TO_KEY = {
|
|
3527
3350
|
[chains.mainnet.id]: "Ethereum",
|
|
3528
3351
|
[chains.base.id]: "Base",
|
|
@@ -3536,7 +3359,8 @@ var CHAIN_ID_TO_KEY = {
|
|
|
3536
3359
|
[chains.avalanche.id]: "Avalanche",
|
|
3537
3360
|
[chains.unichain.id]: "Unichain",
|
|
3538
3361
|
[chains.monad.id]: "Monad",
|
|
3539
|
-
"9000": "Stellar"
|
|
3362
|
+
"9000": "Stellar",
|
|
3363
|
+
"5000": "Stacks"
|
|
3540
3364
|
};
|
|
3541
3365
|
|
|
3542
3366
|
// src/index.ts
|
|
@@ -3546,24 +3370,117 @@ init_TransferManager();
|
|
|
3546
3370
|
init_near();
|
|
3547
3371
|
init_cctp2();
|
|
3548
3372
|
init_stargate();
|
|
3549
|
-
|
|
3373
|
+
var UNISWAP_V3_ROUTER = "0x2626664c2603336E57B271c5C0b26F421741e481";
|
|
3374
|
+
var UNISWAP_V3_QUOTER = "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a";
|
|
3375
|
+
var USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
3376
|
+
var WETH_ADDRESS = "0x4200000000000000000000000000000000000006";
|
|
3377
|
+
var QUOTER_ABI = viem.parseAbi([
|
|
3378
|
+
"function quoteExactOutputSingle((address tokenIn, address tokenOut, uint256 amount, uint24 fee, uint160 sqrtPriceLimitX96) params) external returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
|
|
3379
|
+
]);
|
|
3380
|
+
var ROUTER_ABI = viem.parseAbi([
|
|
3381
|
+
"function exactOutputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 amountOut, uint256 amountInMaximum, uint160 sqrtPriceLimitX96) params) external payable returns (uint256 amountIn)"
|
|
3382
|
+
]);
|
|
3383
|
+
var UniswapService = class {
|
|
3384
|
+
constructor() {
|
|
3385
|
+
this.publicClient = viem.createPublicClient({
|
|
3386
|
+
chain: chains.base,
|
|
3387
|
+
transport: viem.http("https://mainnet.base.org")
|
|
3388
|
+
// Default public RPC
|
|
3389
|
+
});
|
|
3390
|
+
}
|
|
3391
|
+
/**
|
|
3392
|
+
* Get amount of USDC needed to buy exact amount of ETH
|
|
3393
|
+
* @param amountETHWei Amount of ETH (Wei) needed
|
|
3394
|
+
*/
|
|
3395
|
+
async quoteUSDCForETH(amountETHWei) {
|
|
3396
|
+
try {
|
|
3397
|
+
const params = {
|
|
3398
|
+
tokenIn: USDC_ADDRESS,
|
|
3399
|
+
tokenOut: WETH_ADDRESS,
|
|
3400
|
+
amount: amountETHWei,
|
|
3401
|
+
fee: 500,
|
|
3402
|
+
sqrtPriceLimitX96: 0n
|
|
3403
|
+
};
|
|
3404
|
+
const result = await this.publicClient.readContract({
|
|
3405
|
+
address: UNISWAP_V3_QUOTER,
|
|
3406
|
+
abi: QUOTER_ABI,
|
|
3407
|
+
functionName: "quoteExactOutputSingle",
|
|
3408
|
+
args: [params]
|
|
3409
|
+
});
|
|
3410
|
+
const amountIn = result[0];
|
|
3411
|
+
return amountIn * 105n / 100n;
|
|
3412
|
+
} catch (e) {
|
|
3413
|
+
console.error("Quote failed", e);
|
|
3414
|
+
throw new Error("Failed to quote USDC for ETH swap");
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
/**
|
|
3418
|
+
* Build tx data for swapping USDC -> ETH
|
|
3419
|
+
* Uses SwapRouter02.exactOutputSingle + unwrapWETH9
|
|
3420
|
+
*/
|
|
3421
|
+
buildSwapData(recipient, amountOutETH, maxAmountInUSDC) {
|
|
3422
|
+
const swapParams = {
|
|
3423
|
+
tokenIn: USDC_ADDRESS,
|
|
3424
|
+
tokenOut: WETH_ADDRESS,
|
|
3425
|
+
fee: 500,
|
|
3426
|
+
recipient: UNISWAP_V3_ROUTER,
|
|
3427
|
+
// Router must hold WETH to unwrap it
|
|
3428
|
+
amountOut: amountOutETH,
|
|
3429
|
+
amountInMaximum: maxAmountInUSDC,
|
|
3430
|
+
sqrtPriceLimitX96: 0n
|
|
3431
|
+
};
|
|
3432
|
+
const swapCalldata = viem.encodeFunctionData({
|
|
3433
|
+
abi: ROUTER_ABI,
|
|
3434
|
+
functionName: "exactOutputSingle",
|
|
3435
|
+
args: [swapParams]
|
|
3436
|
+
});
|
|
3437
|
+
const unwrapCalldata = viem.encodeFunctionData({
|
|
3438
|
+
abi: viem.parseAbi(["function unwrapWETH9(uint256 amountMinimum, address recipient) payable"]),
|
|
3439
|
+
functionName: "unwrapWETH9",
|
|
3440
|
+
args: [amountOutETH, recipient]
|
|
3441
|
+
});
|
|
3442
|
+
const multicallCalldata = viem.encodeFunctionData({
|
|
3443
|
+
abi: viem.parseAbi(["function multicall(bytes[] data) payable returns (bytes[])"]),
|
|
3444
|
+
functionName: "multicall",
|
|
3445
|
+
args: [[swapCalldata, unwrapCalldata]]
|
|
3446
|
+
});
|
|
3447
|
+
return multicallCalldata;
|
|
3448
|
+
}
|
|
3449
|
+
getRouterAddress() {
|
|
3450
|
+
return UNISWAP_V3_ROUTER;
|
|
3451
|
+
}
|
|
3452
|
+
getUSDCAddress() {
|
|
3453
|
+
return USDC_ADDRESS;
|
|
3454
|
+
}
|
|
3455
|
+
};
|
|
3456
|
+
var uniswapService = new UniswapService();
|
|
3457
|
+
|
|
3458
|
+
// src/index.ts
|
|
3550
3459
|
init_Router();
|
|
3551
3460
|
|
|
3552
3461
|
exports.ARBITRUM_MAINNET = ARBITRUM_MAINNET;
|
|
3553
3462
|
exports.AVALANCHE_MAINNET = AVALANCHE_MAINNET;
|
|
3463
|
+
exports.AccountAbstraction = AccountAbstraction;
|
|
3554
3464
|
exports.BASE_MAINNET = BASE_MAINNET;
|
|
3555
3465
|
exports.BASE_SEPOLIA = BASE_SEPOLIA2;
|
|
3556
3466
|
exports.BSC_MAINNET = BSC_MAINNET;
|
|
3467
|
+
exports.BundlerClient = BundlerClient;
|
|
3557
3468
|
exports.CHAIN_CONFIGS = CHAIN_CONFIGS;
|
|
3558
3469
|
exports.CHAIN_ID_TO_KEY = CHAIN_ID_TO_KEY;
|
|
3559
3470
|
exports.GNOSIS_MAINNET = GNOSIS_MAINNET;
|
|
3560
3471
|
exports.MONAD_MAINNET = MONAD_MAINNET;
|
|
3561
3472
|
exports.OPTIMISM_MAINNET = OPTIMISM_MAINNET;
|
|
3562
3473
|
exports.POLYGON_MAINNET = POLYGON_MAINNET;
|
|
3474
|
+
exports.STACKS_MAINNET = STACKS_MAINNET;
|
|
3563
3475
|
exports.STELLAR_MAINNET = STELLAR_MAINNET;
|
|
3564
3476
|
exports.UNICHAIN_MAINNET = UNICHAIN_MAINNET;
|
|
3477
|
+
exports.UniswapService = UniswapService;
|
|
3478
|
+
exports.entryPointAbi = entryPointAbi;
|
|
3479
|
+
exports.erc20Abi = erc20Abi;
|
|
3565
3480
|
exports.getNearQuote = getNearQuote;
|
|
3566
3481
|
exports.getNearSimulation = getNearSimulation;
|
|
3567
3482
|
exports.getStargateSimulation = getStargateSimulation;
|
|
3483
|
+
exports.smartAccountAbi = smartAccountAbi;
|
|
3484
|
+
exports.uniswapService = uniswapService;
|
|
3568
3485
|
//# sourceMappingURL=index.js.map
|
|
3569
3486
|
//# sourceMappingURL=index.js.map
|