four-flap-meme-sdk 1.4.14 → 1.4.16

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.
@@ -91,3 +91,43 @@ export interface FourBatchSwapResult {
91
91
  * 限制:最多 24 个买方(服务器限制 25 笔交易,包含 1 笔利润交易)
92
92
  */
93
93
  export declare function fourBatchSwapMerkle(params: FourBatchSwapSignParams): Promise<FourBatchSwapResult>;
94
+ /**
95
+ * Four 快捷批量换手参数
96
+ */
97
+ export interface FourQuickBatchSwapSignParams {
98
+ sellerPrivateKey: string;
99
+ sellAmount?: string;
100
+ sellPercentage?: number;
101
+ buyerPrivateKeys: string[];
102
+ buyerRatios?: number[];
103
+ buyerAmounts?: string[];
104
+ tokenAddress: string;
105
+ config: FourSwapSignConfig;
106
+ }
107
+ /**
108
+ * Four 快捷批量换手结果
109
+ */
110
+ export interface FourQuickBatchSwapResult {
111
+ signedTransactions: string[];
112
+ metadata?: {
113
+ sellerAddress: string;
114
+ buyerAddresses: string[];
115
+ sellAmount: string;
116
+ estimatedBNBOut: string;
117
+ transferAmounts: string[];
118
+ profitAmount?: string;
119
+ };
120
+ }
121
+ /**
122
+ * Four 内盘快捷批量换手(资金利用率模式)
123
+ *
124
+ * 流程:[贿赂] → [卖出] → [转账1, 转账2, ...] → [买入1, 买入2, ...] → [利润]
125
+ *
126
+ * 特点:
127
+ * - 子钱包不需要预先有 BNB
128
+ * - 资金来自主钱包卖出代币所得
129
+ * - 提升资金利用率
130
+ *
131
+ * 限制:最多 23 个买方(2N + 3 ≤ 50)
132
+ */
133
+ export declare function fourQuickBatchSwapMerkle(params: FourQuickBatchSwapSignParams): Promise<FourQuickBatchSwapResult>;
@@ -425,3 +425,210 @@ export async function fourBatchSwapMerkle(params) {
425
425
  }
426
426
  };
427
427
  }
