four-flap-meme-sdk 1.3.91 → 1.3.93

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 +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/pancake-proxy.js +103 -54
  6. package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +0 -1
  7. package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +36 -6
  8. package/dist/contracts/tm-bundle-merkle/swap.d.ts +0 -3
  9. package/dist/contracts/tm-bundle-merkle/swap.js +59 -6
  10. package/dist/flap/portal-bundle-merkle/config.d.ts +8 -0
  11. package/dist/flap/portal-bundle-merkle/config.js +17 -0
  12. package/dist/flap/portal-bundle-merkle/core.js +120 -68
  13. package/dist/flap/portal-bundle-merkle/encryption.d.ts +16 -0
  14. package/dist/flap/portal-bundle-merkle/encryption.js +146 -0
  15. package/dist/flap/portal-bundle-merkle/pancake-proxy.js +136 -78
  16. package/dist/flap/portal-bundle-merkle/swap-buy-first.d.ts +0 -2
  17. package/dist/flap/portal-bundle-merkle/swap-buy-first.js +49 -30
  18. package/dist/flap/portal-bundle-merkle/swap.d.ts +0 -2
  19. package/dist/flap/portal-bundle-merkle/swap.js +75 -47
  20. package/dist/flap/portal-bundle-merkle/types.d.ts +1 -0
  21. package/dist/index.d.ts +1 -2
  22. package/dist/index.js +0 -1
  23. package/dist/pancake/bundle-buy-first.d.ts +1 -1
  24. package/dist/pancake/bundle-buy-first.js +49 -17
  25. package/dist/pancake/bundle-swap.d.ts +1 -4
  26. package/dist/pancake/bundle-swap.js +98 -33
  27. package/dist/utils/erc20.d.ts +108 -2
  28. package/dist/utils/erc20.js +65 -17
  29. package/package.json +4 -39
  30. package/dist/sol/constants.d.ts +0 -126
  31. package/dist/sol/constants.js +0 -145
  32. package/dist/sol/dex/index.d.ts +0 -8
  33. package/dist/sol/dex/index.js +0 -12
  34. package/dist/sol/dex/meteora/client.d.ts +0 -76
  35. package/dist/sol/dex/meteora/client.js +0 -219
  36. package/dist/sol/dex/meteora/damm-v1-bundle.d.ts +0 -61
  37. package/dist/sol/dex/meteora/damm-v1-bundle.js +0 -112
  38. package/dist/sol/dex/meteora/damm-v1.d.ts +0 -118
  39. package/dist/sol/dex/meteora/damm-v1.js +0 -315
  40. package/dist/sol/dex/meteora/damm-v2-bundle.d.ts +0 -82
  41. package/dist/sol/dex/meteora/damm-v2-bundle.js +0 -242
  42. package/dist/sol/dex/meteora/damm-v2.d.ts +0 -172
  43. package/dist/sol/dex/meteora/damm-v2.js +0 -632
  44. package/dist/sol/dex/meteora/dbc-bundle.d.ts +0 -123
  45. package/dist/sol/dex/meteora/dbc-bundle.js +0 -304
  46. package/dist/sol/dex/meteora/dbc.d.ts +0 -192
  47. package/dist/sol/dex/meteora/dbc.js +0 -619
  48. package/dist/sol/dex/meteora/dlmm-bundle.d.ts +0 -39
  49. package/dist/sol/dex/meteora/dlmm-bundle.js +0 -189
  50. package/dist/sol/dex/meteora/dlmm.d.ts +0 -146
  51. package/dist/sol/dex/meteora/dlmm.js +0 -593
  52. package/dist/sol/dex/meteora/index.d.ts +0 -25
  53. package/dist/sol/dex/meteora/index.js +0 -65
  54. package/dist/sol/dex/meteora/types.d.ts +0 -787
  55. package/dist/sol/dex/meteora/types.js +0 -110
  56. package/dist/sol/dex/orca/index.d.ts +0 -10
  57. package/dist/sol/dex/orca/index.js +0 -16
  58. package/dist/sol/dex/orca/orca-bundle.d.ts +0 -41
  59. package/dist/sol/dex/orca/orca-bundle.js +0 -173
  60. package/dist/sol/dex/orca/orca.d.ts +0 -65
  61. package/dist/sol/dex/orca/orca.js +0 -474
  62. package/dist/sol/dex/orca/types.d.ts +0 -263
  63. package/dist/sol/dex/orca/types.js +0 -38
  64. package/dist/sol/dex/orca/wavebreak-bundle.d.ts +0 -34
  65. package/dist/sol/dex/orca/wavebreak-bundle.js +0 -198
  66. package/dist/sol/dex/orca/wavebreak-types.d.ts +0 -227
  67. package/dist/sol/dex/orca/wavebreak-types.js +0 -23
  68. package/dist/sol/dex/orca/wavebreak.d.ts +0 -78
  69. package/dist/sol/dex/orca/wavebreak.js +0 -497
  70. package/dist/sol/dex/pump/index.d.ts +0 -9
  71. package/dist/sol/dex/pump/index.js +0 -14
  72. package/dist/sol/dex/pump/pump-bundle.d.ts +0 -92
  73. package/dist/sol/dex/pump/pump-bundle.js +0 -383
  74. package/dist/sol/dex/pump/pump-swap-bundle.d.ts +0 -103
  75. package/dist/sol/dex/pump/pump-swap-bundle.js +0 -380
  76. package/dist/sol/dex/pump/pump-swap.d.ts +0 -46
  77. package/dist/sol/dex/pump/pump-swap.js +0 -199
  78. package/dist/sol/dex/pump/pump.d.ts +0 -35
  79. package/dist/sol/dex/pump/pump.js +0 -352
  80. package/dist/sol/dex/pump/types.d.ts +0 -215
  81. package/dist/sol/dex/pump/types.js +0 -5
  82. package/dist/sol/dex/raydium/index.d.ts +0 -8
  83. package/dist/sol/dex/raydium/index.js +0 -12
  84. package/dist/sol/dex/raydium/launchlab.d.ts +0 -68
  85. package/dist/sol/dex/raydium/launchlab.js +0 -210
  86. package/dist/sol/dex/raydium/raydium-bundle.d.ts +0 -64
  87. package/dist/sol/dex/raydium/raydium-bundle.js +0 -324
  88. package/dist/sol/dex/raydium/raydium.d.ts +0 -40
  89. package/dist/sol/dex/raydium/raydium.js +0 -366
  90. package/dist/sol/dex/raydium/types.d.ts +0 -240
  91. package/dist/sol/dex/raydium/types.js +0 -5
  92. package/dist/sol/index.d.ts +0 -10
  93. package/dist/sol/index.js +0 -16
  94. package/dist/sol/jito/bundle.d.ts +0 -90
  95. package/dist/sol/jito/bundle.js +0 -263
  96. package/dist/sol/jito/index.d.ts +0 -7
  97. package/dist/sol/jito/index.js +0 -7
  98. package/dist/sol/jito/tip.d.ts +0 -51
  99. package/dist/sol/jito/tip.js +0 -83
  100. package/dist/sol/jito/types.d.ts +0 -100
  101. package/dist/sol/jito/types.js +0 -5
  102. package/dist/sol/token/create-complete.d.ts +0 -115
  103. package/dist/sol/token/create-complete.js +0 -235
  104. package/dist/sol/token/create-token.d.ts +0 -57
  105. package/dist/sol/token/create-token.js +0 -230
  106. package/dist/sol/token/index.d.ts +0 -9
  107. package/dist/sol/token/index.js +0 -14
  108. package/dist/sol/token/metadata-upload.d.ts +0 -86
  109. package/dist/sol/token/metadata-upload.js +0 -173
  110. package/dist/sol/token/metadata.d.ts +0 -92
  111. package/dist/sol/token/metadata.js +0 -274
  112. package/dist/sol/token/types.d.ts +0 -153
  113. package/dist/sol/token/types.js +0 -5
  114. package/dist/sol/types.d.ts +0 -176
  115. package/dist/sol/types.js +0 -7
  116. package/dist/sol/utils/balance.d.ts +0 -160
  117. package/dist/sol/utils/balance.js +0 -638
  118. package/dist/sol/utils/connection.d.ts +0 -78
  119. package/dist/sol/utils/connection.js +0 -168
  120. package/dist/sol/utils/index.d.ts +0 -9
  121. package/dist/sol/utils/index.js +0 -9
  122. package/dist/sol/utils/lp-inspect.d.ts +0 -129
  123. package/dist/sol/utils/lp-inspect.js +0 -529
  124. package/dist/sol/utils/transfer.d.ts +0 -125
  125. package/dist/sol/utils/transfer.js +0 -220
  126. package/dist/sol/utils/wallet.d.ts +0 -107
  127. package/dist/sol/utils/wallet.js +0 -210
