four-flap-meme-sdk 1.4.39 → 1.4.41

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.
@@ -1,5 +1,5 @@
1
1
  import { ethers, Wallet } from 'ethers';
2
- import { getOptimizedGasPrice, NonceManager } from '../../utils/bundle-helpers.js';
2
+ import { getOptimizedGasPrice, NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
3
3
  import { PROFIT_CONFIG, ZERO_ADDRESS } from '../../utils/constants.js';
4
4
  import { getTxType, getGasPriceConfig, shouldExtractProfit, getProfitRecipient } from './config.js';
5
5
  import { getErc20DecimalsMerkle as _getErc20DecimalsMerkle, generateHopWallets as _generateHopWallets, normalizeAmounts as _normalizeAmounts, batchGetBalances as _batchGetBalances, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress } from './internal.js';
@@ -283,19 +283,22 @@ export async function disperseWithBundleMerkle(params) {
283
283
  chainId: chainIdNum,
284
284
  type: txType
285
285
  }));
286
- // 利润交易也并行签名
286
+ signedTxs.push(...(await Promise.all(txPromises)));
287
+ // ✅ 利润多跳转账(强制 2 跳中转)
287
288
  if (extractProfit && totalProfit > 0n) {
288
- txPromises.push(mainWallet.signTransaction({
289
- to: getProfitRecipient(),
290
- value: totalProfit,
291
- nonce: nonces[recipients.length],
289
+ const profitHopResult = await buildProfitHopTransactions({
290
+ provider,
291
+ payerWallet: mainWallet,
292
+ profitAmount: totalProfit,
293
+ profitRecipient: getProfitRecipient(),
294
+ hopCount: PROFIT_HOP_COUNT,
292
295
  gasPrice,
293
- gasLimit: 21000n,
294
296
  chainId: chainIdNum,
295
- type: txType
296
- }));
297
+ txType,
298
+ startNonce: nonces[recipients.length]
299
+ });
300
+ signedTxs.push(...profitHopResult.signedTransactions);
297
301
  }
298
- signedTxs.push(...(await Promise.all(txPromises)));
299
302
  }
300
303
  else {
301
304
  // ✅ ERC20:并行获取 decimals(传入 chainIdNum 避免 NETWORK_ERROR)
@@ -332,19 +335,22 @@ export async function disperseWithBundleMerkle(params) {
332
335
  chainId: chainIdNum,
333
336
  type: txType
334
337
  }));
335
- // 利润交易:转等值的原生代币(BNB)
338
+ signedTxs.push(...(await Promise.all(txPromises)));
339
+ // ✅ 利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
336
340
  if (extractProfit && nativeProfitAmount > 0n) {
337
- txPromises.push(mainWallet.signTransaction({
338
- to: getProfitRecipient(),
339
- value: nativeProfitAmount, // ✅ 转等值 BNB
340
- nonce: nonces[recipients.length],
341
+ const profitHopResult = await buildProfitHopTransactions({
342
+ provider,
343
+ payerWallet: mainWallet,
344
+ profitAmount: nativeProfitAmount,
345
+ profitRecipient: getProfitRecipient(),
346
+ hopCount: PROFIT_HOP_COUNT,
341
347
  gasPrice,
342
- gasLimit: 21000n,
343
348
  chainId: chainIdNum,
344
- type: txType
345
- }));
349
+ txType,
350
+ startNonce: nonces[recipients.length]
351
+ });
352
+ signedTxs.push(...profitHopResult.signedTransactions);
346
353
  }
347
- signedTxs.push(...(await Promise.all(txPromises)));
348
354
  }
349
355
  }
350
356
  else {
@@ -579,25 +585,25 @@ export async function disperseWithBundleMerkle(params) {
579
585
  const nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalTokenProfit, chainIdNum, tokenPoolType, quoteToken, config.rpcUrl);
580
586
  totalProfit = nativeProfitAmount; // 更新为原生代币利润
581
587
  }