428
+ /**
429
+ * Four 内盘快捷批量换手(资金利用率模式)
430
+ *
431
+ * 流程:[贿赂] → [卖出] → [转账1, 转账2, ...] → [买入1, 买入2, ...] → [利润]
432
+ *
433
+ * 特点:
434
+ * - 子钱包不需要预先有 BNB
435
+ * - 资金来自主钱包卖出代币所得
436
+ * - 提升资金利用率
437
+ *
438
+ * 限制:最多 23 个买方(2N + 3 ≤ 50)
439
+ */
440
+ export async function fourQuickBatchSwapMerkle(params) {
441
+ const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerRatios, buyerAmounts, tokenAddress, config } = params;
442
+ // ✅ 校验买方数量
443
+ // 贿赂(1) + 卖出(1) + 转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
444
+ const MAX_BUYERS = 23;
445
+ if (buyerPrivateKeys.length === 0) {
446
+ throw new Error('至少需要一个买方钱包');
447
+ }
448
+ if (buyerPrivateKeys.length > MAX_BUYERS) {
449
+ throw new Error(`资金利用率模式买方钱包数量超过限制: ${buyerPrivateKeys.length} > ${MAX_BUYERS}`);
450
+ }
451
+ // ✅ 校验分配模式
452
+ if (!buyerRatios && !buyerAmounts) {
453
+ throw new Error('必须提供 buyerRatios 或 buyerAmounts');
454
+ }
455
+ if (buyerRatios && buyerRatios.length !== buyerPrivateKeys.length) {
456
+ throw new Error(`buyerRatios 长度 (${buyerRatios.length}) 与 buyerPrivateKeys 长度 (${buyerPrivateKeys.length}) 不匹配`);
457
+ }
458
+ if (buyerAmounts && buyerAmounts.length !== buyerPrivateKeys.length) {
459
+ throw new Error(`buyerAmounts 长度 (${buyerAmounts.length}) 与 buyerPrivateKeys 长度 (${buyerPrivateKeys.length}) 不匹配`);
460
+ }
461
+ const chainIdNum = config.chainId ?? 56;
462
+ const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
463
+ chainId: chainIdNum,
464
+ name: 'BSC'
465
+ });
466
+ const seller = new Wallet(sellerPrivateKey, provider);
467
+ const buyers = buyerPrivateKeys.map(pk => new Wallet(pk, provider));
468
+ const nonceManager = new NonceManager(provider);
469
+ // 创建适配的配置对象
470
+ const bundleConfig = {
471
+ minGasPriceGwei: config.minGasPriceGwei,
472
+ maxGasPriceGwei: config.maxGasPriceGwei,
473
+ gasLimit: typeof config.gasLimit === 'bigint' ? Number(config.gasLimit) : config.gasLimit,
474
+ gasLimitMultiplier: config.gasLimitMultiplier,
475
+ txType: config.txType,
476
+ chainId: config.chainId
477
+ };
478
+ const finalGasLimit = getGasLimit(bundleConfig);
479
+ const txType = getTxType(bundleConfig);
480
+ // ✅ 并行获取:卖出数量、gasPrice
481
+ const [sellAmountResult, gasPrice] = await Promise.all([
482
+ calculateSellAmount(provider, tokenAddress, seller.address, sellAmount, sellPercentage),
483
+ getOptimizedGasPrice(provider, getGasPriceConfig(bundleConfig))
484
+ ]);
485
+ const { amount: sellAmountWei, decimals } = sellAmountResult;
486
+ // ✅ 获取卖出报价
487
+ const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider);
488
+ const sellQuote = await helper3.trySell(tokenAddress, sellAmountWei);
489
+ const estimatedBNBOut = sellQuote.funds;
490
+ console.log(`[fourQuickBatchSwapMerkle] 卖出数量: ${ethers.formatUnits(sellAmountWei, decimals)}`);
491
+ console.log(`[fourQuickBatchSwapMerkle] 预估卖出所得: ${ethers.formatEther(estimatedBNBOut)} BNB`);
492
+ // ✅ 计算利润
493
+ const profitRateBps = PROFIT_CONFIG.RATE_BPS;
494
+ const profitAmount = estimatedBNBOut > 0n
495
+ ? (estimatedBNBOut * BigInt(profitRateBps)) / 10000n
496
+ : 0n;
497
+ const distributableAmount = estimatedBNBOut - profitAmount;
498
+ // ✅ 计算每个买方分到的金额
499
+ let transferAmountsWei;
500
+ if (buyerAmounts && buyerAmounts.length === buyers.length) {
501
+ // 数量模式
502
+ transferAmountsWei = buyerAmounts.map(amt => ethers.parseEther(amt));
503
+ const totalTransfer = transferAmountsWei.reduce((a, b) => a + b, 0n);
504
+ if (totalTransfer > distributableAmount) {
505
+ throw new Error(`指定的买入总金额超过可分配金额 (${ethers.formatEther(distributableAmount)} BNB)`);
506
+ }
507
+ }
508
+ else if (buyerRatios && buyerRatios.length === buyers.length) {
509
+ // 比例模式
510
+ transferAmountsWei = buyerRatios.map(ratio => {
511
+ return (distributableAmount * BigInt(Math.round(ratio * 10000))) / 10000n;
512
+ });
513
+ }
514
+ else {
515
+ throw new Error('必须提供 buyerRatios 或 buyerAmounts');
516
+ }
517
+ // ✅ 获取贿赂金额
518
+ const bribeAmount = getBribeAmount(config);
519
+ // ✅ 验证主钱包余额
520
+ const sellerBalance = await seller.provider.getBalance(seller.address);
521
+ // 主钱包只需要支付:贿赂 + Gas(卖出后有 BNB 可用于转账和利润)
522
+ const sellerGasCost = gasPrice * (21000n + finalGasLimit + 21000n * BigInt(buyers.length) + 21000n);
523
+ const sellerRequired = bribeAmount + sellerGasCost;
524
+ if (sellerBalance < sellerRequired) {
525
+ throw new Error(`主钱包 BNB 余额不足: 需要约 ${ethers.formatEther(sellerRequired)} BNB (贿赂: ${ethers.formatEther(bribeAmount)}, Gas: ${ethers.formatEther(sellerGasCost)}), 实际 ${ethers.formatEther(sellerBalance)} BNB`);
526
+ }
527
+ // ==================== 规划 Nonce ====================
528
+ let sellerNonce = await nonceManager.getNextNonce(seller);
529
+ // ==================== 1. 贿赂交易 ====================
530
+ let bribeTx = null;
531
+ if (bribeAmount > 0n) {
532
+ bribeTx = await seller.signTransaction({
533
+ to: BLOCKRAZOR_BUILDER_EOA,
534
+ value: bribeAmount,
535
+ nonce: sellerNonce++,
536
+ gasPrice,
537
+ gasLimit: 21000n,
538
+ chainId: chainIdNum,
539
+ type: txType
540
+ });
541
+ console.log(`[fourQuickBatchSwapMerkle] 贿赂交易已签名`);
542
+ }
543
+ // ==================== 2. 卖出交易 ====================
544
+ const tmSeller = new Contract(TM_ADDRESS, TM_ABI, seller);
545
+ const sellUnsigned = await tmSeller.sellToken.populateTransaction(0n, tokenAddress, sellAmountWei, 0n);
546
+ const signedSell = await seller.signTransaction({
547
+ ...sellUnsigned,
548
+ from: seller.address,
549
+ nonce: sellerNonce++,
550
+ gasLimit: finalGasLimit,
551
+ gasPrice,
552
+ chainId: chainIdNum,
553
+ type: txType
554
+ });
555
+ console.log(`[fourQuickBatchSwapMerkle] 卖出交易已签名`);
556
+ // ==================== 3. 转账交易 ====================
557
+ const transferTxs = [];
558
+ const reserveGas = ethers.parseEther((config.reserveGasBNB || 0.0005).toString());
559
+ for (let i = 0; i < buyers.length; i++) {
560
+ // 转账金额 = 买入金额 + Gas 预留
561
+ const buyerGasCost = gasPrice * finalGasLimit;
562
+ const transferValue = transferAmountsWei[i] + reserveGas + buyerGasCost;
563
+ const transferTx = await seller.signTransaction({
564
+ to: buyers[i].address,
565
+ value: transferValue,
566
+ nonce: sellerNonce++,
567
+ gasPrice,
568
+ gasLimit: 21000n,
569
+ chainId: chainIdNum,
570
+ type: txType
571
+ });
572
+ transferTxs.push(transferTx);
573
+ }
574
+ console.log(`[fourQuickBatchSwapMerkle] ${transferTxs.length} 笔转账交易已签名`);
575
+ // ==================== 4. 买入交易 ====================
576
+ const buyerNonces = await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
577
+ const signedBuys = await Promise.all(buyers.map(async (buyer, i) => {
578
+ const buyAmount = transferAmountsWei[i];
579
+ const tmBuyer = new Contract(TM_ADDRESS, TM_ABI, buyer);
580
+ const buyUnsigned = await tmBuyer.buyTokenAMAP.populateTransaction(0n, tokenAddress, buyer.address, buyAmount, 0n, { value: buyAmount });
581
+ return buyer.signTransaction({
582
+ ...buyUnsigned,
583
+ from: buyer.address,
584
+ nonce: buyerNonces[i],
585
+ gasLimit: finalGasLimit,
586
+ gasPrice,
587
+ chainId: chainIdNum,
588
+ type: txType,
589
+ value: buyAmount
590
+ });
591
+ }));
592
+ console.log(`[fourQuickBatchSwapMerkle] ${signedBuys.length} 笔买入交易已签名`);
593
+ // ==================== 5. 利润交易 ====================
594
+ let profitTx = null;
595
+ if (profitAmount > 0n) {
596
+ profitTx = await seller.signTransaction({
597
+ to: PROFIT_CONFIG.RECIPIENT,
598
+ value: profitAmount,
599
+ nonce: sellerNonce++,
600
+ gasPrice,
601
+ gasLimit: 21000n,
602
+ chainId: chainIdNum,
603
+ type: txType
604
+ });
605
+ console.log(`[fourQuickBatchSwapMerkle] 利润交易已签名`);
606
+ }
607
+ nonceManager.clearTemp();
608
+ // ==================== 组装交易数组 ====================
609
+ const signedTransactions = [];
610
+ if (bribeTx)
611
+ signedTransactions.push(bribeTx);
612
+ signedTransactions.push(signedSell);
613
+ signedTransactions.push(...transferTxs);
614
+ signedTransactions.push(...signedBuys);
615
+ if (profitTx)
616
+ signedTransactions.push(profitTx);
617
+ console.log(`[fourQuickBatchSwapMerkle] 交易组装完成: ${signedTransactions.length} 笔`);
618
+ console.log(` - 贿赂: ${bribeTx ? 1 : 0}`);
619
+ console.log(` - 卖出: 1`);
620
+ console.log(` - 转账: ${transferTxs.length}`);
621
+ console.log(` - 买入: ${signedBuys.length}`);
622
+ console.log(` - 利润: ${profitTx ? 1 : 0}`);
623
+ return {
624
+ signedTransactions,
625
+ metadata: {
626
+ sellerAddress: seller.address,
627
+ buyerAddresses: buyers.map(b => b.address),
628
+ sellAmount: ethers.formatUnits(sellAmountWei, decimals),
629
+ estimatedBNBOut: ethers.formatEther(estimatedBNBOut),
630
+ transferAmounts: transferAmountsWei.map(amt => ethers.formatEther(amt)),
631
+ profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
632
+ }
633
+ };
634
+ }
@@ -101,3 +101,48 @@ export interface FlapBatchSwapResult {
101
101
  * 限制:最多 24 个买方(服务器限制 25 笔交易,包含 1 笔利润交易)
102
102
  */
103
103
  export declare function flapBatchSwapMerkle(params: FlapBatchSwapSignParams): Promise<FlapBatchSwapResult>;
104
+ /**
105
+ * Flap 快捷批量换手参数
106
+ */
107
+ export interface FlapQuickBatchSwapSignParams {
108
+ chain: FlapChain;
109
+ sellerPrivateKey: string;
110
+ sellAmount?: string;
111
+ sellPercentage?: number;
112
+ buyerPrivateKeys: string[];
113
+ buyerRatios?: number[];
114
+ buyerAmounts?: string[];
115
+ tokenAddress: string;
116
+ config: FlapSwapSignConfig;
117
+ quoteToken?: string;
118
+ quoteTokenDecimals?: number;
119
+ }
120
+ /**
121
+ * Flap 快捷批量换手结果
122
+ */
123
+ export interface FlapQuickBatchSwapResult {
124
+ signedTransactions: string[];
125
+ metadata?: {
126
+ sellerAddress: string;
127
+ buyerAddresses: string[];
128
+ sellAmount: string;
129
+ estimatedOutput: string;
130
+ transferAmounts: string[];
131
+ profitAmount?: string;
132
+ useNativeToken: boolean;
133
+ };
134
+ }
135
+ /**
136
+ * Flap 内盘快捷批量换手(资金利用率模式)
137
+ *
138
+ * 流程:[贿赂] → [卖出] → [转账1, 转账2, ...] → [买入1, 买入2, ...] → [利润]
139
+ *
140
+ * 特点:
141
+ * - 子钱包不需要预先有余额
142
+ * - 资金来自主钱包卖出代币所得
143
+ * - 提升资金利用率
144
+ * - 支持原生代币(BNB/OKB/ETH)和 ERC20(如 USDT)两种模式
145
+ *
146
+ * 限制:最多 23 个买方(2N + 3 ≤ 50)
147
+ */
148
+ export declare function flapQuickBatchSwapMerkle(params: FlapQuickBatchSwapSignParams): Promise<FlapQuickBatchSwapResult>;
@@ -668,3 +668,278 @@ export async function flapBatchSwapMerkle(params) {
668
668
  }
669
669
  };
