@paraswap/dex-lib 2.42.26 → 2.42.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/build/abi/smardex/all/smardex-router.json +648 -0
  2. package/build/abi/smardex/layer-1/smardex-factory.json +242 -0
  3. package/build/abi/smardex/layer-1/smardex-pool.json +506 -0
  4. package/build/abi/smardex/layer-2/smardex-factory.json +185 -0
  5. package/build/abi/smardex/layer-2/smardex-pool.json +578 -0
  6. package/build/config.js +20 -10
  7. package/build/config.js.map +1 -1
  8. package/build/dex/index.js +2 -0
  9. package/build/dex/index.js.map +1 -1
  10. package/build/dex/smardex/config.d.ts +4 -0
  11. package/build/dex/smardex/config.js +64 -0
  12. package/build/dex/smardex/config.js.map +1 -0
  13. package/build/dex/smardex/constants.d.ts +18 -0
  14. package/build/dex/smardex/constants.js +33 -0
  15. package/build/dex/smardex/constants.js.map +1 -0
  16. package/build/dex/smardex/sdk/constants.d.ts +6 -0
  17. package/build/dex/smardex/sdk/constants.js +13 -0
  18. package/build/dex/smardex/sdk/constants.js.map +1 -0
  19. package/build/dex/smardex/sdk/core.d.ts +113 -0
  20. package/build/dex/smardex/sdk/core.js +499 -0
  21. package/build/dex/smardex/sdk/core.js.map +1 -0
  22. package/build/dex/smardex/sdk/errors.d.ts +15 -0
  23. package/build/dex/smardex/sdk/errors.js +22 -0
  24. package/build/dex/smardex/sdk/errors.js.map +1 -0
  25. package/build/dex/smardex/sdk/types.d.ts +62 -0
  26. package/build/dex/smardex/sdk/types.js +3 -0
  27. package/build/dex/smardex/sdk/types.js.map +1 -0
  28. package/build/dex/smardex/sdk/utils.d.ts +44 -0
  29. package/build/dex/smardex/sdk/utils.js +133 -0
  30. package/build/dex/smardex/sdk/utils.js.map +1 -0
  31. package/build/dex/smardex/smardex-event-pool.d.ts +28 -0
  32. package/build/dex/smardex/smardex-event-pool.js +119 -0
  33. package/build/dex/smardex/smardex-event-pool.js.map +1 -0
  34. package/build/dex/smardex/smardex.d.ts +65 -0
  35. package/build/dex/smardex/smardex.js +519 -0
  36. package/build/dex/smardex/smardex.js.map +1 -0
  37. package/build/dex/smardex/types.d.ts +55 -0
  38. package/build/dex/smardex/types.js +3 -0
  39. package/build/dex/smardex/types.js.map +1 -0
  40. package/build/types.d.ts +1 -0
  41. package/package.json +3 -2
  42. package/src/abi/smardex/all/smardex-router.json +648 -0
  43. package/src/abi/smardex/layer-1/smardex-factory.json +242 -0
  44. package/src/abi/smardex/layer-1/smardex-pool.json +506 -0
  45. package/src/abi/smardex/layer-2/smardex-factory.json +185 -0
  46. package/src/abi/smardex/layer-2/smardex-pool.json +578 -0
  47. package/src/config.ts +21 -10
  48. package/src/dex/index.ts +2 -0
  49. package/src/dex/smardex/config.ts +67 -0
  50. package/src/dex/smardex/constants.ts +35 -0
  51. package/src/dex/smardex/sdk/constants.ts +10 -0
  52. package/src/dex/smardex/sdk/core.ts +832 -0
  53. package/src/dex/smardex/sdk/errors.ts +18 -0
  54. package/src/dex/smardex/sdk/types.ts +68 -0
  55. package/src/dex/smardex/sdk/utils.ts +156 -0
  56. package/src/dex/smardex/smardex-e2e.test.ts +275 -0
  57. package/src/dex/smardex/smardex-event-pool.ts +164 -0
  58. package/src/dex/smardex/smardex-events.test.ts +297 -0
  59. package/src/dex/smardex/smardex-integration.test.ts +258 -0
  60. package/src/dex/smardex/smardex.ts +770 -0
  61. package/src/dex/smardex/types.ts +69 -0
  62. package/src/types.ts +1 -0
  63. package/tests/constants-e2e.ts +26 -1
  64. package/.vscode/launch.json +0 -54
  65. package/.vscode/settings.json +0 -2
  66. package/.vscode/tasks.json +0 -15