582
- // 利润转账(转等值原生代币)
588
+ // ✅ 并行签名所有交易
589
+ const signedTxsResult = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
590
+ signedTxs.push(...signedTxsResult);
591
+ // ✅ 利润多跳转账(强制 2 跳中转)
583
592
  if (extractProfit && totalProfit > 0n) {
584
593
  const profitNonce = allMainNonces[mainNonceIdx++];
585
- txsToSign.push({
586
- wallet: mainWallet,
587
- tx: {
588
- to: getProfitRecipient(),
589
- value: totalProfit, // ✅ 转等值原生代币
590
- nonce: profitNonce,
591
- gasPrice,
592
- gasLimit: 21000n,
593
- chainId: chainIdNum,
594
- type: txType
595
- }
594
+ const profitHopResult = await buildProfitHopTransactions({
595
+ provider,
596
+ payerWallet: mainWallet,
597
+ profitAmount: totalProfit,
598
+ profitRecipient: getProfitRecipient(),
599
+ hopCount: PROFIT_HOP_COUNT,
600
+ gasPrice,
601
+ chainId: chainIdNum,
602
+ txType,
603
+ startNonce: profitNonce
596
604
  });
605
+ signedTxs.push(...profitHopResult.signedTransactions);
597
606
  }
598
- // ✅ 并行签名所有交易
599
- const signedTxsResult = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
600
- signedTxs.push(...signedTxsResult);
601
607
  }
602
608
  // ✅ 简化返回:只返回签名交易、多跳钱包和元数据
603
609
  return {
@@ -811,19 +817,21 @@ export async function sweepWithBundleMerkle(params) {
811
817
  });
812
818
  const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
813
819
  signedTxs.push(...allTxs);
814
- // ✅ 第三步:在所有归集交易之后,生成利润交易
820
+ // ✅ 第三步:利润多跳转账(强制 2 跳中转)
815
821
  if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
816
822
  const payerWallet = wallets[maxSweepIndex];
817
- const profitTx = await payerWallet.signTransaction({
818
- to: getProfitRecipient(),
819
- value: totalProfit,
820
- nonce: payerProfitNonce,
823
+ const profitHopResult = await buildProfitHopTransactions({
824
+ provider,
825
+ payerWallet,
826
+ profitAmount: totalProfit,
827
+ profitRecipient: getProfitRecipient(),
828
+ hopCount: PROFIT_HOP_COUNT,
821
829
  gasPrice,
822
- gasLimit: nativeGasLimit,
823
830
  chainId: chainIdNum,
824
- type: txType
831
+ txType,
832
+ startNonce: payerProfitNonce
825
833
  });
826
- signedTxs.push(profitTx);
834
+ signedTxs.push(...profitHopResult.signedTransactions);
827
835
  }
828
836
  }
829
837
  else {
@@ -947,20 +955,22 @@ export async function sweepWithBundleMerkle(params) {
947
955
  });
948
956
  const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
949
957
  signedTxs.push(...allTxs);
950
- // ✅ 第三步:生成利润交易(转等值原生代币)
958
+ // ✅ 第三步:利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
951
959
  if (extractProfit && nativeProfitAmount > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
952
960
  const payerWallet = wallets[maxSweepIndex];
953
961
  totalProfit = nativeProfitAmount; // 更新为原生代币利润
954
- const profitTx = await payerWallet.signTransaction({
955
- to: getProfitRecipient(),
956
- value: nativeProfitAmount, // ✅ 转等值原生代币
957
- nonce: payerProfitNonce,
962
+ const profitHopResult = await buildProfitHopTransactions({
963
+ provider,
964
+ payerWallet,
965
+ profitAmount: nativeProfitAmount,
966
+ profitRecipient: getProfitRecipient(),
967
+ hopCount: PROFIT_HOP_COUNT,
958
968
  gasPrice,
959
- gasLimit: 21000n,
960
969
  chainId: chainIdNum,
961
- type: txType
970
+ txType,
971
+ startNonce: payerProfitNonce
962
972
  });
963
- signedTxs.push(profitTx);
973
+ signedTxs.push(...profitHopResult.signedTransactions);
964
974
  }
965
975
  }
966
976
  }
@@ -1318,20 +1328,22 @@ export async function sweepWithBundleMerkle(params) {
1318
1328
  nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalTokenProfit, chainIdNum, tokenPoolType, quoteToken, config.rpcUrl);
1319
1329
  totalProfit = nativeProfitAmount;
1320
1330
  }