670
670
  }
671
+ /**
672
+ * Flap 内盘快捷批量换手(资金利用率模式)
673
+ *
674
+ * 流程:[贿赂] → [卖出] → [转账1, 转账2, ...] → [买入1, 买入2, ...] → [利润]
675
+ *
676
+ * 特点:
677
+ * - 子钱包不需要预先有余额
678
+ * - 资金来自主钱包卖出代币所得
679
+ * - 提升资金利用率
680
+ * - 支持原生代币(BNB/OKB/ETH)和 ERC20(如 USDT)两种模式
681
+ *
682
+ * 限制:最多 23 个买方(2N + 3 ≤ 50)
683
+ */
684
+ export async function flapQuickBatchSwapMerkle(params) {
685
+ const { chain, sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerRatios, buyerAmounts, tokenAddress, config, quoteToken, quoteTokenDecimals = 18 } = params;
686
+ // ✅ 校验买方数量
687
+ // BNB 模式:贿赂(1) + 卖出(1) + 转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
688
+ // ERC20 模式:贿赂(1) + 卖出(1) + ERC20转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
689
+ const MAX_BUYERS = 23;
690
+ if (buyerPrivateKeys.length === 0) {
691
+ throw new Error('至少需要一个买方钱包');
692
+ }
693
+ if (buyerPrivateKeys.length > MAX_BUYERS) {
694
+ throw new Error(`资金利用率模式买方钱包数量超过限制: ${buyerPrivateKeys.length} > ${MAX_BUYERS}`);
695
+ }
696
+ // ✅ 校验分配模式
697
+ if (!buyerRatios && !buyerAmounts) {
698
+ throw new Error('必须提供 buyerRatios 或 buyerAmounts');
699
+ }
700
+ if (buyerRatios && buyerRatios.length !== buyerPrivateKeys.length) {
701
+ throw new Error(`buyerRatios 长度 (${buyerRatios.length}) 与 buyerPrivateKeys 长度 (${buyerPrivateKeys.length}) 不匹配`);
702
+ }
703
+ if (buyerAmounts && buyerAmounts.length !== buyerPrivateKeys.length) {
704
+ throw new Error(`buyerAmounts 长度 (${buyerAmounts.length}) 与 buyerPrivateKeys 长度 (${buyerPrivateKeys.length}) 不匹配`);
705
+ }
706
+ // ✅ 判断是否使用原生代币
707
+ const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
708
+ const outputToken = useNativeToken ? ZERO_ADDRESS : quoteToken;
709
+ const ERC20_TRANSFER_GAS = 65000n;
710
+ const chainContext = createChainContext(chain, config);
711
+ const seller = new Wallet(sellerPrivateKey, chainContext.provider);
712
+ const buyers = buyerPrivateKeys.map(pk => new Wallet(pk, chainContext.provider));
713
+ const nonceManager = new NonceManager(chainContext.provider);
714
+ const finalGasLimit = getGasLimit(config);
715
+ const txType = getTxType(config);
716
+ // ✅ 并行获取:卖出数量、gasPrice
717
+ const [sellAmountResult, gasPrice] = await Promise.all([
718
+ calculateSellAmount(chainContext.provider, tokenAddress, seller.address, sellAmount, sellPercentage),
719
+ getOptimizedGasPrice(chainContext.provider, getGasPriceConfig(config))
720
+ ]);
721
+ const { amount: sellAmountWei, decimals } = sellAmountResult;
722
+ const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
723
+ // ✅ 获取卖出报价
724
+ const quote = await quoteSellOutput({
725
+ portalAddress: chainContext.portalAddress,
726
+ tokenAddress,
727
+ sellAmountWei,
728
+ provider: chainContext.provider,
729
+ skipQuoteOnError: config.skipQuoteOnError,
730
+ outputToken
731
+ });
732
+ const estimatedOutput = quote.quotedNative;
733
+ const outputFormatted = useNativeToken
734
+ ? ethers.formatEther(estimatedOutput)
735
+ : ethers.formatUnits(estimatedOutput, quoteTokenDecimals);
736
+ console.log(`[flapQuickBatchSwapMerkle] 模式: ${useNativeToken ? '原生代币' : 'ERC20'}`);
737
+ console.log(`[flapQuickBatchSwapMerkle] 卖出数量: ${ethers.formatUnits(sellAmountWei, decimals)}`);
738
+ console.log(`[flapQuickBatchSwapMerkle] 预估卖出所得: ${outputFormatted}`);
739
+ // ✅ 计算利润(基于原生代币价值)
740
+ let tokenProfitAmount = calculateProfitAmount(estimatedOutput);
741
+ let nativeProfitAmount = tokenProfitAmount;
742
+ if (!useNativeToken && tokenProfitAmount > 0n) {
743
+ // ERC20 模式:将代币利润转换为等值原生代币
744
+ nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, quoteToken, tokenProfitAmount, chainContext.chainId);
745
+ console.log(`[flapQuickBatchSwapMerkle] ERC20→原生代币 报价: ${ethers.formatUnits(tokenProfitAmount, quoteTokenDecimals)} → ${ethers.formatEther(nativeProfitAmount)}`);
746
+ }
747
+ const distributableAmount = useNativeToken
748
+ ? estimatedOutput - tokenProfitAmount
749
+ : estimatedOutput; // ERC20 模式利润从原生代币扣
750
+ // ✅ 计算每个买方分到的金额
751
+ let transferAmountsWei;
752
+ if (buyerAmounts && buyerAmounts.length === buyers.length) {
753
+ // 数量模式
754
+ transferAmountsWei = buyerAmounts.map(amt => useNativeToken
755
+ ? ethers.parseEther(amt)
756
+ : ethers.parseUnits(amt, quoteTokenDecimals));
757
+ const totalTransfer = transferAmountsWei.reduce((a, b) => a + b, 0n);
758
+ if (totalTransfer > distributableAmount) {
759
+ const formatted = useNativeToken
760
+ ? ethers.formatEther(distributableAmount)
761
+ : ethers.formatUnits(distributableAmount, quoteTokenDecimals);
762
+ throw new Error(`指定的买入总金额超过可分配金额 (${formatted})`);
763
+ }
764
+ }
765
+ else if (buyerRatios && buyerRatios.length === buyers.length) {
766
+ // 比例模式
767
+ transferAmountsWei = buyerRatios.map(ratio => {
768
+ return (distributableAmount * BigInt(Math.round(ratio * 10000))) / 10000n;
769
+ });
770
+ }
771
+ else {
772
+ throw new Error('必须提供 buyerRatios 或 buyerAmounts');
773
+ }
774
+ // ✅ 获取贿赂金额
775
+ const bribeAmount = getBribeAmount(config);
776
+ // ✅ 验证主钱包余额
777
+ const sellerBalance = await seller.provider.getBalance(seller.address);
778
+ let sellerGasCost;
779
+ let sellerRequired;
780
+ if (useNativeToken) {
781
+ // 原生代币模式:贿赂 + Gas(卖出 + 转账 + 利润)
782
+ sellerGasCost = gasPrice * (21000n + finalGasLimit + 21000n * BigInt(buyers.length) + 21000n);
783
+ sellerRequired = bribeAmount + sellerGasCost;
784
+ }
785
+ else {
786
+ // ERC20 模式:贿赂 + Gas(卖出 + ERC20转账 + 利润)
787
+ sellerGasCost = gasPrice * (21000n + finalGasLimit + ERC20_TRANSFER_GAS * BigInt(buyers.length) + 21000n);
788
+ sellerRequired = bribeAmount + sellerGasCost;
789
+ }
790
+ if (sellerBalance < sellerRequired) {
791
+ throw new Error(`主钱包 ${chainContext.nativeToken} 余额不足: 需要约 ${ethers.formatEther(sellerRequired)} (贿赂: ${ethers.formatEther(bribeAmount)}, Gas: ${ethers.formatEther(sellerGasCost)}), 实际 ${ethers.formatEther(sellerBalance)}`);
792
+ }
793
+ // ==================== 规划 Nonce ====================
794
+ let sellerNonce = await nonceManager.getNextNonce(seller);
795
+ // ==================== 1. 贿赂交易 ====================
796
+ let bribeTx = null;
797
+ if (bribeAmount > 0n) {
798
+ bribeTx = await seller.signTransaction({
799
+ to: BLOCKRAZOR_BUILDER_EOA,
800
+ value: bribeAmount,
801
+ nonce: sellerNonce++,
802
+ gasPrice,
803
+ gasLimit: 21000n,
804
+ chainId: chainContext.chainId,
805
+ type: txType
806
+ });
807
+ console.log(`[flapQuickBatchSwapMerkle] 贿赂交易已签名`);
808
+ }
809
+ // ==================== 2. 卖出交易 ====================
810
+ const portalSeller = new Contract(chainContext.portalAddress, PORTAL_ABI, seller);
811
+ const sellUnsigned = await portalSeller.swapExactInput.populateTransaction({
812
+ inputToken: tokenAddress,
813
+ outputToken,
814
+ inputAmount: sellAmountWei,
815
+ minOutputAmount: 0,
816
+ permitData: '0x'
817
+ });
818
+ const sellTx = buildTransactionRequest(sellUnsigned, {
819
+ from: seller.address,
820
+ nonce: sellerNonce++,
821
+ gasLimit: finalGasLimit,
822
+ gasPrice,
823
+ priorityFee,
824
+ chainId: chainContext.chainId,
825
+ txType,
826
+ value: 0n
827
+ });
828
+ const signedSell = await seller.signTransaction(sellTx);
829
+ console.log(`[flapQuickBatchSwapMerkle] 卖出交易已签名`);
830
+ // ==================== 3. 转账交易 ====================
831
+ const transferTxs = [];
832
+ const reserveGas = ethers.parseEther((config.reserveGasETH || 0.0005).toString());
833
+ if (useNativeToken) {
834
+ // 原生代币模式:直接转账
835
+ for (let i = 0; i < buyers.length; i++) {
836
+ const buyerGasCost = gasPrice * finalGasLimit;
837
+ const transferValue = transferAmountsWei[i] + reserveGas + buyerGasCost;
838
+ const transferTx = await seller.signTransaction({
839
+ to: buyers[i].address,
840
+ value: transferValue,
841
+ nonce: sellerNonce++,
842
+ gasPrice,
843
+ gasLimit: 21000n,
844
+ chainId: chainContext.chainId,
845
+ type: txType
846
+ });
847
+ transferTxs.push(transferTx);
848
+ }
849
+ }
850
+ else {
851
+ // ERC20 模式:ERC20 transfer(子钱包已预留原生代币)
852
+ const erc20Interface = new ethers.Interface([
853
+ 'function transfer(address to, uint256 amount) returns (bool)'
854
+ ]);
855
+ for (let i = 0; i < buyers.length; i++) {
856
+ const transferData = erc20Interface.encodeFunctionData('transfer', [
857
+ buyers[i].address,
858
+ transferAmountsWei[i]
859
+ ]);
860
+ const transferTx = await seller.signTransaction({
861
+ to: quoteToken,
862
+ data: transferData,
863
+ value: 0n,
864
+ nonce: sellerNonce++,
865
+ gasPrice,
866
+ gasLimit: ERC20_TRANSFER_GAS,
867
+ chainId: chainContext.chainId,
868
+ type: txType
869
+ });
870
+ transferTxs.push(transferTx);
871
+ }
872
+ }
873
+ console.log(`[flapQuickBatchSwapMerkle] ${transferTxs.length} 笔转账交易已签名`);
874
+ // ==================== 4. 买入交易 ====================
875
+ const buyerNonces = await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
876
+ const signedBuys = await Promise.all(buyers.map(async (buyer, i) => {
877
+ const buyAmount = transferAmountsWei[i];
878
+ const portalBuyer = new Contract(chainContext.portalAddress, PORTAL_ABI, buyer);
879
+ const buyUnsigned = await portalBuyer.swapExactInput.populateTransaction({
880
+ inputToken: outputToken,
881
+ outputToken: tokenAddress,
882
+ inputAmount: buyAmount,
883
+ minOutputAmount: 0,
884
+ permitData: '0x'
885
+ }, useNativeToken ? { value: buyAmount } : {});
886
+ const buyTx = buildTransactionRequest(buyUnsigned, {
887
+ from: buyer.address,
888
+ nonce: buyerNonces[i],
889
+ gasLimit: finalGasLimit,
890
+ gasPrice,
891
+ priorityFee,
892
+ chainId: chainContext.chainId,
893
+ txType,
894
+ value: useNativeToken ? buyAmount : 0n
895
+ });
896
+ return buyer.signTransaction(buyTx);
897
+ }));
898
+ console.log(`[flapQuickBatchSwapMerkle] ${signedBuys.length} 笔买入交易已签名`);
899
+ // ==================== 5. 利润交易 ====================
900
+ let profitTx = null;
901
+ if (nativeProfitAmount > 0n) {
902
+ profitTx = await seller.signTransaction({
903
+ to: getProfitRecipient(),
904
+ value: nativeProfitAmount,
905
+ nonce: sellerNonce++,
906
+ gasPrice,
907
+ gasLimit: 21000n,
908
+ chainId: chainContext.chainId,
909
+ type: txType
910
+ });
911
+ console.log(`[flapQuickBatchSwapMerkle] 利润交易已签名`);
912
+ }
913
+ nonceManager.clearTemp();
914
+ // ==================== 组装交易数组 ====================
915
+ const signedTransactions = [];
916
+ if (bribeTx)
917
+ signedTransactions.push(bribeTx);
918
+ signedTransactions.push(signedSell);
919
+ signedTransactions.push(...transferTxs);
920
+ signedTransactions.push(...signedBuys);
921
+ if (profitTx)
922
+ signedTransactions.push(profitTx);
923
+ console.log(`[flapQuickBatchSwapMerkle] 交易组装完成: ${signedTransactions.length} 笔`);
924
+ console.log(` - 贿赂: ${bribeTx ? 1 : 0}`);
925
+ console.log(` - 卖出: 1`);
926
+ console.log(` - 转账: ${transferTxs.length}`);
927
+ console.log(` - 买入: ${signedBuys.length}`);
928
+ console.log(` - 利润: ${profitTx ? 1 : 0}`);
929
+ return {
930
+ signedTransactions,
931
+ metadata: {
932
+ sellerAddress: seller.address,
933
+ buyerAddresses: buyers.map(b => b.address),
934
+ sellAmount: ethers.formatUnits(sellAmountWei, decimals),
935
+ estimatedOutput: useNativeToken
936
+ ? ethers.formatEther(estimatedOutput)
937
+ : ethers.formatUnits(estimatedOutput, quoteTokenDecimals),
938
+ transferAmounts: transferAmountsWei.map(amt => useNativeToken
939
+ ? ethers.formatEther(amt)
940
+ : ethers.formatUnits(amt, quoteTokenDecimals)),
941
+ profitAmount: nativeProfitAmount > 0n ? ethers.formatEther(nativeProfitAmount) : undefined,
942
+ useNativeToken
943
+ }
944
+ };
945
+ }
package/dist/index.d.ts CHANGED
@@ -36,8 +36,8 @@ export { validatePrivateKeys, type PrivateKeyValidation } from './utils/wallet.j
36
36
  export { stealthTransfer, type StealthTransferResult, type StealthTransferSimpleParams } from './utils/stealth-transfer.js';
