four-flap-meme-sdk 1.4.85 → 1.4.87

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.
@@ -31,9 +31,9 @@ const MAX_SWAP_TX_COUNT = MAX_BUNDLE_SIGNATURES - BRIBE_TX_COUNT - PROFIT_TX_COU
31
31
  */
32
32
  function getProfitRatePerTxBps(userType) {
33
33
  if (userType === 'v1') {
34
- return PROFIT_CONFIG.RATE_BPS_V1;
34
+ return PROFIT_CONFIG.RATE_BPS_V1_DOUBLE;
35
35
  }
36
- return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认
36
+ return PROFIT_CONFIG.RATE_BPS_V0_DOUBLE; // v0 或默认
37
37
  }
38
38
  /**
39
39
  * 验证买卖笔数
@@ -71,9 +71,9 @@ const MAX_SWAP_TX_COUNT = MAX_BUNDLE_SIGNATURES - BRIBE_TX_COUNT - PROFIT_TX_COU
71
71
  */
72
72
  function getProfitRatePerTxBps(userType) {
73
73
  if (userType === 'v1') {
74
- return PROFIT_CONFIG.RATE_BPS_V1;
74
+ return PROFIT_CONFIG.RATE_BPS_V1_DOUBLE;
75
75
  }
76
- return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认
76
+ return PROFIT_CONFIG.RATE_BPS_V0_DOUBLE; // v0 或默认
77
77
  }
78
78
  /**
79
79
  * 验证买卖笔数
@@ -6,7 +6,7 @@
6
6
  import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../utils/bundle-helpers.js';
8
8
  import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA, ZERO_ADDRESS } from '../utils/constants.js';
9
- import { quoteV2, quoteV3, getTokenToNativeQuote, getWrappedNativeAddress } from '../utils/quote-helpers.js';
9
+ import { quoteV2, quoteV3, getTokenToNativeQuote } from '../utils/quote-helpers.js';
10
10
  import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI } from '../abis/common.js';
11
11
  /**
12
12
  * 获取 Gas Limit
@@ -57,9 +57,9 @@ const MAX_SWAP_TX_COUNT = MAX_BUNDLE_SIGNATURES - BRIBE_TX_COUNT - PROFIT_TX_COU
57
57
  */
58
58
  function getProfitRatePerTxBps(userType) {
59
59
  if (userType === 'v1') {
60
- return PROFIT_CONFIG.RATE_BPS_V1;
60
+ return PROFIT_CONFIG.RATE_BPS_V1_DOUBLE;
61
61
  }
62
- return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认
62
+ return PROFIT_CONFIG.RATE_BPS_V0_DOUBLE; // v0 或默认
63
63
  }
