four-flap-meme-sdk 1.5.51 → 1.5.52

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.
@@ -648,7 +648,7 @@ export class BundleExecutor {
648
648
  // TODO: 如果需要,可以在这里检查并转账 ERC20 代币到 sender
649
649
  }
650
650
  });
651
- // ✅ 构建买入 callData:如果使用 ERC20 代币,需要修改 encodeBuyCall 以支持 inputToken
651
+ // ✅ 构建买入 callData:如果使用 ERC20 代币,需要先 approve
652
652
  const buyCallDatas = buyWeis.map((buyWei) => {
653
653
  // 使用 portal 的 swapExactInput,支持 inputToken 参数
654
654
  const portalIface = new Interface([
@@ -663,8 +663,16 @@ export class BundleExecutor {
663
663
  permitData: '0x',
664
664
  },
665
665
  ]);
666
- // 如果使用原生代币,value 为买入金额;否则为 0
667
- return encodeExecute(this.portalAddress, useNativeToken ? buyWei : 0n, swapData);
666
+ // ERC20 代币需要先 approve,使用 executeBatch 将 approve + swap 合并为一个 UserOp
667
+ if (useNativeToken) {
668
+ // 原生代币:直接 swap
669
+ return encodeExecute(this.portalAddress, buyWei, swapData);
670
+ }
671
+ else {
672
+ // ERC20 代币:approve + swap 批量调用
673
+ const approveData = encodeApproveCall(this.portalAddress, buyWei);
674
+ return encodeExecuteBatch([inputToken, this.portalAddress], [0n, 0n], [approveData, swapData]);
675
+ }
668
676
  });
669
677
  const initCodes = accountInfos.map((ai, i) => ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address));
670
678
  const { userOps: buyUserOps, prefundWeis } = await this.aaManager.buildUserOpsWithBundlerEstimateBatch({
@@ -977,7 +985,7 @@ export class BundleExecutor {
977
985
  // TODO: 如果需要,可以在这里检查并转账 ERC20 代币到 sender
978
986
  }
979
987
  });
980
- // ✅ 构建买入 callData:如果使用 ERC20 代币,需要修改 encodeBuyCall 以支持 inputToken
988
+ // ✅ 构建买入 callData:如果使用 ERC20 代币,需要先 approve
981
989
  const buyCallDatas = buyWeis.map((buyWei) => {
982
990
  // 使用 portal 的 swapExactInput,支持 inputToken 参数
983
991
  const portalIface = new Interface([
@@ -992,8 +1000,16 @@ export class BundleExecutor {
992
1000
  permitData: '0x',
993
1001
  },
994
1002
  ]);
995
- // 如果使用原生代币,value 为买入金额;否则为 0
996
- return encodeExecute(this.portalAddress, useNativeToken ? buyWei : 0n, swapData);
1003
+ // ERC20 代币需要先 approve,使用 executeBatch 将 approve + swap 合并为一个 UserOp
1004
+ if (useNativeToken) {
1005
+ // 原生代币:直接 swap
1006
+ return encodeExecute(this.portalAddress, buyWei, swapData);
1007
+ }
1008
+ else {
1009
+ // ERC20 代币:approve + swap 批量调用
1010
+ const approveData = encodeApproveCall(this.portalAddress, buyWei);
1011
+ return encodeExecuteBatch([inputToken, this.portalAddress], [0n, 0n], [approveData, swapData]);
1012
+ }
997
1013
  });
998
1014
  const initCodes = accountInfos.map((ai, i) => (ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address)));
