four-flap-meme-sdk 1.3.93 → 1.3.94

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.
Files changed (127) hide show
  1. package/dist/clients/blockrazor.js +1 -0
  2. package/dist/contracts/tm-bundle-merkle/config.d.ts +0 -5
  3. package/dist/contracts/tm-bundle-merkle/config.js +0 -10
  4. package/dist/contracts/tm-bundle-merkle/core.js +24 -92
  5. package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +54 -103
  6. package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +1 -0
  7. package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +6 -36
  8. package/dist/contracts/tm-bundle-merkle/swap.d.ts +3 -0
  9. package/dist/contracts/tm-bundle-merkle/swap.js +6 -59
  10. package/dist/flap/portal-bundle-merkle/config.d.ts +0 -8
  11. package/dist/flap/portal-bundle-merkle/config.js +0 -17
  12. package/dist/flap/portal-bundle-merkle/core.js +68 -120
  13. package/dist/flap/portal-bundle-merkle/pancake-proxy.js +78 -136
  14. package/dist/flap/portal-bundle-merkle/swap-buy-first.d.ts +2 -0
  15. package/dist/flap/portal-bundle-merkle/swap-buy-first.js +30 -49
  16. package/dist/flap/portal-bundle-merkle/swap.d.ts +2 -0
  17. package/dist/flap/portal-bundle-merkle/swap.js +47 -75
  18. package/dist/flap/portal-bundle-merkle/types.d.ts +0 -1
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.js +1 -0
  21. package/dist/pancake/bundle-buy-first.d.ts +1 -1
  22. package/dist/pancake/bundle-buy-first.js +17 -49
  23. package/dist/pancake/bundle-swap.d.ts +4 -1
  24. package/dist/pancake/bundle-swap.js +33 -98
  25. package/dist/sol/constants.d.ts +126 -0
  26. package/dist/sol/constants.js +145 -0
  27. package/dist/sol/dex/index.d.ts +8 -0
  28. package/dist/sol/dex/index.js +12 -0
  29. package/dist/sol/dex/meteora/client.d.ts +76 -0
  30. package/dist/sol/dex/meteora/client.js +219 -0
  31. package/dist/sol/dex/meteora/damm-v1-bundle.d.ts +61 -0
  32. package/dist/sol/dex/meteora/damm-v1-bundle.js +112 -0
  33. package/dist/sol/dex/meteora/damm-v1.d.ts +118 -0
  34. package/dist/sol/dex/meteora/damm-v1.js +315 -0
  35. package/dist/sol/dex/meteora/damm-v2-bundle.d.ts +82 -0
  36. package/dist/sol/dex/meteora/damm-v2-bundle.js +242 -0
  37. package/dist/sol/dex/meteora/damm-v2.d.ts +172 -0
  38. package/dist/sol/dex/meteora/damm-v2.js +632 -0
  39. package/dist/sol/dex/meteora/dbc-bundle.d.ts +123 -0
  40. package/dist/sol/dex/meteora/dbc-bundle.js +304 -0
  41. package/dist/sol/dex/meteora/dbc.d.ts +192 -0
  42. package/dist/sol/dex/meteora/dbc.js +619 -0
  43. package/dist/sol/dex/meteora/dlmm-bundle.d.ts +39 -0
  44. package/dist/sol/dex/meteora/dlmm-bundle.js +189 -0
  45. package/dist/sol/dex/meteora/dlmm.d.ts +157 -0
  46. package/dist/sol/dex/meteora/dlmm.js +671 -0
  47. package/dist/sol/dex/meteora/index.d.ts +25 -0
  48. package/dist/sol/dex/meteora/index.js +65 -0
  49. package/dist/sol/dex/meteora/types.d.ts +787 -0
  50. package/dist/sol/dex/meteora/types.js +110 -0
  51. package/dist/sol/dex/orca/index.d.ts +10 -0
  52. package/dist/sol/dex/orca/index.js +16 -0
  53. package/dist/sol/dex/orca/orca-bundle.d.ts +41 -0
  54. package/dist/sol/dex/orca/orca-bundle.js +173 -0
  55. package/dist/sol/dex/orca/orca.d.ts +65 -0
  56. package/dist/sol/dex/orca/orca.js +474 -0
  57. package/dist/sol/dex/orca/types.d.ts +263 -0
  58. package/dist/sol/dex/orca/types.js +38 -0
  59. package/dist/sol/dex/orca/wavebreak-bundle.d.ts +34 -0
  60. package/dist/sol/dex/orca/wavebreak-bundle.js +198 -0
  61. package/dist/sol/dex/orca/wavebreak-types.d.ts +227 -0
  62. package/dist/sol/dex/orca/wavebreak-types.js +23 -0
  63. package/dist/sol/dex/orca/wavebreak.d.ts +78 -0
  64. package/dist/sol/dex/orca/wavebreak.js +497 -0
  65. package/dist/sol/dex/pump/index.d.ts +9 -0
  66. package/dist/sol/dex/pump/index.js +14 -0
  67. package/dist/sol/dex/pump/pump-bundle.d.ts +92 -0
  68. package/dist/sol/dex/pump/pump-bundle.js +383 -0
  69. package/dist/sol/dex/pump/pump-swap-bundle.d.ts +103 -0
  70. package/dist/sol/dex/pump/pump-swap-bundle.js +380 -0
  71. package/dist/sol/dex/pump/pump-swap.d.ts +46 -0
  72. package/dist/sol/dex/pump/pump-swap.js +199 -0
  73. package/dist/sol/dex/pump/pump.d.ts +35 -0
  74. package/dist/sol/dex/pump/pump.js +352 -0
  75. package/dist/sol/dex/pump/types.d.ts +215 -0
  76. package/dist/sol/dex/pump/types.js +5 -0
  77. package/dist/sol/dex/raydium/index.d.ts +8 -0
  78. package/dist/sol/dex/raydium/index.js +12 -0
  79. package/dist/sol/dex/raydium/launchlab.d.ts +68 -0
  80. package/dist/sol/dex/raydium/launchlab.js +210 -0
  81. package/dist/sol/dex/raydium/raydium-bundle.d.ts +64 -0
  82. package/dist/sol/dex/raydium/raydium-bundle.js +324 -0
  83. package/dist/sol/dex/raydium/raydium.d.ts +40 -0
  84. package/dist/sol/dex/raydium/raydium.js +366 -0
  85. package/dist/sol/dex/raydium/types.d.ts +240 -0
  86. package/dist/sol/dex/raydium/types.js +5 -0
  87. package/dist/sol/index.d.ts +10 -0
  88. package/dist/sol/index.js +16 -0
  89. package/dist/sol/jito/bundle.d.ts +90 -0
  90. package/dist/sol/jito/bundle.js +263 -0
  91. package/dist/sol/jito/index.d.ts +7 -0
  92. package/dist/sol/jito/index.js +7 -0
  93. package/dist/sol/jito/tip.d.ts +51 -0
  94. package/dist/sol/jito/tip.js +83 -0
  95. package/dist/sol/jito/types.d.ts +100 -0
  96. package/dist/sol/jito/types.js +5 -0
  97. package/dist/sol/token/create-complete.d.ts +115 -0
  98. package/dist/sol/token/create-complete.js +235 -0
  99. package/dist/sol/token/create-token.d.ts +57 -0
  100. package/dist/sol/token/create-token.js +230 -0
  101. package/dist/sol/token/index.d.ts +9 -0
  102. package/dist/sol/token/index.js +14 -0
  103. package/dist/sol/token/metadata-upload.d.ts +86 -0
  104. package/dist/sol/token/metadata-upload.js +173 -0
  105. package/dist/sol/token/metadata.d.ts +92 -0
  106. package/dist/sol/token/metadata.js +274 -0
  107. package/dist/sol/token/types.d.ts +153 -0
  108. package/dist/sol/token/types.js +5 -0
  109. package/dist/sol/types.d.ts +176 -0
  110. package/dist/sol/types.js +7 -0
  111. package/dist/sol/utils/balance.d.ts +160 -0
  112. package/dist/sol/utils/balance.js +638 -0
  113. package/dist/sol/utils/connection.d.ts +78 -0
  114. package/dist/sol/utils/connection.js +168 -0
  115. package/dist/sol/utils/index.d.ts +9 -0
  116. package/dist/sol/utils/index.js +9 -0
  117. package/dist/sol/utils/lp-inspect.d.ts +129 -0
  118. package/dist/sol/utils/lp-inspect.js +900 -0
  119. package/dist/sol/utils/transfer.d.ts +125 -0
  120. package/dist/sol/utils/transfer.js +220 -0
  121. package/dist/sol/utils/wallet.d.ts +107 -0
  122. package/dist/sol/utils/wallet.js +210 -0
  123. package/dist/utils/erc20.d.ts +2 -108
  124. package/dist/utils/erc20.js +17 -65
  125. package/package.json +39 -4
  126. package/dist/flap/portal-bundle-merkle/encryption.d.ts +0 -16
  127. package/dist/flap/portal-bundle-merkle/encryption.js +0 -146
