four-flap-meme-sdk 1.4.72 → 1.4.74

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.
@@ -139,14 +139,8 @@ export async function fourBundleBuyFirstMerkle(params) {
139
139
  if (!estimatedTokenAmount || estimatedTokenAmount <= 0n) {
140
140
  throw new Error('报价失败:无法估算可买入的代币数量');
141
141
  }
142
- // ✅ 多笔买入时添加安全系数:减少 1% 卖出数量以应对报价误差/税/滑点
143
- // 原因:多笔买入会产生滑点累积,实际获得的代币可能少于报价
144
- // 单笔买入时不需要安全系数(与普通捆绑换手一致)
145
- let sellAmountWei = estimatedTokenAmount;
146
- if (buyCount > 1) {
147
- const SELL_SAFETY_BPS = 100n; // 1% = 100 bps(仅多笔时)
148
- sellAmountWei = estimatedTokenAmount * (10000n - SELL_SAFETY_BPS) / 10000n;
149
- }
142
+ // ✅ 直接使用报价数量(不添加滑点保护)
143
+ const sellAmountWei = estimatedTokenAmount;
150
144
  // 卖方余额检查
151
145
  if (!sameAddress && sellerTokenBal < sellAmountWei) {
152
146
  throw new Error(`卖方代币余额不足: 需要 ${ethers.formatUnits(sellAmountWei, decimals)},实际 ${ethers.formatUnits(sellerTokenBal, decimals)}`);
@@ -140,14 +140,8 @@ export async function pancakeBundleBuyFirstMerkle(params) {
140
140
  buyerFundsWei: buyerFundsInfo.buyerFundsWei,
141
141
  provider: context.provider
142
142
  });
143
- // ✅ 多笔买入时添加安全系数:减少 1% 卖出数量以应对报价误差/税/滑点
144
- // 原因:多笔买入会产生滑点累积,实际获得的代币可能少于报价
145
- // 单笔买入时不需要安全系数(与普通捆绑换手一致)
146
- let adjustedSellAmount = quoteResult.quotedTokenOut;
147
- if (buyCount > 1) {
148
- const SELL_SAFETY_BPS = 100n; // 1% = 100 bps(仅多笔时)
149
- adjustedSellAmount = quoteResult.quotedTokenOut * (10000n - SELL_SAFETY_BPS) / 10000n;
150
- }
143
+ // ✅ 直接使用报价数量(不添加滑点保护)
144
+ const adjustedSellAmount = quoteResult.quotedTokenOut;
151
145
  // ✅ 拆分买入和卖出金额
152
146
  const buyAmountsWei = splitAmount(buyerFundsInfo.buyerFundsWei, buyCount);
153
147
  const sellAmountsWei = splitAmount(adjustedSellAmount, sellCount);
@@ -409,26 +403,34 @@ function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas }) {
409
403
  }
410
404
  async function buildRouteTransactions({ routeParams, buyerFundsWei, sellAmountToken, buyer, seller, tokenAddress, useNativeToken = true }) {
411
405
  const deadline = getDeadline();
412
- // ✅ ERC20 购买时,value 只需要 FLAT_FEE
413
- const buyValue = useNativeToken ? buyerFundsWei + FLAT_FEE : FLAT_FEE;
414
406
  if (routeParams.routeType === 'v2') {
415
407
  const { v2Path } = routeParams;
416
408
  const reversePath = [...v2Path].reverse();
417
409
  // ✅ 使用官方 V2 Router
418
410
  const v2RouterBuyer = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, buyer);
419
411
  const v2RouterSeller = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, seller);
420
- // 买入:BNB → Token
421
- const buyUnsigned = await v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
422
- // 卖出:Token BNB
423
- const sellUnsigned = await v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
424
- return { buyUnsigned, sellUnsigned };
412
+ if (useNativeToken) {
413
+ // BNB 池子:使用 swapExactETHForTokens / swapExactTokensForETH
414
+ const buyValue = buyerFundsWei + FLAT_FEE;
415
+ const buyUnsigned = await v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
416
+ const sellUnsigned = await v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
417
+ return { buyUnsigned, sellUnsigned };
418
+ }
419
+ else {
420
+ // ✅ ERC20 池子(如 USDT):使用 swapExactTokensForTokens
421
+ const buyUnsigned = await v2RouterBuyer.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(buyerFundsWei, 0n, v2Path, buyer.address, deadline);
422
+ const sellUnsigned = await v2RouterSeller.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
423
+ return { buyUnsigned, sellUnsigned };
424
+ }
425
425
  }