@@ -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;
@@ -8,7 +8,7 @@ import { calculateSellAmount } from '../../utils/swap-helpers.js';
8
8
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
9
9
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
10
10
  import { PROFIT_CONFIG } from '../../utils/constants.js';
11
- import { getGasPriceConfig, getTxType, getProfitRecipient } from './config.js';
11
+ import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
12
12
  /**
13
13
  * 获取 Gas Limit(支持 FlapAnyConfig)
14
14
  */
@@ -116,7 +116,7 @@ export async function flapBundleSwapMerkle(params) {
116
116
  ]);
117
117
  const { amount: sellAmountWei, decimals } = sellAmountResult;
118
118
  const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
119
- // ✅ 优化:第二批并行 - approval、quote
119
+ // ✅ 优化:第二批并行 - approval、quote(已移除滑点保护)
120
120
  const [approvalTx, quote] = await Promise.all([
121
121
  config.skipApprovalCheck
122
122
  ? Promise.resolve(null)
@@ -134,7 +134,6 @@ export async function flapBundleSwapMerkle(params) {
134
134
  tokenAddress,
135
135
  sellAmountWei,
136
136
  provider: chainContext.provider,
137
- slippageBps: config.slippageBps,
138
137
  skipQuoteOnError: config.skipQuoteOnError,
139
138
  outputToken // ✅ 传递输出代币
140
139
  })
@@ -144,7 +143,6 @@ export async function flapBundleSwapMerkle(params) {
144
143
  buyer,
145
144
  quotedNative: quote.quotedNative,
146
145
  reserveGasEth: config.reserveGasETH,
147
- slippageBps: config.slippageBps,
148
146
  nativeToken: chainContext.nativeToken,
149
147
  useNativeToken,
150
148
  quoteToken,
@@ -159,6 +157,9 @@ export async function flapBundleSwapMerkle(params) {
159
157
  // 将代币利润转换为等值 BNB
160
158
  nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, quoteToken, tokenProfitAmount, chainContext.chainId);
161
159
  }
160
+ // ✅ 获取贿赂金额
161
+ const bribeAmount = getBribeAmount(config);
162
+ const needBribeTx = bribeAmount > 0n;
162
163
  // ✅ 优化:第四批并行 - 构建交易、获取 nonces、验证余额
163
164
  const portalSeller = new Contract(chainContext.portalAddress, PORTAL_ABI, seller);
164
165
  const portalBuyer = new Contract(chainContext.portalAddress, PORTAL_ABI, buyer);
@@ -183,6 +184,7 @@ export async function flapBundleSwapMerkle(params) {
183
184
  buyer,
184
185
  approvalExists: !!approvalTx,
185
186
  extractProfit: nativeProfitAmount > 0n,
187
+ needBribeTx, // ✅ 新增:是否需要贿赂交易
186
188
  nonceManager
187
189
  }),
