@paraswap/dex-lib 2.18.5 → 2.18.6-swaap-v2

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 (69) hide show
  1. package/.idea/aws.xml +17 -0
  2. package/.idea/codeStyles/Project.xml +19 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/misc.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/paraswap-dex-lib.iml +9 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/build/abi/swaap-v2/vault.json +918 -0
  9. package/build/config.js +4 -2
  10. package/build/config.js.map +1 -1
  11. package/build/dex/hashflow/hashflow.js +52 -68
  12. package/build/dex/hashflow/hashflow.js.map +1 -1
  13. package/build/dex/index.js +2 -0
  14. package/build/dex/index.js.map +1 -1
  15. package/build/dex/pancakeswap-v3/types.d.ts +14 -0
  16. package/build/dex/{test-dex → pancakeswap-v3}/types.js.map +1 -1
  17. package/build/dex/{test-dex → swaap-v2}/config.d.ts +1 -1
  18. package/build/dex/swaap-v2/config.js +25 -0
  19. package/build/dex/swaap-v2/config.js.map +1 -0
  20. package/build/dex/swaap-v2/constants.d.ts +9 -0
  21. package/build/dex/swaap-v2/constants.js +13 -0
  22. package/build/dex/swaap-v2/constants.js.map +1 -0
  23. package/build/dex/swaap-v2/rate-fetcher.d.ts +16 -0
  24. package/build/dex/swaap-v2/rate-fetcher.js +100 -0
  25. package/build/dex/swaap-v2/rate-fetcher.js.map +1 -0
  26. package/build/dex/swaap-v2/swaap-v2.d.ts +55 -0
  27. package/build/dex/swaap-v2/swaap-v2.js +465 -0
  28. package/build/dex/swaap-v2/swaap-v2.js.map +1 -0
  29. package/build/dex/swaap-v2/types.d.ts +64 -0
  30. package/build/dex/swaap-v2/types.js +7 -0
  31. package/build/dex/swaap-v2/types.js.map +1 -0
  32. package/build/dex/swaap-v2/utils.d.ts +7 -0
  33. package/build/dex/swaap-v2/utils.js +34 -0
  34. package/build/dex/swaap-v2/utils.js.map +1 -0
  35. package/build/dex/swaap-v2/validators.d.ts +5 -0
  36. package/build/dex/swaap-v2/validators.js +120 -0
  37. package/build/dex/swaap-v2/validators.js.map +1 -0
  38. package/build/types.d.ts +1 -0
  39. package/package.json +1 -1
  40. package/src/abi/swaap-v2/vault.json +918 -0
  41. package/src/config.ts +5 -2
  42. package/src/dex/hashflow/hashflow.ts +85 -110
  43. package/src/dex/index.ts +2 -0
  44. package/src/dex/swaap-v2/config.ts +25 -0
  45. package/src/dex/swaap-v2/constants.ts +14 -0
  46. package/src/dex/swaap-v2/rate-fetcher.ts +164 -0
  47. package/src/dex/swaap-v2/swaap-v2-e2e.test.ts +199 -0
  48. package/src/dex/swaap-v2/swaap-v2-integration.test.ts +142 -0
  49. package/src/dex/swaap-v2/swaap-v2.ts +714 -0
  50. package/src/dex/swaap-v2/types.ts +74 -0
  51. package/src/dex/swaap-v2/utils.ts +44 -0
  52. package/src/dex/swaap-v2/validators.ts +123 -0
  53. package/src/types.ts +1 -0
  54. package/tests/constants-e2e.ts +1 -1
  55. package/tests/utils-e2e.ts +5 -0
  56. package/build/abi/DirectSwap.json +0 -1018
  57. package/build/dex/test-dex/config.js +0 -15
  58. package/build/dex/test-dex/config.js.map +0 -1
  59. package/build/dex/test-dex/test-dex-pool.d.ts +0 -39
  60. package/build/dex/test-dex/test-dex-pool.js +0 -63
  61. package/build/dex/test-dex/test-dex-pool.js.map +0 -1
  62. package/build/dex/test-dex/test-dex.d.ts +0 -37
  63. package/build/dex/test-dex/test-dex.js +0 -126
  64. package/build/dex/test-dex/test-dex.js.map +0 -1
  65. package/build/dex/test-dex/types.d.ts +0 -6
  66. package/build/dex/woo-fi-v2/woo-fi-math.d.ts +0 -16
  67. package/build/dex/woo-fi-v2/woo-fi-math.js +0 -137
  68. package/build/dex/woo-fi-v2/woo-fi-math.js.map +0 -1
  69. /package/build/dex/{test-dex → pancakeswap-v3}/types.js +0 -0