@@ -0,0 +1,18 @@
1
+ /**
2
+ * SmardexError class
3
+ *
4
+ * @class SmardexError extends Error
5
+ */
6
+ export default class SmardexError extends Error {
7
+ /**
8
+ * Create SmardexError object
9
+ *
10
+ * @param {string} message - error message
11
+ * @param {string} [errorName=SmarDexSDK] - identifier for the error
12
+ * @returns {SmardexError} SmarDex Error object
13
+ */
14
+ constructor(message: string, errorName = 'SmarDexSDK') {
15
+ super(message);
16
+ this.name = errorName;
17
+ }
18
+ }
@@ -0,0 +1,68 @@
1
+ import { TradeType } from './constants';
2
+
3
+ export interface Pair {
4
+ address?: string;
5
+ token0: string;
6
+ token1: string;
7
+ reserve0: bigint;
8
+ reserve1: bigint;
9
+ reserve0LastFictive: bigint;
10
+ reserve1LastFictive: bigint;
11
+ priceAverageLastTimestamp: number;
12
+ priceAverage0: bigint;
13
+ priceAverage1: bigint;
14
+ forcedPriceAverageTimestamp?: number;
15
+ prevReserveFic0?: bigint;
16
+ prevReserveFic1?: bigint;
17
+ feesLP: bigint;
18
+ feesPool: bigint;
19
+ }
20
+
21
+ export interface CurrencyAmount {
22
+ currency: string;
23
+ amount: bigint;
24
+ amountMax?: bigint;
25
+ newRes0?: bigint;
26
+ newRes1?: bigint;
27
+ newRes0Fic?: bigint;
28
+ newRes1Fic?: bigint;
29
+ newPriceAverage0?: bigint;
30
+ newPriceAverage1?: bigint;
31
+ forcedPriceAverageTimestamp?: number;
32
+ }
33
+
34
+ export interface BestTradeOptions {
35
+ maxNumResults?: number; // how many results to return
36
+ maxHops?: number; // the maximum number of hops for the swap
37
+ arbitrage?: boolean; // consider arbitrage loops or not
38
+ }
39
+
40
+ export interface Route {
41
+ pairs: Pair[];
42
+ path: string[];
43
+ input: string;
44
+ output: string;
45
+ }
46
+
47
+ export interface Trade {
48
+ route: Route;
49
+ amountIn: CurrencyAmount;
50
+ amountOut: CurrencyAmount;
51
+ tradeType: TradeType;
52
+ priceImpact?: bigint;
53
+ gasFeesUSD?: bigint;
54
+ amountInUSD?: bigint;
55
+ amountOutUSD?: bigint;
56
+ }
57
+
58
+ export interface GasEstimateData {
59
+ gasPrice: bigint;
60
+ gasQuantitiesFirstHop: number;
61
+ gasQuantitiesAdditionalHop: number;
62
+ nativeTokenPrice: bigint;
63
+ nativeTokenDecimals: number;
64
+ inputTokenPrice: bigint;
65
+ inputTokenDecimals: number;
66
+ outputTokenPrice: bigint;
67
+ outputTokenDecimals: number;
68
+ }
@@ -0,0 +1,156 @@
1
+ import { parseUnits } from 'ethers/lib/utils';
2
+
3
+ import { CurrencyAmount, Trade } from './types';
4
+
5
+ // Constants to compute approximate equality
6
+ const APPROX_EQ_PRECISION = 1n;
7
+ const APPROX_EQ_BASE_PRECISION = 1000000n;
8
+
9
+ /**
10
+ * Computes logarithm in base 2 for a given positive number.
11
+ * Result is rounded down.
12
+ *
13
+ * @param {bigint} value - value to compute the log2
14
+ * @returns {bigint} the log in base 2 of the value, 0 if given 0.
15
+ */
16
+ /* eslint-disable no-param-reassign */
17
+ export function log2(value: bigint): bigint {
18
+ let result = 0n;
19
+
20
+ if (value >> 128n > 0n) {
21
+ value >>= 128n;
22
+ result += 128n;
23
+ }
24
+
25
+ if (value >> 64n > 0n) {
26
+ value >>= 64n;
27
+ result += 64n;
28
+ }
29
+
30
+ if (value >> 32n > 0n) {
31
+ value >>= 32n;
32
+ result += 32n;
33
+ }
34
+
35
+ if (value >> 16n > 0n) {
36
+ value >>= 16n;
37
+ result += 16n;
38
+ }
39
+
40
+ if (value >> 8n > 0n) {
41
+ value >>= 8n;
42
+ result += 8n;
43
+ }
44
+
45
+ if (value >> 4n > 0n) {
46
+ value >>= 4n;
47
+ result += 4n;
48
+ }
49
+
50
+ if (value >> 2n > 0n) {
51
+ value >>= 2n;
52
+ result += 2n;
53
+ }
54
+
55
+ if (value >> 1n > 0n) {
56
+ result += 1n;
57
+ }
58
+
59
+ return result;
60
+ }
61
+
62
+ /**
63
+ * Computes the square root of a number. If the number is not a perfect square, the value is rounded down.
64
+ * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
65
+ *
66
+ * @param {bigint} value - value to compute the square root
67
+ * @returns {bigint} the square root of the value
68
+ */
69
+ export function sqrt(value: bigint): bigint {
70
+ if (value === 0n) {
71
+ return 0n;
72
+ }
73
+
74
+ // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
75
+ //
76
+ // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
77
+ // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
78
+ //
79
+ // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
80
+ // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
81
+ // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
82
+ //
83
+ // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
84
+ let result = 1n << (log2(value) / 2n);
85
+
86
+ // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
87
+ // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
88
+ // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
89
+ // into the expected uint128 result.
90
+ result = (result + value / result) >> 1n;
91
+ result = (result + value / result) >> 1n;
92
+ result = (result + value / result) >> 1n;
93
+ result = (result + value / result) >> 1n;
94
+ result = (result + value / result) >> 1n;
95
+ result = (result + value / result) >> 1n;
96
+ result = (result + value / result) >> 1n;
97
+
98
+ return result < value / result ? result : value / result;
99
+ }
100
+
101
+ /**
102
+ * Evaluates the equality of two numbers at a precision of 1/1_000_000
103
+ *
104
+ * @param {bigint} x - value to compare
105
+ * @param {bigint} y - value to compare
106
+ * @returns {boolean} true if numbers are approximatively equal at 1/1_000_000, false otherwise
107
+ */
108
+ export function approxEq(x: bigint, y: bigint): true | false {
109
+ return x > y
110
+ ? x < y + (y * APPROX_EQ_PRECISION) / APPROX_EQ_BASE_PRECISION
111
+ : y < x + (x * APPROX_EQ_PRECISION) / APPROX_EQ_BASE_PRECISION;
112
+ }
113
+
114
+ /**
115
+ * Evaluates the equality of two ratio numbers at a precision of 1/1_000_000. xNum / xDen ~= yNum / yDen
116
+ *
117
+ * @param {bigint} _xNum - first number numerator
118
+ * @param {bigint} _xDen - first number denominator
119
+ * @param {bigint} _yNum - second number numerator
120
+ * @param {bigint} _yDen - second number denominator
121
+ * @returns {boolean} true if the two ratios are approximatively equal at 1/1_000_000, false otherwise
122
+ */
123
+ export function ratioApproxEq(
124
+ _xNum: bigint,
125
+ _xDen: bigint,
126
+ _yNum: bigint,
127
+ _yDen: bigint,
128
+ ): true | false {
129
+ return approxEq(_xNum * _yDen, _xDen * _yNum);
130
+ }
131
+
132
+ /**
133
+ * Computes the ratio of two numbers
134
+ *
135
+ * @param {bigint} numerator - numerator number
136
+ * @param {bigint} denominator - denominator number
137
+ * @param {number} decimals - decimals
138
+ * @returns {bigint} ratio of the two numbers. returns 0 if denominator is 0
139
+ */
140
+ export function priceRatio(
141
+ numerator: bigint,
142
+ denominator: bigint,
143
+ decimals = 18,
144
+ ) {
145
+ if (denominator === 0n) {
146
+ return 0n;
147
+ }
148
+
149
+ return (
150
+ BigInt(parseUnits(numerator.toString(), decimals).toString()) / denominator
151
+ );
152
+ }
153
+
154
+ export function abs(value: bigint) {
155
+ return value === -0n || value < 0n ? -value : value;
156
+ }
@@ -0,0 +1,275 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+
4
+ import { testE2E } from '../../../tests/utils-e2e';
5
+ import { Tokens, Holders } from '../../../tests/constants-e2e';
6
+ import { Network, ContractMethod, SwapSide } from '../../constants';
7
+ import { StaticJsonRpcProvider } from '@ethersproject/providers';
8
+ import { generateConfig } from '../../config';
9
+
10
+ function testForNetwork(
11
+ network: Network,
12
+ dexKey: string,
13
+ pairs: { name: string; sellAmount: string; buyAmount: string }[][],
14
+ ) {
15
+ const provider = new StaticJsonRpcProvider(
16
+ generateConfig(network).privateHttpProvider,
17
+ network,
18
+ );
19
+ const tokens = Tokens[network];
20
+ const holders = Holders[network];
21
+
22
+ const sideToContractMethods = new Map([
23
+ [
24
+ SwapSide.SELL,
25
+ [
26
+ ContractMethod.simpleSwap,
27
+ ContractMethod.multiSwap,
28
+ ContractMethod.megaSwap,
29
+ ],
30
+ ],
31
+ [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]],
32
+ ]);
33
+
34
+ sideToContractMethods.forEach((contractMethods, side) =>
35
+ describe(`${side}`, () => {
36
+ contractMethods.forEach((contractMethod: ContractMethod) => {
37
+ pairs.forEach(pair => {
38
+ describe(`${contractMethod}`, () => {
39
+ it(`${pair[0].name} -> ${pair[1].name}`, async () => {
40
+ await testE2E(
41
+ tokens[pair[0].name],
42
+ tokens[pair[1].name],
43
+ holders[pair[0].name],
44
+ side === SwapSide.SELL ? pair[0].sellAmount : pair[0].buyAmount,
45
+ side,
46
+ dexKey,
47
+ contractMethod,
48
+ network,
49
+ provider,
50
+ );
51
+ });
52
+ it(`${pair[1].name} -> ${pair[0].name}`, async () => {
53
+ await testE2E(
54
+ tokens[pair[1].name],
55
+ tokens[pair[0].name],
56
+ holders[pair[1].name],
57
+ side === SwapSide.SELL ? pair[1].sellAmount : pair[1].buyAmount,
58
+ side,
59
+ dexKey,
60
+ contractMethod,
61
+ network,
62
+ provider,
63
+ );
64
+ });
65
+ });
66
+ });
67
+ });
68
+ }),
69
+ );
70
+ }
71
+
72
+ describe('SmarDex E2E', () => {
73
+ const dexKey = 'SmarDex';
74
+
75
+ describe('MAINNET', () => {
76
+ const network = Network.MAINNET;
77
+
78
+ const pairs = [
79
+ [
80
+ {
81
+ name: 'USDT',
82
+ sellAmount: '1200000000',
83
+ buyAmount: '120000',
84
+ },
85
+ {
86
+ name: 'SDEX',
87
+ sellAmount: '300000000000000000000000',
88
+ buyAmount: '30000000000',
89
+ },
90
+ ],
91
+ [
92
+ {
93
+ name: 'SDEX',
94
+ sellAmount: '300000000000000000000000',
95
+ buyAmount: '30000000000',
96
+ },
97
+ {
98
+ name: 'ETH',
99
+ sellAmount: '11000000000000000',
100
+ buyAmount: '1100000000',
101
+ },
102
+ ],
103
+ ];
104
+
105
+ testForNetwork(network, dexKey, pairs);
106
+ });
107
+
108
+ describe('ARBITRUM', () => {
109
+ const network = Network.ARBITRUM;
110
+
111
+ const pairs = [
112
+ [
113
+ {
114
+ name: 'USDC',
115
+ sellAmount: '1200000000',
116
+ buyAmount: '120000',
117
+ },
118
+ {
119
+ name: 'SDEX',
120
+ sellAmount: '300000000000000000000000',
121
+ buyAmount: '30000000000',
122
+ },
123
+ ],
124
+ [
125
+ {
126
+ name: 'SDEX',
127
+ sellAmount: '300000000000000000000000',
128
+ buyAmount: '11000000000000000',
129
+ },
130
+ {
131
+ name: 'ETH',
132
+ sellAmount: '11000000000000000',
133
+ buyAmount: '11000000',
134
+ },
135
+ ],
136
+ ];
137
+
138
+ testForNetwork(network, dexKey, pairs);
139
+ });
140
+
141
+ describe('BSC', () => {
142
+ const network = Network.BSC;
143
+
144
+ const pairs = [
145
+ [
146
+ {
147
+ name: 'USDT',
148
+ sellAmount: '1200000000000000000000',
149
+ buyAmount: '300000000000000000000000',
150
+ },
151
+ {
152
+ name: 'SDEX',
153
+ sellAmount: '300000000000000000000000',
154
+ buyAmount: '120000000000000000000',
155
+ },
156
+ ],
157
+ [
158
+ {
159
+ name: 'SDEX',
160
+ sellAmount: '300000000000000000000000',
161
+ buyAmount: '50000000000000000',
162
+ },
163
+ {
164
+ name: 'bBTC',
165
+ sellAmount: '50000000000000000',
166
+ buyAmount: '300000000000000000000000',
167
+ },
168
+ ],
169
+ [
170
+ {
171
+ name: 'USDT',
172
+ sellAmount: '1500000000000000000000',
173
+ buyAmount: '20000000000000000000',
174
+ },
175
+ {
176
+ name: 'BNB',
177
+ sellAmount: '20000000000000000000',
178
+ buyAmount: '1500000000000000000000',
179
+ },
180
+ ],
181
+ ];
182
+
183
+ testForNetwork(network, dexKey, pairs);
184
+ });
185
+
186
+ describe('POLYGON', () => {
187
+ const network = Network.POLYGON;
188
+
189
+ const pairs = [
190
+ [
191
+ {
192
+ name: 'WETH',
193
+ sellAmount: '1500000000000000000',
194
+ buyAmount: '250000000000000000000000',
195
+ },
196
+ {
197
+ name: 'SDEX',
198
+ sellAmount: '250000000000000000000000',
199
+ buyAmount: '1500000000000000000',
200
+ },
201
+ ],
202
+ [
203
+ {
204
+ name: 'USDC',
205
+ sellAmount: '2500000000',
206
+ buyAmount: '300000000000000000000000',
207
+ },
208
+ {
209
+ name: 'SDEX',
210
+ sellAmount: '300000000000000000000000',
211
+ buyAmount: '2500000000',
212
+ },
213
+ ],
214
+ [
215
+ {
216
+ name: 'USDC',
217
+ sellAmount: '2500000000',
218
+ buyAmount: '8000000000000000000000',
219
+ },
220
+ {
221
+ name: 'MATIC',
222
+ sellAmount: '8000000000000000000000',
223
+ buyAmount: '2500000000',
224
+ },
225
+ ],
226
+ [
227
+ {
228
+ name: 'SDEX',
229
+ sellAmount: '190000000000000000000000',
230
+ buyAmount: '8000000',
231
+ },
232
+ {
233
+ name: 'WBTC',
234
+ sellAmount: '8000000',
235
+ buyAmount: '190000000000000000000000',
236
+ },
237
+ ],
238
+ ];
239
+
240
+ testForNetwork(network, dexKey, pairs);
241
+ });
242
+
243
+ describe('BASE', () => {
244
+ const network = Network.BASE;
245
+
246
+ const pairs = [
247
+ [
248
+ {
249
+ name: 'WETH',
250
+ sellAmount: '1500000000000000000',
251
+ buyAmount: '2500000000',
252
+ },
253
+ {
254
+ name: 'USDbC',
255
+ sellAmount: '2500000000',
256
+ buyAmount: '1500000000000000000',
257
+ },
258
+ ],
259
+ [
260
+ {
261
+ name: 'WETH',
262
+ sellAmount: '1500000000000000000',
263
+ buyAmount: '250000000000000000000000',
264
+ },
265
+ {
266
+ name: 'SDEX',
267
+ sellAmount: '250000000000000000000000',
268
+ buyAmount: '1500000000000000000',
269
+ },
270
+ ],
271
+ ];
272
+
273
+ testForNetwork(network, dexKey, pairs);
274
+ });
275
+ });
@@ -0,0 +1,164 @@
1
+ import { StatefulEventSubscriber } from '../../stateful-event-subscriber';
2
+ import { SmardexFees, SmardexPoolState } from './types';
3
+ import { AbiCoder, Interface } from '@ethersproject/abi';
4
+ import { IDexHelper } from '../../dex-helper';
5
+ import { Address, Log, Logger, Token } from '../../types';
6
+ import { DeepReadonly } from 'ts-essentials';
7
+ import { FEES_LAYER_ONE, TOPICS } from './constants';
8
+
9
+ const coder = new AbiCoder();
10
+
11
+ export class SmardexEventPool extends StatefulEventSubscriber<SmardexPoolState> {
12
+ constructor(
13
+ protected poolInterface: Interface,
14
+ protected dexHelper: IDexHelper,
15
+ public poolAddress: Address,
16
+ token0: Token,
17
+ token1: Token,
18
+ logger: Logger,
19
+ protected smardexFeesMultiCallEntry?: {
20
+ target: string;
21
+ callData: string;
22
+ },
23
+ protected smardexFeesMulticallDecoder?: (values: any[]) => SmardexFees,
24
+ private isLayerOne = true,
25
+ ) {
26
+ super('Smardex', `${token0.address}_${token1.address}`, dexHelper, logger);
27
+ }
28
+
29
+ async fetchPairFeesAndLastTimestamp(blockNumber: number): Promise<{
30
+ feesLP: bigint;
31
+ feesPool: bigint;
32
+ priceAverageLastTimestamp: number;
33
+ }> {
34
+ let calldata = [
35
+ {
36
+ target: this.poolAddress,
37
+ callData: this.poolInterface.encodeFunctionData('getPriceAverage', []),
38
+ },
39
+ ];
40
+ if (!this.isLayerOne) {
41
+ calldata.push(this.smardexFeesMultiCallEntry!);
42
+ }
43
+
44
+ const data: { returnData: any[] } =
45
+ await this.dexHelper.multiContract.methods
46
+ .aggregate(calldata)
47
+ .call({}, blockNumber);
48
+
49
+ const priceAverageLastTimestamp = coder.decode(
50
+ ['uint256', 'uint256', 'uint256'],
51
+ data.returnData[0],
52
+ )[2];
53
+
54
+ const fees = this.isLayerOne
55
+ ? FEES_LAYER_ONE
56
+ : this.smardexFeesMulticallDecoder!(data.returnData[1]);
57
+ return {
58
+ feesLP: fees.feesLP,
59
+ feesPool: fees.feesPool,
60
+ priceAverageLastTimestamp: priceAverageLastTimestamp.toNumber(),
61
+ };
62
+ }
63
+
64
+ // This methode overrides previous state with new state.
65
+ // Problem: Smardex Pair state is updated partially on different events
66
+ // This is why we must fetch pair's missing state in Events
67
+ protected async processLog(
68
+ state: DeepReadonly<SmardexPoolState>,
69
+ log: Readonly<Log>,
70
+ ): Promise<DeepReadonly<SmardexPoolState> | null> {
71
+ if (!Object.values(TOPICS).includes(log.topics[0] as TOPICS)) return null;
72
+ const event = this.poolInterface.parseLog(log);
73
+ switch (event.name) {
74
+ case 'Sync':
75
+ const fetchedSync = await this.fetchPairFeesAndLastTimestamp(
76
+ log.blockNumber,
77
+ );
78
+ return {
79
+ reserves0: event.args.reserve0.toString(),
80
+ reserves1: event.args.reserve1.toString(),
81
+ fictiveReserves0: event.args.fictiveReserve0.toString(),
82
+ fictiveReserves1: event.args.fictiveReserve1.toString(),
83
+ priceAverage0: event.args.priceAverage0.toString(),
84
+ priceAverage1: event.args.priceAverage1.toString(),
85
+ priceAverageLastTimestamp: fetchedSync.priceAverageLastTimestamp,
86
+ feesLP: fetchedSync.feesLP,
87
+ feesPool: fetchedSync.feesPool,
88
+ };
89
+ case 'FeesChanged': // only triggerd on L2
90
+ return {
91
+ reserves0: state.reserves0,
92
+ reserves1: state.reserves1,
93
+ fictiveReserves0: state.fictiveReserves0,
94
+ fictiveReserves1: state.fictiveReserves1,
95
+ priceAverage0: state.priceAverage0,
96
+ priceAverage1: state.priceAverage1,
97
+ priceAverageLastTimestamp: state.priceAverageLastTimestamp,
98
+ feesLP: BigInt(event.args.feesLP),
99
+ feesPool: BigInt(event.args.feesPool),
100
+ };
101
+ }
102
+ return null;
103
+ }
104
+
105
+ async generateState(
106
+ blockNumber: number | 'latest' = 'latest',
107
+ ): Promise<DeepReadonly<SmardexPoolState>> {
108
+ const coder = new AbiCoder();
109
+ let calldata = [
110
+ {
111
+ target: this.poolAddress,
112
+ callData: this.poolInterface.encodeFunctionData('getReserves', []),
113
+ },
114
+ {
115
+ target: this.poolAddress,
116
+ callData: this.poolInterface.encodeFunctionData(
117
+ 'getFictiveReserves',
118
+ [],
119
+ ),
120
+ },
121
+ {
122
+ target: this.poolAddress,
123
+ callData: this.poolInterface.encodeFunctionData('getPriceAverage', []),
124
+ },
125
+ ];
126
+ if (!this.isLayerOne) {
127
+ calldata.push(this.smardexFeesMultiCallEntry!);
128
+ }
129
+
130
+ const data: { returnData: any[] } =
131
+ await this.dexHelper.multiContract.methods
132
+ .aggregate(calldata)
133
+ .call({}, blockNumber);
134
+
135
+ const [reserves0, reserves1] = coder.decode(
136
+ ['uint256', 'uint256'],
137
+ data.returnData[0],
138
+ );
139
+
140
+ const [fictiveReserve0, fictiveReserve1] = coder.decode(
141
+ ['uint256', 'uint256'],
142
+ data.returnData[1],
143
+ );
144
+
145
+ const [priceAverage0, priceAverage1, priceAverageLastTimestamp] =
146
+ coder.decode(['uint256', 'uint256', 'uint256'], data.returnData[2]);
147
+
148
+ const fees = this.isLayerOne
149
+ ? FEES_LAYER_ONE
150
+ : this.smardexFeesMulticallDecoder!(data.returnData[3]);
151
+
152
+ return {
153
+ reserves0: reserves0.toString(),
154
+ reserves1: reserves1.toString(),
155
+ fictiveReserves0: fictiveReserve0.toString(),
156
+ fictiveReserves1: fictiveReserve1.toString(),
157
+ priceAverage0: priceAverage0.toString(),
158
+ priceAverage1: priceAverage1.toString(),
159
+ priceAverageLastTimestamp: priceAverageLastTimestamp.toNumber(),
160
+ feesLP: fees.feesLP,
161
+ feesPool: fees.feesPool,
162
+ };
163
+ }
164
+ }