four-flap-meme-sdk 4.0.9 → 4.0.11
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/bundle/four-meme/swap/batch.js +3 -4
- package/dist/bundle/four-meme/swap/bundle.js +5 -4
- package/dist/bundle/four-meme/swap/quick-batch.js +3 -3
- package/dist/bundle/four-meme/swap-sign-helpers.d.ts +2 -0
- package/dist/bundle/four-meme/swap-sign-helpers.js +16 -0
- package/dist/chains/bsc/pancake/quote.d.ts +11 -0
- package/dist/chains/bsc/pancake/quote.js +18 -0
- package/dist/chains/bsc/pancake/swap-batch.js +15 -8
- package/dist/chains/bsc/pancake/swap-quick.js +15 -7
- package/dist/chains/bsc/pancake/swap-single.js +15 -13
- package/dist/core/quote/quote-helpers.js +11 -8
- package/dist/domains/flap/portal-bundle-merkle/swap-batch.js +13 -5
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-multi-wallet.js +3 -5
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first.js +4 -5
- package/dist/domains/flap/portal-bundle-merkle/swap-planning.d.ts +9 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-planning.js +20 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-quick-batch.js +13 -5
- package/dist/domains/flap/portal-bundle-merkle/swap-single.js +13 -5
- package/dist/domains/lp-inspect/inspect.js +26 -13
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Four.meme 内盘批量换手(Merkle Bundle)— 一卖多买流程
|
|
3
3
|
*/
|
|
4
4
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
5
|
-
import { countSellerNonceSlots, createFourSwapGasContext, fetchFourSwapSellQuoteAllowanceAndBalances, needsTmTokenApproval, planSellerNonces, signTmMaxApprovalTx, } from '../swap-sign-helpers.js';
|
|
5
|
+
import { countSellerNonceSlots, createFourSwapGasContext, fetchFourSwapSellQuoteAllowanceAndBalances, grossUpFourSellProceedsToBuySide, needsTmTokenApproval, planSellerNonces, signTmMaxApprovalTx, } from '../swap-sign-helpers.js';
|
|
6
6
|
import { signBribeTransaction } from '../../../core/sign-context-helpers.js';
|
|
7
7
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, getOptimizedGasPrice, getGasPriceConfig, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
@@ -58,9 +58,8 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
58
58
|
});
|
|
59
59
|
// 检查是否需要授权
|
|
60
60
|
const needApproval = needsTmTokenApproval(currentAllowance, decimals);
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
const profitAmount = totalBuyerFunds > 0n ? calculateBundleSwapRoundTripProfit(buySum, totalBuyerFunds) : 0n;
|
|
61
|
+
const profitNotional = await grossUpFourSellProceedsToBuySide(provider, tokenAddress, sellAmountWei, totalBuyerFunds);
|
|
62
|
+
const profitAmount = profitNotional > 0n ? calculateBundleSwapRoundTripProfit(profitNotional, profitNotional) : 0n;
|
|
64
63
|
// ✅ 获取贿赂金额
|
|
65
64
|
const bribeAmount = getBribeAmount(config);
|
|
66
65
|
const needBribeTx = bribeAmount > 0n;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Four.meme 内盘捆绑换手(Merkle Bundle)— 单卖单买流程
|
|
3
3
|
*/
|
|
4
4
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
5
|
-
import { countSellerNonceSlots, createFourSwapGasContext, fetchFourSwapSellQuoteAndAllowance, needsTmTokenApproval, planSellerNonces, signTmMaxApprovalTx, } from '../swap-sign-helpers.js';
|
|
5
|
+
import { countSellerNonceSlots, createFourSwapGasContext, fetchFourSwapSellQuoteAndAllowance, grossUpFourSellProceedsToBuySide, needsTmTokenApproval, planSellerNonces, signTmMaxApprovalTx, } from '../swap-sign-helpers.js';
|
|
6
6
|
import { signBribeTransaction } from '../../../core/sign-context-helpers.js';
|
|
7
7
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, getOptimizedGasPrice, getGasPriceConfig, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
@@ -40,10 +40,11 @@ export async function fourBundleSwapMerkle(params) {
|
|
|
40
40
|
}
|
|
41
41
|
// 检查是否需要授权
|
|
42
42
|
const needApproval = needsTmTokenApproval(currentAllowance, decimals);
|
|
43
|
-
//
|
|
43
|
+
// 利润配置:按卖出代币的买侧计价收万六,避免曲线折价后只剩万五点多
|
|
44
44
|
const extractProfit = true;
|
|
45
|
-
const
|
|
46
|
-
|
|
45
|
+
const profitNotional = await grossUpFourSellProceedsToBuySide(provider, tokenAddress, sellAmountWei, sellerWillGetBNB);
|
|
46
|
+
const profitAmount = extractProfit && profitNotional > 0n
|
|
47
|
+
? calculateBundleSwapRoundTripProfit(profitNotional, profitNotional)
|
|
47
48
|
: 0n;
|
|
48
49
|
// ✅ 获取贿赂金额
|
|
49
50
|
const bribeAmount = getBribeAmount(config);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Four.meme 内盘快捷批量换手(Merkle Bundle)— 资金利用率模式流程
|
|
3
3
|
*/
|
|
4
4
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
5
|
-
import { createFourSwapGasContext, quoteFourSwapSellFunds, } from '../swap-sign-helpers.js';
|
|
5
|
+
import { createFourSwapGasContext, grossUpFourSellProceedsToBuySide, quoteFourSwapSellFunds, } from '../swap-sign-helpers.js';
|
|
6
6
|
import { generateDisperseHopPaths, buildNativeHopChain, NATIVE_TRANSFER_GAS_LIMIT } from '../swap-hop-helpers.js';
|
|
7
7
|
import { signBribeTransaction } from '../../../core/sign-context-helpers.js';
|
|
8
8
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
@@ -51,8 +51,8 @@ export async function fourQuickBatchSwapMerkle(params) {
|
|
|
51
51
|
]);
|
|
52
52
|
const { amount: sellAmountWei, decimals } = sellAmountResult;
|
|
53
53
|
const estimatedBNBOut = await quoteFourSwapSellFunds(provider, tokenAddress, sellAmountWei);
|
|
54
|
-
|
|
55
|
-
const profitAmount =
|
|
54
|
+
const profitNotional = await grossUpFourSellProceedsToBuySide(provider, tokenAddress, sellAmountWei, estimatedBNBOut);
|
|
55
|
+
const profitAmount = profitNotional > 0n ? calculateBundleSwapRoundTripProfit(profitNotional, profitNotional) : 0n;
|
|
56
56
|
const distributableAmount = estimatedBNBOut - profitAmount;
|
|
57
57
|
// ✅ 计算每个买方分到的金额
|
|
58
58
|
let transferAmountsWei;
|
|
@@ -8,6 +8,8 @@ export declare function countSellerNonceSlots(needBribeTx: boolean, needApproval
|
|
|
8
8
|
export declare function planSellerNonces(sellerNonces: number[], needBribeTx: boolean, needApproval: boolean, extractProfit: boolean): SellerNoncePlan;
|
|
9
9
|
export declare function signTmMaxApprovalTx(seller: Wallet, tokenAddress: string, approvalNonce: number, gasPrice: bigint, chainIdNum: number, txType: 0 | 2): Promise<string>;
|
|
10
10
|
export declare function quoteFourSwapSellFunds(provider: JsonRpcProvider, tokenAddress: string, sellAmountWei: bigint): Promise<bigint>;
|
|
11
|
+
/** 换手按卖出所得收万六会像万五点多:用所得能买回的数量把计价额抬到买侧。 */
|
|
12
|
+
export declare function grossUpFourSellProceedsToBuySide(provider: JsonRpcProvider, tokenAddress: string, sellAmountWei: bigint, sellProceedsWei: bigint): Promise<bigint>;
|
|
11
13
|
export declare function fetchFourSwapSellQuoteAndAllowance(provider: JsonRpcProvider, tokenAddress: string, sellerAddress: string, sellAmountWei: bigint): Promise<{
|
|
12
14
|
sellFunds: bigint;
|
|
13
15
|
allowance: bigint;
|
|
@@ -54,6 +54,22 @@ export async function quoteFourSwapSellFunds(provider, tokenAddress, sellAmountW
|
|
|
54
54
|
const sellQuote = await helper3.trySell(tokenAddress, sellAmountWei);
|
|
55
55
|
return sellQuote.funds;
|
|
56
56
|
}
|
|
57
|
+
/** 换手按卖出所得收万六会像万五点多:用所得能买回的数量把计价额抬到买侧。 */
|
|
58
|
+
export async function grossUpFourSellProceedsToBuySide(provider, tokenAddress, sellAmountWei, sellProceedsWei) {
|
|
59
|
+
if (sellProceedsWei <= 0n || sellAmountWei <= 0n)
|
|
60
|
+
return sellProceedsWei;
|
|
61
|
+
try {
|
|
62
|
+
const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider);
|
|
63
|
+
const buyQuote = await helper3.tryBuy(tokenAddress, 0n, sellProceedsWei);
|
|
64
|
+
const tokensBought = buyQuote.estimatedAmount;
|
|
65
|
+
if (tokensBought <= 0n || tokensBought >= sellAmountWei)
|
|
66
|
+
return sellProceedsWei;
|
|
67
|
+
return (sellProceedsWei * sellAmountWei) / tokensBought;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return sellProceedsWei;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
57
73
|
export async function fetchFourSwapSellQuoteAndAllowance(provider, tokenAddress, sellerAddress, sellAmountWei) {
|
|
58
74
|
const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider);
|
|
59
75
|
const erc20 = new Contract(tokenAddress, ERC20_ALLOWANCE_ABI, provider);
|
|
@@ -6,6 +6,17 @@ export declare function quoteSellOutput({ routeParams, sellAmountWei, provider,
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function getProfitRateBps(_userType?: UserType): number;
|
|
8
8
|
export declare function calculateProfitAmount(estimatedBNBOut: bigint, _userType?: UserType): bigint;
|
|
9
|
+
/** 换手按卖出所得收万六会像万五点多:用所得能买回的数量把计价额抬到买侧。 */
|
|
10
|
+
export declare function grossUpPancakeSellProceedsToBuySide(params: {
|
|
11
|
+
provider: ethers.JsonRpcProvider;
|
|
12
|
+
tokenAddress: string;
|
|
13
|
+
sellAmountWei: bigint;
|
|
14
|
+
sellProceedsWei: bigint;
|
|
15
|
+
quoteTokenIn: string;
|
|
16
|
+
version: 'v2' | 'v3';
|
|
17
|
+
fee?: number;
|
|
18
|
+
v2RouterAddress?: string;
|
|
19
|
+
}): Promise<bigint>;
|
|
9
20
|
/**
|
|
10
21
|
* ✅ 获取 ERC20 代币 → 原生代币(BNB)的报价
|
|
11
22
|
* 用于将 ERC20 利润转换为 BNB
|
|
@@ -50,6 +50,24 @@ export function calculateProfitAmount(estimatedBNBOut, _userType) {
|
|
|
50
50
|
}
|
|
51
51
|
return calculateBundleSwapRoundTripProfit(estimatedBNBOut, estimatedBNBOut);
|
|
52
52
|
}
|
|
53
|
+
/** 换手按卖出所得收万六会像万五点多:用所得能买回的数量把计价额抬到买侧。 */
|
|
54
|
+
export async function grossUpPancakeSellProceedsToBuySide(params) {
|
|
55
|
+
const { sellAmountWei, sellProceedsWei } = params;
|
|
56
|
+
if (sellProceedsWei <= 0n || sellAmountWei <= 0n)
|
|
57
|
+
return sellProceedsWei;
|
|
58
|
+
try {
|
|
59
|
+
const quoted = params.version === 'v3'
|
|
60
|
+
? await quoteV3(params.provider, params.quoteTokenIn, params.tokenAddress, sellProceedsWei, 'BSC', params.fee)
|
|
61
|
+
: await quoteV2(params.provider, params.quoteTokenIn, params.tokenAddress, sellProceedsWei, 'BSC', params.v2RouterAddress);
|
|
62
|
+
const tokensBought = quoted.amountOut;
|
|
63
|
+
if (tokensBought <= 0n || tokensBought >= sellAmountWei)
|
|
64
|
+
return sellProceedsWei;
|
|
65
|
+
return (sellProceedsWei * sellAmountWei) / tokensBought;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return sellProceedsWei;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
53
71
|
/**
|
|
54
72
|
* ✅ 获取 ERC20 代币 → 原生代币(BNB)的报价
|
|
55
73
|
* 用于将 ERC20 利润转换为 BNB
|
|
@@ -6,7 +6,7 @@ import { getGasLimit } from '../../../core/gas/bundle-gas.js';
|
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
7
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
9
|
-
import { BRIBE_GAS_LIMIT, ERC20_BALANCE_OF_ABI, FLAT_FEE, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, ZERO_ADDRESS, calculateProfitAmount, createPancakeContext, getERC20ToNativeQuote, getGasPrice, quoteSellOutput, } from './bundle-swap-helpers.js';
|
|
9
|
+
import { BRIBE_GAS_LIMIT, ERC20_BALANCE_OF_ABI, FLAT_FEE, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, WBNB_ADDRESS, ZERO_ADDRESS, calculateProfitAmount, createPancakeContext, getERC20ToNativeQuote, getGasPrice, grossUpPancakeSellProceedsToBuySide, quoteSellOutput, } from './bundle-swap-helpers.js';
|
|
10
10
|
/**
|
|
11
11
|
* PancakeSwap 批量换手(一卖多买)
|
|
12
12
|
*
|
|
@@ -203,18 +203,25 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
203
203
|
type: txType,
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
|
-
|
|
206
|
+
const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
|
|
207
|
+
const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
|
|
208
|
+
const profitNotional = await grossUpPancakeSellProceedsToBuySide({
|
|
209
|
+
provider: context.provider,
|
|
210
|
+
tokenAddress,
|
|
211
|
+
sellAmountWei,
|
|
212
|
+
sellProceedsWei: estimatedBNBOut,
|
|
213
|
+
quoteTokenIn: useNativeToken ? WBNB_ADDRESS : quoteToken,
|
|
214
|
+
version,
|
|
215
|
+
fee,
|
|
216
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
217
|
+
});
|
|
207
218
|
let profitAmount;
|
|
208
219
|
if (useNativeToken) {
|
|
209
|
-
profitAmount = calculateProfitAmount(
|
|
210
|
-
// 利润计算完成
|
|
220
|
+
profitAmount = calculateProfitAmount(profitNotional, config.userType);
|
|
211
221
|
}
|
|
212
222
|
else {
|
|
213
|
-
const
|
|
214
|
-
const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
|
|
215
|
-
const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, estimatedBNBOut, version, fee);
|
|
223
|
+
const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, profitNotional, version, fee);
|
|
216
224
|
profitAmount = calculateProfitAmount(estimatedBNBValue, config.userType);
|
|
217
|
-
// ERC20→BNB 报价完成
|
|
218
225
|
}
|
|
219
226
|
// 计算利润 nonce
|
|
220
227
|
const profitNonce = profitAmount > 0n
|
|
@@ -7,7 +7,7 @@ import { ethers, Contract, Wallet } from 'ethers';
|
|
|
7
7
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
9
9
|
import { ERC20_ABI } from '../../../abis/common.js';
|
|
10
|
-
import { BRIBE_GAS_LIMIT, FLAT_FEE, NATIVE_TRANSFER_GAS_LIMIT, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, ZERO_ADDRESS, buildBNBHopChainForERC20, buildERC20HopChain, buildNativeHopChain, calculateProfitAmount, createPancakeContext, generateDisperseHopPaths, getERC20ToNativeQuote, getGasPrice, quoteSellOutput, } from './bundle-swap-helpers.js';
|
|
10
|
+
import { BRIBE_GAS_LIMIT, FLAT_FEE, NATIVE_TRANSFER_GAS_LIMIT, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, WBNB_ADDRESS, ZERO_ADDRESS, buildBNBHopChainForERC20, buildERC20HopChain, buildNativeHopChain, calculateProfitAmount, createPancakeContext, generateDisperseHopPaths, getERC20ToNativeQuote, getGasPrice, grossUpPancakeSellProceedsToBuySide, quoteSellOutput, } from './bundle-swap-helpers.js';
|
|
11
11
|
/**
|
|
12
12
|
* PancakeSwap 快捷批量换手(资金自动流转)
|
|
13
13
|
*
|
|
@@ -120,16 +120,24 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
120
120
|
v2RouterAddress: config.v2RouterAddress,
|
|
121
121
|
});
|
|
122
122
|
const estimatedOutput = quoteResult.estimatedBNBOut;
|
|
123
|
-
|
|
123
|
+
const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
|
|
124
|
+
const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
|
|
125
|
+
const profitNotional = await grossUpPancakeSellProceedsToBuySide({
|
|
126
|
+
provider: context.provider,
|
|
127
|
+
tokenAddress,
|
|
128
|
+
sellAmountWei,
|
|
129
|
+
sellProceedsWei: estimatedOutput,
|
|
130
|
+
quoteTokenIn: useNativeToken ? WBNB_ADDRESS : quoteToken,
|
|
131
|
+
version,
|
|
132
|
+
fee,
|
|
133
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
134
|
+
});
|
|
124
135
|
let profitAmount;
|
|
125
136
|
if (useNativeToken) {
|
|
126
|
-
profitAmount = calculateProfitAmount(
|
|
137
|
+
profitAmount = calculateProfitAmount(profitNotional, config.userType);
|
|
127
138
|
}
|
|
128
139
|
else {
|
|
129
|
-
|
|
130
|
-
const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
|
|
131
|
-
const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
|
|
132
|
-
const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, estimatedOutput, version, fee);
|
|
140
|
+
const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, profitNotional, version, fee);
|
|
133
141
|
profitAmount = calculateProfitAmount(estimatedBNBValue, config.userType);
|
|
134
142
|
}
|
|
135
143
|
const distributableAmount = estimatedOutput - (useNativeToken ? profitAmount : 0n);
|
|
@@ -6,7 +6,7 @@ import { getGasLimit } from '../../../core/gas/bundle-gas.js';
|
|
|
6
6
|
import { ethers, Wallet } from 'ethers';
|
|
7
7
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
9
|
-
import { BRIBE_GAS_LIMIT, ZERO_ADDRESS, buildNoncePlanFromNonces, buildSwapTransactions, calculateBuyerBudget, calculateProfitAmount, createPancakeContext, getERC20ToNativeQuote, getGasPrice, planNonces, quoteSellOutput, validateFinalBalances, } from './bundle-swap-helpers.js';
|
|
9
|
+
import { BRIBE_GAS_LIMIT, ZERO_ADDRESS, buildNoncePlanFromNonces, buildSwapTransactions, WBNB_ADDRESS, calculateBuyerBudget, calculateProfitAmount, createPancakeContext, getERC20ToNativeQuote, getGasPrice, grossUpPancakeSellProceedsToBuySide, planNonces, quoteSellOutput, validateFinalBalances, } from './bundle-swap-helpers.js';
|
|
10
10
|
export async function pancakeBundleSwapMerkle(params) {
|
|
11
11
|
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, startNonces, // ✅ 可选:前端预获取的 nonces
|
|
12
12
|
} = params;
|
|
@@ -51,23 +51,25 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
51
51
|
useNativeToken,
|
|
52
52
|
v2RouterAddress: config.v2RouterAddress,
|
|
53
53
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
|
|
55
|
+
const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
|
|
56
|
+
const profitNotional = await grossUpPancakeSellProceedsToBuySide({
|
|
57
|
+
provider: context.provider,
|
|
58
|
+
tokenAddress,
|
|
59
|
+
sellAmountWei,
|
|
60
|
+
sellProceedsWei: quoteResult.estimatedBNBOut,
|
|
61
|
+
quoteTokenIn: useNativeToken ? WBNB_ADDRESS : quoteToken,
|
|
62
|
+
version,
|
|
63
|
+
fee,
|
|
64
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
65
|
+
});
|
|
57
66
|
let profitAmount;
|
|
58
67
|
if (useNativeToken) {
|
|
59
|
-
|
|
60
|
-
profitAmount = calculateProfitAmount(quoteResult.estimatedBNBOut, config.userType);
|
|
61
|
-
// 利润计算完成
|
|
68
|
+
profitAmount = calculateProfitAmount(profitNotional, config.userType);
|
|
62
69
|
}
|
|
63
70
|
else {
|
|
64
|
-
|
|
65
|
-
const version = routeParams.routeType === 'v2' ? 'v2' : 'v3';
|
|
66
|
-
const fee = routeParams.routeType === 'v3-single' ? routeParams.v3Fee : undefined;
|
|
67
|
-
const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, quoteResult.estimatedBNBOut, // 这实际上是 ERC20 数量
|
|
68
|
-
version, fee);
|
|
71
|
+
const estimatedBNBValue = await getERC20ToNativeQuote(context.provider, quoteToken, profitNotional, version, fee);
|
|
69
72
|
profitAmount = calculateProfitAmount(estimatedBNBValue, config.userType);
|
|
70
|
-
// ERC20→BNB 报价完成
|
|
71
73
|
}
|
|
72
74
|
// ✅ 获取贿赂金额
|
|
73
75
|
const bribeAmount = config.bribeAmount && config.bribeAmount > 0 ? ethers.parseEther(String(config.bribeAmount)) : 0n;
|
|
@@ -59,12 +59,18 @@ export async function quoteV2(provider, tokenIn, tokenOut, amountIn, chain, rout
|
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
const results = await Promise.all(quotePromises);
|
|
62
|
-
//
|
|
62
|
+
// 取报价最高的路径:薄直连池(如 ANTFUN/WBNB)会先成功但少报,利润看起来不像万六
|
|
63
|
+
let best;
|
|
63
64
|
for (const result of results) {
|
|
64
|
-
if (result.success)
|
|
65
|
-
|
|
65
|
+
if (!result.success)
|
|
66
|
+
continue;
|
|
67
|
+
if (!best || result.amountOut > best.amountOut) {
|
|
68
|
+
best = { amountOut: result.amountOut, path: result.path };
|
|
66
69
|
}
|
|
67
70
|
}
|
|
71
|
+
if (best) {
|
|
72
|
+
return { amountOut: best.amountOut, path: best.path };
|
|
73
|
+
}
|
|
68
74
|
return { amountOut: 0n };
|
|
69
75
|
}
|
|
70
76
|
// ============================================================================
|
|
@@ -260,11 +266,8 @@ export async function quoteRoundTripProfitToNative(provider, quoteToken, buyQuot
|
|
|
260
266
|
};
|
|
261
267
|
const buyNative = await quoteLeg(buyQuoteWei);
|
|
262
268
|
const sellNative = sellQuoteWei === buyQuoteWei ? buyNative : await quoteLeg(sellQuoteWei);
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
throw new Error('计价币利润折成原生币报价为 0,请检查计价币流动性后重试');
|
|
266
|
-
}
|
|
267
|
-
return profit;
|
|
269
|
+
const notional = buyNative > sellNative ? buyNative : sellNative;
|
|
270
|
+
return calculateBundleSwapRoundTripProfit(notional, notional);
|
|
268
271
|
}
|
|
269
272
|
export async function quoteRoundTripProfitToNativeByChainId(provider, quoteToken, buyQuoteWei, sellQuoteWei, chainId) {
|
|
270
273
|
const chain = getQuoteChainKey(chainId);
|
|
@@ -10,7 +10,7 @@ import { quoteRoundTripProfitToNativeByChainId } from '../../../core/quote/quote
|
|
|
10
10
|
import { getGasPriceConfig, getTxType, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI, } from './config.js';
|
|
11
11
|
import { buildTransactionRequest } from '../../../core/tx/build-request.js';
|
|
12
12
|
import { BRIBE_GAS_LIMIT, ERC20_BALANCE_OF_ABI, } from './swap-helpers.js';
|
|
13
|
-
import { buildApprovalTransaction, buildProfitTransaction, calculateProfitAmount, createChainContext, quoteSellOutput, } from './swap-planning.js';
|
|
13
|
+
import { buildApprovalTransaction, buildProfitTransaction, calculateProfitAmount, createChainContext, grossUpSellProceedsToBuySide, quoteSellOutput, } from './swap-planning.js';
|
|
14
14
|
/**
|
|
15
15
|
* Flap 内盘批量换手(一卖多买)
|
|
16
16
|
*
|
|
@@ -100,13 +100,21 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
}));
|
|
103
|
-
// ✅
|
|
103
|
+
// ✅ 计算利润。换手按卖出代币的买侧计价收万六,避免曲线折价后只剩万五点多
|
|
104
|
+
const profitNotional = await grossUpSellProceedsToBuySide({
|
|
105
|
+
provider: chainContext.provider,
|
|
106
|
+
portalAddress: chainContext.portalAddress,
|
|
107
|
+
quoteToken: outputToken,
|
|
108
|
+
tokenAddress,
|
|
109
|
+
sellAmountWei,
|
|
110
|
+
sellProceedsWei: quote.quotedNative,
|
|
111
|
+
});
|
|
104
112
|
let nativeProfitAmount = 0n;
|
|
105
113
|
if (useNativeToken) {
|
|
106
|
-
nativeProfitAmount = calculateProfitAmount(
|
|
114
|
+
nativeProfitAmount = calculateProfitAmount(profitNotional, config.userType);
|
|
107
115
|
}
|
|
108
|
-
else if (
|
|
109
|
-
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken,
|
|
116
|
+
else if (profitNotional > 0n && quoteToken) {
|
|
117
|
+
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken, profitNotional, profitNotional, chainContext.chainId);
|
|
110
118
|
}
|
|
111
119
|
// ✅ 并行构建所有买入交易
|
|
112
120
|
const portalSeller = new Contract(chainContext.portalAddress, PORTAL_ABI, seller);
|
|
@@ -11,7 +11,7 @@ import { BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI, getBribeAmount, getGasPriceConfig,
|
|
|
11
11
|
import { buildTransactionRequest } from '../../../core/tx/build-request.js';
|
|
12
12
|
import { splitAmountByWeight as splitAmount } from '../../../core/amount/split-by-weight.js';
|
|
13
13
|
import { createChainContext } from './swap-buy-first-chain.js';
|
|
14
|
-
import { quoteBuyerOutput
|
|
14
|
+
import { quoteBuyerOutput } from './swap-buy-first-quote.js';
|
|
15
15
|
import { validateSwapCounts } from './swap-buy-first-plan.js';
|
|
16
16
|
import { buildProfitTransaction } from './swap-buy-first-profit.js';
|
|
17
17
|
/**
|
|
@@ -88,12 +88,10 @@ export async function flapBundleBuyFirstMultiWallet(params) {
|
|
|
88
88
|
const buyAmountsWei = splitAmount(totalFundsWei, buyCount);
|
|
89
89
|
// ✅ 将代币平均分配给卖方
|
|
90
90
|
const sellAmountsWei = splitAmount(quoteResult.sellAmountWei, sellCount);
|
|
91
|
-
// ✅
|
|
92
|
-
const portal = new Contract(chainContext.portalAddress, PORTAL_ABI, chainContext.provider);
|
|
93
|
-
const estimatedSellFunds = await estimateSellFunds(portal, tokenAddress, quoteResult.sellAmountWei, outputToken);
|
|
91
|
+
// ✅ 第二批:ERC20 转原生代币报价(如需要)
|
|
94
92
|
let nativeProfitAmount = 0n;
|
|
95
93
|
if (useNativeToken) {
|
|
96
|
-
nativeProfitAmount = calculateBundleSwapRoundTripProfit(totalFundsWei,
|
|
94
|
+
nativeProfitAmount = calculateBundleSwapRoundTripProfit(totalFundsWei, totalFundsWei);
|
|
97
95
|
}
|
|
98
96
|
else if (totalFundsWei > 0n) {
|
|
99
97
|
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, inputToken, totalFundsWei, totalFundsWei, chainContext.chainId);
|
|
@@ -9,7 +9,7 @@ import { ZERO_ADDRESS, GAS_LIMITS, calculateBundleSwapRoundTripProfit } from '..
|
|
|
9
9
|
import { getGasPriceConfig, getTxType, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI, } from './config.js';
|
|
10
10
|
import { buildTransactionRequest } from '../../../core/tx/build-request.js';
|
|
11
11
|
import { splitAmountByWeight as splitAmount } from '../../../core/amount/split-by-weight.js';
|
|
12
|
-
import { validateSwapCounts, calculateBuyerFunds, quoteBuyerOutput, ensureSellerBalance,
|
|
12
|
+
import { validateSwapCounts, calculateBuyerFunds, quoteBuyerOutput, ensureSellerBalance, planMultiNonces, buildProfitTransaction, createChainContext, flapBundleBuyFirstMultiWallet, } from './swap-buy-first-helpers.js';
|
|
13
13
|
export async function flapBundleBuyFirstMerkle(params) {
|
|
14
14
|
const { chain, buyerPrivateKey, buyerPrivateKeys, sellerPrivateKey, sellerPrivateKeys, tokenAddress, buyerFunds, buyerFundsPercentage, config, quoteToken, quoteTokenDecimals, buyCount: _buyCount, sellCount: _sellCount, } = params;
|
|
15
15
|
// ✅ 判断是否为多钱包模式
|
|
@@ -86,7 +86,7 @@ export async function flapBundleBuyFirstMerkle(params) {
|
|
|
86
86
|
// ✅ 拆分买入和卖出金额
|
|
87
87
|
const buyAmountsWei = splitAmount(buyerFundsWei, buyCount);
|
|
88
88
|
const sellAmountsWei = splitAmount(sellAmountWei, sellCount);
|
|
89
|
-
// ✅ 第三批并行 -
|
|
89
|
+
// ✅ 第三批并行 - 构建多笔买入和卖出交易
|
|
90
90
|
const buyUnsignedPromises = buyAmountsWei.map((amount) => portalBuyer.swapExactInput.populateTransaction({
|
|
91
91
|
inputToken,
|
|
92
92
|
outputToken: tokenAddress,
|
|
@@ -101,10 +101,9 @@ export async function flapBundleBuyFirstMerkle(params) {
|
|
|
101
101
|
minOutputAmount: 0,
|
|
102
102
|
permitData: '0x',
|
|
103
103
|
}));
|
|
104
|
-
const [buyUnsignedArray, sellUnsignedArray
|
|
104
|
+
const [buyUnsignedArray, sellUnsignedArray] = await Promise.all([
|
|
105
105
|
Promise.all(buyUnsignedPromises),
|
|
106
106
|
Promise.all(sellUnsignedPromises),
|
|
107
|
-
estimateSellFunds(portalSeller, tokenAddress, sellAmountWei, outputToken),
|
|
108
107
|
]);
|
|
109
108
|
// ✅ 获取贿赂金额
|
|
110
109
|
const bribeAmount = getBribeAmount(config);
|
|
@@ -123,7 +122,7 @@ export async function flapBundleBuyFirstMerkle(params) {
|
|
|
123
122
|
// 买合计万三 + 卖合计万三。ERC-20 先把买入合计折成原生币再计提,避免 ANTFUN 微额报价为 0
|
|
124
123
|
let nativeProfitAmount = 0n;
|
|
125
124
|
if (useNativeToken) {
|
|
126
|
-
nativeProfitAmount = calculateBundleSwapRoundTripProfit(buyerFundsWei,
|
|
125
|
+
nativeProfitAmount = calculateBundleSwapRoundTripProfit(buyerFundsWei, buyerFundsWei);
|
|
127
126
|
}
|
|
128
127
|
else if (buyerFundsWei > 0n) {
|
|
129
128
|
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, inputToken, buyerFundsWei, buyerFundsWei, chainContext.chainId);
|
|
@@ -22,6 +22,15 @@ type QuoteSellParams = {
|
|
|
22
22
|
outputToken?: string;
|
|
23
23
|
};
|
|
24
24
|
export declare function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, provider, skipQuoteOnError, outputToken, }: QuoteSellParams): Promise<QuoteResult>;
|
|
25
|
+
/** 换手按卖出所得收万六会像万五点多:卖出折价后小于买同等代币的花费。按卖出代币的买侧计价抬到买侧。 */
|
|
26
|
+
export declare function grossUpSellProceedsToBuySide(params: {
|
|
27
|
+
provider: ethers.JsonRpcProvider;
|
|
28
|
+
portalAddress: string;
|
|
29
|
+
quoteToken: string;
|
|
30
|
+
tokenAddress: string;
|
|
31
|
+
sellAmountWei: bigint;
|
|
32
|
+
sellProceedsWei: bigint;
|
|
33
|
+
}): Promise<bigint>;
|
|
25
34
|
type BuyerNeedParams = {
|
|
26
35
|
buyer: Wallet;
|
|
27
36
|
quotedNative: bigint;
|
|
@@ -65,6 +65,26 @@ export async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountW
|
|
|
65
65
|
throw new Error(`卖出报价失败: ${getErrorMessageFromUnknown(err)}`, { cause: err });
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
/** 换手按卖出所得收万六会像万五点多:卖出折价后小于买同等代币的花费。按卖出代币的买侧计价抬到买侧。 */
|
|
69
|
+
export async function grossUpSellProceedsToBuySide(params) {
|
|
70
|
+
const { sellAmountWei, sellProceedsWei } = params;
|
|
71
|
+
if (sellProceedsWei <= 0n || sellAmountWei <= 0n)
|
|
72
|
+
return sellProceedsWei;
|
|
73
|
+
try {
|
|
74
|
+
const portal = new Contract(params.portalAddress, PORTAL_ABI, params.provider);
|
|
75
|
+
const tokensBought = (await portal.quoteExactInput.staticCall({
|
|
76
|
+
inputToken: params.quoteToken,
|
|
77
|
+
outputToken: params.tokenAddress,
|
|
78
|
+
inputAmount: sellProceedsWei,
|
|
79
|
+
}));
|
|
80
|
+
if (tokensBought <= 0n || tokensBought >= sellAmountWei)
|
|
81
|
+
return sellProceedsWei;
|
|
82
|
+
return (sellProceedsWei * sellAmountWei) / tokensBought;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return sellProceedsWei;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
68
88
|
export async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider, }) {
|
|
69
89
|
const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
|
|
70
90
|
let buyerBalance;
|
|
@@ -12,7 +12,7 @@ import { getGasPriceConfig, getTxType, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, P
|
|
|
12
12
|
import { buildTransactionRequest } from '../../../core/tx/build-request.js';
|
|
13
13
|
import { GAS_LIMITS } from '../../../core/constants/index.js';
|
|
14
14
|
import { BRIBE_GAS_LIMIT, NATIVE_TRANSFER_GAS_LIMIT, buildBNBHopChainForERC20, buildERC20HopChain, buildNativeHopChain, generateDisperseHopPaths, } from './swap-helpers.js';
|
|
15
|
-
import { buildProfitTransaction, calculateProfitAmount, createChainContext, quoteSellOutput, } from './swap-planning.js';
|
|
15
|
+
import { buildProfitTransaction, calculateProfitAmount, createChainContext, grossUpSellProceedsToBuySide, quoteSellOutput, } from './swap-planning.js';
|
|
16
16
|
/**
|
|
17
17
|
* Flap 内盘快捷批量换手(资金利用率模式)
|
|
18
18
|
*
|
|
@@ -89,11 +89,19 @@ export async function flapQuickBatchSwapMerkle(params) {
|
|
|
89
89
|
outputToken,
|
|
90
90
|
});
|
|
91
91
|
const estimatedOutput = quote.quotedNative;
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const profitNotional = await grossUpSellProceedsToBuySide({
|
|
93
|
+
provider: chainContext.provider,
|
|
94
|
+
portalAddress: chainContext.portalAddress,
|
|
95
|
+
quoteToken: outputToken,
|
|
96
|
+
tokenAddress,
|
|
97
|
+
sellAmountWei,
|
|
98
|
+
sellProceedsWei: estimatedOutput,
|
|
99
|
+
});
|
|
100
|
+
// ✅ 计算利润。换手按卖出代币的买侧计价收万六;原生币从卖出所得预留,ERC-20 利润 hop 另付
|
|
101
|
+
const tokenProfitAmount = calculateProfitAmount(profitNotional, config.userType);
|
|
94
102
|
let nativeProfitAmount = tokenProfitAmount;
|
|
95
|
-
if (!useNativeToken &&
|
|
96
|
-
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken,
|
|
103
|
+
if (!useNativeToken && profitNotional > 0n && quoteToken) {
|
|
104
|
+
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken, profitNotional, profitNotional, chainContext.chainId);
|
|
97
105
|
}
|
|
98
106
|
const distributableAmount = useNativeToken ? estimatedOutput - tokenProfitAmount : estimatedOutput; // ERC20 模式利润从原生代币扣
|
|
99
107
|
// ✅ 计算每个买方分到的金额
|
|
@@ -10,7 +10,7 @@ import { quoteRoundTripProfitToNativeByChainId } from '../../../core/quote/quote
|
|
|
10
10
|
import { getGasPriceConfig, getTxType, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI, } from './config.js';
|
|
11
11
|
import { buildTransactionRequest } from '../../../core/tx/build-request.js';
|
|
12
12
|
import { BRIBE_GAS_LIMIT, } from './swap-helpers.js';
|
|
13
|
-
import { buildApprovalTransaction, buildNoncePlan, buildProfitTransaction, calculateBuyerNeed, calculateProfitAmount, createChainContext, planNonces, quoteSellOutput, validateBalances, } from './swap-planning.js';
|
|
13
|
+
import { buildApprovalTransaction, buildNoncePlan, buildProfitTransaction, calculateBuyerNeed, calculateProfitAmount, createChainContext, grossUpSellProceedsToBuySide, planNonces, quoteSellOutput, validateBalances, } from './swap-planning.js';
|
|
14
14
|
export async function flapBundleSwapMerkle(params) {
|
|
15
15
|
const { chain, sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, config, quoteToken, quoteTokenDecimals, startNonces, // ✅ 可选:前端预获取的 nonces
|
|
16
16
|
} = params;
|
|
@@ -63,13 +63,21 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
63
63
|
quoteTokenDecimals,
|
|
64
64
|
provider: chainContext.provider,
|
|
65
65
|
});
|
|
66
|
-
|
|
66
|
+
const profitNotional = await grossUpSellProceedsToBuySide({
|
|
67
|
+
provider: chainContext.provider,
|
|
68
|
+
portalAddress: chainContext.portalAddress,
|
|
69
|
+
quoteToken: outputToken,
|
|
70
|
+
tokenAddress,
|
|
71
|
+
sellAmountWei,
|
|
72
|
+
sellProceedsWei: quote.quotedNative,
|
|
73
|
+
});
|
|
74
|
+
// ✅ 计算利润。换手按卖出代币的买侧计价收万六,避免曲线折价后只剩万五点多
|
|
67
75
|
let nativeProfitAmount = 0n;
|
|
68
76
|
if (useNativeToken) {
|
|
69
|
-
nativeProfitAmount = calculateProfitAmount(
|
|
77
|
+
nativeProfitAmount = calculateProfitAmount(profitNotional, config.userType);
|
|
70
78
|
}
|
|
71
|
-
else if (
|
|
72
|
-
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken,
|
|
79
|
+
else if (profitNotional > 0n && quoteToken) {
|
|
80
|
+
nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken, profitNotional, profitNotional, chainContext.chainId);
|
|
73
81
|
}
|
|
74
82
|
// ✅ 获取贿赂金额
|
|
75
83
|
const bribeAmount = getBribeAmount(config);
|
|
@@ -8,6 +8,7 @@ import { Contract, formatEther } from 'ethers';
|
|
|
8
8
|
import { ADDRESSES, ZERO_ADDRESS } from '../../core/constants/index.js';
|
|
9
9
|
import { Helper3 } from '../four/contracts/helper3.js';
|
|
10
10
|
import { FlapPortal } from '../flap/portal.js';
|
|
11
|
+
import { getTaxTokenInfo, isTaxToken } from '../four/tax-token.js';
|
|
11
12
|
import { DEFAULT_V3_FEE_TIERS } from './lp-inspect-helpers.js';
|
|
12
13
|
import { getChainConfig } from './registry.js';
|
|
13
14
|
import { determinePlatform, formatBalance, getProvider, getTokenDecimals, normalizeLiquidity, queryV2Pairs, queryV3Pools, } from './inspect-helpers.js';
|
|
@@ -15,6 +16,12 @@ import { determinePlatform, formatBalance, getProvider, getTokenDecimals, normal
|
|
|
15
16
|
// 常量(从公共模块导入)
|
|
16
17
|
// ============================================================================
|
|
17
18
|
const MULTICALL3_ADDRESS = ADDRESSES.BSC.Multicall3;
|
|
19
|
+
/** BSC V8 买卖税;status=0 说明不是 Flap 币,slot 里常见残留 100 bps(1%)不能当当前税。 */
|
|
20
|
+
function flapV8TaxBps(st) {
|
|
21
|
+
if (!Number(st.status))
|
|
22
|
+
return 0;
|
|
23
|
+
return Math.max(Number(st.buyTaxRate ?? 0n), Number(st.sellTaxRate ?? 0n));
|
|
24
|
+
}
|
|
18
25
|
// ============================================================================
|
|
19
26
|
// 主查询函数
|
|
20
27
|
// ============================================================================
|
|
@@ -64,24 +71,25 @@ export async function inspectTokenLP(token, opts) {
|
|
|
64
71
|
if (opts.flapChain) {
|
|
65
72
|
try {
|
|
66
73
|
const flap = new FlapPortal({ chain: opts.flapChain, rpcUrl: opts.rpcUrl });
|
|
67
|
-
// ✅ 优先尝试 getTokenV7(包含 taxRate),失败则 fallback 到 getTokenV5
|
|
68
74
|
let st = null;
|
|
69
75
|
let taxRate;
|
|
70
|
-
|
|
76
|
+
const useBscV8 = opts.flapChain === 'BSC';
|
|
77
|
+
if (useBscV8) {
|
|
71
78
|
try {
|
|
72
79
|
const stV8 = await flap.getTokenV8Safe(token);
|
|
73
80
|
st = stV8;
|
|
74
|
-
taxRate =
|
|
81
|
+
taxRate = flapV8TaxBps(stV8);
|
|
75
82
|
}
|
|
76
83
|
catch {
|
|
77
|
-
// V8
|
|
84
|
+
// V8 不可用时只借 V7/V5 读盘面,不用 V7 残留 taxRate(常见 100 bps)
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
if (!st) {
|
|
81
88
|
try {
|
|
82
89
|
const stV7 = await flap.getTokenV7(token);
|
|
83
90
|
st = stV7;
|
|
84
|
-
|
|
91
|
+
if (!useBscV8)
|
|
92
|
+
taxRate = Number(stV7.taxRate ?? 0n);
|
|
85
93
|
}
|
|
86
94
|
catch {
|
|
87
95
|
st = await flap.getTokenV5(token);
|
|
@@ -190,6 +198,17 @@ export async function inspectTokenLP(token, opts) {
|
|
|
190
198
|
const offerTokens = formatBalance(info.offers, shouldFormat);
|
|
191
199
|
const lastPrice = formatBalance(info.lastPrice, shouldFormat);
|
|
192
200
|
result.four = { helper: ADDRESSES.BSC.TokenManagerHelper3, reserveNative, offerTokens, lastPrice };
|
|
201
|
+
try {
|
|
202
|
+
if (await isTaxToken(token, opts.rpcUrl)) {
|
|
203
|
+
const fee = Number((await getTaxTokenInfo(token, opts.rpcUrl)).config.feeRate);
|
|
204
|
+
const taxRate = fee > 0 && fee <= 10 ? fee * 100 : fee;
|
|
205
|
+
if (taxRate > 0)
|
|
206
|
+
result.taxRate = taxRate;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// 非 TaxToken 或读费率失败
|
|
211
|
+
}
|
|
193
212
|
return result;
|
|
194
213
|
}
|
|
195
214
|
}
|
|
@@ -331,14 +350,8 @@ export async function inspectTokenLP(token, opts) {
|
|
|
331
350
|
const flap = new FlapPortal({ chain: opts.flapChain, rpcUrl: opts.rpcUrl });
|
|
332
351
|
let taxRate = 0;
|
|
333
352
|
if (opts.flapChain === 'BSC') {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
taxRate = Math.max(Number(stV8.buyTaxRate ?? 0n), Number(stV8.sellTaxRate ?? 0n));
|
|
337
|
-
}
|
|
338
|
-
catch {
|
|
339
|
-
const stV7 = await flap.getTokenV7(token);
|
|
340
|
-
taxRate = Number(stV7.taxRate ?? 0n);
|
|
341
|
-
}
|
|
353
|
+
const stV8 = await flap.getTokenV8Safe(token);
|
|
354
|
+
taxRate = flapV8TaxBps(stV8);
|
|
342
355
|
}
|
|
343
356
|
else {
|
|
344
357
|
const stV7 = await flap.getTokenV7(token);
|