four-flap-meme-sdk 1.6.36 → 1.6.37
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.
|
@@ -89,6 +89,12 @@ export declare class AAAccountManager {
|
|
|
89
89
|
* 获取完整的 AA 账户信息
|
|
90
90
|
*/
|
|
91
91
|
getAccountInfo(ownerAddress: string, salt?: bigint): Promise<AAAccount>;
|
|
92
|
+
/**
|
|
93
|
+
* 批量获取多个 AA sender 的 nonce
|
|
94
|
+
* @param senderAddresses AA sender 地址列表
|
|
95
|
+
* @returns 对应的 nonce 数组
|
|
96
|
+
*/
|
|
97
|
+
batchGetNonces(senderAddresses: string[]): Promise<bigint[]>;
|
|
92
98
|
/**
|
|
93
99
|
* 生成 initCode(用于在 UserOp 中部署账户)
|
|
94
100
|
*/
|
|
@@ -290,6 +290,40 @@ export class AAAccountManager {
|
|
|
290
290
|
nonce,
|
|
291
291
|
};
|
|
292
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* 批量获取多个 AA sender 的 nonce
|
|
295
|
+
* @param senderAddresses AA sender 地址列表
|
|
296
|
+
* @returns 对应的 nonce 数组
|
|
297
|
+
*/
|
|
298
|
+
async batchGetNonces(senderAddresses) {
|
|
299
|
+
if (senderAddresses.length === 0)
|
|
300
|
+
return [];
|
|
301
|
+
await this.syncEntryPointIfNeeded();
|
|
302
|
+
const epIface = new Interface(ENTRYPOINT_ABI);
|
|
303
|
+
const nonceCalls = senderAddresses.map((sender) => ({
|
|
304
|
+
target: this.entryPointAddress,
|
|
305
|
+
allowFailure: true,
|
|
306
|
+
callData: epIface.encodeFunctionData('getNonce', [sender, 0]),
|
|
307
|
+
}));
|
|
308
|
+
const nonces = new Array(senderAddresses.length).fill(0n);
|
|
309
|
+
const BATCH = 350;
|
|
310
|
+
for (let cursor = 0; cursor < nonceCalls.length; cursor += BATCH) {
|
|
311
|
+
const sliceCalls = nonceCalls.slice(cursor, cursor + BATCH);
|
|
312
|
+
const res = await this.multicallAggregate3({ calls: sliceCalls });
|
|
313
|
+
for (let i = 0; i < res.length; i++) {
|
|
314
|
+
const r = res[i];
|
|
315
|
+
const idx = cursor + i;
|
|
316
|
+
if (!r?.success || !r.returnData || r.returnData === '0x')
|
|
317
|
+
continue;
|
|
318
|
+
try {
|
|
319
|
+
const decoded = epIface.decodeFunctionResult('getNonce', r.returnData);
|
|
320
|
+
nonces[idx] = BigInt(decoded?.[0] ?? 0n);
|
|
321
|
+
}
|
|
322
|
+
catch { /* ignore */ }
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return nonces;
|
|
326
|
+
}
|
|
293
327
|
/**
|
|
294
328
|
* 生成 initCode(用于在 UserOp 中部署账户)
|
|
295
329
|
*/
|
|
@@ -688,11 +688,14 @@ export class AADexSwapExecutor {
|
|
|
688
688
|
if (prefundedHopWallets.length < totalHopsNeeded) {
|
|
689
689
|
throw new Error(`预充值 hop 钱包数量不足: 需要 ${totalHopsNeeded} 个,实际 ${prefundedHopWallets.length} 个`);
|
|
690
690
|
}
|
|
691
|
+
// ✅ 关键修复:从链上获取所有 hop 钱包的真实 nonce(用户可能重复使用同一批 hop 钱包)
|
|
692
|
+
const hopSenders = prefundedHopWallets.slice(0, totalHopsNeeded).map(h => h.senderAddress);
|
|
693
|
+
const hopNonces = await this.aaManager.batchGetNonces(hopSenders);
|
|
691
694
|
let hopIdx = 0;
|
|
692
695
|
for (let buyerIdx = 0; buyerIdx < buyerSenders.length; buyerIdx++) {
|
|
693
696
|
const chainHops = [];
|
|
694
697
|
for (let h = 0; h < effectiveHopCount; h++) {
|
|
695
|
-
const prefundedHop = prefundedHopWallets[hopIdx
|
|
698
|
+
const prefundedHop = prefundedHopWallets[hopIdx];
|
|
696
699
|
const wallet = new ethers.Wallet(prefundedHop.privateKey, provider);
|
|
697
700
|
chainHops.push({
|
|
698
701
|
wallet,
|
|
@@ -700,8 +703,10 @@ export class AADexSwapExecutor {
|
|
|
700
703
|
deployed: prefundedHop.deployed,
|
|
701
704
|
initCode: prefundedHop.initCode,
|
|
702
705
|
});
|
|
703
|
-
//
|
|
704
|
-
|
|
706
|
+
// ✅ 使用从链上获取的真实 nonce(而非硬编码 0)
|
|
707
|
+
const realNonce = hopNonces[hopIdx] ?? 0n;
|
|
708
|
+
nonceMap.init(prefundedHop.senderAddress, realNonce);
|
|
709
|
+
hopIdx++;
|
|
705
710
|
}
|
|
706
711
|
allGeneratedHopWallets.push(chainHops);
|
|
707
712
|
}
|
|
@@ -329,6 +329,9 @@ export class HopWalletManager {
|
|
|
329
329
|
// 构建所有退款 UserOps
|
|
330
330
|
const userOps = [];
|
|
331
331
|
const hopWalletsToRefund = [];
|
|
332
|
+
// ✅ 关键修复:从链上批量获取所有 hop 钱包的真实 nonce
|
|
333
|
+
const hopSenders = hopWallets.map(h => h.senderAddress);
|
|
334
|
+
const hopNonces = await this.aaManager.batchGetNonces(hopSenders);
|
|
332
335
|
for (let i = 0; i < hopWallets.length; i++) {
|
|
333
336
|
const hop = hopWallets[i];
|
|
334
337
|
try {
|
|
@@ -346,13 +349,18 @@ export class HopWalletManager {
|
|
|
346
349
|
const refundAmount = balance - estimatedGas;
|
|
347
350
|
// 构建 UserOp
|
|
348
351
|
const hopWallet = new Wallet(hop.privateKey, this.provider);
|
|
352
|
+
// ✅ 使用从链上获取的真实 nonce
|
|
353
|
+
const realNonce = hopNonces[i] ?? 0n;
|
|
354
|
+
// ✅ 检查 hop 钱包是否已部署(根据 nonce 判断,nonce > 0 说明已用过,肯定已部署)
|
|
355
|
+
const isDeployed = realNonce > 0n || hop.deployed;
|
|
356
|
+
const initCode = isDeployed ? '0x' : hop.initCode;
|
|
349
357
|
const { userOp } = await this.aaManager.buildUserOpWithFixedGas({
|
|
350
358
|
ownerWallet: hopWallet,
|
|
351
359
|
sender: hop.senderAddress,
|
|
352
|
-
nonce:
|
|
353
|
-
initCode
|
|
360
|
+
nonce: realNonce,
|
|
361
|
+
initCode,
|
|
354
362
|
callData: this.encodeExecute(refundTo, refundAmount, '0x'),
|
|
355
|
-
deployed:
|
|
363
|
+
deployed: isDeployed,
|
|
356
364
|
});
|
|
357
365
|
// 签名
|
|
358
366
|
const signedOp = await this.aaManager.signUserOp(userOp, hopWallet);
|
|
@@ -495,11 +495,14 @@ export class AAPortalSwapExecutor {
|
|
|
495
495
|
if (prefundedHopWallets.length < totalHopsNeeded) {
|
|
496
496
|
throw new Error(`预充值 hop 钱包数量不足: 需要 ${totalHopsNeeded} 个,实际 ${prefundedHopWallets.length} 个`);
|
|
497
497
|
}
|
|
498
|
+
// ✅ 关键修复:从链上获取所有 hop 钱包的真实 nonce(用户可能重复使用同一批 hop 钱包)
|
|
499
|
+
const hopSenders = prefundedHopWallets.slice(0, totalHopsNeeded).map(h => h.senderAddress);
|
|
500
|
+
const hopNonces = await this.aaManager.batchGetNonces(hopSenders);
|
|
498
501
|
let hopIdx = 0;
|
|
499
502
|
for (let buyerIdx = 0; buyerIdx < buyerSenders.length; buyerIdx++) {
|
|
500
503
|
const chainHops = [];
|
|
501
504
|
for (let h = 0; h < effectiveHopCount; h++) {
|
|
502
|
-
const prefundedHop = prefundedHopWallets[hopIdx
|
|
505
|
+
const prefundedHop = prefundedHopWallets[hopIdx];
|
|
503
506
|
const wallet = new ethers.Wallet(prefundedHop.privateKey, provider);
|
|
504
507
|
chainHops.push({
|
|
505
508
|
wallet,
|
|
@@ -507,7 +510,10 @@ export class AAPortalSwapExecutor {
|
|
|
507
510
|
deployed: prefundedHop.deployed,
|
|
508
511
|
initCode: prefundedHop.initCode,
|
|
509
512
|
});
|
|
510
|
-
|
|
513
|
+
// ✅ 使用从链上获取的真实 nonce(而非硬编码 0)
|
|
514
|
+
const realNonce = hopNonces[hopIdx] ?? 0n;
|
|
515
|
+
nonceMap.init(prefundedHop.senderAddress, realNonce);
|
|
516
|
+
hopIdx++;
|
|
511
517
|
}
|
|
512
518
|
allGeneratedHopWallets.push(chainHops);
|
|
513
519
|
}
|