@paraswap/dex-lib 3.10.0 → 3.10.2

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 (43) hide show
  1. package/build/abi/fluid-dex/dexFactory.abi.json +506 -0
  2. package/build/abi/fluid-dex/fluid-dex.abi.json +922 -0
  3. package/build/abi/fluid-dex/liquidityUserModule.abi.json +145 -0
  4. package/build/abi/fluid-dex/resolver.abi.json +999 -0
  5. package/build/dex/fluid-dex/config.d.ts +4 -0
  6. package/build/dex/fluid-dex/config.js +20 -0
  7. package/build/dex/fluid-dex/config.js.map +1 -0
  8. package/build/dex/fluid-dex/fluid-dex-factory.d.ts +49 -0
  9. package/build/dex/fluid-dex/fluid-dex-factory.js +104 -0
  10. package/build/dex/fluid-dex/fluid-dex-factory.js.map +1 -0
  11. package/build/dex/fluid-dex/fluid-dex-pool.d.ts +47 -0
  12. package/build/dex/fluid-dex/fluid-dex-pool.js +119 -0
  13. package/build/dex/fluid-dex/fluid-dex-pool.js.map +1 -0
  14. package/build/dex/fluid-dex/fluid-dex.d.ts +127 -0
  15. package/build/dex/fluid-dex/fluid-dex.js +502 -0
  16. package/build/dex/fluid-dex/fluid-dex.js.map +1 -0
  17. package/build/dex/fluid-dex/types.d.ts +52 -0
  18. package/build/dex/fluid-dex/types.js +3 -0
  19. package/build/dex/fluid-dex/types.js.map +1 -0
  20. package/build/dex/fluid-dex/utils.d.ts +2 -0
  21. package/build/dex/fluid-dex/utils.js +18 -0
  22. package/build/dex/fluid-dex/utils.js.map +1 -0
  23. package/build/dex/index.js +2 -0
  24. package/build/dex/index.js.map +1 -1
  25. package/build/dex/paraswap-limit-orders/paraswap-limit-orders.js +1 -1
  26. package/build/dex/paraswap-limit-orders/paraswap-limit-orders.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/abi/fluid-dex/dexFactory.abi.json +506 -0
  29. package/src/abi/fluid-dex/fluid-dex.abi.json +922 -0
  30. package/src/abi/fluid-dex/liquidityUserModule.abi.json +145 -0
  31. package/src/abi/fluid-dex/resolver.abi.json +999 -0
  32. package/src/dex/fluid-dex/config.ts +20 -0
  33. package/src/dex/fluid-dex/fluid-dex-e2e.test.ts +153 -0
  34. package/src/dex/fluid-dex/fluid-dex-events.test.ts +293 -0
  35. package/src/dex/fluid-dex/fluid-dex-factory.ts +143 -0
  36. package/src/dex/fluid-dex/fluid-dex-integration.test.ts +299 -0
  37. package/src/dex/fluid-dex/fluid-dex-pool.ts +178 -0
  38. package/src/dex/fluid-dex/fluid-dex.ts +790 -0
  39. package/src/dex/fluid-dex/types.ts +62 -0
  40. package/src/dex/fluid-dex/utils.ts +15 -0
  41. package/src/dex/index.ts +2 -0
  42. package/src/dex/paraswap-limit-orders/paraswap-limit-orders.ts +1 -1
  43. package/tests/constants-e2e.ts +2 -2
