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.
- package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +2 -1
- package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +14 -7
- package/dist/contracts/tm-bundle-merkle/swap.d.ts +2 -0
- package/dist/contracts/tm-bundle-merkle/swap.js +16 -4
- package/dist/contracts/tm-bundle-merkle/types.d.ts +10 -0
- package/dist/contracts/tm-bundle-merkle/utils.js +24 -14
- package/dist/flap/constants.d.ts +1 -1
- package/dist/flap/constants.js +1 -1
- package/dist/flap/portal-bundle-merkle/core.js +36 -5
- package/dist/flap/portal-bundle-merkle/create-to-dex.d.ts +8 -0
- package/dist/flap/portal-bundle-merkle/create-to-dex.js +61 -13
- package/dist/flap/portal-bundle-merkle/swap-buy-first.d.ts +2 -0
- package/dist/flap/portal-bundle-merkle/swap-buy-first.js +25 -9
- package/dist/flap/portal-bundle-merkle/swap.d.ts +2 -0
- package/dist/flap/portal-bundle-merkle/swap.js +21 -8
- package/dist/flap/portal-bundle-merkle/types.d.ts +4 -0
- package/dist/flap/portal.d.ts +78 -0
- package/dist/flap/portal.js +77 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pancake/bundle-buy-first.d.ts +2 -0
- package/dist/pancake/bundle-buy-first.js +37 -212
- package/dist/pancake/bundle-swap.d.ts +2 -0
- package/dist/pancake/bundle-swap.js +22 -9
- package/dist/utils/constants.d.ts +4 -2
- package/dist/utils/constants.js +4 -2
- package/dist/utils/holders-maker.js +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
/**
|
|
30
|
-
|
|
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
|
-
// ✅
|
|
114
|
+
// ✅ 计算利润比例(根据 userType 动态调整)
|
|
108
115
|
const totalTxCount = buyCount + sellCount;
|
|
109
|
-
const profitRateBps =
|
|
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
|
-
// ✅
|
|
335
|
+
// ✅ 计算利润比例(根据 userType 动态调整)
|
|
329
336
|
const totalTxCount = buyCount + sellCount;
|
|
330
|
-
const profitRateBps =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
*
|
|
7
|
+
* 根据用户类型获取利润费率(bps)
|
|
8
|
+
* - v0: 万分之6 (6 bps = 0.06%)
|
|
9
|
+
* - v1: 万分之5 (5 bps = 0.05%)
|
|
10
10
|
*/
|
|
11
|
-
function
|
|
12
|
-
|
|
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
|
}
|
package/dist/flap/constants.d.ts
CHANGED
|
@@ -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: "
|
|
30
|
+
readonly BSC_TAXED: "0x29e6383F0ce68507b5A72a53c2B118a118332aA8";
|
|
31
31
|
readonly BASE: "0xF3c514E04f83166E80718f29f0d34F206be40A0A";
|
|
32
32
|
readonly XLAYER: "0x12Dc83157Bf1cfCB8Db5952b3ba5bb56Cc38f8C9";
|
|
33
33
|
readonly MORPH: "0x8b4329947e34b6d56d71a3385cac122bade7d78d";
|
package/dist/flap/constants.js
CHANGED
|
@@ -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: '
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
/**
|
|
70
|
-
|
|
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
|
-
// ✅
|
|
134
|
+
// ✅ 计算利润比例(根据 userType 动态调整)
|
|
128
135
|
const totalTxCount = buyCount + sellCount;
|
|
129
|
-
const profitRateBps =
|
|
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
|
-
|
|
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(
|
|
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
|
-
// ✅
|
|
640
|
+
// ✅ 计算利润比例(根据 userType 动态调整)
|
|
625
641
|
const totalTxCount = buyCount + sellCount;
|
|
626
|
-
const profitRateBps =
|
|
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
|
-
|
|
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
|
-
|
|
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 创建代币 + 购买结果(简化版)
|