426
426
  if (routeParams.routeType === 'v3-single') {
427
427
  const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
428
428
  const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
429
429
  const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
430
430
  const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
431
- // 买入:WBNB Token
431
+ // V3 池子的处理(ERC20 模式 value = 0,因为通过代币授权支付)
432
+ const buyValue = useNativeToken ? buyerFundsWei + FLAT_FEE : 0n;
433
+ // 买入交易
432
434
  const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
433
435
  tokenIn: v3TokenIn,
434
436
  tokenOut: v3TokenOut,
@@ -439,19 +441,36 @@ async function buildRouteTransactions({ routeParams, buyerFundsWei, sellAmountTo
439
441
  sqrtPriceLimitX96: 0n
440
442
  }]);
441
443
  const buyUnsigned = await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
442
- // 卖出:Token → WBNB → BNB
443
- const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
444
- tokenIn: v3TokenOut,
445
- tokenOut: v3TokenIn,
446
- fee: v3Fee,
447
- recipient: PANCAKE_V3_ROUTER_ADDRESS,
448
- amountIn: sellAmountToken,
449
- amountOutMinimum: 0n,
450
- sqrtPriceLimitX96: 0n
451
- }]);
452
- const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
453
- const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
454
- return { buyUnsigned, sellUnsigned };
444
+ // 卖出交易
445
+ if (useNativeToken) {
446
+ // ✅ BNB 池子:卖出后 unwrap WBNB 为 BNB
447
+ const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
448
+ tokenIn: v3TokenOut,
449
+ tokenOut: v3TokenIn,
450
+ fee: v3Fee,
451
+ recipient: PANCAKE_V3_ROUTER_ADDRESS,
452
+ amountIn: sellAmountToken,
453
+ amountOutMinimum: 0n,
454
+ sqrtPriceLimitX96: 0n
455
+ }]);
456
+ const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
457
+ const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
458
+ return { buyUnsigned, sellUnsigned };
459
+ }
460
+ else {
461
+ // ✅ ERC20 池子:卖出后直接获得 ERC20
462
+ const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
463
+ tokenIn: v3TokenOut,
464
+ tokenOut: v3TokenIn,
465
+ fee: v3Fee,
466
+ recipient: seller.address, // 直接发送到卖方地址
467
+ amountIn: sellAmountToken,
468
+ amountOutMinimum: 0n,
469
+ sqrtPriceLimitX96: 0n
470
+ }]);
471
+ const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData]);
472
+ return { buyUnsigned, sellUnsigned };
473
+ }
455
474
  }
456
475
  // V3 多跳暂不支持官方合约
457
476
  throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
@@ -466,23 +485,31 @@ async function buildMultiRouteTransactions({ routeParams, buyAmountsWei, sellAmo
466
485
  const reversePath = [...v2Path].reverse();
467
486
  const v2RouterBuyer = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, buyer);
468
487
  const v2RouterSeller = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, seller);