64
64
  /**
65
65
  * 验证买卖笔数
@@ -180,31 +180,22 @@ export async function pancakeBundleBuyFirstMerkle(params) {
180
180
  tokenAddress,
181
181
  useNativeToken
182
182
  });
183
- const quotedNative = await quoteSellerNative({
184
- provider: context.provider,
185
- tokenAddress,
186
- sellAmountToken: quoteResult.quotedTokenOut,
187
- routeParams // ✅ 传递路由参数
188
- });
189
- const buyerNeed = calculateBuyerNeed({
190
- quotedNative,
191
- buyerBalance: buyerFundsInfo.buyerBalance,
192
- reserveGas: buyerFundsInfo.reserveGas
193
- });
194
183
  const finalGasLimit = getGasLimit(config);
195
184
  const gasPrice = await getGasPrice(context.provider, config);
196
185
  const txType = config.txType ?? 0;
197
186
  const nonceManager = new NonceManager(context.provider);
198
- // ✅ 修复:基于买入金额估算利润(使用动态利润比例)
199
- const estimatedProfitFromSell = await estimateProfitAmount({
200
- provider: context.provider,
201
- tokenAddress,
202
- sellAmountToken: quoteResult.quotedTokenOut,
203
- routeParams
204
- });
205
- // 使用动态利润比例
206
- const profitBase = estimatedProfitFromSell > 0n ? estimatedProfitFromSell : buyerFundsInfo.buyerFundsWei;
207
- const profitAmount = (profitBase * BigInt(profitRateBps)) / 10000n;
187
+ // ✅ 直接使用买入金额作为利润基础(先买后卖模式)
188
+ // profitRateBps = 每笔交易利润率(bps) * 交易笔数
189
+ // 例如:v1用户,1买1卖 → 5 * 2 = 10 bps = 0.1%
190
+ const tokenProfitAmount = (buyerFundsInfo.buyerFundsWei * BigInt(profitRateBps)) / 10000n;
191
+ // ✅ ERC20 购买:将代币利润转换为等值 BNB(因为利润是用 BNB 转账的)
192
+ let profitAmount = tokenProfitAmount;
193
+ if (!useNativeToken && tokenProfitAmount > 0n && quoteToken) {
194
+ const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
195
+ const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
196
+ profitAmount = await getTokenToNativeQuote(context.provider, quoteToken, tokenProfitAmount, 'BSC', version, fee);
197
+ console.log(`[pancakeBundleBuyFirstMerkle] ERC20→BNB 利润转换: ${ethers.formatUnits(tokenProfitAmount, quoteTokenDecimals)} → ${ethers.formatEther(profitAmount)} BNB`);
198
+ }
208
199
  // ✅ 获取贿赂金额
209
200
  const bribeAmount = config.bribeAmount && config.bribeAmount > 0
210
201
  ? ethers.parseEther(String(config.bribeAmount))
@@ -406,100 +397,6 @@ async function quoteTokenOutput({ routeParams, buyerFundsWei, provider }) {
406
397
  }
407
398
  return { quotedTokenOut: result.amountOut };
408
399
  }
409
- /**
410
- * ✅ 使用 quote-helpers 统一报价(卖出 → 原生代币)
411
- */
412
- async function quoteSellerNative({ provider, tokenAddress, sellAmountToken, routeParams }) {
413
- const wbnb = getWrappedNativeAddress('BSC');
414
- const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
415
- const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
416
- return await getTokenToNativeQuote(provider, tokenAddress, sellAmountToken, 'BSC', version, fee);
417
- }
418
- function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas }) {
419
- const estimatedBuyerNeed = quotedNative;
420
- const buyerNeedTotal = estimatedBuyerNeed + reserveGas;
421
- if (buyerBalance < buyerNeedTotal) {
422
- throw new Error(`买方余额不足:\n - 需要: ${ethers.formatEther(buyerNeedTotal)} BNB\n - 实际: ${ethers.formatEther(buyerBalance)} BNB`);
423
- }
424
- const maxBuyerValue = estimatedBuyerNeed > 0n
425
- ? estimatedBuyerNeed
426
- : buyerBalance - reserveGas;
427
- return { buyerNeedTotal, maxBuyerValue };
428
- }
429
- async function buildRouteTransactions({ routeParams, buyerFundsWei, sellAmountToken, buyer, seller, tokenAddress, useNativeToken = true }) {
430
- const deadline = getDeadline();
431
- if (routeParams.routeType === 'v2') {
432
- const { v2Path } = routeParams;
433
- const reversePath = [...v2Path].reverse();
434
- // ✅ 使用官方 V2 Router
435
- const v2RouterBuyer = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, buyer);
436
- const v2RouterSeller = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, seller);
437
- if (useNativeToken) {
438
- // ✅ BNB 池子:使用 swapExactETHForTokens / swapExactTokensForETH
439
- const buyValue = buyerFundsWei + FLAT_FEE;
440
- const buyUnsigned = await v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
441
- const sellUnsigned = await v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
442
- return { buyUnsigned, sellUnsigned };
443
- }
444
- else {
445
- // ✅ ERC20 池子(如 USDT):使用 swapExactTokensForTokens
446
- const buyUnsigned = await v2RouterBuyer.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(buyerFundsWei, 0n, v2Path, buyer.address, deadline);
447
- const sellUnsigned = await v2RouterSeller.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
448
- return { buyUnsigned, sellUnsigned };
449
- }
450
- }
451
- if (routeParams.routeType === 'v3-single') {
452
- const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
453
- const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
454
- const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
455
- const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
456
- // ✅ V3 池子的处理(ERC20 模式 value = 0,因为通过代币授权支付)
457
- const buyValue = useNativeToken ? buyerFundsWei + FLAT_FEE : 0n;
458
- // 买入交易
459
- const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
460
- tokenIn: v3TokenIn,
461
- tokenOut: v3TokenOut,
462
- fee: v3Fee,
463
- recipient: buyer.address,
464
- amountIn: buyerFundsWei,
465
- amountOutMinimum: 0n,
466
- sqrtPriceLimitX96: 0n
467
- }]);
468
- const buyUnsigned = await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
469
- // 卖出交易
470
- if (useNativeToken) {
471
- // ✅ BNB 池子:卖出后 unwrap WBNB 为 BNB
472
- const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
473
- tokenIn: v3TokenOut,
474
- tokenOut: v3TokenIn,
475
- fee: v3Fee,
476
- recipient: PANCAKE_V3_ROUTER_ADDRESS,
477
- amountIn: sellAmountToken,
478
- amountOutMinimum: 0n,
479
- sqrtPriceLimitX96: 0n
480
- }]);
481
- const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
482
- const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
483
- return { buyUnsigned, sellUnsigned };
484
- }
485
- else {
486
- // ✅ ERC20 池子:卖出后直接获得 ERC20
487
- const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
488
- tokenIn: v3TokenOut,
489
- tokenOut: v3TokenIn,
490
- fee: v3Fee,
491
- recipient: seller.address, // 直接发送到卖方地址
492
- amountIn: sellAmountToken,
493
- amountOutMinimum: 0n,
494
- sqrtPriceLimitX96: 0n
495
- }]);
496
- const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData]);
497
- return { buyUnsigned, sellUnsigned };
498
- }
499
- }
500
- // V3 多跳暂不支持官方合约
501
- throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
502
- }
503
400
  /**
504
401
  * ✅ 构建多笔买入和卖出交易
505
402
  */