1321
- // 由归集金额最大的钱包支付利润
1331
+ // ✅ 利润多跳转账(强制 2 跳中转)
1322
1332
  if (nativeProfitAmount > 0n && maxSweepIndex >= 0) {
1323
1333
  const payerWallet = sourceWallets[maxSweepIndex];
1324
1334
  const profitNonce = await nonceManager.getNextNonce(payerWallet);
1325
- const profitTx = await payerWallet.signTransaction({
1326
- to: getProfitRecipient(),
1327
- value: nativeProfitAmount,
1328
- nonce: profitNonce,
1335
+ const profitHopResult = await buildProfitHopTransactions({
1336
+ provider,
1337
+ payerWallet,
1338
+ profitAmount: nativeProfitAmount,
1339
+ profitRecipient: getProfitRecipient(),
1340
+ hopCount: PROFIT_HOP_COUNT,
1329
1341
  gasPrice,
1330
- gasLimit: 21000n,
1331
1342
  chainId: chainIdNum,
1332
- type: txType
1343
+ txType,
1344
+ startNonce: profitNonce
1333
1345
  });
1334
- signedTxs.push(profitTx);
1346
+ signedTxs.push(...profitHopResult.signedTransactions);
1335
1347
  }
1336
1348
  }
1337
1349
  }
@@ -1,6 +1,7 @@
1
1
  import { ethers, Wallet, JsonRpcProvider } from 'ethers';
2
2
  import { Club48Client, sendBatchPrivateTransactions, BUILDER_CONTROL_EOA } from '../clients/club48.js';
3
3
  import { ADDRESSES, PROFIT_CONFIG } from '../utils/constants.js';
4
+ import { buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../utils/bundle-helpers.js';
4
5
  import TM2Abi from '../abis/TokenManager2.json' with { type: 'json' };
5
6
  import { FourClient, buildLoginMessage } from '../clients/four.js';
6
7
  import { trySell } from './tm.js';
@@ -279,22 +280,25 @@ export async function createTokenWithBundleBuy(params) {
279
280
  }));
280
281
  signedTxs.push(...signedBuyTxList);
281
282
  buyTxs.push(...signedBuyTxList);
282
- // ✅ 聚合利润:由买入最多的人支付总利润
283
+ // ✅ 聚合利润:由买入最多的人支付总利润(强制 2 跳中转)
283
284
  const totalBuyAmount = buyAmountsWei.reduce((sum, amount) => sum + amount, 0n);
