@paraswap/dex-lib 2.33.4-balancer-v2-multihop.1 → 2.34.0

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 (156) hide show
  1. package/build/abi/algebra/AlgebraPool.abi.json +727 -0
  2. package/build/config.js +27 -0
  3. package/build/config.js.map +1 -1
  4. package/build/dex/algebra/algebra-pool-v1_1.d.ts +16 -2
  5. package/build/dex/algebra/algebra-pool-v1_1.js +166 -4
  6. package/build/dex/algebra/algebra-pool-v1_1.js.map +1 -1
  7. package/build/dex/algebra/algebra-pool.d.ts +46 -0
  8. package/build/dex/algebra/algebra-pool.js +336 -0
  9. package/build/dex/algebra/algebra-pool.js.map +1 -0
  10. package/build/dex/algebra/algebra.js +9 -7
  11. package/build/dex/algebra/algebra.js.map +1 -1
  12. package/build/dex/algebra/config.js +1 -0
  13. package/build/dex/algebra/config.js.map +1 -1
  14. package/build/dex/algebra/types.d.ts +3 -2
  15. package/build/dex/algebra/utils.d.ts +3 -1
  16. package/build/dex/algebra/utils.js +59 -1
  17. package/build/dex/algebra/utils.js.map +1 -1
  18. package/build/dex/balancer-v2/optimizer.d.ts +0 -1
  19. package/build/dex/balancer-v2/optimizer.js +21 -27
  20. package/build/dex/balancer-v2/optimizer.js.map +1 -1
  21. package/build/dex/solidly/forks-override/velodromeV2.js +4 -1
  22. package/build/dex/solidly/forks-override/velodromeV2.js.map +1 -1
  23. package/build/dex/uniswap-v2/nomiswap-v2.js.map +1 -1
  24. package/build/dex/uniswap-v3/uniswap-v3.js +7 -1
  25. package/build/dex/uniswap-v3/uniswap-v3.js.map +1 -1
  26. package/build/lib/decoders.d.ts +3 -0
  27. package/build/lib/decoders.js +9 -1
  28. package/build/lib/decoders.js.map +1 -1
  29. package/build/stateful-event-subscriber.d.ts +1 -0
  30. package/build/stateful-event-subscriber.js +6 -0
  31. package/build/stateful-event-subscriber.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/abi/algebra/AlgebraFactory-v1_1.abi.json +250 -0
  34. package/src/config.ts +30 -0
  35. package/src/dex/algebra/algebra-integration.test.ts +122 -0
  36. package/src/dex/algebra/algebra-pool-v1_1.ts +259 -8
  37. package/src/dex/algebra/algebra.ts +9 -6
  38. package/src/dex/algebra/config.ts +1 -0
  39. package/src/dex/algebra/types.ts +3 -2
  40. package/src/dex/algebra/utils.ts +83 -2
  41. package/src/dex/balancer-v2/optimizer.ts +23 -32
  42. package/src/dex/solidly/forks-override/velodromeV2.ts +4 -2
  43. package/src/dex/uniswap-v2/nomiswap-v2.ts +2 -1
  44. package/src/dex/uniswap-v2/uniswap-v2-e2e-bsc.test.ts +6 -8
  45. package/src/dex/uniswap-v3/uniswap-v3-e2e.test.ts +52 -47
  46. package/src/dex/uniswap-v3/uniswap-v3-integration.test.ts +1 -9
  47. package/src/dex/uniswap-v3/uniswap-v3.ts +7 -1
  48. package/src/lib/decoders.ts +13 -0
  49. package/src/stateful-event-subscriber.ts +8 -0
  50. package/build/abi/api3-proxy.json +0 -46
  51. package/build/abi/api3-server-v1.json +0 -463
  52. package/build/abi/quick-perps/fast-price-events.json +0 -70
  53. package/build/abi/quick-perps/fast-price-feed.json +0 -741
  54. package/build/abi/quick-perps/reader.json +0 -313
  55. package/build/abi/quick-perps/vault-price-feed.json +0 -323
  56. package/build/abi/quick-perps/vault.json +0 -1953
  57. package/build/abi/quickPerps/fast-price-events.json +0 -70
  58. package/build/abi/quickPerps/fast-price-feed.json +0 -748
  59. package/build/abi/quickPerps/reader.json +0 -313
  60. package/build/abi/quickPerps/vault-price-feed.json +0 -477
  61. package/build/abi/quickPerps/vault.json +0 -1953
  62. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3QuoterV2.abi.json +0 -285
  63. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3Router.abi.json +0 -583
  64. package/build/abi/woo-fi/WooFeeManager.abi.json +0 -318
  65. package/build/abi/woo-fi/WooPP.abi.json +0 -548
  66. package/build/abi/woo-fi/Wooracle.abi.json +0 -260
  67. package/build/dex/aave-v3/tokens/arbitrum.json +0 -50
  68. package/build/dex/aave-v3/tokens/avalanche.json +0 -74
  69. package/build/dex/aave-v3/tokens/fantom.json +0 -62
  70. package/build/dex/aave-v3/tokens/optimism.json +0 -50
  71. package/build/dex/aave-v3/tokens/polygon.json +0 -116
  72. package/build/dex/balancer-v2/LinearMath.d.ts +0 -19
  73. package/build/dex/balancer-v2/LinearMath.js +0 -179
  74. package/build/dex/balancer-v2/LinearMath.js.map +0 -1
  75. package/build/dex/balancer-v2/LinearPool.d.ts +0 -47
  76. package/build/dex/balancer-v2/LinearPool.js +0 -324
  77. package/build/dex/balancer-v2/LinearPool.js.map +0 -1
  78. package/build/dex/balancer-v2/PhantomStablePool.d.ts +0 -47
  79. package/build/dex/balancer-v2/PhantomStablePool.js +0 -294
  80. package/build/dex/balancer-v2/PhantomStablePool.js.map +0 -1
  81. package/build/dex/balancer-v2/StableMath.d.ts +0 -9
  82. package/build/dex/balancer-v2/StableMath.js +0 -272
  83. package/build/dex/balancer-v2/StableMath.js.map +0 -1
  84. package/build/dex/balancer-v2/balancer-v2-pool.d.ts +0 -75
  85. package/build/dex/balancer-v2/balancer-v2-pool.js +0 -417
  86. package/build/dex/balancer-v2/balancer-v2-pool.js.map +0 -1
  87. package/build/dex/quick-perps/config.d.ts +0 -11
  88. package/build/dex/quick-perps/config.js +0 -27
  89. package/build/dex/quick-perps/config.js.map +0 -1
  90. package/build/dex/quick-perps/fast-price-feed.d.ts +0 -26
  91. package/build/dex/quick-perps/fast-price-feed.js +0 -176
  92. package/build/dex/quick-perps/fast-price-feed.js.map +0 -1
  93. package/build/dex/quick-perps/pool.d.ts +0 -21
  94. package/build/dex/quick-perps/pool.js +0 -210
  95. package/build/dex/quick-perps/pool.js.map +0 -1
  96. package/build/dex/quick-perps/quick-perps.d.ts +0 -52
  97. package/build/dex/quick-perps/quick-perps.js +0 -205
  98. package/build/dex/quick-perps/quick-perps.js.map +0 -1
  99. package/build/dex/quick-perps/types.d.ts +0 -98
  100. package/build/dex/quick-perps/types.js +0 -3
  101. package/build/dex/quick-perps/types.js.map +0 -1
  102. package/build/dex/quick-perps/usdq.d.ts +0 -15
  103. package/build/dex/quick-perps/usdq.js +0 -61
  104. package/build/dex/quick-perps/usdq.js.map +0 -1
  105. package/build/dex/quick-perps/vault-price-feed.d.ts +0 -43
  106. package/build/dex/quick-perps/vault-price-feed.js +0 -194
  107. package/build/dex/quick-perps/vault-price-feed.js.map +0 -1
  108. package/build/dex/quick-perps/vault-utils.d.ts +0 -8
  109. package/build/dex/quick-perps/vault-utils.js +0 -41
  110. package/build/dex/quick-perps/vault-utils.js.map +0 -1
  111. package/build/dex/quick-perps/vault.d.ts +0 -46
  112. package/build/dex/quick-perps/vault.js +0 -166
  113. package/build/dex/quick-perps/vault.js.map +0 -1
  114. package/build/dex/quickswap-v3.d.ts +0 -21
  115. package/build/dex/quickswap-v3.js +0 -40
  116. package/build/dex/quickswap-v3.js.map +0 -1
  117. package/build/dex/test-dex/config.d.ts +0 -4
  118. package/build/dex/test-dex/config.js +0 -15
  119. package/build/dex/test-dex/config.js.map +0 -1
  120. package/build/dex/test-dex/test-dex-pool.d.ts +0 -39
  121. package/build/dex/test-dex/test-dex-pool.js +0 -63
  122. package/build/dex/test-dex/test-dex-pool.js.map +0 -1
  123. package/build/dex/test-dex/test-dex.d.ts +0 -37
  124. package/build/dex/test-dex/test-dex.js +0 -126
  125. package/build/dex/test-dex/test-dex.js.map +0 -1
  126. package/build/dex/test-dex/types.d.ts +0 -6
  127. package/build/dex/test-dex/types.js +0 -3
  128. package/build/dex/test-dex/types.js.map +0 -1
  129. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.d.ts +0 -12
  130. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js +0 -23
  131. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js.map +0 -1
  132. package/build/dex/woo-fi/config.d.ts +0 -4
  133. package/build/dex/woo-fi/config.js +0 -141
  134. package/build/dex/woo-fi/config.js.map +0 -1
  135. package/build/dex/woo-fi/constants.d.ts +0 -5
  136. package/build/dex/woo-fi/constants.js +0 -20
  137. package/build/dex/woo-fi/constants.js.map +0 -1
  138. package/build/dex/woo-fi/types.d.ts +0 -48
  139. package/build/dex/woo-fi/types.js +0 -3
  140. package/build/dex/woo-fi/types.js.map +0 -1
  141. package/build/dex/woo-fi/woo-fi-decimal-math.d.ts +0 -14
  142. package/build/dex/woo-fi/woo-fi-decimal-math.js +0 -42
  143. package/build/dex/woo-fi/woo-fi-decimal-math.js.map +0 -1
  144. package/build/dex/woo-fi/woo-fi-math.d.ts +0 -31
  145. package/build/dex/woo-fi/woo-fi-math.js +0 -300
  146. package/build/dex/woo-fi/woo-fi-math.js.map +0 -1
  147. package/build/dex/woo-fi/woo-fi.d.ts +0 -65
  148. package/build/dex/woo-fi/woo-fi.js +0 -480
  149. package/build/dex/woo-fi/woo-fi.js.map +0 -1
  150. package/build/dex/woo-fi-v2/woo-fi-math.d.ts +0 -16
  151. package/build/dex/woo-fi-v2/woo-fi-math.js +0 -137
  152. package/build/dex/woo-fi-v2/woo-fi-math.js.map +0 -1
  153. package/build/lib/api3-feed.d.ts +0 -26
  154. package/build/lib/api3-feed.js +0 -82
  155. package/build/lib/api3-feed.js.map +0 -1
  156. package/src/dex/balancer-v2/balancer-v2-optimizer.test.ts +0 -226
