four-flap-meme-sdk 1.4.13 → 1.4.15

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.
@@ -8,7 +8,6 @@ export interface PancakeSwapSignConfig {
8
8
  txType?: 0 | 2;
9
9
  chainId?: number;
10
10
  reserveGasBNB?: number;
11
- skipApprovalCheck?: boolean;
12
11
  bribeAmount?: number;
13
12
  }
14
13
  export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
@@ -19,7 +18,6 @@ export interface PancakeSwapConfig extends CommonBundleConfig {
19
18
  reserveGasBNB?: number;
20
19
  waitForConfirmation?: boolean;
21
20
  waitTimeoutMs?: number;
22
- skipApprovalCheck?: boolean;
23
21
  }
24
22
  export interface V2RouteParams {
25
23
  routeType: 'v2';
@@ -67,7 +65,6 @@ export type PancakeSwapResult = {
67
65
  buyerAddress: string;
68
66
  sellAmount: string;
69
67
  buyAmount: string;
70
- hasApproval?: boolean;
71
68
  profitAmount?: string;
72
69
  };
73
70
  };
@@ -102,7 +99,6 @@ export interface PancakeBatchSwapResult {
102
99
  buyerAddresses: string[];
103
100
  sellAmount: string;
104
101
  buyAmounts: string[];
105
- hasApproval?: boolean;
106
102
  profitAmount?: string;
107
103
  };
108
104
  }
@@ -7,31 +7,6 @@ function createPancakeContext(config) {
7
7
  });
8
8
  return { chainId, provider };
9
9
  }
