@paraswap/dex-lib 2.42.28 → 2.42.29

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 (130) hide show
  1. package/build/abi/{algebra/AlgebraPool.abi.json → solidly-v3/SolidlyV3Pool.abi.json} +293 -282
  2. package/build/abi/solidly-v3/SolidlyV3StateMulticall.abi.json +375 -0
  3. package/build/config.js +2 -2
  4. package/build/dex/index.js +2 -0
  5. package/build/dex/index.js.map +1 -1
  6. package/build/dex/solidly-v3/config.d.ts +9 -0
  7. package/build/dex/solidly-v3/config.js +58 -0
  8. package/build/dex/solidly-v3/config.js.map +1 -0
  9. package/build/dex/solidly-v3/constants.d.ts +27 -0
  10. package/build/dex/solidly-v3/constants.js +34 -0
  11. package/build/dex/solidly-v3/constants.js.map +1 -0
  12. package/build/dex/solidly-v3/contract-math/BitMath.d.ts +4 -0
  13. package/build/dex/solidly-v3/contract-math/BitMath.js +93 -0
  14. package/build/dex/solidly-v3/contract-math/BitMath.js.map +1 -0
  15. package/build/dex/solidly-v3/contract-math/FixedPoint128.d.ts +3 -0
  16. package/build/dex/solidly-v3/contract-math/FixedPoint128.js +8 -0
  17. package/build/dex/solidly-v3/contract-math/FixedPoint128.js.map +1 -0
  18. package/build/dex/solidly-v3/contract-math/FixedPoint96.d.ts +4 -0
  19. package/build/dex/solidly-v3/contract-math/FixedPoint96.js +9 -0
  20. package/build/dex/solidly-v3/contract-math/FixedPoint96.js.map +1 -0
  21. package/build/dex/solidly-v3/contract-math/FullMath.d.ts +4 -0
  22. package/build/dex/solidly-v3/contract-math/FullMath.js +19 -0
  23. package/build/dex/solidly-v3/contract-math/FullMath.js.map +1 -0
  24. package/build/dex/solidly-v3/contract-math/LiquidityMath.d.ts +3 -0
  25. package/build/dex/solidly-v3/contract-math/LiquidityMath.js +22 -0
  26. package/build/dex/solidly-v3/contract-math/LiquidityMath.js.map +1 -0
  27. package/build/dex/solidly-v3/contract-math/SqrtPriceMath.d.ts +10 -0
  28. package/build/dex/solidly-v3/contract-math/SqrtPriceMath.js +91 -0
  29. package/build/dex/solidly-v3/contract-math/SqrtPriceMath.js.map +1 -0
  30. package/build/dex/solidly-v3/contract-math/SwapMath.d.ts +8 -0
  31. package/build/dex/solidly-v3/contract-math/SwapMath.js +70 -0
  32. package/build/dex/solidly-v3/contract-math/SwapMath.js.map +1 -0
  33. package/build/dex/solidly-v3/contract-math/Tick.d.ts +7 -0
  34. package/build/dex/solidly-v3/contract-math/Tick.js +36 -0
  35. package/build/dex/solidly-v3/contract-math/Tick.js.map +1 -0
  36. package/build/dex/solidly-v3/contract-math/TickBitMap.d.ts +7 -0
  37. package/build/dex/solidly-v3/contract-math/TickBitMap.js +84 -0
  38. package/build/dex/solidly-v3/contract-math/TickBitMap.js.map +1 -0
  39. package/build/dex/solidly-v3/contract-math/TickMath.d.ts +8 -0
  40. package/build/dex/solidly-v3/contract-math/TickMath.js +162 -0
  41. package/build/dex/solidly-v3/contract-math/TickMath.js.map +1 -0
  42. package/build/dex/solidly-v3/contract-math/UnsafeMath.d.ts +3 -0
  43. package/build/dex/solidly-v3/contract-math/UnsafeMath.js +10 -0
  44. package/build/dex/solidly-v3/contract-math/UnsafeMath.js.map +1 -0
  45. package/build/dex/solidly-v3/contract-math/uniswap-v3-math.d.ts +31 -0
  46. package/build/dex/solidly-v3/contract-math/uniswap-v3-math.js +363 -0
  47. package/build/dex/solidly-v3/contract-math/uniswap-v3-math.js.map +1 -0
  48. package/build/dex/solidly-v3/contract-math/utils.d.ts +7 -0
  49. package/build/dex/solidly-v3/contract-math/utils.js +39 -0
  50. package/build/dex/solidly-v3/contract-math/utils.js.map +1 -0
  51. package/build/dex/solidly-v3/solidly-v3-factory.d.ts +26 -0
  52. package/build/dex/solidly-v3/solidly-v3-factory.js +44 -0
  53. package/build/dex/solidly-v3/solidly-v3-factory.js.map +1 -0
  54. package/build/dex/{algebra/algebra-pool.d.ts → solidly-v3/solidly-v3-pool.d.ts} +14 -16
  55. package/build/dex/{algebra/algebra-pool.js → solidly-v3/solidly-v3-pool.js} +127 -165
  56. package/build/dex/solidly-v3/solidly-v3-pool.js.map +1 -0
  57. package/build/dex/solidly-v3/solidly-v3.d.ts +67 -0
  58. package/build/dex/solidly-v3/solidly-v3.js +590 -0
  59. package/build/dex/solidly-v3/solidly-v3.js.map +1 -0
  60. package/build/dex/solidly-v3/types.d.ts +132 -0
  61. package/build/dex/solidly-v3/types.js +9 -0
  62. package/build/dex/solidly-v3/types.js.map +1 -0
  63. package/build/dex/solidly-v3/utils.d.ts +6 -0
  64. package/build/dex/solidly-v3/utils.js +53 -0
  65. package/build/dex/solidly-v3/utils.js.map +1 -0
  66. package/build/dex/trader-joe-v2-1-2/config.d.ts +4 -0
  67. package/build/dex/trader-joe-v2-1-2/config.js +15 -0
  68. package/build/dex/trader-joe-v2-1-2/config.js.map +1 -0
  69. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2-pool.d.ts +39 -0
  70. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2-pool.js +64 -0
  71. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2-pool.js.map +1 -0
  72. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2.d.ts +37 -0
  73. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2.js +126 -0
  74. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2.js.map +1 -0
  75. package/build/dex/trader-joe-v2-1-2/types.d.ts +6 -0
  76. package/build/dex/trader-joe-v2-1-2/types.js +3 -0
  77. package/build/dex/trader-joe-v2-1-2/types.js.map +1 -0
  78. package/build/dex/trader-joe-v2_1/config.d.ts +4 -0
  79. package/build/dex/trader-joe-v2_1/config.js +48 -0
  80. package/build/dex/trader-joe-v2_1/config.js.map +1 -0
  81. package/build/dex/trader-joe-v2_1/constants.d.ts +15 -0
  82. package/build/dex/trader-joe-v2_1/constants.js +17 -0
  83. package/build/dex/trader-joe-v2_1/constants.js.map +1 -0
  84. package/build/dex/trader-joe-v2_1/trader-joe-v2.1.d.ts +0 -0
  85. package/build/dex/trader-joe-v2_1/trader-joe-v2.1.js +183 -0
  86. package/build/dex/trader-joe-v2_1/trader-joe-v2.1.js.map +1 -0
  87. package/build/dex/trader-joe-v2_1/types.d.ts +39 -0
  88. package/build/dex/trader-joe-v2_1/types.js +3 -0
  89. package/build/dex/trader-joe-v2_1/types.js.map +1 -0
  90. package/build/dex/wombat/wombat-pool-poller.d.ts +22 -0
  91. package/build/dex/wombat/wombat-pool-poller.js +164 -0
  92. package/build/dex/wombat/wombat-pool-poller.js.map +1 -0
  93. package/package.json +1 -1
  94. package/src/abi/solidly-v3/SolidlyV3Pool.abi.json +738 -0
  95. package/src/abi/solidly-v3/SolidlyV3StateMulticall.abi.json +375 -0
  96. package/src/config.ts +2 -2
  97. package/src/dex/index.ts +2 -0
  98. package/src/dex/solidly-v3/config.ts +64 -0
  99. package/src/dex/solidly-v3/constants.ts +42 -0
  100. package/src/dex/solidly-v3/contract-math/BitMath.ts +90 -0
  101. package/src/dex/solidly-v3/contract-math/FixedPoint128.ts +3 -0
  102. package/src/dex/solidly-v3/contract-math/FixedPoint96.ts +4 -0
  103. package/src/dex/solidly-v3/contract-math/FullMath.ts +30 -0
  104. package/src/dex/solidly-v3/contract-math/LiquidityMath.ts +17 -0
  105. package/src/dex/solidly-v3/contract-math/SqrtPriceMath.ts +226 -0
  106. package/src/dex/solidly-v3/contract-math/SwapMath.ts +139 -0
  107. package/src/dex/solidly-v3/contract-math/Tick.ts +66 -0
  108. package/src/dex/solidly-v3/contract-math/TickBitMap.ts +123 -0
  109. package/src/dex/solidly-v3/contract-math/TickMath.ts +211 -0
  110. package/src/dex/solidly-v3/contract-math/UnsafeMath.ts +5 -0
  111. package/src/dex/solidly-v3/contract-math/uniswap-v3-math.ts +570 -0
  112. package/src/dex/solidly-v3/contract-math/utils.ts +50 -0
  113. package/src/dex/solidly-v3/solidly-v3-e2e.test.ts +124 -0
  114. package/src/dex/solidly-v3/solidly-v3-events.test.ts +144 -0
  115. package/src/dex/solidly-v3/solidly-v3-factory.ts +73 -0
  116. package/src/dex/solidly-v3/solidly-v3-integration.test.ts +358 -0
  117. package/src/dex/solidly-v3/solidly-v3-pool.ts +494 -0
  118. package/src/dex/solidly-v3/solidly-v3.ts +988 -0
  119. package/src/dex/solidly-v3/types.ts +158 -0
  120. package/src/dex/solidly-v3/utils.ts +71 -0
  121. package/src/dex/uniswap-v3/uniswap-v3-events.test.ts +3 -0
  122. package/build/abi/uniswap-v3/UniswapV3Quoter.abi.json +0 -193
  123. package/build/dex/algebra/algebra-pool.js.map +0 -1
  124. package/build/dex/quickswap/camelot-v3.d.ts +0 -6
  125. package/build/dex/quickswap/camelot-v3.js +0 -19
  126. package/build/dex/quickswap/camelot-v3.js.map +0 -1
  127. package/build/dex/quickswap/zyberswap-v3.d.ts +0 -6
  128. package/build/dex/quickswap/zyberswap-v3.js +0 -19
  129. package/build/dex/quickswap/zyberswap-v3.js.map +0 -1
  130. package/build/dex/uniswap-v2/rebase-tokens.json +0 -7