@@ -9,31 +9,47 @@ import {
9
9
  } from '../../stateful-event-subscriber';
10
10
  import { IDexHelper } from '../../dex-helper/idex-helper';
11
11
  import {
12
+ DecodedGlobalStateV1_1,
12
13
  PoolStateV1_1,
13
14
  TickBitMapMappingsWithBigNumber,
14
15
  TickInfoMappingsWithBigNumber,
16
+ TickInfoWithBigNumber,
15
17
  } from './types';
16
- import { ethers } from 'ethers';
18
+ import { BigNumber, ethers } from 'ethers';
17
19
  import { Contract } from 'web3-eth-contract';
18
20
  import AlgebraABI from '../../abi/algebra/AlgebraPool-v1_1.abi.json';
21
+ import FactoryABI from '../../abi/algebra/AlgebraFactory-v1_1.abi.json';
19
22
  import { DecodedStateMultiCallResultWithRelativeBitmapsV1_1 } from './types';
20
23
  import {
21
24
  OUT_OF_RANGE_ERROR_POSTFIX,
22
25
  TICK_BITMAP_BUFFER,
23
26
  TICK_BITMAP_TO_USE,
24
27
  } from '../uniswap-v3/constants';
25
- import { uint256ToBigInt } from '../../lib/decoders';
28
+ import {
29
+ addressDecode,
30
+ uint256ToBigInt,
31
+ uint128ToBigNumber,
32
+ int24ToNumber,
33
+ } from '../../lib/decoders';
26
34
  import { MultiCallParams } from '../../lib/multi-wrapper';