@@ -0,0 +1,714 @@
1
+ import {
2
+ Token,
3
+ Address,
4
+ ExchangePrices,
5
+ PoolPrices,
6
+ AdapterExchangeParam,
7
+ SimpleExchangeParam,
8
+ PoolLiquidity,
9
+ Logger,
10
+ ExchangeTxInfo,
11
+ OptimalSwapExchange,
12
+ PreprocessTransactionOptions,
13
+ } from '../../types';
14
+ import { SwapSide, Network, MAX_INT, MAX_UINT } from '../../constants';
15
+ import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
16
+ import { getDexKeysWithNetwork } from '../../utils';
17
+ import { IDex } from '../idex';
18
+ import { IDexHelper } from '../../dex-helper/idex-helper';
19
+ import {
20
+ SwaapV2Data,
21
+ SwaapV2PriceLevel,
22
+ SwaapV2PriceLevels,
23
+ SwaapV2APIParameters,
24
+ SwaapV2QuoteError,
25
+ } from './types';
26
+ import { getLocalDeadlineAsFriendlyPlaceholder, SimpleExchange } from '../simple-exchange';
27
+ import { Adapters, SwaapV2Config } from './config';
28
+ import { RateFetcher } from './rate-fetcher';
29
+ import routerAbi from '../../abi/swaap-v2/vault.json';
30
+ import BigNumber from 'bignumber.js';
31
+ import { BN_0, BN_1, getBigNumberPow } from '../../bignumber-constants';
32
+ import { Interface } from 'ethers/lib/utils';
33
+ import { assert } from 'ts-essentials';
34
+ import {
35
+ SWAAP_RFQ_API_URL,
36
+ SWAAP_RFQ_PRICES_ENDPOINT,
37
+ SWAAP_RFQ_QUOTE_ENDPOINT,
38
+ SWAAP_RFQ_API_PRICES_POLLING_INTERVAL_MS,
39
+ SWAAP_RFQ_PRICES_CACHES_TTL_S,
40
+ GAS_COST_ESTIMATION,
41
+ BATCH_SWAP_SELECTOR,
42
+ CALLER_SLOT,
43
+ } from './constants';
44
+ import { BI_MAX_UINT256 } from '../../bigint-constants';
45
+ import {
46
+ getPoolIdentifier,
47
+ getPriceLevelsCacheKey,
48
+ normalizeTokenAddress,
49
+ getPairName,
50
+ } from './utils';
51
+ import { Method } from '../../dex-helper/irequest-wrapper';
52
+
53
+ export class SwaapV2 extends SimpleExchange implements IDex<SwaapV2Data> {
54
+ readonly isStatePollingDex = true;
55
+ readonly hasConstantPriceLargeAmounts = false;
56
+ readonly needWrapNative = false;
57
+ readonly isFeeOnTransferSupported = false;
58
+ private rateFetcher: RateFetcher;
59
+ private swaapV2AuthToken: string;
60
+
61
+ public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
62
+ getDexKeysWithNetwork(SwaapV2Config);
63
+
64
+ logger: Logger;
65
+
66
+ constructor(
67
+ readonly network: Network,
68
+ readonly dexKey: string,
69
+ readonly dexHelper: IDexHelper,
70
+ protected adapters = Adapters[network] || {},
71
+ readonly routerAddressPlaceholder: string = SwaapV2Config['SwaapV2'][
72
+ network
73
+ ].routerAddress,
74
+ protected routerInterface = new Interface(routerAbi),
75
+ ) {
76
+ super(dexHelper, dexKey);
77
+ this.logger = dexHelper.getLogger(dexKey);
78
+ const token = dexHelper.config.data.swaapV2AuthToken;
79
+ assert(
80
+ token !== undefined,
81
+ 'SwaapV2 auth token is not specified with env variable',
82
+ );
83
+
84
+ this.swaapV2AuthToken = token;
85
+
86
+ this.rateFetcher = new RateFetcher(
87
+ this.dexHelper,
88
+ this.dexKey,
89
+ this.logger,
90
+ {
91
+ rateConfig: {
92
+ pricesIntervalMs: SWAAP_RFQ_API_PRICES_POLLING_INTERVAL_MS,
93
+ pricesReqParams: this.getPriceLevelsReqParams(),
94
+ pricesCacheTTLSecs: SWAAP_RFQ_PRICES_CACHES_TTL_S,
95
+ },
96
+ },
97
+ );
98
+ }
99
+
100
+ async initializePricing(blockNumber: number): Promise<void> {
101
+ if (!this.dexHelper.config.isSlave) {
102
+ await this.rateFetcher.start();
103
+ }
104
+ return;
105
+ }
106
+
107
+ getAdapters(side: SwapSide): { name: string; index: number }[] | null {
108
+ return this.adapters[side] ? this.adapters[side] : null;
109
+ }
110
+
111
+ async getPoolIdentifiers(
112
+ srcToken: Token,
113
+ destToken: Token,
114
+ side: SwapSide,
115
+ blockNumber: number,
116
+ ): Promise<string[]> {
117
+ const normalizedSrcToken = this.normalizeToken(srcToken);
118
+ const normalizedDestToken = this.normalizeToken(destToken);
119
+
120
+ if (normalizedSrcToken.address === normalizedDestToken.address) {
121
+ return [];
122
+ }
123
+
124
+ const poolIdentifier = getPoolIdentifier(
125
+ this.dexKey,
126
+ normalizedSrcToken.address,
127
+ normalizedDestToken.address,
128
+ );
129
+
130
+ const levels = await this.getCachedLevels();
131
+ if (levels == null) {
132
+ return [];
133
+ }
134
+
135
+ return Object.keys(levels)
136
+ .map((pair: string) => {
137
+ return getPoolIdentifier(
138
+ this.dexKey,
139
+ levels[pair].base!,
140
+ levels[pair].quote!,
141
+ );
142
+ })
143
+ .filter((pi: string) => pi == poolIdentifier);
144
+ }
145
+
146
+ computePricesFromLevelsBis(
147
+ amounts: BigNumber[],
148
+ asksAndBids: SwaapV2PriceLevels,
149
+ srcToken: Token,
150
+ destToken: Token,
151
+ side: SwapSide,
152
+ ): bigint[] {
153
+ let levels: SwaapV2PriceLevel[] = [];
154
+ if (side == SwapSide.BUY) {
155
+ if (destToken.address == asksAndBids.base!) {
156
+ levels = asksAndBids.asks;
157
+ } else {
158
+ levels = this.invertPrices(asksAndBids.bids);
159
+ }
160
+ } else {
161
+ if (srcToken.address == asksAndBids.base!) {
162
+ levels = asksAndBids.bids;
163
+ } else {
164
+ levels = this.invertPrices(asksAndBids.asks);
165
+ }
166
+ }
167
+ return this.computeLevelsQuote(amounts, levels, srcToken, destToken, side);
168
+ }
169
+
170
+ inversePrice(priceLevel: SwaapV2PriceLevel): SwaapV2PriceLevel {
171
+ return {
172
+ level: priceLevel.level * priceLevel.price,
173
+ price: 1 / priceLevel.price,
174
+ };
175
+ }
176
+
177
+ invertPrices(levels: SwaapV2PriceLevel[]): SwaapV2PriceLevel[] {
178
+ return levels.map(pl => this.inversePrice(pl));
179
+ }
180
+
181
+ computeLevelsQuote(
182
+ amounts: BigNumber[],
183
+ levels: SwaapV2PriceLevel[],
184
+ srcToken: Token,
185
+ destToken: Token,
186
+ side: SwapSide,
187
+ ): bigint[] {
188
+ const size = levels.length;
189
+ if (size == 0) {
190
+ return amounts.map(_ => BigInt(0));
191
+ }
192
+ return amounts.map((amount: BigNumber) => {
193
+ if (amount.isZero() || amount.lt(BigNumber(levels[0].level))) {
194
+ return BigInt(0);
195
+ }
196
+
197
+ let i = 0;
198
+ let output = BN_0;
199
+ let previousLevel = BN_0;
200
+ let remaininig = BigNumber(amount);
201
+ let enoughLiquidity = false;
202
+ while (i < size) {
203
+ const levelDelta = BigNumber(levels[i].level).minus(previousLevel);
204
+ if (levelDelta.lte(remaininig)) {
205
+ output = output.plus(levelDelta.times(levels[i].price));
206
+ remaininig = remaininig.minus(levelDelta);
207
+ previousLevel = BigNumber(levels[i].level);
208
+ i += 1;
209
+ } else {
210
+ output = output.plus(remaininig.times(levels[i].price));
211
+ enoughLiquidity = true;
212
+ break;
213
+ }
214
+ }
215
+ if (enoughLiquidity) {
216
+ return BigInt(
217
+ output
218
+ .multipliedBy(
219
+ getBigNumberPow(
220
+ side == SwapSide.BUY ? srcToken.decimals : destToken.decimals,
221
+ ),
222
+ )
223
+ .toFixed(0),
224
+ );
225
+ }
226
+ return BigInt(0); // not enough liquidity
227
+ });
228
+ }
229
+
230
+ async getCachedLevels(): Promise<Record<string, SwaapV2PriceLevels> | null> {
231
+ const cachedLevels = await this.dexHelper.cache.get(
232
+ this.dexKey,
233
+ this.network,
234
+ getPriceLevelsCacheKey(this.dexKey),
235
+ );
236
+
237
+ if (cachedLevels) {
238
+ return JSON.parse(cachedLevels) as Record<string, SwaapV2PriceLevels>;
239
+ }
240
+
241
+ return null;
242
+ }
243
+
244
+ normalizeToken(token: Token): Token {
245
+ return {
246
+ address: normalizeTokenAddress(token.address),
247
+ decimals: token.decimals,
248
+ };
249
+ }
250
+
251
+ async getPricesVolume(
252
+ srcToken: Token,
253
+ destToken: Token,
254
+ amounts: bigint[],
255
+ side: SwapSide,
256
+ blockNumber: number,
257
+ limitPools?: string[],
258
+ ): Promise<null | ExchangePrices<SwaapV2Data>> {
259
+ const normalizedSrcToken = this.normalizeToken(srcToken);
260
+ const normalizedDestToken = this.normalizeToken(destToken);
261
+
262
+ const requestedPoolIdentifier: string = getPoolIdentifier(
263
+ this.dexKey,
264
+ normalizedSrcToken.address,
265
+ normalizedDestToken.address,
266
+ );
267
+
268
+ if (normalizedSrcToken.address === normalizedDestToken.address) {
269
+ return null;
270
+ }
271
+
272
+ const pools =
273
+ limitPools ??
274
+ (await this.getPoolIdentifiers(srcToken, destToken, side, blockNumber));
275
+
276
+ const levels = await this.getCachedLevels();
277
+ if (levels == null) {
278
+ return null;
279
+ }
280
+
281
+ const levelEntries: SwaapV2PriceLevels[] = Object.keys(levels)
282
+ .map((pair: string) => {
283
+ if (
284
+ pools.includes(
285
+ getPoolIdentifier(
286
+ this.dexKey,
287
+ normalizedSrcToken.address,
288
+ normalizedDestToken.address,
289
+ ),
290
+ )
291
+ ) {
292
+ return levels[pair];
293
+ }
294
+ return undefined;
295
+ })
296
+ .filter(o => o !== undefined)
297
+ .map(o => o!);
298
+
299
+ const prices = levelEntries.map((askAndBids: SwaapV2PriceLevels) => {
300
+ const divider = getBigNumberPow(
301
+ (side === SwapSide.SELL ? normalizedSrcToken : normalizedDestToken)
302
+ .decimals,
303
+ );
304
+
305
+ const amountsFloat = amounts.map(a =>
306
+ new BigNumber(a.toString()).dividedBy(divider),
307
+ );
308
+
309
+ const unitPrice = this.computePricesFromLevelsBis(
310
+ [BN_1],
311
+ askAndBids,
312
+ normalizedSrcToken,
313
+ normalizedDestToken,
314
+ side,
315
+ )[0];
316
+ const prices = this.computePricesFromLevelsBis(
317
+ amountsFloat,
318
+ askAndBids,
319
+ normalizedSrcToken,
320
+ normalizedDestToken,
321
+ side,
322
+ );
323
+
324
+ return {
325
+ gasCost: GAS_COST_ESTIMATION,
326
+ exchange: this.dexKey,
327
+ data: {},
328
+ prices,
329
+ unit: unitPrice,
330
+ poolIdentifier: requestedPoolIdentifier,
331
+ poolAddresses: [this.routerAddressPlaceholder],
332
+ } as PoolPrices<SwaapV2Data>;
333
+ });
334
+
335
+ return prices;
336
+ }
337
+
338
+ getBaseToken(poolIdentifier: string): string {
339
+ return poolIdentifier.split('_')[1];
340
+ }
341
+
342
+ getLevels(
343
+ askAndBids: SwaapV2PriceLevels,
344
+ side: SwapSide,
345
+ poolIdentifier: string,
346
+ ) {
347
+ const baseToken: string = this.getBaseToken(poolIdentifier);
348
+ if (side == SwapSide.SELL) {
349
+ return askAndBids.asks;
350
+ }
351
+ return askAndBids.asks;
352
+ }
353
+
354
+ async preProcessTransaction(
355
+ optimalSwapExchange: OptimalSwapExchange<SwaapV2Data>,
356
+ srcToken: Token,
357
+ destToken: Token,
358
+ side: SwapSide,
359
+ options: PreprocessTransactionOptions,
360
+ ): Promise<[OptimalSwapExchange<SwaapV2Data>, ExchangeTxInfo]> {
361
+ const isSell = side === SwapSide.SELL;
362
+
363
+ const normalizedSrcToken = this.normalizeToken(srcToken);
364
+ const normalizedDestToken = this.normalizeToken(destToken);
365
+
366
+ const tolerance = (
367
+ options.slippageFactor > BN_1
368
+ ? options.slippageFactor.minus(BN_1)
369
+ : BN_1.minus(options.slippageFactor)
370
+ ).toNumber();
371
+
372
+ const quote = await this.rateFetcher.getQuote(
373
+ this.network,
374
+ normalizedSrcToken,
375
+ normalizedDestToken,
376
+ isSell ? optimalSwapExchange.srcAmount : optimalSwapExchange.destAmount,
377
+ isSell ? 1 : 2,
378
+ options.txOrigin,
379
+ this.augustusAddress,
380
+ tolerance,
381
+ this.getQuoteReqParams(),
382
+ );
383
+
384
+ if (!quote.success) {
385
+ const message = `${this.dexKey}-${
386
+ this.network
387
+ }: Failed to fetch RFQ for ${getPairName(
388
+ normalizedSrcToken.address,
389
+ normalizedDestToken.address,
390
+ )}: ${JSON.stringify(quote)}`;
391
+ this.logger.warn(message);
392
+ throw new SwaapV2QuoteError(message);
393
+ } else if (!quote.calldata) {
394
+ const message = `${this.dexKey}-${
395
+ this.network
396
+ }: Failed to fetch RFQ for ${getPairName(
397
+ normalizedSrcToken.address,
398
+ normalizedDestToken.address,
399
+ )}. Missing quote data`;
400
+ this.logger.warn(message);
401
+ throw new SwaapV2QuoteError(message);
402
+ } else if (!quote.router) {
403
+ const message = `${this.dexKey}-${
404
+ this.network
405
+ }: Failed to fetch RFQ for ${getPairName(
406
+ normalizedSrcToken.address,
407
+ normalizedDestToken.address,
408
+ )}. Missing router address`;
409
+ this.logger.warn(message);
410
+ throw new SwaapV2QuoteError(message);
411
+ }
412
+
413
+ return [
414
+ {
415
+ ...optimalSwapExchange,
416
+ data: {
417
+ router: quote.router,
418
+ callData: quote.calldata,
419
+ },
420
+ },
421
+ { deadline: BigInt(getLocalDeadlineAsFriendlyPlaceholder()) },
422
+ ];
423
+ }
424
+
425
+ // Returns estimated gas cost of calldata for this DEX in multiSwap
426
+ getCalldataGasCost(poolPrices: PoolPrices<SwaapV2Data>): number | number[] {
427
+ return (
428
+ CALLDATA_GAS_COST.DEX_OVERHEAD +
429
+ CALLDATA_GAS_COST.LENGTH_LARGE +
430
+ // ParentStruct header
431
+ CALLDATA_GAS_COST.OFFSET_SMALL +
432
+ // ParentStruct -> swaps[] header
433
+ CALLDATA_GAS_COST.OFFSET_LARGE +
434
+ // ParentStruct -> assets[] header
435
+ CALLDATA_GAS_COST.OFFSET_LARGE +
436
+ // ParentStruct -> funds
437
+ CALLDATA_GAS_COST.ADDRESS +
438
+ CALLDATA_GAS_COST.BOOL +
439
+ CALLDATA_GAS_COST.ADDRESS +
440
+ CALLDATA_GAS_COST.BOOL +
441
+ // ParentStruct -> limits[] header
442
+ CALLDATA_GAS_COST.OFFSET_LARGE +
443
+ // ParentStruct -> deadline
444
+ CALLDATA_GAS_COST.TIMESTAMP +
445
+ // ParentStruct -> swaps[]
446
+ CALLDATA_GAS_COST.LENGTH_SMALL +
447
+ // ParentStruct -> swaps[0] header
448
+ CALLDATA_GAS_COST.OFFSET_SMALL +
449
+ // ParentStruct -> swaps[0] -> poolId
450
+ CALLDATA_GAS_COST.FULL_WORD +
451
+ // ParentStruct -> swaps[0] -> assetInIndex
452
+ CALLDATA_GAS_COST.INDEX +
453
+ // ParentStruct -> swaps[0] -> assetOutIndex
454
+ CALLDATA_GAS_COST.INDEX +
455
+ // ParentStruct -> swaps[0] -> amount
456
+ CALLDATA_GAS_COST.AMOUNT +
457
+ // ParentStruct -> swaps[0] -> userData header
458
+ CALLDATA_GAS_COST.OFFSET_SMALL +
459
+ // ParentStruct -> swaps[0] -> userData
460
+ CALLDATA_GAS_COST.ZERO +
461
+ // ParentStruct -> assets[]
462
+ CALLDATA_GAS_COST.LENGTH_SMALL +
463
+ // ParentStruct -> assets[0:2]
464
+ CALLDATA_GAS_COST.ADDRESS * 2 +
465
+ // ParentStruct -> limits[]
466
+ CALLDATA_GAS_COST.LENGTH_SMALL +
467
+ // ParentStruct -> limits[0:2]
468
+ CALLDATA_GAS_COST.FULL_WORD * 2 +
469
+ // Bool -> IsBatchSwap
470
+ CALLDATA_GAS_COST.BOOL
471
+ );
472
+ }
473
+
474
+ getAdapterParam(
475
+ srcToken: string,
476
+ destToken: string,
477
+ srcAmount: string,
478
+ destAmount: string,
479
+ data: SwaapV2Data,
480
+ side: SwapSide,
481
+ ): AdapterExchangeParam {
482
+ const { router, callData } = data;
483
+
484
+ assert(
485
+ router !== undefined,
486
+ `${this.dexKey}-${this.network}: router undefined`,
487
+ );
488
+
489
+ assert(
490
+ callData !== undefined,
491
+ `${this.dexKey}-${this.network}: callData undefined`,
492
+ );
493
+
494
+ let payload: string;
495
+ const truncatedCalldata = '0x' + callData.slice(10); // droping the function selector
496
+ const isBatchSwap = callData.slice(0, 10) == BATCH_SWAP_SELECTOR;
497
+
498
+ if (isBatchSwap) {
499
+ const batchswapAbi = routerAbi.filter(abi => abi.name == 'batchSwap');
500
+
501
+ const callDataStruct = this.abiCoder.decodeParameters(
502
+ batchswapAbi[0].inputs!,
503
+ truncatedCalldata,
504
+ );
505
+
506
+ const callerSlots = Array(callDataStruct.swaps.length).fill(160);
507
+
508
+ payload = this.abiCoder.encodeParameters(
509
+ [
510
+ 'bool',
511
+ 'uint256[]',
512
+ {
513
+ ParentStruct: {
514
+ 'swaps[]': {
515
+ poolId: 'bytes32',
516
+ assetInIndex: 'uint256',
517
+ assetOutIndex: 'uint256',
518
+ amount: 'uint256',
519
+ userData: 'bytes',
520
+ },
521
+ assets: 'address[]',
522
+ funds: {
523
+ sender: 'address',
524
+ fromInternalBalance: 'bool',
525
+ recipient: 'address',
526
+ toInternalBalance: 'bool',
527
+ },
528
+ limits: 'int256[]',
529
+ },
530
+ },
531
+ ],
532
+ [
533
+ isBatchSwap,
534
+ callerSlots,
535
+ {
536
+ swaps: callDataStruct.swaps,
537
+ assets: callDataStruct.assets,
538
+ funds: callDataStruct.funds,
539
+ limits: callDataStruct.limits.map((_: any) => MAX_INT),
540
+ },
541
+ ],
542
+ );
543
+ } else {
544
+ const swapAbi = routerAbi.filter(abi => abi.name == 'swap');
545
+
546
+ const callDataStruct = this.abiCoder.decodeParameters(
547
+ swapAbi[0].inputs!,
548
+ truncatedCalldata,
549
+ );
550
+
551
+ const callerSlot = CALLER_SLOT;
552
+
553
+ payload = this.abiCoder.encodeParameters(
554
+ [
555
+ 'bool',
556
+ 'uint256',
557
+ {
558
+ ParentStruct: {
559
+ swap: {
560
+ poolId: 'bytes32',
561
+ kind: 'uint8',
562
+ assetIn: 'address',
563
+ assetOut: 'address',
564
+ amount: 'uint256',
565
+ userData: 'bytes',
566
+ },
567
+ funds: {
568
+ sender: 'address',
569
+ fromInternalBalance: 'bool',
570
+ recipient: 'address',
571
+ toInternalBalance: 'bool',
572
+ },
573
+ limit: 'uint256',
574
+ },
575
+ },
576
+ ],
577
+ [
578
+ isBatchSwap,
579
+ callerSlot,
580
+ {
581
+ swap: {
582
+ poolId: callDataStruct.singleSwap.poolId,
583
+ kind: callDataStruct.singleSwap.kind,
584
+ assetIn: callDataStruct.singleSwap.assetIn,
585
+ assetOut: callDataStruct.singleSwap.assetOut,
586
+ amount: callDataStruct.singleSwap.amount,
587
+ userData: callDataStruct.singleSwap.userData,
588
+ },
589
+ funds: {
590
+ sender: callDataStruct.funds.sender,
591
+ fromInternalBalance: callDataStruct.funds.fromInternalBalance,
592
+ recipient: callDataStruct.funds.recipient,
593
+ toInternalBalance: callDataStruct.funds.toInternalBalance,
594
+ },
595
+ limit: side == SwapSide.BUY ? MAX_UINT : BN_0,
596
+ },
597
+ ],
598
+ );
599
+ }
600
+
601
+ return {
602
+ targetExchange: router,
603
+ payload: payload,
604
+ networkFee: '0',
605
+ };
606
+ }
607
+
608
+ async getSimpleParam(
609
+ srcToken: string,
610
+ destToken: string,
611
+ srcAmount: string,
612
+ destAmount: string,
613
+ data: SwaapV2Data,
614
+ side: SwapSide,
615
+ ): Promise<SimpleExchangeParam> {
616
+ const { router, callData } = data;
617
+
618
+ assert(
619
+ router !== undefined,
620
+ `${this.dexKey}-${this.network}: router undefined`,
621
+ );
622
+
623
+ assert(
624
+ callData !== undefined,
625
+ `${this.dexKey}-${this.network}: callData undefined`,
626
+ );
627
+
628
+ return this.buildSimpleParamWithoutWETHConversion(
629
+ srcToken,
630
+ srcAmount,
631
+ destToken,
632
+ destAmount,
633
+ callData,
634
+ router,
635
+ );
636
+ }
637
+
638
+ computeMaxLiquidity = (
639
+ levels: SwaapV2PriceLevels,
640
+ tokenAddress: string,
641
+ ): number => {
642
+ if (tokenAddress == levels.base!) {
643
+ return (
644
+ (levels.asks[levels.asks.length - 1]?.level ?? 0) *
645
+ levels.asks[0]?.price
646
+ );
647
+ }
648
+ return (
649
+ (levels.asks[levels.bids.length - 1]?.level ?? 0) * levels.asks[0]?.price
650
+ );
651
+ };
652
+
653
+ async getTopPoolsForToken(
654
+ tokenAddress: Address,
655
+ limit: number,
656
+ ): Promise<PoolLiquidity[]> {
657
+ const normalizedTokenAddress = normalizeTokenAddress(tokenAddress);
658
+
659
+ const pLevels = await this.getCachedLevels();
660
+
661
+ if (pLevels == null) {
662
+ return [];
663
+ }
664
+
665
+ return Object.keys(pLevels)
666
+ .filter((pair: string) => {
667
+ return (
668
+ normalizedTokenAddress == pLevels[pair].base ||
669
+ normalizedTokenAddress == pLevels[pair].quote
670
+ );
671
+ })
672
+ .map((pair: string) => {
673
+ return {
674
+ exchange: this.dexKey,
675
+ address: this.routerAddressPlaceholder,
676
+ connectorTokens: [this.getTokenFromAddress(pLevels[pair].quote!)],
677
+ liquidityUSD: this.computeMaxLiquidity(pLevels[pair], tokenAddress),
678
+ } as PoolLiquidity;
679
+ })
680
+ .sort((pl: PoolLiquidity) => {
681
+ return -pl.liquidityUSD;
682
+ })
683
+ .slice(0, limit);
684
+ }
685
+
686
+ getTokenFromAddress(address: Address): Token {
687
+ return { address, decimals: 0 };
688
+ }
689
+
690
+ releaseResources(): void {
691
+ if (this.rateFetcher) {
692
+ this.rateFetcher.stop();
693
+ }
694
+ }
695
+
696
+ getPriceLevelsReqParams(): SwaapV2APIParameters {
697
+ return this.geAPIReqParams(SWAAP_RFQ_PRICES_ENDPOINT, 'GET');
698
+ }
699
+
700
+ getQuoteReqParams(): SwaapV2APIParameters {
701
+ return this.geAPIReqParams(SWAAP_RFQ_QUOTE_ENDPOINT, 'POST');
702
+ }
703
+
704
+ geAPIReqParams(endpoint: string, method: Method): SwaapV2APIParameters {
705
+ return {
706
+ url: `${SWAAP_RFQ_API_URL}/${endpoint}`,
707
+ params: {
708
+ networkId: this.network,
709
+ },
710
+ headers: { 'x-api-key': this.swaapV2AuthToken },
711
+ method: method,
712
+ };
713
+ }
714
+ }