four-flap-meme-sdk 1.4.38 → 1.4.40

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,8 +1,8 @@
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
- import { getErc20DecimalsMerkle as _getErc20DecimalsMerkle, generateHopWallets as _generateHopWallets, normalizeAmounts as _normalizeAmounts, batchGetBalances as _batchGetBalances, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress, estimateErc20TransferGas as _estimateErc20TransferGas } from './internal.js';
5
+ import { getErc20DecimalsMerkle as _getErc20DecimalsMerkle, generateHopWallets as _generateHopWallets, normalizeAmounts as _normalizeAmounts, batchGetBalances as _batchGetBalances, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress } from './internal.js';
6
6
  // ==================== 本地利润计算(万分之三)====================
7
7
  /**
8
8
  * 计算利润金额(万分之三)
@@ -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 {
@@ -357,25 +363,9 @@ export async function disperseWithBundleMerkle(params) {
357
363
  const iface = isNative ? null : new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
358
364
  // ✅ Gas limit 设置
359
365
  // - 原生代币转账:21000(固定)
360
- // - ERC20 转账:通过模拟交易获取最小 gas limit(减少中转钱包 BNB 残留)
366
+ // - ERC20 转账:65000(固定,因为 gas 波动较大,不再使用模拟预估)
361
367
  const nativeTransferGasLimit = 21000n;
362
- // ERC20 多跳:模拟交易获取精确的 gas limit
363
- // ⚠️ 注意:多跳时中转钱包是新生成的地址,第一次发送 ERC20 的 gas 消耗可能高于主钱包
364
- // 因此需要添加 10% 缓冲以确保交易成功
365
- let erc20TransferGasLimit = finalGasLimit;
366
- if (!isNative && config.estimateGas !== false) {
367
- try {
368
- // 使用第一个接收者模拟一笔转账,获取精确的 gas limit
369
- const sampleAmount = ethers.parseUnits(normalizedAmounts[0], decimals);
370
- const estimatedGas = await _estimateErc20TransferGas(provider, tokenAddress, mainWallet.address, recipients[0], sampleAmount, 10 // ✅ 添加 10% 缓冲,因为中转钱包首次发送 ERC20 gas 消耗可能更高
371
- );
372
- erc20TransferGasLimit = estimatedGas;
373
- console.log(`[disperseWithBundleMerkle] 使用模拟估算的 ERC20 gas limit: ${erc20TransferGasLimit} (+10% buffer)`);
374
- }
375
- catch (error) {
376
- console.warn(`[disperseWithBundleMerkle] 模拟估算失败,使用默认值:`, error);
377
- }
378
- }
368
+ const erc20TransferGasLimit = 65000n;
379
369
  // ✅ 原生代币多跳的 gas 费(每跳只需要 21000)
380
370
  const nativeHopGasFee = nativeTransferGasLimit * gasPrice;
381
371
  // ✅ ERC20 多跳时,中转钱包需要执行 2 笔交易(转 gas + 转 ERC20)
@@ -595,25 +585,25 @@ export async function disperseWithBundleMerkle(params) {
595
585
  const nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalTokenProfit, chainIdNum, tokenPoolType, quoteToken, config.rpcUrl);
596
586
  totalProfit = nativeProfitAmount; // 更新为原生代币利润
597
587
  }
598
- // 利润转账(转等值原生代币)
588
+ // ✅ 并行签名所有交易
589
+ const signedTxsResult = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
590
+ signedTxs.push(...signedTxsResult);
591
+ // ✅ 利润多跳转账(强制 2 跳中转)
599
592
  if (extractProfit && totalProfit > 0n) {
600
593
  const profitNonce = allMainNonces[mainNonceIdx++];
601
- txsToSign.push({
602
- wallet: mainWallet,
603
- tx: {
604
- to: getProfitRecipient(),
605
- value: totalProfit, // ✅ 转等值原生代币
606
- nonce: profitNonce,
607
- gasPrice,
608
- gasLimit: 21000n,
609
- chainId: chainIdNum,
610
- type: txType
611
- }
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
612
604
  });
605
+ signedTxs.push(...profitHopResult.signedTransactions);
613
606
  }
614
- // ✅ 并行签名所有交易
615
- const signedTxsResult = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
616
- signedTxs.push(...signedTxsResult);
617
607
  }
618
608
  // ✅ 简化返回:只返回签名交易、多跳钱包和元数据
619
609
  return {
@@ -827,19 +817,21 @@ export async function sweepWithBundleMerkle(params) {
827
817
  });
828
818
  const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
829
819
  signedTxs.push(...allTxs);
830
- // ✅ 第三步:在所有归集交易之后,生成利润交易
820
+ // ✅ 第三步:利润多跳转账(强制 2 跳中转)
831
821
  if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
832
822
  const payerWallet = wallets[maxSweepIndex];
833
- const profitTx = await payerWallet.signTransaction({
834
- to: getProfitRecipient(),
835
- value: totalProfit,
836
- nonce: payerProfitNonce,
823
+ const profitHopResult = await buildProfitHopTransactions({
824
+ provider,
825
+ payerWallet,
826
+ profitAmount: totalProfit,
827
+ profitRecipient: getProfitRecipient(),
828
+ hopCount: PROFIT_HOP_COUNT,
837
829
  gasPrice,
838
- gasLimit: nativeGasLimit,
839
830
  chainId: chainIdNum,
840
- type: txType
831
+ txType,
832
+ startNonce: payerProfitNonce
841
833
  });
842
- signedTxs.push(profitTx);
834
+ signedTxs.push(...profitHopResult.signedTransactions);
843
835
  }
844
836
  }
845
837
  else {
@@ -963,20 +955,22 @@ export async function sweepWithBundleMerkle(params) {
963
955
  });
964
956
  const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
965
957
  signedTxs.push(...allTxs);
966
- // ✅ 第三步:生成利润交易(转等值原生代币)
958
+ // ✅ 第三步:利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
967
959
  if (extractProfit && nativeProfitAmount > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
968
960
  const payerWallet = wallets[maxSweepIndex];
969
961
  totalProfit = nativeProfitAmount; // 更新为原生代币利润
970
- const profitTx = await payerWallet.signTransaction({
971
- to: getProfitRecipient(),
972
- value: nativeProfitAmount, // ✅ 转等值原生代币
973
- nonce: payerProfitNonce,
962
+ const profitHopResult = await buildProfitHopTransactions({
963
+ provider,
964
+ payerWallet,
965
+ profitAmount: nativeProfitAmount,
966
+ profitRecipient: getProfitRecipient(),
967
+ hopCount: PROFIT_HOP_COUNT,
974
968
  gasPrice,
975
- gasLimit: 21000n,
976
969
  chainId: chainIdNum,
977
- type: txType
970
+ txType,
971
+ startNonce: payerProfitNonce
978
972
  });
979
- signedTxs.push(profitTx);
973
+ signedTxs.push(...profitHopResult.signedTransactions);
980
974
  }
981
975
  }
982
976
  }
@@ -1004,27 +998,10 @@ export async function sweepWithBundleMerkle(params) {
1004
998
  ]);
1005
999
  const iface = isNative ? null : new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
1006
1000
  // ✅ Gas limit 设置(与分散函数保持一致)
1001
+ // - 原生代币转账:21000(固定)
1002
+ // - ERC20 转账:65000(固定,因为 gas 波动较大,不再使用模拟预估)
1007
1003
  const nativeTransferGasLimit = 21000n;
1008
- // ERC20 多跳:模拟交易获取精确的 gas limit
1009
- // ⚠️ 注意:多跳时中转钱包是新生成的地址,第一次发送 ERC20 的 gas 消耗可能高于已有余额的钱包
1010
- // 因此需要添加 10% 缓冲以确保交易成功
1011
- let erc20TransferGasLimit = finalGasLimit;
1012
- if (!isNative && config.estimateGas !== false) {
1013
- try {
1014
- // 找到第一个有余额的钱包来模拟转账
1015
- const firstWithBalance = balances.findIndex(b => b > 0n);
1016
- if (firstWithBalance >= 0) {
1017
- const sampleAmount = balances[firstWithBalance] > 0n ? balances[firstWithBalance] / 2n : 1n;
1018
- const estimatedGas = await _estimateErc20TransferGas(provider, tokenAddress, sourceAddresses[firstWithBalance], target, sampleAmount, 10 // ✅ 添加 10% 缓冲,因为中转钱包首次发送 ERC20 gas 消耗可能更高
1019
- );
1020
- erc20TransferGasLimit = estimatedGas;
1021
- console.log(`[sweepWithBundleMerkle] 使用模拟估算的 ERC20 gas limit: ${erc20TransferGasLimit} (+10% buffer)`);
1022
- }
1023
- }
1024
- catch (error) {
1025
- console.warn(`[sweepWithBundleMerkle] 模拟估算失败,使用默认值:`, error);
1026
- }
1027
- }
1004
+ const erc20TransferGasLimit = 65000n;
1028
1005
  // ✅ 原生代币多跳的 gas 费(每跳只需要 21000)
1029
1006
  const nativeHopGasFee = nativeTransferGasLimit * gasPrice;
1030
1007
  // ✅ ERC20 多跳时,中转钱包需要执行 2 笔交易(转 gas + 转 ERC20)
@@ -1351,20 +1328,22 @@ export async function sweepWithBundleMerkle(params) {
1351
1328
  nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalTokenProfit, chainIdNum, tokenPoolType, quoteToken, config.rpcUrl);
1352
1329
  totalProfit = nativeProfitAmount;
1353
1330
  }
1354
- // 由归集金额最大的钱包支付利润
1331
+ // ✅ 利润多跳转账(强制 2 跳中转)
1355
1332
  if (nativeProfitAmount > 0n && maxSweepIndex >= 0) {
1356
1333
  const payerWallet = sourceWallets[maxSweepIndex];
1357
1334
  const profitNonce = await nonceManager.getNextNonce(payerWallet);
1358
- const profitTx = await payerWallet.signTransaction({
1359
- to: getProfitRecipient(),
1360
- value: nativeProfitAmount,
1361
- nonce: profitNonce,
1335
+ const profitHopResult = await buildProfitHopTransactions({
1336
+ provider,
1337
+ payerWallet,
1338
+ profitAmount: nativeProfitAmount,
1339
+ profitRecipient: getProfitRecipient(),
1340
+ hopCount: PROFIT_HOP_COUNT,
1362
1341
  gasPrice,
1363
- gasLimit: 21000n,
1364
1342
  chainId: chainIdNum,
1365
- type: txType
1343
+ txType,
1344
+ startNonce: profitNonce
1366
1345
  });
1367
- signedTxs.push(profitTx);
1346
+ signedTxs.push(...profitHopResult.signedTransactions);
1368
1347
  }
1369
1348
  }
1370
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
  };