37
37
  export { inspectTokenLP, getFactoryFromRouter, registerDYORSwap, registerDex, getChainConfig, type LPInfo, type LPPlatform, type InspectOptions, type DexConfig, type ChainDexConfig, } from './utils/lp-inspect.js';
38
38
  export { disperseWithBundle, sweepWithBundle, type DisperseSignParams, type SweepSignParams, type SignedTransactionsResult, type DisperseParams, type SweepParams, type BundleSubmitResult } from './utils/airdrop-sweep.js';
39
- export { fourBundleSwapMerkle, fourBatchSwapMerkle, type FourSwapSignConfig, type FourSwapConfig, type FourBundleSwapSignParams, type FourBundleSwapParams, type FourSwapResult, type FourBatchSwapSignParams, type FourBatchSwapResult } from './contracts/tm-bundle-merkle/swap.js';
40
- export { flapBundleSwapMerkle, flapBatchSwapMerkle, type FlapSwapSignConfig, type FlapSwapConfig, type FlapBundleSwapSignParams, type FlapBundleSwapParams, type FlapSwapResult, type FlapBatchSwapSignParams, type FlapBatchSwapResult } from './flap/portal-bundle-merkle/swap.js';
39
+ export { fourBundleSwapMerkle, fourBatchSwapMerkle, fourQuickBatchSwapMerkle, type FourSwapSignConfig, type FourSwapConfig, type FourBundleSwapSignParams, type FourBundleSwapParams, type FourSwapResult, type FourBatchSwapSignParams, type FourBatchSwapResult, type FourQuickBatchSwapSignParams, type FourQuickBatchSwapResult } from './contracts/tm-bundle-merkle/swap.js';
40
+ export { flapBundleSwapMerkle, flapBatchSwapMerkle, flapQuickBatchSwapMerkle, type FlapSwapSignConfig, type FlapSwapConfig, type FlapBundleSwapSignParams, type FlapBundleSwapParams, type FlapSwapResult, type FlapBatchSwapSignParams, type FlapBatchSwapResult, type FlapQuickBatchSwapSignParams, type FlapQuickBatchSwapResult } from './flap/portal-bundle-merkle/swap.js';
41
41
  export { pancakeBundleSwapMerkle, pancakeBatchSwapMerkle, pancakeQuickBatchSwapMerkle, type PancakeSwapSignConfig, type PancakeBundleSwapSignParams, type PancakeSwapConfig, type PancakeBundleSwapParams, type PancakeSwapResult, type PancakeBatchSwapSignParams, type PancakeBatchSwapResult, type PancakeQuickBatchSwapParams, type PancakeQuickBatchSwapResult, type SwapRouteType, type V2RouteParams, type V3SingleRouteParams, type V3MultiRouteParams, type RouteParams } from './pancake/bundle-swap.js';
