@paraswap/dex-lib 2.33.4-balancer-v2-multihop.2 → 2.35.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 (148) hide show
  1. package/build/abi/algebra/AlgebraPool.abi.json +727 -0
  2. package/build/composed-event-subscriber.js +8 -2
  3. package/build/composed-event-subscriber.js.map +1 -1
  4. package/build/config.js +27 -0
  5. package/build/config.js.map +1 -1
  6. package/build/dex/algebra/algebra-pool-v1_1.d.ts +16 -2
  7. package/build/dex/algebra/algebra-pool-v1_1.js +166 -4
  8. package/build/dex/algebra/algebra-pool-v1_1.js.map +1 -1
  9. package/build/dex/algebra/algebra-pool.d.ts +46 -0
  10. package/build/dex/algebra/algebra-pool.js +336 -0
  11. package/build/dex/algebra/algebra-pool.js.map +1 -0
  12. package/build/dex/algebra/algebra.js +9 -7
  13. package/build/dex/algebra/algebra.js.map +1 -1
  14. package/build/dex/algebra/config.js +1 -0
  15. package/build/dex/algebra/config.js.map +1 -1
  16. package/build/dex/algebra/types.d.ts +3 -2
  17. package/build/dex/algebra/utils.d.ts +3 -1
  18. package/build/dex/algebra/utils.js +59 -1
  19. package/build/dex/algebra/utils.js.map +1 -1
  20. package/build/dex/balancer-v2/optimizer.d.ts +0 -1
  21. package/build/dex/balancer-v2/optimizer.js +21 -29
  22. package/build/dex/balancer-v2/optimizer.js.map +1 -1
  23. package/build/dex/index.js +2 -0
  24. package/build/dex/index.js.map +1 -1
  25. package/build/dex/solidly/forks-override/velodromeV2.js +4 -1
  26. package/build/dex/solidly/forks-override/velodromeV2.js.map +1 -1
  27. package/build/dex/uniswap-v2/nomiswap-v2.js.map +1 -1
  28. package/build/dex/uniswap-v3/uniswap-v3.js +7 -1
  29. package/build/dex/uniswap-v3/uniswap-v3.js.map +1 -1
  30. package/build/lib/decoders.d.ts +3 -0
  31. package/build/lib/decoders.js +9 -1
  32. package/build/lib/decoders.js.map +1 -1
  33. package/build/stateful-event-subscriber.d.ts +1 -0
  34. package/build/stateful-event-subscriber.js +6 -0
  35. package/build/stateful-event-subscriber.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/abi/algebra/AlgebraFactory-v1_1.abi.json +250 -0
  38. package/src/abi/api3-proxy.json +46 -0
  39. package/src/abi/api3-server-v1.json +463 -0
  40. package/src/abi/quick-perps/fast-price-events.json +70 -0
  41. package/src/abi/quick-perps/fast-price-feed.json +741 -0
  42. package/src/abi/quick-perps/reader.json +313 -0
  43. package/src/abi/quick-perps/vault-price-feed.json +323 -0
  44. package/src/abi/quick-perps/vault.json +1953 -0
  45. package/src/composed-event-subscriber.ts +16 -11
  46. package/src/config.ts +30 -0
  47. package/src/dex/algebra/algebra-integration.test.ts +122 -0
  48. package/src/dex/algebra/algebra-pool-v1_1.ts +259 -8
  49. package/src/dex/algebra/algebra.ts +9 -6
  50. package/src/dex/algebra/config.ts +1 -0
  51. package/src/dex/algebra/types.ts +3 -2
  52. package/src/dex/algebra/utils.ts +83 -2
  53. package/src/dex/balancer-v2/optimizer.ts +23 -38
  54. package/src/dex/index.ts +2 -0
  55. package/src/dex/quick-perps/config.ts +31 -0
  56. package/src/dex/quick-perps/fast-price-feed.ts +279 -0
  57. package/src/dex/quick-perps/pool.ts +372 -0
  58. package/src/dex/quick-perps/quick-perps-e2e.test.ts +65 -0
  59. package/src/dex/quick-perps/quick-perps-events.test.ts +101 -0
  60. package/src/dex/quick-perps/quick-perps-integration.test.ts +153 -0
  61. package/src/dex/quick-perps/quick-perps.ts +292 -0
  62. package/src/dex/quick-perps/types.ts +97 -0
  63. package/src/dex/quick-perps/usdq.ts +83 -0
  64. package/src/dex/quick-perps/vault-price-feed.ts +322 -0
  65. package/src/dex/quick-perps/vault-utils.ts +53 -0
  66. package/src/dex/quick-perps/vault.ts +290 -0
  67. package/src/dex/solidly/forks-override/velodromeV2.ts +4 -2
  68. package/src/dex/uniswap-v2/nomiswap-v2.ts +2 -1
  69. package/src/dex/uniswap-v2/uniswap-v2-e2e-bsc.test.ts +6 -8
  70. package/src/dex/uniswap-v3/uniswap-v3-e2e.test.ts +52 -47
  71. package/src/dex/uniswap-v3/uniswap-v3-integration.test.ts +1 -9
  72. package/src/dex/uniswap-v3/uniswap-v3.ts +7 -1
  73. package/src/lib/api3-feed.ts +140 -0
  74. package/src/lib/decoders.ts +13 -0
  75. package/src/stateful-event-subscriber.ts +8 -0
  76. package/tests/constants-e2e.ts +29 -0
  77. package/tests/tenderly-simulation.ts +46 -2
  78. package/tests/utils-e2e.ts +18 -10
  79. package/build/abi/quickPerps/fast-price-events.json +0 -70
  80. package/build/abi/quickPerps/fast-price-feed.json +0 -748
  81. package/build/abi/quickPerps/reader.json +0 -313
  82. package/build/abi/quickPerps/vault-price-feed.json +0 -477
  83. package/build/abi/quickPerps/vault.json +0 -1953
  84. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3QuoterV2.abi.json +0 -285
  85. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3Router.abi.json +0 -583
  86. package/build/abi/woo-fi/WooFeeManager.abi.json +0 -318
  87. package/build/abi/woo-fi/WooPP.abi.json +0 -548
  88. package/build/abi/woo-fi/Wooracle.abi.json +0 -260
  89. package/build/dex/aave-v3/tokens/arbitrum.json +0 -50
  90. package/build/dex/aave-v3/tokens/avalanche.json +0 -74
  91. package/build/dex/aave-v3/tokens/fantom.json +0 -62
  92. package/build/dex/aave-v3/tokens/optimism.json +0 -50
  93. package/build/dex/aave-v3/tokens/polygon.json +0 -116
  94. package/build/dex/balancer-v2/LinearMath.d.ts +0 -19
  95. package/build/dex/balancer-v2/LinearMath.js +0 -179
  96. package/build/dex/balancer-v2/LinearMath.js.map +0 -1
  97. package/build/dex/balancer-v2/LinearPool.d.ts +0 -47
  98. package/build/dex/balancer-v2/LinearPool.js +0 -324
  99. package/build/dex/balancer-v2/LinearPool.js.map +0 -1
  100. package/build/dex/balancer-v2/PhantomStablePool.d.ts +0 -47
  101. package/build/dex/balancer-v2/PhantomStablePool.js +0 -294
  102. package/build/dex/balancer-v2/PhantomStablePool.js.map +0 -1
  103. package/build/dex/balancer-v2/StableMath.d.ts +0 -9
  104. package/build/dex/balancer-v2/StableMath.js +0 -272
  105. package/build/dex/balancer-v2/StableMath.js.map +0 -1
  106. package/build/dex/balancer-v2/balancer-v2-pool.d.ts +0 -75
  107. package/build/dex/balancer-v2/balancer-v2-pool.js +0 -417
  108. package/build/dex/balancer-v2/balancer-v2-pool.js.map +0 -1
  109. package/build/dex/quickswap-v3.d.ts +0 -21
  110. package/build/dex/quickswap-v3.js +0 -40
  111. package/build/dex/quickswap-v3.js.map +0 -1
  112. package/build/dex/test-dex/config.d.ts +0 -4
  113. package/build/dex/test-dex/config.js +0 -15
  114. package/build/dex/test-dex/config.js.map +0 -1
  115. package/build/dex/test-dex/test-dex-pool.d.ts +0 -39
  116. package/build/dex/test-dex/test-dex-pool.js +0 -63
  117. package/build/dex/test-dex/test-dex-pool.js.map +0 -1
  118. package/build/dex/test-dex/test-dex.d.ts +0 -37
  119. package/build/dex/test-dex/test-dex.js +0 -126
  120. package/build/dex/test-dex/test-dex.js.map +0 -1
  121. package/build/dex/test-dex/types.d.ts +0 -6
  122. package/build/dex/test-dex/types.js +0 -3
  123. package/build/dex/test-dex/types.js.map +0 -1
  124. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.d.ts +0 -12
  125. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js +0 -23
  126. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js.map +0 -1
  127. package/build/dex/woo-fi/config.d.ts +0 -4
  128. package/build/dex/woo-fi/config.js +0 -141
  129. package/build/dex/woo-fi/config.js.map +0 -1
  130. package/build/dex/woo-fi/constants.d.ts +0 -5
  131. package/build/dex/woo-fi/constants.js +0 -20
  132. package/build/dex/woo-fi/constants.js.map +0 -1
  133. package/build/dex/woo-fi/types.d.ts +0 -48
  134. package/build/dex/woo-fi/types.js +0 -3
  135. package/build/dex/woo-fi/types.js.map +0 -1
  136. package/build/dex/woo-fi/woo-fi-decimal-math.d.ts +0 -14
  137. package/build/dex/woo-fi/woo-fi-decimal-math.js +0 -42
  138. package/build/dex/woo-fi/woo-fi-decimal-math.js.map +0 -1
  139. package/build/dex/woo-fi/woo-fi-math.d.ts +0 -31
  140. package/build/dex/woo-fi/woo-fi-math.js +0 -300
  141. package/build/dex/woo-fi/woo-fi-math.js.map +0 -1
  142. package/build/dex/woo-fi/woo-fi.d.ts +0 -65
  143. package/build/dex/woo-fi/woo-fi.js +0 -480
  144. package/build/dex/woo-fi/woo-fi.js.map +0 -1
  145. package/build/dex/woo-fi-v2/woo-fi-math.d.ts +0 -16
  146. package/build/dex/woo-fi-v2/woo-fi-math.js +0 -137
  147. package/build/dex/woo-fi-v2/woo-fi-math.js.map +0 -1
  148. package/src/dex/balancer-v2/balancer-v2-optimizer.test.ts +0 -226
