four-flap-meme-sdk 1.4.84 → 1.4.86

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
  }
@@ -239,19 +239,67 @@ export async function flapBundleCreateToDex(params) {
239
239
  const devNonce = noncesMap.get(devAddr);
240
240
  noncesMap.set(devAddr, devNonce + 1);
241
241
  const originalPortal = new Contract(originalPortalAddress, PORTAL_ABI, devWallet);
242
- const createUnsigned = await originalPortal.newTokenV2.populateTransaction({
243
- name: tokenInfo.name,
244
- symbol: tokenInfo.symbol,
245
- meta: tokenInfo.meta,
246
- dexThresh: (params.dexThresh ?? 1) & 0xff,
247
- salt: params.salt ?? '0x' + '00'.repeat(32),
248
- taxRate: (params.taxRate ?? 0) & 0xffff,
249
- migratorType: (params.migratorType ?? 0) & 0xff,
250
- quoteToken: inputToken,
251
- quoteAmt: 0n,
252
- beneficiary: devWallet.address,
253
- permitData: '0x'
254
- });
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
+ }
255
303
  const createTx = {
256
304
  ...createUnsigned,
257
305
  from: devWallet.address,
@@ -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 创建代币 + 购买结果(简化版)