188
190
  validateBalances({
@@ -218,23 +220,38 @@ export async function flapBundleSwapMerkle(params) {
218
220
  txType,
219
221
  value: useNativeToken ? buyerNeed.maxBuyerValue : 0n // ✅ ERC20 购买时 value=0
220
222
  });
221
- // ✅ 优化:并行签名所有交易(包括利润交易)
222
- const signPromises = [
223
- seller.signTransaction(sellTx),
224
- buyer.signTransaction(buyTx),
225
- buildProfitTransaction({
226
- seller,
227
- profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
228
- profitNonce: noncePlan.profitNonce,
223
+ // ✅ 贿赂交易放在首位
224
+ let bribeTx = null;
225
+ if (needBribeTx && noncePlan.bribeNonce !== undefined) {
226
+ bribeTx = await seller.signTransaction({
227
+ to: BLOCKRAZOR_BUILDER_EOA,
228
+ value: bribeAmount,
229
+ nonce: noncePlan.bribeNonce,
229
230
  gasPrice,
231
+ gasLimit: 21000n,
230
232
  chainId: chainContext.chainId,
231
- txType
232
- })
233
- ];
234
- const [signedSell, signedBuy, profitTx] = await Promise.all(signPromises);
233
+ type: txType
234
+ });
235
+ }
236
+ // 并行签名卖出和买入交易
237
+ const [signedSell, signedBuy] = await Promise.all([
238
+ seller.signTransaction(sellTx),
239
+ buyer.signTransaction(buyTx)
240
+ ]);
241
+ // ✅ 利润交易放在末尾
242
+ const profitTx = await buildProfitTransaction({
243
+ seller,
244
+ profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
245
+ profitNonce: noncePlan.profitNonce,
246
+ gasPrice,
247
+ chainId: chainContext.chainId,
248
+ txType
249
+ });
235
250
  nonceManager.clearTemp();
236
- // 组装交易列表
251
+ // ✅ 组装顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
237
252
  const allTransactions = [];
253
+ if (bribeTx)
254
+ allTransactions.push(bribeTx);
238
255
  if (approvalTx)
239
256
  allTransactions.push(approvalTx);
240
257
  allTransactions.push(signedSell, signedBuy);
@@ -301,32 +318,28 @@ async function buildApprovalTransaction({ tokenAddress, seller, provider, decima
301
318
  type: txType
302
319
  });
303
320
  }