10
- async function ensureSellerApproval({ tokenAddress, seller, provider, decimals, chainId, config, nonceManager, gasPrice, txType }) {
11
- if (config.skipApprovalCheck) {
12
- return null;
13
- }
14
- const erc20 = new Contract(tokenAddress, ERC20_ALLOWANCE_ABI, provider);
15
- const currentAllowance = await erc20.allowance(seller.address, PANCAKE_PROXY_ADDRESS);
16
- // ✅ 阈值:MaxUint256 / 2,如果授权额度超过这个值,认为是"无限授权"
17
- // 这样可以检测到用户之前的 MaxUint256 授权
18
- const halfMaxUint = ethers.MaxUint256 / 2n;
19
- if (currentAllowance >= halfMaxUint) {
20
- return null;
21
- }
22
- // ✅ 使用共享的 NonceManager
23
- const approvalNonce = await nonceManager.getNextNonce(seller);
24
- return await seller.signTransaction({
25
- to: tokenAddress,
26
- data: APPROVE_INTERFACE.encodeFunctionData('approve', [PANCAKE_PROXY_ADDRESS, ethers.MaxUint256]),
27
- value: 0n,
28
- nonce: approvalNonce,
29
- gasLimit: 80000n,
30
- gasPrice,
31
- chainId,
32
- type: txType
33
- });
34
- }
35
10
  async function quoteSellOutput({ routeParams, sellAmountWei, provider }) {
36
11
  console.log(`[quoteSellOutput] 开始报价, routeType=${routeParams.routeType}, sellAmount=${sellAmountWei} wei`);
37
12
  // ==================== V2 报价 ====================
@@ -312,13 +287,6 @@ const PANCAKE_PROXY_ADDRESS = ADDRESSES.BSC.PancakeProxy;
312
287
  // 代理合约手续费
313
288
  const FLAT_FEE = 0n; // ✅ 已移除合约固定手续费
314
289
  const WBNB_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
315
- // ✅ STABLE_COINS 和 V3_FEE_TIERS 已移至 ../utils/quote-helpers.ts
316
- const ERC20_ALLOWANCE_ABI = [
317
- 'function allowance(address,address) view returns (uint256)',
318
- 'function approve(address spender,uint256 amount) returns (bool)',
319
- 'function decimals() view returns (uint8)'
320
- ];
321
- const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
322
290
  const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
323
291
  const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
324
292
  /**
@@ -343,18 +311,6 @@ export async function pancakeBundleSwapMerkle(params) {
343
311
  calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage)
344
312
  ]);
345
313
  const { amount: sellAmountWei, decimals } = sellAmountResult;
346
- // ✅ 先构建授权交易(会消耗 nonce)
347
- const approvalTx = await ensureSellerApproval({
348
- tokenAddress,
349
- seller,
350
- provider: context.provider,
351
- decimals,
352
- chainId: context.chainId,
353
- config,
354
- nonceManager, // ✅ 共享 NonceManager
355
- gasPrice,
356
- txType
357
- });
358
314
  const quoteResult = await quoteSellOutput({
359
315
  routeParams,
360
316
  sellAmountWei,
@@ -401,14 +357,14 @@ export async function pancakeBundleSwapMerkle(params) {
401
357
  ? ethers.parseEther(String(config.bribeAmount))
402
358
  : 0n;
403
359
  const needBribeTx = bribeAmount > 0n;
404
- // ✅ 使用共享的 NonceManager 规划 nonce(授权已消耗一个 nonce)
360
+ // ✅ 使用共享的 NonceManager 规划 nonce
405
361
  const noncePlan = await planNonces({
406
362
  seller,
407
363
  buyer,
408
364
  sameAddress,
409
- approvalExists: !!approvalTx,
365
+ approvalExists: false, // ✅ 已移除授权
410
366
  profitNeeded: profitAmount > 0n,
411
- needBribeTx, // ✅ 新增
367
+ needBribeTx,
412
368
  nonceManager
413
369
  });
414
370
  // ✅ 并行签名所有交易
@@ -477,12 +433,10 @@ export async function pancakeBundleSwapMerkle(params) {
477
433
  provider: context.provider,
478
434
  buyerAddress: buyer.address
479
435
  });
480
- // ✅ 组装顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
436
+ // ✅ 组装顺序:贿赂 → 卖出 → 买入 → 利润
481
437
  const signedTransactions = [];
482
438
  if (bribeTx)
483
439
  signedTransactions.push(bribeTx);
484
- if (approvalTx)
485
- signedTransactions.push(approvalTx);
486
440
  signedTransactions.push(signedSell, signedBuy);
487
441
  if (profitTx)
488
442
  signedTransactions.push(profitTx);
@@ -495,7 +449,6 @@ export async function pancakeBundleSwapMerkle(params) {
495
449
  buyAmount: useNativeToken
496
450
  ? ethers.formatEther(buyerBudget.buyAmountBNB)
497
451
  : ethers.formatUnits(buyerBudget.buyAmountBNB, quoteTokenDecimals),
498
- hasApproval: !!approvalTx,
499
452
  profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
500
453
  }
501
454
  };
@@ -532,18 +485,6 @@ export async function pancakeBatchSwapMerkle(params) {
532
485
  calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage)
533
486
  ]);
534
487
  const { amount: sellAmountWei, decimals } = sellAmountResult;
535
- // ✅ 构建授权交易(如果需要)
536
- const approvalTx = await ensureSellerApproval({
537
- tokenAddress,
538
- seller,
539
- provider: context.provider,
540
- decimals,
541
- chainId: context.chainId,
542
- config,
543
- nonceManager,
544
- gasPrice,
545
- txType
546
- });
547
488
  // ✅ 获取卖出报价
548
489
  const quoteResult = await quoteSellOutput({
549
490
  routeParams,
@@ -713,12 +654,10 @@ export async function pancakeBatchSwapMerkle(params) {
713
654
  signedSellPromise,
714
655
  ...signedBuyPromises
715
656
  ]);
716
- // 4. 按顺序组装交易数组:贿赂 → 授权 → 卖出 → 买入 → 利润
657
+ // 4. 按顺序组装交易数组:贿赂 → 卖出 → 买入 → 利润
717
658
  const signedTransactions = [];
718
659
  if (bribeTx)
719
660
  signedTransactions.push(bribeTx); // 贿赂(首位)
720
- if (approvalTx)
721
- signedTransactions.push(approvalTx); // 授权(如果有)
722
661
  signedTransactions.push(signedSell); // 卖出
723
662
  signedTransactions.push(...signedBuys); // 多个买入
724
663
  if (profitTx)
@@ -732,7 +671,6 @@ export async function pancakeBatchSwapMerkle(params) {
732
671
  buyAmounts: buyAmountsWei.map(amt => useNativeToken
733
672
  ? ethers.formatEther(amt)
734
673
  : ethers.formatUnits(amt, quoteTokenDecimals)),
735
- hasApproval: !!approvalTx,
736
674
  profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
737
675
  }
738
676
  };
@@ -755,12 +693,10 @@ export async function pancakeQuickBatchSwapMerkle(params) {
755
693
  // ✅ 判断是否使用原生代币
756
694
  const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
757
695
  const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'.toLowerCase();
758
- // ✅ 校验买方数量
696
+ // ✅ 校验买方数量(子钱包已预留 BNB,不需要主钱包转 Gas)
759
697
  // BNB 模式:贿赂(1) + 卖出(1) + 转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
760
- // ERC20 模式:贿赂(1) + 卖出(1) + ERC20转账(N) + BNB Gas转账(N) + 买入(N) + 利润(1) ≤ 50 → 3N + 3 ≤ 50 → N ≤ 15
761
- const MAX_BUYERS_NATIVE = 23;
762
- const MAX_BUYERS_ERC20 = 15;
763
- const MAX_BUYERS = useNativeToken ? MAX_BUYERS_NATIVE : MAX_BUYERS_ERC20;
698
+ // ERC20 模式:贿赂(1) + 卖出(1) + ERC20转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
699
+ const MAX_BUYERS = 23;
764
700
  if (buyerPrivateKeys.length === 0) {
765
701
  throw new Error('至少需要一个买方钱包');
766
702
  }
@@ -895,12 +831,10 @@ export async function pancakeQuickBatchSwapMerkle(params) {
895
831
  sellerRequired = bribeAmount + sellerGasCost;
896
832
  }
897
833
  else {
898
- // ERC20 模式:
899
- // - 贿赂(21000) + 卖出(gasLimit) + N个ERC20转账(65000 each) + N个BNB Gas转账(21000 each) + 利润(21000)
900
- // - 还需要给买家转 BNB 用于支付 FLAT_FEE 和买入 Gas
901
- sellerGasCost = gasPrice * (21000n + finalGasLimit + (ERC20_TRANSFER_GAS + 21000n) * BigInt(buyers.length) + 21000n);
902
- const buyerGasNeeded = (gasPrice * finalGasLimit + FLAT_FEE) * BigInt(buyers.length);
903
- sellerRequired = bribeAmount + sellerGasCost + buyerGasNeeded;
834
+ // ERC20 模式:子钱包已预留 BNB,不需要主钱包转 Gas
835
+ // 卖方 Gas: 贿赂(21000) + 卖出(gasLimit) + N个ERC20转账(65000 each) + 利润(21000)
836
+ sellerGasCost = gasPrice * (21000n + finalGasLimit + ERC20_TRANSFER_GAS * BigInt(buyers.length) + 21000n);
837
+ sellerRequired = bribeAmount + sellerGasCost;
904
838
  }
905
839
  if (sellerBalance < sellerRequired) {
906
840
  throw new Error(`主钱包 BNB 余额不足: 需要约 ${ethers.formatEther(sellerRequired)} BNB (贿赂: ${ethers.formatEther(bribeAmount)}, Gas: ${ethers.formatEther(sellerGasCost)}), 实际 ${ethers.formatEther(sellerBalance)} BNB`);
@@ -967,7 +901,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
967
901
  }
968
902
  }
969
903
  else {
970
- // ✅ ERC20 模式:ERC20 transfer 调用
904
+ // ✅ ERC20 模式:ERC20 transfer 调用(子钱包已预留 BNB,不需要转 Gas)
971
905
  const erc20Interface = new ethers.Interface([
972
906
  'function transfer(address to, uint256 amount) returns (bool)'
973
907
  ]);
@@ -988,20 +922,6 @@ export async function pancakeQuickBatchSwapMerkle(params) {
988
922
  });
989
923
  transferTxs.push(transferTx);
990
924
  }
991
- // ERC20 模式:额外转账 Gas 费用给买家(用于支付 FLAT_FEE 和买入 Gas)
992
- for (let i = 0; i < buyers.length; i++) {
993
- const buyerGasCost = gasPrice * finalGasLimit + FLAT_FEE;
994
- const gasTx = await seller.signTransaction({
995
- to: buyers[i].address,
996
- value: buyerGasCost,
997
- nonce: sellerNonce++,
998
- gasPrice,
999
- gasLimit: 21000n,
1000
- chainId: context.chainId,
1001
- type: txType
1002
- });
1003
- transferTxs.push(gasTx);
1004
- }
1005
925
  }
1006
926
  console.log(`[pancakeQuickBatchSwapMerkle] ${transferTxs.length} 笔转账交易已签名`);
1007
927
  // ==================== 4. 买入交易 ====================
@@ -1010,7 +930,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
1010
930
  const buyAmount = transferAmountsWei[i];
1011
931
  const proxyBuyer = new Contract(PANCAKE_PROXY_ADDRESS, PANCAKE_PROXY_ABI, buyer);
1012
932
  // BNB 模式:value = buyAmount + FLAT_FEE
1013
- // ERC20 模式:value = FLAT_FEE(买入金额是 ERC20,通过授权支付)
933
+ // ERC20 模式:value = FLAT_FEE(买入金额通过授权支付)
1014
934
  const buyValue = useNativeToken ? buyAmount + FLAT_FEE : FLAT_FEE;
1015
935
  let buyUnsigned;
1016
936
  if (routeParams.routeType === 'v2') {
@@ -1053,6 +973,8 @@ export async function pancakeQuickBatchSwapMerkle(params) {
1053
973
  }
1054
974
  nonceManager.clearTemp();
1055
975
  // ==================== 组装交易数组 ====================
976
+ // BNB 模式:贿赂 → 卖出 → 转账 → 买入 → 利润
977
+ // ERC20 模式:贿赂 → 卖出 → ERC20转账 → BNB Gas转账 → 买入 → 利润
1056
978
  const signedTransactions = [];
1057
979
  if (bribeTx)
1058
980
  signedTransactions.push(bribeTx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.13",
3
+ "version": "1.4.15",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",