42
42
  export { fourBundleBuyFirstMerkle, type FourBuyFirstConfig, type FourBundleBuyFirstParams, type FourBuyFirstSignConfig, type FourBundleBuyFirstSignParams, type FourBuyFirstResult } from './contracts/tm-bundle-merkle/swap-buy-first.js';
43
43
  export { flapBundleBuyFirstMerkle, type FlapBuyFirstSignConfig, type FlapBuyFirstConfig, type FlapBundleBuyFirstSignParams, type FlapBundleBuyFirstParams, type FlapBuyFirstResult } from './flap/portal-bundle-merkle/swap-buy-first.js';
package/dist/index.js CHANGED
@@ -52,9 +52,9 @@ export { disperseWithBundle, sweepWithBundle } from './utils/airdrop-sweep.js';
52
52
  // 捆绑换手功能(Bundle Swap)
53
53
  // ============================================================
54
54
  // Four内盘换手
55
- export { fourBundleSwapMerkle, fourBatchSwapMerkle } from './contracts/tm-bundle-merkle/swap.js';
55
+ export { fourBundleSwapMerkle, fourBatchSwapMerkle, fourQuickBatchSwapMerkle } from './contracts/tm-bundle-merkle/swap.js';
56
56
  // Flap内盘换手
57
- export { flapBundleSwapMerkle, flapBatchSwapMerkle } from './flap/portal-bundle-merkle/swap.js';
57
+ export { flapBundleSwapMerkle, flapBatchSwapMerkle, flapQuickBatchSwapMerkle } from './flap/portal-bundle-merkle/swap.js';
58
58
  // PancakeSwap V2/V3通用换手
