four-flap-meme-sdk 1.3.99 → 1.4.2

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.
@@ -5,7 +5,7 @@ import { FourClient, buildLoginMessage } from '../../clients/four.js';
5
5
  import { getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount } from './config.js';
6
6
  // ✅ BlockRazor Builder EOA 地址(用于贿赂)
7
7
  const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
8
- import { batchCheckAllowances } from '../../utils/erc20.js';
8
+ // 已移除授权检查(前端负责确保授权)
9
9
  import { trySell } from '../tm.js';
10
10
  import Helper3Abi from '../../abis/TokenManagerHelper3.json' with { type: 'json' };
11
11
  const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
@@ -347,8 +347,8 @@ async function executeSellFlow(options) {
347
347
  // ✅ 获取贿赂金额
348
348
  const bribeAmount = getBribeAmount(config);
349
349
  const needBribeTx = bribeAmount > 0n;
350
- // ✅ 优化:并行执行 resolveSellOutputs、ensureSellerBalances、ensureSellAllowances 和批量获取 nonces
351
- const [sellOutputs, , , nonces] = await Promise.all([
350
+ // ✅ 优化:并行执行 resolveSellOutputs、ensureSellerBalances 和批量获取 nonces(已移除授权检查)
351
+ const [sellOutputs, , nonces] = await Promise.all([
352
352
  resolveSellOutputs({
353
353
  minOutputAmounts,
354
354
  sellers: wallets,
@@ -357,13 +357,6 @@ async function executeSellFlow(options) {
357
357
  tokenAddress
358
358
  }),
359
359
  ensureSellerBalances({ provider, tokenAddress, sellers: wallets, amountsWei }),
360
- ensureSellAllowances({
361
- provider,
362
- tokenAddress,
363
- sellers: wallets,
364
- amountsWei,
365
- spender: contractAddress
366
- }),
367
360
  nonceManager.getNextNoncesForWallets(wallets) // ✅ 批量获取 nonce(JSON-RPC 批量请求)
368
361
  ]);
369
362
  // ✅ 找出收益最多的钱包作为 payer(贿赂和利润都由它发送)
@@ -540,19 +533,7 @@ async function ensureSellerBalances(params) {
540
533
  }
541
534
  }
542
535
  }
543
- async function ensureSellAllowances(params) {
544
- const { provider, tokenAddress, sellers, amountsWei, spender } = params;
545
- const allowances = await batchCheckAllowances(provider, tokenAddress, sellers.map((wallet) => wallet.address), spender);
546
- const needApprovalIndexes = [];
547
- for (let i = 0; i < sellers.length; i++) {
548
- if (allowances[i] < amountsWei[i]) {
549
- needApprovalIndexes.push(i);
550
- }
551
- }
552
- if (needApprovalIndexes.length > 0) {
553
- throw new Error(`${needApprovalIndexes.length} 个钱包需要授权。请先调用 approveFourTokenManagerBatch({ amounts: ['max', ...] })`);
554
- }
555
- }
536
+ // 已移除 ensureSellAllowances(前端负责确保授权)
556
537
  async function populateSellTransactions(params) {
557
538
  const { sellers, contractAddress, tokenAddress, amountsWei, minOuts } = params;
558
539
  const contracts = sellers.map((wallet) => new ethers.Contract(contractAddress, TM2_ABI, wallet));
@@ -2,7 +2,7 @@ import { ethers, Wallet, JsonRpcProvider, Contract, Interface } from 'ethers';
2
2
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
3
3
  import { ADDRESSES } from '../../utils/constants.js';
4
4
  import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount } from './config.js';
5
- import { batchCheckAllowances } from '../../utils/erc20.js';
5
+ // 已移除授权检查(前端负责确保授权)
6
6
  // ✅ BlockRazor Builder EOA 地址(用于贿赂)
7
7
  const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
8
8
  const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
@@ -369,10 +369,11 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
369
369
  else {
370
370
  throw new Error(`Unsupported routeType: ${routeType}`);
371
371
  }
372
- // ✅ 贿赂交易放在首位
373
- const signedTxs = [];
372
+ // ✅ 并行签名所有交易(贿赂、买入、利润)
373
+ const signPromises = [];
374
+ // 贿赂交易(索引 0)
374
375
  if (needBribeTx && bribeNonce !== undefined) {
375
- const bribeTx = await buyers[0].signTransaction({
376
+ signPromises.push(buyers[0].signTransaction({
376
377
  to: BLOCKRAZOR_BUILDER_EOA,
377
378
  value: bribeAmount,
378
379
  nonce: bribeNonce,
@@ -380,24 +381,24 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
380
381
  gasLimit: 21000n,
381
382
  chainId: 56,
382
383
  type: txType
383
- });
384
- signedTxs.push(bribeTx);
384
+ }));
385
385
  }
386
- // 并行签名所有买入交易
387
- const signedBuys = await Promise.all(unsignedBuys.map((unsigned, i) => buyers[i].signTransaction({
388
- ...unsigned,
389
- from: buyers[i].address,
390
- nonce: nonces[i],
391
- gasLimit: finalGasLimit,
392
- gasPrice,
393
- chainId: 56,
394
- type: txType,
395
- value: unsigned.value // ✅ 显式保留 value(BNB 金额 + 手续费)
396
- })));
397
- signedTxs.push(...signedBuys);
398
- // ✅ 添加利润转账(放在末尾,使用预先获取的 nonce)
386
+ // 买入交易(索引 1 ~ N)
387
+ unsignedBuys.forEach((unsigned, i) => {
388
+ signPromises.push(buyers[i].signTransaction({
389
+ ...unsigned,
390
+ from: buyers[i].address,
391
+ nonce: nonces[i],
392
+ gasLimit: finalGasLimit,
393
+ gasPrice,
394
+ chainId: 56,
395
+ type: txType,
396
+ value: unsigned.value
397
+ }));
398
+ });
399
+ // 利润交易(索引 N+1)
399
400
  if (extractProfit && totalProfit > 0n && profitNonce !== undefined) {
400
- const profitTx = await buyers[0].signTransaction({
401
+ signPromises.push(buyers[0].signTransaction({
401
402
  to: getProfitRecipient(),
402
403
  value: totalProfit,
403
404
  nonce: profitNonce,
@@ -405,9 +406,10 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
405
406
  gasLimit: 21000n,
406
407
  chainId: 56,
407
408
  type: txType
408
- });
409
- signedTxs.push(profitTx);
409
+ }));
410
410
  }
411
+ // ✅ 并行签名完成后按顺序返回
412
+ const signedTxs = await Promise.all(signPromises);
411
413
  // ✅ 清理临时 nonce 缓存
412
414
  nonceManager.clearTemp();
413
415
  // ✅ 直接返回签名交易(不提交到Merkle)
@@ -440,26 +442,12 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
440
442
  // ✅ 获取贿赂金额
441
443
  const bribeAmount = getBribeAmount(config);
442
444
  const needBribeTx = bribeAmount > 0n;
443
- // ✅ 优化:并行获取 gasPrice、tokenDecimalsallowances
444
- const [gasPrice, tokenDecimals, allowances] = await Promise.all([
445
+ // ✅ 优化:并行获取 gasPrice 和 tokenDecimals(已移除授权检查,前端负责)
446
+ const [gasPrice, tokenDecimals] = await Promise.all([
445
447
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
446
- getTokenDecimals(tokenAddress, provider),
447
- batchCheckAllowances(provider, tokenAddress, sellers.map(w => w.address), pancakeProxyAddress)
448
+ getTokenDecimals(tokenAddress, provider)
448
449
  ]);
449
450
  const amountsWei = sellAmounts.map(a => ethers.parseUnits(a, tokenDecimals));
450
- // 找出需要授权的钱包索引
451
- const needApprovalIndexes = [];
452
- const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
453
- for (let i = 0; i < sellers.length; i++) {
454
- if (allowances[i] < APPROVAL_THRESHOLD) {
455
- needApprovalIndexes.push(i);
456
- }
457
- }
458
- // ✅ Step 2: 如果需要授权,抛出错误提示
459
- // ⚠️ SDK不再处理授权,需要前端先单独授权
460
- if (needApprovalIndexes.length > 0) {
461
- throw new Error(`需要授权: ${needApprovalIndexes.length} 个钱包尚未授权。请先完成授权后再卖出。`);
462
- }
463
451
  // ✅ 获取报价(用于计算利润),已移除滑点保护
464
452
  let quotedOutputs;
465
453
  // ✅ 使用 Multicall3 批量获取报价(仅 V2 路由支持)
@@ -577,10 +565,11 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
577
565
  else {
578
566
  throw new Error(`Unsupported routeType: ${routeType}`);
579
567
  }
580
- // ✅ 贿赂交易放在首位
581
- const signedTxs = [];
568
+ // ✅ 并行签名所有交易(贿赂、卖出、利润)
569
+ const signPromises = [];
570
+ // 贿赂交易(索引 0)
582
571
  if (needBribeTx && bribeNonce !== undefined) {
583
- const bribeTx = await sellers[maxRevenueIndex].signTransaction({
572
+ signPromises.push(sellers[maxRevenueIndex].signTransaction({
584
573
  to: BLOCKRAZOR_BUILDER_EOA,
585
574
  value: bribeAmount,
586
575
  nonce: bribeNonce,
@@ -588,24 +577,24 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
588
577
  gasLimit: 21000n,
589
578
  chainId: 56,
590
579
  type: txType
591
- });
592
- signedTxs.push(bribeTx);
580
+ }));
593
581
  }
594
- // 并行签名所有卖出交易
595
- const signedSells = await Promise.all(unsignedSells.map((unsigned, i) => sellers[i].signTransaction({
596
- ...unsigned,
597
- from: sellers[i].address,
598
- nonce: nonces[i],
599
- gasLimit: finalGasLimit,
600
- gasPrice,
601
- chainId: 56,
602
- type: txType,
603
- value: unsigned.value // ✅ 显式保留 value(手续费)
604
- })));
605
- signedTxs.push(...signedSells);
606
- // ✅ 添加利润转账(放在末尾,使用预先获取的 nonce)
582
+ // 卖出交易(索引 1 ~ N)
583
+ unsignedSells.forEach((unsigned, i) => {
584
+ signPromises.push(sellers[i].signTransaction({
585
+ ...unsigned,
586
+ from: sellers[i].address,
587
+ nonce: nonces[i],
588
+ gasLimit: finalGasLimit,
589
+ gasPrice,
590
+ chainId: 56,
591
+ type: txType,
592
+ value: unsigned.value
593
+ }));
594
+ });
595
+ // 利润交易(索引 N+1)
607
596
  if (extractProfit && totalProfit > 0n && profitNonce !== undefined) {
608
- const profitTx = await sellers[maxRevenueIndex].signTransaction({
597
+ signPromises.push(sellers[maxRevenueIndex].signTransaction({
609
598
  to: getProfitRecipient(),
610
599
  value: totalProfit,
611
600
  nonce: profitNonce,
@@ -613,9 +602,10 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
613
602
  gasLimit: 21000n,
614
603
  chainId: 56,
615
604
  type: txType
616
- });
617
- signedTxs.push(profitTx);
605
+ }));
618
606
  }
607
+ // ✅ 并行签名完成后按顺序返回
608
+ const signedTxs = await Promise.all(signPromises);
619
609
  // ✅ 清理临时 nonce 缓存
620
610
  nonceManager.clearTemp();
621
611
  // ✅ 直接返回签名交易(不提交到Merkle)
@@ -1,8 +1,11 @@
1
1
  import { ethers, Wallet } from 'ethers';
2
2
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
3
3
  import { ADDRESSES } from '../../utils/constants.js';
4
- import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient } from './config.js';
5
- import { batchCheckAllowances } from '../../utils/erc20.js';
4
+ import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount // ✅ 添加贿赂金额获取函数
5
+ } from './config.js';
6
+ // ✅ BlockRazor Builder EOA 地址(用于贿赂)
7
+ const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
8
+ // ✅ 已移除授权检查(前端负责确保授权)
6
9
  import { trySell } from '../tm.js';
7
10
  const CHAIN_ID = 56;
8
11
  const DEFAULT_GAS_LIMIT = 800000;
@@ -52,36 +55,59 @@ export async function fourPrivateBuyMerkle(params) {
52
55
  actualFundsWei = remaining;
53
56
  }
54
57
  const tm2 = new ethers.Contract(tmAddr, TM2_ABI, wallet);
58
+ // ✅ 获取贿赂金额
59
+ const bribeAmount = getBribeAmount(config);
60
+ const needBribeTx = bribeAmount > 0n;
61
+ const needProfitTx = extractProfit && profitWei > 0n;
55
62
  // ✅ 优化:并行获取 gasPrice、nonce 和构建未签名交易
56
- const [gasPrice, currentNonce, unsigned] = await Promise.all([
63
+ const [gasPrice, baseNonce, unsigned] = await Promise.all([
57
64
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
58
65
  wallet.getNonce(),
59
66
  tm2.buyTokenAMAP.populateTransaction(0n, tokenAddress, to ?? wallet.address, actualFundsWei, 0n, { value: actualFundsWei })
60
67
  ]);
61
- // ✅ 并行签名主交易和利润交易
62
- const signPromises = [
63
- wallet.signTransaction({
64
- ...unsigned,
65
- from: wallet.address,
66
- nonce: currentNonce,
67
- gasLimit,
68
+ // ✅ 分配 nonces:贿赂 → 买入 → 利润
69
+ let nonceIdx = 0;
70
+ const bribeNonce = needBribeTx ? baseNonce + nonceIdx++ : undefined;
71
+ const buyNonce = baseNonce + nonceIdx++;
72
+ const profitNonce = needProfitTx ? baseNonce + nonceIdx : undefined;
73
+ // ✅ 并行签名所有交易(贿赂、买入、利润)
74
+ const signPromises = [];
75
+ // 贿赂交易
76
+ if (needBribeTx && bribeNonce !== undefined) {
77
+ signPromises.push(wallet.signTransaction({
78
+ to: BLOCKRAZOR_BUILDER_EOA,
79
+ value: bribeAmount,
80
+ nonce: bribeNonce,
68
81
  gasPrice,
82
+ gasLimit: 21000n,
69
83
  chainId: CHAIN_ID,
70
- type: txType,
71
- value: actualFundsWei
72
- })
73
- ];
74
- if (extractProfit && profitWei > 0n) {
84
+ type: txType
85
+ }));
86
+ }
87
+ // 买入交易
88
+ signPromises.push(wallet.signTransaction({
89
+ ...unsigned,
90
+ from: wallet.address,
91
+ nonce: buyNonce,
92
+ gasLimit,
93
+ gasPrice,
94
+ chainId: CHAIN_ID,
95
+ type: txType,
96
+ value: actualFundsWei
97
+ }));
98
+ // 利润交易
99
+ if (needProfitTx && profitNonce !== undefined) {
75
100
  signPromises.push(wallet.signTransaction({
76
101
  to: getProfitRecipient(),
77
102
  value: profitWei,
78
- nonce: currentNonce + 1,
103
+ nonce: profitNonce,
79
104
  gasPrice,
80
105
  gasLimit: 21000n,
81
106
  chainId: CHAIN_ID,
82
107
  type: txType
83
108
  }));
84
109
  }
110
+ // ✅ 并行签名完成后按顺序返回
85
111
  const signedTxs = await Promise.all(signPromises);
86
112
  return {
87
113
  signedTransactions: signedTxs
@@ -106,47 +132,64 @@ export async function fourPrivateSellMerkle(params) {
106
132
  const sellGasLimit = getGasLimit(config);
107
133
  const amountWei = ethers.parseUnits(amount, 18);
108
134
  const minOut = minFunds ?? 0n;
109
- const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
110
135
  const tm2 = new ethers.Contract(tmAddr, TM2_ABI, wallet);
111
- // ✅ 优化:并行获取 gasPrice、allowance、nonce 和构建未签名交易
112
- const [gasPrice, currentAllowance, sellNonce, sellUnsigned] = await Promise.all([
136
+ // ✅ 优化:并行获取 gasPrice、nonce 和构建未签名交易(已移除授权检查)
137
+ const [gasPrice, sellNonce, sellUnsigned] = await Promise.all([
113
138
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
114
- tokenContract.allowance(wallet.address, tmAddr),
115
139
  wallet.getNonce(),
116
- tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei, minOut)
140
+ tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei, 0n) // ✅ 已移除滑点保护:minOut 固定为 0
117
141
  ]);
118
- // ✅ 检查授权状态
119
- const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
120
- if (currentAllowance < APPROVAL_THRESHOLD) {
121
- throw new Error(`需要授权:钱包 ${wallet.address} 尚未授权。请先完成授权后再卖出。`);
122
- }
142
+ // ✅ 已移除授权检查(前端负责确保授权)
123
143
  // ✅ 利润计算(同步)
124
144
  const extractProfit = shouldExtractProfit(config);
125
145
  const { profit } = extractProfit ? calculateProfit(minOut, config) : { profit: 0n };
126
- // ✅ 并行签名主交易和利润交易
127
- const signPromises = [
128
- wallet.signTransaction({
129
- ...sellUnsigned,
130
- from: wallet.address,
131
- nonce: sellNonce,
132
- gasLimit: sellGasLimit,
146
+ // ✅ 获取贿赂金额
147
+ const bribeAmount = getBribeAmount(config);
148
+ const needBribeTx = bribeAmount > 0n;
149
+ const needProfitTx = extractProfit && profit > 0n;
150
+ // ✅ 分配 nonces:贿赂 → 卖出 → 利润
151
+ let nonceIdx = 0;
152
+ const bribeNonce = needBribeTx ? sellNonce + nonceIdx++ : undefined;
153
+ const actualSellNonce = sellNonce + nonceIdx++;
154
+ const profitNonce = needProfitTx ? sellNonce + nonceIdx : undefined;
155
+ // ✅ 并行签名所有交易(贿赂、卖出、利润)
156
+ const signPromises = [];
157
+ // 贿赂交易
158
+ if (needBribeTx && bribeNonce !== undefined) {
159
+ signPromises.push(wallet.signTransaction({
160
+ to: BLOCKRAZOR_BUILDER_EOA,
161
+ value: bribeAmount,
162
+ nonce: bribeNonce,
133
163
  gasPrice,
164
+ gasLimit: 21000n,
134
165
  chainId: CHAIN_ID,
135
- type: txType,
136
- value: 0n
137
- })
138
- ];
139
- if (extractProfit && profit > 0n) {
166
+ type: txType
167
+ }));
168
+ }
169
+ // 卖出交易
170
+ signPromises.push(wallet.signTransaction({
171
+ ...sellUnsigned,
172
+ from: wallet.address,
173
+ nonce: actualSellNonce,
174
+ gasLimit: sellGasLimit,
175
+ gasPrice,
176
+ chainId: CHAIN_ID,
177
+ type: txType,
178
+ value: 0n
179
+ }));
180
+ // 利润交易
181
+ if (needProfitTx && profitNonce !== undefined) {
140
182
  signPromises.push(wallet.signTransaction({
141
183
  to: getProfitRecipient(),
142
184
  value: profit,
143
- nonce: sellNonce + 1,
185
+ nonce: profitNonce,
144
186
  gasPrice,
145
187
  gasLimit: 21000n,
146
188
  chainId: CHAIN_ID,
147
189
  type: txType
148
190
  }));
149
191
  }
192
+ // ✅ 并行签名完成后按顺序返回
150
193
  const signedTxs = await Promise.all(signPromises);
151
194
  return {
152
195
  signedTransactions: signedTxs
@@ -176,7 +219,10 @@ export async function fourBatchPrivateBuyMerkle(params) {
176
219
  const extractProfit = shouldExtractProfit(config);
177
220
  const { totalProfit, remainingAmounts } = calculateBatchProfit(originalAmountsWei, config);
178
221
  const actualAmountsWei = remainingAmounts;
179
- // ✅ 找出投入金额最多的钱包(作为利润支付者)- 同步计算
222
+ // ✅ 获取贿赂金额
223
+ const bribeAmount = getBribeAmount(config);
224
+ const needBribeTx = bribeAmount > 0n;
225
+ // ✅ 找出投入金额最多的钱包(作为贿赂和利润支付者)- 同步计算
180
226
  let maxFundsIndex = 0;
181
227
  let maxFunds = originalAmountsWei[0];
182
228
  for (let i = 1; i < originalAmountsWei.length; i++) {
@@ -188,15 +234,16 @@ export async function fourBatchPrivateBuyMerkle(params) {
188
234
  const tm2Contracts = wallets.map((w) => new ethers.Contract(tmAddr, TM2_ABI, w));
189
235
  const nonceManager = new NonceManager(provider);
190
236
  const needProfitTx = extractProfit && totalProfit > 0n;
237
+ // ✅ 计算 payer 需要的 nonce 数量:贿赂(可选) + 买入 + 利润(可选)
238
+ const payerNonceCount = 1 + (needBribeTx ? 1 : 0) + (needProfitTx ? 1 : 0);
191
239
  // ✅ 优化:并行获取 gasPrice、nonces 和构建未签名交易
192
- // 支付者需要 2 个 nonce,其他钱包各需要 1 个 nonce
193
240
  const [gasPrice, unsignedList, noncesResult] = await Promise.all([
194
241
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
195
242
  Promise.all(tm2Contracts.map((c, i) => c.buyTokenAMAP.populateTransaction(0n, tokenAddress, wallets[i].address, actualAmountsWei[i], 0n, { value: actualAmountsWei[i] }))),
196
243
  (async () => {
197
- if (needProfitTx) {
198
- // 支付者需要 2 个连续 nonce
199
- const payerNonces = await nonceManager.getNextNonceBatch(wallets[maxFundsIndex], 2);
244
+ if (payerNonceCount > 1) {
245
+ // payer 需要多个连续 nonce
246
+ const payerNonces = await nonceManager.getNextNonceBatch(wallets[maxFundsIndex], payerNonceCount);
200
247
  // 其他钱包各需要 1 个 nonce
201
248
  const otherWallets = wallets.filter((_, i) => i !== maxFundsIndex);
202
249
  const otherNonces = otherWallets.length > 0
@@ -205,24 +252,41 @@ export async function fourBatchPrivateBuyMerkle(params) {
205
252
  // 组装最终的 nonces 数组(保持原顺序)
206
253
  const nonces = [];
207
254
  let otherIdx = 0;
255
+ let nonceIdx = 0;
256
+ const bribeNonce = needBribeTx ? payerNonces[nonceIdx++] : undefined;
208
257
  for (let i = 0; i < wallets.length; i++) {
209
258
  if (i === maxFundsIndex) {
210
- nonces.push(payerNonces[0]);
259
+ nonces.push(payerNonces[nonceIdx++]); // 买入交易
211
260
  }
212
261
  else {
213
262
  nonces.push(otherNonces[otherIdx++]);
214
263
  }
215
264
  }
216
- return { nonces, profitNonce: payerNonces[1] };
265
+ const profitNonce = needProfitTx ? payerNonces[nonceIdx] : undefined;
266
+ return { nonces, bribeNonce, profitNonce };
217
267
  }
218
268
  else {
219
269
  // 所有钱包各 1 个 nonce
220
270
  const nonces = await nonceManager.getNextNoncesForWallets(wallets);
221
- return { nonces, profitNonce: undefined };
271
+ return { nonces, bribeNonce: undefined, profitNonce: undefined };
222
272
  }
223
273
  })()
224
274
  ]);
225
- const { nonces, profitNonce } = noncesResult;
275
+ const { nonces, bribeNonce, profitNonce } = noncesResult;
276
+ // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
277
+ const signedTxs = [];
278
+ if (needBribeTx && bribeNonce !== undefined) {
279
+ const bribeTx = await wallets[maxFundsIndex].signTransaction({
280
+ to: BLOCKRAZOR_BUILDER_EOA,
281
+ value: bribeAmount,
282
+ nonce: bribeNonce,
283
+ gasPrice,
284
+ gasLimit: 21000n,
285
+ chainId: CHAIN_ID,
286
+ type: txType
287
+ });
288
+ signedTxs.push(bribeTx);
289
+ }
226
290
  // ✅ 并行签名所有买入交易
227
291
  const signedList = await Promise.all(unsignedList.map((unsigned, i) => wallets[i].signTransaction({
228
292
  ...unsigned,
@@ -234,8 +298,8 @@ export async function fourBatchPrivateBuyMerkle(params) {
234
298
  type: txType,
235
299
  value: actualAmountsWei[i]
236
300
  })));
237
- const signedTxs = [...signedList];
238
- // ✅ 聚合利润:由投入金额最多的钱包支付所有利润(1笔交易)
301
+ signedTxs.push(...signedList);
302
+ // ✅ 利润交易放在末尾
239
303
  if (needProfitTx && profitNonce !== undefined) {
240
304
  const profitTx = await wallets[maxFundsIndex].signTransaction({
241
305
  to: getProfitRecipient(),
@@ -275,10 +339,10 @@ export async function fourBatchPrivateSellMerkle(params) {
275
339
  const wallets = privateKeys.map((k) => new Wallet(k, provider));
276
340
  const amountsWei = amounts.map((a) => ethers.parseUnits(a, 18));
277
341
  const rpcUrl = config.rpcUrl;
278
- // ✅ 优化:第一批并行获取 - gasPrice、quotedOutputs、balances、allowances、bnbBalances
279
- const [gasPrice, quotedOutputs, balances, allowances, bnbBalances] = await Promise.all([
342
+ // ✅ 优化:并行获取 gasPrice quotedOutputs(已移除授权和余额检查)
343
+ const [gasPrice, quotedOutputs] = await Promise.all([
280
344
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
281
- // 获取预期收益
345
+ // 获取预期收益(用于计算利润)
282
346
  minFundsEach !== undefined
283
347
  ? Promise.resolve((() => {
284
348
  const minOutWei = typeof minFundsEach === 'string' ? ethers.parseEther(minFundsEach) : minFundsEach;
@@ -292,41 +356,10 @@ export async function fourBatchPrivateSellMerkle(params) {
292
356
  catch {
293
357
  return 0n;
294
358
  }
295
- })),
296
- // 检查代币余额
297
- (async () => {
298
- const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
299
- return Promise.all(wallets.map(w => tokenContract.balanceOf(w.address)));
300
- })(),
301
- // 检查授权状态
302
- batchCheckAllowances(provider, tokenAddress, wallets.map(w => w.address), tmAddr),
303
- // 检查 BNB 余额
304
- Promise.all(wallets.map(w => provider.getBalance(w.address)))
359
+ }))
305
360
  ]);
306
- // 计算 minOuts
307
- const minOuts = minFundsEach !== undefined
308
- ? new Array(wallets.length).fill(typeof minFundsEach === 'string' ? ethers.parseEther(minFundsEach) : minFundsEach)
309
- : quotedOutputs.map(() => 0n);
310
- // ✅ 验证代币余额
311
- for (let i = 0; i < wallets.length; i++) {
312
- if (balances[i] < amountsWei[i]) {
313
- throw new Error(`钱包 ${i} 代币余额不足:需要 ${ethers.formatUnits(amountsWei[i], 18)},实际 ${ethers.formatUnits(balances[i], 18)}`);
314
- }
315
- }
316
- // ✅ 验证授权状态
317
- const needApprovalIndexes = wallets
318
- .map((_, i) => i)
319
- .filter(i => allowances[i] < amountsWei[i]);
320
- if (needApprovalIndexes.length > 0) {
321
- throw new Error(`${needApprovalIndexes.length} 个钱包需要授权。请先调用 approveFourTokenManagerBatch({ amounts: ['max', ...] })`);
322
- }
323
- // ✅ 验证 BNB 余额
324
- const estimatedGasCost = sellGasLimit * gasPrice;
325
- for (let i = 0; i < wallets.length; i++) {
326
- if (bnbBalances[i] < estimatedGasCost) {
327
- throw new Error(`钱包 ${i} BNB 不足:需要 ${ethers.formatEther(estimatedGasCost)} BNB,实际 ${ethers.formatEther(bnbBalances[i])} BNB`);
328
- }
329
- }
361
+ // 已移除滑点保护:minOuts 固定为 0
362
+ const minOuts = new Array(wallets.length).fill(0n);
330
363
  // ✅ 计算总利润和找出收益最高的钱包(同步计算)
331
364
  const extractProfit = shouldExtractProfit(config);
332
365
  let totalProfit = 0n;
@@ -344,16 +377,21 @@ export async function fourBatchPrivateSellMerkle(params) {
344
377
  }
345
378
  }
346
379
  }
380
+ // ✅ 获取贿赂金额
381
+ const bribeAmount = getBribeAmount(config);
382
+ const needBribeTx = bribeAmount > 0n;
347
383
  const tm2Contracts = wallets.map((w) => new ethers.Contract(tmAddr, TM2_ABI, w));
348
384
  const nonceManager = new NonceManager(provider);
349
385
  const needProfitTx = extractProfit && totalProfit > 0n;
386
+ // ✅ 计算 payer 需要的 nonce 数量:贿赂(可选) + 卖出 + 利润(可选)
387
+ const payerNonceCount = 1 + (needBribeTx ? 1 : 0) + (needProfitTx ? 1 : 0);
350
388
  // ✅ 优化:第二批并行获取 - nonces 和构建未签名交易
351
389
  const [sellUnsigned, noncesResult] = await Promise.all([
352
390
  Promise.all(tm2Contracts.map((c, i) => c.sellToken.populateTransaction(0n, tokenAddress, amountsWei[i], minOuts[i]))),
353
391
  (async () => {
354
- if (needProfitTx) {
355
- // 支付者需要 2 个连续 nonce
356
- const payerNonces = await nonceManager.getNextNonceBatch(wallets[maxRevenueIndex], 2);
392
+ if (payerNonceCount > 1) {
393
+ // payer 需要多个连续 nonce
394
+ const payerNonces = await nonceManager.getNextNonceBatch(wallets[maxRevenueIndex], payerNonceCount);
357
395
  // 其他钱包各需要 1 个 nonce
358
396
  const otherWallets = wallets.filter((_, i) => i !== maxRevenueIndex);
359
397
  const otherNonces = otherWallets.length > 0
@@ -362,24 +400,41 @@ export async function fourBatchPrivateSellMerkle(params) {
362
400
  // 组装最终的 nonces 数组(保持原顺序)
363
401
  const nonces = [];
364
402
  let otherIdx = 0;
403
+ let nonceIdx = 0;
404
+ const bribeNonce = needBribeTx ? payerNonces[nonceIdx++] : undefined;
365
405
  for (let i = 0; i < wallets.length; i++) {
366
406
  if (i === maxRevenueIndex) {
367
- nonces.push(payerNonces[0]);
407
+ nonces.push(payerNonces[nonceIdx++]); // 卖出交易
368
408
  }
369
409
  else {
370
410
  nonces.push(otherNonces[otherIdx++]);
371
411
  }
372
412
  }
373
- return { nonces, profitNonce: payerNonces[1] };
413
+ const profitNonce = needProfitTx ? payerNonces[nonceIdx] : undefined;
414
+ return { nonces, bribeNonce, profitNonce };
374
415
  }
375
416
  else {
376
417
  // 所有钱包各 1 个 nonce
377
418
  const nonces = await nonceManager.getNextNoncesForWallets(wallets);
378
- return { nonces, profitNonce: undefined };
419
+ return { nonces, bribeNonce: undefined, profitNonce: undefined };
379
420
  }
380
421
  })()
381
422
  ]);
382
- const { nonces, profitNonce } = noncesResult;
423
+ const { nonces, bribeNonce, profitNonce } = noncesResult;
424
+ // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
425
+ const signedTxs = [];
426
+ if (needBribeTx && bribeNonce !== undefined) {
427
+ const bribeTx = await wallets[maxRevenueIndex].signTransaction({
428
+ to: BLOCKRAZOR_BUILDER_EOA,
429
+ value: bribeAmount,
430
+ nonce: bribeNonce,
431
+ gasPrice,
432
+ gasLimit: 21000n,
433
+ chainId: CHAIN_ID,
434
+ type: txType
435
+ });
436
+ signedTxs.push(bribeTx);
437
+ }
383
438
  // ✅ 并行签名所有卖出交易
384
439
  const signedSells = await Promise.all(sellUnsigned.map((unsigned, i) => wallets[i].signTransaction({
385
440
  ...unsigned,
@@ -391,8 +446,8 @@ export async function fourBatchPrivateSellMerkle(params) {
391
446
  type: txType,
392
447
  value: 0n
393
448
  })));
394
- const signedTxs = [...signedSells];
395
- // ✅ 聚合利润:由收益最高的钱包支付所有利润(1笔交易)
449
+ signedTxs.push(...signedSells);
450
+ // ✅ 利润交易放在末尾
396
451
  if (needProfitTx && profitNonce !== undefined) {
397
452
  const profitTx = await wallets[maxRevenueIndex].signTransaction({
398
453
  to: getProfitRecipient(),
@@ -55,6 +55,7 @@ export interface DirectV2BuyParams {
55
55
  routerAddress: string;
56
56
  quoteToken?: string;
57
57
  quoteTokenDecimals?: number;
58
+ startNonces?: number[];
58
59
  config: DirectRouterSignConfig;
59
60
  }
60
61
  export interface DirectV2SellParams {
@@ -62,6 +63,7 @@ export interface DirectV2SellParams {
62
63
  privateKeys: string[];
63
64
  sellPercentages?: number[];
64
65
  sellAmounts?: string[];
66
+ startNonces?: number[];
65
67
  tokenAddress: string;
66
68
  tokenDecimals?: number;
67
69
  routerAddress: string;
@@ -77,6 +79,7 @@ export interface DirectV3BuyParams {
77
79
  fee: number;
78
80
  quoteToken?: string;
79
81
  quoteTokenDecimals?: number;
82
+ startNonces?: number[];
80
83
  config: DirectRouterSignConfig;
81
84
  }
82
85
  export interface DirectV3SellParams {
@@ -89,6 +92,7 @@ export interface DirectV3SellParams {
89
92
  routerAddress: string;
90
93
  fee: number;
91
94
  quoteToken?: string;
95
+ startNonces?: number[];
92
96
  config: DirectRouterSignConfig;
93
97
  }
94
98
  export interface DirectRouterResult {