999
1015
  const { userOps: buyUserOps, prefundWeis } = await this.aaManager.buildUserOpsWithBundlerEstimateBatch({
@@ -1252,12 +1268,15 @@ export class BundleExecutor {
1252
1268
  const inputToken = params.quoteToken && params.quoteToken !== ZERO_ADDRESS ? params.quoteToken : ZERO_ADDRESS;
1253
1269
  const useNativeToken = inputToken === ZERO_ADDRESS;
1254
1270
  const quoteDecimals = 18;
1255
- let totalBuyWei = 0n;
1256
- let totalBuyProfitWei = 0n;
1257
- const buyerSenders = [];
1258
1271
  const portalIface = new Interface(PORTAL_ABI);
1259
- for (let i = 0; i < buyerWallets.length; i++) {
1260
- const buyer = buyerWallets[i];
1272
+ // 批量获取所有买家的账户信息(并行优化)
1273
+ const buyerAccountInfos = await this.aaManager.getMultipleAccountInfo(buyerWallets.map(w => w.address));
1274
+ const buyerSenders = buyerAccountInfos.map(ai => ai.sender);
1275
+ for (const ai of buyerAccountInfos) {
1276
+ nonceMap.init(ai.sender, ai.nonce);
1277
+ }
1278
+ // ✅ 预计算所有买家的金额和利润
1279
+ const buyerData = buyerWallets.map((buyer, i) => {
1261
1280
  const amountStr = buyAmounts[i] || '0';
1262
1281
  const originalWei = useNativeToken ? parseOkb(amountStr) : ethers.parseUnits(amountStr, quoteDecimals);
1263
1282
  let buyWei = originalWei;
@@ -1267,11 +1286,13 @@ export class BundleExecutor {
1267
1286
  buyWei = res.remaining;
1268
1287
  profitWei = res.profit;
1269
1288
  }
1270
- totalBuyWei += buyWei;
1271
- totalBuyProfitWei += profitWei;
1272
- const buyerAccount = await this.aaManager.getAccountInfo(buyer.address);
1273
- buyerSenders.push(buyerAccount.sender);
1274
- nonceMap.init(buyerAccount.sender, buyerAccount.nonce);
1289
+ return { buyer, buyWei, profitWei, accountInfo: buyerAccountInfos[i] };
1290
+ });
1291
+ const totalBuyWei = buyerData.reduce((sum, d) => sum + d.buyWei, 0n);
1292
+ const totalBuyProfitWei = buyerData.reduce((sum, d) => sum + d.profitWei, 0n);
1293
+ // ✅ 并行构建和签名所有买家的 UserOps
1294
+ const signedBuyOps = await mapWithConcurrency(buyerData, 5, async (data) => {
1295
+ const { buyer, buyWei, accountInfo } = data;
1275
1296
  const swapData = portalIface.encodeFunctionData('swapExactInput', [
1276
1297
  {
1277
1298
  inputToken,
@@ -1281,17 +1302,28 @@ export class BundleExecutor {
1281
1302
  permitData: '0x',
1282
1303
  },
1283
1304
  ]);
1305
+ // ✅ ERC20 代币需要先 approve,使用 executeBatch 将 approve + swap 合并为一个 UserOp
1306
+ let buyCallData;
1307
+ if (useNativeToken) {
1308
+ buyCallData = encodeExecute(this.portalAddress, buyWei, swapData);
1309
+ }
1310
+ else {
1311
+ const approveData = encodeApproveCall(this.portalAddress, buyWei);
1312
+ buyCallData = encodeExecuteBatch([inputToken, this.portalAddress], [0n, 0n], [approveData, swapData]);
1313
+ }
1284
1314
  const buyOp = await this.aaManager.buildUserOpWithFixedGas({
1285
1315
  ownerWallet: buyer,
1286
- sender: buyerAccount.sender,
1287
- callData: encodeExecute(this.portalAddress, useNativeToken ? buyWei : 0n, swapData),
1288
- nonce: nonceMap.next(buyerAccount.sender),
1289
- initCode: buyerAccount.deployed ? '0x' : this.aaManager.generateInitCode(buyer.address),
1290
- deployed: buyerAccount.deployed
1316
+ sender: accountInfo.sender,
1317
+ callData: buyCallData,
1318
+ nonce: nonceMap.next(accountInfo.sender),
1319
+ initCode: accountInfo.deployed ? '0x' : this.aaManager.generateInitCode(buyer.address),
1320
+ deployed: accountInfo.deployed
1291
1321
  });
1292
1322
  const signedBuyOp = await this.aaManager.signUserOp(buyOp.userOp, buyer);
1293
- ops.push(signedBuyOp.userOp);
1294
- }
1323
+ return signedBuyOp.userOp;
1324
+ });
1325
+ // 将所有签名的买入 UserOps 添加到操作列表
1326
+ ops.push(...signedBuyOps);
1295
1327
  // 利润由尾笔交易处理(不再在买入阶段追加利润转账 UserOp)
1296
1328
  // === 计算利润金额 ===
1297
1329
  let nativeProfitAmount = 0n;
@@ -1425,17 +1457,20 @@ export class BundleExecutor {
1425
1457
  });
1426
1458
  const signedCreateOp = await aaManager.signUserOp(createOpRes.userOp, payerWallet);
1427
1459
  ops1.push(signedCreateOp.userOp);
1428
- // --- 3. 构建内盘买入 Ops ---
1429
- for (let i = 0; i < curveBuyerWallets.length; i++) {
1430
- const wallet = curveBuyerWallets[i];
1431
- const info = curveBuyerInfos[i];
1460
+ // --- 3. 构建内盘买入 Ops(并行优化)---
1461
+ // 预计算所有买入金额
1462
+ const curveBuyData = curveBuyerWallets.map((wallet, i) => {
1432
1463
  const buyWei = parseOkb(curveBuyAmounts[i]);
1433
- totalCurveBuyWei += buyWei;
1464
+ const isLast = i === curveBuyerWallets.length - 1;
1465
+ const gasLimit = isLast ? 8000000n : 800000n; // 最后一笔触发毕业,给大一点
1466
+ return { wallet, info: curveBuyerInfos[i], buyWei, gasLimit };
1467
+ });
1468
+ totalCurveBuyWei = curveBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
1469
+ // ✅ 并行构建和签名所有内盘买入 UserOps
1470
+ const signedCurveBuyOps = await mapWithConcurrency(curveBuyData, 5, async (data) => {
1471
+ const { wallet, info, buyWei, gasLimit } = data;
1434
1472
  const buyData = encodeBuyCall(tokenAddress, buyWei, 0n);
1435
1473
  const buyCallData = encodeExecute(FLAP_PORTAL, buyWei, buyData);
1436
- // 最后一笔买入通常触发毕业,GasLimit 给大一点 (8M)
1437
- const isLast = i === curveBuyerWallets.length - 1;
1438
- const gasLimit = isLast ? 8000000n : 800000n;
1439
1474
  const buyOpRes = await aaManager.buildUserOpWithFixedGas({
1440
1475
  ownerWallet: wallet,
1441
1476
  sender: info.sender,
@@ -1446,8 +1481,9 @@ export class BundleExecutor {
1446
1481
  fixedGas: { callGasLimit: gasLimit }
1447
1482
  });
1448
1483
  const signedBuyOp = await aaManager.signUserOp(buyOpRes.userOp, wallet);
1449
- ops1.push(signedBuyOp.userOp);
1450
- }
1484
+ return signedBuyOp.userOp;
1485
+ });
1486
+ ops1.push(...signedCurveBuyOps);
1451
1487
  // 签名第一个 handleOps
1452
1488
  const startNonce = params.payerStartNonce ?? (await provider.getTransactionCount(payerWallet.address, 'pending'));
1453
1489
  const signedMainTx = await this.signHandleOpsTx({
@@ -1467,40 +1503,32 @@ export class BundleExecutor {
1467
1503
  });
1468
1504
  const ops2 = [];
1469
1505
  const deadline = Math.floor(Date.now() / 1000) + 1200; // 20 min
1470
- for (let i = 0; i < dexBuyerWallets.length; i++) {
1471
- const wallet = dexBuyerWallets[i];
1472
- const info = dexBuyerInfos[i];
1506
+ // 预计算所有外盘买入金额
1507
+ const dexBuyData = dexBuyerWallets.map((wallet, i) => {
1473
1508
  const buyWei = parseOkb(dexBuyAmounts[i]);
1474
- totalDexBuyWei += buyWei;
1475
- // AA 模式外盘:Approve + Swap
1476
- // 1. Approve (PotatoSwap Router)
1509
+ return { wallet, info: dexBuyerInfos[i], buyWei };
1510
+ });
1511
+ totalDexBuyWei = dexBuyData.reduce((sum, d) => sum + d.buyWei, 0n);
1512
+ // ✅ 并行构建和签名所有外盘买入 UserOps
1513
+ const signedDexBuyOps = await mapWithConcurrency(dexBuyData, 5, async (data) => {
1514
+ const { wallet, info, buyWei } = data;
1515
+ // AA 模式外盘:使用 executeBatch 将 Approve + Swap 合并为一个 UserOp
1477
1516
  const approveData = encodeApproveCall(POTATOSWAP_V2_ROUTER);
1478
- const approveCallData = encodeExecute(tokenAddress, 0n, approveData);
1479
- const approveOpRes = await aaManager.buildUserOpWithFixedGas({
1480
- ownerWallet: wallet,
1481
- sender: info.sender,
1482
- callData: approveCallData,
1483
- nonce: nonceMap.next(info.sender),
1484
- initCode: '0x', // HandleOps1 已部署
1485
- deployed: true,
1486
- fixedGas: { callGasLimit: 100000n }
1487
- });
1488
- const signedApprove = await aaManager.signUserOp(approveOpRes.userOp, wallet);
1489
- ops2.push(signedApprove.userOp);
1490
- // 2. Swap (PotatoSwap V2)
1491
1517
  const swapData = encodeSwapExactETHForTokensSupportingFee(0n, [WOKB, tokenAddress], info.sender, deadline);
1492
- const swapCallData = encodeExecute(POTATOSWAP_V2_ROUTER, buyWei, swapData);
1493
- const swapOpRes = await aaManager.buildUserOpWithFixedGas({
1518
+ const batchCallData = encodeExecuteBatch([tokenAddress, POTATOSWAP_V2_ROUTER], [0n, buyWei], [approveData, swapData]);
1519
+ const dexBuyOpRes = await aaManager.buildUserOpWithFixedGas({
1494
1520
  ownerWallet: wallet,
1495
1521
  sender: info.sender,
1496
- callData: swapCallData,
1522
+ callData: batchCallData,
1497
1523
  nonce: nonceMap.next(info.sender),
1524
+ initCode: '0x', // HandleOps1 已部署
1498
1525
  deployed: true,
1499
- fixedGas: { callGasLimit: 500000n }
1526
+ fixedGas: { callGasLimit: 600000n }
1500
1527
  });
1501
- const signedSwap = await aaManager.signUserOp(swapOpRes.userOp, wallet);
1502
- ops2.push(signedSwap.userOp);
1503
- }
1528
+ const signedDexBuyOp = await aaManager.signUserOp(dexBuyOpRes.userOp, wallet);
1529
+ return signedDexBuyOp.userOp;
1530
+ });
1531
+ ops2.push(...signedDexBuyOps);
1504
1532
  const signedDexTx = await this.signHandleOpsTx({
1505
1533
  ops: ops2,
1506
1534
  payerWallet: payerWallet,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.51",
3
+ "version": "1.5.52",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",