@@ -110,17 +110,22 @@ export abstract class ComposedEventSubscriber<
110
110
  .call({}, blockNumber)
111
111
  ).returnData;
112
112
  }
113
- const stateParts = await Promise.all(
114
- this.parts.map((p, i) =>
115
- p.generateState(
116
- returnData.slice(...this.multiCallSlices[i]),
117
- blockNumber,
113
+ try {
114
+ const stateParts = await Promise.all(
115
+ this.parts.map((p, i) =>
116
+ p.generateState(
117
+ returnData.slice(...this.multiCallSlices[i]),
118
+ blockNumber,
119
+ ),
118
120
  ),
119
- ),
120
- );
121
- return this.parts.reduce(
122
- (acc, p, i) => p.lens.set(stateParts[i])(acc),
123
- this.blankState,
124
- );
121
+ );
122
+ return this.parts.reduce(
123
+ (acc, p, i) => p.lens.set(stateParts[i])(acc),
124
+ this.blankState,
125
+ );
126
+ } catch (e) {
127
+ this.logger.error(`Error generating state: ${e}`);
128
+ throw e;
129
+ }
125
130
  }
126
131
  }
package/src/config.ts CHANGED
@@ -317,6 +317,36 @@ const baseConfigs: { [network: number]: BaseConfig } = {
317
317
  rpcPollingBlocksBackToTriggerUpdate: 3,
318
318
  forceRpcFallbackDexs: [],
319
319
  },
