@mento-protocol/mento-sdk 3.1.0-beta.3 → 3.1.0-beta.5
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/core/types/liquidity.d.ts +20 -0
- package/dist/esm/index.js +25 -9
- package/dist/esm/services/borrow/internal/borrowReadService.js +63 -34
- package/dist/esm/services/borrow/internal/borrowRegistryReader.js +45 -28
- package/dist/esm/services/index.js +1 -0
- package/dist/esm/services/liquidity/LiquidityService.js +8 -2
- package/dist/esm/services/liquidity/liquidityHelpers.js +27 -1
- package/dist/esm/services/liquidity/zapHelpers.js +20 -24
- package/dist/esm/services/liquidity/zapIn.js +68 -75
- package/dist/esm/services/liquidity/zapOut.js +89 -77
- package/dist/esm/services/pools/PoolService.js +117 -22
- package/dist/esm/services/pools/poolDetails.js +80 -40
- package/dist/esm/services/pools/poolDiscovery.js +3 -2
- package/dist/esm/services/quotes/QuoteService.js +22 -20
- package/dist/esm/services/routes/RouteService.js +82 -24
- package/dist/esm/services/swap/SwapService.js +81 -37
- package/dist/esm/services/tokens/tokenService.js +142 -29
- package/dist/esm/services/trading/TradingService.js +51 -12
- package/dist/esm/utils/chainConfig.js +12 -0
- package/dist/esm/utils/costUtils.js +8 -9
- package/dist/esm/utils/multicall.js +42 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +25 -9
- package/dist/services/borrow/internal/borrowReadService.d.ts +1 -0
- package/dist/services/borrow/internal/borrowReadService.js +63 -34
- package/dist/services/borrow/internal/borrowRegistryReader.js +45 -28
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/liquidity/LiquidityService.d.ts +3 -1
- package/dist/services/liquidity/LiquidityService.js +6 -0
- package/dist/services/liquidity/liquidityHelpers.d.ts +6 -0
- package/dist/services/liquidity/liquidityHelpers.js +27 -0
- package/dist/services/liquidity/zapHelpers.js +20 -24
- package/dist/services/liquidity/zapIn.d.ts +2 -1
- package/dist/services/liquidity/zapIn.js +67 -73
- package/dist/services/liquidity/zapOut.d.ts +2 -10
- package/dist/services/liquidity/zapOut.js +90 -77
- package/dist/services/pools/PoolService.d.ts +5 -0
- package/dist/services/pools/PoolService.js +116 -21
- package/dist/services/pools/poolDetails.d.ts +2 -0
- package/dist/services/pools/poolDetails.js +82 -40
- package/dist/services/pools/poolDiscovery.js +3 -2
- package/dist/services/quotes/QuoteService.d.ts +1 -0
- package/dist/services/quotes/QuoteService.js +24 -21
- package/dist/services/routes/RouteService.d.ts +8 -0
- package/dist/services/routes/RouteService.js +82 -24
- package/dist/services/swap/SwapService.d.ts +19 -0
- package/dist/services/swap/SwapService.js +81 -37
- package/dist/services/tokens/tokenService.d.ts +7 -0
- package/dist/services/tokens/tokenService.js +142 -29
- package/dist/services/trading/TradingService.d.ts +3 -0
- package/dist/services/trading/TradingService.js +51 -12
- package/dist/utils/chainConfig.js +12 -0
- package/dist/utils/costUtils.js +8 -9
- package/dist/utils/multicall.d.ts +30 -0
- package/dist/utils/multicall.js +47 -0
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ exports.TokenService = void 0;
|
|
|
4
4
|
const abis_1 = require("../../core/abis");
|
|
5
5
|
const constants_1 = require("../../core/constants");
|
|
6
6
|
const utils_1 = require("../../utils");
|
|
7
|
+
const multicall_1 = require("../../utils/multicall");
|
|
7
8
|
/**
|
|
8
9
|
* Chains that use ReserveV2 (v3) instead of the legacy Reserve contract.
|
|
9
10
|
*/
|
|
@@ -12,6 +13,7 @@ class TokenService {
|
|
|
12
13
|
constructor(publicClient, chainId) {
|
|
13
14
|
this.publicClient = publicClient;
|
|
14
15
|
this.chainId = chainId;
|
|
16
|
+
this.tokenMetadataCache = new Map();
|
|
15
17
|
}
|
|
16
18
|
isReserveV2() {
|
|
17
19
|
return RESERVE_V2_CHAINS.has(this.chainId);
|
|
@@ -22,6 +24,76 @@ class TokenService {
|
|
|
22
24
|
* @returns Token metadata
|
|
23
25
|
*/
|
|
24
26
|
async getTokenMetadata(address) {
|
|
27
|
+
const cacheKey = address.toLowerCase();
|
|
28
|
+
const cached = this.tokenMetadataCache.get(cacheKey);
|
|
29
|
+
if (cached) {
|
|
30
|
+
return cached;
|
|
31
|
+
}
|
|
32
|
+
const [metadata] = await this.getTokenMetadataBatch([address]);
|
|
33
|
+
this.tokenMetadataCache.set(cacheKey, metadata);
|
|
34
|
+
return metadata;
|
|
35
|
+
}
|
|
36
|
+
async getTokenMetadataBatch(addresses) {
|
|
37
|
+
if (addresses.length === 0) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const results = new Array(addresses.length);
|
|
41
|
+
const missing = [];
|
|
42
|
+
for (const [index, address] of addresses.entries()) {
|
|
43
|
+
const cached = this.tokenMetadataCache.get(address.toLowerCase());
|
|
44
|
+
if (cached) {
|
|
45
|
+
results[index] = cached;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
missing.push({ address, index });
|
|
49
|
+
}
|
|
50
|
+
if (missing.length === 0) {
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
const multicallResults = await (0, multicall_1.multicall)(this.publicClient, missing.flatMap(({ address }) => ([
|
|
54
|
+
{
|
|
55
|
+
address: address,
|
|
56
|
+
abi: abis_1.ERC20_ABI,
|
|
57
|
+
functionName: 'name',
|
|
58
|
+
args: [],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
address: address,
|
|
62
|
+
abi: abis_1.ERC20_ABI,
|
|
63
|
+
functionName: 'symbol',
|
|
64
|
+
args: [],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
address: address,
|
|
68
|
+
abi: abis_1.ERC20_ABI,
|
|
69
|
+
functionName: 'decimals',
|
|
70
|
+
args: [],
|
|
71
|
+
},
|
|
72
|
+
])), { allowFailure: true });
|
|
73
|
+
const hydrated = await Promise.all(missing.map(async ({ address }, index) => {
|
|
74
|
+
const resultOffset = index * 3;
|
|
75
|
+
const name = multicallResults[resultOffset];
|
|
76
|
+
const symbol = multicallResults[resultOffset + 1];
|
|
77
|
+
const decimals = multicallResults[resultOffset + 2];
|
|
78
|
+
if (name?.status === 'success' &&
|
|
79
|
+
symbol?.status === 'success' &&
|
|
80
|
+
decimals?.status === 'success') {
|
|
81
|
+
return {
|
|
82
|
+
name: name.result,
|
|
83
|
+
symbol: symbol.result,
|
|
84
|
+
decimals: Number(decimals.result),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return this.readTokenMetadataWithRetry(address);
|
|
88
|
+
}));
|
|
89
|
+
for (const [index, metadata] of hydrated.entries()) {
|
|
90
|
+
const address = missing[index].address;
|
|
91
|
+
this.tokenMetadataCache.set(address.toLowerCase(), metadata);
|
|
92
|
+
results[missing[index].index] = metadata;
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
async readTokenMetadataWithRetry(address) {
|
|
25
97
|
const [name, symbol, decimals] = await Promise.all([
|
|
26
98
|
(0, utils_1.retryOperation)(() => this.publicClient.readContract({
|
|
27
99
|
address: address,
|
|
@@ -54,6 +126,28 @@ class TokenService {
|
|
|
54
126
|
* @returns Total supply as string
|
|
55
127
|
*/
|
|
56
128
|
async getTotalSupply(address) {
|
|
129
|
+
const [totalSupply] = await this.getTotalSupplyBatch([address]);
|
|
130
|
+
return totalSupply;
|
|
131
|
+
}
|
|
132
|
+
async getTotalSupplyBatch(addresses) {
|
|
133
|
+
if (addresses.length === 0) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
const results = await (0, multicall_1.multicall)(this.publicClient, addresses.map((address) => ({
|
|
137
|
+
address: address,
|
|
138
|
+
abi: abis_1.ERC20_ABI,
|
|
139
|
+
functionName: 'totalSupply',
|
|
140
|
+
args: [],
|
|
141
|
+
})), { allowFailure: true });
|
|
142
|
+
return Promise.all(addresses.map(async (address, index) => {
|
|
143
|
+
const result = results[index];
|
|
144
|
+
if (result?.status === 'success') {
|
|
145
|
+
return result.result.toString();
|
|
146
|
+
}
|
|
147
|
+
return this.readTotalSupplyWithRetry(address);
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
async readTotalSupplyWithRetry(address) {
|
|
57
151
|
const totalSupply = await (0, utils_1.retryOperation)(() => this.publicClient.readContract({
|
|
58
152
|
address: address,
|
|
59
153
|
abi: abis_1.ERC20_ABI,
|
|
@@ -62,6 +156,32 @@ class TokenService {
|
|
|
62
156
|
}));
|
|
63
157
|
return totalSupply.toString();
|
|
64
158
|
}
|
|
159
|
+
async getCollateralStatusBatch(reserveAddress, addresses) {
|
|
160
|
+
if (addresses.length === 0) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
const results = await (0, multicall_1.multicall)(this.publicClient, addresses.map((address) => ({
|
|
164
|
+
address: reserveAddress,
|
|
165
|
+
abi: abis_1.RESERVE_ABI,
|
|
166
|
+
functionName: 'isCollateralAsset',
|
|
167
|
+
args: [address],
|
|
168
|
+
})), { allowFailure: true });
|
|
169
|
+
return Promise.all(addresses.map(async (address, index) => {
|
|
170
|
+
const result = results[index];
|
|
171
|
+
if (result?.status === 'success') {
|
|
172
|
+
return result.result;
|
|
173
|
+
}
|
|
174
|
+
return this.readCollateralStatusWithRetry(reserveAddress, address);
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
async readCollateralStatusWithRetry(reserveAddress, address) {
|
|
178
|
+
return (0, utils_1.retryOperation)(() => this.publicClient.readContract({
|
|
179
|
+
address: reserveAddress,
|
|
180
|
+
abi: abis_1.RESERVE_ABI,
|
|
181
|
+
functionName: 'isCollateralAsset',
|
|
182
|
+
args: [address],
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
65
185
|
/**
|
|
66
186
|
* Get stable token addresses from the Reserve contract.
|
|
67
187
|
* Uses getStableAssets() on ReserveV2, getTokens() on legacy Reserve.
|
|
@@ -91,17 +211,14 @@ class TokenService {
|
|
|
91
211
|
async getStableTokens(includeSupply = true) {
|
|
92
212
|
const reserveAddress = (0, constants_1.getContractAddress)(this.chainId, constants_1.RESERVE);
|
|
93
213
|
const tokenAddresses = await this.getStableTokenAddresses(reserveAddress);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
...metadata,
|
|
103
|
-
totalSupply,
|
|
104
|
-
};
|
|
214
|
+
const [metadataList, totalSupplies] = await Promise.all([
|
|
215
|
+
this.getTokenMetadataBatch(tokenAddresses),
|
|
216
|
+
includeSupply ? this.getTotalSupplyBatch(tokenAddresses) : Promise.resolve(tokenAddresses.map(() => '0')),
|
|
217
|
+
]);
|
|
218
|
+
const tokens = tokenAddresses.map((address, index) => ({
|
|
219
|
+
address,
|
|
220
|
+
...metadataList[index],
|
|
221
|
+
totalSupply: totalSupplies[index],
|
|
105
222
|
}));
|
|
106
223
|
return tokens;
|
|
107
224
|
}
|
|
@@ -128,9 +245,10 @@ class TokenService {
|
|
|
128
245
|
functionName: 'getCollateralAssets',
|
|
129
246
|
args: [],
|
|
130
247
|
})));
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
248
|
+
const metadataList = await this.getTokenMetadataBatch(collateralAddresses);
|
|
249
|
+
const assets = collateralAddresses.map((address, index) => ({
|
|
250
|
+
address,
|
|
251
|
+
...metadataList[index],
|
|
134
252
|
}));
|
|
135
253
|
return assets;
|
|
136
254
|
}
|
|
@@ -154,22 +272,17 @@ class TokenService {
|
|
|
154
272
|
for (const exchange of exchanges) {
|
|
155
273
|
exchange.assets.forEach((address) => uniqueAddresses.add(address));
|
|
156
274
|
}
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
})),
|
|
166
|
-
this.getTokenMetadata(address),
|
|
167
|
-
]);
|
|
168
|
-
if (isCollateral) {
|
|
169
|
-
return { address, ...metadata };
|
|
275
|
+
const addresses = Array.from(uniqueAddresses);
|
|
276
|
+
const [collateralStatuses, metadataList] = await Promise.all([
|
|
277
|
+
this.getCollateralStatusBatch(reserveAddress, addresses),
|
|
278
|
+
this.getTokenMetadataBatch(addresses),
|
|
279
|
+
]);
|
|
280
|
+
const results = addresses.map((address, index) => {
|
|
281
|
+
if (!collateralStatuses[index]) {
|
|
282
|
+
return null;
|
|
170
283
|
}
|
|
171
|
-
return
|
|
172
|
-
})
|
|
284
|
+
return { address, ...metadataList[index] };
|
|
285
|
+
});
|
|
173
286
|
return results.filter((asset) => asset !== null);
|
|
174
287
|
}
|
|
175
288
|
}
|
|
@@ -106,5 +106,8 @@ export declare class TradingService {
|
|
|
106
106
|
* @returns The rate feed ID address
|
|
107
107
|
*/
|
|
108
108
|
getPoolRateFeedId(pool: Pool): Promise<string>;
|
|
109
|
+
private getTradingModesForPools;
|
|
110
|
+
private getPoolRateFeedIds;
|
|
111
|
+
private getTradingModesForRateFeeds;
|
|
109
112
|
}
|
|
110
113
|
//# sourceMappingURL=TradingService.d.ts.map
|
|
@@ -5,6 +5,7 @@ const types_1 = require("../../core/types");
|
|
|
5
5
|
const TradingLimitsService_1 = require("./TradingLimitsService");
|
|
6
6
|
const abis_1 = require("../../core/abis");
|
|
7
7
|
const constants_1 = require("../../core/constants");
|
|
8
|
+
const multicall_1 = require("../../utils/multicall");
|
|
8
9
|
/**
|
|
9
10
|
* Service for checking trading status and circuit breaker state in the Mento protocol.
|
|
10
11
|
* Provides methods to query whether trading is enabled for specific rate feeds,
|
|
@@ -81,14 +82,9 @@ class TradingService {
|
|
|
81
82
|
* ```
|
|
82
83
|
*/
|
|
83
84
|
async isRouteTradable(route) {
|
|
84
|
-
|
|
85
|
-
const rateFeedChecks = await Promise.all(route.path.map(async (pool) => {
|
|
86
|
-
const rateFeedId = await this.getPoolRateFeedId(pool);
|
|
87
|
-
const tradingMode = await this.getRateFeedTradingMode(rateFeedId);
|
|
88
|
-
return (0, types_1.isTradingEnabled)(tradingMode);
|
|
89
|
-
}));
|
|
85
|
+
const tradingModes = await this.getTradingModesForPools(route.path);
|
|
90
86
|
// All rate feeds must have trading enabled for the route to be tradable
|
|
91
|
-
return
|
|
87
|
+
return tradingModes.every((tradingMode) => (0, types_1.isTradingEnabled)(tradingMode));
|
|
92
88
|
}
|
|
93
89
|
/**
|
|
94
90
|
* Get trading limits for a pool.
|
|
@@ -126,11 +122,10 @@ class TradingService {
|
|
|
126
122
|
* ```
|
|
127
123
|
*/
|
|
128
124
|
async getPoolTradabilityStatus(pool) {
|
|
129
|
-
const [
|
|
130
|
-
this.
|
|
125
|
+
const [[tradingMode], limits] = await Promise.all([
|
|
126
|
+
this.getTradingModesForPools([pool]),
|
|
131
127
|
this.tradingLimitsService.getPoolTradingLimits(pool),
|
|
132
128
|
]);
|
|
133
|
-
const tradingMode = await this.getRateFeedTradingMode(rateFeedId);
|
|
134
129
|
const circuitBreakerOk = (0, types_1.isTradingEnabled)(tradingMode);
|
|
135
130
|
// Limits are OK if no limits configured OR all limits have capacity
|
|
136
131
|
const limitsOk = limits.length === 0 || limits.every((l) => l.maxIn > 0n && l.maxOut > 0n);
|
|
@@ -150,12 +145,56 @@ class TradingService {
|
|
|
150
145
|
* @returns The rate feed ID address
|
|
151
146
|
*/
|
|
152
147
|
async getPoolRateFeedId(pool) {
|
|
153
|
-
const rateFeedId = await this.
|
|
148
|
+
const [rateFeedId] = await this.getPoolRateFeedIds([pool]);
|
|
149
|
+
return rateFeedId;
|
|
150
|
+
}
|
|
151
|
+
async getTradingModesForPools(pools) {
|
|
152
|
+
const rateFeedIds = await this.getPoolRateFeedIds(pools);
|
|
153
|
+
return this.getTradingModesForRateFeeds(rateFeedIds);
|
|
154
|
+
}
|
|
155
|
+
async getPoolRateFeedIds(pools) {
|
|
156
|
+
if (pools.length === 0) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
const results = await (0, multicall_1.multicall)(this.publicClient, pools.map((pool) => ({
|
|
154
160
|
address: pool.poolAddr,
|
|
155
161
|
abi: abis_1.FPMM_ABI,
|
|
156
162
|
functionName: 'referenceRateFeedID',
|
|
163
|
+
args: [],
|
|
164
|
+
})), { allowFailure: false });
|
|
165
|
+
return results.map((result) => {
|
|
166
|
+
if (result.status === 'failure') {
|
|
167
|
+
throw result.error;
|
|
168
|
+
}
|
|
169
|
+
return result.result;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async getTradingModesForRateFeeds(rateFeedIds) {
|
|
173
|
+
if (rateFeedIds.length === 0) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
const breakerBoxAddr = (0, constants_1.getContractAddress)(this.chainId, 'BreakerBox');
|
|
177
|
+
const uniqueRateFeeds = Array.from(new Map(rateFeedIds.map((rateFeedId) => [rateFeedId.toLowerCase(), rateFeedId])).values());
|
|
178
|
+
const results = await (0, multicall_1.multicall)(this.publicClient, uniqueRateFeeds.map((rateFeedId) => ({
|
|
179
|
+
address: breakerBoxAddr,
|
|
180
|
+
abi: abis_1.BREAKERBOX_ABI,
|
|
181
|
+
functionName: 'getRateFeedTradingMode',
|
|
182
|
+
args: [rateFeedId],
|
|
183
|
+
})), { allowFailure: false });
|
|
184
|
+
const tradingModes = new Map();
|
|
185
|
+
for (const [index, result] of results.entries()) {
|
|
186
|
+
if (result.status === 'failure') {
|
|
187
|
+
throw result.error;
|
|
188
|
+
}
|
|
189
|
+
tradingModes.set(uniqueRateFeeds[index].toLowerCase(), Number(result.result));
|
|
190
|
+
}
|
|
191
|
+
return rateFeedIds.map((rateFeedId) => {
|
|
192
|
+
const tradingMode = tradingModes.get(rateFeedId.toLowerCase());
|
|
193
|
+
if (tradingMode === undefined) {
|
|
194
|
+
throw new Error(`Trading mode not found for rate feed ${rateFeedId}`);
|
|
195
|
+
}
|
|
196
|
+
return tradingMode;
|
|
157
197
|
});
|
|
158
|
-
return rateFeedId;
|
|
159
198
|
}
|
|
160
199
|
}
|
|
161
200
|
exports.TradingService = TradingService;
|
|
@@ -46,6 +46,12 @@ const monadTestnet = (0, viem_1.defineChain)({
|
|
|
46
46
|
url: 'https://testnet.monadexplorer.com',
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
+
contracts: {
|
|
50
|
+
multicall3: {
|
|
51
|
+
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
52
|
+
blockCreated: 251449,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
49
55
|
testnet: true,
|
|
50
56
|
});
|
|
51
57
|
const monad = (0, viem_1.defineChain)({
|
|
@@ -67,6 +73,12 @@ const monad = (0, viem_1.defineChain)({
|
|
|
67
73
|
url: 'https://monadvision.com',
|
|
68
74
|
},
|
|
69
75
|
},
|
|
76
|
+
contracts: {
|
|
77
|
+
multicall3: {
|
|
78
|
+
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
79
|
+
blockCreated: 9248132,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
70
82
|
});
|
|
71
83
|
/**
|
|
72
84
|
* Get the default RPC URL for a given chain ID
|
package/dist/utils/costUtils.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.getPoolCostPercent = getPoolCostPercent;
|
|
|
4
4
|
const types_1 = require("../core/types");
|
|
5
5
|
const abis_1 = require("../core/abis");
|
|
6
6
|
const virtualPool_1 = require("../core/abis/virtualPool");
|
|
7
|
+
const multicall_1 = require("./multicall");
|
|
7
8
|
/**
|
|
8
9
|
* Calculate cost percentage for a pool based on its type
|
|
9
10
|
* Returns cost as a percentage (e.g., 0.5 = 0.5%)
|
|
@@ -28,12 +29,10 @@ async function getPoolCostPercent(pool, publicClient) {
|
|
|
28
29
|
* FPMM pools use lpFee + protocolFee in basis points (10000 = 100%)
|
|
29
30
|
*/
|
|
30
31
|
async function getFPMMCostPercent(poolAddress, publicClient) {
|
|
31
|
-
const results = await
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
],
|
|
36
|
-
});
|
|
32
|
+
const results = await (0, multicall_1.multicall)(publicClient, [
|
|
33
|
+
{ address: poolAddress, abi: abis_1.FPMM_ABI, functionName: 'lpFee' },
|
|
34
|
+
{ address: poolAddress, abi: abis_1.FPMM_ABI, functionName: 'protocolFee' },
|
|
35
|
+
]);
|
|
37
36
|
if (results[0].status === 'failure' || results[1].status === 'failure') {
|
|
38
37
|
throw new Error(`Failed to read fees for pool ${poolAddress}`);
|
|
39
38
|
}
|
|
@@ -48,9 +47,9 @@ async function getFPMMCostPercent(poolAddress, publicClient) {
|
|
|
48
47
|
* Calculate cost for Virtual pools
|
|
49
48
|
*/
|
|
50
49
|
async function getVirtualPoolCostPercent(poolAddress, publicClient) {
|
|
51
|
-
const results = await
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
const results = await (0, multicall_1.multicall)(publicClient, [
|
|
51
|
+
{ address: poolAddress, abi: virtualPool_1.VIRTUAL_POOL_ABI, functionName: 'protocolFee' },
|
|
52
|
+
]);
|
|
54
53
|
if (results[0].status === 'failure') {
|
|
55
54
|
throw new Error(`Failed to read protocolFee for pool ${poolAddress}`);
|
|
56
55
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Abi, PublicClient } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* Standard Multicall3 contract address, deployed at the same address on all EVM chains.
|
|
4
|
+
* https://www.multicall3.com/
|
|
5
|
+
*/
|
|
6
|
+
export declare const MULTICALL3_ADDRESS: "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
7
|
+
type MulticallResult = {
|
|
8
|
+
status: 'success';
|
|
9
|
+
result: unknown;
|
|
10
|
+
} | {
|
|
11
|
+
status: 'failure';
|
|
12
|
+
error: Error;
|
|
13
|
+
};
|
|
14
|
+
interface ContractCall {
|
|
15
|
+
address: `0x${string}`;
|
|
16
|
+
abi: Abi | readonly unknown[];
|
|
17
|
+
functionName: string;
|
|
18
|
+
args?: readonly unknown[];
|
|
19
|
+
}
|
|
20
|
+
interface MulticallOptions {
|
|
21
|
+
allowFailure?: boolean;
|
|
22
|
+
batchSize?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Wrapper around viem's multicall that explicitly provides the Multicall3 address.
|
|
26
|
+
* This ensures multicall works even when the PublicClient was created without a `chain` config.
|
|
27
|
+
*/
|
|
28
|
+
export declare function multicall(publicClient: PublicClient, contracts: ContractCall[], options?: MulticallOptions): Promise<MulticallResult[]>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=multicall.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MULTICALL3_ADDRESS = void 0;
|
|
4
|
+
exports.multicall = multicall;
|
|
5
|
+
/**
|
|
6
|
+
* Standard Multicall3 contract address, deployed at the same address on all EVM chains.
|
|
7
|
+
* https://www.multicall3.com/
|
|
8
|
+
*/
|
|
9
|
+
exports.MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
|
|
10
|
+
/**
|
|
11
|
+
* Wrapper around viem's multicall that explicitly provides the Multicall3 address.
|
|
12
|
+
* This ensures multicall works even when the PublicClient was created without a `chain` config.
|
|
13
|
+
*/
|
|
14
|
+
async function multicall(publicClient, contracts, options = {}) {
|
|
15
|
+
const { allowFailure = true, batchSize } = options;
|
|
16
|
+
const client = publicClient;
|
|
17
|
+
if (typeof client.multicall !== 'function') {
|
|
18
|
+
if (typeof client.readContract !== 'function') {
|
|
19
|
+
throw new Error('Public client does not support multicall or readContract');
|
|
20
|
+
}
|
|
21
|
+
return Promise.all(contracts.map(async (contract) => {
|
|
22
|
+
try {
|
|
23
|
+
const result = await client.readContract({
|
|
24
|
+
...contract,
|
|
25
|
+
args: contract.args ?? [],
|
|
26
|
+
});
|
|
27
|
+
return { status: 'success', result };
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (!allowFailure) {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
status: 'failure',
|
|
35
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
return client.multicall({
|
|
41
|
+
allowFailure,
|
|
42
|
+
batchSize,
|
|
43
|
+
contracts: contracts,
|
|
44
|
+
multicallAddress: exports.MULTICALL3_ADDRESS,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=multicall.js.map
|