four-flap-meme-sdk 1.4.79 → 1.4.81

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.
@@ -112,8 +112,8 @@ export class BlockRazorClient {
112
112
  */
113
113
  async buildIncentiveTransaction(params) {
114
114
  const { wallet, amount, nonce, gasPrice } = params;
115
- // 获取 nonce
116
- const txNonce = nonce ?? await this.provider.getTransactionCount(wallet.address, 'latest');
115
+ // 获取 nonce(使用 pending 确保包含待处理交易)
116
+ const txNonce = nonce ?? await this.provider.getTransactionCount(wallet.address, 'pending');
117
117
  // 获取 gas price
118
118
  let txGasPrice = gasPrice;
119
119
  if (!txGasPrice) {
@@ -291,8 +291,8 @@ export class BlockRazorClient {
291
291
  * @returns Bundle 结果
292
292
  */
293
293
  async sendBundleWithIncentive(options, incentive) {
294
- // 获取激励钱包的 nonce
295
- const nonce = await this.provider.getTransactionCount(incentive.wallet.address, 'latest');
294
+ // 获取激励钱包的 nonce(使用 pending 确保包含待处理交易)
295
+ const nonce = await this.provider.getTransactionCount(incentive.wallet.address, 'pending');
296
296
  // 构建激励交易(放在 Bundle 最后)
297
297
  const incentiveTx = await this.buildIncentiveTransaction({
298
298
  wallet: incentive.wallet,
@@ -365,10 +365,10 @@ export class BlockRazorClient {
365
365
  if (!transactions || transactions.length === 0) {
366
366
  throw new Error('Transactions array cannot be empty');
367
367
  }
368
- // 获取 nonce
368
+ // 获取 nonce(使用 pending 确保包含待处理交易)
369
369
  let nonce = options?.startNonce;
370
370
  if (nonce === undefined) {
371
- nonce = await this.provider.getTransactionCount(wallet.address, 'latest');
371
+ nonce = await this.provider.getTransactionCount(wallet.address, 'pending');
372
372
  }
373
373
  // 获取 Gas Price(确保不低于最低要求)
374
374
  let gasPrice = options?.gasPrice;
@@ -289,10 +289,10 @@ export class MerkleClient {
289
289
  if (!transactions || transactions.length === 0) {
290
290
  throw new Error('Transactions array cannot be empty');
291
291
  }
292
- // 获取起始 Nonce(使用 latest 避免 pending 状态问题)
292
+ // 获取起始 Nonce(使用 pending 确保包含待处理交易)
293
293
  let nonce = options?.startNonce;
294
294
  if (nonce === undefined) {
295
- nonce = await this.provider.getTransactionCount(wallet.address, 'latest');
295
+ nonce = await this.provider.getTransactionCount(wallet.address, 'pending');
296
296
  }
297
297
  // 获取 Gas Price
298
298
  let gasPrice = options?.gasPrice;
@@ -313,6 +313,7 @@ async function planMultiNonces({ buyer, seller, buyCount, sellCount, extractProf
313
313
  * - 多个买方钱包执行买入(每个钱包1笔)
314
314
  * - 多个卖方钱包执行卖出(每个钱包1笔)
315
315
  * - 买入总价值 = 卖出总价值
316
+ * - ✅ 优化:最大化并行操作
316
317
  */
317
318
  async function fourBundleBuyFirstMultiWallet(params) {
318
319
  const { buyerPrivateKeys, sellerPrivateKeys, tokenAddress, buyerFunds, config } = params;
@@ -346,9 +347,20 @@ async function fourBundleBuyFirstMultiWallet(params) {
346
347
  if (totalFundsWei <= 0n) {
347
348
  throw new Error('交易金额必须大于0');
348
349
  }
349
- // 获取报价:买入能获得多少代币
350
+ const finalGasLimit = getGasLimit(config);
351
+ const txType = getTxType(config);
352
+ const bribeAmount = getBribeAmount(config);
353
+ const needBribeTx = bribeAmount > 0n;
354
+ // ✅ 第一批并行:报价 + Gas价格 + 代币精度
350
355
  const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider);
351
- const buyQuote = await helper3.tryBuy(tokenAddress, 0n, totalFundsWei);
356
+ const erc20 = new Contract(tokenAddress, [
357
+ 'function decimals() view returns (uint8)'
358
+ ], provider);
359
+ const [buyQuote, gasPrice, decimals] = await Promise.all([
360
+ helper3.tryBuy(tokenAddress, 0n, totalFundsWei),
361
+ getOptimizedGasPrice(provider, getGasPriceConfig(config)),
362
+ erc20.decimals()
363
+ ]);
352
364
  const estimatedTokenAmount = buyQuote.estimatedAmount ?? buyQuote[2];
353
365
  if (!estimatedTokenAmount || estimatedTokenAmount <= 0n) {
354
366
  throw new Error('报价失败:无法估算可买入的代币数量');
@@ -357,33 +369,36 @@ async function fourBundleBuyFirstMultiWallet(params) {
357
369
  const buyAmountsWei = splitAmount(totalFundsWei, buyCount);
358
370
  // ✅ 将代币平均分配给卖方
359
371
  const sellAmountsWei = splitAmount(estimatedTokenAmount, sellCount);
360
- const finalGasLimit = getGasLimit(config);
361
- const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
362
- const txType = getTxType(config);
363
- // 估算利润
364
- const sellResult = await trySell('BSC', config.rpcUrl, tokenAddress, estimatedTokenAmount);
372
+ // 第二批并行:估算利润 + 获取所有钱包 nonces
373
+ // 预先计算所有唯一钱包地址(去重)
374
+ const allWallets = [...sellers, ...buyers];
375
+ const uniqueAddresses = new Set(allWallets.map(w => w.address.toLowerCase()));
376
+ const uniqueWallets = allWallets.filter((w, i) => {
377
+ const addr = w.address.toLowerCase();
378
+ const firstIdx = allWallets.findIndex(x => x.address.toLowerCase() === addr);
379
+ return firstIdx === i;
380
+ });
381
+ const [sellResult, noncesArray] = await Promise.all([
382
+ trySell('BSC', config.rpcUrl, tokenAddress, estimatedTokenAmount),
383
+ nonceManager.getNextNoncesForWallets(uniqueWallets)
384
+ ]);
385
+ // 构建 nonces Map
386
+ const noncesMap = new Map();
387
+ uniqueWallets.forEach((wallet, i) => {
388
+ noncesMap.set(wallet.address.toLowerCase(), noncesArray[i]);
389
+ });
365
390
  const estimatedSellFunds = sellResult.funds;
366
391
  const profitAmount = (estimatedSellFunds * BigInt(profitRateBps)) / 10000n;
367
- // ✅ 获取贿赂金额
368
- const bribeAmount = getBribeAmount(config);
369
- const needBribeTx = bribeAmount > 0n;
370
- // ✅ 获取所有钱包的 nonces
371
- const noncesMap = new Map();
372
- await Promise.all([...sellers, ...buyers].map(async (wallet) => {
373
- const addr = wallet.address.toLowerCase();
374
- if (!noncesMap.has(addr)) {
375
- const nonce = await nonceManager.getNextNonce(wallet);
376
- noncesMap.set(addr, nonce);
377
- }
378
- }));
379
- // ✅ 构建交易列表
392
+ // ✅ 第三批并行:构建并签名所有交易
380
393
  const allTransactions = [];
381
- // 1. 贿赂交易(由主卖方支付)
394
+ const tm = new Contract(TM_ADDRESS, TM_ABI, provider);
395
+ // 1. 贿赂交易(由主卖方支付)- 先处理以确定 nonce 偏移
396
+ let bribeTxPromise = null;
382
397
  if (needBribeTx) {
383
398
  const mainSellerAddr = mainSeller.address.toLowerCase();
384
399
  const bribeNonce = noncesMap.get(mainSellerAddr);
385
400
  noncesMap.set(mainSellerAddr, bribeNonce + 1);
386
- const bribeTx = await mainSeller.signTransaction({
401
+ bribeTxPromise = mainSeller.signTransaction({
387
402
  to: BLOCKRAZOR_BUILDER_EOA,
388
403
  value: bribeAmount,
389
404
  nonce: bribeNonce,
@@ -392,40 +407,45 @@ async function fourBundleBuyFirstMultiWallet(params) {
392
407
  chainId: chainIdNum,
393
408
  type: txType
394
409
  });
395
- allTransactions.push(bribeTx);
396
410
  }
397
- // 2. 构建所有买入交易
398
- const tm = new Contract(TM_ADDRESS, TM_ABI, provider);
411
+ // 2. 预分配所有 nonces(同步操作,避免竞态)
412
+ const buyerNonces = [];
413
+ const sellerNonces = [];
414
+ buyers.forEach(buyer => {
415
+ const addr = buyer.address.toLowerCase();
416
+ const nonce = noncesMap.get(addr);
417
+ buyerNonces.push(nonce);
418
+ noncesMap.set(addr, nonce + 1);
419
+ });
420
+ sellers.forEach(seller => {
421
+ const addr = seller.address.toLowerCase();
422
+ const nonce = noncesMap.get(addr);
423
+ sellerNonces.push(nonce);
424
+ noncesMap.set(addr, nonce + 1);
425
+ });
426
+ // 3. 并行构建所有买入交易
399
427
  const buyTxPromises = buyers.map(async (buyer, i) => {
400
- const buyAmount = buyAmountsWei[i];
401
- const buyerAddr = buyer.address.toLowerCase();
402
- const nonce = noncesMap.get(buyerAddr);
403
- noncesMap.set(buyerAddr, nonce + 1);
404
428
  const tmBuyer = tm.connect(buyer);
405
- const unsigned = await tmBuyer.buyTokenAMAP.populateTransaction(0n, tokenAddress, buyer.address, buyAmount, 0n, { value: buyAmount });
429
+ const unsigned = await tmBuyer.buyTokenAMAP.populateTransaction(0n, tokenAddress, buyer.address, buyAmountsWei[i], 0n, { value: buyAmountsWei[i] });
406
430
  return buyer.signTransaction({
407
431
  ...unsigned,
408
432
  from: buyer.address,
409
- nonce,
433
+ nonce: buyerNonces[i],
410
434
  gasLimit: finalGasLimit,
411
435
  gasPrice,
412
436
  chainId: chainIdNum,
413
437
  type: txType,
414
- value: buyAmount
438
+ value: buyAmountsWei[i]
415
439
  });
416
440
  });
417
- // 3. 构建所有卖出交易
441
+ // 4. 并行构建所有卖出交易
418
442
  const sellTxPromises = sellers.map(async (seller, i) => {
419
- const sellAmount = sellAmountsWei[i];
420
- const sellerAddr = seller.address.toLowerCase();
421
- const nonce = noncesMap.get(sellerAddr);
422
- noncesMap.set(sellerAddr, nonce + 1);
423
443
  const tmSeller = tm.connect(seller);
424
- const unsigned = await tmSeller.sellToken.populateTransaction(0n, tokenAddress, sellAmount, 0n);
444
+ const unsigned = await tmSeller.sellToken.populateTransaction(0n, tokenAddress, sellAmountsWei[i], 0n);
425
445
  return seller.signTransaction({
426
446
  ...unsigned,
427
447
  from: seller.address,
428
- nonce,
448
+ nonce: sellerNonces[i],
429
449
  gasLimit: finalGasLimit,
430
450
  gasPrice,
431
451
  chainId: chainIdNum,
@@ -433,14 +453,17 @@ async function fourBundleBuyFirstMultiWallet(params) {
433
453
  value: 0n
434
454
  });
435
455
  });
436
- // ✅ 并行签名所有买卖交易
437
- const [signedBuys, signedSells] = await Promise.all([
456
+ // ✅ 并行签名所有交易(贿赂 + 买入 + 卖出)
457
+ const [bribeTx, signedBuys, signedSells] = await Promise.all([
458
+ bribeTxPromise,
438
459
  Promise.all(buyTxPromises),
439
460
  Promise.all(sellTxPromises)
440
461
  ]);
441
- // 先买后卖:买入交易在前
462
+ // 组装交易顺序:贿赂 → 买入 → 卖出
463
+ if (bribeTx)
464
+ allTransactions.push(bribeTx);
442
465
  allTransactions.push(...signedBuys, ...signedSells);
443
- // 4. 利润多跳转账(由主卖方支付)
466
+ // 5. 利润多跳转账(由主卖方支付)
444
467
  let profitHopWallets;
445
468
  if (profitAmount > 0n) {
446
469
  const mainSellerAddr = mainSeller.address.toLowerCase();
@@ -460,11 +483,6 @@ async function fourBundleBuyFirstMultiWallet(params) {
460
483
  profitHopWallets = profitHopResult.hopWallets;
461
484
  }
462
485
  nonceManager.clearTemp();
463
- // 获取代币精度用于显示
464
- const erc20 = new Contract(tokenAddress, [
465
- 'function decimals() view returns (uint8)'
466
- ], provider);
467
- const decimals = await erc20.decimals();
468
486
  return {
469
487
  signedTransactions: allTransactions,
470
488
  profitHopWallets,
@@ -609,6 +609,7 @@ function createChainContext(chain, rpcUrl) {
609
609
  * - 多个买方钱包执行买入(每个钱包1笔)
610
610
  * - 多个卖方钱包执行卖出(每个钱包1笔)
611
611
  * - 买入总价值 = 卖出总价值
612
+ * - ✅ 优化:最大化并行操作
612
613
  */
613
614
  async function flapBundleBuyFirstMultiWallet(params) {
614
615
  const { chain, buyerPrivateKeys, sellerPrivateKeys, tokenAddress, buyerFunds, config, quoteToken, quoteTokenDecimals = 18 } = params;
@@ -644,24 +645,43 @@ async function flapBundleBuyFirstMultiWallet(params) {
644
645
  if (totalFundsWei <= 0n) {
645
646
  throw new Error('交易金额必须大于0');
646
647
  }
647
- // 获取报价:买入能获得多少代币
648
- const quoteResult = await quoteBuyerOutput({
649
- portalAddress: chainContext.portalAddress,
650
- tokenAddress,
651
- buyerFundsWei: totalFundsWei,
652
- provider: chainContext.provider,
653
- skipQuoteOnError: config.skipQuoteOnError,
654
- inputToken
648
+ const finalGasLimit = getGasLimit(config);
649
+ const txType = getTxType(config);
650
+ const bribeAmount = getBribeAmount(config);
651
+ const needBribeTx = bribeAmount > 0n;
652
+ // ✅ 第一批并行:报价 + Gas价格 + 代币精度 + 所有钱包 nonces
653
+ // 预先计算所有唯一钱包地址(去重)
654
+ const allWallets = [...sellers, ...buyers];
655
+ const uniqueWallets = allWallets.filter((w, i) => {
656
+ const addr = w.address.toLowerCase();
657
+ const firstIdx = allWallets.findIndex(x => x.address.toLowerCase() === addr);
658
+ return firstIdx === i;
655
659
  });
660
+ const erc20 = new Contract(tokenAddress, ERC20_BALANCE_ABI, chainContext.provider);
661
+ const [quoteResult, gasPrice, decimals, noncesArray] = await Promise.all([
662
+ quoteBuyerOutput({
663
+ portalAddress: chainContext.portalAddress,
664
+ tokenAddress,
665
+ buyerFundsWei: totalFundsWei,
666
+ provider: chainContext.provider,
667
+ skipQuoteOnError: config.skipQuoteOnError,
668
+ inputToken
669
+ }),
670
+ getOptimizedGasPrice(chainContext.provider, getGasPriceConfig(config)),
671
+ erc20.decimals(),
672
+ nonceManager.getNextNoncesForWallets(uniqueWallets)
673
+ ]);
674
+ // 构建 nonces Map
675
+ const noncesMap = new Map();
676
+ uniqueWallets.forEach((wallet, i) => {
677
+ noncesMap.set(wallet.address.toLowerCase(), noncesArray[i]);
678
+ });
679
+ const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
656
680
  // ✅ 将总金额平均分配给买方
657
681
  const buyAmountsWei = splitAmount(totalFundsWei, buyCount);
658
682
  // ✅ 将代币平均分配给卖方
659
683
  const sellAmountsWei = splitAmount(quoteResult.sellAmountWei, sellCount);
660
- const finalGasLimit = getGasLimit(config);
661
- const gasPrice = await getOptimizedGasPrice(chainContext.provider, getGasPriceConfig(config));
662
- const txType = getTxType(config);
663
- const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
664
- // ✅ 估算利润
684
+ // 第二批并行:估算利润 + ERC20 转原生代币报价(如需要)
665
685
  const portal = new Contract(chainContext.portalAddress, PORTAL_ABI, chainContext.provider);
666
686
  const estimatedSellFunds = await estimateSellFunds(portal, tokenAddress, quoteResult.sellAmountWei, outputToken);
667
687
  const profitBase = estimatedSellFunds > 0n ? estimatedSellFunds : totalFundsWei;
@@ -671,26 +691,15 @@ async function flapBundleBuyFirstMultiWallet(params) {
671
691
  if (!useNativeToken && tokenProfitAmount > 0n) {
672
692
  nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, inputToken, tokenProfitAmount, chainContext.chainId);
673
693
  }
674
- // ✅ 获取贿赂金额
675
- const bribeAmount = getBribeAmount(config);
676
- const needBribeTx = bribeAmount > 0n;
677
- // ✅ 获取所有钱包的 nonces
678
- const noncesMap = new Map();
679
- await Promise.all([...sellers, ...buyers].map(async (wallet) => {
680
- const addr = wallet.address.toLowerCase();
681
- if (!noncesMap.has(addr)) {
682
- const nonce = await nonceManager.getNextNonce(wallet);
683
- noncesMap.set(addr, nonce);
684
- }
685
- }));
686
- // ✅ 构建交易列表
694
+ // ✅ 第三批并行:构建并签名所有交易
687
695
  const allTransactions = [];
688
- // 1. 贿赂交易(由主卖方支付)
696
+ // 1. 贿赂交易(由主卖方支付)- 先处理以确定 nonce 偏移
697
+ let bribeTxPromise = null;
689
698
  if (needBribeTx) {
690
699
  const mainSellerAddr = mainSeller.address.toLowerCase();
691
700
  const bribeNonce = noncesMap.get(mainSellerAddr);
692
701
  noncesMap.set(mainSellerAddr, bribeNonce + 1);
693
- const bribeTx = await mainSeller.signTransaction({
702
+ bribeTxPromise = mainSeller.signTransaction({
694
703
  to: BLOCKRAZOR_BUILDER_EOA,
695
704
  value: bribeAmount,
696
705
  nonce: bribeNonce,
@@ -699,50 +708,56 @@ async function flapBundleBuyFirstMultiWallet(params) {
699
708
  chainId: chainContext.chainId,
700
709
  type: txType
701
710
  });
702
- allTransactions.push(bribeTx);
703
711
  }
704
- // 2. 构建所有买入交易
712
+ // 2. 预分配所有 nonces(同步操作,避免竞态)
713
+ const buyerNonces = [];
714
+ const sellerNonces = [];
715
+ buyers.forEach(buyer => {
716
+ const addr = buyer.address.toLowerCase();
717
+ const nonce = noncesMap.get(addr);
718
+ buyerNonces.push(nonce);
719
+ noncesMap.set(addr, nonce + 1);
720
+ });
721
+ sellers.forEach(seller => {
722
+ const addr = seller.address.toLowerCase();
723
+ const nonce = noncesMap.get(addr);
724
+ sellerNonces.push(nonce);
725
+ noncesMap.set(addr, nonce + 1);
726
+ });
727
+ // 3. 并行构建所有买入交易
705
728
  const buyTxPromises = buyers.map(async (buyer, i) => {
706
- const buyAmount = buyAmountsWei[i];
707
- const buyerAddr = buyer.address.toLowerCase();
708
- const nonce = noncesMap.get(buyerAddr);
709
- noncesMap.set(buyerAddr, nonce + 1);
710
729
  const portalBuyer = new Contract(chainContext.portalAddress, PORTAL_ABI, buyer);
711
730
  const unsigned = await portalBuyer.swapExactInput.populateTransaction({
712
731
  inputToken,
713
732
  outputToken: tokenAddress,
714
- inputAmount: buyAmount,
733
+ inputAmount: buyAmountsWei[i],
715
734
  minOutputAmount: 0n,
716
735
  permitData: '0x'
717
- }, useNativeToken ? { value: buyAmount } : {});
736
+ }, useNativeToken ? { value: buyAmountsWei[i] } : {});
718
737
  return buyer.signTransaction(buildTransactionRequest(unsigned, {
719
738
  from: buyer.address,
720
- nonce,
739
+ nonce: buyerNonces[i],
721
740
  gasLimit: finalGasLimit,
722
741
  gasPrice,
723
742
  priorityFee,
724
743
  chainId: chainContext.chainId,
725
744
  txType,
726
- value: useNativeToken ? buyAmount : 0n
745
+ value: useNativeToken ? buyAmountsWei[i] : 0n
727
746
  }));
728
747
  });
729
- // 3. 构建所有卖出交易
748
+ // 4. 并行构建所有卖出交易
730
749
  const sellTxPromises = sellers.map(async (seller, i) => {
731
- const sellAmount = sellAmountsWei[i];
732
- const sellerAddr = seller.address.toLowerCase();
733
- const nonce = noncesMap.get(sellerAddr);
734
- noncesMap.set(sellerAddr, nonce + 1);
735
750
  const portalSeller = new Contract(chainContext.portalAddress, PORTAL_ABI, seller);
736
751
  const unsigned = await portalSeller.swapExactInput.populateTransaction({
737
752
  inputToken: tokenAddress,
738
753
  outputToken,
739
- inputAmount: sellAmount,
754
+ inputAmount: sellAmountsWei[i],
740
755
  minOutputAmount: 0n,
741
756
  permitData: '0x'
742
757
  });
743
758
  return seller.signTransaction(buildTransactionRequest(unsigned, {
744
759
  from: seller.address,
745
- nonce,
760
+ nonce: sellerNonces[i],
746
761
  gasLimit: finalGasLimit,
747
762
  gasPrice,
748
763
  priorityFee,
@@ -751,14 +766,17 @@ async function flapBundleBuyFirstMultiWallet(params) {
751
766
  value: 0n
752
767
  }));
753
768
  });
754
- // ✅ 并行签名所有买卖交易
755
- const [signedBuys, signedSells] = await Promise.all([
769
+ // ✅ 并行签名所有交易(贿赂 + 买入 + 卖出)
770
+ const [bribeTx, signedBuys, signedSells] = await Promise.all([
771
+ bribeTxPromise,
756
772
  Promise.all(buyTxPromises),
757
773
  Promise.all(sellTxPromises)
758
774
  ]);
759
- // 先买后卖:买入交易在前
775
+ // 组装交易顺序:贿赂 → 买入 → 卖出
776
+ if (bribeTx)
777
+ allTransactions.push(bribeTx);
760
778
  allTransactions.push(...signedBuys, ...signedSells);
761
- // 4. 利润多跳转账(由主卖方支付)
779
+ // 5. 利润多跳转账(由主卖方支付)
762
780
  let profitHopWallets;
763
781
  if (nativeProfitAmount > 0n) {
764
782
  const mainSellerAddr = mainSeller.address.toLowerCase();
@@ -778,14 +796,6 @@ async function flapBundleBuyFirstMultiWallet(params) {
778
796
  }
779
797
  }
780
798
  nonceManager.clearTemp();
781
- // 获取代币精度
782
- const sellerInfo = await ensureSellerBalance({
783
- tokenAddress,
784
- provider: chainContext.provider,
785
- seller: mainSeller,
786
- sellAmountWei: 0n,
787
- skipBalanceCheck: true
788
- });
789
799
  return {
790
800
  signedTransactions: allTransactions,
791
801
  profitHopWallets,
@@ -793,12 +803,12 @@ async function flapBundleBuyFirstMultiWallet(params) {
793
803
  buyerAddress: buyers.map(b => b.address).join(','),
794
804
  sellerAddress: sellers.map(s => s.address).join(','),
795
805
  buyAmount: ethers.formatEther(totalFundsWei),
796
- sellAmount: ethers.formatUnits(quoteResult.sellAmountWei, sellerInfo.decimals),
806
+ sellAmount: ethers.formatUnits(quoteResult.sellAmountWei, decimals),
797
807
  profitAmount: nativeProfitAmount > 0n ? ethers.formatEther(nativeProfitAmount) : undefined,
798
808
  buyCount,
799
809
  sellCount,
800
810
  buyAmounts: buyAmountsWei.map(amt => ethers.formatEther(amt)),
801
- sellAmounts: sellAmountsWei.map(amt => ethers.formatUnits(amt, sellerInfo.decimals))
811
+ sellAmounts: sellAmountsWei.map(amt => ethers.formatUnits(amt, decimals))
802
812
  }
803
813
  };
804
814
  }
@@ -754,6 +754,7 @@ function buildNoncePlanFromStartNonces(startNonces, sameAddress, profitNeeded, n
754
754
  * - 多个买方钱包执行买入(每个钱包1笔)
755
755
  * - 多个卖方钱包执行卖出(每个钱包1笔)
756
756
  * - 买入总价值 = 卖出总价值
757
+ * - ✅ 优化:最大化并行操作
757
758
  */
758
759
  async function pancakeBundleBuyFirstMultiWallet(params) {
759
760
  const { buyerPrivateKeys, sellerPrivateKeys, tokenAddress, routeParams, buyerFunds, config, quoteToken, quoteTokenDecimals = 18 } = params;
@@ -790,21 +791,40 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
790
791
  if (totalFundsWei <= 0n) {
791
792
  throw new Error('交易金额必须大于0');
792
793
  }
793
- // 获取报价:买入能获得多少代币
794
- const quoteResult = await quoteTokenOutput({
795
- routeParams,
796
- buyerFundsWei: totalFundsWei,
797
- provider: context.provider
794
+ const finalGasLimit = getGasLimit(config);
795
+ const txType = config.txType ?? 0;
796
+ const deadline = BigInt(getDeadline());
797
+ const bribeAmount = config.bribeAmount && config.bribeAmount > 0
798
+ ? ethers.parseEther(String(config.bribeAmount))
799
+ : 0n;
800
+ const needBribeTx = bribeAmount > 0n;
801
+ // ✅ 第一批并行:报价 + Gas价格 + 所有钱包 nonces
802
+ // 预先计算所有唯一钱包地址(去重)
803
+ const allWallets = [...sellers, ...buyers];
804
+ const uniqueWallets = allWallets.filter((w, i) => {
805
+ const addr = w.address.toLowerCase();
806
+ const firstIdx = allWallets.findIndex(x => x.address.toLowerCase() === addr);
807
+ return firstIdx === i;
808
+ });
809
+ const [quoteResult, gasPrice, noncesArray] = await Promise.all([
810
+ quoteTokenOutput({
811
+ routeParams,
812
+ buyerFundsWei: totalFundsWei,
813
+ provider: context.provider
814
+ }),
815
+ getGasPrice(context.provider, config),
816
+ nonceManager.getNextNoncesForWallets(uniqueWallets)
817
+ ]);
818
+ // 构建 nonces Map
819
+ const noncesMap = new Map();
820
+ uniqueWallets.forEach((wallet, i) => {
821
+ noncesMap.set(wallet.address.toLowerCase(), noncesArray[i]);
798
822
  });
799
823
  // ✅ 将总金额平均分配给买方
800
824
  const buyAmountsWei = splitAmount(totalFundsWei, buyCount);
801
825
  // ✅ 将代币平均分配给卖方
802
826
  const sellAmountsWei = splitAmount(quoteResult.quotedTokenOut, sellCount);
803
- const finalGasLimit = getGasLimit(config);
804
- const gasPrice = await getGasPrice(context.provider, config);
805
- const txType = config.txType ?? 0;
806
- const deadline = BigInt(getDeadline());
807
- // ✅ 估算利润
827
+ // 第二批并行:估算利润(可以和交易构建并行,但需要先获取报价)
808
828
  const estimatedProfitFromSell = await estimateProfitAmount({
809
829
  provider: context.provider,
810
830
  tokenAddress,
@@ -813,29 +833,15 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
813
833
  });
814
834
  const profitBase = estimatedProfitFromSell > 0n ? estimatedProfitFromSell : totalFundsWei;
815
835
  const profitAmount = (profitBase * BigInt(profitRateBps)) / 10000n;
816
- // ✅ 获取贿赂金额
817
- const bribeAmount = config.bribeAmount && config.bribeAmount > 0
818
- ? ethers.parseEther(String(config.bribeAmount))
819
- : 0n;
820
- const needBribeTx = bribeAmount > 0n;
821
- // ✅ 获取所有钱包的 nonces
822
- const allWallets = [...sellers, ...buyers];
823
- const noncesMap = new Map();
824
- await Promise.all(allWallets.map(async (wallet) => {
825
- const addr = wallet.address.toLowerCase();
826
- if (!noncesMap.has(addr)) {
827
- const nonce = await nonceManager.getNextNonce(wallet);
828
- noncesMap.set(addr, nonce);
829
- }
830
- }));
831
- // ✅ 构建交易列表
836
+ // ✅ 第三批并行:构建并签名所有交易
832
837
  const allTransactions = [];
833
- // 1. 贿赂交易(由主卖方支付)
838
+ // 1. 贿赂交易(由主卖方支付)- 先处理以确定 nonce 偏移
839
+ let bribeTxPromise = null;
834
840
  if (needBribeTx) {
835
841
  const mainSellerAddr = mainSeller.address.toLowerCase();
836
842
  const bribeNonce = noncesMap.get(mainSellerAddr);
837
843
  noncesMap.set(mainSellerAddr, bribeNonce + 1);
838
- const bribeTx = await mainSeller.signTransaction({
844
+ bribeTxPromise = mainSeller.signTransaction({
839
845
  to: BLOCKRAZOR_BUILDER_EOA,
840
846
  value: bribeAmount,
841
847
  nonce: bribeNonce,
@@ -844,17 +850,27 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
844
850
  chainId: context.chainId,
845
851
  type: txType
846
852
  });
847
- allTransactions.push(bribeTx);
848
853
  }
849
- // 2. 构建所有买入交易
854
+ // 2. 预分配所有 nonces(同步操作,避免竞态)
855
+ const buyerNonces = [];
856
+ const sellerNonces = [];
857
+ buyers.forEach(buyer => {
858
+ const addr = buyer.address.toLowerCase();
859
+ const nonce = noncesMap.get(addr);
860
+ buyerNonces.push(nonce);
861
+ noncesMap.set(addr, nonce + 1);
862
+ });
863
+ sellers.forEach(seller => {
864
+ const addr = seller.address.toLowerCase();
865
+ const nonce = noncesMap.get(addr);
866
+ sellerNonces.push(nonce);
867
+ noncesMap.set(addr, nonce + 1);
868
+ });
869
+ // 3. 并行构建所有买入交易
850
870
  const buyTxPromises = buyers.map(async (buyer, i) => {
851
- const buyAmount = buyAmountsWei[i];
852
- const buyerAddr = buyer.address.toLowerCase();
853
- const nonce = noncesMap.get(buyerAddr);
854
- noncesMap.set(buyerAddr, nonce + 1);
855
871
  const unsigned = await buildSingleBuyTx({
856
872
  routeParams,
857
- buyAmount,
873
+ buyAmount: buyAmountsWei[i],
858
874
  buyer,
859
875
  tokenAddress,
860
876
  useNativeToken,
@@ -863,22 +879,18 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
863
879
  return buyer.signTransaction({
864
880
  ...unsigned,
865
881
  from: buyer.address,
866
- nonce,
882
+ nonce: buyerNonces[i],
867
883
  gasLimit: finalGasLimit,
868
884
  gasPrice,
869
885
  chainId: context.chainId,
870
886
  type: txType
871
887
  });
872
888
  });
873
- // 3. 构建所有卖出交易
889
+ // 4. 并行构建所有卖出交易
874
890
  const sellTxPromises = sellers.map(async (seller, i) => {
875
- const sellAmount = sellAmountsWei[i];
876
- const sellerAddr = seller.address.toLowerCase();
877
- const nonce = noncesMap.get(sellerAddr);
878
- noncesMap.set(sellerAddr, nonce + 1);
879
891
  const unsigned = await buildSingleSellTx({
880
892
  routeParams,
881
- sellAmount,
893
+ sellAmount: sellAmountsWei[i],
882
894
  seller,
883
895
  tokenAddress,
884
896
  useNativeToken,
@@ -887,21 +899,24 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
887
899
  return seller.signTransaction({
888
900
  ...unsigned,
889
901
  from: seller.address,
890
- nonce,
902
+ nonce: sellerNonces[i],
891
903
  gasLimit: finalGasLimit,
892
904
  gasPrice,
893
905
  chainId: context.chainId,
894
906
  type: txType
895
907
  });
896
908
  });
897
- // ✅ 并行签名所有买卖交易
898
- const [signedBuys, signedSells] = await Promise.all([
909
+ // ✅ 并行签名所有交易(贿赂 + 买入 + 卖出)
910
+ const [bribeTx, signedBuys, signedSells] = await Promise.all([
911
+ bribeTxPromise,
899
912
  Promise.all(buyTxPromises),
900
913
  Promise.all(sellTxPromises)
901
914
  ]);
902
- // 先买后卖:买入交易在前
915
+ // 组装交易顺序:贿赂 → 买入 → 卖出
916
+ if (bribeTx)
917
+ allTransactions.push(bribeTx);
903
918
  allTransactions.push(...signedBuys, ...signedSells);
904
- // 4. 利润多跳转账(由主卖方支付)
919
+ // 5. 利润多跳转账(由主卖方支付)
905
920
  let profitHopWallets;
906
921
  if (profitAmount > 0n) {
907
922
  const mainSellerAddr = mainSeller.address.toLowerCase();
@@ -9,7 +9,7 @@ import { type GeneratedWallet } from './wallet.js';
9
9
  * 用于在 bundle 交易中管理多个钱包的 nonce
10
10
  *
11
11
  * 策略:
12
- * 1. 每次获取 nonce 时查询链上最新状态('latest' 不含 pending)
12
+ * 1. 每次获取 nonce 时查询链上状态(使用 'pending' 包含待处理交易)
13
13
  * 2. 仅在同一批次内维护临时递增缓存
14
14
  * 3. 不持久化缓存,避免因失败交易导致 nonce 过高
15
15
  */
@@ -9,7 +9,7 @@ import { generateWallets } from './wallet.js';
9
9
  * 用于在 bundle 交易中管理多个钱包的 nonce
10
10
  *
11
11
  * 策略:
12
- * 1. 每次获取 nonce 时查询链上最新状态('latest' 不含 pending)
12
+ * 1. 每次获取 nonce 时查询链上状态(使用 'pending' 包含待处理交易)
13
13
  * 2. 仅在同一批次内维护临时递增缓存
14
14
  * 3. 不持久化缓存,避免因失败交易导致 nonce 过高
15
15
  */
@@ -33,9 +33,9 @@ export class NonceManager {
33
33
  this.tempNonceCache.set(key, cachedNonce + 1);
34
34
  return cachedNonce;
35
35
  }
36
- // ✅ 使用 'latest' 获取 nonce(已确认的交易)
36
+ // ✅ 使用 'pending' 获取 nonce(包含待处理交易)
37
37
  // 由于前端已移除 nonce 缓存,SDK 每次都从链上获取最新状态
38
- const onchainNonce = await this.provider.getTransactionCount(address, 'latest');
38
+ const onchainNonce = await this.provider.getTransactionCount(address, 'pending');
39
39
  // 缓存下一个值(仅在当前批次内有效)
40
40
  this.tempNonceCache.set(key, onchainNonce + 1);
41
41
  return onchainNonce;
@@ -54,7 +54,7 @@ export class NonceManager {
54
54
  startNonce = this.tempNonceCache.get(key);
55
55
  }
56
56
  else {
57
- startNonce = await this.provider.getTransactionCount(address, 'latest');
57
+ startNonce = await this.provider.getTransactionCount(address, 'pending');
58
58
  }
59
59
  // 更新缓存
60
60
  this.tempNonceCache.set(key, startNonce + count);
@@ -101,9 +101,10 @@ export class NonceManager {
101
101
  let queryResults;
102
102
  try {
103
103
  // ✅ 使用 JSON-RPC 批量请求(单次网络往返)
104
+ // ✅ 使用 'pending' 状态获取 nonce,避免与待处理交易冲突
104
105
  const batchRequests = needQuery.map(({ address }, idx) => ({
105
106
  method: 'eth_getTransactionCount',
106
- params: [address, 'latest'],
107
+ params: [address, 'pending'],
107
108
  id: idx + 1,
108
109
  jsonrpc: '2.0'
109
110
  }));
@@ -119,7 +120,8 @@ export class NonceManager {
119
120
  }
120
121
  catch {
121
122
  // 如果批量请求失败,回退到 Promise.all
122
- const queryPromises = needQuery.map(({ address }) => this.provider.getTransactionCount(address, 'latest'));
123
+ // 同样使用 'pending' 状态
124
+ const queryPromises = needQuery.map(({ address }) => this.provider.getTransactionCount(address, 'pending'));
123
125
  queryResults = await Promise.all(queryPromises);
124
126
  }
125
127
  // 填充结果并更新缓存
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.79",
3
+ "version": "1.4.81",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",