@mento-protocol/mento-sdk 3.1.0-beta.1 → 3.1.0-beta.3
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/esm/services/pools/poolDetails.js +64 -41
- package/dist/esm/services/pools/poolDiscovery.js +28 -26
- package/dist/esm/services/tokens/tokenService.js +0 -7
- package/dist/esm/utils/chainConfig.js +1 -1
- package/dist/esm/utils/costUtils.js +17 -17
- package/dist/services/pools/poolDetails.js +64 -41
- package/dist/services/pools/poolDiscovery.js +28 -26
- package/dist/services/tokens/tokenService.js +0 -7
- package/dist/utils/chainConfig.js +1 -1
- package/dist/utils/costUtils.js +17 -17
- package/package.json +1 -1
|
@@ -9,42 +9,62 @@ export async function fetchFPMMPoolDetails(publicClient, chainId, pool) {
|
|
|
9
9
|
try {
|
|
10
10
|
// Known liquidity strategy addresses for this chain
|
|
11
11
|
const knownStrategies = getKnownLiquidityStrategies(chainId);
|
|
12
|
-
//
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
...knownStrategies.map((strategyAddr) =>
|
|
12
|
+
// Build all contract reads for a single multicall
|
|
13
|
+
const coreContracts = [
|
|
14
|
+
{ address, abi: FPMM_ABI, functionName: 'getReserves' },
|
|
15
|
+
{ address, abi: FPMM_ABI, functionName: 'decimals0' },
|
|
16
|
+
{ address, abi: FPMM_ABI, functionName: 'decimals1' },
|
|
17
|
+
{ address, abi: FPMM_ABI, functionName: 'lpFee' },
|
|
18
|
+
{ address, abi: FPMM_ABI, functionName: 'protocolFee' },
|
|
19
|
+
{ address, abi: FPMM_ABI, functionName: 'rebalanceIncentive' },
|
|
20
|
+
{ address, abi: FPMM_ABI, functionName: 'rebalanceThresholdAbove' },
|
|
21
|
+
{ address, abi: FPMM_ABI, functionName: 'rebalanceThresholdBelow' },
|
|
22
|
+
...knownStrategies.map((strategyAddr) => ({
|
|
23
23
|
address,
|
|
24
24
|
abi: FPMM_ABI,
|
|
25
25
|
functionName: 'liquidityStrategy',
|
|
26
26
|
args: [strategyAddr],
|
|
27
27
|
})),
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const
|
|
28
|
+
// Include getRebalancingState in the same multicall (allowFailure handles FXMarketClosed)
|
|
29
|
+
{ address, abi: FPMM_ABI, functionName: 'getRebalancingState' },
|
|
30
|
+
];
|
|
31
|
+
const results = await publicClient.multicall({ contracts: coreContracts });
|
|
32
|
+
// Parse core results (first 8 are fixed)
|
|
33
|
+
const reservesRes = results[0];
|
|
34
|
+
const decimals0Res = results[1];
|
|
35
|
+
const decimals1Res = results[2];
|
|
36
|
+
const lpFeeRes = results[3];
|
|
37
|
+
const protocolFeeRes = results[4];
|
|
38
|
+
const rebalanceIncentiveRes = results[5];
|
|
39
|
+
const thresholdAboveRes = results[6];
|
|
40
|
+
const thresholdBelowRes = results[7];
|
|
41
|
+
// Check core results
|
|
42
|
+
if (reservesRes.status === 'failure' ||
|
|
43
|
+
decimals0Res.status === 'failure' ||
|
|
44
|
+
decimals1Res.status === 'failure' ||
|
|
45
|
+
lpFeeRes.status === 'failure' ||
|
|
46
|
+
protocolFeeRes.status === 'failure' ||
|
|
47
|
+
rebalanceIncentiveRes.status === 'failure' ||
|
|
48
|
+
thresholdAboveRes.status === 'failure' ||
|
|
49
|
+
thresholdBelowRes.status === 'failure') {
|
|
50
|
+
throw new Error('One or more core pool reads failed');
|
|
51
|
+
}
|
|
52
|
+
const [reserve0, reserve1, blockTimestampLast] = reservesRes.result;
|
|
53
|
+
const lpFeeBps = lpFeeRes.result;
|
|
54
|
+
const protocolFeeBps = protocolFeeRes.result;
|
|
55
|
+
const rebalanceIncentiveBps = rebalanceIncentiveRes.result;
|
|
56
|
+
const thresholdAboveBps = thresholdAboveRes.result;
|
|
57
|
+
const thresholdBelowBps = thresholdBelowRes.result;
|
|
58
|
+
// Parse strategy results (indices 8 .. 8+N-1)
|
|
59
|
+
const strategyResults = results.slice(8, 8 + knownStrategies.length);
|
|
60
|
+
const activeIndex = strategyResults.findIndex((r) => r.status === 'success' && r.result === true);
|
|
37
61
|
const liquidityStrategy = activeIndex >= 0 ? knownStrategies[activeIndex] : null;
|
|
38
|
-
//
|
|
62
|
+
// Parse getRebalancingState (last result) — graceful degradation when FX market is closed
|
|
63
|
+
const rebalancingRes = results[8 + knownStrategies.length];
|
|
39
64
|
let pricing = null;
|
|
40
65
|
let inBand = null;
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
address,
|
|
44
|
-
abi: FPMM_ABI,
|
|
45
|
-
functionName: 'getRebalancingState',
|
|
46
|
-
});
|
|
47
|
-
const [oraclePriceNum, oraclePriceDen, reservePriceNum, reservePriceDen, reservePriceAboveOraclePrice, rebalanceThreshold, priceDifference,] = rebalancingStateResult;
|
|
66
|
+
if (rebalancingRes.status === 'success') {
|
|
67
|
+
const [oraclePriceNum, oraclePriceDen, reservePriceNum, reservePriceDen, reservePriceAboveOraclePrice, rebalanceThreshold, priceDifference,] = rebalancingRes.result;
|
|
48
68
|
pricing = {
|
|
49
69
|
oraclePriceNum,
|
|
50
70
|
oraclePriceDen,
|
|
@@ -58,14 +78,12 @@ export async function fetchFPMMPoolDetails(publicClient, chainId, pool) {
|
|
|
58
78
|
};
|
|
59
79
|
inBand = priceDifference < BigInt(rebalanceThreshold);
|
|
60
80
|
}
|
|
61
|
-
|
|
62
|
-
// getRebalancingState() failed (likely FXMarketClosed) — pricing stays null
|
|
63
|
-
}
|
|
81
|
+
// If rebalancingRes.status === 'failure' (likely FXMarketClosed) — pricing stays null
|
|
64
82
|
return {
|
|
65
83
|
...pool,
|
|
66
84
|
poolType: 'FPMM',
|
|
67
|
-
scalingFactor0:
|
|
68
|
-
scalingFactor1:
|
|
85
|
+
scalingFactor0: decimals0Res.result,
|
|
86
|
+
scalingFactor1: decimals1Res.result,
|
|
69
87
|
reserve0,
|
|
70
88
|
reserve1,
|
|
71
89
|
blockTimestampLast,
|
|
@@ -99,14 +117,19 @@ export async function fetchFPMMPoolDetails(publicClient, chainId, pool) {
|
|
|
99
117
|
export async function fetchVirtualPoolDetails(publicClient, pool) {
|
|
100
118
|
const address = pool.poolAddr;
|
|
101
119
|
try {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
const results = await publicClient.multicall({
|
|
121
|
+
contracts: [
|
|
122
|
+
{ address, abi: VIRTUAL_POOL_ABI, functionName: 'getReserves' },
|
|
123
|
+
{ address, abi: VIRTUAL_POOL_ABI, functionName: 'protocolFee' },
|
|
124
|
+
{ address, abi: VIRTUAL_POOL_ABI, functionName: 'metadata' },
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
if (results[0].status === 'failure' || results[1].status === 'failure' || results[2].status === 'failure') {
|
|
128
|
+
throw new Error('One or more virtual pool reads failed');
|
|
129
|
+
}
|
|
130
|
+
const [reserve0, reserve1, blockTimestampLast] = results[0].result;
|
|
131
|
+
const [dec0, dec1] = results[2].result;
|
|
132
|
+
const spreadBps = results[1].result;
|
|
110
133
|
return {
|
|
111
134
|
...pool,
|
|
112
135
|
poolType: 'Virtual',
|
|
@@ -20,28 +20,26 @@ export async function fetchFPMMPools(publicClient, chainId) {
|
|
|
20
20
|
if (poolAddresses.length === 0) {
|
|
21
21
|
return [];
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
]);
|
|
23
|
+
// Batch all token0/token1 reads into a single multicall
|
|
24
|
+
const contracts = poolAddresses.flatMap((poolAddress) => [
|
|
25
|
+
{ address: poolAddress, abi: FPMM_ABI, functionName: 'token0' },
|
|
26
|
+
{ address: poolAddress, abi: FPMM_ABI, functionName: 'token1' },
|
|
27
|
+
]);
|
|
28
|
+
const results = await publicClient.multicall({ contracts });
|
|
29
|
+
return poolAddresses.map((poolAddress, i) => {
|
|
30
|
+
const token0Result = results[i * 2];
|
|
31
|
+
const token1Result = results[i * 2 + 1];
|
|
32
|
+
if (token0Result.status === 'failure' || token1Result.status === 'failure') {
|
|
33
|
+
throw new Error(`Failed to read token addresses for pool ${poolAddress}`);
|
|
34
|
+
}
|
|
36
35
|
return {
|
|
37
36
|
factoryAddr: fpmmFactoryAddress,
|
|
38
37
|
poolAddr: poolAddress,
|
|
39
|
-
token0:
|
|
40
|
-
token1:
|
|
38
|
+
token0: token0Result.result,
|
|
39
|
+
token1: token1Result.result,
|
|
41
40
|
poolType: PoolType.FPMM,
|
|
42
41
|
};
|
|
43
42
|
});
|
|
44
|
-
return await Promise.all(poolDataPromises);
|
|
45
43
|
}
|
|
46
44
|
catch (error) {
|
|
47
45
|
throw new Error(`Failed to fetch FPMM pools: ${error.message}`);
|
|
@@ -82,16 +80,22 @@ export async function fetchVirtualPools(publicClient, chainId) {
|
|
|
82
80
|
tokenPairToExchangeId.set(`${t0}:${t1}`, exchange.exchangeId);
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
|
-
//
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
// Batch all tokens() reads into a single multicall
|
|
84
|
+
const contracts = poolAddresses.map((poolAddress) => ({
|
|
85
|
+
address: poolAddress,
|
|
86
|
+
abi: VIRTUAL_POOL_ABI,
|
|
87
|
+
functionName: 'tokens',
|
|
88
|
+
}));
|
|
89
|
+
const results = await publicClient.multicall({ contracts });
|
|
90
|
+
return poolAddresses.map((poolAddress, i) => {
|
|
91
|
+
const result = results[i];
|
|
92
|
+
if (result.status === 'failure') {
|
|
93
|
+
throw new Error(`Failed to read token addresses for virtual pool ${poolAddress}`);
|
|
94
|
+
}
|
|
95
|
+
const [token0, token1] = result.result;
|
|
92
96
|
const [sorted0, sorted1] = sortTokenAddresses(token0, token1);
|
|
93
97
|
const exchangeId = tokenPairToExchangeId.get(`${sorted0}:${sorted1}`);
|
|
94
|
-
|
|
98
|
+
return {
|
|
95
99
|
factoryAddr: virtualPoolFactoryAddress,
|
|
96
100
|
poolAddr: poolAddress,
|
|
97
101
|
token0: sorted0,
|
|
@@ -99,9 +103,7 @@ export async function fetchVirtualPools(publicClient, chainId) {
|
|
|
99
103
|
poolType: PoolType.Virtual,
|
|
100
104
|
exchangeId,
|
|
101
105
|
};
|
|
102
|
-
return pool;
|
|
103
106
|
});
|
|
104
|
-
return await Promise.all(poolPromises);
|
|
105
107
|
}
|
|
106
108
|
catch (error) {
|
|
107
109
|
throw new Error(`Failed to fetch Virtual pools: ${error.message}`);
|
|
@@ -86,15 +86,8 @@ export class TokenService {
|
|
|
86
86
|
* @returns Array of stable tokens
|
|
87
87
|
*/
|
|
88
88
|
async getStableTokens(includeSupply = true) {
|
|
89
|
-
console.log("\r\n =======================================");
|
|
90
|
-
console.log("ReserveV2: " + this.isReserveV2());
|
|
91
|
-
console.log('=======================================');
|
|
92
89
|
const reserveAddress = getContractAddress(this.chainId, RESERVE);
|
|
93
90
|
const tokenAddresses = await this.getStableTokenAddresses(reserveAddress);
|
|
94
|
-
console.log('\r\n =======================================');
|
|
95
|
-
console.log('Stable tokens: ');
|
|
96
|
-
console.log(tokenAddresses);
|
|
97
|
-
console.log('=======================================');
|
|
98
91
|
// Fetch metadata and totalSupply for all tokens concurrently
|
|
99
92
|
const tokens = await Promise.all(tokenAddresses.map(async (address) => {
|
|
100
93
|
const [metadata, totalSupply] = await Promise.all([
|
|
@@ -25,18 +25,17 @@ export async function getPoolCostPercent(pool, publicClient) {
|
|
|
25
25
|
* FPMM pools use lpFee + protocolFee in basis points (10000 = 100%)
|
|
26
26
|
*/
|
|
27
27
|
async function getFPMMCostPercent(poolAddress, publicClient) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
address: poolAddress,
|
|
31
|
-
abi: FPMM_ABI,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
]);
|
|
28
|
+
const results = await publicClient.multicall({
|
|
29
|
+
contracts: [
|
|
30
|
+
{ address: poolAddress, abi: FPMM_ABI, functionName: 'lpFee' },
|
|
31
|
+
{ address: poolAddress, abi: FPMM_ABI, functionName: 'protocolFee' },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
if (results[0].status === 'failure' || results[1].status === 'failure') {
|
|
35
|
+
throw new Error(`Failed to read fees for pool ${poolAddress}`);
|
|
36
|
+
}
|
|
37
|
+
const lpFee = results[0].result;
|
|
38
|
+
const protocolFee = results[1].result;
|
|
40
39
|
// Convert from basis points to percentage using BigInt arithmetic to avoid precision loss
|
|
41
40
|
const totalBasisPoints = lpFee + protocolFee;
|
|
42
41
|
const scaled = totalBasisPoints * 1000000n;
|
|
@@ -46,12 +45,13 @@ async function getFPMMCostPercent(poolAddress, publicClient) {
|
|
|
46
45
|
* Calculate cost for Virtual pools
|
|
47
46
|
*/
|
|
48
47
|
async function getVirtualPoolCostPercent(poolAddress, publicClient) {
|
|
49
|
-
const
|
|
50
|
-
address: poolAddress,
|
|
51
|
-
abi: VIRTUAL_POOL_ABI,
|
|
52
|
-
functionName: 'protocolFee',
|
|
48
|
+
const results = await publicClient.multicall({
|
|
49
|
+
contracts: [{ address: poolAddress, abi: VIRTUAL_POOL_ABI, functionName: 'protocolFee' }],
|
|
53
50
|
});
|
|
51
|
+
if (results[0].status === 'failure') {
|
|
52
|
+
throw new Error(`Failed to read protocolFee for pool ${poolAddress}`);
|
|
53
|
+
}
|
|
54
54
|
// Convert from basis points to percentage using BigInt arithmetic to avoid precision loss
|
|
55
|
-
const scaled =
|
|
55
|
+
const scaled = results[0].result * 1000000n;
|
|
56
56
|
return Number(scaled / 100n) / 1e6;
|
|
57
57
|
}
|
|
@@ -13,42 +13,62 @@ async function fetchFPMMPoolDetails(publicClient, chainId, pool) {
|
|
|
13
13
|
try {
|
|
14
14
|
// Known liquidity strategy addresses for this chain
|
|
15
15
|
const knownStrategies = getKnownLiquidityStrategies(chainId);
|
|
16
|
-
//
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
...knownStrategies.map((strategyAddr) =>
|
|
16
|
+
// Build all contract reads for a single multicall
|
|
17
|
+
const coreContracts = [
|
|
18
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'getReserves' },
|
|
19
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'decimals0' },
|
|
20
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'decimals1' },
|
|
21
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'lpFee' },
|
|
22
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'protocolFee' },
|
|
23
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'rebalanceIncentive' },
|
|
24
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'rebalanceThresholdAbove' },
|
|
25
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'rebalanceThresholdBelow' },
|
|
26
|
+
...knownStrategies.map((strategyAddr) => ({
|
|
27
27
|
address,
|
|
28
28
|
abi: abis_1.FPMM_ABI,
|
|
29
29
|
functionName: 'liquidityStrategy',
|
|
30
30
|
args: [strategyAddr],
|
|
31
31
|
})),
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const
|
|
32
|
+
// Include getRebalancingState in the same multicall (allowFailure handles FXMarketClosed)
|
|
33
|
+
{ address, abi: abis_1.FPMM_ABI, functionName: 'getRebalancingState' },
|
|
34
|
+
];
|
|
35
|
+
const results = await publicClient.multicall({ contracts: coreContracts });
|
|
36
|
+
// Parse core results (first 8 are fixed)
|
|
37
|
+
const reservesRes = results[0];
|
|
38
|
+
const decimals0Res = results[1];
|
|
39
|
+
const decimals1Res = results[2];
|
|
40
|
+
const lpFeeRes = results[3];
|
|
41
|
+
const protocolFeeRes = results[4];
|
|
42
|
+
const rebalanceIncentiveRes = results[5];
|
|
43
|
+
const thresholdAboveRes = results[6];
|
|
44
|
+
const thresholdBelowRes = results[7];
|
|
45
|
+
// Check core results
|
|
46
|
+
if (reservesRes.status === 'failure' ||
|
|
47
|
+
decimals0Res.status === 'failure' ||
|
|
48
|
+
decimals1Res.status === 'failure' ||
|
|
49
|
+
lpFeeRes.status === 'failure' ||
|
|
50
|
+
protocolFeeRes.status === 'failure' ||
|
|
51
|
+
rebalanceIncentiveRes.status === 'failure' ||
|
|
52
|
+
thresholdAboveRes.status === 'failure' ||
|
|
53
|
+
thresholdBelowRes.status === 'failure') {
|
|
54
|
+
throw new Error('One or more core pool reads failed');
|
|
55
|
+
}
|
|
56
|
+
const [reserve0, reserve1, blockTimestampLast] = reservesRes.result;
|
|
57
|
+
const lpFeeBps = lpFeeRes.result;
|
|
58
|
+
const protocolFeeBps = protocolFeeRes.result;
|
|
59
|
+
const rebalanceIncentiveBps = rebalanceIncentiveRes.result;
|
|
60
|
+
const thresholdAboveBps = thresholdAboveRes.result;
|
|
61
|
+
const thresholdBelowBps = thresholdBelowRes.result;
|
|
62
|
+
// Parse strategy results (indices 8 .. 8+N-1)
|
|
63
|
+
const strategyResults = results.slice(8, 8 + knownStrategies.length);
|
|
64
|
+
const activeIndex = strategyResults.findIndex((r) => r.status === 'success' && r.result === true);
|
|
41
65
|
const liquidityStrategy = activeIndex >= 0 ? knownStrategies[activeIndex] : null;
|
|
42
|
-
//
|
|
66
|
+
// Parse getRebalancingState (last result) — graceful degradation when FX market is closed
|
|
67
|
+
const rebalancingRes = results[8 + knownStrategies.length];
|
|
43
68
|
let pricing = null;
|
|
44
69
|
let inBand = null;
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
address,
|
|
48
|
-
abi: abis_1.FPMM_ABI,
|
|
49
|
-
functionName: 'getRebalancingState',
|
|
50
|
-
});
|
|
51
|
-
const [oraclePriceNum, oraclePriceDen, reservePriceNum, reservePriceDen, reservePriceAboveOraclePrice, rebalanceThreshold, priceDifference,] = rebalancingStateResult;
|
|
70
|
+
if (rebalancingRes.status === 'success') {
|
|
71
|
+
const [oraclePriceNum, oraclePriceDen, reservePriceNum, reservePriceDen, reservePriceAboveOraclePrice, rebalanceThreshold, priceDifference,] = rebalancingRes.result;
|
|
52
72
|
pricing = {
|
|
53
73
|
oraclePriceNum,
|
|
54
74
|
oraclePriceDen,
|
|
@@ -62,14 +82,12 @@ async function fetchFPMMPoolDetails(publicClient, chainId, pool) {
|
|
|
62
82
|
};
|
|
63
83
|
inBand = priceDifference < BigInt(rebalanceThreshold);
|
|
64
84
|
}
|
|
65
|
-
|
|
66
|
-
// getRebalancingState() failed (likely FXMarketClosed) — pricing stays null
|
|
67
|
-
}
|
|
85
|
+
// If rebalancingRes.status === 'failure' (likely FXMarketClosed) — pricing stays null
|
|
68
86
|
return {
|
|
69
87
|
...pool,
|
|
70
88
|
poolType: 'FPMM',
|
|
71
|
-
scalingFactor0:
|
|
72
|
-
scalingFactor1:
|
|
89
|
+
scalingFactor0: decimals0Res.result,
|
|
90
|
+
scalingFactor1: decimals1Res.result,
|
|
73
91
|
reserve0,
|
|
74
92
|
reserve1,
|
|
75
93
|
blockTimestampLast,
|
|
@@ -103,14 +121,19 @@ async function fetchFPMMPoolDetails(publicClient, chainId, pool) {
|
|
|
103
121
|
async function fetchVirtualPoolDetails(publicClient, pool) {
|
|
104
122
|
const address = pool.poolAddr;
|
|
105
123
|
try {
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
124
|
+
const results = await publicClient.multicall({
|
|
125
|
+
contracts: [
|
|
126
|
+
{ address, abi: abis_1.VIRTUAL_POOL_ABI, functionName: 'getReserves' },
|
|
127
|
+
{ address, abi: abis_1.VIRTUAL_POOL_ABI, functionName: 'protocolFee' },
|
|
128
|
+
{ address, abi: abis_1.VIRTUAL_POOL_ABI, functionName: 'metadata' },
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
if (results[0].status === 'failure' || results[1].status === 'failure' || results[2].status === 'failure') {
|
|
132
|
+
throw new Error('One or more virtual pool reads failed');
|
|
133
|
+
}
|
|
134
|
+
const [reserve0, reserve1, blockTimestampLast] = results[0].result;
|
|
135
|
+
const [dec0, dec1] = results[2].result;
|
|
136
|
+
const spreadBps = results[1].result;
|
|
114
137
|
return {
|
|
115
138
|
...pool,
|
|
116
139
|
poolType: 'Virtual',
|
|
@@ -24,28 +24,26 @@ async function fetchFPMMPools(publicClient, chainId) {
|
|
|
24
24
|
if (poolAddresses.length === 0) {
|
|
25
25
|
return [];
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
]);
|
|
27
|
+
// Batch all token0/token1 reads into a single multicall
|
|
28
|
+
const contracts = poolAddresses.flatMap((poolAddress) => [
|
|
29
|
+
{ address: poolAddress, abi: abis_1.FPMM_ABI, functionName: 'token0' },
|
|
30
|
+
{ address: poolAddress, abi: abis_1.FPMM_ABI, functionName: 'token1' },
|
|
31
|
+
]);
|
|
32
|
+
const results = await publicClient.multicall({ contracts });
|
|
33
|
+
return poolAddresses.map((poolAddress, i) => {
|
|
34
|
+
const token0Result = results[i * 2];
|
|
35
|
+
const token1Result = results[i * 2 + 1];
|
|
36
|
+
if (token0Result.status === 'failure' || token1Result.status === 'failure') {
|
|
37
|
+
throw new Error(`Failed to read token addresses for pool ${poolAddress}`);
|
|
38
|
+
}
|
|
40
39
|
return {
|
|
41
40
|
factoryAddr: fpmmFactoryAddress,
|
|
42
41
|
poolAddr: poolAddress,
|
|
43
|
-
token0:
|
|
44
|
-
token1:
|
|
42
|
+
token0: token0Result.result,
|
|
43
|
+
token1: token1Result.result,
|
|
45
44
|
poolType: types_1.PoolType.FPMM,
|
|
46
45
|
};
|
|
47
46
|
});
|
|
48
|
-
return await Promise.all(poolDataPromises);
|
|
49
47
|
}
|
|
50
48
|
catch (error) {
|
|
51
49
|
throw new Error(`Failed to fetch FPMM pools: ${error.message}`);
|
|
@@ -86,16 +84,22 @@ async function fetchVirtualPools(publicClient, chainId) {
|
|
|
86
84
|
tokenPairToExchangeId.set(`${t0}:${t1}`, exchange.exchangeId);
|
|
87
85
|
}
|
|
88
86
|
}
|
|
89
|
-
//
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
// Batch all tokens() reads into a single multicall
|
|
88
|
+
const contracts = poolAddresses.map((poolAddress) => ({
|
|
89
|
+
address: poolAddress,
|
|
90
|
+
abi: abis_1.VIRTUAL_POOL_ABI,
|
|
91
|
+
functionName: 'tokens',
|
|
92
|
+
}));
|
|
93
|
+
const results = await publicClient.multicall({ contracts });
|
|
94
|
+
return poolAddresses.map((poolAddress, i) => {
|
|
95
|
+
const result = results[i];
|
|
96
|
+
if (result.status === 'failure') {
|
|
97
|
+
throw new Error(`Failed to read token addresses for virtual pool ${poolAddress}`);
|
|
98
|
+
}
|
|
99
|
+
const [token0, token1] = result.result;
|
|
96
100
|
const [sorted0, sorted1] = (0, sortUtils_1.sortTokenAddresses)(token0, token1);
|
|
97
101
|
const exchangeId = tokenPairToExchangeId.get(`${sorted0}:${sorted1}`);
|
|
98
|
-
|
|
102
|
+
return {
|
|
99
103
|
factoryAddr: virtualPoolFactoryAddress,
|
|
100
104
|
poolAddr: poolAddress,
|
|
101
105
|
token0: sorted0,
|
|
@@ -103,9 +107,7 @@ async function fetchVirtualPools(publicClient, chainId) {
|
|
|
103
107
|
poolType: types_1.PoolType.Virtual,
|
|
104
108
|
exchangeId,
|
|
105
109
|
};
|
|
106
|
-
return pool;
|
|
107
110
|
});
|
|
108
|
-
return await Promise.all(poolPromises);
|
|
109
111
|
}
|
|
110
112
|
catch (error) {
|
|
111
113
|
throw new Error(`Failed to fetch Virtual pools: ${error.message}`);
|
|
@@ -89,15 +89,8 @@ class TokenService {
|
|
|
89
89
|
* @returns Array of stable tokens
|
|
90
90
|
*/
|
|
91
91
|
async getStableTokens(includeSupply = true) {
|
|
92
|
-
console.log("\r\n =======================================");
|
|
93
|
-
console.log("ReserveV2: " + this.isReserveV2());
|
|
94
|
-
console.log('=======================================');
|
|
95
92
|
const reserveAddress = (0, constants_1.getContractAddress)(this.chainId, constants_1.RESERVE);
|
|
96
93
|
const tokenAddresses = await this.getStableTokenAddresses(reserveAddress);
|
|
97
|
-
console.log('\r\n =======================================');
|
|
98
|
-
console.log('Stable tokens: ');
|
|
99
|
-
console.log(tokenAddresses);
|
|
100
|
-
console.log('=======================================');
|
|
101
94
|
// Fetch metadata and totalSupply for all tokens concurrently
|
|
102
95
|
const tokens = await Promise.all(tokenAddresses.map(async (address) => {
|
|
103
96
|
const [metadata, totalSupply] = await Promise.all([
|
package/dist/utils/costUtils.js
CHANGED
|
@@ -28,18 +28,17 @@ async function getPoolCostPercent(pool, publicClient) {
|
|
|
28
28
|
* FPMM pools use lpFee + protocolFee in basis points (10000 = 100%)
|
|
29
29
|
*/
|
|
30
30
|
async function getFPMMCostPercent(poolAddress, publicClient) {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
address: poolAddress,
|
|
34
|
-
abi: abis_1.FPMM_ABI,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
]);
|
|
31
|
+
const results = await publicClient.multicall({
|
|
32
|
+
contracts: [
|
|
33
|
+
{ address: poolAddress, abi: abis_1.FPMM_ABI, functionName: 'lpFee' },
|
|
34
|
+
{ address: poolAddress, abi: abis_1.FPMM_ABI, functionName: 'protocolFee' },
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
if (results[0].status === 'failure' || results[1].status === 'failure') {
|
|
38
|
+
throw new Error(`Failed to read fees for pool ${poolAddress}`);
|
|
39
|
+
}
|
|
40
|
+
const lpFee = results[0].result;
|
|
41
|
+
const protocolFee = results[1].result;
|
|
43
42
|
// Convert from basis points to percentage using BigInt arithmetic to avoid precision loss
|
|
44
43
|
const totalBasisPoints = lpFee + protocolFee;
|
|
45
44
|
const scaled = totalBasisPoints * 1000000n;
|
|
@@ -49,13 +48,14 @@ async function getFPMMCostPercent(poolAddress, publicClient) {
|
|
|
49
48
|
* Calculate cost for Virtual pools
|
|
50
49
|
*/
|
|
51
50
|
async function getVirtualPoolCostPercent(poolAddress, publicClient) {
|
|
52
|
-
const
|
|
53
|
-
address: poolAddress,
|
|
54
|
-
abi: virtualPool_1.VIRTUAL_POOL_ABI,
|
|
55
|
-
functionName: 'protocolFee',
|
|
51
|
+
const results = await publicClient.multicall({
|
|
52
|
+
contracts: [{ address: poolAddress, abi: virtualPool_1.VIRTUAL_POOL_ABI, functionName: 'protocolFee' }],
|
|
56
53
|
});
|
|
54
|
+
if (results[0].status === 'failure') {
|
|
55
|
+
throw new Error(`Failed to read protocolFee for pool ${poolAddress}`);
|
|
56
|
+
}
|
|
57
57
|
// Convert from basis points to percentage using BigInt arithmetic to avoid precision loss
|
|
58
|
-
const scaled =
|
|
58
|
+
const scaled = results[0].result * 1000000n;
|
|
59
59
|
return Number(scaled / 100n) / 1e6;
|
|
60
60
|
}
|
|
61
61
|
//# sourceMappingURL=costUtils.js.map
|