@@ -0,0 +1,124 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { testE2E } from '../../../tests/utils-e2e';
6
+ import {
7
+ Tokens,
8
+ Holders,
9
+ NativeTokenSymbols,
10
+ } from '../../../tests/constants-e2e';
11
+ import { Network, ContractMethod, SwapSide } from '../../constants';
12
+ import { StaticJsonRpcProvider } from '@ethersproject/providers';
13
+ import { generateConfig } from '../../config';
14
+
15
+ function testForNetwork(
16
+ network: Network,
17
+ dexKey: string,
18
+ pairs: { name: string; sellAmount: string; buyAmount: string }[][],
19
+ ) {
20
+ const provider = new StaticJsonRpcProvider(
21
+ generateConfig(network).privateHttpProvider,
22
+ network,
23
+ );
24
+ const tokens = Tokens[network];
25
+ const holders = Holders[network];
26
+
27
+ const sideToContractMethods = new Map([
28
+ [
29
+ SwapSide.SELL,
30
+ [
31
+ ContractMethod.simpleSwap,
32
+ ContractMethod.multiSwap,
33
+ ContractMethod.megaSwap,
34
+ ],
35
+ ],
36
+ [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]],
37
+ ]);
38
+
39
+ sideToContractMethods.forEach((contractMethods, side) =>
40
+ describe(`${side}`, () => {
41
+ contractMethods.forEach((contractMethod: ContractMethod) => {
42
+ pairs.forEach(pair => {
43
+ describe(`${contractMethod}`, () => {
44
+ it(`${pair[0].name} -> ${pair[1].name}`, async () => {
45
+ await testE2E(
46
+ tokens[pair[0].name],
47
+ tokens[pair[1].name],
48
+ holders[pair[0].name],
49
+ side === SwapSide.SELL ? pair[0].sellAmount : pair[0].buyAmount,
50
+ side,
51
+ dexKey,
52
+ contractMethod,
53
+ network,
54
+ provider,
55
+ );
56
+ });
57
+ it(`${pair[1].name} -> ${pair[0].name}`, async () => {
58
+ await testE2E(
59
+ tokens[pair[1].name],
60
+ tokens[pair[0].name],
61
+ holders[pair[1].name],
62
+ side === SwapSide.SELL ? pair[1].sellAmount : pair[1].buyAmount,
63
+ side,
64
+ dexKey,
65
+ contractMethod,
66
+ network,
67
+ provider,
68
+ );
69
+ });
70
+ });
71
+ });
72
+ });
73
+ }),
74
+ );
75
+ }
76
+
77
+ describe('SolidlyV3 E2E', () => {
78
+ const dexKey = 'SolidlyV3';
79
+
80
+ describe('Mainnet', () => {
81
+ const network = Network.MAINNET;
82
+
83
+ const pairs = [
84
+ [
85
+ {
86
+ name: 'ETH',
87
+ sellAmount: '110000000000000000',
88
+ buyAmount: '1100000000',
89
+ },
90
+ {
91
+ name: 'USDC',
92
+ sellAmount: '400000000',
93
+ buyAmount: '4000000',
94
+ },
95
+ ],
96
+ [
97
+ {
98
+ name: 'WETH',
99
+ sellAmount: '1100000000000000000',
100
+ buyAmount: '1100000000',
101
+ },
102
+ {
103
+ name: 'USDC',
104
+ sellAmount: '400000000',
105
+ buyAmount: '4000000',
106
+ },
107
+ ],
108
+ [
109
+ {
110
+ name: 'USDC',
111
+ sellAmount: '400000000',
112
+ buyAmount: '4000000',
113
+ },
114
+ {
115
+ name: 'USDT',
116
+ sellAmount: '500000000',
117
+ buyAmount: '5000000',
118
+ },
119
+ ],
120
+ ];
121
+
122
+ testForNetwork(network, dexKey, pairs);
123
+ });
124
+ });
@@ -0,0 +1,144 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { SolidlyV3EventPool } from './solidly-v3-pool';
6
+ import { Network } from '../../constants';
7
+ import { Address } from '../../types';
8
+ import { DummyDexHelper } from '../../dex-helper/index';
9
+ import { testEventSubscriber } from '../../../tests/utils-events';
10
+ import { PoolState } from './types';
11
+ import {SolidlyV3Config} from "./config";
12
+ import {AbiItem} from "web3-utils";
13
+ import {Interface} from "@ethersproject/abi";
14
+ import StateMulticallABI from '../../abi/solidly-v3/SolidlyV3StateMulticall.abi.json';
15
+ import { decodeStateMultiCallResultWithRelativeBitmaps } from './utils';
16
+ import ERC20ABI from '../../abi/erc20.json';
17
+
18
+ /*
19
+ README
20
+ ======
21
+
22
+ This test script adds unit tests for SolidlyV3 event based
23
+ system. This is done by fetching the state on-chain before the
24
+ event block, manually pushing the block logs to the event-subscriber,
25
+ comparing the local state with on-chain state.
26
+
27
+ Most of the logic for testing is abstracted by `testEventSubscriber`.
28
+ You need to do two things to make the tests work:
29
+
30
+ 1. Fetch the block numbers where certain events were released. You
31
+ can modify the `./scripts/fetch-event-blocknumber.ts` to get the
32
+ block numbers for different events. Make sure to get sufficient
33
+ number of blockNumbers to cover all possible cases for the event
34
+ mutations.
35
+
36
+ 2. Complete the implementation for fetchPoolState function. The
37
+ function should fetch the on-chain state of the event subscriber
38
+ using just the blocknumber.
39
+
40
+ The template tests only include the test for a single event
41
+ subscriber. There can be cases where multiple event subscribers
42
+ exist for a single DEX. In such cases additional tests should be
43
+ added.
44
+
45
+ You can run this individual test script by running:
46
+ `npx jest src/dex/<dex-name>/<dex-name>-events.test.ts`
47
+
48
+ (This comment should be removed from the final implementation)
49
+ */
50
+
51
+ jest.setTimeout(50 * 1000);
52
+ const dexKey = 'SolidlyV3';
53
+ const network = Network.MAINNET;
54
+ const config = SolidlyV3Config[dexKey][network];
55
+
56
+ async function fetchPoolStateFromContract(
57
+ solidlyV3Pool: SolidlyV3EventPool,
58
+ blockNumber: number,
59
+ poolAddress: string,
60
+ ): Promise<PoolState> {
61
+ const message = `SolidlyV3: ${poolAddress} blockNumber ${blockNumber}`;
62
+ console.log(`Fetching state ${message}`);
63
+ // Be careful to not request state prior to contract deployment
64
+ // Otherwise need to use manual state sourcing from multicall
65
+ // We had that mechanism, but removed it with this commit
66
+ // You can restore it, but better just to find block after state multicall
67
+ // deployment
68
+ const state = solidlyV3Pool.generateState(blockNumber);
69
+ console.log(`Done ${message}`);
70
+ return state;
71
+ }
72
+
73
+ // eventName -> blockNumbers
74
+ type EventMappings = Record<string, number[]>;
75
+
76
+ describe('SolidlyV3 Event', function () {
77
+ const poolAddress = '0x831BF48183B999fDe45294b14B55199072f0801B';
78
+ const token0 = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
79
+ const token1 = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
80
+
81
+ const blockNumbers: { [eventName: string]: number[] } = {
82
+ // topic0 - 0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67
83
+ ['Swap']: [
84
+ 18600853, 18616106, 18616441, 18619851, 18622968, 18625121, 18626415, 18627297, 18630574,
85
+ 18718946, 18726197, 18730166, 18758602
86
+ ],
87
+ ['Burn']: [18737937],
88
+ ['Mint']: [18708230, 18709265, 18737969],
89
+ ['Collect']: [18751597],
90
+ //topic0 0x0eb63f4a36d6bdeee05aa00020a97d80c3e84f1b5b3ebf345fb67262e62b0f33
91
+ ['SetFee']: [18427614, 18423073, 18423143, 18425324, 18430069, 18442932, 18442934],
92
+ ['Flash']: [18758872],
93
+ ['CollectProtocol']: [18530529, 18577493],
94
+ }
95
+
96
+ describe('SolidlyV3EventPool', function () {
97
+ Object.keys(blockNumbers).forEach((event: string) => {
98
+ blockNumbers[event].forEach((blockNumber: number) => {
99
+ it(`${event}:${blockNumber} - should return correct state`, async function () {
100
+ const dexHelper = new DummyDexHelper(network);
101
+ // await dexHelper.init();
102
+
103
+ const logger = dexHelper.getLogger(dexKey);
104
+
105
+ const solidlyV3Pool = new SolidlyV3EventPool(
106
+ dexHelper,
107
+ dexKey,
108
+ new dexHelper.web3Provider.eth.Contract(
109
+ StateMulticallABI as AbiItem[],
110
+ config.stateMulticall,
111
+ ),
112
+ decodeStateMultiCallResultWithRelativeBitmaps,
113
+ new Interface(ERC20ABI),
114
+ config.factory,
115
+ 10n,
116
+ token0,
117
+ token1,
118
+ logger,
119
+ undefined,
120
+ config.initHash,
121
+ );
122
+
123
+ // It is done in generateState. But here have to make it manually
124
+ solidlyV3Pool.poolAddress = poolAddress.toLowerCase();
125
+ solidlyV3Pool.addressesSubscribed[0] = poolAddress;
126
+
127
+ await testEventSubscriber(
128
+ solidlyV3Pool,
129
+ solidlyV3Pool.addressesSubscribed,
130
+ (_blockNumber: number) =>
131
+ fetchPoolStateFromContract(
132
+ solidlyV3Pool,
133
+ _blockNumber,
134
+ poolAddress,
135
+ ),
136
+ blockNumber,
137
+ `${dexKey}_${poolAddress}`,
138
+ dexHelper.provider,
139
+ );
140
+ });
141
+ });
142
+ });
143
+ });
144
+ });
@@ -0,0 +1,73 @@
1
+ import { Interface } from '@ethersproject/abi';
2
+ import { DeepReadonly } from 'ts-essentials';
3
+ import FactoryABI from '../../abi/uniswap-v3/UniswapV3Factory.abi.json';
4
+ import { IDexHelper } from '../../dex-helper/idex-helper';
5
+ import { StatefulEventSubscriber } from '../../stateful-event-subscriber';
6
+ import { Address, Log, Logger } from '../../types';
7
+ import { LogDescription } from 'ethers/lib/utils';
8
+ import { FactoryState } from './types';
9
+
10
+ export type OnPoolCreatedCallback = ({
11
+ token0,
12
+ token1,
13
+ tickSpacing,
14
+ }: {
15
+ token0: string;
16
+ token1: string;
17
+ tickSpacing: bigint;
18
+ }) => Promise<void>;
19
+
20
+ /*
21
+ * "Stateless" event subscriber in order to capture "PoolCreated" event on new pools created.
22
+ * State is present, but it's a placeholder to actually make the events reach handlers (if there's no previous state - `processBlockLogs` is not called)
23
+ */
24
+ export class SolidlyV3Factory extends StatefulEventSubscriber<FactoryState> {
25
+ handlers: {
26
+ [event: string]: (event: any) => Promise<void>;
27
+ } = {};
28
+
29
+ logDecoder: (log: Log) => any;
30
+
31
+ public readonly factoryIface = new Interface(FactoryABI);
32
+
33
+ constructor(
34
+ readonly dexHelper: IDexHelper,
35
+ parentName: string,
36
+ protected readonly factoryAddress: Address,
37
+ logger: Logger,
38
+ protected readonly onPoolCreated: OnPoolCreatedCallback,
39
+ mapKey: string = '',
40
+ ) {
41
+ super(parentName, `${parentName} Factory`, dexHelper, logger, true, mapKey);
42
+
43
+ this.addressesSubscribed = [factoryAddress];
44
+
45
+ this.logDecoder = (log: Log) => this.factoryIface.parseLog(log);
46
+
47
+ this.handlers['PoolCreated'] = this.handleNewPool.bind(this);
48
+ }
49
+
50
+ generateState(): FactoryState {
51
+ return {};
52
+ }
53
+
54
+ protected async processLog(
55
+ _: DeepReadonly<FactoryState>,
56
+ log: Readonly<Log>,
57
+ ): Promise<FactoryState> {
58
+ const event = this.logDecoder(log);
59
+ if (event.name in this.handlers) {
60
+ await this.handlers[event.name](event);
61
+ }
62
+
63
+ return {};
64
+ }
65
+
66
+ async handleNewPool(event: LogDescription) {
67
+ const token0 = event.args.token0.toLowerCase();
68
+ const token1 = event.args.token1.toLowerCase();
69
+ const tickSpacing = BigInt(event.args.tickSpacing);
70
+
71
+ await this.onPoolCreated({ token0, token1, tickSpacing });
72
+ }
73
+ }
@@ -0,0 +1,358 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { Interface, Result } from '@ethersproject/abi';
6
+ import { DummyDexHelper, IDexHelper } from '../../dex-helper/index';
7
+ import { Network, SwapSide } from '../../constants';
8
+ import { BI_POWS } from '../../bigint-constants';
9
+ import { SolidlyV3 } from './solidly-v3';
10
+ import { MIN_SQRT_RATIO, MAX_SQRT_RATIO } from './constants';
11
+ import {
12
+ checkPoolPrices,
13
+ checkPoolsLiquidity,
14
+ checkConstantPoolPrices,
15
+ } from '../../../tests/utils';
16
+ import { Tokens } from '../../../tests/constants-e2e';
17
+ import { Address } from '@paraswap/core';
18
+ import SolidlyV3PoolABI from '../../abi/solidly-v3/SolidlyV3Pool.abi.json';
19
+
20
+ /*
21
+ README
22
+ ======
23
+
24
+ This test script adds tests for SolidlyV3 general integration
25
+ with the DEX interface. The test cases below are example tests.
26
+ It is recommended to add tests which cover SolidlyV3 specific
27
+ logic.
28
+
29
+ You can run this individual test script by running:
30
+ `npx jest src/dex/<dex-name>/<dex-name>-integration.test.ts`
31
+
32
+ (This comment should be removed from the final implementation)
33
+ */
34
+
35
+ const network = Network.MAINNET;
36
+ const dexHelper = new DummyDexHelper(network);
37
+
38
+ const WETH = Tokens[network]['WETH'];
39
+ const USDC = Tokens[network]['USDC'];
40
+
41
+ const amounts = [0n, 1n * BI_POWS[18], 2n * BI_POWS[18]];
42
+ // Sell WETH to receive 1000 USDC, 2000 UDST, and 3000 USDC
43
+ const amountsBuy = [
44
+ 0n,
45
+ 1000n * BI_POWS[6],
46
+ 2000n * BI_POWS[6],
47
+ 3000n * BI_POWS[6],
48
+ ];
49
+
50
+ function getReaderCalldata(
51
+ exchangeAddress: string,
52
+ readerIface: Interface,
53
+ amounts: bigint[],
54
+ funcName: string,
55
+ zeroForOne: boolean,
56
+ sqrtPriceLimitX96: bigint,
57
+ exactInput: boolean,
58
+ ) {
59
+ return amounts.map(amount => ({
60
+ target: exchangeAddress,
61
+ callData: readerIface.encodeFunctionData(funcName, [
62
+ zeroForOne,
63
+ exactInput ? amount.toString() : `-${amount.toString()}`,
64
+ sqrtPriceLimitX96.toString(),
65
+ ]),
66
+ }));
67
+ }
68
+
69
+ // We are only using this function to decode `quoteSwap` on SolidlyV3Pool. The output param we consider relevant
70
+ // depends on `zeroForOne` and `exactInput`.
71
+ function decodeReaderResult(
72
+ results: Result,
73
+ readerIface: Interface,
74
+ funcName: string,
75
+ zeroForOne: boolean,
76
+ exactInput: boolean,
77
+ ) {
78
+ return results.map(result => {
79
+ const parsed = readerIface.decodeFunctionResult(funcName, result);
80
+ // zeroForOne determines whether we want to get amount0 or amount1
81
+ let index;
82
+ if (zeroForOne == exactInput) {
83
+ index = 1;
84
+ } else {
85
+ index = 0;
86
+ }
87
+ return parsed[index]._hex[0] == '-'
88
+ ? BigInt(parsed[index]._hex.slice(1))
89
+ : BigInt(parsed[index]._hex);
90
+ });
91
+ }
92
+
93
+ async function checkOnChainPricing(
94
+ dexHelper: IDexHelper,
95
+ blockNumber: number,
96
+ poolAddress: string,
97
+ prices: bigint[],
98
+ tokenIn: Address,
99
+ tokenOut: Address,
100
+ tickSpacing: bigint,
101
+ _amounts: bigint[],
102
+ exactInput: boolean,
103
+ ) {
104
+ const readerIface = new Interface(SolidlyV3PoolABI);
105
+
106
+ const sum = prices.reduce((acc, curr) => (acc += curr), 0n);
107
+
108
+ if (sum === 0n) {
109
+ console.log(
110
+ `Prices were not calculated for tokenIn=${tokenIn}, tokenOut=${tokenOut}, tickSpacing=${tickSpacing.toString()}. Most likely price impact is too big for requested amount`,
111
+ );
112
+ return false;
113
+ }
114
+
115
+ const readerCallData = getReaderCalldata(
116
+ poolAddress,
117
+ readerIface,
118
+ _amounts.slice(1),
119
+ 'quoteSwap',
120
+ tokenIn < tokenOut,
121
+ tokenIn < tokenOut
122
+ ? MIN_SQRT_RATIO + BigInt(1)
123
+ : MAX_SQRT_RATIO - BigInt(1),
124
+ exactInput,
125
+ );
126
+
127
+ let readerResult;
128
+ try {
129
+ readerResult = (
130
+ await dexHelper.multiContract.methods
131
+ .aggregate(readerCallData)
132
+ .call({}, blockNumber)
133
+ ).returnData;
134
+ } catch (e) {
135
+ console.log(
136
+ `Can not fetch on-chain pricing for tickSpacing ${tickSpacing}. It happens for low liquidity pools`,
137
+ e,
138
+ );
139
+ return false;
140
+ }
141
+
142
+ const expectedPrices = [0n].concat(
143
+ decodeReaderResult(
144
+ readerResult,
145
+ readerIface,
146
+ 'quoteSwap',
147
+ tokenIn < tokenOut,
148
+ exactInput,
149
+ ),
150
+ );
151
+
152
+ console.log('EXPECTED PRICES: ', expectedPrices);
153
+
154
+ let firstZeroIndex = prices.slice(1).indexOf(0n);
155
+
156
+ // we skipped first, so add +1 on result
157
+ firstZeroIndex = firstZeroIndex === -1 ? prices.length : firstZeroIndex;
158
+
159
+ // Compare only the ones for which we were able to calculate prices
160
+ expect(prices.slice(0, firstZeroIndex)).toEqual(
161
+ expectedPrices.slice(0, firstZeroIndex),
162
+ );
163
+ return true;
164
+ }
165
+
166
+ async function testPricingOnNetwork(
167
+ solidlyV3: SolidlyV3,
168
+ network: Network,
169
+ dexKey: string,
170
+ blockNumber: number,
171
+ srcTokenSymbol: string,
172
+ destTokenSymbol: string,
173
+ side: SwapSide,
174
+ amounts: bigint[],
175
+ funcNameToCheck: string,
176
+ ) {
177
+ const networkTokens = Tokens[network];
178
+
179
+ const pools = await solidlyV3.getPoolIdentifiers(
180
+ networkTokens[srcTokenSymbol],
181
+ networkTokens[destTokenSymbol],
182
+ side,
183
+ blockNumber,
184
+ );
185
+ console.log(
186
+ `${srcTokenSymbol} <> ${destTokenSymbol} Pool Identifiers: `,
187
+ pools,
188
+ );
189
+
190
+ expect(pools.length).toBeGreaterThan(0);
191
+
192
+ const poolPrices = await solidlyV3.getPricesVolume(
193
+ networkTokens[srcTokenSymbol],
194
+ networkTokens[destTokenSymbol],
195
+ amounts,
196
+ side,
197
+ blockNumber,
198
+ pools,
199
+ );
200
+ console.log(
201
+ `${srcTokenSymbol} <> ${destTokenSymbol} Pool Prices: `,
202
+ poolPrices,
203
+ );
204
+
205
+ expect(poolPrices).not.toBeNull();
206
+ if (solidlyV3.hasConstantPriceLargeAmounts) {
207
+ checkConstantPoolPrices(poolPrices!, amounts, dexKey);
208
+ } else {
209
+ checkPoolPrices(poolPrices!, amounts, side, dexKey);
210
+ }
211
+ }
212
+
213
+ describe('SolidlyV3', function () {
214
+ const dexKey = 'SolidlyV3';
215
+ let blockNumber: number;
216
+ let solidlyV3: SolidlyV3;
217
+
218
+ beforeEach(async () => {
219
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
220
+ const solidlyV3 = new SolidlyV3(network, dexKey, dexHelper);
221
+ });
222
+
223
+ describe('Mainnet', () => {
224
+ const network = Network.MAINNET;
225
+ const dexHelper = new DummyDexHelper(network);
226
+
227
+ const tokens = Tokens[network];
228
+
229
+ // TODO: Put here token Symbol to check against
230
+ // Don't forget to update relevant tokens in constant-e2e.ts
231
+ const srcTokenSymbol = 'WETH';
232
+ const destTokenSymbol = 'USDC';
233
+
234
+ beforeAll(async () => {
235
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
236
+ solidlyV3 = new SolidlyV3(network, dexKey, dexHelper);
237
+ if (solidlyV3.initializePricing) {
238
+ await solidlyV3.initializePricing(blockNumber);
239
+ }
240
+ });
241
+
242
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
243
+ const pools = await solidlyV3.getPoolIdentifiers(
244
+ WETH,
245
+ USDC,
246
+ SwapSide.SELL,
247
+ blockNumber,
248
+ );
249
+ console.log(`WETH <> USDC Pool Identifiers: `, pools);
250
+
251
+ expect(pools.length).toBeGreaterThan(0);
252
+
253
+ const poolPrices = await solidlyV3.getPricesVolume(
254
+ WETH,
255
+ USDC,
256
+ amounts,
257
+ SwapSide.SELL,
258
+ blockNumber,
259
+ pools,
260
+ );
261
+ console.log(`WETH <> USDC Pool Prices: `, poolPrices);
262
+
263
+ expect(poolPrices).not.toBeNull();
264
+ checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);
265
+
266
+ let falseChecksCounter = 0;
267
+ await Promise.all(
268
+ poolPrices!.map(async price => {
269
+ const tickSpacing =
270
+ solidlyV3.eventPools[price.poolIdentifier!]!.tickSpacing;
271
+ const res = await checkOnChainPricing(
272
+ dexHelper,
273
+ blockNumber,
274
+ solidlyV3.eventPools[price.poolIdentifier!]!.poolAddress,
275
+ price.prices,
276
+ WETH.address,
277
+ USDC.address,
278
+ tickSpacing,
279
+ amounts,
280
+ true,
281
+ );
282
+ if (res === false) falseChecksCounter++;
283
+ }),
284
+ );
285
+
286
+ expect(falseChecksCounter).toBeLessThan(poolPrices!.length);
287
+ });
288
+
289
+ it('getPoolIdentifiers and getPricesVolume BUY', async function () {
290
+ const pools = await solidlyV3.getPoolIdentifiers(
291
+ WETH,
292
+ USDC,
293
+ SwapSide.BUY,
294
+ blockNumber,
295
+ );
296
+ console.log(`WETH <> USDC Pool Identifiers: `, pools);
297
+
298
+ expect(pools.length).toBeGreaterThan(0);
299
+
300
+ const poolPrices = await solidlyV3.getPricesVolume(
301
+ WETH,
302
+ USDC,
303
+ amountsBuy,
304
+ SwapSide.BUY,
305
+ blockNumber,
306
+ pools,
307
+ );
308
+ console.log(`WETH <> USDC Pool Prices: `, poolPrices);
309
+
310
+ expect(poolPrices).not.toBeNull();
311
+ checkPoolPrices(poolPrices!, amountsBuy, SwapSide.BUY, dexKey);
312
+
313
+ let falseChecksCounter = 0;
314
+ await Promise.all(
315
+ poolPrices!.map(async price => {
316
+ const tickSpacing =
317
+ solidlyV3.eventPools[price.poolIdentifier!]!.tickSpacing;
318
+ const res = await checkOnChainPricing(
319
+ dexHelper,
320
+ blockNumber,
321
+ solidlyV3.eventPools[price.poolIdentifier!]!.poolAddress,
322
+ price.prices,
323
+ WETH.address,
324
+ USDC.address,
325
+ tickSpacing,
326
+ amountsBuy,
327
+ false,
328
+ );
329
+ if (res === false) falseChecksCounter++;
330
+ }),
331
+ );
332
+
333
+ expect(falseChecksCounter).toBeLessThan(poolPrices!.length);
334
+ });
335
+
336
+ it('getTopPoolsForToken', async function () {
337
+ // We have to check without calling initializePricing, because
338
+ // pool-tracker is not calling that function
339
+ const newSolidlyV3 = new SolidlyV3(network, dexKey, dexHelper);
340
+ // if (newSolidlyV3.updatePoolState) {
341
+ // await newSolidlyV3.updatePoolState();
342
+ // }
343
+ const poolLiquidity = await newSolidlyV3.getTopPoolsForToken(
344
+ tokens[srcTokenSymbol].address,
345
+ 10,
346
+ );
347
+ console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity);
348
+
349
+ if (!newSolidlyV3.hasConstantPriceLargeAmounts) {
350
+ checkPoolsLiquidity(
351
+ poolLiquidity,
352
+ Tokens[network][srcTokenSymbol].address,
353
+ dexKey,
354
+ );
355
+ }
356
+ });
357
+ });
358
+ });