four-flap-meme-sdk 1.4.83 → 1.4.85

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.
@@ -4,10 +4,11 @@
4
4
  * 功能:钱包B先买入代币 → 钱包A卖出相同数量 → 原子执行
5
5
  */
6
6
  import { CommonBundleConfig } from '../../utils/bundle-helpers.js';
7
- import { FourSignConfig } from './types.js';
7
+ import { FourSignConfig, UserType } from './types.js';
8
8
  import type { GeneratedWallet } from '../../utils/wallet.js';
9
9
  export interface FourBuyFirstSignConfig extends FourSignConfig {
10
10
  reserveGasBNB?: number;
11
+ userType?: UserType;
11
12
  }
12
13
  export interface FourBuyFirstConfig extends CommonBundleConfig {
13
14
  apiKey: string;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
8
- import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA } from '../../utils/constants.js';
8
+ import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA, PROFIT_CONFIG } from '../../utils/constants.js';
9
9
  import { TM_ABI, HELPER3_ABI, TM_ADDRESS } from './swap-internal.js';
10
10
  import { getTxType, getGasPriceConfig, getProfitRecipient, getBribeAmount } from './config.js';
11
11
  import { trySell } from '../tm.js';
@@ -26,8 +26,15 @@ const BRIBE_TX_COUNT = 1;
26
26
  const PROFIT_TX_COUNT = PROFIT_HOP_COUNT + 2; // 2 + 2 = 4
27
27
  /** 最大买卖交易数 */
28
28
  const MAX_SWAP_TX_COUNT = MAX_BUNDLE_SIGNATURES - BRIBE_TX_COUNT - PROFIT_TX_COUNT; // 50 - 1 - 4 = 45
29
- /** 每笔交易利润比例(基点):6 bps = 0.06% = 万分之六 */
30
- const PROFIT_RATE_PER_TX_BPS = 6;
29
+ /**
30
+ * 根据 userType 获取每笔交易的利润率
31
+ */
32
+ function getProfitRatePerTxBps(userType) {
33
+ if (userType === 'v1') {
34
+ return PROFIT_CONFIG.RATE_BPS_V1;
35
+ }
36
+ return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认
37
+ }
31
38
  /**
32
39
  * 验证买卖笔数
33
40
  */
@@ -104,9 +111,9 @@ export async function fourBundleBuyFirstMerkle(params) {
104
111
  throw new Error('单钱包模式需要提供 buyerPrivateKey 和 sellerPrivateKey');
105
112
  }
106
113
  validateSwapCounts(buyCount, sellCount);
107
- // ✅ 计算利润比例:每笔万分之3
114
+ // ✅ 计算利润比例(根据 userType 动态调整)
108
115
  const totalTxCount = buyCount + sellCount;
109
- const profitRateBps = PROFIT_RATE_PER_TX_BPS * totalTxCount;
116
+ const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
110
117
  const chainIdNum = config.chainId ?? 56;
111
118
  const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
112
119
  chainId: chainIdNum,