304
- async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, provider, slippageBps, skipQuoteOnError, outputToken = ZERO_ADDRESS // ✅ 默认使用原生代币
321
+ async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, provider, skipQuoteOnError, outputToken = ZERO_ADDRESS // ✅ 默认使用原生代币
305
322
  }) {
306
323
  const portal = new Contract(portalAddress, PORTAL_ABI, provider);
307
- const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
308
324
  try {
309
325
  const quotedNative = await portal.quoteExactInput.staticCall({
310
326
  inputToken: tokenAddress,
311
327
  outputToken, // ✅ 使用动态输出代币
312
328
  inputAmount: sellAmountWei
313
329
  });
314
- const keep = BigInt(10000 - safeSlippage);
315
- const minOutNative = (quotedNative * keep) / 10000n;
316
- return { quotedNative, minOutNative };
330
+ // 已移除滑点保护:minOutNative 固定为 0
331
+ return { quotedNative, minOutNative: 0n };
317
332
  }
318
333
  catch (err) {
319
334
  if (skipQuoteOnError ?? true) {
320
- console.warn(`⚠️ 报价失败,使用 minOut = 0: ${err}`);
321
335
  return { quotedNative: 0n, minOutNative: 0n };
322
336
  }
323
337
  throw new Error(`卖出报价失败: ${err}`);
324
338
  }
325
339
  }
326
340
  const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
327
- async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, slippageBps, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
341
+ async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
328
342
  const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
329
- const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
330
343
  // ✅ 根据是否使用原生代币获取不同的余额
331
344
  let buyerBalance;
332
345
  if (useNativeToken) {
@@ -337,11 +350,8 @@ async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, slippage
337
350
  const erc20 = new Contract(quoteToken, ERC20_BALANCE_OF_ABI, provider || buyer.provider);
338
351
  buyerBalance = await erc20.balanceOf(buyer.address);
339
352
  }
340
- let estimatedBuyerNeed = 0n;
341
- if (quotedNative > 0n) {
342
- const increase = BigInt(10000 + safeSlippage);
343
- estimatedBuyerNeed = (quotedNative * increase) / 10000n;
344
- }
353
+ // 已移除滑点保护:直接使用报价金额
354
+ const estimatedBuyerNeed = quotedNative;
345
355
  // ✅ 原生代币需要预留 Gas,ERC20 不需要
346
356
  const buyerNeedTotal = useNativeToken
347
357
  ? estimatedBuyerNeed + reserveGas
