four-flap-meme-sdk 1.3.94 → 1.3.95

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 (130) hide show
  1. package/dist/clients/blockrazor.js +0 -1
  2. package/dist/contracts/tm-bundle-merkle/config.d.ts +5 -0
  3. package/dist/contracts/tm-bundle-merkle/config.js +10 -0
  4. package/dist/contracts/tm-bundle-merkle/core.js +92 -24
  5. package/dist/contracts/tm-bundle-merkle/internal.d.ts +1 -1
  6. package/dist/contracts/tm-bundle-merkle/internal.js +4 -3
  7. package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +103 -54
  8. package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +0 -1
  9. package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +36 -6
  10. package/dist/contracts/tm-bundle-merkle/swap.d.ts +0 -3
  11. package/dist/contracts/tm-bundle-merkle/swap.js +59 -6
  12. package/dist/contracts/tm-bundle-merkle/utils.js +7 -7
  13. package/dist/flap/portal-bundle-merkle/config.d.ts +8 -0
  14. package/dist/flap/portal-bundle-merkle/config.js +17 -0
  15. package/dist/flap/portal-bundle-merkle/core.js +120 -68
  16. package/dist/flap/portal-bundle-merkle/encryption.d.ts +16 -0
  17. package/dist/flap/portal-bundle-merkle/encryption.js +146 -0
  18. package/dist/flap/portal-bundle-merkle/pancake-proxy.js +136 -78
  19. package/dist/flap/portal-bundle-merkle/swap-buy-first.d.ts +0 -2
  20. package/dist/flap/portal-bundle-merkle/swap-buy-first.js +49 -30
  21. package/dist/flap/portal-bundle-merkle/swap.d.ts +0 -2
  22. package/dist/flap/portal-bundle-merkle/swap.js +75 -47
  23. package/dist/flap/portal-bundle-merkle/types.d.ts +1 -0
  24. package/dist/index.d.ts +1 -2
  25. package/dist/index.js +0 -1
  26. package/dist/pancake/bundle-buy-first.d.ts +1 -1
  27. package/dist/pancake/bundle-buy-first.js +49 -17
  28. package/dist/pancake/bundle-swap.d.ts +1 -4
  29. package/dist/pancake/bundle-swap.js +98 -33
  30. package/dist/utils/erc20.d.ts +108 -2
  31. package/dist/utils/erc20.js +65 -17
  32. package/package.json +4 -39
  33. package/dist/sol/constants.d.ts +0 -126
  34. package/dist/sol/constants.js +0 -145
  35. package/dist/sol/dex/index.d.ts +0 -8
  36. package/dist/sol/dex/index.js +0 -12
  37. package/dist/sol/dex/meteora/client.d.ts +0 -76
  38. package/dist/sol/dex/meteora/client.js +0 -219
  39. package/dist/sol/dex/meteora/damm-v1-bundle.d.ts +0 -61
  40. package/dist/sol/dex/meteora/damm-v1-bundle.js +0 -112
  41. package/dist/sol/dex/meteora/damm-v1.d.ts +0 -118
  42. package/dist/sol/dex/meteora/damm-v1.js +0 -315
  43. package/dist/sol/dex/meteora/damm-v2-bundle.d.ts +0 -82
  44. package/dist/sol/dex/meteora/damm-v2-bundle.js +0 -242
  45. package/dist/sol/dex/meteora/damm-v2.d.ts +0 -172
  46. package/dist/sol/dex/meteora/damm-v2.js +0 -632
  47. package/dist/sol/dex/meteora/dbc-bundle.d.ts +0 -123
  48. package/dist/sol/dex/meteora/dbc-bundle.js +0 -304
  49. package/dist/sol/dex/meteora/dbc.d.ts +0 -192
  50. package/dist/sol/dex/meteora/dbc.js +0 -619
  51. package/dist/sol/dex/meteora/dlmm-bundle.d.ts +0 -39
  52. package/dist/sol/dex/meteora/dlmm-bundle.js +0 -189
  53. package/dist/sol/dex/meteora/dlmm.d.ts +0 -157
  54. package/dist/sol/dex/meteora/dlmm.js +0 -671
  55. package/dist/sol/dex/meteora/index.d.ts +0 -25
  56. package/dist/sol/dex/meteora/index.js +0 -65
  57. package/dist/sol/dex/meteora/types.d.ts +0 -787
  58. package/dist/sol/dex/meteora/types.js +0 -110
  59. package/dist/sol/dex/orca/index.d.ts +0 -10
  60. package/dist/sol/dex/orca/index.js +0 -16
  61. package/dist/sol/dex/orca/orca-bundle.d.ts +0 -41
  62. package/dist/sol/dex/orca/orca-bundle.js +0 -173
  63. package/dist/sol/dex/orca/orca.d.ts +0 -65
  64. package/dist/sol/dex/orca/orca.js +0 -474
  65. package/dist/sol/dex/orca/types.d.ts +0 -263
  66. package/dist/sol/dex/orca/types.js +0 -38
  67. package/dist/sol/dex/orca/wavebreak-bundle.d.ts +0 -34
  68. package/dist/sol/dex/orca/wavebreak-bundle.js +0 -198
  69. package/dist/sol/dex/orca/wavebreak-types.d.ts +0 -227
  70. package/dist/sol/dex/orca/wavebreak-types.js +0 -23
  71. package/dist/sol/dex/orca/wavebreak.d.ts +0 -78
  72. package/dist/sol/dex/orca/wavebreak.js +0 -497
  73. package/dist/sol/dex/pump/index.d.ts +0 -9
  74. package/dist/sol/dex/pump/index.js +0 -14
  75. package/dist/sol/dex/pump/pump-bundle.d.ts +0 -92
  76. package/dist/sol/dex/pump/pump-bundle.js +0 -383
  77. package/dist/sol/dex/pump/pump-swap-bundle.d.ts +0 -103
  78. package/dist/sol/dex/pump/pump-swap-bundle.js +0 -380
  79. package/dist/sol/dex/pump/pump-swap.d.ts +0 -46
  80. package/dist/sol/dex/pump/pump-swap.js +0 -199
  81. package/dist/sol/dex/pump/pump.d.ts +0 -35
  82. package/dist/sol/dex/pump/pump.js +0 -352
  83. package/dist/sol/dex/pump/types.d.ts +0 -215
  84. package/dist/sol/dex/pump/types.js +0 -5
  85. package/dist/sol/dex/raydium/index.d.ts +0 -8
  86. package/dist/sol/dex/raydium/index.js +0 -12
  87. package/dist/sol/dex/raydium/launchlab.d.ts +0 -68
  88. package/dist/sol/dex/raydium/launchlab.js +0 -210
  89. package/dist/sol/dex/raydium/raydium-bundle.d.ts +0 -64
  90. package/dist/sol/dex/raydium/raydium-bundle.js +0 -324
  91. package/dist/sol/dex/raydium/raydium.d.ts +0 -40
  92. package/dist/sol/dex/raydium/raydium.js +0 -366
  93. package/dist/sol/dex/raydium/types.d.ts +0 -240
  94. package/dist/sol/dex/raydium/types.js +0 -5
  95. package/dist/sol/index.d.ts +0 -10
  96. package/dist/sol/index.js +0 -16
  97. package/dist/sol/jito/bundle.d.ts +0 -90
  98. package/dist/sol/jito/bundle.js +0 -263
  99. package/dist/sol/jito/index.d.ts +0 -7
  100. package/dist/sol/jito/index.js +0 -7
  101. package/dist/sol/jito/tip.d.ts +0 -51
  102. package/dist/sol/jito/tip.js +0 -83
  103. package/dist/sol/jito/types.d.ts +0 -100
  104. package/dist/sol/jito/types.js +0 -5
  105. package/dist/sol/token/create-complete.d.ts +0 -115
  106. package/dist/sol/token/create-complete.js +0 -235
  107. package/dist/sol/token/create-token.d.ts +0 -57
  108. package/dist/sol/token/create-token.js +0 -230
  109. package/dist/sol/token/index.d.ts +0 -9
  110. package/dist/sol/token/index.js +0 -14
  111. package/dist/sol/token/metadata-upload.d.ts +0 -86
  112. package/dist/sol/token/metadata-upload.js +0 -173
  113. package/dist/sol/token/metadata.d.ts +0 -92
  114. package/dist/sol/token/metadata.js +0 -274
  115. package/dist/sol/token/types.d.ts +0 -153
  116. package/dist/sol/token/types.js +0 -5
  117. package/dist/sol/types.d.ts +0 -176
  118. package/dist/sol/types.js +0 -7
  119. package/dist/sol/utils/balance.d.ts +0 -160
  120. package/dist/sol/utils/balance.js +0 -638
  121. package/dist/sol/utils/connection.d.ts +0 -78
  122. package/dist/sol/utils/connection.js +0 -168
  123. package/dist/sol/utils/index.d.ts +0 -9
  124. package/dist/sol/utils/index.js +0 -9
  125. package/dist/sol/utils/lp-inspect.d.ts +0 -129
  126. package/dist/sol/utils/lp-inspect.js +0 -900
  127. package/dist/sol/utils/transfer.d.ts +0 -125
  128. package/dist/sol/utils/transfer.js +0 -220
  129. package/dist/sol/utils/wallet.d.ts +0 -107
  130. package/dist/sol/utils/wallet.js +0 -210
