@paraswap/dex-lib 4.6.21 → 4.6.22
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/build/abi/PendleRouterStatic.json +19 -0
- package/build/abi/apex-defi/ApexDefiFactory.abi.json +1749 -0
- package/build/abi/apex-defi/ApexDefiRouter.abi.json +1120 -0
- package/build/abi/apex-defi/ApexDefiToken.abi.json +229 -0
- package/build/abi/apex-defi/ApexDefiWrapper.abi.json +92 -0
- package/build/abi/apex-defi/ApexDefiWrapperFactory.abi.json +1107 -0
- package/build/abi/ekubo/router.json +416 -398
- package/build/dex/aave-pt-to-underlying/aave-pt-to-underlying.d.ts +2 -3
- package/build/dex/aave-pt-to-underlying/aave-pt-to-underlying.js +53 -26
- package/build/dex/aave-pt-to-underlying/aave-pt-to-underlying.js.map +1 -1
- package/build/dex/aave-pt-to-underlying/config.js +3 -0
- package/build/dex/aave-pt-to-underlying/config.js.map +1 -1
- package/build/dex/aave-pt-to-underlying/types.d.ts +1 -0
- package/build/dex/apex-defi/apex-defi-factory.d.ts +26 -0
- package/build/dex/apex-defi/apex-defi-factory.js +53 -0
- package/build/dex/apex-defi/apex-defi-factory.js.map +1 -0
- package/build/dex/apex-defi/apex-defi-pool.d.ts +55 -0
- package/build/dex/apex-defi/apex-defi-pool.js +247 -0
- package/build/dex/apex-defi/apex-defi-pool.js.map +1 -0
- package/build/dex/apex-defi/apex-defi-wrapper-factory.d.ts +57 -0
- package/build/dex/apex-defi/apex-defi-wrapper-factory.js +250 -0
- package/build/dex/apex-defi/apex-defi-wrapper-factory.js.map +1 -0
- package/build/dex/apex-defi/apex-defi.d.ts +97 -0
- package/build/dex/apex-defi/apex-defi.js +1021 -0
- package/build/dex/apex-defi/apex-defi.js.map +1 -0
- package/build/dex/apex-defi/config.d.ts +4 -0
- package/build/dex/apex-defi/config.js +138 -0
- package/build/dex/apex-defi/config.js.map +1 -0
- package/build/dex/apex-defi/types.d.ts +32 -0
- package/build/dex/apex-defi/types.js +3 -0
- package/build/dex/apex-defi/types.js.map +1 -0
- package/build/dex/apex-defi/utils.d.ts +46 -0
- package/build/dex/apex-defi/utils.js +133 -0
- package/build/dex/apex-defi/utils.js.map +1 -0
- package/build/dex/ekubo/config.d.ts +2 -1
- package/build/dex/ekubo/config.js +6 -4
- package/build/dex/ekubo/config.js.map +1 -1
- package/build/dex/ekubo/ekubo.d.ts +13 -12
- package/build/dex/ekubo/ekubo.js +282 -234
- package/build/dex/ekubo/ekubo.js.map +1 -1
- package/build/dex/ekubo/pools/base.d.ts +6 -2
- package/build/dex/ekubo/pools/base.js +120 -113
- package/build/dex/ekubo/pools/base.js.map +1 -1
- package/build/dex/ekubo/pools/full-range.d.ts +6 -5
- package/build/dex/ekubo/pools/full-range.js +50 -40
- package/build/dex/ekubo/pools/full-range.js.map +1 -1
- package/build/dex/ekubo/pools/math/swap.js +3 -3
- package/build/dex/ekubo/pools/math/swap.js.map +1 -1
- package/build/dex/ekubo/pools/math/tick.d.ts +1 -0
- package/build/dex/ekubo/pools/math/tick.js +9 -4
- package/build/dex/ekubo/pools/math/tick.js.map +1 -1
- package/build/dex/ekubo/pools/oracle.d.ts +5 -6
- package/build/dex/ekubo/pools/oracle.js +8 -10
- package/build/dex/ekubo/pools/oracle.js.map +1 -1
- package/build/dex/ekubo/pools/twamm.d.ts +5 -3
- package/build/dex/ekubo/pools/twamm.js +102 -94
- package/build/dex/ekubo/pools/twamm.js.map +1 -1
- package/build/dex/ekubo/pools/utils.d.ts +8 -7
- package/build/dex/ekubo/pools/utils.js +31 -18
- package/build/dex/ekubo/pools/utils.js.map +1 -1
- package/build/dex/ekubo/types.d.ts +1 -0
- package/build/dex/ekubo/utils.d.ts +0 -1
- package/build/dex/ekubo/utils.js +0 -4
- package/build/dex/ekubo/utils.js.map +1 -1
- package/build/dex/yo/config.d.ts +3 -0
- package/build/dex/yo/config.js +21 -0
- package/build/dex/yo/config.js.map +1 -0
- package/build/dex/yo/types.d.ts +13 -0
- package/build/dex/yo/types.js +3 -0
- package/build/dex/yo/types.js.map +1 -0
- package/build/dex/yo/yo-pool.d.ts +13 -0
- package/build/dex/yo/yo-pool.js +26 -0
- package/build/dex/yo/yo-pool.js.map +1 -0
- package/build/dex/yo/yo.d.ts +39 -0
- package/build/dex/yo/yo.js +248 -0
- package/build/dex/yo/yo.js.map +1 -0
- package/package.json +1 -1
package/build/dex/ekubo/ekubo.js
CHANGED
|
@@ -51,12 +51,14 @@ const utils_3 = require("ethers/lib/utils");
|
|
|
51
51
|
const router_json_1 = __importDefault(require("../../abi/ekubo/router.json"));
|
|
52
52
|
const full_range_1 = require("./pools/full-range");
|
|
53
53
|
const constants_2 = require("./pools/math/constants");
|
|
54
|
-
const
|
|
54
|
+
const sqrt_ratio_1 = require("./pools/math/sqrt-ratio");
|
|
55
55
|
const swap_1 = require("./pools/math/swap");
|
|
56
56
|
const tick_1 = require("./pools/math/tick");
|
|
57
57
|
const oracle_1 = require("./pools/oracle");
|
|
58
58
|
const twamm_1 = require("./pools/twamm");
|
|
59
59
|
const utils_4 = require("./pools/utils");
|
|
60
|
+
const mev_resist_1 = require("./pools/mev-resist");
|
|
61
|
+
const utils_5 = require("../../lib/tokens/utils");
|
|
60
62
|
const FALLBACK_POOL_PARAMETERS = [
|
|
61
63
|
{
|
|
62
64
|
fee: 1844674407370955n,
|
|
@@ -79,15 +81,6 @@ const FALLBACK_POOL_PARAMETERS = [
|
|
|
79
81
|
tickSpacing: 95310,
|
|
80
82
|
},
|
|
81
83
|
];
|
|
82
|
-
const tokenPairSchema = joi_1.default.object({
|
|
83
|
-
topPools: joi_1.default.array().items(joi_1.default.object({
|
|
84
|
-
fee: joi_1.default.string(),
|
|
85
|
-
tick_spacing: joi_1.default.number(),
|
|
86
|
-
extension: joi_1.default.string(),
|
|
87
|
-
tvl0_total: joi_1.default.string(),
|
|
88
|
-
tvl1_total: joi_1.default.string(),
|
|
89
|
-
})),
|
|
90
|
-
});
|
|
91
84
|
const allPoolsSchema = joi_1.default.array().items(joi_1.default.object({
|
|
92
85
|
core_address: joi_1.default.string(),
|
|
93
86
|
token0: joi_1.default.string(),
|
|
@@ -107,9 +100,9 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
107
100
|
hasConstantPriceLargeAmounts = false;
|
|
108
101
|
needWrapNative = false;
|
|
109
102
|
isFeeOnTransferSupported = false;
|
|
110
|
-
static dexKeysWithNetwork = (0, utils_1.getDexKeysWithNetwork)(config_1.
|
|
111
|
-
poolKeys = [];
|
|
103
|
+
static dexKeysWithNetwork = (0, utils_1.getDexKeysWithNetwork)(config_1.EKUBO_CONFIG);
|
|
112
104
|
pools = new Map();
|
|
105
|
+
poolKeysSynced = false;
|
|
113
106
|
logger;
|
|
114
107
|
config;
|
|
115
108
|
routerIface;
|
|
@@ -117,61 +110,146 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
117
110
|
supportedExtensions;
|
|
118
111
|
interval;
|
|
119
112
|
// Caches the number of decimals for TVL computation purposes
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
113
|
+
decimals = {
|
|
114
|
+
[constants_1.ETHER_ADDRESS]: 18,
|
|
115
|
+
};
|
|
123
116
|
constructor(network, dexKey, dexHelper) {
|
|
124
117
|
super(dexHelper, dexKey);
|
|
125
118
|
this.network = network;
|
|
126
119
|
this.dexKey = dexKey;
|
|
127
120
|
this.dexHelper = dexHelper;
|
|
128
121
|
this.logger = dexHelper.getLogger(dexKey);
|
|
129
|
-
this.config = config_1.
|
|
122
|
+
this.config = config_1.EKUBO_CONFIG[dexKey][network];
|
|
130
123
|
this.contracts = (0, utils_2.contractsFromDexParams)(this.config, dexHelper.provider);
|
|
131
124
|
this.routerIface = new abi_1.Interface(router_json_1.default);
|
|
132
|
-
// 0 are vanilla pools
|
|
133
125
|
this.supportedExtensions = [
|
|
134
|
-
0n,
|
|
126
|
+
0n, // Vanilla pools
|
|
135
127
|
BigInt(this.config.oracle),
|
|
136
128
|
BigInt(this.config.twamm),
|
|
129
|
+
BigInt(this.config.mevResist),
|
|
137
130
|
];
|
|
138
131
|
}
|
|
139
|
-
// Periodically schedules fetching pool keys from the Ekubo API and filling in details with the quote data fetcher
|
|
140
132
|
async initializePricing(blockNumber) {
|
|
141
|
-
await this.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}, POOL_MAP_UPDATE_INTERVAL_MS);
|
|
145
|
-
}
|
|
146
|
-
// LEGACY
|
|
147
|
-
getAdapters(_side) {
|
|
148
|
-
return null;
|
|
133
|
+
await this.updatePools(blockNumber, true);
|
|
134
|
+
// Periodically schedules fetching pool keys from the Ekubo API and filling in details with the quote data fetcher
|
|
135
|
+
this.interval = setInterval(async () => this.updatePools(await this.dexHelper.provider.getBlockNumber(), true), POOL_MAP_UPDATE_INTERVAL_MS);
|
|
149
136
|
}
|
|
150
|
-
async
|
|
151
|
-
const [token0, token1] = (0, utils_2.convertAndSortTokens)(srcToken, destToken);
|
|
137
|
+
async updatePools(blockNumber, subscribe) {
|
|
152
138
|
let poolKeys;
|
|
153
|
-
|
|
154
|
-
poolKeys =
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
139
|
+
try {
|
|
140
|
+
[poolKeys, this.poolKeysSynced] = [await this.fetchAllPoolKeys(), true];
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
this.logger.error(`Fetching pool keys from Ekubo API failed: ${err}`);
|
|
144
|
+
[poolKeys, this.poolKeysSynced] = [[], false];
|
|
145
|
+
if (subscribe) {
|
|
146
|
+
return;
|
|
160
147
|
}
|
|
161
148
|
}
|
|
162
|
-
|
|
163
|
-
|
|
149
|
+
const untrackedPoolKeys = poolKeys.filter(poolKey => !this.pools.has(poolKey.stringId));
|
|
150
|
+
const [twammPoolKeys, otherPoolKeys] = untrackedPoolKeys.reduce(([twammPoolKeys, otherPoolKeys], poolKey) => {
|
|
151
|
+
if (poolKey.config.extension === BigInt(this.config.twamm)) {
|
|
152
|
+
twammPoolKeys.push(poolKey);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
otherPoolKeys.push(poolKey);
|
|
156
|
+
}
|
|
157
|
+
return [twammPoolKeys, otherPoolKeys];
|
|
158
|
+
}, [[], []]);
|
|
159
|
+
const promises = [];
|
|
160
|
+
if (!subscribe) {
|
|
161
|
+
promises.push(...this.pools.values().map(pool => pool.updateState(blockNumber).catch(err => {
|
|
162
|
+
this.logger.error(`Updating state of pool ${pool.key.stringId} failed: ${err}`);
|
|
163
|
+
})));
|
|
164
|
+
}
|
|
165
|
+
const commonArgs = [
|
|
166
|
+
this.dexKey,
|
|
167
|
+
this.dexHelper,
|
|
168
|
+
this.logger,
|
|
169
|
+
this.contracts,
|
|
170
|
+
];
|
|
171
|
+
const addPool = async (constructor, initialState, poolKey) => {
|
|
172
|
+
const pool = new constructor(...commonArgs, poolKey);
|
|
173
|
+
if (subscribe) {
|
|
174
|
+
await pool.initialize(blockNumber, { state: initialState });
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
pool.setState(initialState ?? (await pool.generateState(blockNumber)), blockNumber);
|
|
178
|
+
}
|
|
179
|
+
this.pools.set(poolKey.stringId, pool);
|
|
180
|
+
};
|
|
181
|
+
for (let batchStart = 0; batchStart < otherPoolKeys.length; batchStart += MAX_BATCH_SIZE) {
|
|
182
|
+
const batch = otherPoolKeys.slice(batchStart, batchStart + MAX_BATCH_SIZE);
|
|
183
|
+
promises.push(this.contracts.core.dataFetcher.getQuoteData(batch.map(poolKey => poolKey.toAbi()), MIN_TICK_SPACINGS_PER_POOL, {
|
|
184
|
+
blockTag: blockNumber,
|
|
185
|
+
})
|
|
186
|
+
.then(async (fetchedData) => {
|
|
187
|
+
await Promise.all(fetchedData.map(async (data, i) => {
|
|
188
|
+
const poolKey = otherPoolKeys[batchStart + i];
|
|
189
|
+
const extension = poolKey.config.extension;
|
|
190
|
+
try {
|
|
191
|
+
switch (extension) {
|
|
192
|
+
case 0n: {
|
|
193
|
+
if (poolKey.config.tickSpacing === 0) {
|
|
194
|
+
await addPool(full_range_1.FullRangePool, full_range_1.FullRangePoolState.fromQuoter(data), poolKey);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
await addPool(base_1.BasePool, base_1.BasePoolState.fromQuoter(data), poolKey);
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case BigInt(this.config.oracle): {
|
|
202
|
+
await addPool(oracle_1.OraclePool, full_range_1.FullRangePoolState.fromQuoter(data), poolKey);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
case BigInt(this.config.mevResist): {
|
|
206
|
+
await addPool(mev_resist_1.MevResistPool, base_1.BasePoolState.fromQuoter(data), poolKey);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
default:
|
|
210
|
+
throw new Error(`Unknown pool extension ${(0, utils_3.hexZeroPad)((0, utils_3.hexlify)(extension), 20)}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
this.logger.error(`Failed to construct pool ${poolKey.stringId}: ${err}`);
|
|
215
|
+
}
|
|
216
|
+
}));
|
|
217
|
+
})
|
|
218
|
+
.catch((err) => {
|
|
219
|
+
this.logger.error(`Fetching batch failed. Pool keys: ${batch.map(poolKey => poolKey.stringId)}. Error: ${err}`);
|
|
220
|
+
}));
|
|
164
221
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
222
|
+
promises.push(...twammPoolKeys.map(async (poolKey) => {
|
|
223
|
+
// The TWAMM data fetcher doesn't allow fetching state for multiple pools at once, so we just let `generateState` work to avoid duplicating logic
|
|
224
|
+
try {
|
|
225
|
+
await addPool(twamm_1.TwammPool, undefined, poolKey);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
this.logger.error(`Failed to construct pool ${poolKey.stringId}: ${err}`);
|
|
229
|
+
}
|
|
230
|
+
}));
|
|
231
|
+
await Promise.all(promises);
|
|
232
|
+
}
|
|
233
|
+
async getPoolIdentifiers(srcToken, destToken, _side, _blockNumber) {
|
|
234
|
+
const [token0, token1] = (0, utils_2.convertAndSortTokens)(srcToken, destToken);
|
|
235
|
+
const stringIds = new Set(this.pools
|
|
236
|
+
.entries()
|
|
237
|
+
.filter(([_, pool]) => pool.key.token0 === token0 && pool.key.token1 === token1)
|
|
238
|
+
.map(([stringId, _]) => stringId));
|
|
239
|
+
if (!this.poolKeysSynced) {
|
|
240
|
+
for (const params of FALLBACK_POOL_PARAMETERS) {
|
|
241
|
+
stringIds
|
|
242
|
+
.add(new utils_4.PoolKey(token0, token1, new utils_4.PoolConfig(0n, params.fee, params.tickSpacing)).stringId)
|
|
243
|
+
.add(new utils_4.PoolKey(token0, token1, new utils_4.PoolConfig(BigInt(this.config.twamm), params.fee, 0)).stringId);
|
|
244
|
+
}
|
|
245
|
+
if ([token0, token1].includes(utils_2.NATIVE_TOKEN_ADDRESS)) {
|
|
246
|
+
stringIds.add(new utils_4.PoolKey(token0, token1, new utils_4.PoolConfig(BigInt(this.config.oracle), 0n, tick_1.FULL_RANGE_TICK_SPACING)).stringId);
|
|
169
247
|
}
|
|
170
248
|
}
|
|
171
|
-
return
|
|
249
|
+
return Array.from(stringIds);
|
|
172
250
|
}
|
|
173
251
|
async getPricesVolume(srcToken, destToken, amounts, side, blockNumber, limitPools) {
|
|
174
|
-
const pools = this.
|
|
252
|
+
const pools = await this.getPools(srcToken, destToken, blockNumber, limitPools);
|
|
175
253
|
const isExactOut = side === constants_1.SwapSide.BUY;
|
|
176
254
|
const amountToken = isExactOut ? destToken : srcToken;
|
|
177
255
|
const amountTokenAddress = (0, utils_2.convertParaSwapToEkubo)(amountToken.address);
|
|
@@ -180,15 +258,15 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
180
258
|
const exchangePrices = [];
|
|
181
259
|
// eslint-disable-next-line no-restricted-syntax
|
|
182
260
|
poolLoop: for (const pool of pools) {
|
|
183
|
-
const poolId = pool.key.
|
|
261
|
+
const poolId = pool.key.stringId;
|
|
184
262
|
try {
|
|
185
263
|
const quotes = [];
|
|
186
264
|
const skipAheadMap = {};
|
|
187
265
|
for (const amount of [unitAmount, ...amounts]) {
|
|
188
266
|
const inputAmount = isExactOut ? -amount : amount;
|
|
189
267
|
const quote = pool.quote(inputAmount, amountTokenAddress, blockNumber);
|
|
190
|
-
if (
|
|
191
|
-
this.logger.debug(`Pool ${poolId} doesn't have enough liquidity to support
|
|
268
|
+
if (quote.consumedAmount !== inputAmount) {
|
|
269
|
+
this.logger.debug(`Pool ${poolId} doesn't have enough liquidity to support swap of ${amount} ${amountToken.symbol ?? amountToken.address}`);
|
|
192
270
|
// There doesn't seem to be a way to skip just this one price.
|
|
193
271
|
// Anyway, this pool is probably not the right one if it has such thin liquidity.
|
|
194
272
|
continue poolLoop;
|
|
@@ -217,87 +295,6 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
217
295
|
}
|
|
218
296
|
return exchangePrices;
|
|
219
297
|
}
|
|
220
|
-
// LEGACY
|
|
221
|
-
getCalldataGasCost(_poolPrices) {
|
|
222
|
-
return CALLDATA_GAS_COST.DEX_NO_PAYLOAD;
|
|
223
|
-
}
|
|
224
|
-
// LEGACY
|
|
225
|
-
getAdapterParam(_srcToken, _destToken, _srcAmount, _destAmount, _data, _side) {
|
|
226
|
-
return {
|
|
227
|
-
targetExchange: this.dexKey,
|
|
228
|
-
payload: '',
|
|
229
|
-
networkFee: '0',
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
async updatePoolState() { }
|
|
233
|
-
async getTopPoolsForToken(tokenAddress, limit) {
|
|
234
|
-
return [];
|
|
235
|
-
// // The integration tests skip initializePricing, hence this check
|
|
236
|
-
// if (this.pools.size === 0) {
|
|
237
|
-
// await this.updatePoolMap(await this.dexHelper.provider.getBlockNumber());
|
|
238
|
-
// }
|
|
239
|
-
// const token = convertParaSwapToEkubo(tokenAddress);
|
|
240
|
-
// const settledPromises = await Promise.allSettled(
|
|
241
|
-
// Array.from(this.pools.entries()).map(async ([poolId, pool]) => {
|
|
242
|
-
// const tokenPair = [pool.key.token0, pool.key.token1];
|
|
243
|
-
// if (!tokenPair.includes(token)) {
|
|
244
|
-
// return null;
|
|
245
|
-
// }
|
|
246
|
-
// const tvlRes = pool.computeTvl();
|
|
247
|
-
// if (tvlRes === null) {
|
|
248
|
-
// throw new Error(`failed to compute TVL for pool ${poolId}`);
|
|
249
|
-
// }
|
|
250
|
-
// const [info0, info1] = await Promise.all(
|
|
251
|
-
// tokenPair.map((ekuboToken, i) =>
|
|
252
|
-
// (async () => {
|
|
253
|
-
// const paraswapToken = convertEkuboToParaSwap(ekuboToken);
|
|
254
|
-
// const decimals = await this.getDecimals(paraswapToken);
|
|
255
|
-
// const token = {
|
|
256
|
-
// address: paraswapToken,
|
|
257
|
-
// decimals,
|
|
258
|
-
// };
|
|
259
|
-
// return {
|
|
260
|
-
// token,
|
|
261
|
-
// tvl: await this.dexHelper.getTokenUSDPrice(token, tvlRes[i]),
|
|
262
|
-
// };
|
|
263
|
-
// })(),
|
|
264
|
-
// ),
|
|
265
|
-
// );
|
|
266
|
-
// return {
|
|
267
|
-
// exchange: this.dexKey,
|
|
268
|
-
// address: this.config.core,
|
|
269
|
-
// connectorTokens: [
|
|
270
|
-
// (info0.token.address !== tokenAddress ? info0 : info1).token,
|
|
271
|
-
// ],
|
|
272
|
-
// liquidityUSD: info0.tvl + info1.tvl,
|
|
273
|
-
// };
|
|
274
|
-
// }),
|
|
275
|
-
// );
|
|
276
|
-
// const poolLiquidities = settledPromises.flatMap(res => {
|
|
277
|
-
// if (res.status === 'rejected') {
|
|
278
|
-
// this.logger.error('TVL computation failed:', res.reason);
|
|
279
|
-
// return [];
|
|
280
|
-
// }
|
|
281
|
-
// return res.value ? [res.value] : [];
|
|
282
|
-
// });
|
|
283
|
-
// poolLiquidities
|
|
284
|
-
// .sort((a, b) => b.liquidityUSD - a.liquidityUSD)
|
|
285
|
-
// .splice(limit, Infinity);
|
|
286
|
-
// return poolLiquidities;
|
|
287
|
-
}
|
|
288
|
-
// private async getDecimals(paraswapToken: string): Promise<number> {
|
|
289
|
-
// const cached = this.decimals[paraswapToken];
|
|
290
|
-
// if (typeof cached === 'number') {
|
|
291
|
-
// return cached;
|
|
292
|
-
// }
|
|
293
|
-
// const decimals: number = await new Contract(
|
|
294
|
-
// paraswapToken,
|
|
295
|
-
// erc20Iface,
|
|
296
|
-
// this.dexHelper.provider,
|
|
297
|
-
// ).decimals();
|
|
298
|
-
// this.decimals[paraswapToken] = decimals;
|
|
299
|
-
// return decimals;
|
|
300
|
-
// }
|
|
301
298
|
getDexParam(_srcToken, _destToken, srcAmount, destAmount, recipient, data, side, _context, _executorAddress) {
|
|
302
299
|
const amount = BigInt(side === constants_1.SwapSide.BUY ? `-${destAmount}` : srcAmount);
|
|
303
300
|
const amountStr = (side === constants_1.SwapSide.SELL ? srcAmount : destAmount).toString();
|
|
@@ -308,8 +305,8 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
308
305
|
data.isToken1,
|
|
309
306
|
ethers_1.BigNumber.from(amount),
|
|
310
307
|
(0, swap_1.isPriceIncreasing)(amount, data.isToken1)
|
|
311
|
-
?
|
|
312
|
-
:
|
|
308
|
+
? sqrt_ratio_1.MAX_SQRT_RATIO_FLOAT
|
|
309
|
+
: sqrt_ratio_1.MIN_SQRT_RATIO_FLOAT,
|
|
313
310
|
ethers_1.BigNumber.from(data.skipAhead[amountStr] ?? 0),
|
|
314
311
|
constants_2.MIN_I256,
|
|
315
312
|
recipient,
|
|
@@ -319,115 +316,77 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
319
316
|
returnAmountPos: undefined,
|
|
320
317
|
};
|
|
321
318
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
clearInterval(this.interval);
|
|
325
|
-
this.interval = undefined;
|
|
326
|
-
}
|
|
319
|
+
async updatePoolState() {
|
|
320
|
+
return this.updatePools(await this.dexHelper.provider.getBlockNumber(), false);
|
|
327
321
|
}
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return
|
|
322
|
+
async getTopPoolsForToken(tokenAddress, limit) {
|
|
323
|
+
const poolsTokenTvls = (await Promise.all(this.pools.values().map(async (pool) => {
|
|
324
|
+
try {
|
|
325
|
+
const tokenPair = [
|
|
326
|
+
(0, utils_2.convertEkuboToParaSwap)(pool.key.token0),
|
|
327
|
+
(0, utils_2.convertEkuboToParaSwap)(pool.key.token1),
|
|
328
|
+
];
|
|
329
|
+
if (!tokenPair.includes(tokenAddress)) {
|
|
330
|
+
return null;
|
|
337
331
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
332
|
+
const tvls = pool.computeTvl();
|
|
333
|
+
const [token0Tvl, token1Tvl] = await Promise.all(tokenPair.map(async (tokenAddress, i) => {
|
|
334
|
+
const decimals = await this.getDecimals(tokenAddress);
|
|
335
|
+
if (decimals === null) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
tvl: tvls[i],
|
|
340
|
+
address: tokenAddress,
|
|
341
|
+
decimals,
|
|
342
|
+
};
|
|
343
|
+
}));
|
|
344
|
+
if (token0Tvl === null || token1Tvl === null) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
pool,
|
|
349
|
+
token0Tvl,
|
|
350
|
+
token1Tvl,
|
|
351
|
+
};
|
|
356
352
|
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
this.logger.error(`TVL computation for pool ${pool.key.stringId} failed: ${err}`);
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}))).filter(res => res !== null);
|
|
358
|
+
const usdTvls = await this.dexHelper.getUsdTokenAmounts(poolsTokenTvls.flatMap(({ token0Tvl, token1Tvl }) => [
|
|
359
|
+
[token0Tvl.address, token0Tvl.tvl],
|
|
360
|
+
[token1Tvl.address, token1Tvl.tvl],
|
|
361
|
+
]));
|
|
362
|
+
const poolLiquidities = poolsTokenTvls.map(({ token0Tvl, token1Tvl }, i) => {
|
|
363
|
+
const [token0UsdTvl, token1UsdTvl] = usdTvls.slice(i * 2, i * 2 + 2);
|
|
364
|
+
const [connector, thisLiquidityUSD, connectorLiquidityUsd] = token0Tvl.address === tokenAddress
|
|
365
|
+
? [token1Tvl, token0UsdTvl, token1UsdTvl]
|
|
366
|
+
: [token0Tvl, token1UsdTvl, token0UsdTvl];
|
|
367
|
+
return {
|
|
368
|
+
exchange: this.dexKey,
|
|
369
|
+
address: this.config.core,
|
|
370
|
+
connectorTokens: [
|
|
371
|
+
{
|
|
372
|
+
address: connector.address,
|
|
373
|
+
decimals: connector.decimals,
|
|
374
|
+
liquidityUSD: connectorLiquidityUsd,
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
liquidityUSD: thisLiquidityUSD,
|
|
378
|
+
};
|
|
357
379
|
});
|
|
380
|
+
poolLiquidities
|
|
381
|
+
.sort((a, b) => b.liquidityUSD - a.liquidityUSD)
|
|
382
|
+
.splice(limit, Infinity);
|
|
383
|
+
return poolLiquidities;
|
|
358
384
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
twammPoolKeys.push(poolKey);
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
normalPoolKeys.push(poolKey);
|
|
367
|
-
}
|
|
368
|
-
return [normalPoolKeys, twammPoolKeys];
|
|
369
|
-
}, [[], []]);
|
|
370
|
-
const commonArgs = [
|
|
371
|
-
this.dexKey,
|
|
372
|
-
this.dexHelper,
|
|
373
|
-
this.logger,
|
|
374
|
-
this.contracts,
|
|
375
|
-
];
|
|
376
|
-
function constructAndInitialize(constructor, initialState, poolKey) {
|
|
377
|
-
const pool = new constructor(...commonArgs, poolKey);
|
|
378
|
-
// This is fulfilled immediately
|
|
379
|
-
pool.initialize(blockNumber, { state: initialState });
|
|
380
|
-
return pool;
|
|
381
|
-
}
|
|
382
|
-
for (let batchStart = 0; batchStart < normalPoolKeys.length; batchStart += MAX_BATCH_SIZE) {
|
|
383
|
-
const batch = normalPoolKeys.slice(batchStart, batchStart + MAX_BATCH_SIZE);
|
|
384
|
-
promises.push((async () => {
|
|
385
|
-
const fetchedData = await this.contracts.core.dataFetcher.getQuoteData(batch.map(poolKey => poolKey.toAbi()), MIN_TICK_SPACINGS_PER_POOL, {
|
|
386
|
-
blockTag: blockNumber,
|
|
387
|
-
});
|
|
388
|
-
return fetchedData.map((data, i) => {
|
|
389
|
-
const poolKey = normalPoolKeys[batchStart + i];
|
|
390
|
-
const extension = poolKey.config.extension;
|
|
391
|
-
let pool;
|
|
392
|
-
switch (extension) {
|
|
393
|
-
case 0n: {
|
|
394
|
-
if (poolKey.config.tickSpacing === 0) {
|
|
395
|
-
pool = constructAndInitialize(full_range_1.FullRangePool, full_range_1.FullRangePoolState.fromQuoter(data), poolKey);
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
pool = constructAndInitialize(base_1.BasePool, base_1.BasePoolState.fromQuoter(data), poolKey);
|
|
399
|
-
}
|
|
400
|
-
break;
|
|
401
|
-
}
|
|
402
|
-
case BigInt(this.config.oracle): {
|
|
403
|
-
pool = constructAndInitialize(oracle_1.OraclePool, full_range_1.FullRangePoolState.fromQuoter(data), poolKey);
|
|
404
|
-
break;
|
|
405
|
-
}
|
|
406
|
-
default:
|
|
407
|
-
throw new Error(`Unknown pool extension ${(0, utils_3.hexlify)(extension)}`);
|
|
408
|
-
}
|
|
409
|
-
return pool;
|
|
410
|
-
});
|
|
411
|
-
})().catch(err => {
|
|
412
|
-
throw {
|
|
413
|
-
batch,
|
|
414
|
-
err,
|
|
415
|
-
};
|
|
416
|
-
}));
|
|
385
|
+
releaseResources() {
|
|
386
|
+
if (this.interval) {
|
|
387
|
+
clearInterval(this.interval);
|
|
388
|
+
this.interval = undefined;
|
|
417
389
|
}
|
|
418
|
-
promises.push(...twammPoolKeys.map(poolKey => (async () => {
|
|
419
|
-
const quoteData = await this.contracts.twamm.dataFetcher.getPoolState(poolKey.toAbi(), {
|
|
420
|
-
blockTag: blockNumber,
|
|
421
|
-
});
|
|
422
|
-
return [
|
|
423
|
-
constructAndInitialize(twamm_1.TwammPool, twamm_1.TwammPoolState.fromQuoter(quoteData), poolKey),
|
|
424
|
-
];
|
|
425
|
-
})()));
|
|
426
|
-
return promises.map(promise => promise.then(pools => pools.map(pool => {
|
|
427
|
-
const poolId = pool.key.string_id;
|
|
428
|
-
this.pools.set(poolId, pool);
|
|
429
|
-
return poolId;
|
|
430
|
-
})));
|
|
431
390
|
}
|
|
432
391
|
async fetchAllPoolKeys() {
|
|
433
392
|
const res = await this.dexHelper.httpRequest.get(`${this.config.apiUrl}/v1/poolKeys`);
|
|
@@ -442,7 +401,96 @@ class Ekubo extends simple_exchange_1.SimpleExchange {
|
|
|
442
401
|
.filter(res => this.supportedExtensions.includes(BigInt(res.extension)) &&
|
|
443
402
|
BigInt(res.core_address) ===
|
|
444
403
|
BigInt(this.contracts.core.contract.address))
|
|
445
|
-
.map(info => new utils_4.PoolKey(BigInt(info.token0), BigInt(info.token1), new utils_4.PoolConfig(info.
|
|
404
|
+
.map(info => new utils_4.PoolKey(BigInt(info.token0), BigInt(info.token1), new utils_4.PoolConfig(BigInt(info.extension), BigInt(info.fee), info.tick_spacing)));
|
|
405
|
+
}
|
|
406
|
+
getDecimals(erc20Token) {
|
|
407
|
+
const cached = this.decimals[erc20Token];
|
|
408
|
+
if (typeof cached !== 'undefined') {
|
|
409
|
+
return cached;
|
|
410
|
+
}
|
|
411
|
+
const call = new ethers_1.Contract(erc20Token, utils_5.erc20Iface, this.dexHelper.provider).decimals();
|
|
412
|
+
const promise = call.catch((err) => {
|
|
413
|
+
this.logger.error('Failed to fetch decimals for token', erc20Token, 'due to:', err);
|
|
414
|
+
return null;
|
|
415
|
+
});
|
|
416
|
+
this.decimals[erc20Token] = promise;
|
|
417
|
+
return promise;
|
|
418
|
+
}
|
|
419
|
+
async getPools(tokenA, tokenB, blockNumber, limitPools) {
|
|
420
|
+
const [token0, token1] = (0, utils_2.convertAndSortTokens)(tokenA, tokenB);
|
|
421
|
+
let unfilteredPools;
|
|
422
|
+
if (typeof limitPools === 'undefined') {
|
|
423
|
+
unfilteredPools = this.pools.values();
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
const unfilteredPoolsArr = [];
|
|
427
|
+
await Promise.all(limitPools.map(async (stringId) => {
|
|
428
|
+
let pool = this.pools.get(stringId);
|
|
429
|
+
if (typeof pool === 'undefined') {
|
|
430
|
+
try {
|
|
431
|
+
pool = await this.initializeUntrackedPool(stringId, blockNumber);
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
this.logger.error(`Initializing pool ${stringId} failed: ${err}`);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
unfilteredPoolsArr.push(pool);
|
|
439
|
+
}));
|
|
440
|
+
unfilteredPools = Iterator.from(unfilteredPoolsArr);
|
|
441
|
+
}
|
|
442
|
+
return unfilteredPools.filter(pool => pool.key.token0 === token0 && pool.key.token1 === token1);
|
|
443
|
+
}
|
|
444
|
+
async initializeUntrackedPool(stringId, blockNumber) {
|
|
445
|
+
const poolKey = utils_4.PoolKey.fromStringId(stringId);
|
|
446
|
+
let constructor;
|
|
447
|
+
const extension = poolKey.config.extension;
|
|
448
|
+
switch (extension) {
|
|
449
|
+
case 0n: {
|
|
450
|
+
if (poolKey.config.tickSpacing === 0) {
|
|
451
|
+
constructor = full_range_1.FullRangePool;
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
constructor = base_1.BasePool;
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case BigInt(this.config.oracle): {
|
|
459
|
+
constructor = oracle_1.OraclePool;
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
case BigInt(this.config.twamm): {
|
|
463
|
+
constructor = twamm_1.TwammPool;
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
case BigInt(this.config.mevResist): {
|
|
467
|
+
constructor = mev_resist_1.MevResistPool;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
default: {
|
|
471
|
+
throw new Error(`Unknown pool extension ${(0, utils_3.hexZeroPad)((0, utils_3.hexlify)(extension), 20)}`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
const pool = new constructor(this.dexKey, this.dexHelper, this.logger, this.contracts, poolKey);
|
|
475
|
+
await pool.initialize(blockNumber);
|
|
476
|
+
this.pools.set(stringId, pool);
|
|
477
|
+
return pool;
|
|
478
|
+
}
|
|
479
|
+
// LEGACY
|
|
480
|
+
getAdapters(_side) {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
// LEGACY
|
|
484
|
+
getCalldataGasCost(_poolPrices) {
|
|
485
|
+
return CALLDATA_GAS_COST.DEX_NO_PAYLOAD;
|
|
486
|
+
}
|
|
487
|
+
// LEGACY
|
|
488
|
+
getAdapterParam(_srcToken, _destToken, _srcAmount, _destAmount, _data, _side) {
|
|
489
|
+
return {
|
|
490
|
+
targetExchange: this.dexKey,
|
|
491
|
+
payload: '',
|
|
492
|
+
networkFee: '0',
|
|
493
|
+
};
|
|
446
494
|
}
|
|
447
495
|
}
|
|
448
496
|
exports.Ekubo = Ekubo;
|