@@ -325,9 +332,9 @@ async function fourBundleBuyFirstMultiWallet(params) {
325
332
  throw new Error('卖方钱包数量不能为0');
326
333
  // 验证总交易数不超过限制
327
334
  validateSwapCounts(buyCount, sellCount);
328
- // ✅ 计算利润比例:每笔万分之6
335
+ // ✅ 计算利润比例(根据 userType 动态调整)
329
336
  const totalTxCount = buyCount + sellCount;
330
- const profitRateBps = PROFIT_RATE_PER_TX_BPS * totalTxCount;
337
+ const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
331
338
  const chainIdNum = config.chainId ?? 56;
332
339
  const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
333
340
  chainId: chainIdNum,
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { CommonBundleConfig } from '../../utils/bundle-helpers.js';
7
7
  import { type GeneratedWallet } from '../../utils/wallet.js';
8
+ export type UserType = 'v0' | 'v1';
8
9
  export interface FourSwapSignConfig {
9
10
  rpcUrl: string;
10
11
  gasLimit?: number | bigint;
@@ -14,6 +15,7 @@ export interface FourSwapSignConfig {
14
15
  txType?: 0 | 2;
15
16
  chainId?: number;
16
17
  reserveGasBNB?: number;
18
+ userType?: UserType;
17
19
  bribeAmount?: number;
18
20
  }
19
21
  export interface FourSwapConfig extends CommonBundleConfig {
@@ -7,6 +7,18 @@ import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { calculateSellAmount } from '../../utils/swap-helpers.js';
8
8
  import { NonceManager, getOptimizedGasPrice, getGasLimit, getGasPriceConfig, getTxType, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
9
9
  import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from '../../utils/constants.js';
10
+ /**
11
+ * 根据 userType 计算利润率
12
+ */
13
+ function getProfitRateBps(userType) {
14
+ if (userType === 'v0') {
15
+ return PROFIT_CONFIG.RATE_BPS_V0; // 0.06%
16
+ }
17
+ else if (userType === 'v1') {
18
+ return PROFIT_CONFIG.RATE_BPS_V1; // 0.05%
19
+ }
20
+ return PROFIT_CONFIG.RATE_BPS_V0; // 默认 0.06%
21
+ }
10
22
  import { TM_ABI, HELPER3_ABI, TM_ADDRESS } from './swap-internal.js';
11
23
  import { getBribeAmount, getProfitRecipient } from './config.js';
12
24
  import { generateWallets } from '../../utils/wallet.js';
@@ -136,7 +148,7 @@ export async function fourBundleSwapMerkle(params) {
136
148
  const needApproval = currentAllowance < APPROVAL_THRESHOLD;
137
149
  // 利润配置
138
150
  const extractProfit = true;
139
- const profitRateBps = PROFIT_CONFIG.RATE_BPS_SWAP;
151
+ const profitRateBps = getProfitRateBps(config.userType);
140
152
  const profitAmount = extractProfit && sellerWillGetBNB > 0n
141
153
  ? (sellerWillGetBNB * BigInt(profitRateBps)) / 10000n
142
154
  : 0n;
@@ -358,7 +370,7 @@ export async function fourBatchSwapMerkle(params) {
358
370
  const APPROVAL_THRESHOLD = ethers.parseUnits('1000000000', decimals);
359
371
  const needApproval = currentAllowance < APPROVAL_THRESHOLD;
360
372
  // 利润配置
361
- const profitRateBps = PROFIT_CONFIG.RATE_BPS_SWAP;
373
+ const profitRateBps = getProfitRateBps(config.userType);
362
374
  const profitAmount = totalBuyerFunds > 0n
363
375
  ? (totalBuyerFunds * BigInt(profitRateBps)) / 10000n
364
376
  : 0n;
@@ -578,8 +590,8 @@ export async function fourQuickBatchSwapMerkle(params) {
578
590
  const estimatedBNBOut = sellQuote.funds;
579
591
  console.log(`[fourQuickBatchSwapMerkle] 卖出数量: ${ethers.formatUnits(sellAmountWei, decimals)}`);
580
592
  console.log(`[fourQuickBatchSwapMerkle] 预估卖出所得: ${ethers.formatEther(estimatedBNBOut)} BNB`);
581
- // ✅ 计算利润(万分之六)
582
- const profitRateBps = PROFIT_CONFIG.RATE_BPS_SWAP;
593
+ // ✅ 计算利润(根据 userType 动态调整)
594
+ const profitRateBps = getProfitRateBps(config.userType);
583
595
  const profitAmount = estimatedBNBOut > 0n
584
596
  ? (estimatedBNBOut * BigInt(profitRateBps)) / 10000n
585
597
  : 0n;
@@ -244,6 +244,12 @@ export type DisperseMerkleParams = {
244
244
  export type TokenPoolType = 'flap' | 'four' | 'v2' | 'v3';
245
245
  /** 报价代币类型(池子的计价代币) */
246
246
  export type QuoteTokenType = 'native' | 'usdt' | 'usdc';
247
+ /**
248
+ * 用户类型(用于利润费率)
249
+ * - v0: 万分之6 (6 bps = 0.06%)
250
+ * - v1: 万分之5 (5 bps = 0.05%)
251
+ */
252
+ export type UserType = 'v0' | 'v1';
247
253
  export type DisperseSignParams = {
248
254
  fromPrivateKey: string;
249
255
  recipients: string[];
@@ -266,6 +272,8 @@ export type DisperseSignParams = {
266
272
  tokenPoolType?: TokenPoolType;
267
273
  /** ✅ 新增:报价代币类型(池子的计价代币),默认 'native'(BNB/MON) */
268
274
  quoteToken?: QuoteTokenType;
275
+ /** ✅ 新增:用户类型(用于利润费率),v0=万分之6,v1=万分之5,默认 v0 */
276
+ userType?: UserType;
269
277
  };
270
278
  /**
271
279
  * ✅ 分发结果(简化版)
@@ -321,6 +329,8 @@ export type SweepSignParams = {
321
329
  tokenPoolType?: TokenPoolType;
322
330
  /** ✅ 新增:报价代币类型(池子的计价代币),默认 'native'(BNB/MON) */
323
331
  quoteToken?: QuoteTokenType;
332
+ /** ✅ 新增:用户类型(用于利润费率),v0=万分之6,v1=万分之5,默认 v0 */
333
+ userType?: UserType;
324
334
  };
325
335
  /**
326
336
  * ✅ 归集结果(简化版)
@@ -3,13 +3,23 @@ import { getOptimizedGasPrice, NonceManager, buildProfitHopTransactions, PROFIT_
3
3
  import { PROFIT_CONFIG, ZERO_ADDRESS } from '../../utils/constants.js';
4
4
  import { getTxType, getGasPriceConfig, shouldExtractProfit, getProfitRecipient } from './config.js';
5
5
  import { getErc20DecimalsMerkle as _getErc20DecimalsMerkle, generateHopWallets as _generateHopWallets, normalizeAmounts as _normalizeAmounts, batchGetBalances as _batchGetBalances, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress } from './internal.js';
6
- // ==================== 本地利润计算(万分之三)====================
7
6
  /**
8
- * 计算利润金额(万分之三)
9
- * 归集和分散专用:3 bps = 0.03%
7
+ * 根据用户类型获取利润费率(bps)
8
+ * - v0: 万分之6 (6 bps = 0.06%)
9
+ * - v1: 万分之5 (5 bps = 0.05%)
10
10
  */
11
- function calculateProfit(amount) {
12
- const profit = (amount * BigInt(PROFIT_CONFIG.RATE_BPS_CAPITAL)) / 10000n;
11
+ function getProfitRateBps(userType) {
12
+ if (userType === 'v1')
13
+ return PROFIT_CONFIG.RATE_BPS_V1; // v1 用户:万分之5
14
+ return PROFIT_CONFIG.RATE_BPS_V0; // v0 用户(默认):万分之6
15
+ }
16
+ /**
17
+ * 计算利润金额
18
+ * ✅ 归集和分散专用:根据 userType 使用不同费率
19
+ */
20
+ function calculateProfit(amount, userType) {
21
+ const rateBps = getProfitRateBps(userType);
22
+ const profit = (amount * BigInt(rateBps)) / 10000n;
13
23
  const remaining = amount - profit;
14
24
  return { profit, remaining };
15
25
  }
@@ -196,7 +206,7 @@ async function getTokenToNativeQuote(provider, tokenAddress, tokenAmount, chainI
196
206
  * ✅ 优化版:支持 startNonce 参数避免并行调用时的 nonce 冲突
197
207
  */
198
208
  export async function disperseWithBundleMerkle(params) {
199
- const { fromPrivateKey, recipients, amount, amounts, tokenAddress, tokenDecimals, hopCount = 0, hopPrivateKeys, items, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native' } = params;
209
+ const { fromPrivateKey, recipients, amount, amounts, tokenAddress, tokenDecimals, hopCount = 0, hopPrivateKeys, items, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native', userType = 'v0' } = params;
200
210
  // 快速返回空结果
201
211
  if (!recipients || recipients.length === 0) {
202
212
  return {
@@ -268,7 +278,7 @@ export async function disperseWithBundleMerkle(params) {
268
278
  totalAmountBeforeProfit += originalAmount;
269
279
  let actualAmount = originalAmount;
270
280
  if (extractProfit) {
271
- const { profit, remaining } = calculateProfit(originalAmount);
281
+ const { profit, remaining } = calculateProfit(originalAmount, userType);
272
282
  actualAmount = remaining;
273
283
  totalProfit += profit;
274
284
  }
@@ -313,7 +323,7 @@ export async function disperseWithBundleMerkle(params) {
313
323
  totalAmountBeforeProfit += originalAmount;
314
324
  let actualAmount = originalAmount;
315
325
  if (extractProfit) {
316
- const { profit, remaining } = calculateProfit(originalAmount);
326
+ const { profit, remaining } = calculateProfit(originalAmount, userType);
317
327
  actualAmount = remaining;
318
328
  totalTokenProfit += profit; // 累计 ERC20 代币利润
319
329
  }
@@ -410,7 +420,7 @@ export async function disperseWithBundleMerkle(params) {
410
420
  totalAmountBeforeProfit += originalAmountWei;
411
421
  let amountWei = originalAmountWei;
412
422
  if (extractProfit) {
413
- const { profit, remaining } = calculateProfit(originalAmountWei);
423
+ const { profit, remaining } = calculateProfit(originalAmountWei, userType);
414
424
  amountWei = remaining;
415
425
  if (isNative) {
416
426
  totalProfit += profit; // 原生币直接累加
@@ -631,7 +641,7 @@ export async function disperseWithBundleMerkle(params) {
631
641
  * ✅ 优化版:支持 startNonce 参数避免并行调用时的 nonce 冲突
632
642
  */
633
643
  export async function sweepWithBundleMerkle(params) {
634
- const { sourcePrivateKeys, target, ratioPct, ratios, amount, amounts, tokenAddress, tokenDecimals, skipIfInsufficient = true, hopCount = 0, hopPrivateKeys, sources, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native' } = params;
644
+ const { sourcePrivateKeys, target, ratioPct, ratios, amount, amounts, tokenAddress, tokenDecimals, skipIfInsufficient = true, hopCount = 0, hopPrivateKeys, sources, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native', userType = 'v0' } = params;
635
645
  // 快速返回空结果
636
646
  if (!sourcePrivateKeys || sourcePrivateKeys.length === 0) {
637
647
  return {
@@ -754,7 +764,7 @@ export async function sweepWithBundleMerkle(params) {
754
764
  }
755
765
  // 累计总利润
756
766
  if (extractProfit && toSend > 0n) {
757
- const { profit } = calculateProfit(toSend);
767
+ const { profit } = calculateProfit(toSend, userType);
758
768
  totalProfit += profit;
759
769
  }
760
770
  }
@@ -772,7 +782,7 @@ export async function sweepWithBundleMerkle(params) {
772
782
  totalProfit = 0n;
773
783
  for (let i = 0; i < sweepAmounts.length; i++) {
774
784
  if (sweepAmounts[i] > 0n) {
775
- totalProfit += calculateProfit(sweepAmounts[i]).profit;
785
+ totalProfit += calculateProfit(sweepAmounts[i], userType).profit;
776
786
  }
777
787
  }
778
788
  }
@@ -907,7 +917,7 @@ export async function sweepWithBundleMerkle(params) {
907
917
  }
908
918
  // 累计总代币利润(ERC20 归集)
909
919
  if (extractProfit && toSend > 0n) {
910
- const { profit } = calculateProfit(toSend);
920
+ const { profit } = calculateProfit(toSend, userType);
911
921
  totalProfit += profit; // 先累计代币利润
912
922
  }
913
923
  }
@@ -1329,7 +1339,7 @@ export async function sweepWithBundleMerkle(params) {
1329
1339
  let totalTokenProfit = 0n;
1330
1340
  for (let i = 0; i < sweepAmounts.length; i++) {
1331
1341
  if (sweepAmounts[i] > 0n) {
1332
- const { profit } = calculateProfit(sweepAmounts[i]);
1342
+ const { profit } = calculateProfit(sweepAmounts[i], userType);
1333
1343
  if (isNative) {
1334
1344
  totalProfit += profit;
1335
1345
  }
@@ -27,7 +27,7 @@ export declare const FLAP_ORIGINAL_PORTAL_ADDRESSES: {
27
27
  */
28
28
  export declare const FLAP_TOKEN_IMPL_ADDRESSES: {
29
29
  readonly BSC_NORMAL: "0x8b4329947e34b6d56d71a3385cac122bade7d78d";
30
- readonly BSC_TAXED: "0x5dd913731C12aD8DF3E574859FDe45412bF4aaD9";
30
+ readonly BSC_TAXED: "0x29e6383F0ce68507b5A72a53c2B118a118332aA8";
31
31
  readonly BASE: "0xF3c514E04f83166E80718f29f0d34F206be40A0A";
32
32
  readonly XLAYER: "0x12Dc83157Bf1cfCB8Db5952b3ba5bb56Cc38f8C9";
33
33
  readonly MORPH: "0x8b4329947e34b6d56d71a3385cac122bade7d78d";
@@ -29,7 +29,7 @@ export const FLAP_ORIGINAL_PORTAL_ADDRESSES = {
29
29
  */
30
30
  export const FLAP_TOKEN_IMPL_ADDRESSES = {
31
31
  BSC_NORMAL: '0x8b4329947e34b6d56d71a3385cac122bade7d78d',
32
- BSC_TAXED: '0x5dd913731C12aD8DF3E574859FDe45412bF4aaD9',
32
+ BSC_TAXED: '0x29e6383F0ce68507b5A72a53c2B118a118332aA8', // 官方文档: https://docs.flap.sh/flap/developers/deployed-contract-addresses
33
33
  BASE: '0xF3c514E04f83166E80718f29f0d34F206be40A0A',
34
34
  XLAYER: '0x12Dc83157Bf1cfCB8Db5952b3ba5bb56Cc38f8C9',
35
35
  MORPH: '0x8b4329947e34b6d56d71a3385cac122bade7d78d', // 暂时使用 BSC NORMAL 地址
@@ -83,10 +83,37 @@ export async function createTokenWithBundleBuyMerkle(params) {
83
83
  const portalAddr = FLAP_PORTAL_ADDRESSES[chain];
84
84
  const originalPortalAddr = FLAP_ORIGINAL_PORTAL_ADDRESSES[chain];
85
85
  const portal = new ethers.Contract(originalPortalAddr, PORTAL_ABI, devWallet);
86
- const useV3 = !!params.extensionID;
86
+ // 判断使用哪个版本的 newToken
87
+ // V4: 提供了 dexId 或 lpFeeProfile(支持 DEX 选择和 LP 费率配置)
88
+ // V3: 提供了 extensionID(支持扩展数据)
89
+ // V2: 默认
90
+ const useV4 = params.dexId !== undefined || params.lpFeeProfile !== undefined;
91
+ const useV3 = !useV4 && !!params.extensionID;
87
92
  // ✅ 优化:并行获取 gasPrice、devWallet nonce 和 createTx
88
- const createTxPromise = useV3
89
- ? portal.newTokenV3.populateTransaction({
93
+ let createTxPromise;
94
+ if (useV4) {
95
+ // V4: 支持 DEX ID 和 LP 费率配置
96
+ createTxPromise = portal.newTokenV4.populateTransaction({
97
+ name: tokenInfo.name,
98
+ symbol: tokenInfo.symbol,
99
+ meta: tokenInfo.meta,
100
+ dexThresh: (params.dexThresh ?? 1) & 0xff,
101
+ salt: params.salt ?? '0x' + '00'.repeat(32),
102
+ taxRate: (params.taxRate ?? 0) & 0xffff,
103
+ migratorType: (params.migratorType ?? 0) & 0xff,
104
+ quoteToken: params.quoteToken || ZERO_ADDRESS,
105
+ quoteAmt: 0n,
106
+ beneficiary: devWallet.address,
107
+ permitData: '0x',
108
+ extensionID: params.extensionID ?? '0x' + '00'.repeat(32),
109
+ extensionData: params.extensionData ?? '0x',
110
+ dexId: (params.dexId ?? 0) & 0xff,
111
+ lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff
112
+ });
113
+ }
114
+ else if (useV3) {
115
+ // V3: 支持扩展数据
116
+ createTxPromise = portal.newTokenV3.populateTransaction({
90
117
  name: tokenInfo.name,
91
118
  symbol: tokenInfo.symbol,
92
119
  meta: tokenInfo.meta,
@@ -100,8 +127,11 @@ export async function createTokenWithBundleBuyMerkle(params) {
100
127
  permitData: '0x',
101
128
  extensionID: params.extensionID,
102
129
  extensionData: params.extensionData ?? '0x'
103
- })
104
- : portal.newTokenV2.populateTransaction({
130
+ });
131
+ }
132
+ else {
133
+ // V2: 基础版本
134
+ createTxPromise = portal.newTokenV2.populateTransaction({
105
135
  name: tokenInfo.name,
106
136
  symbol: tokenInfo.symbol,
107
137
  meta: tokenInfo.meta,
@@ -114,6 +144,7 @@ export async function createTokenWithBundleBuyMerkle(params) {
114
144
  beneficiary: devWallet.address,
115
145
  permitData: '0x'
116
146
  });
147
+ }
117
148
  const [gasPrice, createTxUnsigned, devNonce] = await Promise.all([
118
149
  resolveGasPrice(provider, config),
119
150
  createTxPromise,
@@ -66,6 +66,14 @@ export interface FlapCreateToDexParams {
66
66
  migratorType?: number;
67
67
  taxRate?: number;
68
68
  salt?: string;
69
+ /** V4 参数:DEX ID(0=DEX0, 1=DEX1, 2=DEX2) */
70
+ dexId?: number;
71
+ /** V4 参数:LP 费率档位(0=STANDARD 0.25%, 1=LOW 0.01%, 2=HIGH 1%) */
72
+ lpFeeProfile?: number;
73
+ /** V3 扩展 ID */
74
+ extensionID?: string;
75
+ /** V3 扩展数据 */
76
+ extensionData?: string;
69
77
  /** 配置 */
70
78
  config: CreateToDexSignConfig;
71
79
  }
@@ -12,6 +12,19 @@ import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_
12
12
  import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
13
13
  import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
14
14
  import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
15
+ // ==================== ERC20 ABI ====================
16
+ const ERC20_ABI = [
17
+ {
18
+ type: "function",
19
+ name: "approve",
20
+ inputs: [
21
+ { name: "spender", type: "address" },
22
+ { name: "amount", type: "uint256" }
23
+ ],
24
+ outputs: [{ name: "", type: "bool" }],
25
+ stateMutability: "nonpayable"
26
+ }
27
+ ];
15
28
  // ==================== 链常量 ====================
16
29
  const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
17
30
  const BSC_PANCAKE_V3_ROUTER = ADDRESSES.BSC.PancakeV3Router;
@@ -57,9 +70,36 @@ const PANCAKE_V3_ROUTER_ABI = [
57
70
  ],
58
71
  "outputs": [{ "name": "amountOut", "type": "uint256" }],
59
72
  "stateMutability": "payable"
60
- }
73
+ },
61
74
  ];
75
+ // ==================== V3 费率配置 ====================
76
+ // USD1/USDT 使用 100 bps (0.01%),其他使用 2500 bps (0.25%)
77
+ const USD1_V3_FEE = 100;
78
+ const DEFAULT_V3_FEE = 2500;
62
79
  // ==================== 工具函数 ====================
80
+ /** 构建 ERC20 approve 交易 */
81
+ async function buildApproveTransaction(wallet, tokenAddress, spenderAddress, amount, nonce, gasPrice, txType) {
82
+ const erc20Interface = new ethers.Interface(ERC20_ABI);
83
+ const data = erc20Interface.encodeFunctionData('approve', [spenderAddress, amount]);
84
+ const tx = {
85
+ to: tokenAddress,
86
+ data,
87
+ from: wallet.address,
88
+ nonce,
89
+ gasLimit: BigInt(100000), // approve 交易 gas 较低
90
+ chainId: 56,
91
+ type: txType
92
+ };
93
+ if (txType === 2) {
94
+ const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
95
+ tx.maxFeePerGas = gasPrice;
96
+ tx.maxPriorityFeePerGas = priorityFee;
97
+ }
98
+ else {
99
+ tx.gasPrice = gasPrice;
100
+ }
101
+ return wallet.signTransaction(tx);
102
+ }
63
103
  function getGasLimit(config, defaultGas = 800000) {
64
104
  if (config.gasLimit !== undefined) {
65
105
  return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
@@ -199,19 +239,67 @@ export async function flapBundleCreateToDex(params) {
199
239
  const devNonce = noncesMap.get(devAddr);
200
240
  noncesMap.set(devAddr, devNonce + 1);
201
241
  const originalPortal = new Contract(originalPortalAddress, PORTAL_ABI, devWallet);
202
- const createUnsigned = await originalPortal.newTokenV2.populateTransaction({
203
- name: tokenInfo.name,
204
- symbol: tokenInfo.symbol,
205
- meta: tokenInfo.meta,
206
- dexThresh: (params.dexThresh ?? 1) & 0xff,
207
- salt: params.salt ?? '0x' + '00'.repeat(32),
208
- taxRate: (params.taxRate ?? 0) & 0xffff,
209
- migratorType: (params.migratorType ?? 0) & 0xff,
210
- quoteToken: inputToken,
211
- quoteAmt: 0n,
212
- beneficiary: devWallet.address,
213
- permitData: '0x'
214
- });
242
+ // 判断使用哪个版本的 newToken
243
+ // V4: 提供了 dexId 或 lpFeeProfile(支持 DEX 选择和 LP 费率配置)
244
+ // V3: 提供了 extensionID(支持扩展数据)
245
+ // V2: 默认
246
+ const useV4 = params.dexId !== undefined || params.lpFeeProfile !== undefined;
247
+ const useV3 = !useV4 && !!params.extensionID;
248
+ let createUnsigned;
249
+ if (useV4) {
250
+ // V4: 支持 DEX ID 和 LP 费率配置(用于选择池子费率)
251
+ createUnsigned = await originalPortal.newTokenV4.populateTransaction({
252
+ name: tokenInfo.name,
253
+ symbol: tokenInfo.symbol,
254
+ meta: tokenInfo.meta,
255
+ dexThresh: (params.dexThresh ?? 1) & 0xff,
256
+ salt: params.salt ?? '0x' + '00'.repeat(32),
257
+ taxRate: (params.taxRate ?? 0) & 0xffff,
258
+ migratorType: (params.migratorType ?? 0) & 0xff,
259
+ quoteToken: inputToken,
260
+ quoteAmt: 0n,
261
+ beneficiary: devWallet.address,
262
+ permitData: '0x',
263
+ extensionID: params.extensionID ?? '0x' + '00'.repeat(32),
264
+ extensionData: params.extensionData ?? '0x',
265
+ dexId: (params.dexId ?? 0) & 0xff,
266
+ lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff
267
+ });
268
+ }
269
+ else if (useV3) {
270
+ // V3: 支持扩展数据
271
+ createUnsigned = await originalPortal.newTokenV3.populateTransaction({
272
+ name: tokenInfo.name,
273
+ symbol: tokenInfo.symbol,
274
+ meta: tokenInfo.meta,
275
+ dexThresh: (params.dexThresh ?? 1) & 0xff,
276
+ salt: params.salt ?? '0x' + '00'.repeat(32),
277
+ taxRate: (params.taxRate ?? 0) & 0xffff,
278
+ migratorType: (params.migratorType ?? 0) & 0xff,
279
+ quoteToken: inputToken,
280
+ quoteAmt: 0n,
281
+ beneficiary: devWallet.address,
282
+ permitData: '0x',
283
+ extensionID: params.extensionID,
284
+ extensionData: params.extensionData ?? '0x'
285
+ });
286
+ }
287
+ else {
288
+ // V2: 基础版本
289
+ createUnsigned = await originalPortal.newTokenV2.populateTransaction({
290
+ name: tokenInfo.name,
291
+ symbol: tokenInfo.symbol,
292
+ meta: tokenInfo.meta,
293
+ dexThresh: (params.dexThresh ?? 1) & 0xff,
294
+ salt: params.salt ?? '0x' + '00'.repeat(32),
295
+ taxRate: (params.taxRate ?? 0) & 0xffff,
296
+ migratorType: (params.migratorType ?? 0) & 0xff,
297
+ quoteToken: inputToken,
298
+ quoteAmt: 0n,
299
+ beneficiary: devWallet.address,
300
+ permitData: '0x'
301
+ });
302
+ }
215
303
  const createTx = {
216
304
  ...createUnsigned,
217
305
  from: devWallet.address,
@@ -232,17 +320,27 @@ export async function flapBundleCreateToDex(params) {
232
320
  }
233
321
  // 3. 内盘买入交易(包含毕业触发)
234
322
  // 最后一个买入交易会触发毕业,需要更多 gas
323
+ // ✅ ERC20 需要先 approve,再买入
235
324
  const curveBuyTxPromises = curveWallets.map(async ({ wallet }, i) => {
236
325
  const addr = wallet.address.toLowerCase();
237
- const nonce = noncesMap.get(addr);
238
- noncesMap.set(addr, nonce + 1);
326
+ const signedTxs = [];
327
+ // ERC20: 先构建 approve 交易
328
+ if (!useNativeToken) {
329
+ const approveNonce = noncesMap.get(addr);
330
+ noncesMap.set(addr, approveNonce + 1);
331
+ const approveTx = await buildApproveTransaction(wallet, quoteToken, portalAddress, curveBuyAmounts[i], approveNonce, gasPrice, txType);
332
+ signedTxs.push(approveTx);
333
+ }
334
+ // 构建买入交易
335
+ const buyNonce = noncesMap.get(addr);
336
+ noncesMap.set(addr, buyNonce + 1);
239
337
  const portal = new Contract(portalAddress, PORTAL_ABI, wallet);
240
338
  const unsigned = await portal.swapExactInput.populateTransaction({
241
339
  inputToken,
242
340
  outputToken: tokenAddress,
243
341
  inputAmount: curveBuyAmounts[i],
244
342
  minOutputAmount: 0n,
245
- permitData: '0x'
343
+ permitData: '0x' // 不使用 permit,使用链上 approve
246
344
  }, useNativeToken ? { value: curveBuyAmounts[i] } : {});
247
345
  // 最后一个买家触发毕业,需要更多 gas
248
346
  const isLastBuyer = i === curveWallets.length - 1;
@@ -250,7 +348,7 @@ export async function flapBundleCreateToDex(params) {
250
348
  const tx = {
251
349
  ...unsigned,
252
350
  from: wallet.address,
253
- nonce,
351
+ nonce: buyNonce,
254
352
  gasLimit: buyGasLimit,
255
353
  chainId: 56,
256
354
  type: txType,
@@ -263,67 +361,63 @@ export async function flapBundleCreateToDex(params) {
263
361
  else {
264
362
  tx.gasPrice = gasPrice;
265
363
  }
266
- return wallet.signTransaction(tx);
364
+ const signedBuy = await wallet.signTransaction(tx);
365
+ signedTxs.push(signedBuy);
366
+ return signedTxs;
267
367
  });
268
- const signedCurveBuys = await Promise.all(curveBuyTxPromises);
269
- allTransactions.push(...signedCurveBuys);
368
+ const curveBuyResults = await Promise.all(curveBuyTxPromises);
369
+ // 展平数组:每个钱包可能有 [approve, buy] 或只有 [buy]
370
+ curveBuyResults.forEach(txs => allTransactions.push(...txs));
270
371
  // 4. 外盘买入交易(PancakeSwap)
372
+ // ✅ ERC20 需要先 approve,再 swap
271
373
  if (enableDexBuy && dexWallets.length > 0) {
272
374
  const dexBuyTxPromises = dexWallets.map(async ({ wallet }, i) => {
273
375
  const addr = wallet.address.toLowerCase();
274
- const nonce = noncesMap.get(addr);
275
- noncesMap.set(addr, nonce + 1);
376
+ const signedTxs = [];
276
377
  const buyAmount = dexBuyAmounts[i];
277
378
  const smartRouter = dexPoolType === 'v3' ? BSC_PANCAKE_V3_ROUTER : BSC_PANCAKE_V2_ROUTER;
278
- let calldata;
379
+ // ✅ 根据 quoteToken 选择 V3 费率
380
+ const actualV3Fee = v3Fee || (useNativeToken ? DEFAULT_V3_FEE : USD1_V3_FEE);
381
+ // ✅ ERC20: 先构建 approve 交易
382
+ if (!useNativeToken) {
383
+ const approveNonce = noncesMap.get(addr);
384
+ noncesMap.set(addr, approveNonce + 1);
385
+ const approveTx = await buildApproveTransaction(wallet, quoteToken, smartRouter, buyAmount, approveNonce, gasPrice, txType);
386
+ signedTxs.push(approveTx);
387
+ }
388
+ // 构建买入交易
389
+ const buyNonce = noncesMap.get(addr);
390
+ noncesMap.set(addr, buyNonce + 1);
391
+ let multicallData = [];
279
392
  let value;
393
+ const routerInterface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
280
394
  if (dexPoolType === 'v3') {
281
- if (useNativeToken) {
282
- const params = {
283
- tokenIn: BSC_WBNB,
284
- tokenOut: tokenAddress,
285
- fee: v3Fee,
286
- recipient: wallet.address,
287
- amountIn: buyAmount,
288
- amountOutMinimum: 0n,
289
- sqrtPriceLimitX96: 0n
290
- };
291
- const exactInputSingleData = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('exactInputSingle', [params]);
292
- calldata = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('multicall', [[exactInputSingleData]]);
293
- value = buyAmount;
294
- }
295
- else {
296
- const params = {
297
- tokenIn: quoteToken,
298
- tokenOut: tokenAddress,
299
- fee: v3Fee,
300
- recipient: wallet.address,
301
- amountIn: buyAmount,
302
- amountOutMinimum: 0n,
303
- sqrtPriceLimitX96: 0n
304
- };
305
- const exactInputSingleData = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('exactInputSingle', [params]);
306
- calldata = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('multicall', [[exactInputSingleData]]);
307
- value = 0n;
308
- }
395
+ // V3: exactInputSingle
396
+ const params = {
397
+ tokenIn: useNativeToken ? BSC_WBNB : quoteToken,
398
+ tokenOut: tokenAddress,
399
+ fee: actualV3Fee,
400
+ recipient: wallet.address,
401
+ amountIn: buyAmount,
402
+ amountOutMinimum: 0n,
403
+ sqrtPriceLimitX96: 0n
404
+ };
405
+ multicallData = [routerInterface.encodeFunctionData('exactInputSingle', [params])];
406
+ value = useNativeToken ? buyAmount : 0n;
309
407
  }
310
408
  else {
311
- if (useNativeToken) {
312
- const swapData = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('swapExactTokensForTokens', [buyAmount, 0n, [BSC_WBNB, tokenAddress], wallet.address]);
313
- calldata = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('multicall', [[swapData]]);
314
- value = buyAmount;
315
- }
316
- else {
317
- const swapData = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('swapExactTokensForTokens', [buyAmount, 0n, [quoteToken, tokenAddress], wallet.address]);
318
- calldata = new ethers.Interface(PANCAKE_V3_ROUTER_ABI).encodeFunctionData('multicall', [[swapData]]);
319
- value = 0n;
320
- }
409
+ // V2: swapExactTokensForTokens
410
+ const path = useNativeToken ? [BSC_WBNB, tokenAddress] : [quoteToken, tokenAddress];
411
+ const swapData = routerInterface.encodeFunctionData('swapExactTokensForTokens', [buyAmount, 0n, path, wallet.address]);
412
+ multicallData = [swapData];
413
+ value = useNativeToken ? buyAmount : 0n;
321
414
  }
415
+ const calldata = routerInterface.encodeFunctionData('multicall', [multicallData]);
322
416
  const tx = {
323
417
  to: smartRouter,
324
418
  data: calldata,
325
419
  from: wallet.address,
326
- nonce,
420
+ nonce: buyNonce,
327
421
  gasLimit: BigInt(500000),
328
422
  chainId: 56,
329
423
  type: txType,
@@ -336,10 +430,13 @@ export async function flapBundleCreateToDex(params) {
336
430
  else {
337
431
  tx.gasPrice = gasPrice;
338
432
  }
339
- return wallet.signTransaction(tx);
433
+ const signedBuy = await wallet.signTransaction(tx);
434
+ signedTxs.push(signedBuy);
435
+ return signedTxs;
340
436
  });
341
- const signedDexBuys = await Promise.all(dexBuyTxPromises);
342
- allTransactions.push(...signedDexBuys);
437
+ const dexBuyResults = await Promise.all(dexBuyTxPromises);
438
+ // 展平数组:每个钱包可能有 [approve, buy] 或只有 [buy]
439
+ dexBuyResults.forEach(txs => allTransactions.push(...txs));
343
440
  }
344
441
  // 5. 利润多跳转账
345
442
  let profitHopWallets;
@@ -7,9 +7,11 @@ import { CommonBundleConfig } from '../../utils/bundle-helpers.js';
7
7
  import { FlapSignConfig } from './config.js';
8
8
  import type { GeneratedWallet } from '../../utils/wallet.js';
9
9
  export type FlapChain = 'bsc' | 'xlayer' | 'base';
10
+ export type UserType = 'v0' | 'v1';
10
11
  export interface FlapBuyFirstSignConfig extends FlapSignConfig {
11
12
  reserveGasETH?: number;
12
13
  skipQuoteOnError?: boolean;
14
+ userType?: UserType;
13
15
  }
14
16
  export interface FlapBuyFirstConfig extends CommonBundleConfig {
15
17
  apiKey: string;
@@ -66,8 +66,15 @@ const BRIBE_TX_COUNT = 1;
66
66
  const PROFIT_TX_COUNT = PROFIT_HOP_COUNT + 2; // 2 + 2 = 4
67
67
  /** 最大买卖交易数 */
68
68
  const MAX_SWAP_TX_COUNT = MAX_BUNDLE_SIGNATURES - BRIBE_TX_COUNT - PROFIT_TX_COUNT; // 50 - 1 - 4 = 45
69
- /** 每笔交易利润比例(基点):6 bps = 0.06% = 万分之六 */
70
- const PROFIT_RATE_PER_TX_BPS = 6;
69
+ /**
70
+ * 根据 userType 获取每笔交易的利润率
71
+ */
72
+ function getProfitRatePerTxBps(userType) {
73
+ if (userType === 'v1') {
74
+ return PROFIT_CONFIG.RATE_BPS_V1;
75
+ }
76
+ return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认
77
+ }
71
78
  /**
72
79
  * 验证买卖笔数
73
80
  */
@@ -124,9 +131,9 @@ export async function flapBundleBuyFirstMerkle(params) {
124
131
  throw new Error('单钱包模式需要提供 buyerPrivateKey 和 sellerPrivateKey');
125
132
  }
126
133
  validateSwapCounts(buyCount, sellCount);
127
- // ✅ 计算利润比例:每笔万分之3
134
+ // ✅ 计算利润比例(根据 userType 动态调整)
128
135
  const totalTxCount = buyCount + sellCount;
129
- const profitRateBps = PROFIT_RATE_PER_TX_BPS * totalTxCount;
136
+ const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
130
137
  const chainContext = createChainContext(chain, config.rpcUrl);
131
138
  const buyer = new Wallet(buyerPrivateKey, chainContext.provider);
132
139
  const seller = new Wallet(sellerPrivateKey, chainContext.provider);
@@ -404,12 +411,21 @@ async function estimateSellFunds(portal, tokenAddress, sellAmountWei, outputToke
404
411
  return 0n;
405
412
  }
406
413
  }
407
- function calculateProfitAmount(expectedFunds) {
414
+ /**
415
+ * 根据 userType 获取利润率(基点)
416
+ */
417
+ function getProfitRateBps(userType) {
418
+ if (userType === 'v1') {
419
+ return PROFIT_CONFIG.RATE_BPS_V1; // 0.05%
420
+ }
421
+ return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认 0.06%
422
+ }
423
+ function calculateProfitAmount(expectedFunds, userType) {
408
424
  if (expectedFunds <= 0n) {
409
425
  return 0n;
410
426
  }
411
- // 万分之六
412
- return (expectedFunds * BigInt(PROFIT_CONFIG.RATE_BPS_SWAP)) / 10000n;
427
+ const rateBps = getProfitRateBps(userType);
428
+ return (expectedFunds * BigInt(rateBps)) / 10000n;
413
429
  }
414
430
  /**
415
431
  * 计算多笔交易的利润金额
@@ -621,9 +637,9 @@ async function flapBundleBuyFirstMultiWallet(params) {
621
637
  throw new Error('卖方钱包数量不能为0');
622
638
  // 验证总交易数不超过限制
623
639
  validateSwapCounts(buyCount, sellCount);
624
- // ✅ 计算利润比例:每笔万分之6
640
+ // ✅ 计算利润比例(根据 userType 动态调整)
625
641
  const totalTxCount = buyCount + sellCount;
626
- const profitRateBps = PROFIT_RATE_PER_TX_BPS * totalTxCount;
642
+ const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
627
643
  const chainContext = createChainContext(chain, config.rpcUrl);
628
644
  const nonceManager = new NonceManager(chainContext.provider);
629
645
  // 创建所有钱包实例
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { CommonBundleConfig } from '../../utils/bundle-helpers.js';
7
7
  import { type GeneratedWallet } from '../../utils/wallet.js';
8
+ export type UserType = 'v0' | 'v1';
8
9
  export interface FlapSwapSignConfig {
9
10
  rpcUrl: string;
10
11
  gasLimit?: number | bigint;
@@ -17,6 +18,7 @@ export interface FlapSwapSignConfig {
17
18
  skipQuoteOnError?: boolean;
18
19
  skipApprovalCheck?: boolean;
19
20
  bribeAmount?: number;
21
+ userType?: UserType;
20
22
  }
21
23
  export type FlapChain = 'bsc' | 'xlayer' | 'base';
22
24
  export interface FlapSwapConfig extends CommonBundleConfig {
@@ -305,8 +305,8 @@ export async function flapBundleSwapMerkle(params) {
305
305
  quoteTokenDecimals,
306
306
  provider: chainContext.provider
307
307
  });
308
- // ✅ 计算利润(基于卖出报价)
309
- const tokenProfitAmount = calculateProfitAmount(quote.quotedNative);
308
+ // ✅ 计算利润(基于卖出报价,根据 userType 动态调整)
309
+ const tokenProfitAmount = calculateProfitAmount(quote.quotedNative, config.userType);
310
310
  // ✅ ERC20 输出:获取代币利润等值的原生代币(BNB)报价
311
311
  let nativeProfitAmount = tokenProfitAmount; // 原生代币输出时直接使用
312
312
  if (!useNativeToken && tokenProfitAmount > 0n) {
@@ -642,11 +642,24 @@ async function buildProfitTransaction({ provider, seller, profitAmount, profitNo
642
642
  hopWallets: profitHopResult.hopWallets
643
643
  };
644
644
  }
645
- function calculateProfitAmount(quotedNative) {
645
+ /**
646
+ * 根据 userType 计算利润率
647
+ */
648
+ function getProfitRateBps(userType) {
649
+ if (userType === 'v0') {
650
+ return PROFIT_CONFIG.RATE_BPS_V0; // 0.06%
651
+ }
652
+ else if (userType === 'v1') {
653
+ return PROFIT_CONFIG.RATE_BPS_V1; // 0.05%
654
+ }
655
+ return PROFIT_CONFIG.RATE_BPS_V0; // 默认 0.06%
656
+ }
657
+ function calculateProfitAmount(quotedNative, userType) {
646
658
  if (quotedNative <= 0n) {
647
659
  return 0n;
648
660
  }
649
- return (quotedNative * BigInt(PROFIT_CONFIG.RATE_BPS_SWAP)) / 10000n;
661
+ const rateBps = getProfitRateBps(userType);
662
+ return (quotedNative * BigInt(rateBps)) / 10000n;
650
663
  }
651
664
  function countTruthy(values) {
652
665
  return values.filter(Boolean).length;
@@ -740,8 +753,8 @@ export async function flapBatchSwapMerkle(params) {
740
753
  }
741
754
  }
742
755
  }));
743
- // ✅ 计算利润
744
- const tokenProfitAmount = calculateProfitAmount(quote.quotedNative);
756
+ // ✅ 计算利润(根据 userType 动态调整)
757
+ const tokenProfitAmount = calculateProfitAmount(quote.quotedNative, config.userType);
745
758
  let nativeProfitAmount = tokenProfitAmount;
746
759
  if (!useNativeToken && tokenProfitAmount > 0n) {
747
760
  nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, quoteToken, tokenProfitAmount, chainContext.chainId);
@@ -952,8 +965,8 @@ export async function flapQuickBatchSwapMerkle(params) {
952
965
  console.log(`[flapQuickBatchSwapMerkle] 模式: ${useNativeToken ? '原生代币' : 'ERC20'}`);
953
966
  console.log(`[flapQuickBatchSwapMerkle] 卖出数量: ${ethers.formatUnits(sellAmountWei, decimals)}`);
954
967
  console.log(`[flapQuickBatchSwapMerkle] 预估卖出所得: ${outputFormatted}`);
955
- // ✅ 计算利润(万分之六)
956
- let tokenProfitAmount = calculateProfitAmount(estimatedOutput);
968
+ // ✅ 计算利润(根据 userType 动态调整)
969
+ let tokenProfitAmount = calculateProfitAmount(estimatedOutput, config.userType);
957
970
  let nativeProfitAmount = tokenProfitAmount;
958
971
  if (!useNativeToken && tokenProfitAmount > 0n) {
959
972
  // ERC20 模式:将代币利润转换为等值原生代币
@@ -106,6 +106,10 @@ export type FlapCreateWithBundleBuySignParams = {
106
106
  salt?: string;
107
107
  extensionID?: string;
108
108
  extensionData?: string;
109
+ /** DEX ID:0=DEX0, 1=DEX1, 2=DEX2(BSC: DEX0=PancakeSwap, Monad: DEX0=Uniswap, DEX1=PancakeSwap) */
110
+ dexId?: number;
111
+ /** LP 费率档位:0=STANDARD(0.25%), 1=LOW(0.01%), 2=HIGH(1%) */
112
+ lpFeeProfile?: number;
109
113
  };
110
114
  /**
111
115
  * ✅ Flap 创建代币 + 购买结果(简化版)
@@ -25,6 +25,30 @@ export declare enum MigratorType {
25
25
  V3_MIGRATOR = 0,
26
26
  V2_MIGRATOR = 1
27
27
  }
28
+ /**
29
+ * V3 LP 费率档位
30
+ * 决定代币迁移到 Uniswap V3 或 PancakeSwap V3 时使用的费率
31
+ */
32
+ export declare enum V3LPFeeProfile {
33
+ /** 标准费率: PancakeSwap 0.25%, Uniswap 0.3% */
34
+ LP_FEE_PROFILE_STANDARD = 0,
35
+ /** 低费率: PancakeSwap 0.01%, Uniswap 0.05% (BNB 链需要白名单) */
36
+ LP_FEE_PROFILE_LOW = 1,
37
+ /** 高费率: 1% (适用于特殊交易对) */
38
+ LP_FEE_PROFILE_HIGH = 2
39
+ }
40
+ /**
41
+ * DEX ID
42
+ * 决定代币迁移到哪个 DEX
43
+ * - BSC: DEX0 = PancakeSwap
44
+ * - xLayer: DEX0 = PotatoSwap
45
+ * - Monad: DEX0 = Uniswap, DEX1 = PancakeSwap, DEX2 = Monday
46
+ */
47
+ export declare enum DEXId {
48
+ DEX0 = 0,
49
+ DEX1 = 1,
50
+ DEX2 = 2
51
+ }
28
52
  export type TokenStateV2 = {
29
53
  status: number;
30
54
  reserve: bigint;
@@ -120,6 +144,27 @@ export type NewTokenV3Params = {
120
144
  extensionID: string;
121
145
  extensionData?: string;
122
146
  };
147
+ /**
148
+ * newTokenV4 参数
149
+ * 相比 V3 新增了 DEX 选择和 LP 费率配置
150
+ */
151
+ export type NewTokenV4Params = {
152
+ name: string;
153
+ symbol: string;
154
+ meta: string;
155
+ dexThresh: number;
156
+ salt: string;
157
+ taxRate: number;
158
+ migratorType: number;
159
+ quoteToken: string;
160
+ quoteAmt: bigint;
161
+ beneficiary: string;
162
+ permitData?: string;
163
+ extensionID: string;
164
+ extensionData?: string;
165
+ dexId: number;
166
+ lpFeeProfile: number;
167
+ };
123
168
  export declare class FlapPortal {
124
169
  private rpcUrl;
125
170
  protected portal: string;
@@ -174,6 +219,39 @@ export declare class FlapPortalWriter extends FlapPortal {
174
219
  newTokenV3(args: NewTokenV3Params & {
175
220
  msgValue?: bigint;
176
221
  }): Promise<any>;
222
+ /**
223
+ * 创建代币 V4 版本
224
+ * 相比 V3 新增了 DEX 选择和 LP 费率配置
225
+ *
226
+ * @param args 创建代币参数
227
+ * @param args.dexId DEX ID,选择迁移到哪个 DEX(使用 DEXId 枚举)
228
+ * @param args.lpFeeProfile LP 费率档位(使用 V3LPFeeProfile 枚举)
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * await portal.newTokenV4({
233
+ * name: 'My Token',
234
+ * symbol: 'MTK',
235
+ * meta: 'bafkreicwlkpvrcqg4bbhyp2fnhdwbqos5ghka6gdjra3tdkgxxs74hqsze',
236
+ * dexThresh: DexThreshType.FOUR_FIFTHS,
237
+ * salt: '0x...',
238
+ * taxRate: 0,
239
+ * migratorType: MigratorType.V3_MIGRATOR,
240
+ * quoteToken: '0x0000000000000000000000000000000000000000',
241
+ * quoteAmt: 0n,
242
+ * beneficiary: '0x...',
243
+ * extensionID: '0x0000000000000000000000000000000000000000000000000000000000000000',
244
+ * dexId: DEXId.DEX0,
245
+ * lpFeeProfile: V3LPFeeProfile.LP_FEE_PROFILE_STANDARD,
246
+ * msgValue: parseEther('0.01'),
247
+ * });
248
+ * ```
249
+ *
250
+ * @note BNB 链上使用 LP_FEE_PROFILE_LOW (0.01%) 需要白名单地址
251
+ */
252
+ newTokenV4(args: NewTokenV4Params & {
253
+ msgValue?: bigint;
254
+ }): Promise<any>;
177
255
  claim(token: string): Promise<{
178
256
  txHash: string;
179
257
  tokenAmount: bigint;
@@ -31,6 +31,32 @@ export var MigratorType;
31
31
  MigratorType[MigratorType["V3_MIGRATOR"] = 0] = "V3_MIGRATOR";
32
32
  MigratorType[MigratorType["V2_MIGRATOR"] = 1] = "V2_MIGRATOR";
33
33
  })(MigratorType || (MigratorType = {}));
34
+ /**
35
+ * V3 LP 费率档位
36
+ * 决定代币迁移到 Uniswap V3 或 PancakeSwap V3 时使用的费率
37
+ */
38
+ export var V3LPFeeProfile;
39
+ (function (V3LPFeeProfile) {
40
+ /** 标准费率: PancakeSwap 0.25%, Uniswap 0.3% */
41
+ V3LPFeeProfile[V3LPFeeProfile["LP_FEE_PROFILE_STANDARD"] = 0] = "LP_FEE_PROFILE_STANDARD";
42
+ /** 低费率: PancakeSwap 0.01%, Uniswap 0.05% (BNB 链需要白名单) */
43
+ V3LPFeeProfile[V3LPFeeProfile["LP_FEE_PROFILE_LOW"] = 1] = "LP_FEE_PROFILE_LOW";
44
+ /** 高费率: 1% (适用于特殊交易对) */
45
+ V3LPFeeProfile[V3LPFeeProfile["LP_FEE_PROFILE_HIGH"] = 2] = "LP_FEE_PROFILE_HIGH";
46
+ })(V3LPFeeProfile || (V3LPFeeProfile = {}));
47
+ /**
48
+ * DEX ID
49
+ * 决定代币迁移到哪个 DEX
50
+ * - BSC: DEX0 = PancakeSwap
51
+ * - xLayer: DEX0 = PotatoSwap
52
+ * - Monad: DEX0 = Uniswap, DEX1 = PancakeSwap, DEX2 = Monday
53
+ */
54
+ export var DEXId;
55
+ (function (DEXId) {
56
+ DEXId[DEXId["DEX0"] = 0] = "DEX0";
57
+ DEXId[DEXId["DEX1"] = 1] = "DEX1";
58
+ DEXId[DEXId["DEX2"] = 2] = "DEX2";
59
+ })(DEXId || (DEXId = {}));
34
60
  // Portal ABI (使用 ethers 标准格式)
35
61
  const PORTAL_ABI = [
36
62
  // Token 状态查询
@@ -52,6 +78,7 @@ const PORTAL_ABI = [
52
78
  // 创建代币
53
79
  'function newTokenV2((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData)) external payable returns (address)',
54
80
  'function newTokenV3((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData)) external payable returns (address)',
81
+ 'function newTokenV4((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile)) external payable returns (address)',
55
82
  // 受益人领取
56
83
  'function claim(address token) external returns (uint256,uint256)',
57
84
  'function delegateClaim(address token) external returns (uint256,uint256)',
@@ -315,6 +342,56 @@ export class FlapPortalWriter extends FlapPortal {
315
342
  }, { value: args.msgValue });
316
343
  return await tx.wait();
317
344
  }
345
+ /**
346
+ * 创建代币 V4 版本
347
+ * 相比 V3 新增了 DEX 选择和 LP 费率配置
348
+ *
349
+ * @param args 创建代币参数
350
+ * @param args.dexId DEX ID,选择迁移到哪个 DEX(使用 DEXId 枚举)
351
+ * @param args.lpFeeProfile LP 费率档位(使用 V3LPFeeProfile 枚举)
352
+ *
353
+ * @example
354
+ * ```typescript
355
+ * await portal.newTokenV4({
356
+ * name: 'My Token',
357
+ * symbol: 'MTK',
358
+ * meta: 'bafkreicwlkpvrcqg4bbhyp2fnhdwbqos5ghka6gdjra3tdkgxxs74hqsze',
359
+ * dexThresh: DexThreshType.FOUR_FIFTHS,
360
+ * salt: '0x...',
361
+ * taxRate: 0,
362
+ * migratorType: MigratorType.V3_MIGRATOR,
363
+ * quoteToken: '0x0000000000000000000000000000000000000000',
364
+ * quoteAmt: 0n,
365
+ * beneficiary: '0x...',
366
+ * extensionID: '0x0000000000000000000000000000000000000000000000000000000000000000',
367
+ * dexId: DEXId.DEX0,
368
+ * lpFeeProfile: V3LPFeeProfile.LP_FEE_PROFILE_STANDARD,
369
+ * msgValue: parseEther('0.01'),
370
+ * });
371
+ * ```
372
+ *
373
+ * @note BNB 链上使用 LP_FEE_PROFILE_LOW (0.01%) 需要白名单地址
374
+ */
375
+ async newTokenV4(args) {
376
+ const tx = await this.contract.newTokenV4({
377
+ name: args.name,
378
+ symbol: args.symbol,
379
+ meta: args.meta,
380
+ dexThresh: args.dexThresh,
381
+ salt: args.salt,
382
+ taxRate: args.taxRate,
383
+ migratorType: args.migratorType,
384
+ quoteToken: args.quoteToken,
385
+ quoteAmt: args.quoteAmt,
386
+ beneficiary: args.beneficiary,
387
+ permitData: args.permitData ?? '0x',
388
+ extensionID: args.extensionID,
389
+ extensionData: args.extensionData ?? '0x',
390
+ dexId: args.dexId,
391
+ lpFeeProfile: args.lpFeeProfile,
392
+ }, { value: args.msgValue });
393
+ return await tx.wait();
394
+ }
318
395
  // 受益人领取收益
319
396
  async claim(token) {
320
397
  const tx = await this.contract.claim(token);
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { TM1, type FourChainV1 } from './contracts/tm1.js';
11
11
  export { TM2, type FourChainV2 } from './contracts/tm2.js';
12
12
  export { Helper3, Helper3Writer } from './contracts/helper3.js';
13
13
  export { CDPV2 } from './flap/curve.js';
14
- export { FlapPortal, FlapPortalWriter, type FlapChain, type PortalConfig, type TokenStateV2, type TokenStateV3, type TokenStateV4, type TokenStateV5, type QuoteExactInputParams, type ExactInputParams, type ExactInputV3Params, type NewTokenV3Params, TokenStatus, TokenVersion, DexThreshType, MigratorType } from './flap/portal.js';
14
+ export { FlapPortal, FlapPortalWriter, type FlapChain, type PortalConfig, type TokenStateV2, type TokenStateV3, type TokenStateV4, type TokenStateV5, type QuoteExactInputParams, type ExactInputParams, type ExactInputV3Params, type NewTokenV3Params, type NewTokenV4Params, TokenStatus, TokenVersion, DexThreshType, MigratorType, V3LPFeeProfile, DEXId } from './flap/portal.js';
15
15
  export { uploadTokenMeta, type TokenMetaInput } from './flap/ipfs.js';
16
16
  export { buildPermitPiggybackAuto } from './flap/permit.js';
17
17
  export { predictVanityTokenAddressByChain, findSaltEndingByChain } from './flap/vanity.js';
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ export { TM1 } from './contracts/tm1.js';
29
29
  export { TM2 } from './contracts/tm2.js';
30
30
  export { Helper3, Helper3Writer } from './contracts/helper3.js';
31
31
  export { CDPV2 } from './flap/curve.js';
32
- export { FlapPortal, FlapPortalWriter, TokenStatus, TokenVersion, DexThreshType, MigratorType } from './flap/portal.js';
32
+ export { FlapPortal, FlapPortalWriter, TokenStatus, TokenVersion, DexThreshType, MigratorType, V3LPFeeProfile, DEXId } from './flap/portal.js';
33
33
  export { uploadTokenMeta } from './flap/ipfs.js';
34
34
  export { buildPermitPiggybackAuto } from './flap/permit.js';
35
35
  export { predictVanityTokenAddressByChain, findSaltEndingByChain } from './flap/vanity.js';
@@ -15,8 +15,10 @@ export interface PancakeBuyFirstSignConfig {
15
15
  chainId?: number;
16
16
  reserveGasBNB?: number;
17
17
  skipQuoteOnError?: boolean;
18
+ userType?: UserType;
18
19
  bribeAmount?: number;
19
20
  }
21
+ export type UserType = 'v0' | 'v1';
20
22
  export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
21
23
  export interface V2RouteParams {
22
24
  routeType: 'v2';
@@ -52,8 +52,15 @@ const BRIBE_TX_COUNT = 1;
52
52
  const PROFIT_TX_COUNT = PROFIT_HOP_COUNT + 2; // 2 + 2 = 4
53
53
  /** 最大买卖交易数 */
54
54
  const MAX_SWAP_TX_COUNT = MAX_BUNDLE_SIGNATURES - BRIBE_TX_COUNT - PROFIT_TX_COUNT; // 50 - 1 - 4 = 45
55
- /** 每笔交易利润比例(基点):6 bps = 0.06% = 万分之六 */
56
- const PROFIT_RATE_PER_TX_BPS = 6;
55
+ /**
56
+ * 根据 userType 获取每笔交易的利润率
57
+ */
58
+ function getProfitRatePerTxBps(userType) {
59
+ if (userType === 'v1') {
60
+ return PROFIT_CONFIG.RATE_BPS_V1;
61
+ }
62
+ return PROFIT_CONFIG.RATE_BPS_V0; // v0 或默认
63
+ }
57
64
  /**
58
65
  * 验证买卖笔数
59
66
  */
@@ -136,9 +143,9 @@ export async function pancakeBundleBuyFirstMerkle(params) {
136
143
  throw new Error('单钱包模式需要提供 buyerPrivateKey 和 sellerPrivateKey');
137
144
  }
138
145
  validateSwapCounts(buyCount, sellCount);
139
- // ✅ 计算利润比例:每笔万分之3
146
+ // ✅ 计算利润比例(根据 userType 动态调整)
140
147
  const totalTxCount = buyCount + sellCount;
141
- const profitRateBps = PROFIT_RATE_PER_TX_BPS * totalTxCount;
148
+ const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
142
149
  // ✅ 判断是否使用原生代币(BNB)或 ERC20 代币(如 USDT)
143
150
  const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
144
151
  const context = createPancakeContext(config);
@@ -766,9 +773,9 @@ async function pancakeBundleBuyFirstMultiWallet(params) {
766
773
  throw new Error('卖方钱包数量不能为0');
767
774
  // 验证总交易数不超过限制
768
775
  validateSwapCounts(buyCount, sellCount);
769
- // ✅ 计算利润比例:每笔万分之6
776
+ // ✅ 计算利润比例(根据 userType 动态调整)
770
777
  const totalTxCount = buyCount + sellCount;
771
- const profitRateBps = PROFIT_RATE_PER_TX_BPS * totalTxCount;
778
+ const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
772
779
  // ✅ 判断是否使用原生代币
773
780
  const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
774
781
  const context = createPancakeContext(config);
@@ -1,5 +1,6 @@
1
1
  import { CommonBundleConfig } from '../utils/bundle-helpers.js';
2
2
  import { type GeneratedWallet } from '../utils/wallet.js';
3
+ export type UserType = 'v0' | 'v1';
3
4
  export interface PancakeSwapSignConfig {
4
5
  rpcUrl: string;
5
6
  gasLimit?: number | bigint;
@@ -9,6 +10,7 @@ export interface PancakeSwapSignConfig {
9
10
  txType?: 0 | 2;
10
11
  chainId?: number;
11
12
  reserveGasBNB?: number;
13
+ userType?: UserType;
12
14
  bribeAmount?: number;
13
15
  }
14
16
  export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
@@ -439,11 +439,24 @@ async function planNonces({ seller, buyer, sameAddress, approvalExists, profitNe
439
439
  ]);
440
440
  return { sellerNonce, buyerNonce };
441
441
  }
442
- function calculateProfitAmount(estimatedBNBOut) {
442
+ /**
443
+ * 根据 userType 计算利润率
444
+ */
445
+ function getProfitRateBps(userType) {
446
+ if (userType === 'v0') {
447
+ return PROFIT_CONFIG.RATE_BPS_V0; // 0.06%
448
+ }
449
+ else if (userType === 'v1') {
450
+ return PROFIT_CONFIG.RATE_BPS_V1; // 0.05%
451
+ }
452
+ return PROFIT_CONFIG.RATE_BPS_V0; // 默认 0.06%
453
+ }
454
+ function calculateProfitAmount(estimatedBNBOut, userType) {
443
455
  if (estimatedBNBOut <= 0n) {
444
456
  return 0n;
445
457
  }
446
- return (estimatedBNBOut * BigInt(PROFIT_CONFIG.RATE_BPS_SWAP)) / 10000n;
458
+ const rateBps = getProfitRateBps(userType);
459
+ return (estimatedBNBOut * BigInt(rateBps)) / 10000n;
447
460
  }
448
461
  /**
449
462
  * ✅ 获取 ERC20 代币 → 原生代币(BNB)的报价
@@ -619,8 +632,8 @@ export async function pancakeBundleSwapMerkle(params) {
619
632
  // 如果输出是 ERC20(如 USDT),需要先转换为 BNB 等值
620
633
  let profitAmount;
621
634
  if (useNativeToken) {
622
- // 输出是 BNB,直接计算利润
623
- profitAmount = calculateProfitAmount(quoteResult.estimatedBNBOut);
635
+ // 输出是 BNB,直接计算利润(根据 userType 动态调整)
636
+ profitAmount = calculateProfitAmount(quoteResult.estimatedBNBOut, config.userType);
624
637
  console.log(`[pancakeBundleSwapMerkle] 原生代币利润: ${ethers.formatEther(profitAmount)} BNB`);
625
638
  }
626
639
  else {
@@ -629,7 +642,7 @@ export async function pancakeBundleSwapMerkle(params) {
629
642
  const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
630
643
  const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, quoteResult.estimatedBNBOut, // 这实际上是 ERC20 数量
631
644
  version, fee);
632
- profitAmount = calculateProfitAmount(estimatedBNBValue);
645
+ profitAmount = calculateProfitAmount(estimatedBNBValue, config.userType);
633
646
  console.log(`[pancakeBundleSwapMerkle] ERC20→BNB 报价: ${ethers.formatUnits(quoteResult.estimatedBNBOut, quoteTokenDecimals)} ${quoteToken?.slice(0, 10)}... → ${ethers.formatEther(estimatedBNBValue)} BNB, 利润: ${ethers.formatEther(profitAmount)} BNB`);
634
647
  }
635
648
  // ✅ 获取贿赂金额
@@ -940,14 +953,14 @@ export async function pancakeBatchSwapMerkle(params) {
940
953
  // ✅ 修复:利润计算应基于 BNB 数量,不是 ERC20 数量
941
954
  let profitAmount;
942
955
  if (useNativeToken) {
943
- profitAmount = calculateProfitAmount(estimatedBNBOut);
956
+ profitAmount = calculateProfitAmount(estimatedBNBOut, config.userType);
944
957
  console.log(`[pancakeBatchSwapMerkle] 原生代币利润: ${ethers.formatEther(profitAmount)} BNB`);
945
958
  }
946
959
  else {
947
960
  const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
948
961
  const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
949
962
  const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, estimatedBNBOut, version, fee);
950
- profitAmount = calculateProfitAmount(estimatedBNBValue);
963
+ profitAmount = calculateProfitAmount(estimatedBNBValue, config.userType);
951
964
  console.log(`[pancakeBatchSwapMerkle] ERC20→BNB 报价: ${ethers.formatUnits(estimatedBNBOut, quoteTokenDecimals)} → ${ethers.formatEther(estimatedBNBValue)} BNB, 利润: ${ethers.formatEther(profitAmount)} BNB`);
952
965
  }
953
966
  // 计算利润 nonce
@@ -1143,14 +1156,14 @@ export async function pancakeQuickBatchSwapMerkle(params) {
1143
1156
  // ✅ 计算利润(万分之六)
1144
1157
  let profitAmount;
1145
1158
  if (useNativeToken) {
1146
- profitAmount = calculateProfitAmount(estimatedOutput);
1159
+ profitAmount = calculateProfitAmount(estimatedOutput, config.userType);
1147
1160
  }
1148
1161
  else {
1149
1162
  // ERC20 模式:需要将 ERC20 价值转换为 BNB
1150
1163
  const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
1151
1164
  const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
1152
1165
  const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, estimatedOutput, version, fee);
1153
- profitAmount = calculateProfitAmount(estimatedBNBValue);
1166
+ profitAmount = calculateProfitAmount(estimatedBNBValue, config.userType);
1154
1167
  console.log(`[pancakeQuickBatchSwapMerkle] ERC20→BNB 报价: ${outputFormatted} → ${ethers.formatEther(estimatedBNBValue)} BNB`);
1155
1168
  }
1156
1169
  const distributableAmount = estimatedOutput - (useNativeToken ? profitAmount : 0n);
@@ -17,10 +17,12 @@ export declare const PROFIT_CONFIG: {
17
17
  readonly RECIPIENT: "0xe8D0334fAf713884133640CAEe4ECdd2106AF103";
18
18
  /** 利润比例(基点):30 bps = 0.3% = 千分之三(普通模式) */
19
19
  readonly RATE_BPS: 30;
20
- /** 利润比例(基点):6 bps = 0.06% = 万分之六(资金利用率模式) */
21
- readonly RATE_BPS_CAPITAL: 6;
22
20
  /** 利润比例(基点):6 bps = 0.06% = 万分之六(捆绑换手模式) */
23
21
  readonly RATE_BPS_SWAP: 6;
22
+ /** 利润比例(基点):6 bps = 0.06% = 万分之六(用户类型 v0) */
23
+ readonly RATE_BPS_V0: 6;
24
+ /** 利润比例(基点):5 bps = 0.05% = 万分之五(用户类型 v1) */
25
+ readonly RATE_BPS_V1: 5;
24
26
  };
25
27
  export declare const CHAIN: {
26
28
  BSC: {
@@ -23,10 +23,12 @@ export const PROFIT_CONFIG = {
23
23
  RECIPIENT: '0xe8D0334fAf713884133640CAEe4ECdd2106AF103',
24
24
  /** 利润比例(基点):30 bps = 0.3% = 千分之三(普通模式) */
25
25
  RATE_BPS: 30,
26
- /** 利润比例(基点):6 bps = 0.06% = 万分之六(资金利用率模式) */
27
- RATE_BPS_CAPITAL: 6,
28
26
  /** 利润比例(基点):6 bps = 0.06% = 万分之六(捆绑换手模式) */
29
27
  RATE_BPS_SWAP: 6,
28
+ /** 利润比例(基点):6 bps = 0.06% = 万分之六(用户类型 v0) */
29
+ RATE_BPS_V0: 6,
30
+ /** 利润比例(基点):5 bps = 0.05% = 万分之五(用户类型 v1) */
31
+ RATE_BPS_V1: 5,
30
32
  };
31
33
  export const CHAIN = {
32
34
  BSC: {
@@ -620,7 +620,7 @@ export async function holdersMaker(params) {
620
620
  const totalBuyAmountForProfit = isERC20Mode
621
621
  ? ethers.parseEther(buyAmountPerHolder) * BigInt(holdersCount) // 按等值 BNB 计算
622
622
  : buyAmountWei * BigInt(holdersCount);
623
- const profitRateBps = PROFIT_CONFIG.RATE_BPS_SWAP;
623
+ const profitRateBps = PROFIT_CONFIG.RATE_BPS;
624
624
  const totalProfit = (totalBuyAmountForProfit * BigInt(profitRateBps)) / 10000n;
625
625
  const profitPerBatch = totalProfit / BigInt(walletBatches.length);
626
626
  console.log(`[HoldersMaker] 总利润: ${ethers.formatEther(totalProfit)} BNB`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.83",
3
+ "version": "1.4.85",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",