@@ -1,7 +1,7 @@
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 { CHAIN_ID_MAP, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient } from './config.js';
4
+ import { CHAIN_ID_MAP, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
5
5
  import { batchCheckAllowances } from '../../utils/erc20.js';
6
6
  const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
7
7
  const MULTICALL3_ABI = [
@@ -56,16 +56,27 @@ function getGasLimit(config, defaultGas = DEFAULT_GAS_LIMIT) {
56
56
  return BigInt(calculatedGas);
57
57
  }
58
58
  /**
59
- * 查询代币 decimals
59
+ * 查询代币 decimals(带缓存)
60
+ * ✅ 代币精度不会变化,缓存后永久有效
60
61
  */
61
62
  async function getTokenDecimals(tokenAddress, provider) {
63
+ const cacheKey = tokenAddress.toLowerCase();
64
+ // ✅ 检查缓存
65
+ const cached = tokenDecimalsCache.get(cacheKey);
66
+ if (cached !== undefined) {
67
+ return cached;
68
+ }
62
69
  try {
63
70
  const token = new Contract(tokenAddress, ERC20_ABI, provider);
64
71
  const decimals = await token.decimals();
65
- return Number(decimals);
72
+ const result = Number(decimals);
73
+ // ✅ 缓存结果
74
+ tokenDecimalsCache.set(cacheKey, result);
75
+ return result;
66
76
  }
67
77
  catch {
68
- // 默认返回 18,兼容大部分 ERC20
78
+ // 默认返回 18,兼容大部分 ERC20(也缓存)
79
+ tokenDecimalsCache.set(cacheKey, 18);
69
80
  return 18;
70
81
  }
71
82
  }
@@ -281,11 +292,21 @@ export async function pancakeProxyBatchBuyMerkle(params) {
281
292
  const divisor = BigInt(10 ** decimalsDiff);
282
293
  actualAmountsWei = remainingAmounts.map(amount => amount / divisor);
283
294
  }
284
- // ✅ 优化:第一批并行 - gasPrice、tokenDecimals、nonces(JSON-RPC 批量请求)
295
+ // ✅ 优化:如果前端传入了 gasPrice nonces,跳过 RPC 调用
296
+ const presetGasPrice = config.gasPrice;
297
+ const presetNonces = config.nonces;
298
+ // ✅ 只获取必需的数据(跳过已有的)
285
299
  const [gasPrice, tokenDecimals, nonces] = await Promise.all([
286
- getOptimizedGasPrice(provider, getGasPriceConfig(config)),
300
+ // gasPrice:优先使用前端传入的
301
+ presetGasPrice !== undefined
302
+ ? Promise.resolve(presetGasPrice)
303
+ : getOptimizedGasPrice(provider, getGasPriceConfig(config)),
304
+ // tokenDecimals:有缓存
287
305
  getTokenDecimals(tokenAddress, provider),
288
- allocateProfitAwareNonces(buyers, shouldExtractProfitForBuy, maxFundsIndex, nativeProfitAmount, nonceManager)
306
+ // nonces:优先使用前端传入的
307
+ presetNonces && presetNonces.length === buyers.length
308
+ ? Promise.resolve(presetNonces)
309
+ : allocateProfitAwareNonces(buyers, shouldExtractProfitForBuy, maxFundsIndex, nativeProfitAmount, nonceManager)
289
310
  ]);
290
311
  const minOuts = resolveBuyMinOutputs(params, buyers.length, tokenDecimals);
291
312
  const needBNB = needSendBNB(routeType, params, useNativeToken);
@@ -301,8 +322,26 @@ export async function pancakeProxyBatchBuyMerkle(params) {
301
322
  minOuts,
302
323
  needBNB
303
324
  });
304
- // ✅ 并行签名所有交易
305
- const signedTxs = await Promise.all(unsignedBuys.map((unsigned, i) => {
325
+ // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
326
+ const bribeAmount = getBribeAmount(config);
327
+ const bribeTxs = [];
328
+ if (bribeAmount > 0n && maxFundsIndex >= 0 && buyers.length > 0) {
329
+ const bribeNonce = nonces[maxFundsIndex];
330
+ const bribeTx = await buyers[maxFundsIndex].signTransaction({
331
+ to: BLOCKRAZOR_BUILDER_EOA,
332
+ value: bribeAmount,
333
+ nonce: bribeNonce,
334
+ gasPrice,
335
+ gasLimit: 21000n,
336
+ chainId,
337
+ type: getTxType(config)
338
+ });
339
+ bribeTxs.push(bribeTx);
340
+ // 调整 maxFundsIndex 钱包的 nonce(买入交易 +1)
341
+ nonces[maxFundsIndex] = bribeNonce + 1;
342
+ }
343
+ // ✅ 并行签名所有买入交易
344
+ const signedBuys = await Promise.all(unsignedBuys.map((unsigned, i) => {
306
345
  // ✅ ERC20 购买时 value 只需要 FLAT_FEE,不需要发送代币金额
307
346
  const txValue = useNativeToken ? unsigned.value : FLAT_FEE;
308
347
  return buyers[i].signTransaction({
@@ -316,20 +355,25 @@ export async function pancakeProxyBatchBuyMerkle(params) {
316
355
  value: txValue
317
356
  });
318
357
  }));
319
- await appendProfitTransfer({
320
- extractProfit: shouldExtractProfitForBuy, // ✅ ERC20 购买时不提取利润
321
- totalProfit: nativeProfitAmount,
322
- wallets: buyers,
323
- maxIndex: maxFundsIndex,
324
- nonces,
325
- gasPrice,
326
- chainId,
327
- config,
328
- signedTxs
329
- });
358
+ // ✅ 利润交易放在末尾
359
+ const profitTxs = [];
360
+ if (shouldExtractProfitForBuy && nativeProfitAmount > 0n && maxFundsIndex >= 0) {
361
+ const profitNonce = nonces[maxFundsIndex] + 1;
362
+ const profitTx = await buyers[maxFundsIndex].signTransaction({
363
+ to: getProfitRecipient(),
364
+ value: nativeProfitAmount,
365
+ nonce: profitNonce,
366
+ gasPrice,
367
+ gasLimit: 21000n,
368
+ chainId,
369
+ type: getTxType(config)
370
+ });
371
+ profitTxs.push(profitTx);
372
+ }
330
373
  nonceManager.clearTemp();
374
+ // ✅ 组装顺序:贿赂 → 买入 → 利润
331
375
  return {
332
- signedTransactions: signedTxs
376
+ signedTransactions: [...bribeTxs, ...signedBuys, ...profitTxs]
333
377
  };
334
378
  }
335
379
  /**
@@ -350,10 +394,18 @@ export async function pancakeProxyBatchSellMerkle(params) {
350
394
  const finalGasLimit = getGasLimit(config);
351
395
  const extractProfit = shouldExtractProfit(config);
352
396
  const nonceManager = new NonceManager(provider);
397
+ // ✅ 优化:如果前端传入了 gasPrice 和 nonces,跳过 RPC 调用
398
+ const presetGasPrice = config.gasPrice;
399
+ const presetNonces = config.nonces;
353
400
  // ✅ 优化:第一批并行 - gasPrice、tokenDecimals、allowances
354
401
  const [gasPrice, tokenDecimals] = await Promise.all([
355
- getOptimizedGasPrice(provider, getGasPriceConfig(config)),
402
+ // gasPrice:优先使用前端传入的
403
+ presetGasPrice !== undefined
404
+ ? Promise.resolve(presetGasPrice)
405
+ : getOptimizedGasPrice(provider, getGasPriceConfig(config)),
406
+ // tokenDecimals:有缓存
356
407
  getTokenDecimals(tokenAddress, provider),
408
+ // allowances:必须检查
357
409
  ensureAllowances({
358
410
  provider,
359
411
  tokenAddress,
@@ -362,8 +414,8 @@ export async function pancakeProxyBatchSellMerkle(params) {
362
414
  })
363
415
  ]);
364
416
  const amountsWei = sellAmounts.map(amount => ethers.parseUnits(amount, tokenDecimals));
365
- // ✅ 优化:第二批并行 - resolveSellOutputs 和 buildSellTransactions
366
417
  const proxies = createPancakeProxies(sellers, ADDRESSES.BSC.PancakeProxy);
418
+ // 获取报价(用于计算利润)
367
419
  const { minOuts, quotedOutputs } = await resolveSellOutputs({
368
420
  params,
369
421
  provider,
@@ -388,13 +440,27 @@ export async function pancakeProxyBatchSellMerkle(params) {
388
440
  }
389
441
  }
390
442
  }
391
- // ✅ 修复:根据是否需要利润交易,统一分配 nonces
443
+ // ✅ 修复:根据是否需要贿赂/利润交易,统一分配 nonces
444
+ const bribeAmount = getBribeAmount(config);
445
+ const needBribeTx = bribeAmount > 0n && maxRevenueIndex >= 0;
392
446
  const needProfitTx = extractProfit && totalProfit > 0n && maxRevenueIndex >= 0;
447
+ // 计算 maxRevenueIndex 钱包需要的 nonce 数量:贿赂(可选) + 卖出 + 利润(可选)
448
+ const maxRevenueNonceCount = 1 + (needBribeTx ? 1 : 0) + (needProfitTx ? 1 : 0);
393
449
  let nonces;
450
+ let bribeNonce;
394
451
  let profitNonce;
395
- if (needProfitTx) {
396
- // maxRevenueIndex 钱包需要 2 个连续 nonce(卖出 + 利润)
397
- const maxRevenueNonces = await nonceManager.getNextNonceBatch(sellers[maxRevenueIndex], 2);
452
+ // 优化:如果前端传入了 nonces,直接使用
453
+ if (presetNonces && presetNonces.length === sellers.length) {
454
+ nonces = [...presetNonces];
455
+ if (needBribeTx) {
456
+ bribeNonce = nonces[maxRevenueIndex];
457
+ nonces[maxRevenueIndex] = bribeNonce + 1; // 卖出交易 nonce +1
458
+ }
459
+ profitNonce = needProfitTx ? nonces[maxRevenueIndex] + 1 : undefined;
460
+ }
461
+ else if (maxRevenueNonceCount > 1 && maxRevenueIndex >= 0) {
462
+ // maxRevenueIndex 钱包需要多个连续 nonce
463
+ const maxRevenueNonces = await nonceManager.getNextNonceBatch(sellers[maxRevenueIndex], maxRevenueNonceCount);
398
464
  // 其他钱包各需要 1 个 nonce
399
465
  const otherSellers = sellers.filter((_, i) => i !== maxRevenueIndex);
400
466
  const otherNonces = otherSellers.length > 0
@@ -403,20 +469,40 @@ export async function pancakeProxyBatchSellMerkle(params) {
403
469
  // 组装最终的 nonces 数组(保持原顺序)
404
470
  nonces = [];
405
471
  let otherIdx = 0;
472
+ let nonceIdx = 0;
473
+ if (needBribeTx) {
474
+ bribeNonce = maxRevenueNonces[nonceIdx++]; // 贿赂交易用第一个 nonce
475
+ }
406
476
  for (let i = 0; i < sellers.length; i++) {
407
477
  if (i === maxRevenueIndex) {
408
- nonces.push(maxRevenueNonces[0]); // 卖出交易用第一个 nonce
478
+ nonces.push(maxRevenueNonces[nonceIdx++]); // 卖出交易
409
479
  }
410
480
  else {
411
481
  nonces.push(otherNonces[otherIdx++]);
412
482
  }
413
483
  }
414
- profitNonce = maxRevenueNonces[1]; // 利润交易用第二个 nonce
484
+ if (needProfitTx) {
485
+ profitNonce = maxRevenueNonces[nonceIdx]; // 利润交易用最后一个 nonce
486
+ }
415
487
  }
416
488
  else {
417
- // 不需要利润交易,所有钱包各 1 个 nonce
489
+ // 不需要额外交易,所有钱包各 1 个 nonce
418
490
  nonces = await nonceManager.getNextNoncesForWallets(sellers);
419
491
  }
492
+ // ✅ 贿赂交易放在首位
493
+ const bribeTxs = [];
494
+ if (needBribeTx && bribeNonce !== undefined) {
495
+ const bribeTx = await sellers[maxRevenueIndex].signTransaction({
496
+ to: BLOCKRAZOR_BUILDER_EOA,
497
+ value: bribeAmount,
498
+ nonce: bribeNonce,
499
+ gasPrice,
500
+ gasLimit: 21000n,
501
+ chainId,
502
+ type: getTxType(config)
503
+ });
504
+ bribeTxs.push(bribeTx);
505
+ }
420
506
  const unsignedSells = await buildSellTransactions({
421
507
  routeType,
422
508
  params,
@@ -426,8 +512,8 @@ export async function pancakeProxyBatchSellMerkle(params) {
426
512
  amountsWei,
427
513
  minOuts
428
514
  });
429
- // ✅ 并行签名所有交易
430
- const signedTxs = await Promise.all(unsignedSells.map((unsigned, i) => {
515
+ // ✅ 并行签名所有卖出交易
516
+ const signedSells = await Promise.all(unsignedSells.map((unsigned, i) => {
431
517
  const txValue = unsigned.value;
432
518
  return sellers[i].signTransaction({
433
519
  ...unsigned,
@@ -440,7 +526,8 @@ export async function pancakeProxyBatchSellMerkle(params) {
440
526
  value: txValue
441
527
  });
442
528
  }));
443
- // ✅ 添加利润交易(使用预先分配的 profitNonce)
529
+ // ✅ 利润交易放在末尾
530
+ const profitTxs = [];
444
531
  if (needProfitTx && profitNonce !== undefined) {
445
532
  const profitTx = await sellers[maxRevenueIndex].signTransaction({
446
533
  to: getProfitRecipient(),
@@ -451,16 +538,19 @@ export async function pancakeProxyBatchSellMerkle(params) {
451
538
  chainId,
452
539
  type: getTxType(config)
453
540
  });
454
- signedTxs.push(profitTx);
541
+ profitTxs.push(profitTx);
455
542
  }
456
543
  nonceManager.clearTemp();
544
+ // ✅ 组装顺序:贿赂 → 卖出 → 利润
457
545
  return {
458
- signedTransactions: signedTxs
546
+ signedTransactions: [...bribeTxs, ...signedSells, ...profitTxs]
459
547
  };
460
548
  }
461
549
  // ✅ Provider 缓存(复用连接,减少初始化开销)
462
550
  const providerCache = new Map();
463
551
  const PROVIDER_CACHE_TTL_MS = 60 * 1000; // 60秒缓存
552
+ // ✅ Token Decimals 缓存(代币精度不会变化)
553
+ const tokenDecimalsCache = new Map();
464
554
  function createChainContext(chain, rpcUrl) {
465
555
  const chainId = CHAIN_ID_MAP[chain];
466
556
  const cacheKey = `${chain}-${rpcUrl}`;
@@ -492,10 +582,8 @@ function findMaxAmountIndex(amounts) {
492
582
  }
493
583
  return maxIndex;
494
584
  }
495
- function resolveBuyMinOutputs(params, walletCount, tokenDecimals) {
496
- if (params.minOutputAmounts && params.minOutputAmounts.length === walletCount) {
497
- return params.minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseUnits(m, tokenDecimals) : m);
498
- }
585
+ function resolveBuyMinOutputs(_params, walletCount, _tokenDecimals) {
586
+ // 已移除滑点保护:minOutput 固定为 0
499
587
  return new Array(walletCount).fill(0n);
500
588
  }
501
589
  function createPancakeProxies(wallets, proxyAddress) {
@@ -551,22 +639,6 @@ async function allocateProfitAwareNonces(wallets, extractProfit, maxIndex, total
551
639
  }
552
640
  return nonces;
553
641
  }
554
- async function appendProfitTransfer({ extractProfit, totalProfit, wallets, maxIndex, nonces, gasPrice, chainId, config, signedTxs }) {
555
- if (!extractProfit || totalProfit === 0n || wallets.length === 0 || maxIndex < 0) {
556
- return;
557
- }
558
- const profitNonce = (nonces[maxIndex] ?? 0) + 1;
559
- const profitTx = await wallets[maxIndex].signTransaction({
560
- to: getProfitRecipient(),
561
- value: totalProfit,
562
- nonce: profitNonce,
563
- gasPrice,
564
- gasLimit: 21000n,
565
- chainId,
566
- type: getTxType(config)
567
- });
568
- signedTxs.push(profitTx);
569
- }
570
642
  async function ensureAllowances({ provider, tokenAddress, owners, spender }) {
571
643
  const allowances = await batchCheckAllowances(provider, tokenAddress, owners, spender);
572
644
  const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
@@ -576,26 +648,18 @@ async function ensureAllowances({ provider, tokenAddress, owners, spender }) {
576
648
  }
577
649
  }
578
650
  /**
579
- * ✅ 使用 Multicall3 批量获取卖出报价(单次 RPC)
651
+ * ✅ 获取卖出报价(用于计算利润,不用于滑点保护)
652
+ * ✅ 已移除滑点保护:minOutput 固定为 0
580
653
  */
581
654
  async function resolveSellOutputs({ params, provider, tokenAddress, routeType, amountsWei }) {
582
- // 如果已提供 minOutputAmounts,直接使用,跳过报价查询
583
- if (params.minOutputAmounts && params.minOutputAmounts.length === amountsWei.length) {
584
- const minOuts = params.minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseEther(m) : m);
585
- return {
586
- minOuts,
587
- quotedOutputs: minOuts.map(m => m * 100n / 95n)
588
- };
589
- }
655
+ // 已移除滑点保护:minOutput 固定为 0
656
+ const minOuts = new Array(amountsWei.length).fill(0n);
590
657
  // 如果只有 1 个,直接调用(避免 multicall 开销)
591
658
  if (amountsWei.length === 1) {
592
659
  const quotedOutput = await getSingleQuote(params, provider, tokenAddress, routeType, amountsWei[0]);
593
- return {
594
- quotedOutputs: [quotedOutput],
595
- minOuts: [0n] // ✅ minOutput = 0,不设置滑点限制
596
- };
660
+ return { quotedOutputs: [quotedOutput], minOuts };
597
661
  }
598
- // ✅ 使用 Multicall3 批量获取报价(仅 V2 路由支持)
662
+ // ✅ 使用 Multicall3 批量获取报价(仅 V2 路由支持,用于计算利润)
599
663
  if (routeType === 'v2' && params.v2Path && params.v2Path.length >= 2) {
600
664
  try {
601
665
  const v2RouterIface = new Interface(PANCAKE_V2_ROUTER_ABI);
@@ -619,10 +683,7 @@ async function resolveSellOutputs({ params, provider, tokenAddress, routeType, a
619
683
  }
620
684
  return 0n;
621
685
  });
622
- return {
623
- quotedOutputs,
624
- minOuts: quotedOutputs.map(() => 0n) // ✅ minOutput = 0,不设置滑点限制
625
- };
686
+ return { quotedOutputs, minOuts };
626
687
  }
627
688
  catch {
628
689
  // Multicall 失败,回退到并行调用
@@ -630,10 +691,7 @@ async function resolveSellOutputs({ params, provider, tokenAddress, routeType, a
630
691
  }
631
692
  // 回退:并行调用(V3 路由或 Multicall 失败时)
632
693
  const quotedOutputs = await Promise.all(amountsWei.map(amount => getSingleQuote(params, provider, tokenAddress, routeType, amount)));
633
- return {
634
- quotedOutputs,
635
- minOuts: quotedOutputs.map(() => 0n) // ✅ minOutput = 0,不设置滑点限制
636
- };
694
+ return { quotedOutputs, minOuts };
637
695
  }
638
696
  /**
639
697
  * 获取单个报价
@@ -701,4 +759,4 @@ async function buildSellTransactions({ routeType, params, proxies, wallets, toke
701
759
  }
702
760
  throw new Error(`Unsupported routeType: ${routeType}`);
703
761
  }
704
- // ✅ appendSellProfitTransfer 已内联到 pancakeProxyBatchSellMerkle 中,避免 nonce 竞争问题
762
+ // ✅ 贿赂交易和利润交易已内联到各函数中,确保正确的顺序:贿赂 主交易 利润
@@ -8,7 +8,6 @@ import { FlapSignConfig } from './config.js';
8
8
  export type FlapChain = 'bsc' | 'xlayer' | 'base';
9
9
  export interface FlapBuyFirstSignConfig extends FlapSignConfig {
10
10
  reserveGasETH?: number;
11
- slippageBps?: number;
12
11
  skipQuoteOnError?: boolean;
13
12
  }
14
13
  export interface FlapBuyFirstConfig extends CommonBundleConfig {
@@ -16,7 +15,6 @@ export interface FlapBuyFirstConfig extends CommonBundleConfig {
16
15
  customRpcUrl?: string;
17
16
  bundleBlockOffset?: number;
18
17
  reserveGasETH?: number;
19
- slippageBps?: number;
20
18
  skipQuoteOnError?: boolean;
21
19
  waitForConfirmation?: boolean;
22
20
  waitTimeoutMs?: number;
@@ -7,7 +7,7 @@ import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
8
8
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
9
9
  import { PROFIT_CONFIG } from '../../utils/constants.js';
10
- import { getGasPriceConfig, getTxType, getProfitRecipient } from './config.js';
10
+ import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
11
11
  // Portal ABI
12
12
  const PORTAL_ABI = [
13
13
  'function swapExactInput((address inputToken, address outputToken, uint256 inputAmount, uint256 minOutputAmount, bytes permitData)) payable returns (uint256)',
@@ -124,12 +124,11 @@ export async function flapBundleBuyFirstMerkle(params) {
124
124
  ]);
125
125
  const { buyerFundsWei, buyerBalance } = buyerFundsResult;
126
126
  const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
127
- // ✅ 获取报价
127
+ // ✅ 获取报价(已移除滑点保护)
128
128
  const quoteResult = await quoteBuyerOutput({
129
129
  portalAddress: chainContext.portalAddress,
130
130
  tokenAddress,
131
131
  buyerFundsWei,
132
- slippageBps: config.slippageBps,
133
132
  provider: chainContext.provider,
134
133
  skipQuoteOnError: config.skipQuoteOnError,
135
134
  inputToken // ✅ 传递输入代币
@@ -177,12 +176,16 @@ export async function flapBundleBuyFirstMerkle(params) {
177
176
  gasPrice,
178
177
  txType
179
178
  });
180
- // ✅ 修复:根据实际的授权情况规划 nonce
179
+ // ✅ 获取贿赂金额
180
+ const bribeAmount = getBribeAmount(config);
181
+ const needBribeTx = bribeAmount > 0n;
182
+ // ✅ 修复:根据实际的授权情况规划 nonce(包含贿赂交易)
181
183
  const noncePlan = await planNonces({
182
184
  buyer,
183
185
  seller,
184
186
  approvalExists: approvalTx !== null, // ✅ 使用实际值
185
187
  extractProfit: true,
188
+ needBribeTx, // ✅ 新增:是否需要贿赂交易
186
189
  sameAddress,
187
190
  nonceManager
188
191
  });
@@ -216,21 +219,38 @@ export async function flapBundleBuyFirstMerkle(params) {
216
219
  txType,
217
220
  value: 0n // ✅ 卖出交易不发送原生代币
218
221
  });
219
- // ✅ 并行签名所有交易
220
- const [signedBuy, signedSell, profitTx] = await Promise.all([
221
- buyer.signTransaction(buyTx),
222
- seller.signTransaction(sellTx),
223
- buildProfitTransaction({
224
- seller,
225
- profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
226
- profitNonce: noncePlan.profitNonce,
222
+ // ✅ 贿赂交易放在首位
223
+ let bribeTx = null;
224
+ if (needBribeTx && noncePlan.bribeNonce !== undefined) {
225
+ bribeTx = await seller.signTransaction({
226
+ to: BLOCKRAZOR_BUILDER_EOA,
227
+ value: bribeAmount,
228
+ nonce: noncePlan.bribeNonce,
227
229
  gasPrice,
230
+ gasLimit: 21000n,
228
231
  chainId: chainContext.chainId,
229
- txType
230
- })
232
+ type: txType
233
+ });
234
+ }
235
+ // ✅ 并行签名买入和卖出交易
236
+ const [signedBuy, signedSell] = await Promise.all([
237
+ buyer.signTransaction(buyTx),
238
+ seller.signTransaction(sellTx)
231
239
  ]);
240
+ // ✅ 利润交易放在末尾
241
+ const profitTx = await buildProfitTransaction({
242
+ seller,
243
+ profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
244
+ profitNonce: noncePlan.profitNonce,
245
+ gasPrice,
246
+ chainId: chainContext.chainId,
247
+ txType
248
+ });
232
249
  nonceManager.clearTemp();
250
+ // ✅ 组装顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
233
251
  const allTransactions = [];
252
+ if (bribeTx)
253
+ allTransactions.push(bribeTx);
234
254
  if (approvalTx)
235
255
  allTransactions.push(approvalTx);
236
256
  allTransactions.push(signedBuy, signedSell);
@@ -300,35 +320,31 @@ async function calculateBuyerFunds({ buyer, buyerFunds, buyerFundsPercentage, re
300
320
  }
301
321
  return { buyerFundsWei, buyerBalance };
302
322
  }
303
- async function quoteBuyerOutput({ portalAddress, tokenAddress, buyerFundsWei, slippageBps, provider, skipQuoteOnError, inputToken = ZERO_ADDRESS // ✅ 默认使用原生代币
323
+ async function quoteBuyerOutput({ portalAddress, tokenAddress, buyerFundsWei, provider, skipQuoteOnError, inputToken = ZERO_ADDRESS // ✅ 默认使用原生代币
304
324
  }) {
305
325
  let quotedToken = 0n;
306
- let minOutToken = 0n;
307
326
  const portal = new Contract(portalAddress, PORTAL_ABI, provider);
308
- const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
309
327
  try {
310
328
  quotedToken = await portal.quoteExactInput.staticCall({
311
329
  inputToken, // ✅ 使用动态输入代币
312
330
  outputToken: tokenAddress,
313
331
  inputAmount: buyerFundsWei
314
332
  });
315
- const keep = BigInt(10000 - safeSlippage);
316
- minOutToken = (quotedToken * keep) / 10000n;
317
333
  }
318
334
  catch (error) {
319
335
  if (skipQuoteOnError ?? true) {
320
336
  quotedToken = 0n;
321
- minOutToken = 0n;
322
337
  }
323
338
  else {
324
339
  throw new Error(`买入报价失败: ${error}`);
325
340
  }
326
341
  }
327
- const sellAmountWei = minOutToken > 0n ? minOutToken : quotedToken;
342
+ // 已移除滑点保护:minOutToken 固定为 0
343
+ const sellAmountWei = quotedToken;
328
344
  if (sellAmountWei <= 0n) {
329
- throw new Error('卖方卖出数量为 0:报价失败或滑点过高');
345
+ throw new Error('卖方卖出数量为 0:报价失败');
330
346
  }
331
- return { quotedToken, minOutToken, sellAmountWei };
347
+ return { quotedToken, minOutToken: 0n, sellAmountWei };
332
348
  }
333
349
  async function ensureSellerBalance({ tokenAddress, provider, seller, sellAmountWei, skipBalanceCheck }) {
334
350
  const erc20 = new Contract(tokenAddress, ERC20_BALANCE_ABI, provider);
@@ -400,35 +416,38 @@ async function validateNativeBalances({ sameAddress, buyerBalance, buyerFundsWei
400
416
  }
401
417
  /**
402
418
  * ✅ 优化:使用批量 nonce 获取
419
+ * 交易顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
403
420
  */
404
- async function planNonces({ buyer, seller, approvalExists, extractProfit, sameAddress, nonceManager }) {
421
+ async function planNonces({ buyer, seller, approvalExists, extractProfit, needBribeTx, sameAddress, nonceManager }) {
405
422
  if (sameAddress) {
406
423
  // 同一地址:使用 getNextNonceBatch 获取连续 nonce
407
- const txCount = countTruthy([approvalExists, true, true, extractProfit]);
424
+ const txCount = countTruthy([needBribeTx, approvalExists, true, true, extractProfit]);
408
425
  const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
409
426
  let idx = 0;
427
+ const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
410
428
  if (approvalExists)
411
429
  idx++;
412
430
  const buyerNonce = nonces[idx++];
413
431
  const sellerNonce = nonces[idx++];
414
432
  const profitNonce = extractProfit ? nonces[idx] : undefined;
415
- return { buyerNonce, sellerNonce, profitNonce };
433
+ return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
416
434
  }
417
- if (approvalExists || extractProfit) {
418
- // 卖方需要多个 nonce:使用 getNextNonceBatch
419
- const sellerTxCount = countTruthy([approvalExists, true, extractProfit]);
435
+ if (needBribeTx || approvalExists || extractProfit) {
436
+ // 卖方需要多个 nonce:贿赂(可选) + 授权(可选) + 卖出 + 利润(可选)
437
+ const sellerTxCount = countTruthy([needBribeTx, approvalExists, true, extractProfit]);
420
438
  // ✅ 优化:并行获取 buyer 和 seller 的 nonce(JSON-RPC 批量请求)
421
439
  const [sellerNonces, buyerNonces] = await Promise.all([
422
440
  nonceManager.getNextNonceBatch(seller, sellerTxCount),
423
441
  nonceManager.getNextNoncesForWallets([buyer])
424
442
  ]);
425
443
  let idx = 0;
444
+ const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
426
445
  if (approvalExists)
427
446
  idx++;
428
447
  const sellerNonce = sellerNonces[idx++];
429
448
  const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
430
449
  const buyerNonce = buyerNonces[0];
431
- return { buyerNonce, sellerNonce, profitNonce };
450
+ return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
432
451
  }
433
452
  // ✅ 优化:使用 getNextNoncesForWallets 批量获取(单次网络往返)
434
453
  const nonces = await nonceManager.getNextNoncesForWallets([buyer, seller]);
@@ -13,7 +13,6 @@ export interface FlapSwapSignConfig {
13
13
  txType?: 0 | 2;
14
14
  chainId?: number;
15
15
  reserveGasETH?: number;
16
- slippageBps?: number;
17
16
  skipQuoteOnError?: boolean;
18
17
  skipApprovalCheck?: boolean;
19
18
  }
@@ -23,7 +22,6 @@ export interface FlapSwapConfig extends CommonBundleConfig {
23
22
  customRpcUrl?: string;
24
23
  bundleBlockOffset?: number;
25
24
  reserveGasETH?: number;
26
- slippageBps?: number;
27
25
  skipQuoteOnError?: boolean;
28
26
  waitForConfirmation?: boolean;
29
27
  waitTimeoutMs?: number;