320
+
321
+ [Network.ZKEVM]: {
322
+ network: Network.ZKEVM,
323
+ networkName: 'Polygon zkEVM',
324
+ isTestnet: false,
325
+ nativeTokenName: 'Ether',
326
+ nativeTokenSymbol: 'ETH',
327
+ wrappedNativeTokenAddress: '0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9',
328
+ hasEIP1559: true,
329
+ augustusAddress: '0xB83B554730d29cE4Cb55BB42206c3E2c03E4A40A',
330
+ augustusRFQAddress: '0x7Ee1F7fa4C0b2eDB0Fdd5944c14A07167700486E',
331
+ tokenTransferProxyAddress: '0xc8a21fcd5a100c3ecc037c97e2f9c53a8d3a02a1',
332
+ multicallV2Address: '0x6cA478C852DfA8941FC819fDf248606eA04780B6',
333
+ privateHttpProvider: process.env.HTTP_PROVIDER_1101,
334
+ adapterAddresses: {
335
+ PolygonZkEvmAdapter01: '0xd63B7691dD98fa89A2ea5e1604700489c585aa7B',
336
+ PolygonZkEvmBuyAdapter: '0xe2137168CdA486a2555E16c597905854C84F9127',
337
+ },
338
+
339
+ rpcPollingMaxAllowedStateDelayInBlocks: 0,
340
+ rpcPollingBlocksBackToTriggerUpdate: 0,
341
+ hashFlowAuthToken: process.env.API_KEY_HASHFLOW_AUTH_TOKEN || '',
342
+ hashFlowDisabledMMs:
343
+ process.env[`HASHFLOW_DISABLED_MMS_10`]?.split(',') || [],
344
+ uniswapV3EventLoggingSampleRate: 0,
345
+ rfqConfigs: {},
346
+ forceRpcFallbackDexs: [],
347
+ // FIXME: Not set properly
348
+ uniswapV2ExchangeRouterAddress: '',
349
+ },
320
350
  };
