four-flap-meme-sdk 4.0.7 → 4.0.9

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.
Files changed (62) hide show
  1. package/dist/abis/flap/portal.js +2 -0
  2. package/dist/bundle/four-meme/swap/batch.js +4 -3
  3. package/dist/bundle/four-meme/swap/bundle.js +5 -3
  4. package/dist/bundle/four-meme/swap/quick-batch.js +3 -3
  5. package/dist/bundle/four-meme/swap-buy-first/helpers.d.ts +1 -1
  6. package/dist/bundle/four-meme/swap-buy-first/helpers.js +2 -5
  7. package/dist/bundle/four-meme/swap-buy-first/multi-wallet.js +3 -6
  8. package/dist/bundle/four-meme/swap-buy-first/single.js +5 -6
  9. package/dist/bundle/four-meme/swap-sign-helpers.d.ts +1 -1
  10. package/dist/bundle/four-meme/swap-sign-helpers.js +2 -6
  11. package/dist/chains/bsc/pancake/bundle-buy-first-multi-wallet.js +10 -14
  12. package/dist/chains/bsc/pancake/bundle-buy-first-plan.d.ts +1 -1
  13. package/dist/chains/bsc/pancake/bundle-buy-first-plan.js +2 -5
  14. package/dist/chains/bsc/pancake/bundle-buy-first.js +10 -15
  15. package/dist/chains/bsc/pancake/quote.d.ts +2 -2
  16. package/dist/chains/bsc/pancake/quote.js +5 -12
  17. package/dist/chains/bsc/platforms/iro/token.d.ts +1 -1
  18. package/dist/chains/bsc/platforms/iro/token.js +3 -5
  19. package/dist/chains/eni/platforms/daoaas/portal-direct-submit.js +4 -4
  20. package/dist/chains/xlayer/eip7702/bundle-swap-multi.js +4 -4
  21. package/dist/chains/xlayer/eip7702/profit.d.ts +6 -12
  22. package/dist/chains/xlayer/eip7702/profit.js +13 -22
  23. package/dist/chains/xlayer/eip7702/volume-bundle.js +5 -5
  24. package/dist/chains/xlayer/eip7702/volume-wash.js +4 -4
  25. package/dist/chains/xlayer/eoa/quote.d.ts +2 -2
  26. package/dist/chains/xlayer/eoa/quote.js +5 -10
  27. package/dist/core/constants/index.d.ts +2 -2
  28. package/dist/core/constants/index.js +2 -2
  29. package/dist/core/constants/profit.d.ts +7 -2
  30. package/dist/core/constants/profit.js +16 -6
  31. package/dist/core/constants/profit.test.d.ts +1 -0
  32. package/dist/core/constants/profit.test.js +18 -0
  33. package/dist/core/constants/quote.d.ts +2 -0
  34. package/dist/core/constants/quote.js +13 -0
  35. package/dist/core/quote/quote-helpers.d.ts +11 -0
  36. package/dist/core/quote/quote-helpers.js +42 -1
  37. package/dist/domains/flap/index.d.ts +1 -1
  38. package/dist/domains/flap/module.d.ts +1 -1
  39. package/dist/domains/flap/portal-bundle-merkle/core-helpers.js +3 -35
  40. package/dist/domains/flap/portal-bundle-merkle/core.js +3 -3
  41. package/dist/domains/flap/portal-bundle-merkle/swap-batch.js +9 -6
  42. package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-multi-wallet.js +10 -12
  43. package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-plan.d.ts +1 -1
  44. package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-plan.js +2 -5
  45. package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-quote.js +3 -24
  46. package/dist/domains/flap/portal-bundle-merkle/swap-buy-first.js +10 -14
  47. package/dist/domains/flap/portal-bundle-merkle/swap-helpers.js +3 -23
  48. package/dist/domains/flap/portal-bundle-merkle/swap-planning.d.ts +1 -1
  49. package/dist/domains/flap/portal-bundle-merkle/swap-planning.js +3 -14
  50. package/dist/domains/flap/portal-bundle-merkle/swap-quick-batch.js +4 -4
  51. package/dist/domains/flap/portal-bundle-merkle/swap-single.js +9 -8
  52. package/dist/domains/flap/portal.d.ts +1 -1
  53. package/dist/domains/flap/reader.d.ts +8 -1
  54. package/dist/domains/flap/reader.js +48 -1
  55. package/dist/domains/flap/types.d.ts +14 -0
  56. package/dist/domains/holders/holders-maker.js +3 -7
  57. package/dist/domains/lp-inspect/inspect.js +33 -9
  58. package/dist/exports/root-foundations.d.ts +2 -2
  59. package/dist/exports/root-foundations.js +1 -1
  60. package/dist/utils/constants.d.ts +1 -1
  61. package/dist/utils/constants.js +1 -1
  62. package/package.json +1 -1
@@ -6,12 +6,13 @@
6
6
  */
7
7
  import { ethers, Contract } from 'ethers';
8
8
  import { truncateDecimals } from './volume-helpers.js';
9
- import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, calculateProfitAmountByTxCount, getProfitRecipient, } from './utils.js';
9
+ import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, getProfitRecipient, } from './utils.js';
10
+ import { calculateBundleSwapRoundTripProfit } from '../../../core/constants/index.js';
10
11
  import { UNIFIED_DELEGATE_ADDRESS, UNIFIED_DELEGATE_ABI, FLAP_PORTAL_ABI, FLAP_PORTAL_ADDRESS, WOKB_ADDRESS, V3_FEE_TIERS, } from './constants.js';
11
12
  import { quoteV2, quoteV3 } from '../../../core/quote/quote-helpers.js';
12
13
  import { getDefaultRouter, buildBuyCall, buildSellCall, buildSellCallWithAmount } from './volume-internal.js';
