@paraswap/dex-lib 2.42.3 → 2.42.4-baseswap

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 (99) hide show
  1. package/build/dex/balancer-v1/balancer-v1.js +21 -10
  2. package/build/dex/balancer-v1/balancer-v1.js.map +1 -1
  3. package/build/dex/balancer-v1/config.d.ts +2 -1
  4. package/build/dex/balancer-v1/config.js +3 -2
  5. package/build/dex/balancer-v1/config.js.map +1 -1
  6. package/build/dex/baseswap-v3/baseswap-v3-factory.d.ts +26 -0
  7. package/build/dex/baseswap-v3/baseswap-v3-factory.js +44 -0
  8. package/build/dex/baseswap-v3/baseswap-v3-factory.js.map +1 -0
  9. package/build/dex/baseswap-v3/baseswap-v3-pool.d.ts +46 -0
  10. package/build/dex/baseswap-v3/baseswap-v3-pool.js +312 -0
  11. package/build/dex/baseswap-v3/baseswap-v3-pool.js.map +1 -0
  12. package/build/dex/baseswap-v3/baseswap-v3.d.ts +71 -0
  13. package/build/dex/baseswap-v3/baseswap-v3.js +752 -0
  14. package/build/dex/baseswap-v3/baseswap-v3.js.map +1 -0
  15. package/build/dex/baseswap-v3/config.d.ts +9 -0
  16. package/build/dex/baseswap-v3/config.js +48 -0
  17. package/build/dex/baseswap-v3/config.js.map +1 -0
  18. package/build/dex/baseswap-v3/constants.d.ts +28 -0
  19. package/build/dex/baseswap-v3/constants.js +35 -0
  20. package/build/dex/baseswap-v3/constants.js.map +1 -0
  21. package/build/dex/baseswap-v3/contract-math/BitMath.d.ts +4 -0
  22. package/build/dex/baseswap-v3/contract-math/BitMath.js +93 -0
  23. package/build/dex/baseswap-v3/contract-math/BitMath.js.map +1 -0
  24. package/build/dex/baseswap-v3/contract-math/FixedPoint128.d.ts +3 -0
  25. package/build/dex/baseswap-v3/contract-math/FixedPoint128.js +8 -0
  26. package/build/dex/baseswap-v3/contract-math/FixedPoint128.js.map +1 -0
  27. package/build/dex/baseswap-v3/contract-math/FixedPoint96.d.ts +4 -0
  28. package/build/dex/baseswap-v3/contract-math/FixedPoint96.js +9 -0
  29. package/build/dex/baseswap-v3/contract-math/FixedPoint96.js.map +1 -0
  30. package/build/dex/baseswap-v3/contract-math/FullMath.d.ts +4 -0
  31. package/build/dex/baseswap-v3/contract-math/FullMath.js +19 -0
  32. package/build/dex/baseswap-v3/contract-math/FullMath.js.map +1 -0
  33. package/build/dex/baseswap-v3/contract-math/LiquidityMath.d.ts +3 -0
  34. package/build/dex/baseswap-v3/contract-math/LiquidityMath.js +22 -0
  35. package/build/dex/baseswap-v3/contract-math/LiquidityMath.js.map +1 -0
  36. package/build/dex/baseswap-v3/contract-math/Oracle.d.ts +10 -0
  37. package/build/dex/baseswap-v3/contract-math/Oracle.js +133 -0
  38. package/build/dex/baseswap-v3/contract-math/Oracle.js.map +1 -0
  39. package/build/dex/baseswap-v3/contract-math/SqrtPriceMath.d.ts +10 -0
  40. package/build/dex/baseswap-v3/contract-math/SqrtPriceMath.js +91 -0
  41. package/build/dex/baseswap-v3/contract-math/SqrtPriceMath.js.map +1 -0
  42. package/build/dex/baseswap-v3/contract-math/SwapMath.d.ts +8 -0
  43. package/build/dex/baseswap-v3/contract-math/SwapMath.js +70 -0
  44. package/build/dex/baseswap-v3/contract-math/SwapMath.js.map +1 -0
  45. package/build/dex/baseswap-v3/contract-math/Tick.d.ts +7 -0
  46. package/build/dex/baseswap-v3/contract-math/Tick.js +45 -0
  47. package/build/dex/baseswap-v3/contract-math/Tick.js.map +1 -0
  48. package/build/dex/baseswap-v3/contract-math/TickBitMap.d.ts +7 -0
  49. package/build/dex/baseswap-v3/contract-math/TickBitMap.js +84 -0
  50. package/build/dex/baseswap-v3/contract-math/TickBitMap.js.map +1 -0
  51. package/build/dex/baseswap-v3/contract-math/TickMath.d.ts +8 -0
  52. package/build/dex/baseswap-v3/contract-math/TickMath.js +162 -0
  53. package/build/dex/baseswap-v3/contract-math/TickMath.js.map +1 -0
  54. package/build/dex/baseswap-v3/contract-math/UnsafeMath.d.ts +3 -0
  55. package/build/dex/baseswap-v3/contract-math/UnsafeMath.js +10 -0
  56. package/build/dex/baseswap-v3/contract-math/UnsafeMath.js.map +1 -0
  57. package/build/dex/baseswap-v3/contract-math/uniswap-v3-math.d.ts +37 -0
  58. package/build/dex/baseswap-v3/contract-math/uniswap-v3-math.js +393 -0
  59. package/build/dex/baseswap-v3/contract-math/uniswap-v3-math.js.map +1 -0
  60. package/build/dex/baseswap-v3/contract-math/utils.d.ts +7 -0
  61. package/build/dex/baseswap-v3/contract-math/utils.js +42 -0
  62. package/build/dex/baseswap-v3/contract-math/utils.js.map +1 -0
  63. package/build/dex/baseswap-v3/types.d.ts +164 -0
  64. package/build/dex/baseswap-v3/types.js +9 -0
  65. package/build/dex/baseswap-v3/types.js.map +1 -0
  66. package/build/dex/baseswap-v3/utils.d.ts +6 -0
  67. package/build/dex/baseswap-v3/utils.js +65 -0
  68. package/build/dex/baseswap-v3/utils.js.map +1 -0
  69. package/build/dex/index.js +2 -0
  70. package/build/dex/index.js.map +1 -1
  71. package/package.json +1 -1
  72. package/src/dex/balancer-v1/balancer-v1.ts +32 -13
  73. package/src/dex/balancer-v1/config.ts +2 -1
  74. package/src/dex/baseswap-v3/baseswap-v3-e2e.test.ts +129 -0
  75. package/src/dex/baseswap-v3/baseswap-v3-events.test.ts +141 -0
  76. package/src/dex/baseswap-v3/baseswap-v3-factory.ts +73 -0
  77. package/src/dex/baseswap-v3/baseswap-v3-integration.test.ts +472 -0
  78. package/src/dex/baseswap-v3/baseswap-v3-pool.ts +519 -0
  79. package/src/dex/baseswap-v3/baseswap-v3.ts +1243 -0
  80. package/src/dex/baseswap-v3/config.ts +53 -0
  81. package/src/dex/baseswap-v3/constants.ts +41 -0
  82. package/src/dex/baseswap-v3/contract-math/BitMath.ts +90 -0
  83. package/src/dex/baseswap-v3/contract-math/FixedPoint128.ts +3 -0
  84. package/src/dex/baseswap-v3/contract-math/FixedPoint96.ts +4 -0
  85. package/src/dex/baseswap-v3/contract-math/FullMath.ts +30 -0
  86. package/src/dex/baseswap-v3/contract-math/LiquidityMath.ts +17 -0
  87. package/src/dex/baseswap-v3/contract-math/Oracle.ts +226 -0
  88. package/src/dex/baseswap-v3/contract-math/SqrtPriceMath.ts +226 -0
  89. package/src/dex/baseswap-v3/contract-math/SwapMath.ts +139 -0
  90. package/src/dex/baseswap-v3/contract-math/Tick.ts +82 -0
  91. package/src/dex/baseswap-v3/contract-math/TickBitMap.ts +123 -0
  92. package/src/dex/baseswap-v3/contract-math/TickMath.ts +211 -0
  93. package/src/dex/baseswap-v3/contract-math/UnsafeMath.ts +5 -0
  94. package/src/dex/baseswap-v3/contract-math/uniswap-v3-math.ts +666 -0
  95. package/src/dex/baseswap-v3/contract-math/utils.ts +55 -0
  96. package/src/dex/baseswap-v3/types.ts +191 -0
  97. package/src/dex/baseswap-v3/utils.ts +83 -0
  98. package/src/dex/index.ts +2 -0
  99. package/tests/constants-e2e.ts +1 -1