27
- import { decodeStateMultiCallResultWithRelativeBitmapsV1_1 } from './utils';
35
+ import {
36
+ decodeGlobalStateV1_1,
37
+ decodeStateMultiCallResultWithRelativeBitmapsV1_1,
38
+ decodeTicksV1_1,
39
+ } from './utils';
28
40
  import { AlgebraMath } from './lib/AlgebraMath';
29
41
  import {
30
42
  _reduceTickBitmap,
31
43
  _reduceTicks,
32
44
  } from '../uniswap-v3/contract-math/utils';
33
45
  import { Constants } from './lib/Constants';
34
- import { Network } from '../../constants';
46
+ import { Network, NULL_ADDRESS } from '../../constants';
35
47
  import { TickTable } from './lib/TickTable';
36
48
 
49
+ const BN_ZERO = BigNumber.from(0);
50
+ const MAX_BATCH_SIZE = 100;
51
+ const MAX_NUMBER_OF_BATCH_REQUEST_HALVING = 3;
52
+
37
53
  export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1> {
38
54
  handlers: {
39
55
  [event: string]: (
@@ -53,6 +69,13 @@ export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1>
53
69
  readonly token1: Address;
54
70
 
55
71
  public readonly poolIface = new Interface(AlgebraABI);
72
+ public readonly factoryIface = new Interface(FactoryABI);
73
+
74
+ private readonly cachedStateMultiCalls: MultiCallParams<
75
+ string | bigint | BigNumber | number | DecodedGlobalStateV1_1
76
+ >[];
77
+
78
+ private optimalTickRequestBatchSize?: number;
56
79
 
57
80
  public initFailed = false;
58
81
  public initRetryAttemptCount = 0;
@@ -69,6 +92,7 @@ export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1>
69
92
  mapKey: string = '',
70
93
  readonly poolInitCodeHash: string,
71
94
  readonly poolDeployer: string,
95
+ private readonly forceManualStateGeneration: boolean = false,
72
96
  ) {
73
97
  super(parentName, `${token0}_${token1}`, dexHelper, logger, true, mapKey);
74
98
  this.token0 = token0.toLowerCase();
@@ -84,6 +108,8 @@ export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1>
84
108
  this.handlers['Flash'] = this.handleFlashEvent.bind(this);
85
109
  this.handlers['Collect'] = this.handleCollectEvent.bind(this);
86
110
  this.handlers['CommunityFee'] = this.handleCommunityFee.bind(this);
111
+
112
+ this.cachedStateMultiCalls = this._getStateMulticall();
87
113
  }
88
114
 
89
115
  get poolAddress() {
@@ -174,7 +200,7 @@ export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1>
174
200
  return TICK_BITMAP_TO_USE + TICK_BITMAP_BUFFER;
175
201
  }
176
202
 
177
- private async _fetchPoolStateSingleStep(
203
+ async fetchPoolStateSingleStep(
178
204
  blockNumber: number,
179
205
  ): Promise<
180
206
  [bigint, bigint, DecodedStateMultiCallResultWithRelativeBitmapsV1_1]
@@ -336,7 +362,7 @@ export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1>
336
362
  [bigint, bigint, DecodedStateMultiCallResultWithRelativeBitmapsV1_1]
337
363
  > {
338
364
  try {
339
- return await this._fetchPoolStateSingleStep(blockNumber);
365
+ return await this.fetchPoolStateSingleStep(blockNumber);
340
366
  } catch (e) {
341
367
  if (e instanceof Error && e.message.includes('Pool does not exist'))
342
368
  throw e;
@@ -347,9 +373,234 @@ export class AlgebraEventPoolV1_1 extends StatefulEventSubscriber<PoolStateV1_1>
347
373
  }
348
374
  }
349
375
 
376
+ private _getStateMulticall(): MultiCallParams<
377
+ string | bigint | BigNumber | number | DecodedGlobalStateV1_1
378
+ >[] {
379
+ return [
380
+ {
381
+ target: this.factoryAddress,
382
+ callData: this.factoryIface.encodeFunctionData('poolByPair', [
383
+ this.token0,
384
+ this.token1,
385
+ ]),
386
+ decodeFunction: addressDecode,
387
+ },
388
+ {
389
+ target: this.token0,
390
+ callData: this.erc20Interface.encodeFunctionData('balanceOf', [
391
+ this.poolAddress,
392
+ ]),
393
+ decodeFunction: uint256ToBigInt,
394
+ },
395
+ {
396
+ target: this.token1,
397
+ callData: this.erc20Interface.encodeFunctionData('balanceOf', [
398
+ this.poolAddress,
399
+ ]),
400
+ decodeFunction: uint256ToBigInt,
401
+ },
402
+ {
403
+ target: this.poolAddress,
404
+ callData: this.poolIface.encodeFunctionData('liquidity', []),
405
+ decodeFunction: uint128ToBigNumber,
406
+ },
407
+ {
408
+ target: this.poolAddress,
409
+ callData: this.poolIface.encodeFunctionData('tickSpacing', []),
410
+ decodeFunction: int24ToNumber,
411
+ },
412
+ {
413
+ target: this.poolAddress,
414
+ callData: this.poolIface.encodeFunctionData('maxLiquidityPerTick', []),
415
+ decodeFunction: uint128ToBigNumber,
416
+ },
417
+ {
418
+ target: this.poolAddress,
419
+ callData: this.poolIface.encodeFunctionData('globalState', []),
420
+ decodeFunction: decodeGlobalStateV1_1,
421
+ },
422
+ ];
423
+ }
424
+
425
+ async fetchStateManually(
426
+ blockNumber: number,
427
+ ): Promise<
428
+ [bigint, bigint, DecodedStateMultiCallResultWithRelativeBitmapsV1_1]
429
+ > {
430
+ // Unfortunately I can not unite this call with the next one. For some reason even if pool does not exist
431
+ // call succeeds and makes decoding function to throw. Otherwise, I should rewrite decoders in different which
432
+ // require some time
433
+ const [poolAddress] = (await this.dexHelper.multiWrapper.aggregate<
434
+ string | bigint | BigNumber | number | DecodedGlobalStateV1_1
435
+ >(this.cachedStateMultiCalls.slice(0, 1), blockNumber, MAX_BATCH_SIZE)) as [
436
+ string,
437
+ ];
438
+
439
+ if (poolAddress === NULL_ADDRESS) {
440
+ throw new Error('Pool does not exist');
441
+ }
442
+
443
+ const [
444
+ balance0,
445
+ balance1,
446
+ liquidity,
447
+ tickSpacing,
448
+ maxLiquidityPerTick,
449
+ globalState,
450
+ ] = (await this.dexHelper.multiWrapper.aggregate<
451
+ string | bigint | BigNumber | number | DecodedGlobalStateV1_1
452
+ >(this.cachedStateMultiCalls.slice(1), blockNumber, MAX_BATCH_SIZE)) as [
453
+ bigint,
454
+ bigint,
455
+ BigNumber,
456
+ number,
457
+ BigNumber,
458
+ DecodedGlobalStateV1_1,
459
+ ];
460
+
461
+ assert(
462
+ poolAddress.toLowerCase() === this.poolAddress.toLowerCase(),
463
+ `Pool address mismatch: ${poolAddress.toLowerCase()} != ${this.poolAddress.toLowerCase()}`,
464
+ );
465
+
466
+ const currentBitMapIndex = TickTable.position(
467
+ BigInt(BigInt(globalState.tick) / BigInt(tickSpacing)),
468
+ )[0];
469
+
470
+ const leftBitMapIndex = currentBitMapIndex - this.getBitmapRangeToRequest();
471
+ const rightBitMapIndex =
472
+ currentBitMapIndex + this.getBitmapRangeToRequest();
473
+
474
+ const allTickBitMaps = await this.dexHelper.multiWrapper.aggregate(
475
+ _.range(Number(leftBitMapIndex), Number(rightBitMapIndex + 1n)).map(
476
+ index => {
477
+ return {
478
+ target: poolAddress,
479
+ callData: this.poolIface.encodeFunctionData('tickTable', [
480
+ int16(BigInt(index)),
481
+ ]),
482
+ decodeFunction: uint256ToBigInt,
483
+ };
484
+ },
485
+ ),
486
+ blockNumber,
487
+ MAX_BATCH_SIZE,
488
+ );
489
+
490
+ const tickBitmap: TickBitMapMappingsWithBigNumber[] = [];
491
+
492
+ let globalIndex = 0;
493
+ for (let i = leftBitMapIndex; i <= rightBitMapIndex; i++) {
494
+ const index = Number(int16(i));
495
+ const bitmap = allTickBitMaps[globalIndex];
496
+ globalIndex++;
497
+ if (bitmap == 0n) continue;
498
+ tickBitmap.push({ index: Number(index), value: BigNumber.from(bitmap) });
499
+ }
500
+
501
+ const tickIndexes: bigint[] = [];
502
+
503
+ const tickRequests = tickBitmap
504
+ .map(tb => {
505
+ const allBits: MultiCallParams<TickInfoWithBigNumber>[] = [];
506
+ if (tb.value === BN_ZERO) return allBits;
507
+
508
+ _.range(0, 256).forEach(j => {
509
+ if ((tb.value.toBigInt() & (1n << BigInt(j))) > 0n) {
510
+ const populatedTick =
511
+ (BigInt.asIntN(16, BigInt(tb.index) << 8n) + BigInt(j)) *
512
+ BigInt(tickSpacing);
513
+
514
+ tickIndexes.push(populatedTick);
515
+ allBits.push({
516
+ target: poolAddress,
517
+ callData: this.poolIface.encodeFunctionData('ticks', [
518
+ populatedTick,
519
+ ]),
520
+ decodeFunction: decodeTicksV1_1,
521
+ });
522
+ }
523
+ });
524
+ return allBits;
525
+ })
526
+ .flat();
527
+
528
+ let ticksValues: TickInfoWithBigNumber[] = [];
529
+ if (this.optimalTickRequestBatchSize) {
530
+ ticksValues = await this.dexHelper.multiWrapper.aggregate(
531
+ tickRequests,
532
+ blockNumber,
533
+ this.optimalTickRequestBatchSize,
534
+ );
535
+ // If we don't know what is optimal number of requests for this pool, we want to try it experimentally and save it
536
+ // Maybe later to consider distant caching
537
+ } else {
538
+ for (const i of _.range(0, MAX_NUMBER_OF_BATCH_REQUEST_HALVING)) {
539
+ const currentBatchSize = MAX_BATCH_SIZE / (+i + 1);
540
+ try {
541
+ // Some of the pools fails with 100 batch size, for them we want to try additionally with reduced batch size
542
+ ticksValues = await this.dexHelper.multiWrapper.aggregate(
543
+ tickRequests,
544
+ blockNumber,
545
+ currentBatchSize,
546
+ );
547
+ this.optimalTickRequestBatchSize = currentBatchSize;
548
+ break;
549
+ } catch (e) {
550
+ if (+i + 1 === MAX_NUMBER_OF_BATCH_REQUEST_HALVING) {
551
+ this.logger.warn(
552
+ `Failed to fetch ticks for pool ${poolAddress} (${this.token0}_${this.token1}) with batch size ${currentBatchSize}`,
553
+ e,
554
+ );
555
+ throw e;
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ assert(
562
+ tickIndexes.length === ticksValues.length,
563
+ `Tick indexes mismatch: ${tickIndexes.length} != ${ticksValues.length}`,
564
+ );
565
+
566
+ const ticks: TickInfoMappingsWithBigNumber[] = new Array(
567
+ tickIndexes.length,
568
+ );
569
+
570
+ tickIndexes.forEach((tickIndex, index) => {
571
+ ticks[index] = {
572
+ index: Number(tickIndex),
573
+ value: ticksValues[index],
574
+ };
575
+ });
576
+
577
+ return [
578
+ balance0,
579
+ balance1,
580
+ {
581
+ pool: poolAddress,
582
+ blockTimestamp: BigNumber.from(Date.now()),
583
+ globalState,
584
+ liquidity,
585
+ tickSpacing,
586
+ maxLiquidityPerTick,
587
+ tickBitmap,
588
+ ticks,
589
+ },
590
+ ];
591
+ }
592
+
350
593
  async generateState(blockNumber: number): Promise<Readonly<PoolStateV1_1>> {
351
- const [balance0, balance1, _state] =
352
- await this._fetchInitStateMultiStrategies(blockNumber);
594
+ let balance0 = 0n;
595
+ let balance1 = 0n;
596
+ let _state: DecodedStateMultiCallResultWithRelativeBitmapsV1_1;
597
+ if (this.forceManualStateGeneration) {
598
+ [balance0, balance1, _state] = await this.fetchStateManually(blockNumber);
599
+ } else {
600
+ [balance0, balance1, _state] = await this._fetchInitStateMultiStrategies(
601
+ blockNumber,
602
+ );
603
+ }
353
604
 
354
605
  const tickBitmap = {};
355
606
  const ticks = {};
@@ -160,14 +160,15 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
160
160
  if (this.network !== Network.ZKEVM) return pool;
161
161
 
162
162
  if (
163
- pool.getState(blockNumber) === null &&
164
- blockNumber - pool.getStateBlockNumber() >
165
- MAX_STALE_STATE_BLOCK_AGE[this.network]
163
+ pool.getStaleState() === null ||
164
+ (pool.getState(blockNumber) === null &&
165
+ blockNumber - pool.getStateBlockNumber() >
166
+ MAX_STALE_STATE_BLOCK_AGE[this.network])
166
167
  ) {
167
168
  /* reload state, on zkEVM this would most likely timeout during request life
168
169
  * but would allow to rely on staleState for couple of min for next requests
169
170
  */
170
- await pool.initialize(blockNumber);
171
+ await pool.initialize(blockNumber, { forceRegenerate: true });
171
172
  }
172
173
 
173
174
  return pool;
@@ -226,6 +227,7 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
226
227
  this.cacheStateKey,
227
228
  this.config.initHash,
228
229
  this.config.deployer,
230
+ this.config.forceManualStateGenerate,
229
231
  );
230
232
 
231
233
  try {
@@ -255,10 +257,10 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
255
257
  e,
256
258
  );
257
259
  } else {
258
- // on unkown error mark as failed and increase retryCount for retry init strategy
260
+ // on unknown error mark as failed and increase retryCount for retry init strategy
259
261
  // note: state would be null by default which allows to fallback
260
262
  this.logger.warn(
261
- `${this.dexKey}: Can not generate pool state for srcAddress=${srcAddress}, destAddress=${destAddress}pool fallback to rpc and retry every ${this.config.initRetryFrequency} times, initRetryAttemptCount=${pool.initRetryAttemptCount}`,
263
+ `${this.dexKey}: Can not generate pool state for srcAddress=${srcAddress}, destAddress=${destAddress} pool fallback to rpc and retry every ${this.config.initRetryFrequency} times, initRetryAttemptCount=${pool.initRetryAttemptCount}`,
262
264
  e,
263
265
  );
264
266
  pool.initFailed = true;
@@ -790,6 +792,7 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
790
792
  subgraphURL: this.config.subgraphURL,
791
793
  version: this.config.version,
792
794
  forceRPC: this.config.forceRPC,
795
+ forceManualStateGenerate: this.config.forceManualStateGenerate,
793
796
  };
794
797
  return newConfig;
795
798
  }
@@ -33,6 +33,7 @@ export const AlgebraConfig: DexConfigMap<DexParams> = {
33
33
  uniswapMulticall: '0x61530d6E1c7A47BBB3e48e8b8EdF7569DcFeE121',
34
34
  deployer: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270',
35
35
  version: 'v1.1',
36
+ forceManualStateGenerate: true,
36
37
  },
37
38
  },
38
39
  ZyberSwapV3: {
@@ -2,7 +2,7 @@ import { BigNumber } from 'ethers';
2
2
  import { Address, NumberAsString } from '../../types';
3
3
  import { TickInfo } from '../uniswap-v3/types';
4
4
 
5
- type GlobalStateV1_1 = {
5
+ export type GlobalStateV1_1 = {
6
6
  price: bigint; // The square root of the current price in Q64.96 format
7
7
  tick: bigint; // The current tick
8
8
  fee: bigint; // The current fee in hundredths of a bip, i.e. 1e-6
@@ -72,6 +72,7 @@ export type DexParams = {
72
72
  initHash: string;
73
73
  version: 'v1.1' | 'v1.9';
74
74
  forceRPC?: boolean;
75
+ forceManualStateGenerate?: boolean;
75
76
  };
76
77
 
77
78
  export type IAlgebraPoolState = PoolStateV1_1 | PoolState_v1_9;
@@ -95,7 +96,7 @@ export type TickInfoMappingsWithBigNumber = {
95
96
  value: TickInfoWithBigNumber;
96
97
  };
97
98
 
98
- type DecodedGlobalStateV1_1 = {
99
+ export type DecodedGlobalStateV1_1 = {
99
100
  price: BigNumber;
100
101
  tick: number;
101
102
  fee: number;
@@ -1,11 +1,12 @@
1
- import { BytesLike, ethers } from 'ethers';
1
+ import { BigNumber, BytesLike, ethers } from 'ethers';
2
2
  import { assert } from 'ts-essentials';
3
3
  import { extractSuccessAndValue } from '../../lib/decoders';
4
4
  import { MultiResult } from '../../lib/multi-wrapper';
5
5
  import {
6
- DecodedGlobalStateV1_9,
6
+ DecodedGlobalStateV1_1,
7
7
  DecodedStateMultiCallResultWithRelativeBitmapsV1_1,
8
8
  DecodedStateMultiCallResultWithRelativeBitmapsV1_9,
9
+ TickInfoWithBigNumber,
9
10
  } from './types';
10
11
 
11
12
  export function decodeStateMultiCallResultWithRelativeBitmapsV1_1(
@@ -134,3 +135,83 @@ export function decodeStateMultiCallResultWithRelativeBitmapsV1_9(
134
135
  // But I typed only the ones that are used later
135
136
  return decoded as DecodedStateMultiCallResultWithRelativeBitmapsV1_9;
136
137
  }
138
+
139
+ export function decodeGlobalStateV1_1(
140
+ result: MultiResult<BytesLike> | BytesLike,
141
+ ): DecodedGlobalStateV1_1 {
142
+ const [isSuccess, toDecode] = extractSuccessAndValue(result);
143
+
144
+ assert(
145
+ isSuccess && toDecode !== '0x',
146
+ `decodeGlobalStateV1_1 failed to get decodable result: ${result}`,
147
+ );
148
+
149
+ const results: DecodedGlobalStateV1_1 = {
150
+ price: BigNumber.from(0),
151
+ tick: 0,
152
+ fee: 0,
153
+ communityFeeToken0: 0,
154
+ communityFeeToken1: 0,
155
+ };
156
+
157
+ [
158
+ results.price,
159
+ results.tick,
160
+ results.fee,
161
+ ,
162
+ results.communityFeeToken0,
163
+ results.communityFeeToken1,
164
+ ] = ethers.utils.defaultAbiCoder.decode(
165
+ [`uint160`, `int24`, `uint16`, `uint16`, `uint8`, `uint8`, `bool`],
166
+ toDecode,
167
+ );
168
+ // This conversion is not precise, because when we decode, we have more values
169
+ // But used later
170
+ return results;
171
+ }
172
+
173
+ export function decodeTicksV1_1(
174
+ result: MultiResult<BytesLike> | BytesLike,
175
+ ): TickInfoWithBigNumber {
176
+ const [isSuccess, toDecode] = extractSuccessAndValue(result);
177
+
178
+ assert(
179
+ isSuccess && toDecode !== '0x',
180
+ `decodeGlobalStateV1_1 failed to get decodable result: ${result}`,
181
+ );
182
+
183
+ const results: TickInfoWithBigNumber = {
184
+ liquidityNet: BigNumber.from(0),
185
+ liquidityGross: BigNumber.from(0),
186
+ secondsOutside: 0,
187
+ secondsPerLiquidityOutsideX128: BigNumber.from(0),
188
+ tickCumulativeOutside: BigNumber.from(0),
189
+ initialized: false,
190
+ };
191
+
192
+ [
193
+ results.liquidityGross,
194
+ results.liquidityNet,
195
+ ,
196
+ ,
197
+ results.tickCumulativeOutside,
198
+ results.secondsPerLiquidityOutsideX128,
199
+ results.secondsOutside,
200
+ results.initialized,
201
+ ] = ethers.utils.defaultAbiCoder.decode(
202
+ [
203
+ `uint128`,
204
+ `int128`,
205
+ `uint256`,
206
+ `uint256`,
207
+ `int256`,
208
+ `uint160`,
209
+ `uint32`,
210
+ `bool`,
211
+ ],
212
+ toDecode,
213
+ );
214
+ // This conversion is not precise, because when we decode, we have more values
215
+ // But used later
216
+ return results;
217
+ }
@@ -3,20 +3,22 @@ import { BalancerSwapV2 } from './types';
3
3
  import { SwapSide } from '../../constants';
4
4
  import { BalancerConfig } from './config';
5
5
 
6
- export const AllBalancerV2Forks = Object.keys(BalancerConfig);
6
+ const MAX_UINT256 =
7
+ '115792089237316195423570985008687907853269984665640564039457584007913129639935';
8
+
9
+ const AllBalancerV2Forks = Object.keys(BalancerConfig);
7
10
 
8
11
  export function balancerV2Merge(or: UnoptimizedRate): UnoptimizedRate {
9
12
  const fixSwap = (
10
13
  rawSwap: OptimalSwapExchange<any>[],
11
- accumulatedBalancers: { [key: string]: OptimalSwapExchange<any> },
12
14
  side: SwapSide,
13
15
  ): OptimalSwapExchange<any>[] => {
14
- let optimizedSwap = new Array<OptimalSwapExchange<any>>();
15
16
  const newBalancers: { [key: string]: OptimalSwapExchange<any> } = {};
17
+ let optimizedSwap = new Array<OptimalSwapExchange<any>>();
16
18
  rawSwap.forEach((s: OptimalSwapExchange<any>) => {
17
19
  const exchangeKey = s.exchange.toLowerCase();
18
20
  if (AllBalancerV2Forks.some(d => d.toLowerCase() === exchangeKey)) {
19
- if (!(exchangeKey in accumulatedBalancers)) {
21
+ if (!(exchangeKey in newBalancers)) {
20
22
  newBalancers[exchangeKey] = {
21
23
  exchange: s.exchange,
22
24
  srcAmount: '0',
@@ -28,33 +30,27 @@ export function balancerV2Merge(or: UnoptimizedRate): UnoptimizedRate {
28
30
  gasUSD: '0',
29
31
  },
30
32
  };
31
- accumulatedBalancers[exchangeKey] = newBalancers[exchangeKey];
32
33
  }
33
- accumulatedBalancers[exchangeKey].srcAmount = (
34
- BigInt(accumulatedBalancers[exchangeKey].srcAmount) +
35
- BigInt(s.srcAmount)
34
+ newBalancers[exchangeKey].srcAmount = (
35
+ BigInt(newBalancers[exchangeKey].srcAmount) + BigInt(s.srcAmount)
36
36
  ).toString();
37
37
 
38
- accumulatedBalancers[exchangeKey].destAmount = (
39
- BigInt(accumulatedBalancers[exchangeKey].destAmount) +
40
- BigInt(s.destAmount)
38
+ newBalancers[exchangeKey].destAmount = (
39
+ BigInt(newBalancers[exchangeKey].destAmount) + BigInt(s.destAmount)
41
40
  ).toString();
42
41
 
43
- accumulatedBalancers[exchangeKey].percent += s.percent;
44
- accumulatedBalancers[exchangeKey].data.exchangeProxy =
45
- s.data.exchangeProxy;
46
- accumulatedBalancers[exchangeKey].data.gasUSD = (
47
- parseFloat(accumulatedBalancers[exchangeKey].data.gasUSD) +
42
+ newBalancers[exchangeKey].percent += s.percent;
43
+ newBalancers[exchangeKey].data.exchangeProxy = s.data.exchangeProxy;
44
+ newBalancers[exchangeKey].data.gasUSD = (
45
+ parseFloat(newBalancers[exchangeKey].data.gasUSD) +
48
46
  parseFloat(s.data.gasUSD)
49
47
  ).toFixed(6);
50
48
 
51
- accumulatedBalancers[exchangeKey].data.swaps.push({
49
+ newBalancers[exchangeKey].data.swaps.push({
52
50
  poolId: s.data.poolId,
53
51
  amount: side === SwapSide.SELL ? s.srcAmount : s.destAmount,
54
52
  });
55
- accumulatedBalancers[exchangeKey].poolAddresses!.push(
56
- s.poolAddresses![0],
57
- );
53
+ newBalancers[exchangeKey].poolAddresses!.push(s.poolAddresses![0]);
58
54
  } else {
59
55
  optimizedSwap.push(s);
60
56
  }
@@ -63,17 +59,12 @@ export function balancerV2Merge(or: UnoptimizedRate): UnoptimizedRate {
63
59
  return optimizedSwap;
64
60
  };
65
61
 
66
- or.bestRoute = or.bestRoute.map(r => {
67
- const accumulatedBalancers: {
68
- [key: string]: OptimalSwapExchange<any>;
69
- } = {};
70
- return {
71
- ...r,
72
- swaps: r.swaps.map(s => ({
73
- ...s,
74
- swapExchanges: fixSwap(s.swapExchanges, accumulatedBalancers, or.side),
75
- })),
76
- };
77
- });
62
+ or.bestRoute = or.bestRoute.map(r => ({
63
+ ...r,
64
+ swaps: r.swaps.map(s => ({
65
+ ...s,
66
+ swapExchanges: fixSwap(s.swapExchanges, or.side),
67
+ })),
68
+ }));
78
69
  return or;
79
70
  }
@@ -24,7 +24,6 @@ const VelodromeV2FactoryABI = [
24
24
  const velodromeV2FactoryIface = new Interface(VelodromeV2FactoryABI);
25
25
 
26
26
  export class VelodromeV2 extends Solidly {
27
-
28
27
  public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
29
28
  getDexKeysWithNetwork(_.pick(SolidlyConfig, ['VelodromeV2']));
30
29
 
@@ -44,7 +43,10 @@ export class VelodromeV2 extends Solidly {
44
43
  protected getFeesMultiCallData(pair: SolidlyPair) {
45
44
  const callEntry = {
46
45
  target: this.factoryAddress,
47
- callData: velodromeV2FactoryIface.encodeFunctionData('getFee', [pair.exchange, pair.stable]),
46
+ callData: velodromeV2FactoryIface.encodeFunctionData('getFee', [
47
+ pair.exchange,
48
+ pair.stable,
49
+ ]),
48
50
  };
49
51
  const callDecoder = (values: any[]) =>
50
52
  parseInt(
@@ -15,7 +15,8 @@ export const NomiswapV2Config: DexConfigMap<DexParams> = {
15
15
  '0x83eb759f5ea0525124f03d4ac741bb4af0bb1c703d5f694bd42a8bd72e495a01',
16
16
  poolGasCost: 120 * 1000,
17
17
  feeCode: 0, // this is ignored as Nomiswap uses dynamic fees,
18
- subgraphURL: 'https://api.thegraph.com/subgraphs/name/nominex/nomiswap-exchange-subgraph',
18
+ subgraphURL:
19
+ 'https://api.thegraph.com/subgraphs/name/nominex/nomiswap-exchange-subgraph',
19
20
  },
20
21
  },
21
22
  };
@@ -2,7 +2,11 @@ import dotenv from 'dotenv';
2
2
  dotenv.config();
3
3
 
4
4
  import { testE2E } from '../../../tests/utils-e2e';
5
- import { Tokens, Holders, NativeTokenSymbols } from '../../../tests/constants-e2e';
5
+ import {
6
+ Tokens,
7
+ Holders,
8
+ NativeTokenSymbols,
9
+ } from '../../../tests/constants-e2e';
6
10
  import { Network, ContractMethod, SwapSide } from '../../constants';
7
11
  import { StaticJsonRpcProvider } from '@ethersproject/providers';
8
12
  import { generateConfig } from '../../config';
@@ -34,13 +38,7 @@ function testForNetwork(
34
38
  ContractMethod.megaSwap,
35
39
  ],
36
40
  ],
37
- [
38
- SwapSide.BUY,
39
- [
40
- ContractMethod.simpleBuy,
41
- ContractMethod.buy,
42
- ],
43
- ],
41
+ [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]],
44
42
  ]);
45
43
 
46
44
  describe(`${network}`, () => {