13
14
  export async function washVolume(params) {
14
- const { mainPrivateKey, privateKeys, tokenAddress, tokenDecimals = 18, buyAmountPerWallet, sellPercent = 100, poolType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', // ✅ 用户类型(影响利润率)
15
+ const { mainPrivateKey, privateKeys, tokenAddress, tokenDecimals = 18, buyAmountPerWallet, sellPercent = 100, poolType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType: _userType = 'v0', // 档位已统一为 bundleSwap 两腿万六
15
16
  config, } = params;
16
17
  if (!mainPrivateKey) {
17
18
  throw new Error('必须提供 mainPrivateKey(Payer 钱包私钥)');
@@ -46,8 +47,7 @@ export async function washVolume(params) {
46
47
  // 计算金额(无币刷量:每个钱包 1买 + 1卖 = 2笔交易)
47
48
  const buyAmountWei = ethers.parseEther(truncateDecimals(buyAmountPerWallet));
48
49
  const totalBuyAmount = buyAmountWei * BigInt(wallets.length);
49
- const totalTxCount = wallets.length * 2; // 每个钱包 1买 + 1卖
50
- const profitAmount = calculateProfitAmountByTxCount(totalBuyAmount, totalTxCount, userType);
50
+ const profitAmount = calculateBundleSwapRoundTripProfit(totalBuyAmount, totalBuyAmount);
51
51
  const profitRecipient = getProfitRecipient(config);
52
52
  // ========================================
53
53
  // 合并所有钱包(去重)
@@ -1,6 +1,6 @@
1
1
  import type { JsonRpcProvider } from 'ethers';
2
2
  import { type RouteParams, type UserType } from './eoa-bundle-swap-types.js';
3
- export declare function getProfitRateBps(userType?: UserType): number;
4
- export declare function calculateProfitAmount(estimatedOutput: bigint, userType?: UserType): bigint;
3
+ export declare function getProfitRateBps(_userType?: UserType): number;
4
+ export declare function calculateProfitAmount(estimatedOutput: bigint, _userType?: UserType): bigint;
5
5
  export declare function quoteSellOutput(provider: JsonRpcProvider, routeParams: RouteParams, sellAmountWei: bigint): Promise<bigint>;
6
6
  export declare function getERC20ToOkbQuote(provider: JsonRpcProvider, tokenAddress: string, tokenAmount: bigint, version?: 'v2' | 'v3', fee?: number): Promise<bigint>;
@@ -1,19 +1,14 @@
1
- import { CHAINS, getProfitRateBps as getSharedProfitRateBps } from '../../../core/constants/index.js';
1
+ import { CHAINS, getProfitRateBps as getSharedProfitRateBps, calculateBundleSwapRoundTripProfit } from '../../../core/constants/index.js';
2
2
  import { quoteV2, quoteV3 } from '../../../core/quote/quote-helpers.js';
3
3
  import { WOKB_ADDRESS, } from './eoa-bundle-swap-types.js';
4
4
  const XLAYER_CHAIN_NAME = CHAINS.XLAYER.name;
5
- export function getProfitRateBps(userType) {
6
- if (userType === 'v0')
7
- return getSharedProfitRateBps('v0Single');
8
- if (userType === 'v1')
9
- return getSharedProfitRateBps('v1Single');
10
- return getSharedProfitRateBps('v0Single');
5
+ export function getProfitRateBps(_userType) {
6
+ return getSharedProfitRateBps('bundleSwap');
11
7
  }
12
- export function calculateProfitAmount(estimatedOutput, userType) {
8
+ export function calculateProfitAmount(estimatedOutput, _userType) {
13
9
  if (estimatedOutput <= 0n)
14
10
  return 0n;
15
- const rateBps = getProfitRateBps(userType);
16
- return (estimatedOutput * BigInt(rateBps)) / 10000n;
11
+ return calculateBundleSwapRoundTripProfit(estimatedOutput, estimatedOutput);
17
12
  }
18
13
  // ==================== 报价函数 ====================
19
14
  export async function quoteSellOutput(provider, routeParams, sellAmountWei) {
@@ -10,8 +10,8 @@
10
10
  */
11
11
  export { CHAINS, CHAIN_ID_MAP, getChainById, getChainName, getDefaultRpcUrl, isKnownChain, isBscChain, isXLayerChain, isMonadChain, isEniChain, getConfirmationTimeout, type ChainKey, type ChainConfig, } from './chains.js';
12
12
  export { GAS_LIMITS, GAS_CONFIG, V3_FEE_TIERS, calculateGasLimit, getTransferGasLimit, type GasLimitKey, type V3FeeTier, } from './gas.js';
13
- export { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS, type QuoteConfigChain } from './quote.js';
13
+ export { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS, getQuoteChainKey, type QuoteConfigChain } from './quote.js';
14
14
  /** Flap 链标识(与 `FlapPortal` 一致,供子路径 `./constants` 使用) */
15
15
  export type { FlapChain } from '../../domains/flap/portal.js';
16
16
  export { ZERO_ADDRESS, ZERO_BYTES32, BLOCKRAZOR_BUILDER_EOA, ADDRESSES, getAddress, getWrappedNativeAddress, getMulticall3Address, getFlapPortalAddress, isZeroAddress, isNativeToken, ENI_SPENDERS, getEniSpenders, type ChainAddresses, type AddressKey, } from './addresses.js';
17
- export { PROFIT_CONFIG, getProfitRecipient, getAllProfitRecipients, getProfitRateBps, calculateProfitAmount, calculateProfitHopGasCost, type ProfitRateKey, TRANSFER_FEE_PER_ADDRESS, getTransferFeePerAddress, calculateTransferFee, } from './profit.js';
17
+ export { PROFIT_CONFIG, getProfitRecipient, getAllProfitRecipients, getProfitRateBps, calculateProfitAmount, calculateBundleSwapRoundTripProfit, calculateProfitHopGasCost, type ProfitRateKey, TRANSFER_FEE_PER_ADDRESS, getTransferFeePerAddress, calculateTransferFee, } from './profit.js';
@@ -16,7 +16,7 @@ export { CHAINS, CHAIN_ID_MAP, getChainById, getChainName, getDefaultRpcUrl, isK
16
16
  // Gas 常量
17
17
  // ============================================================================
18
18
  export { GAS_LIMITS, GAS_CONFIG, V3_FEE_TIERS, calculateGasLimit, getTransferGasLimit, } from './gas.js';
19
- export { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS } from './quote.js';
19
+ export { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS, getQuoteChainKey } from './quote.js';
20
20
  // ============================================================================
21
21
  // 合约地址
22
22
  // ============================================================================
@@ -24,6 +24,6 @@ export { ZERO_ADDRESS, ZERO_BYTES32, BLOCKRAZOR_BUILDER_EOA, ADDRESSES, getAddre
24
24
  // ============================================================================
25
25
  // 利润配置
26
26
  // ============================================================================
27
- export { PROFIT_CONFIG, getProfitRecipient, getAllProfitRecipients, getProfitRateBps, calculateProfitAmount, calculateProfitHopGasCost,
27
+ export { PROFIT_CONFIG, getProfitRecipient, getAllProfitRecipients, getProfitRateBps, calculateProfitAmount, calculateBundleSwapRoundTripProfit, calculateProfitHopGasCost,
28
28
  // ✅ 钱包转账按地址收费
29
29
  TRANSFER_FEE_PER_ADDRESS, getTransferFeePerAddress, calculateTransferFee, } from './profit.js';
@@ -9,9 +9,9 @@ export declare const PROFIT_CONFIG: {
9
9
  readonly RECIPIENT: string;
10
10
  /** 利润比例(基点 bps,1 bps = 0.01%) */
11
11
  RATES: {
12
- /** 普通模式:40 bps = 0.4% */
12
+ /** 普通模式:30 bps = 0.3%(代币交易 / 拉盘砸盘) */
13
13
  NORMAL: number;
14
- /** 捆绑换手模式:6 bps = 0.06% */
14
+ /** 捆绑换手 / 刷量单腿:3 bps = 0.03%;买合计 + 卖合计 = 万六 */
15
15
  BUNDLE_SWAP: number;
16
16
  /** V0 用户单边:8 bps = 0.08% */
17
17
  V0_SINGLE: number;
@@ -50,6 +50,11 @@ export declare function getProfitRateBps(mode: 'normal' | 'bundleSwap' | 'v0Sing
50
50
  * @param rateBps 利润比例(基点)
51
51
  */
52
52
  export declare function calculateProfitAmount(amount: bigint, rateBps: number): bigint;
53
+ /**
54
+ * 刷量 / 换手:买的合计收万三,卖的合计(同计价)再收万三。
55
+ * 与钱包数量无关;两腿金额接近时合计万六。
56
+ */
57
+ export declare function calculateBundleSwapRoundTripProfit(buyQuoteWei: bigint, sellQuoteWei: bigint): bigint;
53
58
  /**
54
59
  * 计算利润多跳所需的 Gas 费用
55
60
  * @param gasPrice Gas 价格
@@ -21,10 +21,10 @@ export const PROFIT_CONFIG = {
21
21
  },
22
22
  /** 利润比例(基点 bps,1 bps = 0.01%) */
23
23
  RATES: {
24
- /** 普通模式:40 bps = 0.4% */
25
- NORMAL: 40,
26
- /** 捆绑换手模式:6 bps = 0.06% */
27
- BUNDLE_SWAP: 6,
24
+ /** 普通模式:30 bps = 0.3%(代币交易 / 拉盘砸盘) */
25
+ NORMAL: 30,
26
+ /** 捆绑换手 / 刷量单腿:3 bps = 0.03%;买合计 + 卖合计 = 万六 */
27
+ BUNDLE_SWAP: 3,
28
28
  /** V0 用户单边:8 bps = 0.08% */
29
29
  V0_SINGLE: 8,
30
30
  /** V0 用户双边:4 bps = 0.04% */
@@ -88,6 +88,16 @@ export function getProfitRateBps(mode) {
88
88
  export function calculateProfitAmount(amount, rateBps) {
89
89
  return (amount * BigInt(rateBps)) / 10000n;
90
90
  }
91
+ /**
92
+ * 刷量 / 换手:买的合计收万三,卖的合计(同计价)再收万三。
93
+ * 与钱包数量无关;两腿金额接近时合计万六。
94
+ */
95
+ export function calculateBundleSwapRoundTripProfit(buyQuoteWei, sellQuoteWei) {
96
+ const rate = getProfitRateBps('bundleSwap');
97
+ const buy = buyQuoteWei > 0n ? buyQuoteWei : 0n;
98
+ const sell = sellQuoteWei > 0n ? sellQuoteWei : 0n;
99
+ return calculateProfitAmount(buy, rate) + calculateProfitAmount(sell, rate);
100
+ }
91
101
  /**
92
102
  * 计算利润多跳所需的 Gas 费用
93
103
  * @param gasPrice Gas 价格
@@ -109,8 +119,8 @@ export function calculateProfitHopGasCost(gasPrice) {
109
119
  * - 所有代币(原生币/ERC20)统一按地址执行次数收取原生币
110
120
  */
111
121
  export const TRANSFER_FEE_PER_ADDRESS = {
112
- 56: 1000000000000000n, // BSC: 0.001 BNB
113
- 97: 1000000000000000n, // BSC Testnet: 0.001 tBNB
122
+ 56: 100000000000000n, // BSC: 0.0001 BNB
123
+ 97: 100000000000000n, // BSC Testnet: 0.0001 tBNB
114
124
  196: 10000000000000000n, // XLayer: 0.01 OKB
115
125
  143: 1000000000000000n, // Monad: 0.001 MON
116
126
  8453: 1000000000000000n, // Base: 0.001 ETH
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { calculateBundleSwapRoundTripProfit, calculateProfitAmount, getProfitRateBps, } from './profit.js';
3
+ describe('bundle swap round-trip profit', () => {
4
+ it('charges 3 bps on buy sum and 3 bps on sell sum, not per wallet', () => {
5
+ const buy = 1000000n;
6
+ const sell = 1000000n;
7
+ expect(getProfitRateBps('bundleSwap')).toBe(3);
8
+ expect(calculateBundleSwapRoundTripProfit(buy, sell)).toBe(600n);
9
+ expect(calculateBundleSwapRoundTripProfit(buy, sell)).toBe(calculateProfitAmount(buy, 3) + calculateProfitAmount(sell, 3));
10
+ });
11
+ it('uses actual buy/sell totals when they differ', () => {
12
+ expect(calculateBundleSwapRoundTripProfit(1000000n, 500000n)).toBe(300n + 150n);
13
+ });
14
+ it('ignores non-positive legs', () => {
15
+ expect(calculateBundleSwapRoundTripProfit(1000000n, 0n)).toBe(300n);
16
+ expect(calculateBundleSwapRoundTripProfit(0n, 1000000n)).toBe(300n);
17
+ });
18
+ });
@@ -28,3 +28,5 @@ export declare const QUOTE_CONFIG: {
28
28
  /** V3 报价尝试费率列表(与 `gas.V3_FEE_TIERS` 命名对象区分) */
29
29
  export declare const QUOTE_V3_FEE_TIERS: readonly [100, 500, 2500, 10000];
30
30
  export type QuoteConfigChain = keyof typeof QUOTE_CONFIG;
31
+ /** chainId → QUOTE_CONFIG 键;Flap 旧接口传数字 chainId,不能直接当 'BSC' 用 */
32
+ export declare function getQuoteChainKey(chainId: number): QuoteConfigChain | undefined;
@@ -1,3 +1,4 @@
1
+ import { CHAINS } from './chains.js';
1
2
  /** DEX 报价链配置(V2 Router / V3 Quoter / 包装原生币 / 稳定币) */
2
3
  export const QUOTE_CONFIG = {
3
4
  BSC: {
@@ -35,3 +36,15 @@ export const QUOTE_CONFIG = {
35
36
  };
36
37
  /** V3 报价尝试费率列表(与 `gas.V3_FEE_TIERS` 命名对象区分) */
37
38
  export const QUOTE_V3_FEE_TIERS = [100, 500, 2500, 10000];
39
+ /** chainId → QUOTE_CONFIG 键;Flap 旧接口传数字 chainId,不能直接当 'BSC' 用 */
40
+ export function getQuoteChainKey(chainId) {
41
+ if (chainId === CHAINS.BSC.chainId)
42
+ return 'BSC';
43
+ if (chainId === CHAINS.MONAD.chainId)
44
+ return 'MONAD';
45
+ if (chainId === CHAINS.XLAYER.chainId)
46
+ return 'XLAYER';
47
+ if (chainId === CHAINS.ENI.chainId)
48
+ return 'ENI';
49
+ return undefined;
50
+ }
@@ -55,6 +55,17 @@ export declare function quote(params: QuoteParams): Promise<QuoteResult>;
55
55
  * @returns 等值的原生代币数量(wei),失败返回 0n
56
56
  */
57
57
  export declare function getTokenToNativeQuote(provider: JsonRpcProvider, tokenAddress: string, tokenAmount: bigint, chain: string, version?: 'v2' | 'v3', fee?: number, routerOverride?: string): Promise<bigint>;
58
+ /**
59
+ * Flap 等旧接口传 chainId 数字;转成 QUOTE_CONFIG 键后再走多跳报价。
60
+ * ANTFUN 往往没有 ANTFUN→WBNB 直连池,只走直连会报 0,刷量看起来没收万六。
61
+ */
62
+ export declare function getTokenToNativeQuoteByChainId(provider: JsonRpcProvider, tokenAddress: string, tokenAmount: bigint, chainId: number): Promise<bigint>;
63
+ /**
64
+ * 刷量/换手 ERC-20 计价:先把买/卖合计折成原生币,再各收万三。
65
+ * 不要先抽 6bps 计价币再报价,ANTFUN 等微额路径会报 0,看起来没收万六。
66
+ */
67
+ export declare function quoteRoundTripProfitToNative(provider: JsonRpcProvider, quoteToken: string, buyQuoteWei: bigint, sellQuoteWei: bigint, chain: string, version?: 'v2' | 'v3', fee?: number, routerOverride?: string): Promise<bigint>;
68
+ export declare function quoteRoundTripProfitToNativeByChainId(provider: JsonRpcProvider, quoteToken: string, buyQuoteWei: bigint, sellQuoteWei: bigint, chainId: number): Promise<bigint>;
58
69
  /**
59
70
  * 获取原生代币 → ERC20 代币的报价
60
71
  *
@@ -8,7 +8,8 @@
8
8
  */
9
9
  import { Contract } from 'ethers';
10
10
  import { V2_ROUTER_QUOTE_ABI, V3_QUOTER_ABI } from '../../abis/common.js';
11
- import { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS } from '../constants/quote.js';
11
+ import { calculateBundleSwapRoundTripProfit } from '../constants/profit.js';
12
+ import { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS, getQuoteChainKey } from '../constants/quote.js';
12
13
  const V2_ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
13
14
  export { QUOTE_CONFIG, QUOTE_V3_FEE_TIERS };
14
15
  /**
@@ -232,6 +233,46 @@ export async function getTokenToNativeQuote(provider, tokenAddress, tokenAmount,
232
233
  });
233
234
  return result.amountOut;
234
235
  }
236
+ /**
237
+ * Flap 等旧接口传 chainId 数字;转成 QUOTE_CONFIG 键后再走多跳报价。
238
+ * ANTFUN 往往没有 ANTFUN→WBNB 直连池,只走直连会报 0,刷量看起来没收万六。
239
+ */
240
+ export async function getTokenToNativeQuoteByChainId(provider, tokenAddress, tokenAmount, chainId) {
241
+ const chain = getQuoteChainKey(chainId);
242
+ if (!chain)
243
+ return 0n;
244
+ try {
245
+ return await getTokenToNativeQuote(provider, tokenAddress, tokenAmount, chain);
246
+ }
247
+ catch {
248
+ return 0n;
249
+ }
250
+ }
251
+ /**
252
+ * 刷量/换手 ERC-20 计价:先把买/卖合计折成原生币,再各收万三。
253
+ * 不要先抽 6bps 计价币再报价,ANTFUN 等微额路径会报 0,看起来没收万六。
254
+ */
255
+ export async function quoteRoundTripProfitToNative(provider, quoteToken, buyQuoteWei, sellQuoteWei, chain, version = 'v2', fee, routerOverride) {
256
+ const quoteLeg = async (amount) => {
257
+ if (amount <= 0n)
258
+ return 0n;
259
+ return getTokenToNativeQuote(provider, quoteToken, amount, chain, version, fee, routerOverride);
260
+ };
261
+ const buyNative = await quoteLeg(buyQuoteWei);
262
+ const sellNative = sellQuoteWei === buyQuoteWei ? buyNative : await quoteLeg(sellQuoteWei);
263
+ const profit = calculateBundleSwapRoundTripProfit(buyNative, sellNative);
264
+ if (profit <= 0n && (buyQuoteWei > 0n || sellQuoteWei > 0n)) {
265
+ throw new Error('计价币利润折成原生币报价为 0,请检查计价币流动性后重试');
266
+ }
267
+ return profit;
268
+ }
269
+ export async function quoteRoundTripProfitToNativeByChainId(provider, quoteToken, buyQuoteWei, sellQuoteWei, chainId) {
270
+ const chain = getQuoteChainKey(chainId);
271
+ if (!chain) {
272
+ throw new Error('当前链不支持把计价币利润折成原生币');
273
+ }
274
+ return quoteRoundTripProfitToNative(provider, quoteToken, buyQuoteWei, sellQuoteWei, chain);
275
+ }
235
276
  /**
236
277
  * 获取原生代币 → ERC20 代币的报价
237
278
  *
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Flap domain public facade
3
3
  */
4
- export { FlapPortal, FlapPortalWriter, type TokenStateV7, V3LPFeeProfile, lpFeeProfileToV3Fee, FLAP_TOTAL_SUPPLY, } from './module.js';
4
+ export { FlapPortal, FlapPortalWriter, type TokenStateV7, type TokenStateV8, V3LPFeeProfile, lpFeeProfileToV3Fee, FLAP_TOTAL_SUPPLY, } from './module.js';
5
5
  export { flapBundleSwapMerkle, flapBatchSwapMerkle, flapQuickBatchSwapMerkle, flapCrossSwapMerkle, flapBundleBuyFirstMerkle, flapDisperseWithBundleMerkle, flapSweepWithBundleMerkle, createTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle, batchSellWithBundleMerkle, flapBundleCreateToDex, } from './portal-bundle-merkle/index.js';
6
6
  export type { FlapSwapSignConfig, FlapSwapConfig, FlapBundleSwapSignParams, FlapBundleSwapParams, FlapSwapResult, FlapBatchSwapSignParams, FlapBatchSwapResult, FlapQuickBatchSwapSignParams, FlapQuickBatchSwapResult, FlapCrossSwapParams, FlapCrossSwapResult, UserType as FlapSwapUserType, FlapBuyFirstSignConfig, FlapBuyFirstConfig, FlapBundleBuyFirstSignParams, FlapBundleBuyFirstParams, FlapBuyFirstResult, FlapDisperseSignParams, FlapDisperseMerkleResult, FlapSweepSignParams, FlapSweepMerkleResult, } from './portal-bundle-merkle/index.js';
7
7
  export type { FlapChain } from './portal.js';
@@ -7,7 +7,7 @@
7
7
  * 使用时请从具体文件导入
8
8
  */
9
9
  export { FlapPortal, FlapPortalWriter, type FlapChain, // 主要的 FlapChain 定义
10
- type PortalConfig, type TokenStateV2, type TokenStateV3, type TokenStateV4, type TokenStateV5, type TokenStateV7, type QuoteExactInputParams, type ExactInputParams, type ExactInputV3Params, type NewTokenV3Params, type NewTokenV4Params, type NewTokenV5Params, type TaxDistributionConfig, validateTaxDistribution, TokenStatus, TokenVersion, FeeType, DexThreshType, MigratorType, V3LPFeeProfile, lpFeeProfileToV3Fee, DEXId, } from './portal.js';
10
+ type PortalConfig, type TokenStateV2, type TokenStateV3, type TokenStateV4, type TokenStateV5, type TokenStateV7, type TokenStateV8, type QuoteExactInputParams, type ExactInputParams, type ExactInputV3Params, type NewTokenV3Params, type NewTokenV4Params, type NewTokenV5Params, type TaxDistributionConfig, validateTaxDistribution, TokenStatus, TokenVersion, FeeType, DexThreshType, MigratorType, V3LPFeeProfile, lpFeeProfileToV3Fee, DEXId, } from './portal.js';
11
11
  export { CDPV2 } from './curve.js';
12
12
  export { buildPermitPiggybackAuto } from './permit.js';
13
13
  export { uploadTokenMeta, type TokenMetaInput } from './ipfs.js';
@@ -1,8 +1,9 @@
1
1
  import { ethers, Contract, Wallet, Interface, } from 'ethers';
2
- import { ADDRESSES, CHAINS, } from '../../../core/constants/index.js';
2
+ import { ADDRESSES, } from '../../../core/constants/index.js';
3
3
  import { MULTICALL3_ABI, V2_ROUTER_QUOTE_ABI, } from '../../../core/shared-abis/common.js';
4
4
  import { getGasLimit, } from '../../../core/gas/bundle-gas.js';
5
5
  import { getOptimizedGasPrice, } from '../../../utils/bundle-helpers.js';
6
+ import { getTokenToNativeQuoteByChainId } from '../../../core/quote/quote-helpers.js';
6
7
  import { CHAIN_ID_MAP, PORTAL_ABI, getTxType, getGasPriceConfig, calculateProfit, getProfitRecipient, } from './config.js';
7
8
  import { normalizeTaxLaunchConfig, } from '../portal-create-token.js';
8
9
  import { MigratorType } from '../portal.js';
@@ -30,40 +31,7 @@ export const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
30
31
  * @returns 等值的原生代币数量(wei),失败返回 0n
31
32
  */
32
33
  export async function getTokenToNativeQuote(provider, tokenAddress, tokenAmount, chainId) {
33
- if (tokenAmount <= 0n)
34
- return 0n;
35
- try {
36
- if (chainId === CHAINS.BSC.chainId) {
37
- // BSC: 使用 PancakeSwap V2 Router
38
- const router = new Contract(BSC_PANCAKE_V2_ROUTER, ROUTER_ABI, provider);
39
- const amounts = await router.getAmountsOut(tokenAmount, [tokenAddress, BSC_WBNB]);
40
- return amounts[1];
41
- }
42
- if (chainId === CHAINS.MONAD.chainId) {
43
- // ✅ Monad: 使用 PancakeSwap V2 Router
44
- const router = new Contract(MONAD_PANCAKE_V2_ROUTER, ROUTER_ABI, provider);
45
- const amounts = await router.getAmountsOut(tokenAmount, [tokenAddress, MONAD_WMON]);
46
- return amounts[1];
47
- }
48
- if (chainId === CHAINS.XLAYER.chainId) {
49
- // ✅ XLAYER: 使用 PotatoSwap V2 Router(USDT0 → WOKB)
50
- const router = new Contract(XLAYER_POTATOSWAP_V2_ROUTER, ROUTER_ABI, provider);
51
- const amounts = await router.getAmountsOut(tokenAmount, [tokenAddress, XLAYER_WOKB]);
52
- return amounts[1];
53
- }
54
- if (chainId === CHAINS.BASE.chainId) {
55
- // ✅ Base: 目前大部分 Flap 交易使用 ETH(原生代币),ERC20 报价暂不支持
56
- // Base 主力 DEX 是 Uniswap V3,V2 Router 流动性有限,暂返回 0
57
- // TODO: 后续可接入 Uniswap V3 QuoterV2 进行精确报价
58
- return 0n;
59
- }
60
- // 其他链暂不支持报价,返回 0
61
- return 0n;
62
- }
63
- catch {
64
- // 报价失败返回 0(可能是流动性不足或路径不存在)
65
- return 0n;
66
- }
34
+ return getTokenToNativeQuoteByChainId(provider, tokenAddress, tokenAmount, chainId);
67
35
  }
68
36
  // ==================== 内部辅助函数(从 core.ts 抽取)====================
69
37
  export function validateQuoteTokenDecimals(decimals, source) {
@@ -29,11 +29,11 @@ export async function createTokenWithBundleBuyMerkle(params) {
29
29
  const portalAddr = FLAP_PORTAL_ADDRESSES[chain];
30
30
  const originalPortalAddr = FLAP_ORIGINAL_PORTAL_ADDRESSES[chain];
31
31
  const portal = new ethers.Contract(originalPortalAddr, PORTAL_ABI, devWallet);
32
- const { normalizedTax, useV7Portal } = resolveCreateTokenLaunchFlags(params);
32
+ const { normalizedTax, useV7Portal, isTaxLaunch } = resolveCreateTokenLaunchFlags(params);
33
33
  const inputToken = params.quoteToken && params.quoteToken !== ZERO_ADDRESS ? params.quoteToken : ZERO_ADDRESS;
34
34
  const useNativeToken = inputToken === ZERO_ADDRESS;
35
35
  const extractProfit = config.extractProfitOnLaunch === false ? false : shouldExtractProfit(config);
36
- const useMethodA = canUseLaunchMethodA(privateKeys, buyAmounts, devWallet.address, useNativeToken);
36
+ const useMethodA = !isTaxLaunch && canUseLaunchMethodA(privateKeys, buyAmounts, devWallet.address, useNativeToken);
37
37
  let methodAQuoteAmt = 0n;
38
38
  let methodABuyMeta;
39
39
  if (useMethodA) {
@@ -113,7 +113,7 @@ export async function createTokenWithBundleBuyMerkle(params) {
113
113
  }
114
114
  nonceManager.clearTemp();
115
115
  return {
116
- signedTransactions: [...bribeTxs, ...signedTxs, ...profitTxs],
116
+ signedTransactions: [...signedTxs, ...bribeTxs, ...profitTxs],
117
117
  tokenAddress,
118
118
  profitHopWallets,
119
119
  metadata: {
@@ -6,9 +6,10 @@ import { getGasLimit } from '../../../core/gas/bundle-gas.js';
6
6
  import { calculateSellAmount } from '../../../utils/swap-helpers.js';
7
7
  import { NonceManager, getOptimizedGasPrice } from '../../../utils/bundle-helpers.js';
8
8
  import { ZERO_ADDRESS } from '../../../core/constants/index.js';
9
+ import { quoteRoundTripProfitToNativeByChainId } from '../../../core/quote/quote-helpers.js';
9
10
  import { getGasPriceConfig, getTxType, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI, } from './config.js';
10
11
  import { buildTransactionRequest } from '../../../core/tx/build-request.js';
11
- import { BRIBE_GAS_LIMIT, ERC20_BALANCE_OF_ABI, getTokenToNativeQuote, } from './swap-helpers.js';
12
+ import { BRIBE_GAS_LIMIT, ERC20_BALANCE_OF_ABI, } from './swap-helpers.js';
12
13
  import { buildApprovalTransaction, buildProfitTransaction, calculateProfitAmount, createChainContext, quoteSellOutput, } from './swap-planning.js';
13
14
  /**
14
15
  * Flap 内盘批量换手(一卖多买)
@@ -99,11 +100,13 @@ export async function flapBatchSwapMerkle(params) {
99
100
  }
100
101
  }
101
102
  }));
102
- // ✅ 计算利润(根据 userType 动态调整)
103
- const tokenProfitAmount = calculateProfitAmount(quote.quotedNative, config.userType);
104
- let nativeProfitAmount = tokenProfitAmount;
105
- if (!useNativeToken && tokenProfitAmount > 0n) {
106
- nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, quoteToken, tokenProfitAmount, chainContext.chainId);
103
+ // ✅ 计算利润。ERC-20 先把卖出合计折成原生币再计提万六,避免 ANTFUN 微额报价为 0
104
+ let nativeProfitAmount = 0n;
105
+ if (useNativeToken) {
106
+ nativeProfitAmount = calculateProfitAmount(quote.quotedNative, config.userType);
107
+ }
108
+ else if (quote.quotedNative > 0n && quoteToken) {
109
+ nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, quoteToken, quote.quotedNative, quote.quotedNative, chainContext.chainId);
107
110
  }
108
111
  // ✅ 并行构建所有买入交易
109
112
  const portalSeller = new Contract(chainContext.portalAddress, PORTAL_ABI, seller);
@@ -4,14 +4,15 @@
4
4
  import { ethers, Contract, Wallet } from 'ethers';
5
5
  import { getGasLimit } from '../../../core/gas/bundle-gas.js';
6
6
  import { NonceManager, getOptimizedGasPrice } from '../../../utils/bundle-helpers.js';
7
- import { ZERO_ADDRESS, GAS_LIMITS } from '../../../core/constants/index.js';
7
+ import { ZERO_ADDRESS, GAS_LIMITS, calculateBundleSwapRoundTripProfit } from '../../../core/constants/index.js';
8
+ import { quoteRoundTripProfitToNativeByChainId } from '../../../core/quote/quote-helpers.js';
8
9
  import { ERC20_BALANCE_ABI } from '../../../core/shared-abis/common.js';
9
10
  import { BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI, getBribeAmount, getGasPriceConfig, getTxType, } from './config.js';
10
11
  import { buildTransactionRequest } from '../../../core/tx/build-request.js';
11
12
  import { splitAmountByWeight as splitAmount } from '../../../core/amount/split-by-weight.js';
12
13
  import { createChainContext } from './swap-buy-first-chain.js';
13
- import { quoteBuyerOutput, estimateSellFunds, getTokenToNativeQuote } from './swap-buy-first-quote.js';
14
- import { getProfitRatePerTxBps, validateSwapCounts } from './swap-buy-first-plan.js';
14
+ import { quoteBuyerOutput, estimateSellFunds } from './swap-buy-first-quote.js';
15
+ import { validateSwapCounts } from './swap-buy-first-plan.js';
15
16
  import { buildProfitTransaction } from './swap-buy-first-profit.js';
16
17
  /**
17
18
  * ✅ Flap 多钱包捆绑换手
@@ -30,9 +31,6 @@ export async function flapBundleBuyFirstMultiWallet(params) {
30
31
  throw new Error('卖方钱包数量不能为0');
31
32
  // 验证总交易数不超过限制
32
33
  validateSwapCounts(buyCount, sellCount);
33
- // ✅ 计算利润比例(根据 userType 动态调整)
34
- const totalTxCount = buyCount + sellCount;
35
- const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
36
34
  const chainContext = createChainContext(chain, config.rpcUrl);
37
35
  const nonceManager = new NonceManager(chainContext.provider);
38
36
  // 创建所有钱包实例
@@ -93,12 +91,12 @@ export async function flapBundleBuyFirstMultiWallet(params) {
93
91
  // ✅ 第二批并行:估算利润 + ERC20 转原生代币报价(如需要)
94
92
  const portal = new Contract(chainContext.portalAddress, PORTAL_ABI, chainContext.provider);
95
93
  const estimatedSellFunds = await estimateSellFunds(portal, tokenAddress, quoteResult.sellAmountWei, outputToken);
96
- const profitBase = estimatedSellFunds > 0n ? estimatedSellFunds : totalFundsWei;
97
- const tokenProfitAmount = (profitBase * BigInt(profitRateBps)) / 10000n;
98
- // ERC20 购买:获取代币利润等值的原生代币报价
99
- let nativeProfitAmount = tokenProfitAmount;
100
- if (!useNativeToken && tokenProfitAmount > 0n) {
101
- nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, inputToken, tokenProfitAmount, chainContext.chainId);
94
+ let nativeProfitAmount = 0n;
95
+ if (useNativeToken) {
96
+ nativeProfitAmount = calculateBundleSwapRoundTripProfit(totalFundsWei, estimatedSellFunds > 0n ? estimatedSellFunds : totalFundsWei);
97
+ }
98
+ else if (totalFundsWei > 0n) {
99
+ nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, inputToken, totalFundsWei, totalFundsWei, chainContext.chainId);
102
100
  }
103
101
  // ✅ 第三批并行:构建并签名所有交易
104
102
  const allTransactions = [];
@@ -7,7 +7,7 @@ import type { MultiNoncePlan, UserType } from './swap-buy-first-types.js';
7
7
  /**
8
8
  * 根据 userType 获取每笔交易的利润率
9
9
  */
10
- export declare function getProfitRatePerTxBps(userType?: UserType): number;
10
+ export declare function getProfitRatePerTxBps(_userType?: UserType): number;
11
11
  /**
12
12
  * 验证买卖笔数
13
13
  */
@@ -3,11 +3,8 @@ import { BRIBE_TX_COUNT, MAX_BUNDLE_SIGNATURES, MAX_SWAP_TX_COUNT, PROFIT_TX_COU
3
3
  /**
4
4
  * 根据 userType 获取每笔交易的利润率
5
5
  */
6
- export function getProfitRatePerTxBps(userType) {
7
- if (userType === 'v1') {
8
- return getProfitRateBps('v1Double');
9
- }
10
- return getProfitRateBps('v0Double'); // v0 或默认
6
+ export function getProfitRatePerTxBps(_userType) {
7
+ return getProfitRateBps('bundleSwap');
11
8
  }
12
9
  /**
13
10
  * 验证买卖笔数
@@ -2,11 +2,11 @@
2
2
  * Flap BuyFirst 报价/资金/余额 helper(从 swap-buy-first-helpers.ts 抽取)
3
3
  */
4
4
  import { ethers, Contract } from 'ethers';
5
- import { CHAINS, ZERO_ADDRESS } from '../../../core/constants/index.js';
5
+ import { ZERO_ADDRESS } from '../../../core/constants/index.js';
6
6
  import { ERC20_BALANCE_ABI } from '../../../core/shared-abis/common.js';
7
7
  import { getErrorMessageFromUnknown } from '../../../core/index.js';
8
8
  import { PORTAL_ABI } from './config.js';
9
- import { BSC_PANCAKE_V2_ROUTER, BSC_WBNB, MONAD_PANCAKE_V2_ROUTER, MONAD_WMON, ROUTER_ABI, } from './swap-buy-first-constants.js';
9
+ import { getTokenToNativeQuoteByChainId } from '../../../core/quote/quote-helpers.js';
10
10
  /**
11
11
  * 获取 ERC20 代币 → 原生代币的报价
12
12
  * @param provider - Provider 实例
@@ -16,28 +16,7 @@ import { BSC_PANCAKE_V2_ROUTER, BSC_WBNB, MONAD_PANCAKE_V2_ROUTER, MONAD_WMON, R
16
16
  * @returns 等值的原生代币数量(wei),失败返回 0n
17
17
  */
18
18
  export async function getTokenToNativeQuote(provider, tokenAddress, tokenAmount, chainId) {
19
- if (tokenAmount <= 0n)
20
- return 0n;
21
- try {
22
- if (chainId === CHAINS.BSC.chainId) {
23
- // BSC: 使用 PancakeSwap V2 Router
24
- const router = new Contract(BSC_PANCAKE_V2_ROUTER, ROUTER_ABI, provider);
25
- const amounts = await router.getAmountsOut(tokenAmount, [tokenAddress, BSC_WBNB]);
26
- return amounts[1];
27
- }
28
- if (chainId === CHAINS.MONAD.chainId) {
29
- // ✅ Monad: 使用 PancakeSwap V2 Router
30
- const router = new Contract(MONAD_PANCAKE_V2_ROUTER, ROUTER_ABI, provider);
31
- const amounts = await router.getAmountsOut(tokenAmount, [tokenAddress, MONAD_WMON]);
32
- return amounts[1];
33
- }
34
- // ✅ Base (8453) / XLayer (196) 等链暂不支持 V2 报价,返回 0
35
- return 0n;
36
- }
37
- catch {
38
- // 报价失败返回 0(可能是流动性不足或路径不存在)
39
- return 0n;
40
- }
19
+ return getTokenToNativeQuoteByChainId(provider, tokenAddress, tokenAmount, chainId);
41
20
  }
42
21
  // ✅ 使用公共模块中的 ERC20_BALANCE_ABI
43
22
  const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
@@ -4,12 +4,12 @@
4
4
  import { ethers, Contract, Wallet } from 'ethers';
5
5
  import { getGasLimit } from '../../../core/gas/bundle-gas.js';
6
6
  import { NonceManager, getOptimizedGasPrice, } from '../../../utils/bundle-helpers.js';
7
- import { ZERO_ADDRESS } from '../../../core/constants/index.js';
8
- import { GAS_LIMITS } from '../../../core/constants/index.js';
7
+ import { quoteRoundTripProfitToNativeByChainId } from '../../../core/quote/quote-helpers.js';
8
+ import { ZERO_ADDRESS, GAS_LIMITS, calculateBundleSwapRoundTripProfit } from '../../../core/constants/index.js';
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 { getProfitRatePerTxBps, getTokenToNativeQuote, validateSwapCounts, calculateBuyerFunds, quoteBuyerOutput, ensureSellerBalance, estimateSellFunds, calculateMultiProfitAmount, planMultiNonces, buildProfitTransaction, createChainContext, flapBundleBuyFirstMultiWallet, } from './swap-buy-first-helpers.js';
12
+ import { validateSwapCounts, calculateBuyerFunds, quoteBuyerOutput, ensureSellerBalance, estimateSellFunds, 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
  // ✅ 判断是否为多钱包模式
@@ -34,9 +34,6 @@ export async function flapBundleBuyFirstMerkle(params) {
34
34
  throw new Error('单钱包模式需要提供 buyerPrivateKey 和 sellerPrivateKey');
35
35
  }
36
36
  validateSwapCounts(buyCount, sellCount);
37
- // ✅ 计算利润比例(根据 userType 动态调整)
38
- const totalTxCount = buyCount + sellCount;
39
- const profitRateBps = getProfitRatePerTxBps(config.userType) * totalTxCount;
40
37
  const chainContext = createChainContext(chain, config.rpcUrl);
41
38
  const buyer = new Wallet(buyerPrivateKey, chainContext.provider);
42
39
  const seller = new Wallet(sellerPrivateKey, chainContext.provider);
@@ -123,14 +120,13 @@ export async function flapBundleBuyFirstMerkle(params) {
123
120
  sameAddress,
124
121
  nonceManager,
125
122
  });
126
- // ✅ 修复:基于卖出收益估算利润(使用动态利润比例)
127
- const profitBase = estimatedSellFunds > 0n ? estimatedSellFunds : buyerFundsWei;
128
- const tokenProfitAmount = calculateMultiProfitAmount(profitBase, profitRateBps);
129
- // ✅ ERC20 购买:获取代币利润等值的原生代币(BNB)报价
130
- let nativeProfitAmount = tokenProfitAmount; // 原生代币购买时直接使用
131
- if (!useNativeToken && tokenProfitAmount > 0n) {
132
- // 将代币利润转换为等值 BNB
133
- nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, inputToken, tokenProfitAmount, chainContext.chainId);
123
+ // 买合计万三 + 卖合计万三。ERC-20 先把买入合计折成原生币再计提,避免 ANTFUN 微额报价为 0
124
+ let nativeProfitAmount = 0n;
125
+ if (useNativeToken) {
126
+ nativeProfitAmount = calculateBundleSwapRoundTripProfit(buyerFundsWei, estimatedSellFunds > 0n ? estimatedSellFunds : buyerFundsWei);
127
+ }
128
+ else if (buyerFundsWei > 0n) {
129
+ nativeProfitAmount = await quoteRoundTripProfitToNativeByChainId(chainContext.provider, inputToken, buyerFundsWei, buyerFundsWei, chainContext.chainId);
134
130
  }
135
131
  // ✅ 构建多笔买入交易
136
132
  const buyTxs = buyUnsignedArray.map((unsigned, i) => buildTransactionRequest(unsigned, {