@@ -151,6 +151,7 @@ export class BlockRazorClient {
151
151
  const gasPrice = tx.gasPrice || 0n;
152
152
  const minGasPrice = ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
153
153
  if (gasPrice < minGasPrice) {
154
+ console.warn(`⚠️ 交易 Gas Price (${ethers.formatUnits(gasPrice, 'gwei')} Gwei) 低于最低要求 (${MIN_GAS_PRICE_GWEI} Gwei)`);
154
155
  }
155
156
  }
156
157
  catch {
@@ -64,8 +64,3 @@ export declare function calculateBatchProfit(amounts: bigint[], config?: FourAny
64
64
  totalProfit: bigint;
65
65
  remainingAmounts: bigint[];
66
66
  };
67
- /**
68
- * 获取贿赂金额(Wei)
69
- * ✅ 从配置中读取贿赂金额,转换为 Wei
70
- */
71
- export declare function getBribeAmount(config?: FourAnyConfig): bigint;
@@ -103,13 +103,3 @@ export function calculateBatchProfit(amounts, config) {
103
103
  }
104
104
  return { totalProfit, remainingAmounts };
105
105
  }
106
- /**
107
- * 获取贿赂金额(Wei)
108
- * ✅ 从配置中读取贿赂金额,转换为 Wei
109
- */
110
- export function getBribeAmount(config) {
111
- if (!config || !config.bribeAmount || config.bribeAmount <= 0) {
112
- return 0n;
113
- }
114
- return ethers.parseEther(String(config.bribeAmount));
115
- }
@@ -2,9 +2,7 @@ import { ethers, Wallet, 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 { FourClient, buildLoginMessage } from '../../clients/four.js';
5
- import { getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount } from './config.js';
6
- // ✅ BlockRazor Builder EOA 地址(用于贿赂)
7
- const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
5
+ import { getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
8
6
  import { batchCheckAllowances } from '../../utils/erc20.js';
9
7
  import { trySell } from '../tm.js';
10
8
  import Helper3Abi from '../../abis/TokenManagerHelper3.json' with { type: 'json' };
@@ -89,6 +87,7 @@ export async function createTokenWithBundleBuyMerkle(params) {
89
87
  const txType = getTxType(config);
90
88
  const signedTxs = [];
91
89
  const tmCreateAddr = ADDRESSES.BSC.TokenManagerOriginal;
90
+ const tmBuyAddr = ADDRESSES.BSC.TokenManagerOriginal;
92
91
  // ✅ 单笔交易: 和 Four.meme 官网一样
93
92
  // 计算利润
94
93
  const extractProfit = shouldExtractProfit(config);
@@ -104,9 +103,6 @@ export async function createTokenWithBundleBuyMerkle(params) {
104
103
  actualBuyFunds = originalBuyAmount;
105
104
  profitAmount = 0n;
106
105
  }
107
- // ✅ 获取贿赂金额
108
- const bribeAmount = getBribeAmount(config);
109
- const needBribeTx = bribeAmount > 0n;
110
106
  const b0AmountWei = ethers.parseEther(params.b0Amount ?? '0');
111
107
  const preSaleWei = tokenInfo.preSale ? ethers.parseEther(tokenInfo.preSale) : 0n;
112
108
  // ✅ 关键: value = 创建费用 + b0Amount + preSale + 买入金额
@@ -115,21 +111,6 @@ export async function createTokenWithBundleBuyMerkle(params) {
115
111
  const tmCreate = new ethers.Contract(tmCreateAddr, TM2_ABI, devWallet);
116
112
  const createTxUnsigned = await tmCreate.createToken.populateTransaction(createResp.createArg, createResp.signature, { value: valueWei } // ✅ 包含买入金额
117
113
  );
118
- // ✅ 贿赂交易放在首位(由 devWallet 发送)
119
- let bribeNonce;
120
- if (needBribeTx) {
121
- bribeNonce = await nonceManager.getNextNonce(devWallet);
122
- const bribeTx = await devWallet.signTransaction({
123
- to: BLOCKRAZOR_BUILDER_EOA,
124
- value: bribeAmount,
125
- nonce: bribeNonce,
126
- gasPrice,
127
- gasLimit: 21000n,
128
- chainId,
129
- type: txType
130
- });
131
- signedTxs.push(bribeTx);
132
- }
133
114
  const createTxRequest = {
134
115
  ...createTxUnsigned,
135
116
  from: devWallet.address,
@@ -141,7 +122,7 @@ export async function createTokenWithBundleBuyMerkle(params) {
141
122
  value: valueWei
142
123
  };
143
124
  signedTxs.push(await devWallet.signTransaction(createTxRequest));
144
- // ✅ 添加利润转账交易(放在末尾)
125
+ // ✅ 添加利润转账交易
145
126
  if (extractProfit && profitAmount > 0n) {
146
127
  const profitNonce = await nonceManager.getNextNonce(devWallet);
147
128
  const profitTx = await devWallet.signTransaction({
@@ -276,27 +257,6 @@ async function executeBuyFlow(options) {
276
257
  const extractProfit = shouldExtractProfit(config);
277
258
  const analysis = analyzeBuyFunds(buyAmounts, config, extractProfit);
278
259
  const finalGasLimit = getGasLimit(config);
279
- // ✅ 获取贿赂金额
280
- const bribeAmount = getBribeAmount(config);
281
- const needBribeTx = bribeAmount > 0n;
282
- const payer = profitMode.type === 'aggregated' ? (profitMode.payer ?? wallets[0]) : wallets[0];
283
- // ✅ 贿赂交易放在首位
284
- const signedTxs = [];
285
- let bribeNonceOffset = 0;
286
- if (needBribeTx) {
287
- const bribeNonce = await nonceManager.getNextNonce(payer);
288
- const bribeTx = await payer.signTransaction({
289
- to: BLOCKRAZOR_BUILDER_EOA,
290
- value: bribeAmount,
291
- nonce: bribeNonce,
292
- gasPrice,
293
- gasLimit: 21000n,
294
- chainId,
295
- type: txType
296
- });
297
- signedTxs.push(bribeTx);
298
- bribeNonceOffset = 1; // payer 的买入交易 nonce 需要偏移
299
- }
300
260
  // ✅ 优化:并行执行 populateBuyTransactions 和批量获取 nonces(JSON-RPC 批量请求)
301
261
  const [unsignedBuys, nonces] = await Promise.all([
302
262
  populateBuyTransactions({
@@ -307,24 +267,27 @@ async function executeBuyFlow(options) {
307
267
  }),
308
268
  nonceManager.getNextNoncesForWallets(wallets) // ✅ 批量获取 nonce
309
269
  ]);
310
- // ✅ 调整 payer nonce(如果有贿赂交易,需要偏移)
311
- const payerIndex = wallets.findIndex(w => w.address.toLowerCase() === payer.address.toLowerCase());
312
- const adjustedNonces = nonces.map((n, i) => i === payerIndex ? n + bribeNonceOffset : n);
270
+ // ✅ 如果需要利润转账,预先获取 payer 的下一个 nonce
271
+ let profitNonce;
272
+ if (extractProfit && analysis.totalProfit > 0n && profitMode.type === 'aggregated') {
273
+ const payer = profitMode.payer ?? wallets[0];
274
+ profitNonce = await nonceManager.getNextNonce(payer);
275
+ }
313
276
  // ✅ 并行签名所有买入交易
314
277
  const signedBuys = await Promise.all(unsignedBuys.map((unsigned, index) => wallets[index].signTransaction({
315
278
  ...unsigned,
316
279
  from: wallets[index].address,
317
- nonce: adjustedNonces[index],
280
+ nonce: nonces[index],
318
281
  gasLimit: finalGasLimit,
319
282
  gasPrice,
320
283
  chainId,
321
284
  type: txType,
322
285
  value: analysis.fundsList[index]
323
286
  })));
324
- signedTxs.push(...signedBuys);
325
- // ✅ 添加利润转账交易(放在末尾,由 payer 发送)
326
- if (extractProfit && analysis.totalProfit > 0n && profitMode.type === 'aggregated') {
327
- const profitNonce = await nonceManager.getNextNonce(payer);
287
+ const signedTxs = [...signedBuys];
288
+ // ✅ 添加利润转账交易(使用预先获取的 nonce)
289
+ if (extractProfit && profitNonce !== undefined && profitMode.type === 'aggregated') {
290
+ const payer = profitMode.payer ?? wallets[0];
328
291
  const profitTx = await payer.signTransaction({
329
292
  to: getProfitRecipient(),
330
293
  value: analysis.totalProfit,
@@ -344,9 +307,6 @@ async function executeSellFlow(options) {
344
307
  const amountsWei = sellAmounts.map((amount) => ethers.parseUnits(amount, 18));
345
308
  const finalGasLimit = getGasLimit(config);
346
309
  const extractProfit = shouldExtractProfit(config);
347
- // ✅ 获取贿赂金额
348
- const bribeAmount = getBribeAmount(config);
349
- const needBribeTx = bribeAmount > 0n;
350
310
  // ✅ 优化:并行执行 resolveSellOutputs、ensureSellerBalances、ensureSellAllowances 和批量获取 nonces
351
311
  const [sellOutputs, , , nonces] = await Promise.all([
352
312
  resolveSellOutputs({
@@ -366,29 +326,6 @@ async function executeSellFlow(options) {
366
326
  }),
367
327
  nonceManager.getNextNoncesForWallets(wallets) // ✅ 批量获取 nonce(JSON-RPC 批量请求)
368
328
  ]);
369
- // ✅ 找出收益最多的钱包作为 payer(贿赂和利润都由它发送)
370
- const { totalProfit, payer } = summarizeSellProfits(sellOutputs.quotedOutputs, wallets, config);
371
- const payerWallet = payer ?? wallets[0];
372
- const payerIndex = wallets.findIndex(w => w.address.toLowerCase() === payerWallet.address.toLowerCase());
373
- // ✅ 贿赂交易放在首位
374
- const signedTxs = [];
375
- let bribeNonceOffset = 0;
376
- if (needBribeTx) {
377
- const bribeNonce = nonces[payerIndex];
378
- const bribeTx = await payerWallet.signTransaction({
379
- to: BLOCKRAZOR_BUILDER_EOA,
380
- value: bribeAmount,
381
- nonce: bribeNonce,
382
- gasPrice,
383
- gasLimit: 21000n,
384
- chainId,
385
- type: txType
386
- });
387
- signedTxs.push(bribeTx);
388
- bribeNonceOffset = 1;
389
- }
390
- // ✅ 调整 payer 的 nonce(如果有贿赂交易,需要偏移)
391
- const adjustedNonces = nonces.map((n, i) => i === payerIndex ? n + bribeNonceOffset : n);
392
329
  // ✅ 构建未签名交易
393
330
  const unsignedSells = await populateSellTransactions({
394
331
  sellers: wallets,
@@ -401,24 +338,23 @@ async function executeSellFlow(options) {
401
338
  const signedSells = await Promise.all(unsignedSells.map((unsigned, index) => wallets[index].signTransaction({
402
339
  ...unsigned,
403
340
  from: wallets[index].address,
404
- nonce: adjustedNonces[index],
341
+ nonce: nonces[index],
405
342
  gasLimit: finalGasLimit,
406
343
  gasPrice,
407
344
  chainId,
408
345
  type: txType
409
346
  })));
410
- signedTxs.push(...signedSells);
411
- // 利润交易放在末尾
347
+ const signedTxs = [...signedSells];
348
+ const { totalProfit, payer } = summarizeSellProfits(sellOutputs.quotedOutputs, wallets, config);
412
349
  await appendAggregatedProfitTransfer({
413
350
  extractProfit,
414
351
  totalProfit,
415
- payer: payerWallet,
352
+ payer,
416
353
  nonceManager,
417
354
  gasPrice,
418
355
  chainId,
419
356
  txType,
420
- signedTxs,
421
- baseNonce: adjustedNonces[payerIndex] + 1 // ✅ 传入基础 nonce
357
+ signedTxs
422
358
  });
423
359
  return { signedTxs };
424
360
  }
@@ -476,8 +412,7 @@ async function resolveSellOutputs(params) {
476
412
  try {
477
413
  const result = await trySell('BSC', rpcUrl, tokenAddress, amountsWei[0]);
478
414
  const quotedOutputs = [result.funds];
479
- // ✅ 已移除滑点保护:minOuts 固定为 0
480
- const minOuts = [0n];
415
+ const minOuts = quotedOutputs.map((quote) => (quote * 95n) / 100n);
481
416
  return { minOuts, quotedOutputs };
482
417
  }
483
418
  catch {
@@ -510,8 +445,7 @@ async function resolveSellOutputs(params) {
510
445
  }
511
446
  return 0n;
512
447
  });
513
- // ✅ 已移除滑点保护:minOuts 固定为 0
514
- const minOuts = quotedOutputs.map(() => 0n);
448
+ const minOuts = quotedOutputs.map((quote) => (quote * 95n) / 100n);
515
449
  return { minOuts, quotedOutputs };
516
450
  }
517
451
  catch {
@@ -525,8 +459,7 @@ async function resolveSellOutputs(params) {
525
459
  return 0n;
526
460
  }
527
461
  }));
528
- // ✅ 已移除滑点保护:minOuts 固定为 0
529
- const minOuts = quotedOutputs.map(() => 0n);
462
+ const minOuts = quotedOutputs.map((quote) => (quote * 95n) / 100n);
530
463
  return { minOuts, quotedOutputs };
531
464
  }
532
465
  }
@@ -576,12 +509,11 @@ function summarizeSellProfits(quotedOutputs, sellers, config) {
576
509
  return { totalProfit, payer };
577
510
  }
578
511
  async function appendAggregatedProfitTransfer(params) {
579
- const { extractProfit, totalProfit, payer, nonceManager, gasPrice, chainId, txType, signedTxs, baseNonce } = params;
512
+ const { extractProfit, totalProfit, payer, nonceManager, gasPrice, chainId, txType, signedTxs } = params;
580
513
  if (!extractProfit || totalProfit <= 0n || !payer) {
581
514
  return;
582
515
  }
583
- // 如果提供了 baseNonce,直接使用;否则从 nonceManager 获取
584
- const profitNonce = baseNonce ?? await nonceManager.getNextNonce(payer);
516
+ const profitNonce = await nonceManager.getNextNonce(payer);
585
517
  const profitTx = await payer.signTransaction({
586
518
  to: getProfitRecipient(),
587
519
  value: totalProfit,
@@ -1,10 +1,8 @@
1
1
  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
- import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount } from './config.js';
4
+ import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient } from './config.js';
5
5
  import { batchCheckAllowances } from '../../utils/erc20.js';
6
- // ✅ BlockRazor Builder EOA 地址(用于贿赂)
7
- const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
8
6
  const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
9
7
  const MULTICALL3_ABI = [
10
8
  'function aggregate3(tuple(address target, bool allowFailure, bytes callData)[] calls) external payable returns (tuple(bool success, bytes returnData)[])'
@@ -305,22 +303,15 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
305
303
  const actualAmountsWei = remainingAmounts; // 扣除利润后用于购买的金额
306
304
  const finalGasLimit = getGasLimit(config);
307
305
  const nonceManager = new NonceManager(provider);
308
- // ✅ 获取贿赂金额
309
- const bribeAmount = getBribeAmount(config);
310
- const needBribeTx = bribeAmount > 0n;
311
306
  // ✅ 优化:并行获取 gasPrice 和 tokenDecimals
312
307
  const [gasPrice, tokenDecimals] = await Promise.all([
313
308
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
314
309
  getTokenDecimals(tokenAddress, provider)
315
310
  ]);
316
311
  // ✅ 修复:先计算需要的 nonce 数量,再统一获取
317
- // buyers[0] 可能需要 3 个 nonce(贿赂 + 买入 + 利润转账)
312
+ // buyers[0] 可能需要 2 个 nonce(买入 + 利润转账)
318
313
  const needProfitTx = extractProfit && totalProfit > 0n;
319
- let buyer0NeedCount = 1; // 买入交易
320
- if (needBribeTx)
321
- buyer0NeedCount++; // 贿赂交易
322
- if (needProfitTx)
323
- buyer0NeedCount++; // 利润交易
314
+ const buyer0NeedCount = needProfitTx ? 2 : 1;
324
315
  // 获取 buyers[0] 的连续 nonces
325
316
  const buyer0Nonces = await nonceManager.getNextNonceBatch(buyers[0], buyer0NeedCount);
326
317
  // 获取其他 buyers 的 nonces(如果有)
@@ -328,13 +319,9 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
328
319
  if (buyers.length > 1) {
329
320
  otherNonces = await nonceManager.getNextNoncesForWallets(buyers.slice(1));
330
321
  }
331
- // 分配 nonces
332
- let buyer0NonceIdx = 0;
333
- const bribeNonce = needBribeTx ? buyer0Nonces[buyer0NonceIdx++] : undefined;
334
- const buyer0BuyNonce = buyer0Nonces[buyer0NonceIdx++];
335
- const profitNonce = needProfitTx ? buyer0Nonces[buyer0NonceIdx] : undefined;
336
322
  // 组装最终的 nonces 数组
337
- const nonces = [buyer0BuyNonce, ...otherNonces];
323
+ const nonces = [buyer0Nonces[0], ...otherNonces];
324
+ const profitNonce = needProfitTx ? buyer0Nonces[1] : undefined;
338
325
  // 计算 minOutputAmounts
339
326
  let minOuts;
340
327
  if (params.minOutputAmounts && params.minOutputAmounts.length === buyers.length) {
@@ -369,22 +356,8 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
369
356
  else {
370
357
  throw new Error(`Unsupported routeType: ${routeType}`);
371
358
  }
372
- // ✅ 贿赂交易放在首位
373
- const signedTxs = [];
374
- if (needBribeTx && bribeNonce !== undefined) {
375
- const bribeTx = await buyers[0].signTransaction({
376
- to: BLOCKRAZOR_BUILDER_EOA,
377
- value: bribeAmount,
378
- nonce: bribeNonce,
379
- gasPrice,
380
- gasLimit: 21000n,
381
- chainId: 56,
382
- type: txType
383
- });
384
- signedTxs.push(bribeTx);
385
- }
386
359
  // ✅ 并行签名所有买入交易
387
- const signedBuys = await Promise.all(unsignedBuys.map((unsigned, i) => buyers[i].signTransaction({
360
+ const signedTxs = await Promise.all(unsignedBuys.map((unsigned, i) => buyers[i].signTransaction({
388
361
  ...unsigned,
389
362
  from: buyers[i].address,
390
363
  nonce: nonces[i],
@@ -394,8 +367,7 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
394
367
  type: txType,
395
368
  value: unsigned.value // ✅ 显式保留 value(BNB 金额 + 手续费)
396
369
  })));
397
- signedTxs.push(...signedBuys);
398
- // ✅ 添加利润转账(放在末尾,使用预先获取的 nonce)
370
+ // ✅ 添加利润转账(使用预先获取的 nonce)
399
371
  if (extractProfit && totalProfit > 0n && profitNonce !== undefined) {
400
372
  const profitTx = await buyers[0].signTransaction({
401
373
  to: getProfitRecipient(),
@@ -437,9 +409,6 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
437
409
  const finalGasLimit = getGasLimit(config);
438
410
  const nonceManager = new NonceManager(provider);
439
411
  const extractProfit = shouldExtractProfit(config);
440
- // ✅ 获取贿赂金额
441
- const bribeAmount = getBribeAmount(config);
442
- const needBribeTx = bribeAmount > 0n;
443
412
  // ✅ 优化:并行获取 gasPrice、tokenDecimals 和 allowances
444
413
  const [gasPrice, tokenDecimals, allowances] = await Promise.all([
445
414
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
@@ -460,40 +429,48 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
460
429
  if (needApprovalIndexes.length > 0) {
461
430
  throw new Error(`需要授权: ${needApprovalIndexes.length} 个钱包尚未授权。请先完成授权后再卖出。`);
462
431
  }
463
- // ✅ 获取报价(用于计算利润),已移除滑点保护
432
+ // ✅ 自动获取报价或使用用户提供的 minOutputAmounts
433
+ let minOuts;
464
434
  let quotedOutputs;
465
- // 使用 Multicall3 批量获取报价(仅 V2 路由支持)
466
- if (routeType === 'v2' && params.v2Path && params.v2Path.length >= 2) {
467
- quotedOutputs = await batchGetV2Quotes(provider, amountsWei, params.v2Path);
468
- }
469
- else if (routeType === 'v3-single') {
470
- // V3 单跳:并行调用(V3 Quoter 是 non-view 函数,不支持 Multicall3)
471
- quotedOutputs = await Promise.all(amountsWei.map(async (amount) => {
472
- try {
473
- const quoter = new Contract(PANCAKE_V3_QUOTER_ADDRESS, PANCAKE_V3_QUOTER_ABI, provider);
474
- const result = await quoter.quoteExactInputSingle.staticCall({
475
- tokenIn: tokenAddress,
476
- tokenOut: params.v3TokenOut,
477
- amountIn: amount,
478
- fee: params.v3Fee,
479
- sqrtPriceLimitX96: 0
480
- });
481
- return result[0];
482
- }
483
- catch {
484
- return 0n;
485
- }
486
- }));
487
- }
488
- else if (routeType === 'v3-multi' && params.v2Path && params.v2Path.length >= 2) {
489
- // V3 多跳:使用 V2 备选路由
490
- quotedOutputs = await batchGetV2Quotes(provider, amountsWei, params.v2Path);
435
+ if (params.minOutputAmounts && params.minOutputAmounts.length === sellers.length) {
436
+ // 用户提供了 minOutputAmounts,跳过报价查询
437
+ minOuts = params.minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseEther(m) : m);
438
+ quotedOutputs = minOuts.map(m => m * 100n / 95n); // 反推预期收益
491
439
  }
492
440
  else {
493
- quotedOutputs = new Array(amountsWei.length).fill(0n);
441
+ // 使用 Multicall3 批量获取报价(仅 V2 路由支持)
442
+ if (routeType === 'v2' && params.v2Path && params.v2Path.length >= 2) {
443
+ quotedOutputs = await batchGetV2Quotes(provider, amountsWei, params.v2Path);
444
+ }
445
+ else if (routeType === 'v3-single') {
446
+ // V3 单跳:并行调用(V3 Quoter 是 non-view 函数,不支持 Multicall3)
447
+ quotedOutputs = await Promise.all(amountsWei.map(async (amount) => {
448
+ try {
449
+ const quoter = new Contract(PANCAKE_V3_QUOTER_ADDRESS, PANCAKE_V3_QUOTER_ABI, provider);
450
+ const result = await quoter.quoteExactInputSingle.staticCall({
451
+ tokenIn: tokenAddress,
452
+ tokenOut: params.v3TokenOut,
453
+ amountIn: amount,
454
+ fee: params.v3Fee,
455
+ sqrtPriceLimitX96: 0
456
+ });
457
+ return result[0];
458
+ }
459
+ catch {
460
+ return 0n;
461
+ }
462
+ }));
463
+ }
464
+ else if (routeType === 'v3-multi' && params.v2Path && params.v2Path.length >= 2) {
465
+ // V3 多跳:使用 V2 备选路由
466
+ quotedOutputs = await batchGetV2Quotes(provider, amountsWei, params.v2Path);
467
+ }
468
+ else {
469
+ quotedOutputs = new Array(amountsWei.length).fill(0n);
470
+ }
471
+ // ✅ minOuts = 0,不设置滑点限制(大额交易更稳定)
472
+ minOuts = quotedOutputs.map(() => 0n);
494
473
  }
495
- // ✅ 已移除滑点保护:minOuts 固定为 0
496
- const minOuts = new Array(sellers.length).fill(0n);
497
474
  // ✅ 计算利润并找出收益最多的钱包
498
475
  let totalProfit = 0n;
499
476
  let maxRevenueIndex = 0;
@@ -512,43 +489,32 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
512
489
  }
513
490
  // ✅ 修复:先计算需要的 nonce 数量,再统一获取
514
491
  const needProfitTx = extractProfit && totalProfit > 0n && maxRevenue > 0n;
515
- // 分配 nonces:收益最多的钱包可能需要 3 个 nonce(贿赂 + 卖出 + 利润转账)
492
+ // 分配 nonces:收益最多的钱包可能需要 2 个 nonce(卖出 + 利润转账)
516
493
  let nonces;
517
- let bribeNonce;
518
494
  let profitNonce;
519
- if (needBribeTx || needProfitTx) {
520
- // 计算收益最多的钱包需要的 nonce 数量
521
- let maxRevenueNonceCount = 1; // 卖出交易
522
- if (needBribeTx)
523
- maxRevenueNonceCount++; // 贿赂交易
524
- if (needProfitTx)
525
- maxRevenueNonceCount++; // 利润交易
526
- // 收益最多的钱包需要连续 nonce
527
- const maxRevenueNonces = await nonceManager.getNextNonceBatch(sellers[maxRevenueIndex], maxRevenueNonceCount);
495
+ if (needProfitTx) {
496
+ // 收益最多的钱包需要 2 个连续 nonce
497
+ const maxRevenueNonces = await nonceManager.getNextNonceBatch(sellers[maxRevenueIndex], 2);
528
498
  // 其他钱包各需要 1 个 nonce
529
499
  const otherSellers = sellers.filter((_, i) => i !== maxRevenueIndex);
530
500
  const otherNonces = otherSellers.length > 0
531
501
  ? await nonceManager.getNextNoncesForWallets(otherSellers)
532
502
  : [];
533
- // 分配收益最多钱包的 nonces
534
- let maxRevenueNonceIdx = 0;
535
- bribeNonce = needBribeTx ? maxRevenueNonces[maxRevenueNonceIdx++] : undefined;
536
- const maxRevenueSellNonce = maxRevenueNonces[maxRevenueNonceIdx++];
537
- profitNonce = needProfitTx ? maxRevenueNonces[maxRevenueNonceIdx] : undefined;
538
503
  // 组装最终的 nonces 数组(保持原顺序)
539
504
  nonces = [];
540
505
  let otherIdx = 0;
541
506
  for (let i = 0; i < sellers.length; i++) {
542
507
  if (i === maxRevenueIndex) {
543
- nonces.push(maxRevenueSellNonce); // 卖出交易 nonce
508
+ nonces.push(maxRevenueNonces[0]); // 卖出交易用第一个 nonce
544
509
  }
545
510
  else {
546
511
  nonces.push(otherNonces[otherIdx++]);
547
512
  }
548
513
  }
514
+ profitNonce = maxRevenueNonces[1]; // 利润交易用第二个 nonce
549
515
  }
550
516
  else {
551
- // 不需要贿赂和利润交易,所有钱包各 1 个 nonce
517
+ // 不需要利润交易,所有钱包各 1 个 nonce
552
518
  nonces = await nonceManager.getNextNoncesForWallets(sellers);
553
519
  }
554
520
  // 卖出不需要发送 BNB,只需要 flatFee
@@ -577,22 +543,8 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
577
543
  else {
578
544
  throw new Error(`Unsupported routeType: ${routeType}`);
579
545
  }
580
- // ✅ 贿赂交易放在首位
581
- const signedTxs = [];
582
- if (needBribeTx && bribeNonce !== undefined) {
583
- const bribeTx = await sellers[maxRevenueIndex].signTransaction({
584
- to: BLOCKRAZOR_BUILDER_EOA,
585
- value: bribeAmount,
586
- nonce: bribeNonce,
587
- gasPrice,
588
- gasLimit: 21000n,
589
- chainId: 56,
590
- type: txType
591
- });
592
- signedTxs.push(bribeTx);
593
- }
594
546
  // ✅ 并行签名所有卖出交易
595
- const signedSells = await Promise.all(unsignedSells.map((unsigned, i) => sellers[i].signTransaction({
547
+ const signedTxs = await Promise.all(unsignedSells.map((unsigned, i) => sellers[i].signTransaction({
596
548
  ...unsigned,
597
549
  from: sellers[i].address,
598
550
  nonce: nonces[i],
@@ -602,8 +554,7 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
602
554
  type: txType,
603
555
  value: unsigned.value // ✅ 显式保留 value(手续费)
604
556
  })));
605
- signedTxs.push(...signedSells);
606
- // ✅ 添加利润转账(放在末尾,使用预先获取的 nonce)
557
+ // ✅ 添加利润转账(使用预先获取的 nonce)
607
558
  if (extractProfit && totalProfit > 0n && profitNonce !== undefined) {
608
559
  const profitTx = await sellers[maxRevenueIndex].signTransaction({
609
560
  to: getProfitRecipient(),
@@ -7,6 +7,7 @@ import { CommonBundleConfig } from '../../utils/bundle-helpers.js';
7
7
  import { FourSignConfig } from './types.js';
8
8
  export interface FourBuyFirstSignConfig extends FourSignConfig {
9
9
  reserveGasBNB?: number;
10
+ slippageBps?: number;
10
11
  }
11
12
  export interface FourBuyFirstConfig extends CommonBundleConfig {
12
13
  apiKey: string;
@@ -7,10 +7,8 @@ import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
8
8
  import { ADDRESSES } from '../../utils/constants.js';
9
9
  import { TM_ABI, HELPER3_ABI, TM_ADDRESS } from './swap-internal.js';
10
- import { getTxType, getGasPriceConfig, getProfitRecipient, getProfitRateBps, getBribeAmount } from './config.js';
10
+ import { getTxType, getGasPriceConfig, getProfitRecipient, getProfitRateBps } from './config.js';
11
11
  import { trySell } from '../tm.js';
12
- // ✅ BlockRazor Builder EOA 地址(用于贿赂)
13
- const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
14
12
  /**
15
13
  * 获取 Gas Limit(支持 FourAnyConfig)
16
14
  */
@@ -84,19 +82,14 @@ export async function fourBundleBuyFirstMerkle(params) {
84
82
  // ✅ 优化:第三批并行 - trySell、构建交易、获取 nonces
85
83
  const tmBuyer = new Contract(TM_ADDRESS, TM_ABI, buyer);
86
84
  const tmSeller = new Contract(TM_ADDRESS, TM_ABI, seller);
87
- // 已移除滑点保护:minBuyAmount 固定为 0
88
- const minBuyAmount = 0n;
85
+ const slippageBps = config.slippageBps ?? 100;
86
+ const minBuyAmount = (estimatedTokenAmount * BigInt(10000 - slippageBps)) / 10000n;
89
87
  // 预先规划 nonces
90
88
  const extractProfit = true;
91
89
  const profitRateBps = getProfitRateBps();
92
- // ✅ 获取贿赂金额
93
- const bribeAmount = getBribeAmount(config);
94
- const needBribeTx = bribeAmount > 0n;
95
90
  // 计算需要的 nonce 数量
96
91
  let buyerNonceCount = 1; // 买入交易
97
92
  let sellerNonceCount = 1; // 卖出交易
98
- if (needBribeTx)
99
- sellerNonceCount++; // 贿赂交易(由卖方发送)
100
93
  if (needApproval)
101
94
  sellerNonceCount++; // 授权交易
102
95
  if (extractProfit)
@@ -128,8 +121,7 @@ export async function fourBundleBuyFirstMerkle(params) {
128
121
  ]);
129
122
  const { buyerNonces, sellerNonces } = noncesResult;
130
123
  const estimatedSellFunds = sellResult.funds;
131
- // ✅ 已移除滑点保护:minSellFunds 固定为 0
132
- const minSellFunds = 0n;
124
+ const minSellFunds = (estimatedSellFunds * BigInt(10000 - slippageBps)) / 10000n;
133
125
  const profitAmount = extractProfit ? (estimatedSellFunds * BigInt(profitRateBps)) / 10000n : 0n;
134
126
  // 更新卖出交易的 minSellFunds
135
127
  sellUnsigned.data = tmSeller.interface.encodeFunctionData('sellToken', [
@@ -138,13 +130,10 @@ export async function fourBundleBuyFirstMerkle(params) {
138
130
  // 分配 nonces
139
131
  let buyerNonce;
140
132
  let sellerNonce;
141
- let bribeNonce;
142
133
  let approvalNonce;
143
134
  let profitNonce;
144
135
  if (sameAddress) {
145
136
  let idx = 0;
146
- if (needBribeTx)
147
- bribeNonce = sellerNonces[idx++];
148
137
  if (needApproval)
149
138
  approvalNonce = sellerNonces[idx++];
150
139
  buyerNonce = sellerNonces[idx++];
@@ -155,8 +144,6 @@ export async function fourBundleBuyFirstMerkle(params) {
155
144
  else {
156
145
  buyerNonce = buyerNonces[0];
157
146
  let idx = 0;
158
- if (needBribeTx)
159
- bribeNonce = sellerNonces[idx++];
160
147
  if (needApproval)
161
148
  approvalNonce = sellerNonces[idx++];
162
149
  sellerNonce = sellerNonces[idx++];
@@ -165,19 +152,6 @@ export async function fourBundleBuyFirstMerkle(params) {
165
152
  }
166
153
  // ✅ 并行签名所有交易
167
154
  const signPromises = [];
168
- // ✅ 贿赂交易放在首位
169
- let bribeTx = null;
170
- if (needBribeTx && bribeNonce !== undefined) {
171
- signPromises.push(seller.signTransaction({
172
- to: BLOCKRAZOR_BUILDER_EOA,
173
- value: bribeAmount,
174
- nonce: bribeNonce,
175
- gasPrice,
176
- gasLimit: 21000n,
177
- chainId: chainIdNum,
178
- type: txType
179
- }));
180
- }
181
155
  // 授权交易
182
156
  let approvalTx = null;
183
157
  if (needApproval && approvalNonce !== undefined) {
@@ -216,7 +190,7 @@ export async function fourBundleBuyFirstMerkle(params) {
216
190
  type: txType,
217
191
  value: 0n // ✅ 卖出交易不发送原生代币
218
192
  }));
219
- // ✅ 利润交易放在末尾
193
+ // 利润交易
220
194
  let profitTx = null;
221
195
  if (extractProfit && profitAmount > 0n && profitNonce !== undefined) {
222
196
  signPromises.push(seller.signTransaction({
@@ -232,8 +206,6 @@ export async function fourBundleBuyFirstMerkle(params) {
232
206
  const signedTxs = await Promise.all(signPromises);
233
207
  // 解析签名结果
234
208
  let idx = 0;
235
- if (needBribeTx)
236
- bribeTx = signedTxs[idx++];
237
209
  if (needApproval)
238
210
  approvalTx = signedTxs[idx++];
239
211
  const signedBuy = signedTxs[idx++];
@@ -241,10 +213,8 @@ export async function fourBundleBuyFirstMerkle(params) {
241
213
  if (extractProfit && profitAmount > 0n)
242
214
  profitTx = signedTxs[idx];
243
215
  nonceManager.clearTemp();
244
- // ✅ 组装交易列表:贿赂 → 授权 → 买入 → 卖出 → 利润
216
+ // 组装交易列表
245
217
  const allTransactions = [];
246
- if (bribeTx)
247
- allTransactions.push(bribeTx);
248
218
  if (approvalTx)
249
219
  allTransactions.push(approvalTx);
250
220
  allTransactions.push(signedBuy, signedSell);