@paraswap/dex-lib 2.42.26 → 2.42.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/build/abi/smardex/all/smardex-router.json +648 -0
  2. package/build/abi/smardex/layer-1/smardex-factory.json +242 -0
  3. package/build/abi/smardex/layer-1/smardex-pool.json +506 -0
  4. package/build/abi/smardex/layer-2/smardex-factory.json +185 -0
  5. package/build/abi/smardex/layer-2/smardex-pool.json +578 -0
  6. package/build/config.js +20 -10
  7. package/build/config.js.map +1 -1
  8. package/build/dex/index.js +2 -0
  9. package/build/dex/index.js.map +1 -1
  10. package/build/dex/smardex/config.d.ts +4 -0
  11. package/build/dex/smardex/config.js +64 -0
  12. package/build/dex/smardex/config.js.map +1 -0
  13. package/build/dex/smardex/constants.d.ts +18 -0
  14. package/build/dex/smardex/constants.js +33 -0
  15. package/build/dex/smardex/constants.js.map +1 -0
  16. package/build/dex/smardex/sdk/constants.d.ts +6 -0
  17. package/build/dex/smardex/sdk/constants.js +13 -0
  18. package/build/dex/smardex/sdk/constants.js.map +1 -0
  19. package/build/dex/smardex/sdk/core.d.ts +113 -0
  20. package/build/dex/smardex/sdk/core.js +499 -0
  21. package/build/dex/smardex/sdk/core.js.map +1 -0
  22. package/build/dex/smardex/sdk/errors.d.ts +15 -0
  23. package/build/dex/smardex/sdk/errors.js +22 -0
  24. package/build/dex/smardex/sdk/errors.js.map +1 -0
  25. package/build/dex/smardex/sdk/types.d.ts +62 -0
  26. package/build/dex/smardex/sdk/types.js +3 -0
  27. package/build/dex/smardex/sdk/types.js.map +1 -0
  28. package/build/dex/smardex/sdk/utils.d.ts +44 -0
  29. package/build/dex/smardex/sdk/utils.js +133 -0
  30. package/build/dex/smardex/sdk/utils.js.map +1 -0
  31. package/build/dex/smardex/smardex-event-pool.d.ts +28 -0
  32. package/build/dex/smardex/smardex-event-pool.js +119 -0
  33. package/build/dex/smardex/smardex-event-pool.js.map +1 -0
  34. package/build/dex/smardex/smardex.d.ts +65 -0
  35. package/build/dex/smardex/smardex.js +519 -0
  36. package/build/dex/smardex/smardex.js.map +1 -0
  37. package/build/dex/smardex/types.d.ts +55 -0
  38. package/build/dex/smardex/types.js +3 -0
  39. package/build/dex/smardex/types.js.map +1 -0
  40. package/build/types.d.ts +1 -0
  41. package/package.json +3 -2
  42. package/src/abi/smardex/all/smardex-router.json +648 -0
  43. package/src/abi/smardex/layer-1/smardex-factory.json +242 -0
  44. package/src/abi/smardex/layer-1/smardex-pool.json +506 -0
  45. package/src/abi/smardex/layer-2/smardex-factory.json +185 -0
  46. package/src/abi/smardex/layer-2/smardex-pool.json +578 -0
  47. package/src/config.ts +21 -10
  48. package/src/dex/index.ts +2 -0
  49. package/src/dex/smardex/config.ts +67 -0
  50. package/src/dex/smardex/constants.ts +35 -0
  51. package/src/dex/smardex/sdk/constants.ts +10 -0
  52. package/src/dex/smardex/sdk/core.ts +832 -0
  53. package/src/dex/smardex/sdk/errors.ts +18 -0
  54. package/src/dex/smardex/sdk/types.ts +68 -0
  55. package/src/dex/smardex/sdk/utils.ts +156 -0
  56. package/src/dex/smardex/smardex-e2e.test.ts +275 -0
  57. package/src/dex/smardex/smardex-event-pool.ts +164 -0
  58. package/src/dex/smardex/smardex-events.test.ts +297 -0
  59. package/src/dex/smardex/smardex-integration.test.ts +258 -0
  60. package/src/dex/smardex/smardex.ts +770 -0
  61. package/src/dex/smardex/types.ts +69 -0
  62. package/src/types.ts +1 -0
  63. package/tests/constants-e2e.ts +26 -1
  64. package/.vscode/launch.json +0 -54
  65. package/.vscode/settings.json +0 -2
  66. package/.vscode/tasks.json +0 -15