284
285
  const totalProfitAmount = (totalBuyAmount * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
285
286
  if (totalProfitAmount > 0n) {
286
287
  const payerWallet = new Wallet(privateKeys[maxBuyerIndex + 1], provider);
287
- const profitTx = await payerWallet.signTransaction({
288
- to: PROFIT_CONFIG.RECIPIENT,
289
- value: totalProfitAmount,
290
- nonce: await getNextNonce(payerWallet),
288
+ const profitNonce = await getNextNonce(payerWallet);
289
+ const profitHopResult = await buildProfitHopTransactions({
290
+ provider,
291
+ payerWallet,
292
+ profitAmount: totalProfitAmount,
293
+ profitRecipient: PROFIT_CONFIG.RECIPIENT,
294
+ hopCount: PROFIT_HOP_COUNT,
291
295
  gasPrice,
292
- gasLimit: 21000n,
293
296
  chainId: 56,
294
- type: 0 // Legacy transaction
297
+ txType: 0,
298
+ startNonce: profitNonce
295
299
  });
296
- signedTxs.push(profitTx);
297
- profitTxs.push(profitTx);
300
+ signedTxs.push(...profitHopResult.signedTransactions);
301
+ profitTxs.push(...profitHopResult.signedTransactions);
298
302
  }
299
303
  // 可选 tipTx
300
304
  if (config.tipAmountWei && config.tipAmountWei > 0n) {
@@ -472,21 +476,24 @@ export async function batchBuyWithBundle(params) {
472
476
  return data.buyerWallet.signTransaction(buyTxRequest);
473
477
  }));
474
478
  signedTxs.push(...signedBuyTxList);
475
- // ✅ 聚合利润:由买入最多的人支付总利润
479
+ // ✅ 聚合利润:由买入最多的人支付总利润(强制 2 跳中转)
476
480
  const totalFunds = fundsWeiList.reduce((sum, f) => sum + f, 0n);
477
481
  const totalProfit = (totalFunds * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
478
482
  if (totalProfit > 0n) {
479
483
  const payerWallet = wallets[maxBuyerIndex];
480
- const profitTx = await payerWallet.signTransaction({
481
- to: PROFIT_CONFIG.RECIPIENT,
482
- value: totalProfit,
483
- nonce: getNextNonceLocal(payerWallet),
484
+ const profitNonce = getNextNonceLocal(payerWallet);
485
+ const profitHopResult = await buildProfitHopTransactions({
486
+ provider,
487
+ payerWallet,
488
+ profitAmount: totalProfit,
489
+ profitRecipient: PROFIT_CONFIG.RECIPIENT,
490
+ hopCount: PROFIT_HOP_COUNT,
484
491
  gasPrice,
485
- gasLimit: 21000n,
486
492
  chainId: 56,
487
- type: 0
493
+ txType: 0,
494
+ startNonce: profitNonce
488
495
  });
489
- signedTxs.push(profitTx);
496
+ signedTxs.push(...profitHopResult.signedTransactions);
490
497
  }
491
498
  // 可选 tipTx(置前)
492
499
  if (config.tipAmountWei && config.tipAmountWei > 0n) {
@@ -609,21 +616,24 @@ export async function batchSellWithBundle(params) {
609
616
  return data.sellerWallet.signTransaction(sellTxRequest);
610
617
  }));
611
618
  signedTxs.push(...signedSellTxList);
612
- // ✅ 聚合利润:由收益最高的人支付总利润
619
+ // ✅ 聚合利润:由收益最高的人支付总利润(强制 2 跳中转)
613
620
  const totalBnbOut = estimatedBnbOuts.reduce((sum, b) => sum + b, 0n);
614
621
  const totalProfit = (totalBnbOut * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
615
622
  if (totalProfit > 0n) {
616
623
  const payerWallet = wallets[maxSellerIndex];
617
- const profitTx = await payerWallet.signTransaction({
618
- to: PROFIT_CONFIG.RECIPIENT,
619
- value: totalProfit,
620
- nonce: getNextNonceLocal(payerWallet),
624
+ const profitNonce = getNextNonceLocal(payerWallet);
625
+ const profitHopResult = await buildProfitHopTransactions({
626
+ provider,
627
+ payerWallet,
628
+ profitAmount: totalProfit,
629
+ profitRecipient: PROFIT_CONFIG.RECIPIENT,
630
+ hopCount: PROFIT_HOP_COUNT,
621
631
  gasPrice,
622
- gasLimit: 21000n,
623
632
  chainId: 56,
624
- type: 0
633
+ txType: 0,
634
+ startNonce: profitNonce
625
635
  });
626
- signedTxs.push(profitTx);
636
+ signedTxs.push(...profitHopResult.signedTransactions);
627
637
  }
628
638
  // 可选 tipTx(置前)
629
639
  if (config.tipAmountWei && config.tipAmountWei > 0n) {
@@ -8,7 +8,7 @@
8
8
  * 收费方式:交易末尾附加利润提取交易(和内盘一致)
9
9
  */
10
10
  import { ethers, Wallet, JsonRpcProvider, Contract } from 'ethers';
11
- import { NonceManager, getOptimizedGasPrice, getDeadline as _getDeadline } from '../utils/bundle-helpers.js';
11
+ import { NonceManager, getOptimizedGasPrice, getDeadline as _getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../utils/bundle-helpers.js';
12
12
  import { PROFIT_CONFIG, ZERO_ADDRESS, BLOCKRAZOR_BUILDER_EOA, ADDRESSES } from '../utils/constants.js';
13
13
  import { V2_ROUTER_ABI as _V2_ROUTER_ABI, V3_ROUTER02_ABI as _V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI as _V3_ROUTER_LEGACY_ABI, SWAP_ROUTER02_V2_ABI as _SWAP_ROUTER02_V2_ABI, ERC20_ABI } from '../abis/common.js';
14
14
  import { getTokenToNativeQuote } from '../utils/quote-helpers.js';
@@ -354,18 +354,24 @@ function findMaxFlowIndex(amounts) {
354
354
  function calculateProfitAmount(totalFlowWei) {
355
355
  return (totalFlowWei * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
356
356
  }
357
- /** 构建利润提取交易 */
358
- async function buildProfitTransaction(wallet, profitAmountWei, nonce, gasPrice, chainId, txType = 0) {
359
- const tx = {
360
- to: PROFIT_CONFIG.RECIPIENT,
361
- value: profitAmountWei,
362
- nonce,
363
- gasLimit: 21000n,
357
+ /**
358
+ * 构建利润多跳转账交易(强制 2 跳中转)
359
+ */
360
+ async function buildProfitTransactionWithHops(provider, wallet, profitAmountWei, nonce, gasPrice, chainId, txType = 0) {
361
+ if (profitAmountWei <= 0n)
362
+ return [];
363
+ const profitHopResult = await buildProfitHopTransactions({
364
+ provider,
365
+ payerWallet: wallet,
366
+ profitAmount: profitAmountWei,
367
+ profitRecipient: PROFIT_CONFIG.RECIPIENT,
368
+ hopCount: PROFIT_HOP_COUNT,
364
369
  gasPrice,
365
370
  chainId,
366
- type: txType,
367
- };
368
- return wallet.signTransaction(tx);
371
+ txType,
372
+ startNonce: nonce
373
+ });
374
+ return profitHopResult.signedTransactions;
369
375
  }
370
376
  /**
371
377
  * 获取贿赂金额(wei)
@@ -535,19 +541,18 @@ export async function directV2BatchBuy(params) {
535
541
  type: txType,
536
542
  }).then(tx => ({ type: 'swap', index: i, tx })));
537
543
  });
538
- // 利润交易
539
- if (hasProfit) {
540
- const profitNonce = nonces[maxFlowIndex] + nonceOffsets[maxFlowIndex] + 1;
541
- signPromises.push(buildProfitTransaction(wallets[maxFlowIndex], profitWei, profitNonce, gasPrice, chainId, txType)
542
- .then(tx => ({ type: 'profit', index: 0, tx })));
543
- }
544
544
  // ✅ 并行执行所有签名
545
545
  const signedResults = await Promise.all(signPromises);
546
- // 按类型分组并按顺序组装:贿赂 → 交易 → 利润
546
+ // 按类型分组并按顺序组装:贿赂 → 交易
547
547
  const bribeTxs = signedResults.filter(r => r.type === 'bribe').map(r => r.tx);
548
548
  const swapTxs = signedResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
549
- const profitTxs = signedResults.filter(r => r.type === 'profit').map(r => r.tx);
550
- const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
549
+ const signedTxs = [...bribeTxs, ...swapTxs];
550
+ // 利润多跳转账(强制 2 跳中转)
551
+ if (hasProfit) {
552
+ const profitNonce = nonces[maxFlowIndex] + nonceOffsets[maxFlowIndex] + 1;
553
+ const profitHopTxs = await buildProfitTransactionWithHops(provider, wallets[maxFlowIndex], profitWei, profitNonce, gasPrice, chainId, txType);
554
+ signedTxs.push(...profitHopTxs);
555
+ }
551
556
  return {
552
557
  signedTransactions: signedTxs,
553
558
  metadata: {
@@ -699,17 +704,16 @@ export async function directV2BatchSell(params) {
699
704
  nativeProfitPromise
700
705
  ]);
701
706
  const profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
702
- // 利润交易(需要等 ERC20 报价完成才能确定金额)
703
- let profitTx = null;
707
+ // 利润多跳转账(强制 2 跳中转)
708
+ let profitTxs = [];
704
709
  if (profitWei > 0n && wallets.length > 0) {
705
710
  const profitNonce = nonces[maxOutputIndex] + nonceOffsets[maxOutputIndex] + 1;
706
- profitTx = await buildProfitTransaction(wallets[maxOutputIndex], profitWei, profitNonce, gasPrice, chainId, txType);
711
+ profitTxs = await buildProfitTransactionWithHops(provider, wallets[maxOutputIndex], profitWei, profitNonce, gasPrice, chainId, txType);
707
712
  }
708
713
  // 按类型分组并按顺序组装
709
714
  const validResults = signedResults.filter((r) => r !== null);
710
715
  const bribeTxs = validResults.filter(r => r.type === 'bribe').map(r => r.tx);
711
716
  const swapTxs = validResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
712
- const profitTxs = profitTx ? [profitTx] : [];
713
717
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
714
718
  return {
715
719
  signedTransactions: signedTxs,
@@ -801,15 +805,15 @@ export async function directV3BatchBuy(params) {
801
805
  signPromises.push(wallet.signTransaction({ to: routerAddress, data: txData, value: txValue, nonce: nonces[i] + nonceOffsets[i], gasLimit, gasPrice, chainId, type: txType })
802
806
  .then(tx => ({ type: 'swap', index: i, tx })));
803
807
  });
804
- if (hasProfit) {
805
- const profitNonce = nonces[maxFlowIndex] + nonceOffsets[maxFlowIndex] + 1;
806
- signPromises.push(buildProfitTransaction(wallets[maxFlowIndex], profitWei, profitNonce, gasPrice, chainId, txType)
807
- .then(tx => ({ type: 'profit', index: 0, tx })));
808
- }
809
808
  const signedResults = await Promise.all(signPromises);
810
809
  const bribeTxs = signedResults.filter(r => r.type === 'bribe').map(r => r.tx);
811
810
  const swapTxs = signedResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
812
- const profitTxs = signedResults.filter(r => r.type === 'profit').map(r => r.tx);
811
+ // 利润多跳转账(强制 2 跳中转)
812
+ let profitTxs = [];
813
+ if (hasProfit) {
814
+ const profitNonce = nonces[maxFlowIndex] + nonceOffsets[maxFlowIndex] + 1;
815
+ profitTxs = await buildProfitTransactionWithHops(provider, wallets[maxFlowIndex], profitWei, profitNonce, gasPrice, chainId, txType);
816
+ }
813
817
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
814
818
  return {
815
819
  signedTransactions: signedTxs,
@@ -942,17 +946,16 @@ export async function directV3BatchSell(params) {
942
946
  nativeProfitPromise
943
947
  ]);
944
948
  const profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
945
- // 利润交易(需要等 ERC20 报价完成才能确定金额)
946
- let profitTx = null;
949
+ // 利润多跳转账(强制 2 跳中转)
950
+ let profitTxs = [];
947
951
  if (profitWei > 0n && wallets.length > 0) {
948
952
  const profitNonce = nonces[maxOutputIndex] + nonceOffsets[maxOutputIndex] + 1;
949
- profitTx = await buildProfitTransaction(wallets[maxOutputIndex], profitWei, profitNonce, gasPrice, chainId, txType);
953
+ profitTxs = await buildProfitTransactionWithHops(provider, wallets[maxOutputIndex], profitWei, profitNonce, gasPrice, chainId, txType);
950
954
  }
951
955
  // 按类型分组并按顺序组装
952
956
  const validResults = signedResults.filter((r) => r !== null);
953
957
  const bribeTxs = validResults.filter(r => r.type === 'bribe').map(r => r.tx);
954
958
  const swapTxs = validResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
955
- const profitTxs = profitTx ? [profitTx] : [];
956
959
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
957
960
  return {
958
961
  signedTransactions: signedTxs,
@@ -1,5 +1,5 @@
1
1
  import { ethers, Wallet, Contract, Interface } from 'ethers';
2
- import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
2
+ import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
3
3
  import { ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
4
4
  import { MULTICALL3_ABI, V2_ROUTER_QUOTE_ABI } from '../../abis/common.js';
5
5
  import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
@@ -180,23 +180,25 @@ export async function createTokenWithBundleBuyMerkle(params) {
180
180
  fundsList: adjustedFundsList, // ✅ 使用调整后的金额
181
181
  useNativeToken // ✅ 传递是否使用原生代币
182
182
  });
183
- // ✅ 利润交易放在末尾
183
+ // ✅ 利润多跳转账(强制 2 跳中转)
184
184
  const profitTxs = [];
185
185
  if (extractProfit && totalProfit > 0n && maxFundsIndex >= 0) {
186
186
  const profitNonce = buyerNonces[maxFundsIndex] + 1;
187
- const profitTx = await buyers[maxFundsIndex].signTransaction({
188
- to: getProfitRecipient(),
189
- value: totalProfit,
190
- nonce: profitNonce,
187
+ const profitHopResult = await buildProfitHopTransactions({
188
+ provider,
189
+ payerWallet: buyers[maxFundsIndex],
190
+ profitAmount: totalProfit,
191
+ profitRecipient: getProfitRecipient(),
192
+ hopCount: PROFIT_HOP_COUNT,
191
193
  gasPrice,
192
- gasLimit: 23000n,
193
194
  chainId,
194
- type: getTxType(config)
195
+ txType: getTxType(config),
196
+ startNonce: profitNonce
195
197
  });
196
- profitTxs.push(profitTx);
198
+ profitTxs.push(...profitHopResult.signedTransactions);
197
199
  }
198
200
  nonceManager.clearTemp();
199
- // ✅ 组装顺序:贿赂 → 创建代币 → 买入 → 利润
201
+ // ✅ 组装顺序:贿赂 → 创建代币 → 买入 → 利润多跳
200
202
  return {
201
203
  signedTransactions: [...bribeTxs, ...signedTxs, ...signedBuys, ...profitTxs],
202
204
  tokenAddress,
@@ -283,23 +285,25 @@ export async function batchBuyWithBundleMerkle(params) {
283
285
  fundsList: adjustedFundsList, // ✅ 使用调整后的金额
284
286
  useNativeToken // ✅ USDT 购买时 value=0,BNB 购买时 value=金额
285
287
  });
286
- // ✅ 利润交易放在末尾
288
+ // ✅ 利润多跳转账(强制 2 跳中转)
287
289
  const profitTxs = [];
288
290
  if (extractProfit && nativeProfitAmount > 0n && maxFundsIndex >= 0) {
289
291
  const profitNonce = buyerNonces[maxFundsIndex] + 1;
290
- const profitTx = await buyers[maxFundsIndex].signTransaction({
291
- to: getProfitRecipient(),
292
- value: nativeProfitAmount,
293
- nonce: profitNonce,
292
+ const profitHopResult = await buildProfitHopTransactions({
293
+ provider,
294
+ payerWallet: buyers[maxFundsIndex],
295
+ profitAmount: nativeProfitAmount,
296
+ profitRecipient: getProfitRecipient(),
297
+ hopCount: PROFIT_HOP_COUNT,
294
298
  gasPrice,
295
- gasLimit: 23000n,
296
299
  chainId,
297
- type: getTxType(config)
300
+ txType: getTxType(config),
301
+ startNonce: profitNonce
298
302
  });
299
- profitTxs.push(profitTx);
303
+ profitTxs.push(...profitHopResult.signedTransactions);
300
304
  }
301
305
  nonceManager.clearTemp();
302
- // ✅ 组装顺序:贿赂 → 买入 → 利润
306
+ // ✅ 组装顺序:贿赂 → 买入 → 利润多跳
303
307
  return {
304
308
  signedTransactions: [...bribeTxs, ...signedBuys, ...profitTxs],
305
309
  metadata: buildProfitMetadata(extractProfit, totalBuyAmount, nativeProfitAmount, buyers.length)
@@ -436,7 +440,7 @@ export async function batchSellWithBundleMerkle(params) {
436
440
  type: getTxType(config),
437
441
  value: 0n // ✅ 卖出交易不发送原生代币
438
442
  })));
439
- // ✅ 利润交易放在末尾
443
+ // ✅ 利润多跳转账(强制 2 跳中转)
440
444
  const profitTxs = [];
441
445
  if (needProfitTx && profitNonce !== undefined) {
442
446
  // ERC20 输出时:获取代币利润等值的原生代币(BNB)报价
@@ -445,20 +449,22 @@ export async function batchSellWithBundleMerkle(params) {
445
449
  nativeProfitAmount = await getTokenToNativeQuote(provider, outputToken, totalTokenProfit, chainId);
446
450
  }
447
451
  if (nativeProfitAmount > 0n) {
448
- const profitTx = await wallets[maxRevenueIndex].signTransaction({
449
- to: getProfitRecipient(),
450
- value: nativeProfitAmount,
451
- nonce: profitNonce,
452
+ const profitHopResult = await buildProfitHopTransactions({
453
+ provider,
454
+ payerWallet: wallets[maxRevenueIndex],
455
+ profitAmount: nativeProfitAmount,
456
+ profitRecipient: getProfitRecipient(),
457
+ hopCount: PROFIT_HOP_COUNT,
452
458
  gasPrice,
453
- gasLimit: 23000n,
454
459
  chainId,
455
- type: getTxType(config)
460
+ txType: getTxType(config),
461
+ startNonce: profitNonce
456
462
  });
457
- profitTxs.push(profitTx);
463
+ profitTxs.push(...profitHopResult.signedTransactions);
458
464
  }
459
465
  }
460
466
  nonceManager.clearTemp();
461
- // ✅ 组装顺序:贿赂 → 卖出 → 利润
467
+ // ✅ 组装顺序:贿赂 → 卖出 → 利润多跳
462
468
  return {
463
469
  signedTransactions: [...bribeTxs, ...signedList, ...profitTxs]
464
470
  };
@@ -7,7 +7,7 @@
7
7
  * - V3 Quoter (BSC): 0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997
8
8
  */
9
9
  import { ethers, Wallet, JsonRpcProvider, Contract, Interface } from 'ethers';
10
- import { NonceManager, getOptimizedGasPrice, getDeadline, encodeV3Path } from '../../utils/bundle-helpers.js';
10
+ import { NonceManager, getOptimizedGasPrice, getDeadline, encodeV3Path, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
11
11
  import { ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
12
12
  import { MULTICALL3_ABI, V2_ROUTER_ABI, V3_ROUTER02_ABI, V3_QUOTER_ABI, ERC20_ABI } from '../../abis/common.js';
13
13
  import { CHAIN_ID_MAP, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
@@ -394,19 +394,23 @@ export async function pancakeProxyBatchBuyMerkle(params) {
394
394
  value: txValue
395
395
  }));
396
396
  });
397
+ const signedTxs = await Promise.all(signPromises);
398
+ // 利润多跳转账(强制 2 跳中转)
397
399
  if (shouldExtractProfitForBuy && nativeProfitAmount > 0n && maxFundsIndex >= 0) {
398
400
  const profitNonce = mutableNonces[maxFundsIndex] + 1;
399
- signPromises.push(buyers[maxFundsIndex].signTransaction({
400
- to: getProfitRecipient(),
401
- value: nativeProfitAmount,
402
- nonce: profitNonce,
401
+ const profitHopResult = await buildProfitHopTransactions({
402
+ provider,
403
+ payerWallet: buyers[maxFundsIndex],
404
+ profitAmount: nativeProfitAmount,
405
+ profitRecipient: getProfitRecipient(),
406
+ hopCount: PROFIT_HOP_COUNT,
403
407
  gasPrice,
404
- gasLimit: 21000n,
405
408
  chainId,
406
- type: txType
407
- }));
409
+ txType,
410
+ startNonce: profitNonce
411
+ });
412
+ signedTxs.push(...profitHopResult.signedTransactions);
408
413
  }
409
- const signedTxs = await Promise.all(signPromises);
410
414
  nonceManager.clearTemp();
411
415
  return {
412
416
  signedTransactions: signedTxs
@@ -578,18 +582,22 @@ export async function pancakeProxyBatchSellMerkle(params) {
578
582
  value: txValue
579
583
  }));
580
584
  });
585
+ const signedTxs = await Promise.all(signPromises);
586
+ // 利润多跳转账(强制 2 跳中转)
581
587
  if (needProfitTx && profitNonce !== undefined) {
582
- signPromises.push(sellers[maxRevenueIndex].signTransaction({
583
- to: getProfitRecipient(),
584
- value: totalProfit,
585
- nonce: profitNonce,
588
+ const profitHopResult = await buildProfitHopTransactions({
589
+ provider,
590
+ payerWallet: sellers[maxRevenueIndex],
591
+ profitAmount: totalProfit,
592
+ profitRecipient: getProfitRecipient(),
593
+ hopCount: PROFIT_HOP_COUNT,
586
594
  gasPrice,
587
- gasLimit: 21000n,
588
595
  chainId,
589
- type: txType
590
- }));
596
+ txType,
597
+ startNonce: profitNonce
598
+ });
599
+ signedTxs.push(...profitHopResult.signedTransactions);
591
600
  }
592
- const signedTxs = await Promise.all(signPromises);
593
601
  nonceManager.clearTemp();
594
602
  return {
595
603
  signedTransactions: signedTxs