four-flap-meme-sdk 2.0.0 → 2.2.0
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/__tests__/subpath-exports.test.js +64 -0
- package/dist/chains/bsc/iro.d.ts +5 -0
- package/dist/chains/bsc/iro.js +4 -0
- package/dist/chains/eni/flat-aliases.d.ts +10 -0
- package/dist/chains/eni/flat-aliases.js +8 -0
- package/dist/chains/eni/index.d.ts +1 -0
- package/dist/chains/eni/index.js +1 -0
- package/dist/chains/index.d.ts +13 -0
- package/dist/chains/index.js +13 -0
- package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
- package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
- package/dist/chains/xlayer/eip7702/index.d.ts +1 -0
- package/dist/chains/xlayer/eip7702/index.js +1 -0
- package/dist/chains/xlayer/index.d.ts +3 -2
- package/dist/chains/xlayer/index.js +4 -7
- package/dist/flap/index.d.ts +10 -0
- package/dist/flap/index.js +8 -0
- package/dist/merkle/index.d.ts +12 -0
- package/dist/merkle/index.js +11 -0
- package/dist/shared/constants/index.d.ts +2 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/vanity/index.d.ts +5 -0
- package/dist/vanity/index.js +5 -0
- package/package.json +93 -2
- package/dist/chains/bsc/four/disperse.d.ts +0 -12
- package/dist/chains/bsc/four/disperse.js +0 -470
- package/dist/chains/bsc/four/pairwise.d.ts +0 -7
- package/dist/chains/bsc/four/pairwise.js +0 -308
- package/dist/chains/bsc/four/submit/blockrazor.d.ts +0 -18
- package/dist/chains/bsc/four/submit/blockrazor.js +0 -86
- package/dist/chains/bsc/four/submit/direct.d.ts +0 -66
- package/dist/chains/bsc/four/submit/direct.js +0 -452
- package/dist/chains/bsc/four/submit/helpers.d.ts +0 -18
- package/dist/chains/bsc/four/submit/helpers.js +0 -57
- package/dist/chains/bsc/four/submit/index.d.ts +0 -12
- package/dist/chains/bsc/four/submit/index.js +0 -11
- package/dist/chains/bsc/four/submit/merkle.d.ts +0 -18
- package/dist/chains/bsc/four/submit/merkle.js +0 -74
- package/dist/chains/bsc/four/submit/types.d.ts +0 -143
- package/dist/chains/bsc/four/swap/index.d.ts +0 -32
- package/dist/chains/bsc/four/swap/index.js +0 -829
- package/dist/chains/bsc/four/swap/types.d.ts +0 -70
- package/dist/chains/bsc/four/swap/types.js +0 -1
- package/dist/chains/bsc/four/sweep.d.ts +0 -13
- package/dist/chains/bsc/four/sweep.js +0 -788
- package/dist/chains/bsc/four/utils/index.d.ts +0 -20
- package/dist/chains/bsc/four/utils/index.js +0 -1558
- package/dist/chains/bsc/four/utils/types.d.ts +0 -1
- package/dist/chains/bsc/four/utils/types.js +0 -1
- package/dist/chains/bsc/pancake/bundle-buy-first/index.d.ts +0 -8
- package/dist/chains/bsc/pancake/bundle-buy-first/index.js +0 -907
- package/dist/chains/bsc/pancake/bundle-buy-first/types.d.ts +0 -73
- package/dist/chains/bsc/pancake/bundle-buy-first/types.js +0 -1
- package/dist/chains/bsc/pancake/bundle-swap/helpers.d.ts +0 -102
- package/dist/chains/bsc/pancake/bundle-swap/helpers.js +0 -572
- package/dist/chains/bsc/pancake/bundle-swap/index.d.ts +0 -50
- package/dist/chains/bsc/pancake/bundle-swap/index.js +0 -1066
- package/dist/chains/bsc/pancake/bundle-swap/types.d.ts +0 -202
- package/dist/chains/bsc/pancake/bundle-swap/types.js +0 -3
- package/dist/chains/xlayer/eip7702/bundle-swap/index.d.ts +0 -72
- package/dist/chains/xlayer/eip7702/bundle-swap/index.js +0 -921
- package/dist/chains/xlayer/eip7702/bundle-swap/types.d.ts +0 -65
- package/dist/chains/xlayer/eip7702/bundle-swap/types.js +0 -1
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.d.ts +0 -128
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.js +0 -857
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.d.ts +0 -85
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.js +0 -1
- package/dist/chains/xlayer/eip7702/volume/index.d.ts +0 -96
- package/dist/chains/xlayer/eip7702/volume/index.js +0 -793
- package/dist/chains/xlayer/eip7702/volume/types.d.ts +0 -124
- package/dist/chains/xlayer/eip7702/volume/types.js +0 -1
- package/dist/chains/xlayer/eoa/types-core.d.ts +0 -363
- package/dist/chains/xlayer/eoa/types-core.js +0 -53
- package/dist/chains/xlayer/eoa/types-create.d.ts +0 -413
- package/dist/chains/xlayer/eoa/types-create.js +0 -9
- package/dist/chains/xlayer/eoa/types-volume.d.ts +0 -209
- package/dist/chains/xlayer/eoa/types-volume.js +0 -13
- package/dist/dex/direct-router/index.d.ts +0 -70
- package/dist/dex/direct-router/index.js +0 -1410
- package/dist/dex/direct-router/types.d.ts +0 -81
- package/dist/dex/direct-router/types.js +0 -1
- package/dist/shared/abis/TaxToken.json +0 -969
- package/dist/shared/abis/TokenManager.json +0 -836
- package/dist/shared/abis/TokenManager2.json +0 -136
- package/dist/shared/abis/TokenManagerHelper3.json +0 -993
- package/dist/shared/abis 2/TaxToken.json +0 -105
- package/dist/shared/abis 2/TokenManager.json +0 -836
- package/dist/shared/abis 2/TokenManager2.json +0 -60
- package/dist/shared/abis 2/TokenManagerHelper3.json +0 -993
- package/dist/shared/abis 2/common.d.ts +0 -85
- package/dist/shared/abis 2/common.js +0 -254
- package/dist/shared/abis 2/index.d.ts +0 -8
- package/dist/shared/abis 2/index.js +0 -8
- package/dist/shared/clients 2/blockrazor.d.ts +0 -314
- package/dist/shared/clients 2/blockrazor.js +0 -596
- package/dist/shared/clients 2/club48.d.ts +0 -154
- package/dist/shared/clients 2/club48.js +0 -331
- package/dist/shared/clients 2/emitservice.d.ts +0 -47
- package/dist/shared/clients 2/emitservice.js +0 -44
- package/dist/shared/clients 2/four.d.ts +0 -132
- package/dist/shared/clients 2/four.js +0 -281
- package/dist/shared/clients 2/merkle.d.ts +0 -210
- package/dist/shared/clients 2/merkle.js +0 -400
- package/dist/shared/flap/__tests__/curve.test.d.ts +0 -1
- package/dist/shared/flap/__tests__/curve.test.js +0 -85
- package/dist/shared/flap/portal/index.d.ts +0 -12
- package/dist/shared/flap/portal/index.js +0 -11
- package/dist/shared/flap/portal/portal.d.ts +0 -47
- package/dist/shared/flap/portal/portal.js +0 -218
- package/dist/shared/flap/portal/types.d.ts +0 -227
- package/dist/shared/flap/portal/types.js +0 -80
- package/dist/shared/flap/portal/writer.d.ts +0 -121
- package/dist/shared/flap/portal/writer.js +0 -265
- package/dist/shared/flap/portal-bundle-merkle/core/index.d.ts +0 -18
- package/dist/shared/flap/portal-bundle-merkle/core/index.js +0 -938
- package/dist/shared/flap/portal-bundle-merkle/core/types.d.ts +0 -1
- package/dist/shared/flap/portal-bundle-merkle/core/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/swap/index.d.ts +0 -42
- package/dist/shared/flap/portal-bundle-merkle/swap/index.js +0 -1448
- package/dist/shared/flap/portal-bundle-merkle/swap/types.d.ts +0 -84
- package/dist/shared/flap/portal-bundle-merkle/swap/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/utils/index.d.ts +0 -17
- package/dist/shared/flap/portal-bundle-merkle/utils/index.js +0 -1024
- package/dist/shared/flap/portal-bundle-merkle/utils/types.d.ts +0 -16
- package/dist/shared/flap/portal-bundle-merkle/utils/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/utils-helpers.d.ts +0 -100
- package/dist/shared/flap/portal-bundle-merkle/utils-helpers.js +0 -133
- package/dist/shared/flap 2/__tests__/curve.test.d.ts +0 -1
- package/dist/shared/flap 2/__tests__/curve.test.js +0 -85
- package/dist/shared/flap 2/abi.d.ts +0 -4
- package/dist/shared/flap 2/abi.js +0 -4
- package/dist/shared/flap 2/constants.d.ts +0 -128
- package/dist/shared/flap 2/constants.js +0 -143
- package/dist/shared/flap 2/curve.d.ts +0 -33
- package/dist/shared/flap 2/curve.js +0 -84
- package/dist/shared/flap 2/errors.d.ts +0 -37
- package/dist/shared/flap 2/errors.js +0 -114
- package/dist/shared/flap 2/index.d.ts +0 -22
- package/dist/shared/flap 2/index.js +0 -33
- package/dist/shared/flap 2/ipfs.d.ts +0 -21
- package/dist/shared/flap 2/ipfs.js +0 -38
- package/dist/shared/flap 2/meta.d.ts +0 -30
- package/dist/shared/flap 2/meta.js +0 -195
- package/dist/shared/flap 2/permit.d.ts +0 -16
- package/dist/shared/flap 2/permit.js +0 -67
- package/dist/shared/flap 2/pinata.d.ts +0 -40
- package/dist/shared/flap 2/pinata.js +0 -106
- package/dist/shared/flap 2/portal-bundle-merkle/config.d.ts +0 -79
- package/dist/shared/flap 2/portal-bundle-merkle/config.js +0 -133
- package/dist/shared/flap 2/portal-bundle-merkle/core.d.ts +0 -18
- package/dist/shared/flap 2/portal-bundle-merkle/core.js +0 -938
- package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.d.ts +0 -125
- package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.js +0 -665
- package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.d.ts +0 -88
- package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.js +0 -446
- package/dist/shared/flap 2/portal-bundle-merkle/index.d.ts +0 -14
- package/dist/shared/flap 2/portal-bundle-merkle/index.js +0 -26
- package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.d.ts +0 -28
- package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.js +0 -701
- package/dist/shared/flap 2/portal-bundle-merkle/private.d.ts +0 -17
- package/dist/shared/flap 2/portal-bundle-merkle/private.js +0 -549
- package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.d.ts +0 -65
- package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.js +0 -831
- package/dist/shared/flap 2/portal-bundle-merkle/swap.d.ts +0 -201
- package/dist/shared/flap 2/portal-bundle-merkle/swap.js +0 -1359
- package/dist/shared/flap 2/portal-bundle-merkle/types.d.ts +0 -358
- package/dist/shared/flap 2/portal-bundle-merkle/types.js +0 -1
- package/dist/shared/flap 2/portal-bundle-merkle/utils.d.ts +0 -89
- package/dist/shared/flap 2/portal-bundle-merkle/utils.js +0 -963
- package/dist/shared/flap 2/portal-bundle.d.ts +0 -119
- package/dist/shared/flap 2/portal-bundle.js +0 -584
- package/dist/shared/flap 2/portal.d.ts +0 -392
- package/dist/shared/flap 2/portal.js +0 -559
- package/dist/shared/flap 2/vanity.d.ts +0 -48
- package/dist/shared/flap 2/vanity.js +0 -110
- package/dist/shared/flap 2/vault.d.ts +0 -240
- package/dist/shared/flap 2/vault.js +0 -366
- package/dist/shared/four 2/index.d.ts +0 -7
- package/dist/shared/four 2/index.js +0 -22
- package/dist/shared/four 2/tax-token.d.ts +0 -176
- package/dist/shared/four 2/tax-token.js +0 -302
- package/dist/shared/index 2.js +0 -10
- package/dist/shared/index.d 2.ts +0 -10
- package/dist/types/distribute.d.ts +0 -72
- package/dist/types/distribute.js +0 -1
- package/dist/types 2/errors.d.ts +0 -27
- package/dist/types 2/errors.js +0 -34
- package/dist/utils/__tests__/errors.test.d.ts +0 -1
- package/dist/utils/__tests__/errors.test.js +0 -76
- package/dist/utils/airdrop-sweep-types.d.ts +0 -1
- package/dist/utils/airdrop-sweep-types.js +0 -1
- package/dist/utils/erc20/index.d.ts +0 -242
- package/dist/utils/erc20/index.js +0 -645
- package/dist/utils/erc20/types.d.ts +0 -77
- package/dist/utils/erc20/types.js +0 -1
- package/dist/utils/erc20-types.d.ts +0 -1
- package/dist/utils/erc20-types.js +0 -1
- package/dist/utils/holders-maker/helpers.d.ts +0 -43
- package/dist/utils/holders-maker/helpers.js +0 -371
- package/dist/utils/holders-maker/index.d.ts +0 -26
- package/dist/utils/holders-maker/index.js +0 -218
- package/dist/utils/holders-maker/types.d.ts +0 -72
- package/dist/utils/holders-maker/types.js +0 -4
- package/dist/utils/holders-maker-types.d.ts +0 -1
- package/dist/utils/holders-maker-types.js +0 -1
- package/dist/utils/lp-inspect/index.d.ts +0 -44
- package/dist/utils/lp-inspect/index.js +0 -937
- package/dist/utils/lp-inspect/types.d.ts +0 -100
- package/dist/utils/lp-inspect/types.js +0 -1
- package/dist/utils/lp-inspect-types.d.ts +0 -1
- package/dist/utils/lp-inspect-types.js +0 -1
- package/dist/utils/private-sale-types.d.ts +0 -1
- package/dist/utils/private-sale-types.js +0 -1
- package/dist/utils/quote-helpers/index.d.ts +0 -107
- package/dist/utils/quote-helpers/index.js +0 -346
- package/dist/utils/quote-helpers/types.d.ts +0 -16
- package/dist/utils/quote-helpers/types.js +0 -1
- package/dist/utils/quote-helpers-types.d.ts +0 -1
- package/dist/utils/quote-helpers-types.js +0 -1
- /package/dist/{chains/bsc/four/submit/types.js → __tests__/subpath-exports.test.d.ts} +0 -0
|
@@ -1,937 +0,0 @@
|
|
|
1
|
-
import { Contract, JsonRpcProvider, Interface, formatUnits, formatEther } from 'ethers';
|
|
2
|
-
import { ADDRESSES, ZERO_ADDRESS } from '../constants.js';
|
|
3
|
-
import { MULTICALL3_ABI, V2_FACTORY_ABI, V2_PAIR_ABI, V3_FACTORY_ABI, ERC20_ABI } from '../../shared/abis/common.js';
|
|
4
|
-
import { Helper3 } from '../../contracts/helper3.js';
|
|
5
|
-
import { FlapPortal } from '../../shared/flap/portal.js';
|
|
6
|
-
// ============================================================================
|
|
7
|
-
// 类型定义
|
|
8
|
-
// ============================================================================
|
|
9
|
-
/** DEX 配置 */
|
|
10
|
-
/** 链配置 */
|
|
11
|
-
/** 单个交易对信息 */
|
|
12
|
-
/** V3 池子信息(带 fee) */
|
|
13
|
-
/** DEX 池子信息 */
|
|
14
|
-
/** 最佳池子推荐 */
|
|
15
|
-
/** LP 平台类型 */
|
|
16
|
-
/** 查询选项 */
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// 链配置
|
|
19
|
-
// ============================================================================
|
|
20
|
-
/** 默认 V3 费率档位(合并 PancakeSwap 和 Uniswap 的所有档位) */
|
|
21
|
-
const DEFAULT_V3_FEE_TIERS = [100, 500, 2500, 3000, 10000];
|
|
22
|
-
/** 链 DEX 配置 */
|
|
23
|
-
const CHAIN_DEX_CONFIGS = {
|
|
24
|
-
BSC: {
|
|
25
|
-
wrappedNative: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
|
|
26
|
-
wrappedNativeSymbol: 'WBNB',
|
|
27
|
-
stableCoins: [
|
|
28
|
-
{ address: '0x55d398326f99059fF775485246999027B3197955', symbol: 'USDT', decimals: 18 },
|
|
29
|
-
{ address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', symbol: 'USDC', decimals: 18 },
|
|
30
|
-
],
|
|
31
|
-
dexes: {
|
|
32
|
-
PANCAKESWAP: {
|
|
33
|
-
name: 'PancakeSwap',
|
|
34
|
-
v2Factory: '0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73',
|
|
35
|
-
v3Factory: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865',
|
|
36
|
-
enabled: true,
|
|
37
|
-
},
|
|
38
|
-
IROSWAP: {
|
|
39
|
-
name: 'IROSwap',
|
|
40
|
-
v2Factory: ADDRESSES.BSC.IroSwapV2Factory,
|
|
41
|
-
v2Router: ADDRESSES.BSC.IroSwapV2Router,
|
|
42
|
-
enabled: true,
|
|
43
|
-
},
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
MONAD: {
|
|
47
|
-
wrappedNative: '0x3bd359c1119da7da1d913d1c4d2b7c461115433a',
|
|
48
|
-
wrappedNativeSymbol: 'WMON',
|
|
49
|
-
stableCoins: [
|
|
50
|
-
{ address: '0x754704bc059f8c67012fed69bc8a327a5aafb603', symbol: 'USDC', decimals: 6 },
|
|
51
|
-
],
|
|
52
|
-
dexes: {
|
|
53
|
-
PANCAKESWAP: {
|
|
54
|
-
name: 'PancakeSwap',
|
|
55
|
-
v2Factory: '0x44c90b66eb4c4f814cea6aaf2ac71ca88fa77308',
|
|
56
|
-
v3Factory: '0x40ce898c43df68c8c4229cd5ce21d3ce1f3ddcf1',
|
|
57
|
-
enabled: true,
|
|
58
|
-
},
|
|
59
|
-
UNISWAP: {
|
|
60
|
-
name: 'Uniswap',
|
|
61
|
-
v2Factory: '0x182a927119d56008d921126764bf884221b10f59',
|
|
62
|
-
v3Factory: '0x204faca1764b154221e35c0d20abb3c525710498',
|
|
63
|
-
v2Router: '0x4b2ab38dbf28d31d467aa8993f6c2585981d6804',
|
|
64
|
-
v3Router: '0xd6145b2d3f379919e8cdeda7b97e37c4b2ca9c40',
|
|
65
|
-
quoterV2: '0x661e93cca42afacb172121ef892830ca3b70f08d',
|
|
66
|
-
enabled: true,
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
// ✅ 新增 XLayer 配置
|
|
71
|
-
XLAYER: {
|
|
72
|
-
wrappedNative: '0xe538905cf8410324e03a5a23c1c177a474d59b2b',
|
|
73
|
-
wrappedNativeSymbol: 'WOKB',
|
|
74
|
-
stableCoins: [
|
|
75
|
-
{ address: '0x1e4a5963abfd975d8c9021ce480b42188849d41d', symbol: 'USDT', decimals: 6 },
|
|
76
|
-
{ address: '0x74b7f16337b8972027f6196a17a631ac6de26d22', symbol: 'USDC', decimals: 6 },
|
|
77
|
-
// ✅ XLayer: USD₮0 / USDT0(常见外盘配对)
|
|
78
|
-
{ address: '0x779ded0c9e1022225f8e0630b35a9b54be713736', symbol: 'USDT0', decimals: 6 },
|
|
79
|
-
],
|
|
80
|
-
dexes: {
|
|
81
|
-
POTATOSWAP: {
|
|
82
|
-
name: 'PotatoSwap',
|
|
83
|
-
v2Factory: '0x630DB8E822805c82Ca40a54daE02dd5aC31f7fcF', // V2 Factory
|
|
84
|
-
v2Router: '0x881fb2f98c13d521009464e7d1cbf16e1b394e8e', // ✅ V2 Router (标准 Uniswap V2 风格)
|
|
85
|
-
v3Router: '0xB45D0149249488333E3F3f9F359807F4b810C1FC', // SwapRouter02 (V3 风格)
|
|
86
|
-
v3Factory: '0xa1415fAe79c4B196d087F02b8aD5a622B8A827E5', // V3 Factory
|
|
87
|
-
quoterV2: '0x5A6f3723346aF54a4D0693bfC1718D64d4915C3e', // QuoterV2
|
|
88
|
-
enabled: true,
|
|
89
|
-
},
|
|
90
|
-
DYORSWAP: {
|
|
91
|
-
name: 'DYORSwap',
|
|
92
|
-
v2Factory: '0x2CcaDb1e437AA9cDc741574bDa154686B1F04C09', // ✅ V2 Factory
|
|
93
|
-
v2Router: '0xfb001fbbace32f09cb6d3c449b935183de53ee96', // DYORSwap Router (SwapRouter02 风格)
|
|
94
|
-
enabled: true, // ✅ 已启用
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
ENI: {
|
|
99
|
-
wrappedNative: '0x6d1e851446f4d004ae2a72f9afed85e8829a205e',
|
|
100
|
-
wrappedNativeSymbol: 'WEGAS',
|
|
101
|
-
stableCoins: [
|
|
102
|
-
{ address: '0xDC1a8A35b0BaA3229b13f348ED708a2fd50b5e3a', symbol: 'USDT', decimals: 18 },
|
|
103
|
-
{ address: '0xaFF944b96c1BAEA587159ec446280E468B32ee15', symbol: 'USDC', decimals: 18 },
|
|
104
|
-
],
|
|
105
|
-
dexes: {
|
|
106
|
-
DSWAP: {
|
|
107
|
-
name: 'DSWAP',
|
|
108
|
-
v2Factory: '0x548c0e26ce90b333c07abb6d55546304d46d269d',
|
|
109
|
-
v2Router: '0x97ed8be49d9a8b86247090aa41e908e76b8fcf22',
|
|
110
|
-
v3Factory: '0xa97c5a70Be5B81f573a688F656E7bE569B492A56',
|
|
111
|
-
v3Router: '0xcdE487F5B460a516f31FaC520D4e18BA1C8cda49',
|
|
112
|
-
enabled: true,
|
|
113
|
-
},
|
|
114
|
-
IROSWAP: {
|
|
115
|
-
name: 'IROSwap',
|
|
116
|
-
v2Factory: ADDRESSES.ENI.IroSwapV2Factory,
|
|
117
|
-
v2Router: ADDRESSES.ENI.IroSwapV2Router,
|
|
118
|
-
enabled: true,
|
|
119
|
-
},
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
// ============================================================================
|
|
124
|
-
// 动态配置 API
|
|
125
|
-
// ============================================================================
|
|
126
|
-
/** 运行时配置存储(内存) */
|
|
127
|
-
const runtimeConfigs = {};
|
|
128
|
-
/**
|
|
129
|
-
* 从 Router 合约获取 Factory 地址
|
|
130
|
-
* 支持 Uniswap V2 Router 和 V3 SwapRouter02
|
|
131
|
-
*/
|
|
132
|
-
export async function getFactoryFromRouter(routerAddress, rpcUrl, routerType = 'v2') {
|
|
133
|
-
const provider = new JsonRpcProvider(rpcUrl);
|
|
134
|
-
const result = {};
|
|
135
|
-
// V2 Router ABI: factory()
|
|
136
|
-
const V2_ROUTER_ABI = ['function factory() view returns (address)'];
|
|
137
|
-
// V3 SwapRouter02 ABI: factory() 和 factoryV2()
|
|
138
|
-
const V3_ROUTER_ABI = [
|
|
139
|
-
'function factory() view returns (address)',
|
|
140
|
-
'function factoryV2() view returns (address)',
|
|
141
|
-
];
|
|
142
|
-
try {
|
|
143
|
-
if (routerType === 'v2') {
|
|
144
|
-
const router = new Contract(routerAddress, V2_ROUTER_ABI, provider);
|
|
145
|
-
result.v2Factory = await router.factory();
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
// V3 SwapRouter02 可能同时有 V2 和 V3 Factory
|
|
149
|
-
const router = new Contract(routerAddress, V3_ROUTER_ABI, provider);
|
|
150
|
-
// ✅ 并行获取 V3 和 V2 Factory
|
|
151
|
-
const [v3Factory, v2Factory] = await Promise.all([
|
|
152
|
-
router.factory().catch(() => undefined),
|
|
153
|
-
router.factoryV2().catch(() => undefined)
|
|
154
|
-
]);
|
|
155
|
-
if (v3Factory)
|
|
156
|
-
result.v3Factory = v3Factory;
|
|
157
|
-
if (v2Factory)
|
|
158
|
-
result.v2Factory = v2Factory;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
console.error(`❌ 获取 Factory 地址失败:`, error);
|
|
163
|
-
}
|
|
164
|
-
return result;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* 动态注册 DYORSwap(从 Router 获取 Factory)
|
|
168
|
-
*/
|
|
169
|
-
export async function registerDYORSwap(rpcUrl) {
|
|
170
|
-
const DYORSWAP_ROUTER = '0xfb001fbbace32f09cb6d3c449b935183de53ee96';
|
|
171
|
-
try {
|
|
172
|
-
// 从 Router 获取 Factory 地址
|
|
173
|
-
const factories = await getFactoryFromRouter(DYORSWAP_ROUTER, rpcUrl, 'v3');
|
|
174
|
-
if (factories.v2Factory || factories.v3Factory) {
|
|
175
|
-
const chainConfig = getChainConfig('XLAYER');
|
|
176
|
-
if (chainConfig && chainConfig.dexes.DYORSWAP) {
|
|
177
|
-
if (factories.v2Factory) {
|
|
178
|
-
chainConfig.dexes.DYORSWAP.v2Factory = factories.v2Factory;
|
|
179
|
-
}
|
|
180
|
-
if (factories.v3Factory) {
|
|
181
|
-
chainConfig.dexes.DYORSWAP.v3Factory = factories.v3Factory;
|
|
182
|
-
}
|
|
183
|
-
chainConfig.dexes.DYORSWAP.enabled = true;
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
console.error('❌ 注册 DYORSwap 失败:', error);
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/** 注册新的 DEX */
|
|
195
|
-
export function registerDex(chain, dexKey, config) {
|
|
196
|
-
const chainConfig = getChainConfig(chain);
|
|
197
|
-
if (chainConfig) {
|
|
198
|
-
chainConfig.dexes[dexKey] = config;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/** 注册新的稳定币 */
|
|
202
|
-
export function registerStableCoin(chain, coin) {
|
|
203
|
-
const chainConfig = getChainConfig(chain);
|
|
204
|
-
if (chainConfig) {
|
|
205
|
-
// 检查是否已存在
|
|
206
|
-
const exists = chainConfig.stableCoins.some(c => c.address.toLowerCase() === coin.address.toLowerCase());
|
|
207
|
-
if (!exists) {
|
|
208
|
-
chainConfig.stableCoins.push(coin);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
/** 获取链配置(优先运行时配置) */
|
|
213
|
-
export function getChainConfig(chain) {
|
|
214
|
-
if (runtimeConfigs[chain]) {
|
|
215
|
-
return runtimeConfigs[chain];
|
|
216
|
-
}
|
|
217
|
-
if (CHAIN_DEX_CONFIGS[chain]) {
|
|
218
|
-
// 深拷贝到运行时配置
|
|
219
|
-
runtimeConfigs[chain] = JSON.parse(JSON.stringify(CHAIN_DEX_CONFIGS[chain]));
|
|
220
|
-
return runtimeConfigs[chain];
|
|
221
|
-
}
|
|
222
|
-
return undefined;
|
|
223
|
-
}
|
|
224
|
-
/** 获取支持的 DEX 列表 */
|
|
225
|
-
export function getSupportedDexes(chain) {
|
|
226
|
-
const config = getChainConfig(chain);
|
|
227
|
-
if (!config)
|
|
228
|
-
return [];
|
|
229
|
-
return Object.entries(config.dexes).map(([key, dex]) => ({
|
|
230
|
-
key,
|
|
231
|
-
name: dex.name,
|
|
232
|
-
enabled: dex.enabled,
|
|
233
|
-
}));
|
|
234
|
-
}
|
|
235
|
-
/** 获取支持的稳定币列表 */
|
|
236
|
-
export function getSupportedStableCoins(chain) {
|
|
237
|
-
const config = getChainConfig(chain);
|
|
238
|
-
if (!config)
|
|
239
|
-
return [];
|
|
240
|
-
return config.stableCoins;
|
|
241
|
-
}
|
|
242
|
-
/** 获取所有报价代币(包装原生 + 稳定币) */
|
|
243
|
-
export function getQuoteTokens(chain) {
|
|
244
|
-
const config = getChainConfig(chain);
|
|
245
|
-
if (!config)
|
|
246
|
-
return [];
|
|
247
|
-
return [
|
|
248
|
-
{ address: config.wrappedNative, symbol: config.wrappedNativeSymbol, decimals: 18, isNative: true },
|
|
249
|
-
...config.stableCoins.map(c => ({ ...c, isNative: false })),
|
|
250
|
-
];
|
|
251
|
-
}
|
|
252
|
-
// ============================================================================
|
|
253
|
-
// ABI 别名(从公共模块导入)
|
|
254
|
-
// ============================================================================
|
|
255
|
-
const I_UNIV2_FACTORY_ABI = V2_FACTORY_ABI;
|
|
256
|
-
const I_UNIV2_PAIR_ABI = V2_PAIR_ABI;
|
|
257
|
-
const I_ERC20_ABI = ERC20_ABI;
|
|
258
|
-
const I_UNIV3_FACTORY_ABI = V3_FACTORY_ABI;
|
|
259
|
-
// ============================================================================
|
|
260
|
-
// 常量(从公共模块导入)
|
|
261
|
-
// ============================================================================
|
|
262
|
-
const MULTICALL3_ADDRESS = ADDRESSES.BSC.Multicall3;
|
|
263
|
-
/** Provider 缓存 */
|
|
264
|
-
const providerCache = new Map();
|
|
265
|
-
function getProvider(rpcUrl) {
|
|
266
|
-
if (!providerCache.has(rpcUrl)) {
|
|
267
|
-
providerCache.set(rpcUrl, new JsonRpcProvider(rpcUrl));
|
|
268
|
-
}
|
|
269
|
-
return providerCache.get(rpcUrl);
|
|
270
|
-
}
|
|
271
|
-
/** 精度缓存 */
|
|
272
|
-
const decimalsCache = new Map();
|
|
273
|
-
async function getTokenDecimals(tokenAddress, provider) {
|
|
274
|
-
const key = tokenAddress.toLowerCase();
|
|
275
|
-
if (decimalsCache.has(key)) {
|
|
276
|
-
return decimalsCache.get(key);
|
|
277
|
-
}
|
|
278
|
-
try {
|
|
279
|
-
const contract = new Contract(tokenAddress, I_ERC20_ABI, provider);
|
|
280
|
-
const decimals = await contract.decimals();
|
|
281
|
-
const result = Number(decimals);
|
|
282
|
-
decimalsCache.set(key, result);
|
|
283
|
-
return result;
|
|
284
|
-
}
|
|
285
|
-
catch {
|
|
286
|
-
return 18;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
/** 格式化余额 */
|
|
290
|
-
function formatBalance(balance, format, decimals = 18) {
|
|
291
|
-
return format ? formatUnits(balance, decimals) : balance.toString();
|
|
292
|
-
}
|
|
293
|
-
/** 标准化流动性值(转换为统一精度用于比较) */
|
|
294
|
-
function normalizeLiquidity(amount, decimals) {
|
|
295
|
-
// 将所有值标准化到 18 位精度进行比较
|
|
296
|
-
if (decimals < 18) {
|
|
297
|
-
return amount * BigInt(10 ** (18 - decimals));
|
|
298
|
-
}
|
|
299
|
-
else if (decimals > 18) {
|
|
300
|
-
return amount / BigInt(10 ** (decimals - 18));
|
|
301
|
-
}
|
|
302
|
-
return amount;
|
|
303
|
-
}
|
|
304
|
-
// ============================================================================
|
|
305
|
-
// 主查询函数
|
|
306
|
-
// ============================================================================
|
|
307
|
-
export async function inspectTokenLP(token, opts) {
|
|
308
|
-
const provider = getProvider(opts.rpcUrl);
|
|
309
|
-
const shouldFormat = opts.formatBalances !== false;
|
|
310
|
-
const multicall3 = opts.multicall3 || MULTICALL3_ADDRESS;
|
|
311
|
-
const v3FeeTiers = opts.v3FeeTiers || DEFAULT_V3_FEE_TIERS;
|
|
312
|
-
// 初始化返回结构
|
|
313
|
-
const result = {
|
|
314
|
-
platform: 'UNKNOWN',
|
|
315
|
-
allPools: [],
|
|
316
|
-
bestPools: [],
|
|
317
|
-
};
|
|
318
|
-
// 获取链配置
|
|
319
|
-
let chainConfig = getChainConfig(opts.chain);
|
|
320
|
-
if (!chainConfig) {
|
|
321
|
-
console.warn(`[LP Inspect] Unknown chain: ${opts.chain}`);
|
|
322
|
-
return result;
|
|
323
|
-
}
|
|
324
|
-
// 应用自定义配置
|
|
325
|
-
if (opts.customDexConfig) {
|
|
326
|
-
chainConfig = { ...chainConfig, ...opts.customDexConfig };
|
|
327
|
-
}
|
|
328
|
-
// 查询代币精度和总供应量
|
|
329
|
-
let tokenDecimals;
|
|
330
|
-
let totalSupplyRaw;
|
|
331
|
-
try {
|
|
332
|
-
const tokenContract = new Contract(token, [
|
|
333
|
-
'function decimals() view returns (uint8)',
|
|
334
|
-
'function totalSupply() view returns (uint256)'
|
|
335
|
-
], provider);
|
|
336
|
-
const [decimals, supply] = await Promise.all([
|
|
337
|
-
tokenContract.decimals().catch(() => 18),
|
|
338
|
-
tokenContract.totalSupply().catch(() => undefined)
|
|
339
|
-
]);
|
|
340
|
-
tokenDecimals = Number(decimals);
|
|
341
|
-
totalSupplyRaw = supply ? BigInt(supply) : undefined;
|
|
342
|
-
result.decimals = tokenDecimals;
|
|
343
|
-
if (totalSupplyRaw !== undefined) {
|
|
344
|
-
result.totalSupplyRaw = totalSupplyRaw;
|
|
345
|
-
result.totalSupply = formatBalance(totalSupplyRaw, shouldFormat, tokenDecimals);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
catch {
|
|
349
|
-
tokenDecimals = 18;
|
|
350
|
-
}
|
|
351
|
-
// ========================================
|
|
352
|
-
// 1. 内盘检测:Flap
|
|
353
|
-
// ========================================
|
|
354
|
-
if (opts.flapChain) {
|
|
355
|
-
try {
|
|
356
|
-
const flap = new FlapPortal({ chain: opts.flapChain, rpcUrl: opts.rpcUrl });
|
|
357
|
-
// ✅ 优先尝试 getTokenV7(包含 taxRate),失败则 fallback 到 getTokenV5
|
|
358
|
-
let st = null;
|
|
359
|
-
let taxRate;
|
|
360
|
-
try {
|
|
361
|
-
const stV7 = await flap.getTokenV7(token);
|
|
362
|
-
st = stV7;
|
|
363
|
-
// taxRate 是 bigint,需要转换为 number
|
|
364
|
-
taxRate = typeof stV7.taxRate === 'bigint' ? Number(stV7.taxRate) : Number(stV7.taxRate ?? 0);
|
|
365
|
-
if (opts.debug)
|
|
366
|
-
console.log('[LP Inspect] Flap V7 taxRate:', taxRate);
|
|
367
|
-
}
|
|
368
|
-
catch {
|
|
369
|
-
// V7 不支持,fallback 到 V5
|
|
370
|
-
st = await flap.getTokenV5(token);
|
|
371
|
-
if (opts.debug)
|
|
372
|
-
console.log('[LP Inspect] Flap V7 failed, using V5');
|
|
373
|
-
}
|
|
374
|
-
if (st && st.status !== undefined && Number(st.status) !== 4) {
|
|
375
|
-
result.platform = 'FLAP';
|
|
376
|
-
let quoteDecimals = 18;
|
|
377
|
-
let quoteSymbol = chainConfig.wrappedNativeSymbol;
|
|
378
|
-
if (st.quoteTokenAddress && st.quoteTokenAddress.toLowerCase() !== ZERO_ADDRESS) {
|
|
379
|
-
quoteDecimals = await getTokenDecimals(st.quoteTokenAddress, provider);
|
|
380
|
-
// 查找符号
|
|
381
|
-
const stableCoin = chainConfig.stableCoins.find(c => c.address.toLowerCase() === st.quoteTokenAddress.toLowerCase());
|
|
382
|
-
quoteSymbol = stableCoin?.symbol || 'TOKEN';
|
|
383
|
-
}
|
|
384
|
-
result.flap = {
|
|
385
|
-
quoteToken: st.quoteTokenAddress,
|
|
386
|
-
quoteSymbol,
|
|
387
|
-
quoteDecimals,
|
|
388
|
-
reserveNative: formatBalance(st.reserve, shouldFormat, quoteDecimals),
|
|
389
|
-
circulatingSupply: formatBalance(st.circulatingSupply, shouldFormat, tokenDecimals ?? 18),
|
|
390
|
-
price: formatBalance(st.price, shouldFormat),
|
|
391
|
-
taxRate, // ✅ 包含税率
|
|
392
|
-
};
|
|
393
|
-
// ✅ 同时设置顶层税率,方便统一读取
|
|
394
|
-
if (taxRate && taxRate > 0) {
|
|
395
|
-
result.taxRate = taxRate;
|
|
396
|
-
}
|
|
397
|
-
return result;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
catch (err) {
|
|
401
|
-
if (opts.debug)
|
|
402
|
-
console.log('[LP Inspect] Flap check failed:', err);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
// ========================================
|
|
406
|
-
// 1b. 内盘检测:DAOaaS Portal(ENI 链)
|
|
407
|
-
// ========================================
|
|
408
|
-
if (opts.chain === 'ENI') {
|
|
409
|
-
try {
|
|
410
|
-
const portalAddress = ADDRESSES.ENI.DaoaasPortal;
|
|
411
|
-
const portalAbi = [
|
|
412
|
-
'function getTokenState(address token) view returns (uint256)',
|
|
413
|
-
'function getPrice(address token) view returns (uint256)',
|
|
414
|
-
'function getOKAmountBySale(address token, uint256 tokenAmount) view returns (uint256)',
|
|
415
|
-
];
|
|
416
|
-
const portal = new Contract(portalAddress, portalAbi, provider);
|
|
417
|
-
const status = Number(await portal.getTokenState(token));
|
|
418
|
-
// status: 0=不存在, 1=交易中(内盘), 2=已毕业(外盘)
|
|
419
|
-
if (status === 1) {
|
|
420
|
-
result.platform = 'DAOAAS';
|
|
421
|
-
const price = await portal.getPrice(token);
|
|
422
|
-
const tokenContract = new Contract(token, [
|
|
423
|
-
'function totalSupply() view returns (uint256)',
|
|
424
|
-
'function balanceOf(address) view returns (uint256)',
|
|
425
|
-
], provider);
|
|
426
|
-
const [totalSupply, portalTokenBalance] = await Promise.all([
|
|
427
|
-
tokenContract.totalSupply(),
|
|
428
|
-
tokenContract.balanceOf(portalAddress),
|
|
429
|
-
]);
|
|
430
|
-
const circulatingSupply = totalSupply - portalTokenBalance;
|
|
431
|
-
let reserveNative = '0';
|
|
432
|
-
try {
|
|
433
|
-
if (circulatingSupply > 0n) {
|
|
434
|
-
const saleValue = await portal.getOKAmountBySale(token, circulatingSupply);
|
|
435
|
-
reserveNative = formatBalance(saleValue, shouldFormat, 18);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
catch {
|
|
439
|
-
try {
|
|
440
|
-
const egasBalance = await provider.getBalance(portalAddress);
|
|
441
|
-
reserveNative = formatBalance(egasBalance, shouldFormat, 18);
|
|
442
|
-
}
|
|
443
|
-
catch { /* ignore */ }
|
|
444
|
-
}
|
|
445
|
-
result.daoaas = {
|
|
446
|
-
quoteToken: ZERO_ADDRESS,
|
|
447
|
-
quoteSymbol: 'EGAS',
|
|
448
|
-
quoteDecimals: 18,
|
|
449
|
-
reserveNative,
|
|
450
|
-
circulatingSupply: formatBalance(circulatingSupply, shouldFormat, tokenDecimals ?? 18),
|
|
451
|
-
price: formatEther(price),
|
|
452
|
-
status,
|
|
453
|
-
};
|
|
454
|
-
return result;
|
|
455
|
-
}
|
|
456
|
-
// status === 2 (Graduated): 已毕业到 DSWAP V2,继续走外盘检测
|
|
457
|
-
}
|
|
458
|
-
catch (err) {
|
|
459
|
-
if (opts.debug)
|
|
460
|
-
console.log('[LP Inspect] DAOaaS Portal check failed:', err);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
// ========================================
|
|
464
|
-
// 2. 内盘检测:Four.meme(仅 BSC)
|
|
465
|
-
// ========================================
|
|
466
|
-
if (opts.chain === 'BSC') {
|
|
467
|
-
try {
|
|
468
|
-
const helper = Helper3.connectByChain('BSC', opts.rpcUrl);
|
|
469
|
-
const info = await helper.getTokenInfo(token);
|
|
470
|
-
if (info) {
|
|
471
|
-
const tokenManager = info.tokenManager;
|
|
472
|
-
const versionNum = Number(info.version ?? 0);
|
|
473
|
-
const liquidityAdded = Boolean(info.liquidityAdded);
|
|
474
|
-
const isValid = tokenManager && tokenManager !== ZERO_ADDRESS && (versionNum === 1 || versionNum === 2);
|
|
475
|
-
if (isValid && !liquidityAdded) {
|
|
476
|
-
result.platform = 'FOUR';
|
|
477
|
-
const reserveNative = info.funds !== undefined ? formatBalance(info.funds, shouldFormat) : undefined;
|
|
478
|
-
const offerTokens = info.offers !== undefined ? formatBalance(info.offers, shouldFormat) : undefined;
|
|
479
|
-
const lastPrice = info.lastPrice !== undefined ? formatBalance(info.lastPrice, shouldFormat) : undefined;
|
|
480
|
-
result.four = { helper: ADDRESSES.BSC.TokenManagerHelper3, reserveNative, offerTokens, lastPrice };
|
|
481
|
-
return result;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
catch (err) {
|
|
486
|
-
if (opts.debug)
|
|
487
|
-
console.log('[LP Inspect] Four.meme check failed:', err);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
// ========================================
|
|
491
|
-
// 3. 外盘检测:多 DEX 批量查询
|
|
492
|
-
// ========================================
|
|
493
|
-
const enabledDexes = Object.entries(chainConfig.dexes).filter(([_, dex]) => dex.enabled);
|
|
494
|
-
// 构建报价代币列表
|
|
495
|
-
const quoteTokens = [
|
|
496
|
-
{ address: chainConfig.wrappedNative, symbol: chainConfig.wrappedNativeSymbol, decimals: 18 },
|
|
497
|
-
...chainConfig.stableCoins,
|
|
498
|
-
];
|
|
499
|
-
// 所有最佳池子候选
|
|
500
|
-
const allBestPoolCandidates = [];
|
|
501
|
-
// 并行查询所有 DEX
|
|
502
|
-
const dexPromises = enabledDexes.map(async ([dexKey, dexConfig]) => {
|
|
503
|
-
const dexPoolInfo = {
|
|
504
|
-
dexName: dexConfig.name,
|
|
505
|
-
dexKey,
|
|
506
|
-
v2Pairs: [],
|
|
507
|
-
v3Pools: [],
|
|
508
|
-
};
|
|
509
|
-
// V2 查询
|
|
510
|
-
if (dexConfig.v2Factory) {
|
|
511
|
-
try {
|
|
512
|
-
const v2Pairs = await queryV2Pairs(token, dexConfig.v2Factory, quoteTokens, provider, multicall3, tokenDecimals ?? 18, shouldFormat, opts.debug);
|
|
513
|
-
dexPoolInfo.v2Pairs = v2Pairs;
|
|
514
|
-
// 添加到最佳池子候选
|
|
515
|
-
for (const pair of v2Pairs) {
|
|
516
|
-
if (pair.reserveQuoteRaw && pair.reserveQuoteRaw > 0n) {
|
|
517
|
-
allBestPoolCandidates.push({
|
|
518
|
-
dex: dexConfig.name,
|
|
519
|
-
dexKey,
|
|
520
|
-
version: 'v2',
|
|
521
|
-
quoteToken: pair.quoteToken,
|
|
522
|
-
quoteSymbol: pair.quoteSymbol,
|
|
523
|
-
quoteDecimals: pair.quoteDecimals,
|
|
524
|
-
pairAddress: pair.pairAddress,
|
|
525
|
-
liquidity: pair.reserveQuote,
|
|
526
|
-
liquidityRaw: normalizeLiquidity(pair.reserveQuoteRaw, pair.quoteDecimals),
|
|
527
|
-
reserveToken: pair.reserveToken, // ✅ 新增
|
|
528
|
-
reserveTokenRaw: pair.reserveTokenRaw, // ✅ 新增
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
catch (err) {
|
|
534
|
-
if (opts.debug)
|
|
535
|
-
console.log(`[LP Inspect] ${dexConfig.name} V2 query failed:`, err);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
// V3 查询
|
|
539
|
-
if (dexConfig.v3Factory) {
|
|
540
|
-
try {
|
|
541
|
-
const v3Pools = await queryV3Pools(token, dexConfig.v3Factory, quoteTokens, v3FeeTiers, provider, multicall3, tokenDecimals ?? 18, shouldFormat, opts.debug);
|
|
542
|
-
dexPoolInfo.v3Pools = v3Pools;
|
|
543
|
-
// 添加到最佳池子候选
|
|
544
|
-
for (const pool of v3Pools) {
|
|
545
|
-
if (pool.reserveQuoteRaw && pool.reserveQuoteRaw > 0n) {
|
|
546
|
-
allBestPoolCandidates.push({
|
|
547
|
-
dex: dexConfig.name,
|
|
548
|
-
dexKey,
|
|
549
|
-
version: 'v3',
|
|
550
|
-
fee: pool.fee,
|
|
551
|
-
quoteToken: pool.quoteToken,
|
|
552
|
-
quoteSymbol: pool.quoteSymbol,
|
|
553
|
-
quoteDecimals: pool.quoteDecimals,
|
|
554
|
-
pairAddress: pool.pairAddress,
|
|
555
|
-
liquidity: pool.reserveQuote,
|
|
556
|
-
liquidityRaw: normalizeLiquidity(pool.reserveQuoteRaw, pool.quoteDecimals),
|
|
557
|
-
reserveToken: pool.reserveToken, // ✅ 新增
|
|
558
|
-
reserveTokenRaw: pool.reserveTokenRaw, // ✅ 新增
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
catch (err) {
|
|
564
|
-
if (opts.debug)
|
|
565
|
-
console.log(`[LP Inspect] ${dexConfig.name} V3 query failed:`, err);
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
return dexPoolInfo;
|
|
569
|
-
});
|
|
570
|
-
// 等待所有 DEX 查询完成
|
|
571
|
-
const dexResults = await Promise.all(dexPromises);
|
|
572
|
-
// 过滤出有流动性的 DEX
|
|
573
|
-
result.allPools = dexResults.filter(dex => dex.v2Pairs.length > 0 || dex.v3Pools.length > 0);
|
|
574
|
-
// 按流动性排序最佳池子,并计算 poolRatio
|
|
575
|
-
result.bestPools = allBestPoolCandidates
|
|
576
|
-
.sort((a, b) => {
|
|
577
|
-
// 降序排列
|
|
578
|
-
if (b.liquidityRaw > a.liquidityRaw)
|
|
579
|
-
return 1;
|
|
580
|
-
if (b.liquidityRaw < a.liquidityRaw)
|
|
581
|
-
return -1;
|
|
582
|
-
return 0;
|
|
583
|
-
})
|
|
584
|
-
.slice(0, 10) // 最多返回 10 个
|
|
585
|
-
.map(pool => {
|
|
586
|
-
// ✅ 计算池子代币占比
|
|
587
|
-
if (pool.reserveTokenRaw && totalSupplyRaw && totalSupplyRaw > 0n) {
|
|
588
|
-
// 计算百分比:(reserveTokenRaw / totalSupplyRaw) * 100
|
|
589
|
-
// 为了保持精度,先乘以 10000,再除以 totalSupply,得到万分比
|
|
590
|
-
const ratioBps = (pool.reserveTokenRaw * 10000n) / totalSupplyRaw;
|
|
591
|
-
const ratioPercent = Number(ratioBps) / 100; // 转为百分比
|
|
592
|
-
pool.poolRatio = `${ratioPercent.toFixed(2)}%`;
|
|
593
|
-
}
|
|
594
|
-
return pool;
|
|
595
|
-
});
|
|
596
|
-
// ✅ 同时为 allPools 中的每个池子计算 poolRatio
|
|
597
|
-
if (totalSupplyRaw && totalSupplyRaw > 0n) {
|
|
598
|
-
for (const dexPool of result.allPools) {
|
|
599
|
-
for (const pair of dexPool.v2Pairs) {
|
|
600
|
-
if (pair.reserveTokenRaw) {
|
|
601
|
-
const ratioBps = (pair.reserveTokenRaw * 10000n) / totalSupplyRaw;
|
|
602
|
-
const ratioPercent = Number(ratioBps) / 100;
|
|
603
|
-
pair.poolRatio = `${ratioPercent.toFixed(2)}%`;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
for (const pool of dexPool.v3Pools) {
|
|
607
|
-
if (pool.reserveTokenRaw) {
|
|
608
|
-
const ratioBps = (pool.reserveTokenRaw * 10000n) / totalSupplyRaw;
|
|
609
|
-
const ratioPercent = Number(ratioBps) / 100;
|
|
610
|
-
pool.poolRatio = `${ratioPercent.toFixed(2)}%`;
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
// 确定平台类型
|
|
616
|
-
result.platform = determinePlatform(result.allPools);
|
|
617
|
-
// ========================================
|
|
618
|
-
// 4. 外盘税率查询(仅 Flap 链)
|
|
619
|
-
// ========================================
|
|
620
|
-
// 对于已毕业到外盘的代币,尝试从 Flap Portal 获取税率
|
|
621
|
-
if (opts.flapChain && !result.flap && result.platform !== 'UNKNOWN') {
|
|
622
|
-
try {
|
|
623
|
-
const flap = new FlapPortal({ chain: opts.flapChain, rpcUrl: opts.rpcUrl });
|
|
624
|
-
const stV7 = await flap.getTokenV7(token);
|
|
625
|
-
// taxRate 是 bigint,需要转换为 number
|
|
626
|
-
const taxRate = typeof stV7.taxRate === 'bigint' ? Number(stV7.taxRate) : Number(stV7.taxRate ?? 0);
|
|
627
|
-
if (taxRate > 0) {
|
|
628
|
-
result.taxRate = taxRate;
|
|
629
|
-
if (opts.debug)
|
|
630
|
-
console.log('[LP Inspect] 外盘税率:', taxRate, 'bps');
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
catch (err) {
|
|
634
|
-
// V7 不支持或代币不是 Flap 创建的,忽略
|
|
635
|
-
if (opts.debug)
|
|
636
|
-
console.log('[LP Inspect] 外盘税率查询失败(可忽略):', err);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
return result;
|
|
640
|
-
}
|
|
641
|
-
// ============================================================================
|
|
642
|
-
// V2 批量查询
|
|
643
|
-
// ============================================================================
|
|
644
|
-
async function queryV2Pairs(token, factoryAddress, quoteTokens, provider, multicall3, tokenDecimals, shouldFormat, debug) {
|
|
645
|
-
const results = [];
|
|
646
|
-
const factoryIface = new Interface(I_UNIV2_FACTORY_ABI);
|
|
647
|
-
const pairIface = new Interface(I_UNIV2_PAIR_ABI);
|
|
648
|
-
const mcIface = new Interface(MULTICALL3_ABI);
|
|
649
|
-
// 第一步:批量查询所有 getPair
|
|
650
|
-
const pairCalls = quoteTokens.map(qt => ({
|
|
651
|
-
target: factoryAddress,
|
|
652
|
-
callData: factoryIface.encodeFunctionData('getPair', [token, qt.address]),
|
|
653
|
-
quoteToken: qt,
|
|
654
|
-
}));
|
|
655
|
-
try {
|
|
656
|
-
const aggData = mcIface.encodeFunctionData('aggregate', [
|
|
657
|
-
pairCalls.map(c => ({ target: c.target, callData: c.callData }))
|
|
658
|
-
]);
|
|
659
|
-
const res = await provider.call({ to: multicall3, data: aggData });
|
|
660
|
-
const [, returnData] = mcIface.decodeFunctionResult('aggregate', res);
|
|
661
|
-
// 解析 pair 地址
|
|
662
|
-
const validPairs = [];
|
|
663
|
-
for (let i = 0; i < pairCalls.length; i++) {
|
|
664
|
-
try {
|
|
665
|
-
const decoded = factoryIface.decodeFunctionResult('getPair', returnData[i]);
|
|
666
|
-
const pairAddress = decoded[0];
|
|
667
|
-
if (pairAddress && pairAddress.toLowerCase() !== ZERO_ADDRESS) {
|
|
668
|
-
validPairs.push({ pairAddress, quoteToken: pairCalls[i].quoteToken });
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
catch {
|
|
672
|
-
// 解码失败,跳过
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
if (validPairs.length === 0)
|
|
676
|
-
return results;
|
|
677
|
-
// 第二步:批量查询 getReserves
|
|
678
|
-
const reserveCalls = validPairs.flatMap(p => [
|
|
679
|
-
{ target: p.pairAddress, callData: pairIface.encodeFunctionData('token0', []) },
|
|
680
|
-
{ target: p.pairAddress, callData: pairIface.encodeFunctionData('token1', []) },
|
|
681
|
-
{ target: p.pairAddress, callData: pairIface.encodeFunctionData('getReserves', []) },
|
|
682
|
-
]);
|
|
683
|
-
const aggData2 = mcIface.encodeFunctionData('aggregate', [reserveCalls]);
|
|
684
|
-
const res2 = await provider.call({ to: multicall3, data: aggData2 });
|
|
685
|
-
const [, returnData2] = mcIface.decodeFunctionResult('aggregate', res2);
|
|
686
|
-
// 解析储备量
|
|
687
|
-
for (let i = 0; i < validPairs.length; i++) {
|
|
688
|
-
try {
|
|
689
|
-
const idx = i * 3;
|
|
690
|
-
const token0 = pairIface.decodeFunctionResult('token0', returnData2[idx])[0];
|
|
691
|
-
const token1 = pairIface.decodeFunctionResult('token1', returnData2[idx + 1])[0];
|
|
692
|
-
const [r0, r1] = pairIface.decodeFunctionResult('getReserves', returnData2[idx + 2]);
|
|
693
|
-
const p = validPairs[i];
|
|
694
|
-
const isToken0 = token0.toLowerCase() === token.toLowerCase();
|
|
695
|
-
const reserveToken = isToken0 ? r0 : r1;
|
|
696
|
-
const reserveQuote = isToken0 ? r1 : r0;
|
|
697
|
-
results.push({
|
|
698
|
-
quoteToken: p.quoteToken.address,
|
|
699
|
-
quoteSymbol: p.quoteToken.symbol,
|
|
700
|
-
quoteDecimals: p.quoteToken.decimals,
|
|
701
|
-
pairAddress: p.pairAddress,
|
|
702
|
-
reserveToken: formatBalance(reserveToken, shouldFormat, tokenDecimals),
|
|
703
|
-
reserveQuote: formatBalance(reserveQuote, shouldFormat, p.quoteToken.decimals),
|
|
704
|
-
reserveQuoteRaw: reserveQuote,
|
|
705
|
-
reserveTokenRaw: reserveToken, // ✅ 新增
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
catch (err) {
|
|
709
|
-
if (debug)
|
|
710
|
-
console.log('[V2] Reserve decode error:', err);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
catch (err) {
|
|
715
|
-
if (debug)
|
|
716
|
-
console.log('[V2] Multicall failed:', err);
|
|
717
|
-
// Fallback: 逐个查询
|
|
718
|
-
return queryV2PairsFallback(token, factoryAddress, quoteTokens, provider, tokenDecimals, shouldFormat);
|
|
719
|
-
}
|
|
720
|
-
return results;
|
|
721
|
-
}
|
|
722
|
-
async function queryV2PairsFallback(token, factoryAddress, quoteTokens, provider, tokenDecimals, shouldFormat) {
|
|
723
|
-
const factory = new Contract(factoryAddress, I_UNIV2_FACTORY_ABI, provider);
|
|
724
|
-
// ✅ 并行查询所有 quoteToken 的交易对
|
|
725
|
-
const pairResults = await Promise.all(quoteTokens.map(async (qt) => {
|
|
726
|
-
try {
|
|
727
|
-
const pairAddress = await factory.getPair(token, qt.address);
|
|
728
|
-
if (!pairAddress || pairAddress.toLowerCase() === ZERO_ADDRESS) {
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
|
-
const pair = new Contract(pairAddress, I_UNIV2_PAIR_ABI, provider);
|
|
732
|
-
// ✅ 并行获取 token0、token1 和 reserves
|
|
733
|
-
const [token0, token1, reserves] = await Promise.all([
|
|
734
|
-
pair.token0(),
|
|
735
|
-
pair.token1(),
|
|
736
|
-
pair.getReserves()
|
|
737
|
-
]);
|
|
738
|
-
const [r0, r1] = reserves;
|
|
739
|
-
const isToken0 = token0.toLowerCase() === token.toLowerCase();
|
|
740
|
-
const reserveToken = isToken0 ? r0 : r1;
|
|
741
|
-
const reserveQuote = isToken0 ? r1 : r0;
|
|
742
|
-
return {
|
|
743
|
-
quoteToken: qt.address,
|
|
744
|
-
quoteSymbol: qt.symbol,
|
|
745
|
-
quoteDecimals: qt.decimals,
|
|
746
|
-
pairAddress,
|
|
747
|
-
reserveToken: formatBalance(reserveToken, shouldFormat, tokenDecimals),
|
|
748
|
-
reserveQuote: formatBalance(reserveQuote, shouldFormat, qt.decimals),
|
|
749
|
-
reserveQuoteRaw: reserveQuote,
|
|
750
|
-
reserveTokenRaw: reserveToken,
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
catch {
|
|
754
|
-
return null;
|
|
755
|
-
}
|
|
756
|
-
}));
|
|
757
|
-
// 过滤掉 null 结果
|
|
758
|
-
return pairResults.filter((r) => r !== null);
|
|
759
|
-
}
|
|
760
|
-
// ============================================================================
|
|
761
|
-
// V3 批量查询
|
|
762
|
-
// ============================================================================
|
|
763
|
-
async function queryV3Pools(token, factoryAddress, quoteTokens, feeTiers, provider, multicall3, tokenDecimals, shouldFormat, debug) {
|
|
764
|
-
const results = [];
|
|
765
|
-
const factoryIface = new Interface(I_UNIV3_FACTORY_ABI);
|
|
766
|
-
const erc20Iface = new Interface(I_ERC20_ABI);
|
|
767
|
-
const mcIface = new Interface(MULTICALL3_ABI);
|
|
768
|
-
// 构建所有查询组合
|
|
769
|
-
const poolCalls = [];
|
|
770
|
-
for (const qt of quoteTokens) {
|
|
771
|
-
for (const fee of feeTiers) {
|
|
772
|
-
// V3 要求 token0 < token1
|
|
773
|
-
const tokenLower = token.toLowerCase();
|
|
774
|
-
const quoteLower = qt.address.toLowerCase();
|
|
775
|
-
const [token0, token1] = tokenLower < quoteLower
|
|
776
|
-
? [tokenLower, quoteLower]
|
|
777
|
-
: [quoteLower, tokenLower];
|
|
778
|
-
poolCalls.push({
|
|
779
|
-
target: factoryAddress,
|
|
780
|
-
callData: factoryIface.encodeFunctionData('getPool', [token0, token1, fee]),
|
|
781
|
-
quoteToken: qt,
|
|
782
|
-
fee,
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
try {
|
|
787
|
-
// 第一步:批量查询所有 getPool
|
|
788
|
-
const aggData = mcIface.encodeFunctionData('aggregate', [
|
|
789
|
-
poolCalls.map(c => ({ target: c.target, callData: c.callData }))
|
|
790
|
-
]);
|
|
791
|
-
const res = await provider.call({ to: multicall3, data: aggData });
|
|
792
|
-
const [, returnData] = mcIface.decodeFunctionResult('aggregate', res);
|
|
793
|
-
// 解析有效的池子
|
|
794
|
-
const validPools = [];
|
|
795
|
-
for (let i = 0; i < poolCalls.length; i++) {
|
|
796
|
-
try {
|
|
797
|
-
const decoded = factoryIface.decodeFunctionResult('getPool', returnData[i]);
|
|
798
|
-
const poolAddress = decoded[0];
|
|
799
|
-
if (poolAddress && poolAddress.toLowerCase() !== ZERO_ADDRESS) {
|
|
800
|
-
validPools.push({
|
|
801
|
-
poolAddress,
|
|
802
|
-
quoteToken: poolCalls[i].quoteToken,
|
|
803
|
-
fee: poolCalls[i].fee,
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
catch {
|
|
808
|
-
// 解码失败,跳过
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
if (validPools.length === 0)
|
|
812
|
-
return results;
|
|
813
|
-
// 第二步:批量查询余额
|
|
814
|
-
const balanceCalls = validPools.flatMap(p => [
|
|
815
|
-
{ target: token, callData: erc20Iface.encodeFunctionData('balanceOf', [p.poolAddress]) },
|
|
816
|
-
{ target: p.quoteToken.address, callData: erc20Iface.encodeFunctionData('balanceOf', [p.poolAddress]) },
|
|
817
|
-
]);
|
|
818
|
-
const aggData2 = mcIface.encodeFunctionData('aggregate', [balanceCalls]);
|
|
819
|
-
const res2 = await provider.call({ to: multicall3, data: aggData2 });
|
|
820
|
-
const [, returnData2] = mcIface.decodeFunctionResult('aggregate', res2);
|
|
821
|
-
// 解析余额
|
|
822
|
-
for (let i = 0; i < validPools.length; i++) {
|
|
823
|
-
try {
|
|
824
|
-
const idx = i * 2;
|
|
825
|
-
const tokenBalance = erc20Iface.decodeFunctionResult('balanceOf', returnData2[idx])[0];
|
|
826
|
-
const quoteBalance = erc20Iface.decodeFunctionResult('balanceOf', returnData2[idx + 1])[0];
|
|
827
|
-
const p = validPools[i];
|
|
828
|
-
results.push({
|
|
829
|
-
quoteToken: p.quoteToken.address,
|
|
830
|
-
quoteSymbol: p.quoteToken.symbol,
|
|
831
|
-
quoteDecimals: p.quoteToken.decimals,
|
|
832
|
-
pairAddress: p.poolAddress,
|
|
833
|
-
reserveToken: formatBalance(tokenBalance, shouldFormat, tokenDecimals),
|
|
834
|
-
reserveQuote: formatBalance(quoteBalance, shouldFormat, p.quoteToken.decimals),
|
|
835
|
-
reserveQuoteRaw: quoteBalance,
|
|
836
|
-
reserveTokenRaw: tokenBalance, // ✅ 新增
|
|
837
|
-
fee: p.fee,
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
catch (err) {
|
|
841
|
-
if (debug)
|
|
842
|
-
console.log('[V3] Balance decode error:', err);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
catch (err) {
|
|
847
|
-
if (debug)
|
|
848
|
-
console.log('[V3] Multicall failed:', err);
|
|
849
|
-
// Fallback: 逐个查询
|
|
850
|
-
return queryV3PoolsFallback(token, factoryAddress, quoteTokens, feeTiers, provider, tokenDecimals, shouldFormat);
|
|
851
|
-
}
|
|
852
|
-
return results;
|
|
853
|
-
}
|
|
854
|
-
async function queryV3PoolsFallback(token, factoryAddress, quoteTokens, feeTiers, provider, tokenDecimals, shouldFormat) {
|
|
855
|
-
const factory = new Contract(factoryAddress, I_UNIV3_FACTORY_ABI, provider);
|
|
856
|
-
const tokenContract = new Contract(token, I_ERC20_ABI, provider);
|
|
857
|
-
// ✅ 构建所有查询组合
|
|
858
|
-
const queries = [];
|
|
859
|
-
for (const qt of quoteTokens) {
|
|
860
|
-
const tokenLower = token.toLowerCase();
|
|
861
|
-
const quoteLower = qt.address.toLowerCase();
|
|
862
|
-
const [token0, token1] = tokenLower < quoteLower
|
|
863
|
-
? [tokenLower, quoteLower]
|
|
864
|
-
: [quoteLower, tokenLower];
|
|
865
|
-
for (const fee of feeTiers) {
|
|
866
|
-
queries.push({ qt, fee, token0, token1 });
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
// ✅ 并行查询所有池子
|
|
870
|
-
const poolResults = await Promise.all(queries.map(async ({ qt, fee, token0, token1 }) => {
|
|
871
|
-
try {
|
|
872
|
-
const poolAddress = await factory.getPool(token0, token1, fee);
|
|
873
|
-
if (!poolAddress || poolAddress.toLowerCase() === ZERO_ADDRESS) {
|
|
874
|
-
return null;
|
|
875
|
-
}
|
|
876
|
-
const quoteContract = new Contract(qt.address, I_ERC20_ABI, provider);
|
|
877
|
-
// ✅ 并行获取余额
|
|
878
|
-
const [tokenBalance, quoteBalance] = await Promise.all([
|
|
879
|
-
tokenContract.balanceOf(poolAddress),
|
|
880
|
-
quoteContract.balanceOf(poolAddress),
|
|
881
|
-
]);
|
|
882
|
-
return {
|
|
883
|
-
quoteToken: qt.address,
|
|
884
|
-
quoteSymbol: qt.symbol,
|
|
885
|
-
quoteDecimals: qt.decimals,
|
|
886
|
-
pairAddress: poolAddress,
|
|
887
|
-
reserveToken: formatBalance(tokenBalance, shouldFormat, tokenDecimals),
|
|
888
|
-
reserveQuote: formatBalance(quoteBalance, shouldFormat, qt.decimals),
|
|
889
|
-
reserveQuoteRaw: quoteBalance,
|
|
890
|
-
reserveTokenRaw: tokenBalance,
|
|
891
|
-
fee,
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
catch {
|
|
895
|
-
return null;
|
|
896
|
-
}
|
|
897
|
-
}));
|
|
898
|
-
// 过滤掉 null 结果
|
|
899
|
-
return poolResults.filter((r) => r !== null);
|
|
900
|
-
}
|
|
901
|
-
// ============================================================================
|
|
902
|
-
// 平台类型判断
|
|
903
|
-
// ============================================================================
|
|
904
|
-
function determinePlatform(allPools) {
|
|
905
|
-
if (allPools.length === 0)
|
|
906
|
-
return 'UNKNOWN';
|
|
907
|
-
// 统计有流动性的 DEX
|
|
908
|
-
const dexesWithLiquidity = allPools.filter(dex => dex.v2Pairs.length > 0 || dex.v3Pools.length > 0);
|
|
909
|
-
if (dexesWithLiquidity.length > 1) {
|
|
910
|
-
return 'MULTI_DEX';
|
|
911
|
-
}
|
|
912
|
-
if (dexesWithLiquidity.length === 1) {
|
|
913
|
-
const dex = dexesWithLiquidity[0];
|
|
914
|
-
const hasV2 = dex.v2Pairs.length > 0;
|
|
915
|
-
const hasV3 = dex.v3Pools.length > 0;
|
|
916
|
-
if (dex.dexKey === 'PANCAKESWAP') {
|
|
917
|
-
if (hasV2 && hasV3)
|
|
918
|
-
return 'MULTI_DEX';
|
|
919
|
-
if (hasV3)
|
|
920
|
-
return 'PANCAKESWAP_V3';
|
|
921
|
-
return 'PANCAKESWAP_V2';
|
|
922
|
-
}
|
|
923
|
-
if (dex.dexKey === 'UNISWAP') {
|
|
924
|
-
if (hasV2 && hasV3)
|
|
925
|
-
return 'MULTI_DEX';
|
|
926
|
-
if (hasV3)
|
|
927
|
-
return 'UNISWAP_V3';
|
|
928
|
-
return 'UNISWAP_V2';
|
|
929
|
-
}
|
|
930
|
-
if (dex.dexKey === 'IROSWAP') {
|
|
931
|
-
return 'IROSWAP_V2';
|
|
932
|
-
}
|
|
933
|
-
// 其他 DEX
|
|
934
|
-
return 'MULTI_DEX';
|
|
935
|
-
}
|
|
936
|
-
return 'UNKNOWN';
|
|
937
|
-
}
|