469
- // 构建多笔买入交易
470
- const buyUnsignedArray = await Promise.all(buyAmountsWei.map(amount => {
471
- const buyValue = useNativeToken ? amount + FLAT_FEE : FLAT_FEE;
472
- return v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
473
- }));
474
- // 构建多笔卖出交易
475
- const sellUnsignedArray = await Promise.all(sellAmountsWei.map(amount => v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(amount, 0n, reversePath, seller.address, deadline)));
476
- return { buyUnsignedArray, sellUnsignedArray };
488
+ // ✅ 根据是否使用原生代币选择不同的函数
489
+ if (useNativeToken) {
490
+ // BNB 池子:使用 swapExactETHForTokens / swapExactTokensForETH
491
+ const buyUnsignedArray = await Promise.all(buyAmountsWei.map(amount => {
492
+ const buyValue = amount + FLAT_FEE;
493
+ return v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
494
+ }));
495
+ const sellUnsignedArray = await Promise.all(sellAmountsWei.map(amount => v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(amount, 0n, reversePath, seller.address, deadline)));
496
+ return { buyUnsignedArray, sellUnsignedArray };
497
+ }
498
+ else {
499
+ // ✅ ERC20 池子(如 USDT):使用 swapExactTokensForTokens
500
+ const buyUnsignedArray = await Promise.all(buyAmountsWei.map(amount => v2RouterBuyer.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(amount, 0n, v2Path, buyer.address, deadline)));
501
+ const sellUnsignedArray = await Promise.all(sellAmountsWei.map(amount => v2RouterSeller.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(amount, 0n, reversePath, seller.address, deadline)));
502
+ return { buyUnsignedArray, sellUnsignedArray };
503
+ }
477
504
  }
478
505
  if (routeParams.routeType === 'v3-single') {
479
506
  const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
480
507
  const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
481
508
  const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
482
509
  const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
483
- // 构建多笔买入交易
510
+ // 构建多笔买入交易(ERC20 模式 value = 0,因为通过代币授权支付)
484
511
  const buyUnsignedArray = await Promise.all(buyAmountsWei.map(amount => {
485
- const buyValue = useNativeToken ? amount + FLAT_FEE : FLAT_FEE;
512
+ const buyValue = useNativeToken ? amount + FLAT_FEE : 0n;
486
513
  const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
487
514
  tokenIn: v3TokenIn,
488
515
  tokenOut: v3TokenOut,
@@ -494,21 +521,40 @@ async function buildMultiRouteTransactions({ routeParams, buyAmountsWei, sellAmo
494
521
  }]);
495
522
  return v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
496
523
  }));
497
- // 构建多笔卖出交易
498
- const sellUnsignedArray = await Promise.all(sellAmountsWei.map(amount => {
499
- const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
500
- tokenIn: v3TokenOut,
501
- tokenOut: v3TokenIn,
502
- fee: v3Fee,
503
- recipient: PANCAKE_V3_ROUTER_ADDRESS,
504
- amountIn: amount,
505
- amountOutMinimum: 0n,
506
- sqrtPriceLimitX96: 0n
507
- }]);
508
- const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
509
- return v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
510
- }));
511
- return { buyUnsignedArray, sellUnsignedArray };
524
+ // ✅ 根据是否使用原生代币构建不同的卖出交易
525
+ if (useNativeToken) {
526
+ // BNB 池子:卖出后 unwrap WBNB 为 BNB
527
+ const sellUnsignedArray = await Promise.all(sellAmountsWei.map(amount => {
528
+ const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
529
+ tokenIn: v3TokenOut,
530
+ tokenOut: v3TokenIn,
531
+ fee: v3Fee,
532
+ recipient: PANCAKE_V3_ROUTER_ADDRESS,
533
+ amountIn: amount,
534
+ amountOutMinimum: 0n,
535
+ sqrtPriceLimitX96: 0n
536
+ }]);
537
+ const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
538
+ return v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
539
+ }));
540
+ return { buyUnsignedArray, sellUnsignedArray };
541
+ }
542
+ else {
543
+ // ✅ ERC20 池子:卖出后直接获得 ERC20
544
+ const sellUnsignedArray = await Promise.all(sellAmountsWei.map(amount => {
545
+ const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
546
+ tokenIn: v3TokenOut,
547
+ tokenOut: v3TokenIn,
548
+ fee: v3Fee,
549
+ recipient: seller.address, // 直接发送到卖方地址
550
+ amountIn: amount,
551
+ amountOutMinimum: 0n,
552
+ sqrtPriceLimitX96: 0n
553
+ }]);
554
+ return v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData]);
555
+ }));
556
+ return { buyUnsignedArray, sellUnsignedArray };
557
+ }
512
558
  }
513
559
  throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
514
560
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.72",
3
+ "version": "1.4.74",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",