59
59
  export { pancakeBundleSwapMerkle, pancakeBatchSwapMerkle, pancakeQuickBatchSwapMerkle } from './pancake/bundle-swap.js';
60
60
  // 先买后卖(Buy-First)入口
@@ -693,12 +693,10 @@ export async function pancakeQuickBatchSwapMerkle(params) {
693
693
  // ✅ 判断是否使用原生代币
694
694
  const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
695
695
  const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'.toLowerCase();
696
- // ✅ 校验买方数量(已移除授权交易)
696
+ // ✅ 校验买方数量(子钱包已预留 BNB,不需要主钱包转 Gas)
697
697
  // BNB 模式:贿赂(1) + 卖出(1) + 转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
698
- // ERC20 模式:贿赂(1) + 卖出(1) + ERC20转账(N) + BNB Gas转账(N) + 买入(N) + 利润(1) ≤ 50 → 3N + 3 ≤ 50 → N ≤ 15
699
- const MAX_BUYERS_NATIVE = 23;
700
- const MAX_BUYERS_ERC20 = 15;
701
- 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;
702
700
  if (buyerPrivateKeys.length === 0) {
703
701
  throw new Error('至少需要一个买方钱包');
704
702
  }
@@ -833,12 +831,10 @@ export async function pancakeQuickBatchSwapMerkle(params) {
833
831
  sellerRequired = bribeAmount + sellerGasCost;
834
832
  }
835
833
  else {
836
- // ERC20 模式(已移除授权):
837
- // - 卖方 Gas: 贿赂(21000) + 卖出(gasLimit) + N个ERC20转账(65000 each) + N个BNB Gas转账(21000 each) + 利润(21000)
838
- // - 买方 Gas: N个买入(gasLimit each) + N个FLAT_FEE
839
- sellerGasCost = gasPrice * (21000n + finalGasLimit + (ERC20_TRANSFER_GAS + 21000n) * BigInt(buyers.length) + 21000n);
840
- const buyerGasNeeded = gasPrice * finalGasLimit * BigInt(buyers.length) + FLAT_FEE * BigInt(buyers.length);
841
- 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;
842
838
  }
843
839
  if (sellerBalance < sellerRequired) {
844
840
  throw new Error(`主钱包 BNB 余额不足: 需要约 ${ethers.formatEther(sellerRequired)} BNB (贿赂: ${ethers.formatEther(bribeAmount)}, Gas: ${ethers.formatEther(sellerGasCost)}), 实际 ${ethers.formatEther(sellerBalance)} BNB`);
@@ -905,7 +901,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
905
901
  }
906
902
  }
