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
@@ -8,8 +8,8 @@ export interface PancakeSwapSignConfig {
8
8
  txType?: 0 | 2;
9
9
  chainId?: number;
10
10
  reserveGasBNB?: number;
11
- slippageTolerance?: number;
12
11
  skipApprovalCheck?: boolean;
12
+ bribeAmount?: number;
13
13
  }
14
14
  export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
15
15
  export interface PancakeSwapConfig extends CommonBundleConfig {
@@ -46,7 +46,6 @@ export interface PancakeBundleSwapSignParams {
46
46
  buyerPrivateKey: string;
47
47
  tokenAddress: string;
48
48
  routeParams: RouteParams;
49
- slippageTolerance?: number;
50
49
  config: PancakeSwapSignConfig;
51
50
  quoteToken?: string;
52
51
  quoteTokenDecimals?: number;
@@ -58,7 +57,6 @@ export interface PancakeBundleSwapParams {
58
57
  buyerPrivateKey: string;
59
58
  tokenAddress: string;
60
59
  routeParams: RouteParams;
61
- slippageTolerance?: number;
62
60
  config: PancakeSwapConfig;
63
61
  }
64
62
  /** ✅ Pancake Swap 结果(简化版) */
@@ -90,7 +88,6 @@ export interface PancakeBatchSwapSignParams {
90
88
  buyerRatios?: number[];
91
89
  tokenAddress: string;
92
90
  routeParams: RouteParams;
93
- slippageTolerance?: number;
94
91
  config: PancakeSwapSignConfig;
95
92
  quoteToken?: string;
96
93
  quoteTokenDecimals?: number;
@@ -99,9 +99,10 @@ async function buildSwapTransactions({ routeParams, sellAmountWei, buyAmountBNB,
99
99
  );
100
100
  return { sellUnsigned, buyUnsigned };
101
101
  }
102
- async function calculateBuyerBudget({ buyer, quotedBNBOut, reserveGasBNB, slippageTolerance, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
102
+ async function calculateBuyerBudget({ buyer, quotedBNBOut, reserveGasBNB, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
103
103
  const reserveGas = ethers.parseEther((reserveGasBNB ?? 0.0005).toString());
104
- const buyAmountBNB = applySlippage(quotedBNBOut, slippageTolerance);
104
+ // 已移除滑点保护:直接使用报价金额
105
+ const buyAmountBNB = quotedBNBOut;
105
106
  // ✅ 根据是否使用原生代币获取不同的余额
106
107
  let buyerBalance;
107
108
  if (useNativeToken) {
@@ -128,31 +129,46 @@ async function calculateBuyerBudget({ buyer, quotedBNBOut, reserveGasBNB, slippa
128
129
  return { buyerBalance, reserveGas, requiredBalance, buyAmountBNB, useNativeToken };
129
130
  }
130
131
  }
131
- function applySlippage(amount, tolerancePercent = 0.5) {
132
- if (amount === 0n) {
133
- return 0n;
134
- }
135
- const bps = BigInt(Math.round(Math.max(0, tolerancePercent) * 100));
136
- return (amount * (10000n + bps)) / 10000n;
137
- }
138
- async function planNonces({ seller, buyer, sameAddress, approvalExists, profitNeeded, nonceManager }) {
132
+ /**
133
+ * 规划 nonce
134
+ * 交易顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
135
+ * 贿赂和利润由卖方发送
136
+ */
137
+ async function planNonces({ seller, buyer, sameAddress, approvalExists, profitNeeded, needBribeTx, nonceManager }) {
139
138
  if (sameAddress) {
140
- const txCount = countTruthy([approvalExists, true, true, profitNeeded]);
139
+ // 同一地址:贿赂(可选) + 授权(可选) + 卖出 + 买入 + 利润(可选)
140
+ const txCount = countTruthy([needBribeTx, approvalExists, true, true, profitNeeded]);
141
141
  const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
142
142
  let idx = 0;
143
+ const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
143
144
  if (approvalExists)
144
145
  idx++;
145
- const buyerNonce = nonces[idx++];
146
146
  const sellerNonce = nonces[idx++];
147
+ const buyerNonce = nonces[idx++];
147
148
  const profitNonce = profitNeeded ? nonces[idx] : undefined;
148
- return { sellerNonce, buyerNonce, profitNonce };
149
+ return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
149
150
  }
150
- const sellerNonce = await nonceManager.getNextNonce(seller);
151
- if (profitNeeded) {
152
- const [buyerNonce, profitNonce] = await nonceManager.getNextNonceBatch(buyer, 2);
153
- return { sellerNonce, buyerNonce, profitNonce };
151
+ if (needBribeTx || approvalExists || profitNeeded) {
152
+ // 卖方需要多个 nonce:贿赂(可选) + 授权(可选) + 卖出 + 利润(可选)
153
+ const sellerTxCount = countTruthy([needBribeTx, approvalExists, true, profitNeeded]);
154
+ // 并行获取 seller buyer 的 nonce
155
+ const [sellerNonces, buyerNonce] = await Promise.all([
156
+ nonceManager.getNextNonceBatch(seller, sellerTxCount),
157
+ nonceManager.getNextNonce(buyer)
158
+ ]);
159
+ let idx = 0;
160
+ const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
161
+ if (approvalExists)
162
+ idx++;
163
+ const sellerNonce = sellerNonces[idx++];
164
+ const profitNonce = profitNeeded ? sellerNonces[idx] : undefined;
165
+ return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
154
166
  }
155
- const buyerNonce = await nonceManager.getNextNonce(buyer);
167
+ // 并行获取 seller buyer 的 nonce
168
+ const [sellerNonce, buyerNonce] = await Promise.all([
169
+ nonceManager.getNextNonce(seller),
170
+ nonceManager.getNextNonce(buyer)
171
+ ]);
156
172
  return { sellerNonce, buyerNonce };
157
173
  }
158
174
  async function buildProfitTransaction({ wallet, profitAmount, profitNonce, gasPrice, chainId, txType }) {
@@ -224,6 +240,9 @@ import { ethers, Contract, Wallet } from 'ethers';
224
240
  import { calculateSellAmount } from '../utils/swap-helpers.js';
225
241
  import { NonceManager } from '../utils/bundle-helpers.js';
226
242
  import { ADDRESSES, PROFIT_CONFIG } from '../utils/constants.js';
243
+ // ✅ BlockRazor Builder EOA 地址(用于贿赂)
244
+ // 参考文档: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
245
+ const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
227
246
  /**
228
247
  * 获取 Gas Limit
229
248
  */
@@ -285,7 +304,7 @@ const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256
285
304
  * ✅ 支持 quoteToken:传入 USDT 等地址时,卖出得到该代币,买入使用该代币
286
305
  */
287
306
  export async function pancakeBundleSwapMerkle(params) {
288
- const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, routeParams, slippageTolerance = 0.5, config, quoteToken, quoteTokenDecimals = 18 } = params;
307
+ const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18 } = params;
289
308
  // ✅ 判断是否使用原生代币(BNB)或 ERC20 代币(如 USDT)
290
309
  const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
291
310
  const context = createPancakeContext(config);
@@ -319,7 +338,6 @@ export async function pancakeBundleSwapMerkle(params) {
319
338
  buyer,
320
339
  quotedBNBOut: quoteResult.estimatedBNBOut,
321
340
  reserveGasBNB: config.reserveGasBNB,
322
- slippageTolerance,
323
341
  useNativeToken,
324
342
  quoteToken,
325
343
  quoteTokenDecimals,
@@ -335,6 +353,11 @@ export async function pancakeBundleSwapMerkle(params) {
335
353
  useNativeToken
336
354
  });
337
355
  const profitAmount = calculateProfitAmount(quoteResult.estimatedBNBOut);
356
+ // ✅ 获取贿赂金额
357
+ const bribeAmount = config.bribeAmount && config.bribeAmount > 0
358
+ ? ethers.parseEther(String(config.bribeAmount))
359
+ : 0n;
360
+ const needBribeTx = bribeAmount > 0n;
338
361
  // ✅ 使用共享的 NonceManager 规划 nonce(授权已消耗一个 nonce)
339
362
  const noncePlan = await planNonces({
340
363
  seller,
@@ -342,8 +365,22 @@ export async function pancakeBundleSwapMerkle(params) {
342
365
  sameAddress,
343
366
  approvalExists: !!approvalTx,
344
367
  profitNeeded: profitAmount > 0n,
368
+ needBribeTx, // ✅ 新增
345
369
  nonceManager
346
370
  });
371
+ // ✅ 贿赂交易放在首位(由卖方发送,与利润交易同一钱包)
372
+ let bribeTx = null;
373
+ if (needBribeTx && noncePlan.bribeNonce !== undefined) {
374
+ bribeTx = await seller.signTransaction({
375
+ to: BLOCKRAZOR_BUILDER_EOA,
376
+ value: bribeAmount,
377
+ nonce: noncePlan.bribeNonce,
378
+ gasPrice,
379
+ gasLimit: 21000n,
380
+ chainId: context.chainId,
381
+ type: txType
382
+ });
383
+ }
347
384
  const signedSell = await seller.signTransaction({
348
385
  ...swapUnsigned.sellUnsigned,
349
386
  from: seller.address,
@@ -362,8 +399,9 @@ export async function pancakeBundleSwapMerkle(params) {
362
399
  chainId: context.chainId,
363
400
  type: txType
364
401
  });
402
+ // ✅ 利润交易放在末尾(由卖方发送,与贿赂交易同一钱包)
365
403
  const profitTx = await buildProfitTransaction({
366
- wallet: buyer,
404
+ wallet: seller, // ✅ 改为卖方发送(与贿赂交易一致)
367
405
  profitAmount,
368
406
  profitNonce: noncePlan.profitNonce,
369
407
  gasPrice,
@@ -383,7 +421,10 @@ export async function pancakeBundleSwapMerkle(params) {
383
421
  provider: context.provider,
384
422
  buyerAddress: buyer.address
385
423
  });
424
+ // ✅ 组装顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
386
425
  const signedTransactions = [];
426
+ if (bribeTx)
427
+ signedTransactions.push(bribeTx);
387
428
  if (approvalTx)
388
429
  signedTransactions.push(approvalTx);
389
430
  signedTransactions.push(signedSell, signedBuy);
@@ -412,7 +453,7 @@ export async function pancakeBundleSwapMerkle(params) {
412
453
  * 交易顺序:[授权(可选)] → [卖出] → [买入1, 买入2, ..., 买入N] → [利润]
413
454
  */
414
455
  export async function pancakeBatchSwapMerkle(params) {
415
- const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerAmounts, tokenAddress, routeParams, slippageTolerance = 0.5, config, quoteToken, quoteTokenDecimals = 18 } = params;
456
+ const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerAmounts, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18 } = params;
416
457
  // ✅ 校验买方数量(最多 24 个)
417
458
  const MAX_BUYERS = 24;
418
459
  if (buyerPrivateKeys.length === 0) {
@@ -451,9 +492,9 @@ export async function pancakeBatchSwapMerkle(params) {
451
492
  provider: context.provider
452
493
  });
453
494
  const estimatedBNBOut = quoteResult.estimatedBNBOut;
454
- // ✅ 计算每个买方的买入金额
495
+ // ✅ 计算每个买方的买入金额(已移除滑点保护:直接使用报价金额)
455
496
  let buyAmountsWei;
456
- const totalBuyAmount = applySlippage(estimatedBNBOut, slippageTolerance);
497
+ const totalBuyAmount = estimatedBNBOut;
457
498
  if (buyerAmounts && buyerAmounts.length === buyers.length) {
458
499
  // 方式1:使用指定的买入金额(USDT)
459
500
  buyAmountsWei = buyerAmounts.map(amt => useNativeToken
@@ -531,19 +572,41 @@ export async function pancakeBatchSwapMerkle(params) {
531
572
  return await proxyBuyer.swapV3MultiHop.populateTransaction(v3LpAddresses, exactTokenOut, buyAmount, 0n, buyer.address, { value: buyValue });
532
573
  }
533
574
  }));
534
- // ✅ 规划 Nonce(并行获取所有钱包的 nonce)
535
- // 卖方: [授权(可选)] [卖出]
575
+ // ✅ 获取贿赂金额
576
+ const bribeAmount = config.bribeAmount && config.bribeAmount > 0
577
+ ? ethers.parseEther(String(config.bribeAmount))
578
+ : 0n;
579
+ // ✅ 规划 Nonce(贿赂和利润都由卖方发送)
580
+ // 卖方: [贿赂(可选)] → [授权(可选)] → [卖出] → [利润(可选)]
581
+ let bribeNonce;
582
+ let sellNonceOffset = 0;
583
+ if (bribeAmount > 0n) {
584
+ bribeNonce = await nonceManager.getNextNonce(seller);
585
+ sellNonceOffset = 1; // 卖出交易 nonce 需要偏移
586
+ }
536
587
  const sellNonce = await nonceManager.getNextNonce(seller);
537
588
  // ✅ 并行获取所有买方的 nonce
538
589
  const buyerNonces = await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
539
- // 利润交易:从第一个买方发送
590
+ // ✅ 贿赂交易放在首位(由卖方发送)
591
+ let bribeTx = null;
592
+ if (bribeAmount > 0n && bribeNonce !== undefined) {
593
+ bribeTx = await seller.signTransaction({
594
+ to: BLOCKRAZOR_BUILDER_EOA,
595
+ value: bribeAmount,
596
+ nonce: bribeNonce,
597
+ gasPrice,
598
+ gasLimit: 21000n,
599
+ chainId: context.chainId,
600
+ type: txType
601
+ });
602
+ }
603
+ // 利润交易放在末尾(由卖方发送,与贿赂交易一致)
540
604
  const profitAmount = calculateProfitAmount(estimatedBNBOut);
541
605
  let profitTx = null;
542
606
  if (profitAmount > 0n) {
543
- // 选择第一个买方作为利润支付者
544
- const profitPayer = buyers[0];
545
- const profitNonce = await nonceManager.getNextNonce(profitPayer);
546
- profitTx = await profitPayer.signTransaction({
607
+ // ✅ 利润由卖方发送(与贿赂交易同一钱包)
608
+ const profitNonce = await nonceManager.getNextNonce(seller);
609
+ profitTx = await seller.signTransaction({
547
610
  to: PROFIT_CONFIG.RECIPIENT,
548
611
  value: profitAmount,
549
612
  nonce: profitNonce,
@@ -580,14 +643,16 @@ export async function pancakeBatchSwapMerkle(params) {
580
643
  signedSellPromise,
581
644
  ...signedBuyPromises
582
645
  ]);
583
- // 4. 按顺序组装交易数组
646
+ // 4. 按顺序组装交易数组:贿赂 → 授权 → 卖出 → 买入 → 利润
584
647
  const signedTransactions = [];
648
+ if (bribeTx)
649
+ signedTransactions.push(bribeTx); // 贿赂(首位)
585
650
  if (approvalTx)
586
651
  signedTransactions.push(approvalTx); // 授权(如果有)
587
652
  signedTransactions.push(signedSell); // 卖出
588
653
  signedTransactions.push(...signedBuys); // 多个买入
589
654
  if (profitTx)
590
- signedTransactions.push(profitTx); // 利润(最后)
655
+ signedTransactions.push(profitTx); // 利润(末尾)
591
656
  return {
592
657
  signedTransactions,
593
658
  metadata: {
@@ -167,6 +167,14 @@ export type ApproveTokenBatchParams = {
167
167
  privateKeys: string[];
168
168
  tokenAddress: string;
169
169
  amounts: (bigint | 'max')[];
170
+ /** 是否只签名不提交(默认 false,直接发送交易) */
171
+ signOnly?: boolean;
172
+ /** Gas Price(可选,单位 Gwei,signOnly=true 时生效) */
173
+ gasPriceGwei?: number;
174
+ /** Gas Limit(可选,默认 100000,signOnly=true 时生效) */
175
+ gasLimit?: number;
176
+ /** 链ID(可选,默认56=BSC,signOnly=true 时生效) */
177
+ chainId?: number;
170
178
  };
171
179
  export type ApproveTokenBatchRawParams = {
172
180
  rpcUrl: string;
@@ -174,7 +182,16 @@ export type ApproveTokenBatchRawParams = {
174
182
  tokenAddress: string;
175
183
  spenderAddress: string;
176
184
  amounts: (bigint | 'max')[];
185
+ /** 是否只签名不提交(默认 false,直接发送交易) */
186
+ signOnly?: boolean;
187
+ /** Gas Price(可选,单位 Gwei,signOnly=true 时生效) */
188
+ gasPriceGwei?: number;
189
+ /** Gas Limit(可选,默认 100000,signOnly=true 时生效) */
190
+ gasLimit?: number;
191
+ /** 链ID(可选,默认56=BSC,signOnly=true 时生效) */
192
+ chainId?: number;
177
193
  };
194
+ /** signOnly=false 时的返回结果(直接发送交易) */
178
195
  export type ApproveTokenBatchResult = {
179
196
  success: boolean;
180
197
  approvedCount: number;
@@ -187,18 +204,107 @@ export type ApproveTokenBatchResult = {
187
204
  error?: string;
188
205
  }>;
189
206
  };
207
+ /** signOnly=true 时的返回结果(仅签名) */
208
+ export type ApproveTokenBatchSignResult = {
209
+ /** 需要授权的签名交易数组(已过滤掉已授权的钱包) */
210
+ signedTransactions: string[];
211
+ /** 详细结果 */
212
+ results: Array<{
213
+ owner: string;
214
+ /** 是否已授权(无需发送交易) */
215
+ alreadyApproved: boolean;
216
+ currentAllowance: bigint;
217
+ requiredAllowance: bigint;
218
+ /** 签名交易(仅当 alreadyApproved=false 时有值) */
219
+ signedTx?: string;
220
+ }>;
221
+ /** 需要授权的钱包数量 */
222
+ needApproveCount: number;
223
+ /** 已授权的钱包数量 */
224
+ alreadyApprovedCount: number;
225
+ };
190
226
  /**
191
227
  * ✅ 智能路由:批量授权 ERC20 代币(自动选择 spender,自动检查,只在不足时才发送交易)
192
228
  *
193
229
  * @param params - 批量授权参数
230
+ * @param params.signOnly - 是否只签名不提交(默认 false)
231
+ * - false: 直接发送交易并等待确认,返回 ApproveTokenBatchResult
232
+ * - true: 只签名不提交,返回 ApproveTokenBatchSignResult,前端可通过 submitBundleToBlockRazor 提交
194
233
  * @returns 批量授权结果
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * // 模式1:直接发送交易(默认)
238
+ * const result = await approveTokenBatch({
239
+ * chain: 'BSC',
240
+ * platform: 'four',
241
+ * rpcUrl: 'https://bsc-dataseed.binance.org',
242
+ * privateKeys: [key1, key2],
243
+ * tokenAddress: '0x...',
244
+ * amounts: ['max', 'max']
245
+ * });
246
+ *
247
+ * // 模式2:只签名,前端提交
248
+ * const signResult = await approveTokenBatch({
249
+ * chain: 'BSC',
250
+ * platform: 'four',
251
+ * rpcUrl: 'https://bsc-dataseed.binance.org',
252
+ * privateKeys: [key1, key2],
253
+ * tokenAddress: '0x...',
254
+ * amounts: ['max', 'max'],
255
+ * signOnly: true
256
+ * });
257
+ * // 提交到 BlockRazor
258
+ * if (signResult.signedTransactions.length > 0) {
259
+ * await submitBundleToBlockRazor(signResult.signedTransactions, { blockOffset: 10 });
260
+ * }
261
+ * ```
195
262
  */
196
- export declare function approveTokenBatch(params: ApproveTokenBatchParams): Promise<ApproveTokenBatchResult>;
263
+ export declare function approveTokenBatch(params: ApproveTokenBatchParams & {
264
+ signOnly: true;
265
+ }): Promise<ApproveTokenBatchSignResult>;
266
+ export declare function approveTokenBatch(params: ApproveTokenBatchParams & {
267
+ signOnly?: false;
268
+ }): Promise<ApproveTokenBatchResult>;
197
269
  /**
198
270
  * ✅ 底层方法:批量授权 ERC20 代币(手动指定 spender)
199
271
  * 适用于任意 spender 地址(Flap、Four、PancakeSwap V2/V3 等)
200
272
  *
201
273
  * @param params - 批量授权参数
274
+ * @param params.signOnly - 是否只签名不提交(默认 false)
275
+ * - false: 直接发送交易并等待确认,返回 ApproveTokenBatchResult
276
+ * - true: 只签名不提交,返回 ApproveTokenBatchSignResult,前端可通过 submitBundleToBlockRazor 提交
202
277
  * @returns 批量授权结果
278
+ *
279
+ * @example
280
+ * ```typescript
281
+ * // 模式1:直接发送交易(默认)
282
+ * const result = await approveTokenBatchRaw({
283
+ * rpcUrl: 'https://bsc-dataseed.binance.org',
284
+ * privateKeys: [key1, key2],
285
+ * tokenAddress: '0x...',
286
+ * spenderAddress: '0x...',
287
+ * amounts: ['max', 'max']
288
+ * });
289
+ *
290
+ * // 模式2:只签名,前端提交
291
+ * const signResult = await approveTokenBatchRaw({
292
+ * rpcUrl: 'https://bsc-dataseed.binance.org',
293
+ * privateKeys: [key1, key2],
294
+ * tokenAddress: '0x...',
295
+ * spenderAddress: '0x...',
296
+ * amounts: ['max', 'max'],
297
+ * signOnly: true
298
+ * });
299
+ * // 提交到 BlockRazor
300
+ * if (signResult.signedTransactions.length > 0) {
301
+ * await submitBundleToBlockRazor(signResult.signedTransactions, { blockOffset: 10 });
302
+ * }
303
+ * ```
203
304
  */
204
- export declare function approveTokenBatchRaw(params: ApproveTokenBatchRawParams): Promise<ApproveTokenBatchResult>;
305
+ export declare function approveTokenBatchRaw(params: ApproveTokenBatchRawParams & {
306
+ signOnly: true;
307
+ }): Promise<ApproveTokenBatchSignResult>;
308
+ export declare function approveTokenBatchRaw(params: ApproveTokenBatchRawParams & {
309
+ signOnly?: false;
310
+ }): Promise<ApproveTokenBatchResult>;
@@ -1,4 +1,4 @@
1
- import { Contract, Wallet, JsonRpcProvider } from 'ethers';
1
+ import { Contract, Wallet, JsonRpcProvider, Interface, parseUnits } from 'ethers';
2
2
  import { ADDRESSES } from './constants.js';
3
3
  const ERC20_ABI = [
4
4
  { "constant": false, "inputs": [{ "name": "spender", "type": "address" }, { "name": "value", "type": "uint256" }], "name": "approve", "outputs": [{ "name": "", "type": "bool" }], "type": "function" },
@@ -482,26 +482,13 @@ export async function checkAllowanceBatchRaw(rpcUrl, tokenAddress, ownerAddresse
482
482
  await validateContractAddress(provider, normalizedSpender, 'Spender');
483
483
  return batchCheckAllowances(provider, normalizedToken, normalizedOwners, normalizedSpender);
484
484
  }
485
- /**
486
- * ✅ 智能路由:批量授权 ERC20 代币(自动选择 spender,自动检查,只在不足时才发送交易)
487
- *
488
- * @param params - 批量授权参数
489
- * @returns 批量授权结果
490
- */
491
485
  export async function approveTokenBatch(params) {
492
- const { chain, platform, rpcUrl, privateKeys, tokenAddress, amounts } = params;
486
+ const { chain, platform, rpcUrl, privateKeys, tokenAddress, amounts, signOnly, gasPriceGwei, gasLimit, chainId } = params;
493
487
  const spenderAddress = resolveSpenderAddress(chain, platform);
494
- return approveTokenBatchRaw({ rpcUrl, privateKeys, tokenAddress, spenderAddress, amounts });
488
+ return approveTokenBatchRaw({ rpcUrl, privateKeys, tokenAddress, spenderAddress, amounts, signOnly, gasPriceGwei, gasLimit, chainId });
495
489
  }
496
- /**
497
- * ✅ 底层方法:批量授权 ERC20 代币(手动指定 spender)
498
- * 适用于任意 spender 地址(Flap、Four、PancakeSwap V2/V3 等)
499
- *
500
- * @param params - 批量授权参数
501
- * @returns 批量授权结果
502
- */
503
490
  export async function approveTokenBatchRaw(params) {
504
- const { rpcUrl, privateKeys, tokenAddress, spenderAddress, amounts } = params;
491
+ const { rpcUrl, privateKeys, tokenAddress, spenderAddress, amounts, signOnly, gasPriceGwei, gasLimit, chainId = 56 } = params;
505
492
  if (privateKeys.length === 0 || amounts.length !== privateKeys.length) {
506
493
  throw new Error('❌ 私钥数量和授权数量必须匹配');
507
494
  }
@@ -518,6 +505,67 @@ export async function approveTokenBatchRaw(params) {
518
505
  const requiredAmounts = amounts.map(amount => amount === 'max'
519
506
  ? BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
520
507
  : amount);
508
+ // ==================== signOnly=true:只签名不提交 ====================
509
+ if (signOnly) {
510
+ // ✅ 并行获取:当前授权额度 + nonces + gasPrice
511
+ const [currentAllowances, nonces, fetchedGasPrice] = await Promise.all([
512
+ batchCheckAllowances(provider, normalizedToken, ownerAddresses, normalizedSpender),
513
+ Promise.all(wallets.map(w => provider.getTransactionCount(w.address, 'latest'))),
514
+ gasPriceGwei ? Promise.resolve(parseUnits(gasPriceGwei.toString(), 'gwei')) : provider.getFeeData().then(fee => fee.gasPrice || parseUnits('3', 'gwei'))
515
+ ]);
516
+ const finalGasPrice = fetchedGasPrice;
517
+ const finalGasLimit = BigInt(gasLimit || 100000);
518
+ // ✅ ERC20 approve 函数的 ABI 编码
519
+ const erc20Interface = new Interface(ERC20_ABI);
520
+ // ✅ 并行签名所有需要授权的交易
521
+ const signPromises = wallets.map(async (wallet, i) => {
522
+ const ownerAddress = ownerAddresses[i];
523
+ const currentAllowance = currentAllowances[i];
524
+ const requiredAmount = requiredAmounts[i];
525
+ // 如果已经授权足够,跳过
526
+ if (currentAllowance >= requiredAmount) {
527
+ return {
528
+ owner: ownerAddress,
529
+ alreadyApproved: true,
530
+ currentAllowance,
531
+ requiredAllowance: requiredAmount,
532
+ signedTx: undefined
533
+ };
534
+ }
535
+ // 构建并签名交易
536
+ const txData = erc20Interface.encodeFunctionData('approve', [normalizedSpender, requiredAmount]);
537
+ const signedTx = await wallet.signTransaction({
538
+ to: normalizedToken,
539
+ data: txData,
540
+ nonce: nonces[i],
541
+ gasLimit: finalGasLimit,
542
+ gasPrice: finalGasPrice,
543
+ chainId,
544
+ type: 0 // Legacy 交易
545
+ });
546
+ return {
547
+ owner: ownerAddress,
548
+ alreadyApproved: false,
549
+ currentAllowance,
550
+ requiredAllowance: requiredAmount,
551
+ signedTx
552
+ };
553
+ });
554
+ const results = await Promise.all(signPromises);
555
+ // ✅ 提取所有签名交易(过滤掉已授权的)
556
+ const signedTransactions = results
557
+ .filter(r => !r.alreadyApproved && r.signedTx)
558
+ .map(r => r.signedTx);
559
+ const alreadyApprovedCount = results.filter(r => r.alreadyApproved).length;
560
+ const needApproveCount = results.filter(r => !r.alreadyApproved).length;
561
+ return {
562
+ signedTransactions,
563
+ results,
564
+ needApproveCount,
565
+ alreadyApprovedCount
566
+ };
567
+ }
568
+ // ==================== signOnly=false(默认):直接发送交易 ====================
521
569
  // ✅ 优化:并行检查所有钱包的授权额度
522
570
  const currentAllowances = await batchCheckAllowances(provider, normalizedToken, ownerAddresses, normalizedSpender);
523
571
  // ✅ 优化:并行发送所有需要授权的交易
package/package.json CHANGED
@@ -1,24 +1,10 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.3.91",
4
- "description": "SDK for Flap bonding curve, four.meme TokenManager, and Solana DEX",
3
+ "version": "1.3.93",
4
+ "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- },
13
- "./sol": {
14
- "types": "./dist/sol/index.d.ts",
15
- "import": "./dist/sol/index.js"
16
- },
17
- "./sol/*": {
18
- "types": "./dist/sol/*.d.ts",
19
- "import": "./dist/sol/*.js"
20
- }
21
- },
22
8
  "files": [
23
9
  "dist",
24
10
  "src/abis/*.json"
@@ -43,32 +29,11 @@
43
29
  "node": ">=18"
44
30
  },
45
31
  "dependencies": {
46
- "@metaplex-foundation/mpl-token-metadata": "^3.4.0",
47
- "@metaplex-foundation/umi": "^1.4.1",
48
- "@metaplex-foundation/umi-bundle-defaults": "^1.4.1",
49
- "@metaplex-foundation/umi-web3js-adapters": "^1.4.1",
50
- "@meteora-ag/cp-amm-sdk": "^1.2.6",
51
- "@meteora-ag/dlmm": "^1.9.0",
52
- "@meteora-ag/dynamic-amm-sdk": "^1.4.1",
53
- "@meteora-ag/dynamic-bonding-curve-sdk": "^1.4.9",
54
- "@orca-so/common-sdk": "^0.7.0",
55
- "@orca-so/whirlpools-sdk": "^0.17.0",
56
- "@pump-fun/pump-sdk": "^1.23.0",
57
- "@pump-fun/pump-swap-sdk": "^1.11.0",
58
- "@raydium-io/raydium-sdk-v2": "^0.2.30-alpha",
59
- "@solana/spl-token": "^0.4.14",
60
- "@solana/web3.js": "^1.98.4",
61
32
  "axios": "^1.12.2",
62
33
  "ethers": "^6.11.0",
63
- "pinata": "^1.10.1",
64
- "tweetnacl": "^1.0.3"
65
- },
66
- "optionalDependencies": {
67
- "@orca-so/wavebreak": "^1.1.7"
34
+ "pinata": "^1.10.1"
68
35
  },
69
36
  "devDependencies": {
70
- "@types/bn.js": "^5.2.0",
71
- "@types/bs58": "^4.0.4",
72
37
  "typescript": "^5.6.3"
73
38
  }
74
- }
39
+ }