@@ -583,60 +480,6 @@ async function buildMultiRouteTransactions({ routeParams, buyAmountsWei, sellAmo
583
480
  }
584
481
  throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
585
482
  }
586
- /**
587
- * ✅ 使用 quote-helpers 统一报价(估算利润)
588
- */
589
- async function estimateProfitAmount({ provider, tokenAddress, sellAmountToken, routeParams }) {
590
- try {
591
- const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
592
- const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
593
- const estimatedSellFunds = await getTokenToNativeQuote(provider, tokenAddress, sellAmountToken, 'BSC', version, fee);
594
- if (estimatedSellFunds <= 0n) {
595
- return 0n;
596
- }
597
- // 万分之六
598
- return (estimatedSellFunds * BigInt(PROFIT_CONFIG.RATE_BPS_SWAP)) / 10000n;
599
- }
600
- catch {
601
- return 0n;
602
- }
603
- }
604
- /**
605
- * ✅ 规划 nonce
606
- * 交易顺序:贿赂 → 买入 → 卖出 → 利润
607
- */
608
- async function planNonces({ buyer, seller, sameAddress, extractProfit, needBribeTx, nonceManager }) {
609
- if (sameAddress) {
610
- // 同一地址:贿赂(可选) + 买入 + 卖出 + 利润(可选)
611
- const txCount = countTruthy([needBribeTx, true, true, extractProfit]);
612
- const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
613
- let idx = 0;
614
- const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
615
- const buyerNonce = nonces[idx++];
616
- const sellerNonce = nonces[idx++];
617
- const profitNonce = extractProfit ? nonces[idx] : undefined;
618
- return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
619
- }
620
- if (needBribeTx || extractProfit) {
621
- // 卖方需要多个 nonce:贿赂(可选) + 卖出 + 利润(可选)
622
- const sellerTxCount = countTruthy([needBribeTx, true, extractProfit]);
623
- // ✅ 并行获取 seller 和 buyer 的 nonce
624
- const [sellerNonces, buyerNonce] = await Promise.all([
625
- nonceManager.getNextNonceBatch(seller, sellerTxCount),
626
- nonceManager.getNextNonce(buyer)
627
- ]);
628
- let idx = 0;
629
- const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
630
- const sellerNonce = sellerNonces[idx++];
631
- const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
632
- return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
633
- }
634
- const [buyerNonce, sellerNonce] = await Promise.all([
635
- nonceManager.getNextNonce(buyer),
636
- nonceManager.getNextNonce(seller)
637
- ]);
638
- return { buyerNonce, sellerNonce };
639
- }
640
483
  /**
641
484
  * ✅ 规划多笔交易 nonce(与 Flap 一致)
642
485
  * 交易顺序:贿赂 → 买入(多笔) → 卖出(多笔) → 利润
@@ -729,33 +572,6 @@ async function validateFinalBalances({ sameAddress, buyerFundsWei, buyerBalance,
729
572
  }
730
573
  // ERC20 余额已在 calculateBuyerFunds 中检查过
731
574
  }
732
- function countTruthy(values) {
733
- return values.filter(Boolean).length;
734
- }
735
- /**
736
- * ✅ 从前端传入的 startNonces 构建 NoncePlan(用于性能优化,避免 nonce 冲突)
737
- * 顺序:同地址时 [baseNonce],不同地址时 [sellerNonce, buyerNonce]
738
- */
739
- function buildNoncePlanFromStartNonces(startNonces, sameAddress, profitNeeded, needBribeTx) {
740
- if (sameAddress) {
741
- // 同一地址:贿赂(可选) + 买入 + 卖出 + 利润(可选)
742
- let idx = 0;
743
- const baseNonce = startNonces[0];
744
- const bribeNonce = needBribeTx ? baseNonce + idx++ : undefined;
745
- const buyerNonce = baseNonce + idx++;
746
- const sellerNonce = baseNonce + idx++;
747
- const profitNonce = profitNeeded ? baseNonce + idx : undefined;
748
- return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
749
- }
750
- // 不同地址
751
- let sellerIdx = 0;
752
- const sellerBaseNonce = startNonces[0];
753
- const bribeNonce = needBribeTx ? sellerBaseNonce + sellerIdx++ : undefined;
754
- const sellerNonce = sellerBaseNonce + sellerIdx++;
755
- const profitNonce = profitNeeded ? sellerBaseNonce + sellerIdx : undefined;
756
- const buyerNonce = startNonces[1];
757
- return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
758
- }
759
575
  /**
760
576
  * ✅ 多钱包捆绑换手
761
577
  * - 多个买方钱包执行买入(每个钱包1笔)
@@ -831,15 +647,17 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
831
647
  const buyAmountsWei = splitAmount(totalFundsWei, buyCount);
832
648
  // ✅ 将代币平均分配给卖方
833
649
  const sellAmountsWei = splitAmount(quoteResult.quotedTokenOut, sellCount);
834
- // ✅ 第二批并行:估算利润(可以和交易构建并行,但需要先获取报价)
835
- const estimatedProfitFromSell = await estimateProfitAmount({
836
- provider: context.provider,
837
- tokenAddress,
838
- sellAmountToken: quoteResult.quotedTokenOut,
839
- routeParams
840
- });
841
- const profitBase = estimatedProfitFromSell > 0n ? estimatedProfitFromSell : totalFundsWei;
842
- const profitAmount = (profitBase * BigInt(profitRateBps)) / 10000n;
650
+ // ✅ 直接使用总交易金额作为利润基础(多钱包模式)
651
+ // profitRateBps = 每笔交易利润率(bps) * 交易笔数
652
+ const tokenProfitAmount = (totalFundsWei * BigInt(profitRateBps)) / 10000n;
653
+ // ✅ ERC20 购买:将代币利润转换为等值 BNB(因为利润是用 BNB 转账的)
654
+ let profitAmount = tokenProfitAmount;
655
+ if (!useNativeToken && tokenProfitAmount > 0n && quoteToken) {
656
+ const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
657
+ const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
658
+ profitAmount = await getTokenToNativeQuote(context.provider, quoteToken, tokenProfitAmount, 'BSC', version, fee);
659
+ console.log(`[pancakeBundleBuyFirstMultiWallet] ERC20→BNB 利润转换: ${ethers.formatUnits(tokenProfitAmount, quoteTokenDecimals)} → ${ethers.formatEther(profitAmount)} BNB`);
660
+ }
843
661
  // ✅ 第三批并行:构建并签名所有交易
844
662
  const allTransactions = [];
845
663
  // 1. 贿赂交易(由主卖方支付)- 先处理以确定 nonce 偏移
@@ -19,10 +19,14 @@ export declare const PROFIT_CONFIG: {
19
19
  readonly RATE_BPS: 30;
20
20
  /** 利润比例(基点):6 bps = 0.06% = 万分之六(捆绑换手模式) */