907
903
  else {
908
- // ✅ ERC20 模式:ERC20 transfer 调用
904
+ // ✅ ERC20 模式:ERC20 transfer 调用(子钱包已预留 BNB,不需要转 Gas)
909
905
  const erc20Interface = new ethers.Interface([
910
906
  'function transfer(address to, uint256 amount) returns (bool)'
911
907
  ]);
@@ -926,20 +922,6 @@ export async function pancakeQuickBatchSwapMerkle(params) {
926
922
  });
927
923
  transferTxs.push(transferTx);
928
924
  }
929
- // ERC20 模式:额外转账 Gas 费用给买家(用于支付买入 Gas 和 FLAT_FEE)
930
- for (let i = 0; i < buyers.length; i++) {
931
- const buyerGasCost = gasPrice * finalGasLimit + FLAT_FEE;
932
- const gasTx = await seller.signTransaction({
933
- to: buyers[i].address,
934
- value: buyerGasCost,
935
- nonce: sellerNonce++,
936
- gasPrice,
937
- gasLimit: 21000n,
938
- chainId: context.chainId,
939
- type: txType
940
- });
941
- transferTxs.push(gasTx);
942
- }
943
925
  }
944
926
  console.log(`[pancakeQuickBatchSwapMerkle] ${transferTxs.length} 笔转账交易已签名`);
945
927
  // ==================== 4. 买入交易 ====================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.14",
3
+ "version": "1.4.16",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",