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
@@ -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.94",
4
- "description": "SDK for Flap bonding curve, four.meme TokenManager, and Solana DEX",
3
+ "version": "1.3.95",
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
+ }