@@ -0,0 +1,20 @@
1
+ import { DexParams } from './types';
2
+ import { DexConfigMap } from '../../types';
3
+ import { Network } from '../../constants';
4
+
5
+ export const FluidDexConfig: DexConfigMap<DexParams> = {
6
+ FluidDex: {
7
+ [Network.MAINNET]: {
8
+ commonAddresses: {
9
+ liquidityProxy: '0x52aa899454998be5b000ad077a46bbe360f4e497',
10
+ resolver: '0xE8a07a32489BD9d5a00f01A55749Cf5cB854Fd13',
11
+ dexFactory: '0x91716C4EDA1Fb55e84Bf8b4c7085f84285c19085',
12
+ },
13
+ },
14
+ },
15
+ };
16
+
17
+ // Uniswap takes total gas of 125k = 21k base gas & 104k swap (this is when user has token balance)
18
+ // Fluid takes total gas of 175k = 21k base gas & 154k swap (this is when user has token balance),
19
+ // with ETH swaps costing less (because no WETH conversion)
20
+ export const FLUID_DEX_GAS_COST = 154_000;
@@ -0,0 +1,153 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { StaticJsonRpcProvider } from '@ethersproject/providers';
6
+
7
+ import { testE2E } from '../../../tests/utils-e2e';
8
+ import {
9
+ Tokens,
10
+ Holders,
11
+ NativeTokenSymbols,
12
+ } from '../../../tests/constants-e2e';
13
+ import { Network, ContractMethod, SwapSide } from '../../constants';
14
+ import { generateConfig } from '../../config';
15
+
16
+ /*
17
+ README
18
+ ======
19
+
20
+ This test script should add e2e tests for FluidDex. The tests
21
+ should cover as many cases as possible. Most of the DEXes follow
22
+ the following test structure:
23
+ - DexName
24
+ - ForkName + Network
25
+ - ContractMethod
26
+ - ETH -> Token swap
27
+ - Token -> ETH swap
28
+ - Token -> Token swap
29
+
30
+ The template already enumerates the basic structure which involves
31
+ testing simpleSwap, multiSwap, megaSwap contract methods for
32
+ ETH <> TOKEN and TOKEN <> TOKEN swaps. You should replace tokenA and
33
+ tokenB with any two highly liquid tokens on FluidDex for the tests
34
+ to work. If the tokens that you would like to use are not defined in
35
+ Tokens or Holders map, you can update the './tests/constants-e2e'
36
+
37
+ Other than the standard cases that are already added by the template
38
+ it is highly recommended to add test cases which could be specific
39
+ to testing FluidDex (Eg. Tests based on poolType, special tokens,
40
+ etc).
41
+
42
+ You can run this individual test script by running:
43
+ `npx jest src/dex/<dex-name>/<dex-name>-e2e.test.ts`
44
+
45
+ e2e tests use the Tenderly fork api. Please add the following to your
46
+ .env file:
47
+ TENDERLY_TOKEN=Find this under Account>Settings>Authorization.
48
+ TENDERLY_ACCOUNT_ID=Your Tenderly account name.
49
+ TENDERLY_PROJECT=Name of a Tenderly project you have created in your
50
+ dashboard.
51
+
52
+ (This comment should be removed from the final implementation)
53
+ */
54
+
55
+ function testForNetwork(
56
+ network: Network,
57
+ dexKey: string,
58
+ tokenASymbol: string,
59
+ tokenBSymbol: string,
60
+ tokenAAmount: string,
61
+ tokenBAmount: string,
62
+ ) {
63
+ const provider = new StaticJsonRpcProvider(
64
+ generateConfig(network).privateHttpProvider,
65
+ network,
66
+ );
67
+ const tokens = Tokens[network];
68
+ const holders = Holders[network];
69
+ const nativeTokenSymbol = NativeTokenSymbols[network];
70
+
71
+ const sideToContractMethods = new Map([
72
+ [SwapSide.SELL, [ContractMethod.swapExactAmountIn]],
73
+ ]);
74
+
75
+ describe(`${network}`, () => {
76
+ sideToContractMethods.forEach((contractMethods, side) =>
77
+ describe(`${side}`, () => {
78
+ contractMethods.forEach((contractMethod: string) => {
79
+ describe(`${contractMethod}`, () => {
80
+ it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => {
81
+ await testE2E(
82
+ tokens[tokenASymbol],
83
+ tokens[tokenBSymbol],
84
+ holders[tokenASymbol],
85
+ tokenBAmount,
86
+ SwapSide.SELL,
87
+ dexKey,
88
+ contractMethod as ContractMethod,
89
+ network,
90
+ provider,
91
+ );
92
+ });
93
+ it(`${tokenBSymbol} -> ${tokenASymbol}`, async () => {
94
+ await testE2E(
95
+ tokens[tokenBSymbol],
96
+ tokens[tokenASymbol],
97
+ holders[tokenBSymbol],
98
+ tokenBAmount,
99
+ SwapSide.SELL,
100
+ dexKey,
101
+ contractMethod as ContractMethod,
102
+ network,
103
+ provider,
104
+ );
105
+ });
106
+ });
107
+ });
108
+ }),
109
+ );
110
+ });
111
+ }
112
+
113
+ describe('FluidDex E2E', () => {
114
+ const dexKey = 'FluidDex';
115
+
116
+ describe('Mainnet', () => {
117
+ const network = Network.MAINNET;
118
+
119
+ describe('ETH -> wstETH', () => {
120
+ const tokenASymbol: string = 'wstETH';
121
+ const tokenBSymbol: string = 'ETH';
122
+
123
+ const tokenAAmount: string = '100000000000000';
124
+ const tokenBAmount: string = '100000000000000';
125
+
126
+ testForNetwork(
127
+ network,
128
+ dexKey,
129
+ tokenASymbol,
130
+ tokenBSymbol,
131
+ tokenAAmount,
132
+ tokenBAmount,
133
+ );
134
+ });
135
+
136
+ describe('USDC -> USDT', () => {
137
+ const tokenASymbol: string = 'USDC';
138
+ const tokenBSymbol: string = 'USDT';
139
+
140
+ const tokenAAmount: string = '1000000';
141
+ const tokenBAmount: string = '100000000';
142
+
143
+ testForNetwork(
144
+ network,
145
+ dexKey,
146
+ tokenASymbol,
147
+ tokenBSymbol,
148
+ tokenAAmount,
149
+ tokenBAmount,
150
+ );
151
+ });
152
+ });
153
+ });
@@ -0,0 +1,293 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { FluidDexEventPool } from './fluid-dex-pool';
6
+ import { FluidDexFactory } from './fluid-dex-factory';
7
+ import { FluidDex } from './fluid-dex';
8
+ import { Network } from '../../constants';
9
+ import { Address } from '../../types';
10
+ import { DummyDexHelper } from '../../dex-helper/index';
11
+ import { testEventSubscriber } from '../../../tests/utils-events';
12
+ import { CommonAddresses, FluidDexPoolState, Pool } from './types';
13
+ import { FluidDexConfig } from './config';
14
+ import { DeepReadonly } from 'ts-essentials';
15
+ import { TenderlySimulation } from '../../../tests/tenderly-simulation';
16
+
17
+ /*
18
+ README
19
+ ======
20
+
21
+ This test script adds unit tests for FluidDex event based
22
+ system. This is done by fetching the state on-chain before the
23
+ event block, manually pushing the block logs to the event-subscriber,
24
+ comparing the local state with on-chain state.
25
+
26
+ Most of the logic for testing is abstracted by `testEventSubscriber`.
27
+ You need to do two things to make the tests work:
28
+
29
+ 1. Fetch the block numbers where certain events were released. You
30
+ can modify the `./scripts/fetch-event-blocknumber.ts` to get the
31
+ block numbers for different events. Make sure to get sufficient
32
+ number of blockNumbers to cover all possible cases for the event
33
+ mutations.
34
+
35
+ 2. Complete the implementation for fetchPoolState function. The
36
+ function should fetch the on-chain state of the event subscriber
37
+ using just the blocknumber.
38
+
39
+ The template tests only include the test for a single event
40
+ subscriber. There can be cases where multiple event subscribers
41
+ exist for a single DEX. In such cases additional tests should be
42
+ added.
43
+
44
+ You can run this individual test script by running:
45
+ `npx jest src/dex/<dex-name>/<dex-name>-events.test.ts`
46
+
47
+ (This comment should be removed from the final implementation)
48
+ */
49
+
50
+ jest.setTimeout(50 * 1000);
51
+
52
+ async function fetchPoolState(
53
+ fluidDexPool: FluidDexEventPool,
54
+ blockNumber: number,
55
+ ): Promise<FluidDexPoolState> {
56
+ return await fluidDexPool.generateState(blockNumber);
57
+ }
58
+
59
+ async function fetchTotalPools(
60
+ factory: FluidDexFactory,
61
+ blockNumber: number,
62
+ ): Promise<DeepReadonly<Pool[]>> {
63
+ return await factory.generateState(blockNumber);
64
+ }
65
+
66
+ async function delay(seconds: number): Promise<void> {
67
+ for (let i = seconds; i > 0; i--) {
68
+ process.stdout.write(`\r${i} second${i !== 1 ? 's' : ''} left`);
69
+ await new Promise(resolve => setTimeout(resolve, 1000));
70
+ }
71
+ process.stdout.write("\rTime's up! \n");
72
+ }
73
+
74
+ function stringifyCircular(obj: any, space?: number): string {
75
+ const seen = new WeakSet();
76
+ return JSON.stringify(
77
+ obj,
78
+ (key, value) => {
79
+ if (typeof value === 'object' && value !== null) {
80
+ if (seen.has(value)) {
81
+ return '[Circular]';
82
+ }
83
+ seen.add(value);
84
+ }
85
+ return value;
86
+ },
87
+ space,
88
+ );
89
+ }
90
+
91
+ function replacer(key: string, value: any) {
92
+ if (typeof value === 'bigint') {
93
+ return value.toString();
94
+ }
95
+ return value;
96
+ }
97
+
98
+ // eventName -> blockNumbers
99
+ type EventMappings = Record<string, number[]>;
100
+
101
+ describe('FluidDex EventPool Mainnet', function () {
102
+ const dexKey = 'FluidDex';
103
+ const network = Network.MAINNET;
104
+ const dexHelper = new DummyDexHelper(network);
105
+ const logger = dexHelper.getLogger(dexKey);
106
+ const fluidDexCommonAddressStruct: CommonAddresses =
107
+ FluidDexConfig[dexKey][network].commonAddresses;
108
+ const liquidityProxy: Address = '0x52aa899454998be5b000ad077a46bbe360f4e497';
109
+ const dexFactory: Address = '0x91716C4EDA1Fb55e84Bf8b4c7085f84285c19085';
110
+
111
+ const poolFetchEventsToTest: Record<Address, EventMappings> = {
112
+ [dexFactory]: {
113
+ DexDeployed: [21063272],
114
+ },
115
+ };
116
+
117
+ // poolAddress -> EventMappings
118
+ const poolUpdateEventsToTest: Record<Address, EventMappings> = {
119
+ [dexFactory]: {
120
+ LogOperate: [21063272],
121
+ },
122
+ };
123
+
124
+ let fluidDexEventPool: FluidDexEventPool;
125
+ let factory: FluidDexFactory;
126
+
127
+ Object.entries(poolUpdateEventsToTest).forEach(
128
+ ([poolAddress, events]: [string, EventMappings]) => {
129
+ describe(`Events for ${poolAddress}`, () => {
130
+ Object.entries(events).forEach(
131
+ ([eventName, blockNumbers]: [string, number[]]) => {
132
+ describe(`${eventName}`, () => {
133
+ blockNumbers.forEach((blockNumber: number) => {
134
+ it(`State after ${blockNumber}`, async function () {
135
+ const fluidDex = new FluidDex(network, dexKey, dexHelper);
136
+
137
+ await fluidDex.initializePricing(blockNumber);
138
+ console.log('hello');
139
+
140
+ const ts: TenderlySimulation = new TenderlySimulation(
141
+ network,
142
+ );
143
+
144
+ await ts.setup();
145
+
146
+ const forkId = ts.forkId;
147
+ dexHelper.replaceProviderWithRPC(
148
+ `https://rpc.tenderly.co/fork/${forkId}`,
149
+ );
150
+
151
+ console.log(forkId);
152
+
153
+ const pools = fluidDex.factory.getState(blockNumber);
154
+ let pool: string | undefined;
155
+
156
+ if (pools) {
157
+ for (let i = 0; i < pools.length; i++) {
158
+ if (
159
+ pools[i].token0.toLowerCase() ===
160
+ '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0' &&
161
+ pools[i].token1.toLowerCase() ===
162
+ '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
163
+ ) {
164
+ pool = pools[i].address.toLowerCase();
165
+ break;
166
+ }
167
+ }
168
+ } else {
169
+ console.error('Pools data is null or undefined');
170
+ }
171
+
172
+ fluidDexEventPool = fluidDex.eventPools[`FluidDex_${pool}`];
173
+ console.log(
174
+ `this is the dex key that i fetched from writing the for loop FluidDex_${pool}`,
175
+ );
176
+
177
+ console.log(
178
+ 'eth balance before : ' +
179
+ (await dexHelper.provider.getBalance(
180
+ '0x3c22ec75ea5d745c78fc84762f7f1e6d82a2c5bf',
181
+ )),
182
+ );
183
+
184
+ console.log(
185
+ 'state 1 block before : ' +
186
+ JSON.stringify(
187
+ await fluidDexEventPool.generateState(
188
+ await dexHelper.provider.getBlockNumber(),
189
+ ),
190
+ replacer,
191
+ 2,
192
+ ),
193
+ );
194
+
195
+ const allowanceTxn = await ts.simulate({
196
+ from: '0x3c22ec75ea5d745c78fc84762f7f1e6d82a2c5bf',
197
+ to: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', // undefined in case of contract deployment
198
+ value: '0',
199
+ data: '0x095ea7b30000000000000000000000006a000f20005980200259b80c51020030400010680000000000000000000000000000000000000000000000056bc75e2d63100000',
200
+ });
201
+
202
+ console.log(
203
+ 'allowance txn (isSuccess?) : ' + allowanceTxn.success,
204
+ );
205
+
206
+ const swapTxn = await ts.simulate({
207
+ from: '0x3c22ec75ea5d745c78fc84762f7f1e6d82a2c5bf',
208
+ to: '0x6a000f20005980200259b80c5102003040001068', // undefined in case of contract deployment
209
+ value: '0',
210
+ data: '0xe3ead59e000000000000000000000000000010036c0190e009a000d0fc3541100a07380a0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000000000000000000000000000000005af3107a400000000000000000000000000000000000000000000000000000006a6b745e1dd000000000000000000000000000000000000000000000000000006b7ea416a9c0a47d24fdc9fd475bb1cc320a468c050100000000000000000000000001405b6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001807f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000006000000044ff00000000000000000000000000000000000000000000000000000000000000095ea7b30000000000000000000000000b1a513ee24972daef112bc777a5610d4325c9e7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b1a513ee24972daef112bc777a5610d4325c9e7000000a00024000000000007000000000000000000000000000000000000000000000000000000002668dfaa000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000005af3107a400000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006a000f20005980200259b80c5102003040001068',
211
+ });
212
+
213
+ console.log('swap txn (isSuccess?) : ' + swapTxn.success);
214
+
215
+ console.log(
216
+ 'eth balance after : ' +
217
+ (await dexHelper.provider.getBalance(
218
+ '0x3c22ec75ea5d745c78fc84762f7f1e6d82a2c5bf',
219
+ )),
220
+ );
221
+
222
+ // console.log(JSON.stringify(swapTxn));
223
+
224
+ const txnBlockNumber = swapTxn.transaction.block_number;
225
+
226
+ console.log(txnBlockNumber);
227
+ console.log(await dexHelper.provider.getBlockNumber());
228
+
229
+ await delay(30);
230
+
231
+ console.log(
232
+ 'state 1 block before : ' +
233
+ JSON.stringify(
234
+ await fluidDexEventPool.generateState(
235
+ txnBlockNumber - 2,
236
+ ),
237
+ replacer,
238
+ 2,
239
+ ),
240
+ );
241
+ console.log(
242
+ 'state 1 block after : ' +
243
+ JSON.stringify(
244
+ await fluidDexEventPool.generateState(
245
+ await dexHelper.provider.getBlockNumber(),
246
+ ),
247
+ replacer,
248
+ 2,
249
+ ),
250
+ );
251
+ });
252
+ });
253
+ });
254
+ },
255
+ );
256
+ });
257
+ },
258
+ );
259
+
260
+ Object.entries(poolFetchEventsToTest).forEach(
261
+ ([poolAddress, events]: [string, EventMappings]) => {
262
+ describe(`Events for ${poolAddress}`, () => {
263
+ Object.entries(events).forEach(
264
+ ([eventName, blockNumbers]: [string, number[]]) => {
265
+ describe(`${eventName}`, () => {
266
+ blockNumbers.forEach((blockNumber: number) => {
267
+ it(`State after ${blockNumber}`, async function () {
268
+ factory = new FluidDexFactory(
269
+ 'FluidDex',
270
+ fluidDexCommonAddressStruct,
271
+ network,
272
+ dexHelper,
273
+ logger,
274
+ );
275
+
276
+ await testEventSubscriber(
277
+ factory,
278
+ factory.addressesSubscribed,
279
+ (_blockNumber: number) =>
280
+ fetchTotalPools(factory, _blockNumber),
281
+ blockNumber,
282
+ `${dexKey}_${poolAddress}`,
283
+ dexHelper.provider,
284
+ );
285
+ });
286
+ });
287
+ });
288
+ },
289
+ );
290
+ });
291
+ },
292
+ );
293
+ });
@@ -0,0 +1,143 @@
1
+ import { Interface } from '@ethersproject/abi';
2
+ import { BytesLike } from 'ethers/lib/utils';
3
+ import { DeepReadonly } from 'ts-essentials';
4
+ import { Log, Logger } from '../../types';
5
+ import { catchParseLogError } from '../../utils';
6
+ import { StatefulEventSubscriber } from '../../stateful-event-subscriber';
7
+ import { IDexHelper } from '../../dex-helper/idex-helper';
8
+ import ResolverABI from '../../abi/fluid-dex/resolver.abi.json';
9
+ import DexFactoryABI from '../../abi/fluid-dex/dexFactory.abi.json';
10
+ import { CommonAddresses, Pool } from './types';
11
+ import { MultiResult } from '../../lib/multi-wrapper';
12
+ import { Address } from '../../types';
13
+ import { generalDecoder } from '../../lib/decoders';
14
+ import { Contract } from 'ethers';
15
+
16
+ export class FluidDexFactory extends StatefulEventSubscriber<Pool[]> {
17
+ handlers: {
18
+ [event: string]: (
19
+ event: any,
20
+ state: DeepReadonly<Pool[]>,
21
+ log: Readonly<Log>,
22
+ ) => Promise<DeepReadonly<Pool[]> | null>;
23
+ } = {};
24
+
25
+ logDecoder: (log: Log) => any;
26
+
27
+ addressesSubscribed: Address[];
28
+ protected dexFactoryIface = new Interface(DexFactoryABI);
29
+ protected resolverIface = new Interface(ResolverABI);
30
+
31
+ constructor(
32
+ readonly parentName: string,
33
+ readonly commonAddresses: CommonAddresses,
34
+ protected network: number,
35
+ protected dexHelper: IDexHelper,
36
+ logger: Logger,
37
+ ) {
38
+ super(parentName, 'getAllPools', dexHelper, logger);
39
+
40
+ this.logDecoder = (log: Log) => this.dexFactoryIface.parseLog(log);
41
+ this.addressesSubscribed = [commonAddresses.dexFactory];
42
+
43
+ // Add handlers
44
+ this.handlers['DexDeployed'] = this.handleDexDeployed.bind(this);
45
+ }
46
+
47
+ /**
48
+ * Handle a trade rate change on the pool.
49
+ */
50
+ async handleDexDeployed(
51
+ event: any,
52
+ state: DeepReadonly<Pool[]>,
53
+ log: Readonly<Log>,
54
+ ): Promise<DeepReadonly<Pool[]> | null> {
55
+ const blockNumber_ = await this.dexHelper.provider.getBlockNumber();
56
+ return this.getStateOrGenerate(blockNumber_, false);
57
+ }
58
+
59
+ decodePool = (result: MultiResult<BytesLike> | BytesLike): Pool => {
60
+ return generalDecoder(
61
+ result,
62
+ ['tuple(address pool, address token0, address token1, uint256 fee)'],
63
+ undefined,
64
+ decoded => {
65
+ return {
66
+ address: decoded[0].toLowerCase(),
67
+ token0: decoded[1].toLowerCase(),
68
+ token1: decoded[2].toLowerCase(),
69
+ };
70
+ },
71
+ );
72
+ };
73
+
74
+ /**
75
+ * The function is called every time any of the subscribed
76
+ * addresses release log. The function accepts the current
77
+ * state, updates the state according to the log, and returns
78
+ * the updated state.
79
+ * @param state - Current state of event subscriber
80
+ * @param log - Log released by one of the subscribed addresses
81
+ * @returns Updates state of the event subscriber after the log
82
+ */
83
+ async processLog(
84
+ state: DeepReadonly<Pool[]>,
85
+ log: Readonly<Log>,
86
+ ): Promise<DeepReadonly<Pool[]> | null> {
87
+ try {
88
+ let event;
89
+ try {
90
+ event = this.logDecoder(log);
91
+ } catch (e) {
92
+ return null;
93
+ }
94
+ if (event.name in this.handlers) {
95
+ return await this.handlers[event.name](event, state, log);
96
+ }
97
+ } catch (e) {
98
+ catchParseLogError(e, this.logger);
99
+ }
100
+
101
+ return null;
102
+ }
103
+
104
+ async getStateOrGenerate(
105
+ blockNumber: number,
106
+ readonly: boolean = false,
107
+ ): Promise<DeepReadonly<Pool[]>> {
108
+ let state = this.getState(blockNumber);
109
+ if (!state) {
110
+ state = await this.generateState(blockNumber);
111
+ if (!readonly) this.setState(state, blockNumber);
112
+ }
113
+ return state;
114
+ }
115
+
116
+ /**
117
+ * The function generates state using on-chain calls. This
118
+ * function is called to regenerate state if the event based
119
+ * system fails to fetch events and the local state is no
120
+ * more correct.
121
+ * @param blockNumber - Blocknumber for which the state should
122
+ * should be generated
123
+ * @returns state of the event subscriber at blocknumber
124
+ */
125
+ async generateState(blockNumber: number): Promise<DeepReadonly<Pool[]>> {
126
+ const resolverContract = new Contract(
127
+ this.commonAddresses.resolver,
128
+ ResolverABI,
129
+ this.dexHelper.provider,
130
+ );
131
+ const rawResult = await resolverContract.callStatic.getAllPools({
132
+ blockTag: blockNumber,
133
+ });
134
+
135
+ const pools: Pool[] = rawResult.map((result: any) => ({
136
+ address: result[0],
137
+ token0: result[1],
138
+ token1: result[2],
139
+ }));
140
+
141
+ return pools;
142
+ }
143
+ }