21
21
  readonly RATE_BPS_SWAP: 6;
22
- /** 利润比例(基点):6 bps = 0.06% = 万分之六(用户类型 v0) */
22
+ /** 利润比例(单边基点):6 bps = 0.06% = 万分之六(用户类型 v0) */
23
23
  readonly RATE_BPS_V0: 6;
24
- /** 利润比例(基点):5 bps = 0.05% = 万分之五(用户类型 v1) */
24
+ /** 利润比例(双边基点):3 bps = 0.03% = 千分之三(用户类型 v0) */
25
+ readonly RATE_BPS_V0_DOUBLE: 3;
26
+ /** 利润比例(单边基点):5 bps = 0.05% = 万分之五(用户类型 v1) */
25
27
  readonly RATE_BPS_V1: 5;
28
+ /** 利润比例(双边基点):2.5 bps = 0.025% = 千分之二点五(用户类型 v1) */
29
+ readonly RATE_BPS_V1_DOUBLE: 2.5;
26
30
  };
27
31
  export declare const CHAIN: {
28
32
  BSC: {
@@ -25,10 +25,14 @@ export const PROFIT_CONFIG = {
25
25
  RATE_BPS: 30,
26
26
  /** 利润比例(基点):6 bps = 0.06% = 万分之六(捆绑换手模式) */
27
27
  RATE_BPS_SWAP: 6,
28
- /** 利润比例(基点):6 bps = 0.06% = 万分之六(用户类型 v0) */
28
+ /** 利润比例(单边基点):6 bps = 0.06% = 万分之六(用户类型 v0) */
29
29
  RATE_BPS_V0: 6,
30
- /** 利润比例(基点):5 bps = 0.05% = 万分之五(用户类型 v1) */
30
+ /** 利润比例(双边基点):3 bps = 0.03% = 千分之三(用户类型 v0) */
31
+ RATE_BPS_V0_DOUBLE: 3,
32
+ /** 利润比例(单边基点):5 bps = 0.05% = 万分之五(用户类型 v1) */
31
33
  RATE_BPS_V1: 5,
34
+ /** 利润比例(双边基点):2.5 bps = 0.025% = 千分之二点五(用户类型 v1) */
35
+ RATE_BPS_V1_DOUBLE: 2.5,
32
36
  };
33
37
  export const CHAIN = {
34
38
  BSC: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.85",
3
+ "version": "1.4.87",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",