@@ -0,0 +1,770 @@
1
+ import { AbiCoder, Interface } from '@ethersproject/abi';
2
+ import { Contract } from 'web3-eth-contract';
3
+ import _ from 'lodash';
4
+ import {
5
+ DEST_TOKEN_PARASWAP_TRANSFERS,
6
+ ETHER_ADDRESS,
7
+ NULL_ADDRESS,
8
+ Network,
9
+ SRC_TOKEN_PARASWAP_TRANSFERS,
10
+ SwapSide,
11
+ } from '../../constants';
12
+ import {
13
+ AdapterExchangeParam,
14
+ Address,
15
+ ExchangePrices,
16
+ Logger,
17
+ NumberAsString,
18
+ PoolLiquidity,
19
+ PoolPrices,
20
+ SimpleExchangeParam,
21
+ Token,
22
+ TransferFeeParams,
23
+ TxInfo,
24
+ } from '../../types';
25
+ import { IDexHelper } from '../../dex-helper/index';
26
+ import {
27
+ SmardexFees,
28
+ SmardexPair,
29
+ SmardexPool,
30
+ SmardexPoolOrderedParams,
31
+ SmardexPoolState,
32
+ } from './types';
33
+ import { getBigIntPow, getDexKeysWithNetwork, isETHAddress } from '../../utils';
34
+ import SmardexFactoryLayerOneABI from '../../abi/smardex/layer-1/smardex-factory.json';
35
+ import SmardexFactoryLayerTwoABI from '../../abi/smardex/layer-2/smardex-factory.json';
36
+
37
+ import SmardexRouterABI from '../../abi/smardex/all/smardex-router.json';
38
+ import { SimpleExchange } from '../simple-exchange';
39
+ import {
40
+ SmardexRouterFunctions,
41
+ directSmardexFunctionName,
42
+ DefaultSmardexPoolGasCost,
43
+ SUBGRAPH_TIMEOUT,
44
+ FEES_LAYER_ONE,
45
+ } from '../smardex/constants';
46
+ import { SmardexData, SmardexParam } from '../smardex/types';
47
+ import { IDex } from '../..';
48
+ import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
49
+ import { Adapters, SmardexConfig } from './config';
50
+ import ParaSwapABI from '../../abi/IParaswap.json';
51
+ import { applyTransferFee } from '../../lib/token-transfer-fee';
52
+ import { computeAmountIn, computeAmountOut } from './sdk/core';
53
+ import { SmardexEventPool } from './smardex-event-pool';
54
+ import SmardexPoolLayerOneABI from '../../abi/smardex/layer-1/smardex-pool.json';
55
+ import SmardexPoolLayerTwoABI from '../../abi/smardex/layer-2/smardex-pool.json';
56
+
57
+ const smardexPoolL1 = new Interface(SmardexPoolLayerOneABI);
58
+ const smardexPoolL2 = new Interface(SmardexPoolLayerTwoABI);
59
+
60
+ const coder = new AbiCoder();
61
+
62
+ function encodePools(pools: SmardexPool[]): NumberAsString[] {
63
+ return pools.map(({ fee, direction, address }) => {
64
+ return (
65
+ (BigInt(fee) << 161n) +
66
+ ((direction ? 0n : 1n) << 160n) +
67
+ BigInt(address)
68
+ ).toString();
69
+ });
70
+ }
71
+
72
+ export class Smardex
73
+ extends SimpleExchange
74
+ implements IDex<SmardexData, SmardexParam>
75
+ {
76
+ pairs: { [key: string]: SmardexPair } = {};
77
+ factory: Contract;
78
+
79
+ routerInterface: Interface;
80
+ exchangeRouterInterface: Interface;
81
+ static directFunctionName = directSmardexFunctionName;
82
+
83
+ factoryAddress: string;
84
+ routerAddress: string;
85
+
86
+ protected subgraphURL: string | undefined;
87
+ protected initCode: string;
88
+
89
+ logger: Logger;
90
+ readonly hasConstantPriceLargeAmounts = false;
91
+ readonly isFeeOnTransferSupported: boolean = true;
92
+ readonly SRC_TOKEN_DEX_TRANSFERS = 1;
93
+ readonly DEST_TOKEN_DEX_TRANSFERS = 1;
94
+
95
+ public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
96
+ getDexKeysWithNetwork(SmardexConfig);
97
+
98
+ constructor(
99
+ protected network: Network,
100
+ dexKey: string,
101
+ public dexHelper: IDexHelper,
102
+ protected adapters = Adapters[network] || {},
103
+ ) {
104
+ super(dexHelper, dexKey);
105
+ this.logger = dexHelper.getLogger(dexKey);
106
+ const config = SmardexConfig[dexKey];
107
+ this.routerAddress = config[network].router!;
108
+ this.factoryAddress = config[network].factoryAddress;
109
+ this.subgraphURL = config[network].subgraphURL;
110
+ this.initCode = config[network].initCode;
111
+ const factoryAbi = this.isLayer1()
112
+ ? SmardexFactoryLayerOneABI
113
+ : SmardexFactoryLayerTwoABI;
114
+ this.factory = new dexHelper.web3Provider.eth.Contract(
115
+ factoryAbi as any,
116
+ this.factoryAddress,
117
+ );
118
+ this.routerInterface = new Interface(ParaSwapABI);
119
+ this.exchangeRouterInterface = new Interface(SmardexRouterABI);
120
+ }
121
+
122
+ getAdapters(side: SwapSide): { name: string; index: number }[] | null {
123
+ return this.adapters[side] ? this.adapters[side] : null;
124
+ }
125
+
126
+ async getPoolIdentifiers(
127
+ _from: Token,
128
+ _to: Token,
129
+ side: SwapSide,
130
+ blockNumber: number,
131
+ ): Promise<string[]> {
132
+ const from = this.dexHelper.config.wrapETH(_from);
133
+ const to = this.dexHelper.config.wrapETH(_to);
134
+
135
+ if (from.address.toLowerCase() === to.address.toLowerCase()) {
136
+ return [];
137
+ }
138
+
139
+ const tokenAddress = [from.address.toLowerCase(), to.address.toLowerCase()]
140
+ .sort((a, b) => (BigInt(a) > BigInt(b) ? 1 : -1))
141
+ .join('_');
142
+
143
+ const poolIdentifier = `${this.dexKey}_${tokenAddress}`;
144
+ return [poolIdentifier];
145
+ }
146
+
147
+ async getPricesVolume(
148
+ _from: Token,
149
+ _to: Token,
150
+ amounts: bigint[],
151
+ side: SwapSide,
152
+ blockNumber: number,
153
+ // list of pool identifiers to use for pricing, if undefined use all pools
154
+ limitPools?: string[],
155
+ transferFees: TransferFeeParams = {
156
+ srcFee: 0,
157
+ destFee: 0,
158
+ srcDexFee: 0,
159
+ destDexFee: 0,
160
+ },
161
+ ): Promise<ExchangePrices<SmardexData> | null> {
162
+ try {
163
+ const from = this.dexHelper.config.wrapETH(_from);
164
+ const to = this.dexHelper.config.wrapETH(_to);
165
+
166
+ if (from.address.toLowerCase() === to.address.toLowerCase()) {
167
+ return null;
168
+ }
169
+
170
+ const tokenAddress = [
171
+ from.address.toLowerCase(),
172
+ to.address.toLowerCase(),
173
+ ]
174
+ .sort((a, b) => (BigInt(a) > BigInt(b) ? 1 : -1))
175
+ .join('_');
176
+
177
+ const poolIdentifier = `${this.dexKey}_${tokenAddress}`;
178
+
179
+ if (limitPools && limitPools.every(p => p !== poolIdentifier))
180
+ return null;
181
+
182
+ await this.batchCatchUpPairs([[from, to]], blockNumber);
183
+ const isSell = side === SwapSide.SELL;
184
+ const pairParam = await this.getPairOrderedParams(
185
+ from,
186
+ to,
187
+ blockNumber,
188
+ transferFees.srcDexFee,
189
+ );
190
+
191
+ if (!pairParam) return null;
192
+
193
+ const unitAmount = getBigIntPow(isSell ? from.decimals : to.decimals);
194
+
195
+ // SmarDex does not support Fees on Transfer Tokens
196
+ const [unitVolumeWithFee, ...amountsWithFee] = applyTransferFee(
197
+ [unitAmount, ...amounts],
198
+ side,
199
+ isSell ? transferFees.srcFee : transferFees.destFee,
200
+ isSell ? SRC_TOKEN_PARASWAP_TRANSFERS : DEST_TOKEN_PARASWAP_TRANSFERS,
201
+ );
202
+
203
+ const unit = isSell
204
+ ? await this.getSellPricePath(unitVolumeWithFee, [pairParam])
205
+ : await this.getBuyPricePath(unitVolumeWithFee, [pairParam]);
206
+
207
+ const prices = isSell
208
+ ? await Promise.all(
209
+ amountsWithFee.map(amount =>
210
+ this.getSellPricePath(amount, [pairParam]),
211
+ ),
212
+ )
213
+ : await Promise.all(
214
+ amountsWithFee.map(amount =>
215
+ this.getBuyPricePath(amount, [pairParam]),
216
+ ),
217
+ );
218
+
219
+ const [unitOutWithFee, ...outputsWithFee] = applyTransferFee(
220
+ [unit, ...prices],
221
+ side,
222
+ // This part is confusing, because we treat differently SELL and BUY fees
223
+ // If Buy, we should apply transfer fee on srcToken on top of dexFee applied earlier
224
+ // But for Sell we should apply only one dexFee
225
+ isSell ? transferFees.destDexFee : transferFees.srcFee,
226
+ isSell ? this.DEST_TOKEN_DEX_TRANSFERS : SRC_TOKEN_PARASWAP_TRANSFERS,
227
+ );
228
+
229
+ // As uniswapv2 just has one pool per token pair
230
+ return [
231
+ {
232
+ prices: outputsWithFee,
233
+ unit: unitOutWithFee,
234
+ data: {
235
+ deadline: Math.floor(new Date().getTime()) + 120,
236
+ receiver: this.augustusAddress,
237
+ router: this.routerAddress,
238
+ path: [from.address.toLowerCase(), to.address.toLowerCase()],
239
+ factory: this.factoryAddress,
240
+ initCode: this.initCode,
241
+ pools: [
242
+ {
243
+ address: pairParam.exchange,
244
+ fee: 0, // Smardex does not support Fees on Transfer Tokens
245
+ direction:
246
+ pairParam.fromToken.toLocaleLowerCase() ===
247
+ pairParam.token0.toLocaleLowerCase(),
248
+ },
249
+ ],
250
+ },
251
+ exchange: this.dexKey,
252
+ poolIdentifier,
253
+ gasCost: DefaultSmardexPoolGasCost,
254
+ poolAddresses: [pairParam.exchange],
255
+ },
256
+ ];
257
+ } catch (e) {
258
+ if (blockNumber === 0)
259
+ this.logger.error(
260
+ `Error_getPricesVolume: Aurelius block manager not yet instantiated`,
261
+ );
262
+ this.logger.error(`Error_getPrices:`, e);
263
+ return null;
264
+ }
265
+ }
266
+
267
+ async getBuyPricePath(
268
+ amount: bigint,
269
+ params: SmardexPoolOrderedParams[],
270
+ ): Promise<bigint> {
271
+ let price = amount;
272
+ for (const param of params.reverse()) {
273
+ price = await this.getBuyPrice(param, price);
274
+ }
275
+ return price;
276
+ }
277
+
278
+ async getSellPricePath(
279
+ amount: bigint,
280
+ params: SmardexPoolOrderedParams[],
281
+ ): Promise<bigint> {
282
+ let price = amount;
283
+ for (const param of params) {
284
+ price = await this.getSellPrice(param, price);
285
+ }
286
+ return price;
287
+ }
288
+
289
+ async getBuyPrice(
290
+ priceParams: SmardexPoolOrderedParams,
291
+ destAmount: bigint,
292
+ ): Promise<bigint> {
293
+ const amountIn = computeAmountIn(
294
+ priceParams.token0,
295
+ priceParams.token1,
296
+ priceParams.reserves0,
297
+ priceParams.reserves1,
298
+ priceParams.fictiveReserves0,
299
+ priceParams.fictiveReserves1,
300
+ destAmount,
301
+ priceParams.toToken,
302
+ +priceParams.priceAverageLastTimestamp,
303
+ priceParams.priceAverage0,
304
+ priceParams.priceAverage1,
305
+ priceParams.feesLP,
306
+ priceParams.feesPool,
307
+ ).amount;
308
+
309
+ return BigInt(amountIn.toString());
310
+ }
311
+
312
+ async getSellPrice(
313
+ priceParams: SmardexPoolOrderedParams,
314
+ srcAmount: bigint,
315
+ ): Promise<bigint> {
316
+ const amountOut = computeAmountOut(
317
+ priceParams.token0,
318
+ priceParams.token1,
319
+ priceParams.reserves0,
320
+ priceParams.reserves1,
321
+ priceParams.fictiveReserves0,
322
+ priceParams.fictiveReserves1,
323
+ srcAmount,
324
+ priceParams.fromToken,
325
+ +priceParams.priceAverageLastTimestamp,
326
+ priceParams.priceAverage0,
327
+ priceParams.priceAverage1,
328
+ priceParams.feesLP,
329
+ priceParams.feesPool,
330
+ ).amount;
331
+
332
+ return BigInt(amountOut.toString());
333
+ }
334
+
335
+ // Returns estimated gas cost of calldata for this DEX in multiSwap
336
+ getCalldataGasCost(_poolPrices: PoolPrices<SmardexData>): number | number[] {
337
+ return (
338
+ CALLDATA_GAS_COST.DEX_OVERHEAD +
339
+ CALLDATA_GAS_COST.LENGTH_SMALL +
340
+ // ParentStruct header
341
+ CALLDATA_GAS_COST.OFFSET_SMALL +
342
+ // ParentStruct -> weth
343
+ CALLDATA_GAS_COST.ADDRESS +
344
+ // ParentStruct -> pools[] header
345
+ CALLDATA_GAS_COST.OFFSET_SMALL +
346
+ // ParentStruct -> pools[]
347
+ CALLDATA_GAS_COST.LENGTH_SMALL +
348
+ // ParentStruct -> pools[0]
349
+ CALLDATA_GAS_COST.wordNonZeroBytes(22)
350
+ );
351
+ }
352
+
353
+ async findPair(from: Token, to: Token) {
354
+ if (from.address.toLowerCase() === to.address.toLowerCase()) return null;
355
+ const [token0, token1] =
356
+ BigInt(from.address.toLowerCase()) < BigInt(to.address.toLowerCase())
357
+ ? [from, to]
358
+ : [to, from];
359
+
360
+ const key = `${token0.address.toLowerCase()}-${token1.address.toLowerCase()}`;
361
+ let pair = this.pairs[key];
362
+ if (pair) return pair;
363
+ const exchange = await this.factory.methods
364
+ .getPair(token0.address, token1.address)
365
+ .call();
366
+ if (exchange === NULL_ADDRESS) {
367
+ pair = { token0, token1 };
368
+ } else {
369
+ pair = { token0, token1, exchange };
370
+ }
371
+ this.pairs[key] = pair;
372
+ return pair;
373
+ }
374
+
375
+ async batchCatchUpPairs(pairs: [Token, Token][], blockNumber: number) {
376
+ if (!blockNumber) return;
377
+ const pairsToFetch: SmardexPair[] = [];
378
+ for (const _pair of pairs) {
379
+ const pair = await this.findPair(_pair[0], _pair[1]);
380
+ if (!(pair && pair.exchange)) continue;
381
+ if (!pair.pool) {
382
+ pairsToFetch.push(pair);
383
+ } else if (!pair.pool.getState(blockNumber)) {
384
+ pairsToFetch.push(pair);
385
+ }
386
+ }
387
+
388
+ if (!pairsToFetch.length) return;
389
+
390
+ const reserves = await this.getManyPoolReserves(pairsToFetch, blockNumber);
391
+
392
+ if (reserves.length !== pairsToFetch.length) {
393
+ this.logger.error(
394
+ `Error_getManyPoolReserves didn't get any pool reserves`,
395
+ );
396
+ }
397
+
398
+ for (let i = 0; i < pairsToFetch.length; i++) {
399
+ const pairState = reserves[i];
400
+ const pair = pairsToFetch[i];
401
+ if (!pair.pool) {
402
+ await this.addPool(
403
+ pair,
404
+ pairState.reserves0,
405
+ pairState.reserves1,
406
+ pairState.fictiveReserves0,
407
+ pairState.fictiveReserves1,
408
+ pairState.priceAverage0,
409
+ pairState.priceAverage1,
410
+ pairState.feesLP,
411
+ pairState.feesPool,
412
+ blockNumber,
413
+ pairState.priceAverageLastTimestamp,
414
+ );
415
+ } else pair.pool.setState(pairState, blockNumber);
416
+ }
417
+ }
418
+
419
+ // On Smardex the fees are upgradable on layer 2.
420
+ public getFeesMultiCallData(pairAddress: string) {
421
+ if (this.isLayer1()) {
422
+ return null;
423
+ }
424
+ const callEntry = {
425
+ target: pairAddress,
426
+ callData: smardexPoolL2.encodeFunctionData('getPairFees'),
427
+ };
428
+ const callDecoder = (values: any[]): SmardexFees => {
429
+ const feesData = smardexPoolL2.decodeFunctionResult(
430
+ 'getPairFees',
431
+ values,
432
+ );
433
+ return {
434
+ feesLP: feesData.feesLP_.toBigInt(),
435
+ feesPool: feesData.feesPool_.toBigInt(),
436
+ };
437
+ };
438
+ return {
439
+ callEntry,
440
+ callDecoder,
441
+ };
442
+ }
443
+
444
+ protected async addPool(
445
+ pair: SmardexPair,
446
+ reserves0: string,
447
+ reserves1: string,
448
+ fictiveReserves0: string,
449
+ fictiveReserves1: string,
450
+ priceAverage0: string,
451
+ priceAverage1: string,
452
+ feesLp: bigint,
453
+ feesPool: bigint,
454
+ blockNumber: number,
455
+ priceAverageLastTimestamp: number,
456
+ ) {
457
+ const multiCallFeeData = this.getFeesMultiCallData(pair.exchange!);
458
+ pair.pool = new SmardexEventPool(
459
+ this.isLayer1() ? smardexPoolL1 : smardexPoolL2,
460
+ this.dexHelper,
461
+ pair.exchange!,
462
+ pair.token0,
463
+ pair.token1,
464
+ this.logger,
465
+ // For layer 2 we need to fetch the fees
466
+ multiCallFeeData?.callEntry,
467
+ multiCallFeeData?.callDecoder,
468
+ this.isLayer1(),
469
+ );
470
+ pair.pool.addressesSubscribed.push(pair.exchange!);
471
+
472
+ await pair.pool.initialize(blockNumber, {
473
+ state: {
474
+ reserves0,
475
+ reserves1,
476
+ fictiveReserves0,
477
+ fictiveReserves1,
478
+ priceAverage0,
479
+ priceAverage1,
480
+ feesLP: feesLp,
481
+ feesPool,
482
+ priceAverageLastTimestamp,
483
+ },
484
+ });
485
+ }
486
+
487
+ async getManyPoolReserves(
488
+ pairs: SmardexPair[],
489
+ blockNumber: number,
490
+ ): Promise<SmardexPoolState[]> {
491
+ try {
492
+ const multiCallFeeData = pairs.map(pair =>
493
+ this.getFeesMultiCallData(pair.exchange!),
494
+ );
495
+ const calldata = pairs
496
+ .map((pair, i) => {
497
+ let calldata = [
498
+ {
499
+ target: pair.exchange!,
500
+ callData: smardexPoolL1.encodeFunctionData('getReserves'),
501
+ },
502
+ {
503
+ target: pair.exchange!,
504
+ callData: smardexPoolL1.encodeFunctionData('getFictiveReserves'),
505
+ },
506
+ {
507
+ target: pair.exchange!,
508
+ callData: smardexPoolL1.encodeFunctionData('getPriceAverage'),
509
+ },
510
+ ];
511
+ // Fetch fees only on layer 2
512
+ !this.isLayer1() && calldata.push(multiCallFeeData[i]!.callEntry);
513
+ return calldata;
514
+ })
515
+ .flat();
516
+
517
+ const data: { returnData: any[] } =
518
+ await this.dexHelper.multiContract.methods
519
+ .aggregate(calldata)
520
+ .call({}, blockNumber);
521
+
522
+ const returnData = _.chunk(data.returnData, 4);
523
+ return pairs.map((_pair: SmardexPair, i) => ({
524
+ reserves0: coder
525
+ .decode(['uint256', 'uint256'], returnData[i][0])[0]
526
+ .toString(),
527
+ reserves1: coder
528
+ .decode(['uint256', 'uint256'], returnData[i][0])[1]
529
+ .toString(),
530
+ fictiveReserves0: coder
531
+ .decode(['uint256', 'uint256'], returnData[i][1])[0]
532
+ .toString(),
533
+ fictiveReserves1: coder
534
+ .decode(['uint256', 'uint256'], returnData[i][1])[1]
535
+ .toString(),
536
+ priceAverage0: coder
537
+ .decode(['uint256', 'uint256', 'uint256'], returnData[i][2])[0]
538
+ .toString(),
539
+ priceAverage1: coder
540
+ .decode(['uint256', 'uint256', 'uint256'], returnData[i][2])[1]
541
+ .toString(),
542
+ priceAverageLastTimestamp: coder
543
+ .decode(['uint256', 'uint256', 'uint256'], returnData[i][2])[2]
544
+ .toString(),
545
+ feesLP: this.isLayer1()
546
+ ? FEES_LAYER_ONE.feesLP
547
+ : multiCallFeeData[i]!.callDecoder(returnData[i][3]).feesLP,
548
+ feesPool: this.isLayer1()
549
+ ? FEES_LAYER_ONE.feesPool
550
+ : multiCallFeeData[i]!.callDecoder(returnData[i][3]).feesPool,
551
+ }));
552
+ } catch (e) {
553
+ this.logger.error(
554
+ `Error_getManyPoolReserves could not get reserves with error:`,
555
+ e,
556
+ );
557
+ return [];
558
+ }
559
+ }
560
+
561
+ protected fixPath(path: Address[], srcToken: Address, destToken: Address) {
562
+ return path.map((token: string, i: number) => {
563
+ if (
564
+ (i === 0 && srcToken.toLowerCase() === ETHER_ADDRESS.toLowerCase()) ||
565
+ (i === path.length - 1 &&
566
+ destToken.toLowerCase() === ETHER_ADDRESS.toLowerCase())
567
+ )
568
+ return ETHER_ADDRESS;
569
+ return token;
570
+ });
571
+ }
572
+
573
+ async getPairOrderedParams(
574
+ from: Token,
575
+ to: Token,
576
+ blockNumber: number,
577
+ tokenDexTransferFee: number,
578
+ ): Promise<SmardexPoolOrderedParams | null> {
579
+ const pair = await this.findPair(from, to);
580
+ if (!(pair && pair.pool && pair.exchange)) return null;
581
+ const pairState = pair.pool.getState(blockNumber);
582
+ if (!pairState) {
583
+ this.logger.error(
584
+ `Error_orderPairParams expected reserves, got none (maybe the pool doesn't exist) ${
585
+ from.symbol || from.address
586
+ } ${to.symbol || to.address}`,
587
+ );
588
+ return null;
589
+ }
590
+ // const fee = (pairState.feesPool + tokenDexTransferFee).toString();
591
+
592
+ return {
593
+ fromToken: from.address,
594
+ toToken: to.address,
595
+ token0: pair.token0.address,
596
+ token1: pair.token1.address,
597
+ reserves0: BigInt(pairState.reserves0),
598
+ reserves1: BigInt(pairState.reserves1),
599
+ fictiveReserves0: BigInt(pairState.fictiveReserves0),
600
+ fictiveReserves1: BigInt(pairState.fictiveReserves1),
601
+ priceAverage0: BigInt(pairState.priceAverage0),
602
+ priceAverage1: BigInt(pairState.priceAverage1),
603
+ priceAverageLastTimestamp: pairState.priceAverageLastTimestamp,
604
+ exchange: pair.exchange,
605
+ feesLP: BigInt(pairState.feesLP),
606
+ feesPool: BigInt(pairState.feesPool),
607
+ };
608
+ }
609
+
610
+ getWETHAddress(srcToken: Address, destToken: Address, weth?: Address) {
611
+ if (!isETHAddress(srcToken) && !isETHAddress(destToken))
612
+ return NULL_ADDRESS;
613
+ return weth || this.dexHelper.config.data.wrappedNativeTokenAddress;
614
+ }
615
+
616
+ getAdapterParam(
617
+ srcToken: Address,
618
+ destToken: Address,
619
+ srcAmount: NumberAsString,
620
+ toAmount: NumberAsString,
621
+ data: SmardexData,
622
+ side: SwapSide,
623
+ ): AdapterExchangeParam {
624
+ const payload = this.abiCoder.encodeParameter(
625
+ {
626
+ ParentStruct: {
627
+ path: 'address[]',
628
+ receiver: 'address',
629
+ },
630
+ },
631
+ {
632
+ path: data.path,
633
+ receiver: data.receiver,
634
+ },
635
+ );
636
+ return {
637
+ targetExchange: data.router,
638
+ payload,
639
+ networkFee: '0',
640
+ };
641
+ }
642
+
643
+ async getSimpleParam(
644
+ src: Address,
645
+ dest: Address,
646
+ srcAmount: NumberAsString,
647
+ destAmount: NumberAsString,
648
+ data: SmardexData,
649
+ side: SwapSide,
650
+ ): Promise<SimpleExchangeParam> {
651
+ let routerMethod: any;
652
+ let routerArgs: any;
653
+ if (side === SwapSide.SELL) {
654
+ routerMethod = isETHAddress(src)
655
+ ? SmardexRouterFunctions.sellExactEth
656
+ : SmardexRouterFunctions.swapExactIn;
657
+ routerMethod = isETHAddress(dest)
658
+ ? SmardexRouterFunctions.sellExactToken
659
+ : routerMethod;
660
+
661
+ routerArgs = isETHAddress(src)
662
+ ? [destAmount, data.path, data.receiver, data.deadline]
663
+ : [srcAmount, destAmount, data.path, data.receiver, data.deadline];
664
+ } else {
665
+ routerMethod = isETHAddress(src)
666
+ ? SmardexRouterFunctions.buyExactToken
667
+ : SmardexRouterFunctions.swapExactOut;
668
+ routerMethod = isETHAddress(dest)
669
+ ? SmardexRouterFunctions.buyExactEth
670
+ : routerMethod;
671
+
672
+ routerArgs = isETHAddress(src)
673
+ ? [destAmount, data.path, data.receiver, data.deadline]
674
+ : [destAmount, srcAmount, data.path, data.receiver, data.deadline];
675
+ }
676
+
677
+ const swapData = this.exchangeRouterInterface.encodeFunctionData(
678
+ routerMethod,
679
+ routerArgs,
680
+ );
681
+ return this.buildSimpleParamWithoutWETHConversion(
682
+ src,
683
+ srcAmount,
684
+ dest,
685
+ destAmount,
686
+ swapData,
687
+ data.router,
688
+ );
689
+ }
690
+
691
+ isLayer1(): boolean {
692
+ return this.network === Network.MAINNET;
693
+ }
694
+
695
+ async getTopPoolsForToken(
696
+ tokenAddress: Address,
697
+ limit: number,
698
+ ): Promise<PoolLiquidity[]> {
699
+ if (!this.subgraphURL) return [];
700
+ const query = `
701
+ query ($token: Bytes!, $limit: Int) {
702
+ pools0: pairs(first: $limit, orderBy: reserveUSD, orderDirection: desc, where: {token0: $token, reserve0_gt: 1, reserve1_gt: 1}) {
703
+ id
704
+ token0 {
705
+ id
706
+ decimals
707
+ }
708
+ token1 {
709
+ id
710
+ decimals
711
+ }
712
+ reserveUSD
713
+ }
714
+ pools1: pairs(first: $limit, orderBy: reserveUSD, orderDirection: desc, where: {token1: $token, reserve0_gt: 1, reserve1_gt: 1}) {
715
+ id
716
+ token0 {
717
+ id
718
+ decimals
719
+ }
720
+ token1 {
721
+ id
722
+ decimals
723
+ }
724
+ reserveUSD
725
+ }
726
+ }`;
727
+
728
+ const { data } = await this.dexHelper.httpRequest.post(
729
+ this.subgraphURL,
730
+ {
731
+ query,
732
+ variables: { token: tokenAddress.toLowerCase(), limit },
733
+ },
734
+ SUBGRAPH_TIMEOUT,
735
+ { 'x-api-key': this.dexHelper.config.data.smardexSubgraphAuthToken! },
736
+ );
737
+
738
+ if (!(data && data.pools0 && data.pools1))
739
+ throw new Error("Couldn't fetch the pools from the subgraph");
740
+ const pools0 = _.map(data.pools0, pool => ({
741
+ exchange: this.dexKey,
742
+ address: pool.id.toLowerCase(),
743
+ connectorTokens: [
744
+ {
745
+ address: pool.token1.id.toLowerCase(),
746
+ decimals: parseInt(pool.token1.decimals),
747
+ },
748
+ ],
749
+ liquidityUSD: parseFloat(pool.reserveUSD),
750
+ }));
751
+
752
+ const pools1 = _.map(data.pools1, pool => ({
753
+ exchange: this.dexKey,
754
+ address: pool.id.toLowerCase(),
755
+ connectorTokens: [
756
+ {
757
+ address: pool.token0.id.toLowerCase(),
758
+ decimals: parseInt(pool.token0.decimals),
759
+ },
760
+ ],
761
+ liquidityUSD: parseFloat(pool.reserveUSD),
762
+ }));
763
+
764
+ return _.slice(
765
+ _.sortBy(_.concat(pools0, pools1), [pool => -1 * pool.liquidityUSD]),
766
+ 0,
767
+ limit,
768
+ );
769
+ }
770
+ }