@@ -0,0 +1,519 @@
1
+ import _ from 'lodash';
2
+ import { Contract } from 'web3-eth-contract';
3
+ import { Interface } from '@ethersproject/abi';
4
+ import { ethers } from 'ethers';
5
+ import { assert, DeepReadonly } from 'ts-essentials';
6
+ import { Log, Logger, BlockHeader, Address } from '../../types';
7
+ import {
8
+ InitializeStateOptions,
9
+ StatefulEventSubscriber,
10
+ } from '../../stateful-event-subscriber';
11
+ import { IDexHelper } from '../../dex-helper/idex-helper';
12
+ import {
13
+ PoolState,
14
+ DecodedStateMultiCallResultWithRelativeBitmaps,
15
+ DecodeStateMultiCallFunc,
16
+ } from './types';
17
+ import UniswapV3PoolABI from '../../abi/uniswap-v3/UniswapV3Pool.abi.json';
18
+ import { bigIntify, catchParseLogError, isSampled } from '../../utils';
19
+ import { uniswapV3Math } from './contract-math/uniswap-v3-math';
20
+ import { MultiCallParams } from '../../lib/multi-wrapper';
21
+ import {
22
+ OUT_OF_RANGE_ERROR_POSTFIX,
23
+ TICK_BITMAP_BUFFER,
24
+ TICK_BITMAP_TO_USE,
25
+ } from './constants';
26
+ import { TickBitMap } from './contract-math/TickBitMap';
27
+ import { uint256ToBigInt } from '../../lib/decoders';
28
+ import { decodeStateMultiCallResultWithRelativeBitmaps } from './utils';
29
+ import { _reduceTickBitmap, _reduceTicks } from './contract-math/utils';
30
+
31
+ export class BaseswapV3EventPool extends StatefulEventSubscriber<PoolState> {
32
+ handlers: {
33
+ [event: string]: (
34
+ event: any,
35
+ pool: PoolState,
36
+ log: Log,
37
+ blockHeader: Readonly<BlockHeader>,
38
+ ) => PoolState;
39
+ } = {};
40
+
41
+ logDecoder: (log: Log) => any;
42
+
43
+ readonly token0: Address;
44
+
45
+ readonly token1: Address;
46
+
47
+ private _poolAddress?: Address;
48
+
49
+ protected _stateRequestCallData?: MultiCallParams<
50
+ bigint | DecodedStateMultiCallResultWithRelativeBitmaps
51
+ >[];
52
+
53
+ public readonly poolIface = new Interface(UniswapV3PoolABI);
54
+
55
+ public initFailed = false;
56
+ public initRetryAttemptCount = 0;
57
+
58
+ public feeCodeAsString;
59
+
60
+ constructor(
61
+ readonly dexHelper: IDexHelper,
62
+ parentName: string,
63
+ readonly stateMultiContract: Contract,
64
+ readonly decodeStateMultiCallResultWithRelativeBitmaps:
65
+ | DecodeStateMultiCallFunc
66
+ | undefined,
67
+ readonly erc20Interface: Interface,
68
+ protected readonly factoryAddress: Address,
69
+ public feeCode: bigint,
70
+ token0: Address,
71
+ token1: Address,
72
+ logger: Logger,
73
+ mapKey: string = '',
74
+ readonly poolInitCodeHash: string,
75
+ ) {
76
+ super(
77
+ parentName,
78
+ `${token0}_${token1}_${feeCode}`,
79
+ dexHelper,
80
+ logger,
81
+ true,
82
+ mapKey,
83
+ );
84
+ this.feeCodeAsString = feeCode.toString();
85
+ this.token0 = token0.toLowerCase();
86
+ this.token1 = token1.toLowerCase();
87
+ this.logDecoder = (log: Log) => this.poolIface.parseLog(log);
88
+ this.addressesSubscribed = new Array<Address>(1);
89
+
90
+ // Add handlers
91
+ this.handlers['Swap'] = this.handleSwapEvent.bind(this);
92
+ this.handlers['Burn'] = this.handleBurnEvent.bind(this);
93
+ this.handlers['Mint'] = this.handleMintEvent.bind(this);
94
+ this.handlers['SetFeeProtocol'] = this.handleSetFeeProtocolEvent.bind(this);
95
+ this.handlers['IncreaseObservationCardinalityNext'] =
96
+ this.handleIncreaseObservationCardinalityNextEvent.bind(this);
97
+
98
+ // Wen need them to keep balance of the pool up to date
99
+ this.handlers['Collect'] = this.handleCollectEvent.bind(this);
100
+ // Almost the same as Collect, but for pool owners
101
+ this.handlers['CollectProtocol'] = this.handleCollectEvent.bind(this);
102
+ this.handlers['Flash'] = this.handleFlashEvent.bind(this);
103
+ }
104
+
105
+ get poolAddress() {
106
+ if (this._poolAddress === undefined) {
107
+ this._poolAddress = this._computePoolAddress(
108
+ this.token0,
109
+ this.token1,
110
+ this.feeCode,
111
+ );
112
+ }
113
+ return this._poolAddress;
114
+ }
115
+
116
+ set poolAddress(address: Address) {
117
+ this._poolAddress = address.toLowerCase();
118
+ }
119
+
120
+ async initialize(
121
+ blockNumber: number,
122
+ options?: InitializeStateOptions<PoolState>,
123
+ ) {
124
+ await super.initialize(blockNumber, options);
125
+ }
126
+
127
+ protected async processBlockLogs(
128
+ state: DeepReadonly<PoolState>,
129
+ logs: Readonly<Log>[],
130
+ blockHeader: Readonly<BlockHeader>,
131
+ ): Promise<DeepReadonly<PoolState> | null> {
132
+ const newState = await super.processBlockLogs(state, logs, blockHeader);
133
+ if (newState && !newState.isValid) {
134
+ return await this.generateState(blockHeader.number);
135
+ }
136
+ return newState;
137
+ }
138
+
139
+ protected processLog(
140
+ state: DeepReadonly<PoolState>,
141
+ log: Readonly<Log>,
142
+ blockHeader: Readonly<BlockHeader>,
143
+ ): DeepReadonly<PoolState> | null {
144
+ try {
145
+ const event = this.logDecoder(log);
146
+
147
+ const uniswapV3EventLoggingSampleRate =
148
+ this.dexHelper.config.data.uniswapV3EventLoggingSampleRate;
149
+ if (
150
+ !this.dexHelper.config.isSlave &&
151
+ uniswapV3EventLoggingSampleRate &&
152
+ isSampled(uniswapV3EventLoggingSampleRate)
153
+ ) {
154
+ this.logger.info(
155
+ `event=${event.name} - block=${
156
+ blockHeader.number
157
+ }. Log sampled at rate ${uniswapV3EventLoggingSampleRate * 100}%`,
158
+ );
159
+ }
160
+
161
+ if (event.name in this.handlers) {
162
+ // Because we have observations in array which is mutable by nature, there is a
163
+ // ts compile error: https://stackoverflow.com/questions/53412934/disable-allowing-assigning-readonly-types-to-non-readonly-types
164
+ // And there is no good workaround, so turn off the type checker for this line
165
+ const _state = _.cloneDeep(state) as PoolState;
166
+ try {
167
+ return this.handlers[event.name](event, _state, log, blockHeader);
168
+ } catch (e) {
169
+ if (
170
+ e instanceof Error &&
171
+ e.message.endsWith(OUT_OF_RANGE_ERROR_POSTFIX)
172
+ ) {
173
+ this.logger.warn(
174
+ `${this.parentName}: Pool ${this.poolAddress} on ${
175
+ this.dexHelper.config.data.network
176
+ } is out of TickBitmap requested range. Re-query the state. ${JSON.stringify(
177
+ event,
178
+ )}`,
179
+ e,
180
+ );
181
+ } else {
182
+ this.logger.error(
183
+ `${this.parentName}: Pool ${this.poolAddress}, ` +
184
+ `network=${this.dexHelper.config.data.network}: Unexpected ` +
185
+ `error while handling event on blockNumber=${blockHeader.number}, ` +
186
+ `blockHash=${blockHeader.hash} and parentHash=${
187
+ blockHeader.parentHash
188
+ } for UniswapV3, ${JSON.stringify(event)}`,
189
+ e,
190
+ );
191
+ }
192
+ _state.isValid = false;
193
+ return _state;
194
+ }
195
+ }
196
+ } catch (e) {
197
+ catchParseLogError(e, this.logger);
198
+ }
199
+ return null; // ignore unrecognized event
200
+ }
201
+
202
+ protected _getStateRequestCallData() {
203
+ if (!this._stateRequestCallData) {
204
+ const callData: MultiCallParams<
205
+ bigint | DecodedStateMultiCallResultWithRelativeBitmaps
206
+ >[] = [
207
+ {
208
+ target: this.token0,
209
+ callData: this.erc20Interface.encodeFunctionData('balanceOf', [
210
+ this.poolAddress,
211
+ ]),
212
+ decodeFunction: uint256ToBigInt,
213
+ },
214
+ {
215
+ target: this.token1,
216
+ callData: this.erc20Interface.encodeFunctionData('balanceOf', [
217
+ this.poolAddress,
218
+ ]),
219
+ decodeFunction: uint256ToBigInt,
220
+ },
221
+ {
222
+ target: this.stateMultiContract.options.address,
223
+ callData: this.stateMultiContract.methods
224
+ .getFullStateWithRelativeBitmaps(
225
+ this.factoryAddress,
226
+ this.token0,
227
+ this.token1,
228
+ this.feeCode,
229
+ this.getBitmapRangeToRequest(),
230
+ this.getBitmapRangeToRequest(),
231
+ )
232
+ .encodeABI(),
233
+ decodeFunction:
234
+ this.decodeStateMultiCallResultWithRelativeBitmaps !== undefined
235
+ ? this.decodeStateMultiCallResultWithRelativeBitmaps
236
+ : decodeStateMultiCallResultWithRelativeBitmaps,
237
+ },
238
+ ];
239
+
240
+ this._stateRequestCallData = callData;
241
+ }
242
+ return this._stateRequestCallData;
243
+ }
244
+
245
+ getBitmapRangeToRequest() {
246
+ return TICK_BITMAP_TO_USE + TICK_BITMAP_BUFFER;
247
+ }
248
+
249
+ async generateState(blockNumber: number): Promise<Readonly<PoolState>> {
250
+ const callData = this._getStateRequestCallData();
251
+
252
+ const [resBalance0, resBalance1, resState] =
253
+ await this.dexHelper.multiWrapper.tryAggregate<
254
+ bigint | DecodedStateMultiCallResultWithRelativeBitmaps
255
+ >(
256
+ false,
257
+ callData,
258
+ blockNumber,
259
+ this.dexHelper.multiWrapper.defaultBatchSize,
260
+ false,
261
+ );
262
+
263
+ // Quite ugly solution, but this is the one that fits to current flow.
264
+ // I think UniswapV3 callbacks subscriptions are complexified for no reason.
265
+ // Need to be revisited later
266
+ assert(resState.success, 'Pool does not exist');
267
+
268
+ const [balance0, balance1, _state] = [
269
+ resBalance0.returnData,
270
+ resBalance1.returnData,
271
+ resState.returnData,
272
+ ] as [bigint, bigint, DecodedStateMultiCallResultWithRelativeBitmaps];
273
+
274
+ const tickBitmap = {};
275
+ const ticks = {};
276
+
277
+ _reduceTickBitmap(tickBitmap, _state.tickBitmap);
278
+ _reduceTicks(ticks, _state.ticks);
279
+
280
+ const observations = {
281
+ [_state.slot0.observationIndex]: {
282
+ blockTimestamp: bigIntify(_state.observation.blockTimestamp),
283
+ tickCumulative: bigIntify(_state.observation.tickCumulative),
284
+ secondsPerLiquidityCumulativeX128: bigIntify(
285
+ _state.observation.secondsPerLiquidityCumulativeX128,
286
+ ),
287
+ initialized: _state.observation.initialized,
288
+ },
289
+ };
290
+
291
+ const currentTick = bigIntify(_state.slot0.tick);
292
+ const tickSpacing = bigIntify(_state.tickSpacing);
293
+
294
+ const startTickBitmap = TickBitMap.position(currentTick / tickSpacing)[0];
295
+ const requestedRange = this.getBitmapRangeToRequest();
296
+
297
+ return {
298
+ pool: _state.pool,
299
+ blockTimestamp: bigIntify(_state.blockTimestamp),
300
+ slot0: {
301
+ sqrtPriceX96: bigIntify(_state.slot0.sqrtPriceX96),
302
+ tick: currentTick,
303
+ observationIndex: +_state.slot0.observationIndex,
304
+ observationCardinality: +_state.slot0.observationCardinality,
305
+ observationCardinalityNext: +_state.slot0.observationCardinalityNext,
306
+ feeProtocol: bigIntify(_state.slot0.feeProtocol),
307
+ },
308
+ liquidity: bigIntify(_state.liquidity),
309
+ fee: this.feeCode,
310
+ tickSpacing,
311
+ maxLiquidityPerTick: bigIntify(_state.maxLiquidityPerTick),
312
+ tickBitmap,
313
+ ticks,
314
+ observations,
315
+ isValid: true,
316
+ startTickBitmap,
317
+ lowestKnownTick:
318
+ (BigInt.asIntN(24, startTickBitmap - requestedRange) << 8n) *
319
+ tickSpacing,
320
+ highestKnownTick:
321
+ ((BigInt.asIntN(24, startTickBitmap + requestedRange) << 8n) +
322
+ BigInt.asIntN(24, 255n)) *
323
+ tickSpacing,
324
+ balance0,
325
+ balance1,
326
+ };
327
+ }
328
+
329
+ handleSwapEvent(
330
+ event: any,
331
+ pool: PoolState,
332
+ log: Log,
333
+ blockHeader: BlockHeader,
334
+ ) {
335
+ const newSqrtPriceX96 = bigIntify(event.args.sqrtPriceX96);
336
+ const amount0 = bigIntify(event.args.amount0);
337
+ const amount1 = bigIntify(event.args.amount1);
338
+ const newTick = bigIntify(event.args.tick);
339
+ const newLiquidity = bigIntify(event.args.liquidity);
340
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
341
+
342
+ if (amount0 <= 0n && amount1 <= 0n) {
343
+ this.logger.error(
344
+ `${this.parentName}: amount0 <= 0n && amount1 <= 0n for ` +
345
+ `${this.poolAddress} and ${blockHeader.number}. Check why it happened`,
346
+ );
347
+ pool.isValid = false;
348
+ return pool;
349
+ } else {
350
+ const zeroForOne = amount0 > 0n;
351
+
352
+ uniswapV3Math.swapFromEvent(
353
+ pool,
354
+ newSqrtPriceX96,
355
+ newTick,
356
+ newLiquidity,
357
+ zeroForOne,
358
+ );
359
+
360
+ if (zeroForOne) {
361
+ if (amount1 < 0n) {
362
+ pool.balance1 -= BigInt.asUintN(256, -amount1);
363
+ } else {
364
+ this.logger.error(
365
+ `In swapEvent for pool ${pool.pool} received incorrect values ${zeroForOne} and ${amount1}`,
366
+ );
367
+ pool.isValid = false;
368
+ }
369
+ // This is not correct fully, because pool may get more tokens then it needs, but
370
+ // it is not accounted in internal state, it should be good enough
371
+ pool.balance0 += BigInt.asUintN(256, amount0);
372
+ } else {
373
+ if (amount0 < 0n) {
374
+ pool.balance0 -= BigInt.asUintN(256, -amount0);
375
+ } else {
376
+ this.logger.error(
377
+ `In swapEvent for pool ${pool.pool} received incorrect values ${zeroForOne} and ${amount0}`,
378
+ );
379
+ pool.isValid = false;
380
+ }
381
+ pool.balance1 += BigInt.asUintN(256, amount1);
382
+ }
383
+
384
+ return pool;
385
+ }
386
+ }
387
+
388
+ handleBurnEvent(
389
+ event: any,
390
+ pool: PoolState,
391
+ log: Log,
392
+ blockHeader: BlockHeader,
393
+ ) {
394
+ const amount = bigIntify(event.args.amount);
395
+ const tickLower = bigIntify(event.args.tickLower);
396
+ const tickUpper = bigIntify(event.args.tickUpper);
397
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
398
+
399
+ uniswapV3Math._modifyPosition(pool, {
400
+ tickLower,
401
+ tickUpper,
402
+ liquidityDelta: -BigInt.asIntN(128, BigInt.asIntN(256, amount)),
403
+ });
404
+
405
+ // From this transaction I conclude that there is no balance change from
406
+ // Burn event: https://dashboard.tenderly.co/tx/mainnet/0xfccf5341147ac3ad0e66452273d12dfc3219e81f8fb369a6cdecfb24b9b9d078/logs
407
+ // And it aligns with UniswapV3 doc:
408
+ // https://github.com/Uniswap/v3-core/blob/05c10bf6d547d6121622ac51c457f93775e1df09/contracts/interfaces/pool/IUniswapV3PoolActions.sol#L59
409
+ // It just updates positions and tokensOwed which may be requested calling collect
410
+ // So, we don't need to update pool.balances0 and pool.balances1 here
411
+
412
+ return pool;
413
+ }
414
+
415
+ handleMintEvent(
416
+ event: any,
417
+ pool: PoolState,
418
+ log: Log,
419
+ blockHeader: BlockHeader,
420
+ ) {
421
+ const amount = bigIntify(event.args.amount);
422
+ const tickLower = bigIntify(event.args.tickLower);
423
+ const tickUpper = bigIntify(event.args.tickUpper);
424
+ const amount0 = bigIntify(event.args.amount0);
425
+ const amount1 = bigIntify(event.args.amount1);
426
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
427
+
428
+ uniswapV3Math._modifyPosition(pool, {
429
+ tickLower,
430
+ tickUpper,
431
+ liquidityDelta: amount,
432
+ });
433
+
434
+ pool.balance0 += amount0;
435
+ pool.balance1 += amount1;
436
+
437
+ return pool;
438
+ }
439
+
440
+ handleSetFeeProtocolEvent(
441
+ event: any,
442
+ pool: PoolState,
443
+ log: Log,
444
+ blockHeader: BlockHeader,
445
+ ) {
446
+ const feeProtocol0 = bigIntify(event.args.feeProtocol0New);
447
+ const feeProtocol1 = bigIntify(event.args.feeProtocol1New);
448
+ pool.slot0.feeProtocol = feeProtocol0 + (feeProtocol1 << 4n);
449
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
450
+
451
+ return pool;
452
+ }
453
+
454
+ handleCollectEvent(
455
+ event: any,
456
+ pool: PoolState,
457
+ log: Log,
458
+ blockHeader: BlockHeader,
459
+ ) {
460
+ const amount0 = bigIntify(event.args.amount0);
461
+ const amount1 = bigIntify(event.args.amount1);
462
+ pool.balance0 -= amount0;
463
+ pool.balance1 -= amount1;
464
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
465
+
466
+ return pool;
467
+ }
468
+
469
+ handleFlashEvent(
470
+ event: any,
471
+ pool: PoolState,
472
+ log: Log,
473
+ blockHeader: BlockHeader,
474
+ ) {
475
+ const paid0 = bigIntify(event.args.paid0);
476
+ const paid1 = bigIntify(event.args.paid1);
477
+ pool.balance0 += paid0;
478
+ pool.balance1 += paid1;
479
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
480
+
481
+ return pool;
482
+ }
483
+
484
+ handleIncreaseObservationCardinalityNextEvent(
485
+ event: any,
486
+ pool: PoolState,
487
+ log: Log,
488
+ blockHeader: BlockHeader,
489
+ ) {
490
+ pool.slot0.observationCardinalityNext = parseInt(
491
+ event.args.observationCardinalityNextNew,
492
+ 10,
493
+ );
494
+ pool.blockTimestamp = bigIntify(blockHeader.timestamp);
495
+ return pool;
496
+ }
497
+
498
+ private _computePoolAddress(
499
+ token0: Address,
500
+ token1: Address,
501
+ fee: bigint,
502
+ ): Address {
503
+ // https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/PoolAddress.sol
504
+ if (token0 > token1) [token0, token1] = [token1, token0];
505
+
506
+ const encodedKey = ethers.utils.keccak256(
507
+ ethers.utils.defaultAbiCoder.encode(
508
+ ['address', 'address', 'uint24'],
509
+ [token0, token1, BigInt.asUintN(24, fee)],
510
+ ),
511
+ );
512
+
513
+ return ethers.utils.getCreate2Address(
514
+ this.factoryAddress,
515
+ encodedKey,
516
+ this.poolInitCodeHash,
517
+ );
518
+ }
519
+ }