321
351
 
322
352
  // Should not be used, except by internal test code
@@ -14,6 +14,8 @@ import {
14
14
  } from '../../../tests/utils';
15
15
  import { Tokens } from '../../../tests/constants-e2e';
16
16
  import { Address } from '@paraswap/core';
17
+ import { AlgebraEventPoolV1_1 } from './algebra-pool-v1_1';
18
+ import { DecodedStateMultiCallResultWithRelativeBitmapsV1_1 } from './types';
17
19
 
18
20
  function getReaderCalldata(
19
21
  exchangeAddress: string,
@@ -432,5 +434,125 @@ describe('Algebra', function () {
432
434
  );
433
435
  }
434
436
  });
437
+
438
+ it('both generate state result match', async function () {
439
+ const pool = (await algebra.getPool(
440
+ tokens[srcTokenSymbol].address,
441
+ tokens[destTokenSymbol].address,
442
+ blockNumber,
443
+ )) as AlgebraEventPoolV1_1;
444
+
445
+ const [balance0, balance1, stateMulticallFull] =
446
+ await pool.fetchPoolStateSingleStep(blockNumber);
447
+
448
+ const stateMulticall = {
449
+ pool: stateMulticallFull.pool.toLowerCase(),
450
+ globalState: {
451
+ price: stateMulticallFull.globalState.price,
452
+ tick: stateMulticallFull.globalState.tick,
453
+ fee: stateMulticallFull.globalState.fee,
454
+ communityFeeToken0: stateMulticallFull.globalState.communityFeeToken0,
455
+ communityFeeToken1: stateMulticallFull.globalState.communityFeeToken1,
456
+ },
457
+ liquidity: stateMulticallFull.liquidity,
458
+ tickSpacing: stateMulticallFull.tickSpacing,
459
+ maxLiquidityPerTick: stateMulticallFull.maxLiquidityPerTick,
460
+ tickBitmap: stateMulticallFull.tickBitmap.map(t => ({
461
+ index: t.index,
462
+ value: t.value,
463
+ })),
464
+ ticks: stateMulticallFull.ticks.map(t => ({
465
+ index: t.index,
466
+ value: {
467
+ liquidityNet: t.value.liquidityNet,
468
+ liquidityGross: t.value.liquidityGross,
469
+ secondsOutside: t.value.secondsOutside,
470
+ secondsPerLiquidityOutsideX128:
471
+ t.value.secondsPerLiquidityOutsideX128,
472
+ tickCumulativeOutside: t.value.tickCumulativeOutside,
473
+ initialized: t.value.initialized,
474
+ },
475
+ })),
476
+ };
477
+
478
+ const stateMulticallWithBalance = [balance0, balance1, stateMulticall];
479
+ const stateManually = await pool.fetchStateManually(blockNumber);
480
+ // @ts-ignore
481
+ delete stateManually[2]['blockTimestamp'];
482
+ stateManually[2].pool = stateManually[2].pool.toLowerCase();
483
+
484
+ expect(stateMulticallWithBalance).toStrictEqual(stateManually);
485
+ });
486
+ });
487
+
488
+ describe('ZKEVM', () => {
489
+ const network = Network.ZKEVM;
490
+ const dexHelper = new DummyDexHelper(network);
491
+
492
+ beforeAll(async () => {
493
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
494
+ algebra = new Algebra(network, dexKey, dexHelper);
495
+ if (algebra.initializePricing) {
496
+ await algebra.initializePricing(blockNumber);
497
+ }
498
+ });
499
+
500
+ it('WETH/DAI generate state is working for problematic pool', async function () {
501
+ const pool = (await algebra.getPool(
502
+ '0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9',
503
+ '0xc5015b9d9161dca7e18e32f6f25c4ad850731fd4',
504
+ blockNumber,
505
+ )) as AlgebraEventPoolV1_1;
506
+
507
+ const stateManually = await pool.fetchStateManually(blockNumber);
508
+ // We can not compare with usual way, because this pool can not be requested normally
509
+ expect(Array.isArray(stateManually)).toBeTruthy();
510
+ });
511
+
512
+ it('WETH/MATIC generate state is working for problematic pool', async function () {
513
+ const pool = (await algebra.getPool(
514
+ '0x4f9a0e7fd2bf6067db6994cf12e4495df938e6e9',
515
+ '0xa2036f0538221a77a3937f1379699f44945018d0',
516
+ blockNumber,
517
+ )) as AlgebraEventPoolV1_1;
518
+
519
+ const stateManually = await pool.fetchStateManually(blockNumber);
520
+ // We can not compare with usual way, because this pool can not be requested normally
521
+ expect(Array.isArray(stateManually)).toBeTruthy();
522
+ });
523
+
524
+ it('stMATIC/WETH generate state is working for problematic pool', async function () {
525
+ const pool = (await algebra.getPool(
526
+ '0x83b874c1e09d316059d929da402dcb1a98e92082',
527
+ '0x4f9a0e7fd2bf6067db6994cf12e4495df938e6e9',
528
+ blockNumber,
529
+ )) as AlgebraEventPoolV1_1;
530
+
531
+ const stateManually = await pool.fetchStateManually(blockNumber);
532
+ // We can not compare with usual way, because this pool can not be requested normally
533
+ expect(Array.isArray(stateManually)).toBeTruthy();
534
+ });
535
+
536
+ it('WETH/USDC generate state is working for problematic pool', async function () {
537
+ const pool = (await algebra.getPool(
538
+ '0x4f9a0e7fd2bf6067db6994cf12e4495df938e6e9',
539
+ '0xa8ce8aee21bc2a48a5ef670afcc9274c7bbbc035',
540
+ blockNumber,
541
+ )) as AlgebraEventPoolV1_1;
542
+
543
+ const stateManually = await pool.fetchStateManually(blockNumber);
544
+ // We can not compare with usual way, because this pool can not be requested normally
545
+ expect(Array.isArray(stateManually)).toBeTruthy();
546
+ });
547
+
548
+ it('recognize pool does not exist error', async function () {
549
+ const pool = (await algebra.getPool(
550
+ '0x8aaebb46e1742f4623e6e1621f909f01846ca5e2',
551
+ '0xf9ed88937b2d82707d0eabd8c3d9aa4870b714d3',
552
+ blockNumber,
553
+ )) as AlgebraEventPoolV1_1;
554
+
555
+ expect(pool).toBeNull();
556
+ });
435
557
  });
436
558
  });
@@ -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;