@@ -385,23 +395,25 @@ async function validateBalances({ buyerNeed, buyerAddress, portalGasCost, provid
385
395
  }
386
396
  /**
387
397
  * ✅ 优化:使用批量 nonce 获取(JSON-RPC 批量请求)
398
+ * 交易顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
388
399
  */
389
- async function planNonces({ seller, buyer, approvalExists, extractProfit, nonceManager }) {
390
- if (approvalExists || extractProfit) {
391
- // 卖方需要多个 nonce:使用 getNextNonceBatch
392
- const sellerTxCount = countTruthy([approvalExists, true, extractProfit]);
400
+ async function planNonces({ seller, buyer, approvalExists, extractProfit, needBribeTx, nonceManager }) {
401
+ if (needBribeTx || approvalExists || extractProfit) {
402
+ // 卖方需要多个 nonce:贿赂(可选) + 授权(可选) + 卖出 + 利润(可选)
403
+ const sellerTxCount = countTruthy([needBribeTx, approvalExists, true, extractProfit]);
393
404
  // ✅ 优化:并行获取 seller 和 buyer 的 nonce
394
405
  const [sellerNonces, buyerNonces] = await Promise.all([
395
406
  nonceManager.getNextNonceBatch(seller, sellerTxCount),
396
407
  nonceManager.getNextNoncesForWallets([buyer])
397
408
  ]);
398
409
  let idx = 0;
410
+ const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
399
411
  if (approvalExists)
400
412
  idx++;
401
413
  const sellerNonce = sellerNonces[idx++];
402
414
  const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
403
415
  const buyerNonce = buyerNonces[0];
404
- return { sellerNonce, buyerNonce, profitNonce };
416
+ return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
405
417
  }
406
418
  // ✅ 优化:使用 getNextNoncesForWallets 批量获取(单次网络往返)
407
419
  const nonces = await nonceManager.getNextNoncesForWallets([seller, buyer]);
@@ -483,7 +495,7 @@ export async function flapBatchSwapMerkle(params) {
483
495
  ]);
484
496
  const { amount: sellAmountWei, decimals } = sellAmountResult;
485
497
  const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
486
- // ✅ 并行获取:授权、报价
498
+ // ✅ 并行获取:授权、报价(已移除滑点保护)
487
499
  const [approvalTx, quote] = await Promise.all([
488
500
  config.skipApprovalCheck
489
501
  ? Promise.resolve(null)
@@ -501,15 +513,12 @@ export async function flapBatchSwapMerkle(params) {
501
513
  tokenAddress,
502
514
  sellAmountWei,
503
515
  provider: chainContext.provider,
504
- slippageBps: config.slippageBps,
505
516
  skipQuoteOnError: config.skipQuoteOnError,
506
517
  outputToken
507
518
  })
508
519
  ]);
509
- // ✅ 计算每个买方的买入金额(按比例分配)
510
- const safeSlippage = Math.max(0, Math.min(5000, config.slippageBps ?? 100));
511
- const increase = BigInt(10000 + safeSlippage);
512
- const totalBuyAmount = (quote.quotedNative * increase) / 10000n;
520
+ // ✅ 计算每个买方的买入金额(按比例分配,已移除滑点保护)
521
+ const totalBuyAmount = quote.quotedNative;
513
522
  let buyAmountsWei;
514
523
  if (params.buyerRatios && params.buyerRatios.length === buyers.length) {
515
524
  // 按比例分配
@@ -575,12 +584,29 @@ export async function flapBatchSwapMerkle(params) {
575
584
  // ✅ 并行获取所有 nonce
576
585
  const sellNonce = await nonceManager.getNextNonce(seller);
577
586
  const buyerNonces = await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
578
- // 利润交易 nonce(从第一个买方发送)
587
+ // 贿赂交易和利润交易都由卖方发送(保持一致)
588
+ const bribeAmount = getBribeAmount(config);
589
+ let bribeTx = null;
590
+ let bribeNonceOffset = 0;
591
+ if (bribeAmount > 0n) {
592
+ const bribeNonce = sellNonce; // 使用卖方的第一个 nonce
593
+ bribeTx = await seller.signTransaction({
594
+ to: BLOCKRAZOR_BUILDER_EOA,
595
+ value: bribeAmount,
596
+ nonce: bribeNonce,
597
+ gasPrice,
598
+ gasLimit: 21000n,
599
+ chainId: chainContext.chainId,
600
+ type: txType
601
+ });
602
+ bribeNonceOffset = 1; // 卖出交易的 nonce 需要 +1
603
+ }
604
+ // 利润交易放在末尾(由卖方发送,与贿赂交易同一钱包)
579
605
  let profitTx = null;
580
606
  if (nativeProfitAmount > 0n) {
581
- const profitPayer = buyers[0];
582
- const profitNonce = await nonceManager.getNextNonce(profitPayer);
583
- profitTx = await profitPayer.signTransaction({
607
+ // 利润交易 nonce = 卖出 nonce + 1
608
+ const profitNonce = sellNonce + bribeNonceOffset + 1;
609
+ profitTx = await seller.signTransaction({
584
610
  to: getProfitRecipient(),
585
611
  value: nativeProfitAmount,
586
612
  nonce: profitNonce,
@@ -594,7 +620,7 @@ export async function flapBatchSwapMerkle(params) {
594
620
  // ✅ 并行签名所有交易
595
621
  const sellTx = buildTransactionRequest(sellUnsigned, {
596
622
  from: seller.address,
597
- nonce: sellNonce,
623
+ nonce: sellNonce + bribeNonceOffset, // ✅ 考虑贿赂交易的 nonce 偏移
598
624
  gasLimit: finalGasLimit,
599
625
  gasPrice,
600
626
  priorityFee,
@@ -618,8 +644,10 @@ export async function flapBatchSwapMerkle(params) {
618
644
  return buyer.signTransaction(buyTx);
619
645
  })
620
646
  ]);
621
- // ✅ 按顺序组装交易数组
647
+ // ✅ 按顺序组装交易数组:贿赂 → 授权 → 卖出 → 买入 → 利润
622
648
  const signedTransactions = [];
649
+ if (bribeTx)
650
+ signedTransactions.push(bribeTx);
623
651
  if (approvalTx)
624
652
  signedTransactions.push(approvalTx);
625
653
  signedTransactions.push(signedSell);
@@ -7,6 +7,7 @@ export type FlapSignConfig = {
7
7
  minGasPriceGwei?: number;
8
8
  nonces?: number[];
9
9
  gasPrice?: bigint;
10
+ bribeAmount?: number;
10
11
  };
11
12
  export type FlapBundleMerkleConfig = {
12
13
  apiKey: string;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  export * as Abis from './abis/index.js';
2
- export * as Sol from './sol/index.js';
3
2
  export { ADDRESSES, CHAIN } from './utils/constants.js';
4
3
  export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
5
- export { ensureSellApprovalV1, checkSellApprovalV1, ensureSellApprovalV2, checkSellApprovalV2, ensureSellApproval, checkSellApproval, ensureFlapSellApproval, checkFlapSellApproval, ensureFlapSellApprovalBatch, checkFlapSellApprovalBatch, checkAllowance, approveToken, checkAllowanceBatch, approveTokenBatch, checkAllowanceRaw, approveTokenRaw, checkAllowanceBatchRaw, approveTokenBatchRaw, type EnsureAllowanceBatchItemResult, type ApproveTokenBatchParams, type ApproveTokenBatchRawParams, type ApproveTokenBatchResult } from './utils/erc20.js';
4
+ export { ensureSellApprovalV1, checkSellApprovalV1, ensureSellApprovalV2, checkSellApprovalV2, ensureSellApproval, checkSellApproval, ensureFlapSellApproval, checkFlapSellApproval, ensureFlapSellApprovalBatch, checkFlapSellApprovalBatch, checkAllowance, approveToken, checkAllowanceBatch, approveTokenBatch, checkAllowanceRaw, approveTokenRaw, checkAllowanceBatchRaw, approveTokenBatchRaw, type EnsureAllowanceBatchItemResult, type ApproveTokenBatchParams, type ApproveTokenBatchRawParams, type ApproveTokenBatchResult, type ApproveTokenBatchSignResult } from './utils/erc20.js';
6
5
  export { parseFourError, type FourErrorCode } from './utils/errors.js';
7
6
  export { getTokenManagerV1, getTokenManagerV2, getTokenManagerHelper3, getTokenManagerV1Writer, getTokenManagerV2Writer, getTokenManagerHelper3Writer, getTokenManagerAddress, type ChainName } from './utils/contract-factory.js';
8
7
  export { FourClient, buildLoginMessage, type FourConfig, type GenerateNonceReq, type LoginReq, type CreateTokenReq, type CreateTokenResp } from './clients/four.js';
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * as Abis from './abis/index.js';
2
- export * as Sol from './sol/index.js';
3
2
  export { ADDRESSES, CHAIN } from './utils/constants.js';
4
3
  export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
5
4
  export {
@@ -13,9 +13,9 @@ export interface PancakeBuyFirstSignConfig {
13
13
  txType?: 0 | 2;
14
14
  chainId?: number;
15
15
  reserveGasBNB?: number;
16
- slippageBps?: number;
17
16
  skipQuoteOnError?: boolean;
18
17
  skipApprovalCheck?: boolean;
18
+ bribeAmount?: number;
19
19
  }
20
20
  export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
21
21
  export interface V2RouteParams {
@@ -6,6 +6,9 @@
6
6
  import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager } from '../utils/bundle-helpers.js';
8
8
  import { ADDRESSES, PROFIT_CONFIG } from '../utils/constants.js';
9
+ // ✅ BlockRazor Builder EOA 地址(用于贿赂)
10
+ // 参考文档: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
11
+ const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
9
12
  function getGasLimit(config, defaultGas = 800000) {
10
13
  if (config.gasLimit !== undefined) {
11
14
  return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
@@ -98,8 +101,7 @@ export async function pancakeBundleBuyFirstMerkle(params) {
98
101
  const buyerNeed = calculateBuyerNeed({
99
102
  quotedNative,
100
103
  buyerBalance: buyerFundsInfo.buyerBalance,
101
- reserveGas: buyerFundsInfo.reserveGas,
102
- slippageBps: config.slippageBps
104
+ reserveGas: buyerFundsInfo.reserveGas
103
105
  });
104
106
  const finalGasLimit = getGasLimit(config);
105
107
  const gasPrice = await getGasPrice(context.provider, config);
@@ -125,14 +127,33 @@ export async function pancakeBundleBuyFirstMerkle(params) {
125
127
  });
126
128
  const profitBase = estimatedProfitFromSell > 0n ? estimatedProfitFromSell : (buyerFundsInfo.buyerFundsWei * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
127
129
  const profitAmount = profitBase;
130
+ // ✅ 获取贿赂金额
131
+ const bribeAmount = config.bribeAmount && config.bribeAmount > 0
132
+ ? ethers.parseEther(String(config.bribeAmount))
133
+ : 0n;
134
+ const needBribeTx = bribeAmount > 0n;
128
135
  const noncePlan = await planNonces({
129
136
  buyer,
130
137
  seller,
131
138
  sameAddress,
132
139
  approvalExists: !!approvalTx,
133
140
  extractProfit: profitAmount > 0n,
141
+ needBribeTx, // ✅ 新增
134
142
  nonceManager
135
143
  });
144
+ // ✅ 贿赂交易放在首位(由卖方发送,与利润交易同一钱包)
145
+ let bribeTx = null;
146
+ if (needBribeTx && noncePlan.bribeNonce !== undefined) {
147
+ bribeTx = await seller.signTransaction({
148
+ to: BLOCKRAZOR_BUILDER_EOA,
149
+ value: bribeAmount,
150
+ nonce: noncePlan.bribeNonce,
151
+ gasPrice,
152
+ gasLimit: 21000n,
153
+ chainId: context.chainId,
154
+ type: txType
155
+ });
156
+ }
136
157
  const signedBuy = await buyer.signTransaction({
137
158
  ...swapUnsigned.buyUnsigned,
138
159
  from: buyer.address,
@@ -151,6 +172,7 @@ export async function pancakeBundleBuyFirstMerkle(params) {
151
172
  chainId: context.chainId,
152
173
  type: txType
153
174
  });
175
+ // ✅ 利润交易放在末尾
154
176
  const profitTx = await buildProfitTransaction({
155
177
  seller,
156
178
  profitAmount,
@@ -172,7 +194,10 @@ export async function pancakeBundleBuyFirstMerkle(params) {
172
194
  provider: context.provider,
173
195
  buyerAddress: buyer.address
174
196
  });
197
+ // ✅ 组装顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
175
198
  const allTransactions = [];
199
+ if (bribeTx)
200
+ allTransactions.push(bribeTx);
176
201
  if (approvalTx)
177
202
  allTransactions.push(approvalTx);
178
203
  allTransactions.push(signedBuy, signedSell);
@@ -303,13 +328,9 @@ async function quoteSellerNative({ provider, tokenAddress, sellAmountToken }) {
303
328
  return 0n;
304
329
  }
305
330
  }
306
- function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas, slippageBps }) {
307
- let estimatedBuyerNeed = 0n;
308
- if (quotedNative > 0n) {
309
- const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
310
- const increase = BigInt(10000 + safeSlippage);
311
- estimatedBuyerNeed = (quotedNative * increase) / 10000n;
312
- }
331
+ function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas }) {
332
+ // 已移除滑点保护:直接使用报价金额
333
+ const estimatedBuyerNeed = quotedNative;
313
334
  const buyerNeedTotal = estimatedBuyerNeed + reserveGas;
314
335
  if (buyerBalance < buyerNeedTotal) {
315
336
  throw new Error(`买方余额不足:\n - 需要: ${ethers.formatEther(buyerNeedTotal)} BNB\n - 实际: ${ethers.formatEther(buyerBalance)} BNB`);
@@ -381,28 +402,39 @@ async function estimateProfitAmount({ provider, tokenAddress, sellAmountToken })
381
402
  return 0n;
382
403
  }
383
404
  }
384
- async function planNonces({ buyer, seller, sameAddress, approvalExists, extractProfit, nonceManager }) {
405
+ /**
406
+ * ✅ 规划 nonce
407
+ * 交易顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
408
+ */
409
+ async function planNonces({ buyer, seller, sameAddress, approvalExists, extractProfit, needBribeTx, nonceManager }) {
385
410
  if (sameAddress) {
386
- const txCount = countTruthy([approvalExists, true, true, extractProfit]);
411
+ // 同一地址:贿赂(可选) + 授权(可选) + 买入 + 卖出 + 利润(可选)
412
+ const txCount = countTruthy([needBribeTx, approvalExists, true, true, extractProfit]);
387
413
  const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
388
414
  let idx = 0;
415
+ const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
389
416
  if (approvalExists)
390
417
  idx++;
391
418
  const buyerNonce = nonces[idx++];
392
419
  const sellerNonce = nonces[idx++];
393
420
  const profitNonce = extractProfit ? nonces[idx] : undefined;
394
- return { buyerNonce, sellerNonce, profitNonce };
421
+ return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
395
422
  }
396
- if (approvalExists || extractProfit) {
397
- const sellerTxCount = countTruthy([approvalExists, true, extractProfit]);
398
- const sellerNonces = await nonceManager.getNextNonceBatch(seller, sellerTxCount);
423
+ if (needBribeTx || approvalExists || extractProfit) {
424
+ // 卖方需要多个 nonce:贿赂(可选) + 授权(可选) + 卖出 + 利润(可选)
425
+ const sellerTxCount = countTruthy([needBribeTx, approvalExists, true, extractProfit]);
426
+ // ✅ 并行获取 seller 和 buyer 的 nonce
427
+ const [sellerNonces, buyerNonce] = await Promise.all([
428
+ nonceManager.getNextNonceBatch(seller, sellerTxCount),
429
+ nonceManager.getNextNonce(buyer)
430
+ ]);
399
431
  let idx = 0;
432
+ const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
400
433
  if (approvalExists)
401
434
  idx++;
402
435
  const sellerNonce = sellerNonces[idx++];
403
436
  const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
404
- const buyerNonce = await nonceManager.getNextNonce(buyer);
405
- return { buyerNonce, sellerNonce, profitNonce };
437
+ return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
406
438
  }
407
439
  const [buyerNonce, sellerNonce] = await Promise.all([
408
440
  nonceManager.getNextNonce(buyer),