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
- // 初始化 nonce(预充值的钱包 nonce 应该是 0)
704
- nonceMap.init(prefundedHop.senderAddress, 0n);
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: 0n,
353
- initCode: hop.initCode,
360
+ nonce: realNonce,
361
+ initCode,
354
362
  callData: this.encodeExecute(refundTo, refundAmount, '0x'),
355
- deployed: hop.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
- nonceMap.init(prefundedHop.senderAddress, 0n);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.6.36",
3
+ "version": "1.6.37",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",