@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,570 @@
1
+ import _ from 'lodash';
2
+ import { OutputResult, PoolState, Slot0, TickInfo } from '../types';
3
+ import { LiquidityMath } from './LiquidityMath';
4
+ import { SqrtPriceMath } from './SqrtPriceMath';
5
+ import { SwapMath } from './SwapMath';
6
+ import { Tick } from './Tick';
7
+ import { TickBitMap } from './TickBitMap';
8
+ import { TickMath } from './TickMath';
9
+ import { _require } from '../../../utils';
10
+ import { DeepReadonly } from 'ts-essentials';
11
+ import { NumberAsString, SwapSide } from '@paraswap/core';
12
+ import { BI_MAX_INT } from '../../../bigint-constants';
13
+ import {
14
+ MAX_PRICING_COMPUTATION_STEPS_ALLOWED,
15
+ OUT_OF_RANGE_ERROR_POSTFIX,
16
+ } from '../constants';
17
+
18
+ type ModifyPositionParams = {
19
+ tickLower: bigint;
20
+ tickUpper: bigint;
21
+ liquidityDelta: bigint;
22
+ };
23
+
24
+ export type PriceComputationState = {
25
+ amountSpecifiedRemaining: bigint;
26
+ amountCalculated: bigint;
27
+ sqrtPriceX96: bigint;
28
+ tick: bigint;
29
+ protocolFee: bigint;
30
+ liquidity: bigint;
31
+ isFirstCycleState: boolean;
32
+ };
33
+
34
+ export type PriceComputationCache = {
35
+ tickCount: number;
36
+ };
37
+
38
+ export function _updatePriceComputationObjects<
39
+ T extends PriceComputationState | PriceComputationCache,
40
+ >(toUpdate: T, updateBy: T) {
41
+ for (const k of Object.keys(updateBy) as (keyof T)[]) {
42
+ toUpdate[k] = updateBy[k];
43
+ }
44
+ }
45
+
46
+ function _priceComputationCycles(
47
+ poolState: DeepReadonly<PoolState>,
48
+ ticksCopy: Record<NumberAsString, TickInfo>,
49
+ slot0Start: Slot0,
50
+ state: PriceComputationState,
51
+ cache: PriceComputationCache,
52
+ sqrtPriceLimitX96: bigint,
53
+ zeroForOne: boolean,
54
+ exactInput: boolean,
55
+ ): [
56
+ // result
57
+ PriceComputationState,
58
+ // Latest calculated full cycle state we can use for bigger amounts
59
+ {
60
+ latestFullCycleState: PriceComputationState;
61
+ latestFullCycleCache: PriceComputationCache;
62
+ },
63
+ ] {
64
+ const latestFullCycleState: PriceComputationState = { ...state };
65
+
66
+ if (cache.tickCount == 0) {
67
+ cache.tickCount = 1;
68
+ }
69
+ const latestFullCycleCache: PriceComputationCache = { ...cache };
70
+
71
+ // We save tick before any change. Later we use this to restore
72
+ // state before last step
73
+ let lastTicksCopy: { index: number; tick: TickInfo } | undefined;
74
+
75
+ let i = 0;
76
+ for (
77
+ ;
78
+ state.amountSpecifiedRemaining !== 0n &&
79
+ state.sqrtPriceX96 !== sqrtPriceLimitX96;
80
+ ++i
81
+ ) {
82
+ if (
83
+ latestFullCycleCache.tickCount + i >
84
+ MAX_PRICING_COMPUTATION_STEPS_ALLOWED
85
+ ) {
86
+ state.amountSpecifiedRemaining = 0n;
87
+ state.amountCalculated = 0n;
88
+ break;
89
+ }
90
+
91
+ const step = {
92
+ sqrtPriceStartX96: 0n,
93
+ tickNext: 0n,
94
+ initialized: false,
95
+ sqrtPriceNextX96: 0n,
96
+ amountIn: 0n,
97
+ amountOut: 0n,
98
+ feeAmount: 0n,
99
+ };
100
+
101
+ step.sqrtPriceStartX96 = state.sqrtPriceX96;
102
+
103
+ try {
104
+ [step.tickNext, step.initialized] =
105
+ TickBitMap.nextInitializedTickWithinOneWord(
106
+ poolState,
107
+ state.tick,
108
+ poolState.tickSpacing,
109
+ zeroForOne,
110
+ true,
111
+ );
112
+ } catch (e) {
113
+ if (
114
+ e instanceof Error &&
115
+ e.message.endsWith(OUT_OF_RANGE_ERROR_POSTFIX)
116
+ ) {
117
+ state.amountSpecifiedRemaining = 0n;
118
+ state.amountCalculated = 0n;
119
+ break;
120
+ }
121
+ throw e;
122
+ }
123
+
124
+ if (step.tickNext < TickMath.MIN_TICK) {
125
+ step.tickNext = TickMath.MIN_TICK;
126
+ } else if (step.tickNext > TickMath.MAX_TICK) {
127
+ step.tickNext = TickMath.MAX_TICK;
128
+ }
129
+
130
+ step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
131
+
132
+ const swapStepResult = SwapMath.computeSwapStep(
133
+ state.sqrtPriceX96,
134
+ (
135
+ zeroForOne
136
+ ? step.sqrtPriceNextX96 < sqrtPriceLimitX96
137
+ : step.sqrtPriceNextX96 > sqrtPriceLimitX96
138
+ )
139
+ ? sqrtPriceLimitX96
140
+ : step.sqrtPriceNextX96,
141
+ state.liquidity,
142
+ state.amountSpecifiedRemaining,
143
+ poolState.slot0.fee,
144
+ );
145
+
146
+ state.sqrtPriceX96 = swapStepResult.sqrtRatioNextX96;
147
+ step.amountIn = swapStepResult.amountIn;
148
+ step.amountOut = swapStepResult.amountOut;
149
+ step.feeAmount = swapStepResult.feeAmount;
150
+
151
+ if (exactInput) {
152
+ state.amountSpecifiedRemaining -= step.amountIn + step.feeAmount;
153
+ state.amountCalculated = state.amountCalculated - step.amountOut;
154
+ } else {
155
+ state.amountSpecifiedRemaining += step.amountOut;
156
+ state.amountCalculated =
157
+ state.amountCalculated + step.amountIn + step.feeAmount;
158
+ }
159
+
160
+ if (state.sqrtPriceX96 === step.sqrtPriceNextX96) {
161
+ if (step.initialized) {
162
+
163
+ if (state.amountSpecifiedRemaining === 0n) {
164
+ const castTickNext = Number(step.tickNext);
165
+ lastTicksCopy = {
166
+ index: castTickNext,
167
+ tick: { ...ticksCopy[castTickNext] },
168
+ };
169
+ }
170
+
171
+ let liquidityNet = Tick.cross(
172
+ ticksCopy,
173
+ step.tickNext,
174
+ );
175
+ if (zeroForOne) liquidityNet = -liquidityNet;
176
+
177
+ state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet);
178
+ }
179
+
180
+ state.tick = zeroForOne ? step.tickNext - 1n : step.tickNext;
181
+ } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) {
182
+ state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
183
+ }
184
+
185
+ if (state.amountSpecifiedRemaining !== 0n) {
186
+ _updatePriceComputationObjects(latestFullCycleState, state);
187
+ _updatePriceComputationObjects(latestFullCycleCache, cache);
188
+ // If it last cycle, check if ticks were changed and then restore previous state
189
+ // for next calculations
190
+ } else if (lastTicksCopy !== undefined) {
191
+ ticksCopy[lastTicksCopy.index] = lastTicksCopy.tick;
192
+ }
193
+ }
194
+
195
+ if (i > 1) {
196
+ latestFullCycleCache.tickCount += i - 1;
197
+ }
198
+
199
+ if (state.amountSpecifiedRemaining !== 0n) {
200
+ state.amountSpecifiedRemaining = 0n;
201
+ state.amountCalculated = 0n;
202
+ }
203
+
204
+ return [state, { latestFullCycleState, latestFullCycleCache }];
205
+ }
206
+
207
+ class UniswapV3Math {
208
+ queryOutputs(
209
+ poolState: DeepReadonly<PoolState>,
210
+ // Amounts must increase
211
+ amounts: bigint[],
212
+ zeroForOne: boolean,
213
+ side: SwapSide,
214
+ ): OutputResult {
215
+ const slot0Start = poolState.slot0;
216
+
217
+ const isSell = side === SwapSide.SELL;
218
+
219
+ // While calculating, ticks are changing, so to not change the actual state,
220
+ // we use copy
221
+ const ticksCopy = _.cloneDeep(poolState.ticks);
222
+
223
+ const sqrtPriceLimitX96 = zeroForOne
224
+ ? TickMath.MIN_SQRT_RATIO + 1n
225
+ : TickMath.MAX_SQRT_RATIO - 1n;
226
+
227
+ const cache: PriceComputationCache = {
228
+ tickCount: 0,
229
+ };
230
+
231
+ const state: PriceComputationState = {
232
+ // Will be overwritten later
233
+ amountSpecifiedRemaining: 0n,
234
+ amountCalculated: 0n,
235
+ sqrtPriceX96: slot0Start.sqrtPriceX96,
236
+ tick: slot0Start.tick,
237
+ protocolFee: 0n,
238
+ liquidity: poolState.liquidity,
239
+ isFirstCycleState: true,
240
+ };
241
+
242
+ let isOutOfRange = false;
243
+ let previousAmount = 0n;
244
+
245
+ const outputs = new Array(amounts.length);
246
+ const tickCounts = new Array(amounts.length);
247
+ for (const [i, amount] of amounts.entries()) {
248
+ if (amount === 0n) {
249
+ outputs[i] = 0n;
250
+ tickCounts[i] = 0;
251
+ continue;
252
+ }
253
+
254
+ const amountSpecified = isSell
255
+ ? BigInt.asIntN(256, amount)
256
+ : -BigInt.asIntN(256, amount);
257
+
258
+ if (state.isFirstCycleState) {
259
+ // Set first non zero amount
260
+ state.amountSpecifiedRemaining = amountSpecified;
261
+ state.isFirstCycleState = false;
262
+ } else {
263
+ state.amountSpecifiedRemaining =
264
+ amountSpecified - (previousAmount - state.amountSpecifiedRemaining);
265
+ }
266
+
267
+ const exactInput = amountSpecified > 0n;
268
+
269
+ _require(
270
+ zeroForOne
271
+ ? sqrtPriceLimitX96 < slot0Start.sqrtPriceX96 &&
272
+ sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO
273
+ : sqrtPriceLimitX96 > slot0Start.sqrtPriceX96 &&
274
+ sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO,
275
+ 'SPL',
276
+ { zeroForOne, sqrtPriceLimitX96, slot0Start },
277
+ 'zeroForOne ? sqrtPriceLimitX96 < slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO : sqrtPriceLimitX96 > slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO',
278
+ );
279
+
280
+ if (!isOutOfRange) {
281
+ const [finalState, { latestFullCycleState, latestFullCycleCache }] =
282
+ _priceComputationCycles(
283
+ poolState,
284
+ ticksCopy,
285
+ slot0Start,
286
+ state,
287
+ cache,
288
+ sqrtPriceLimitX96,
289
+ zeroForOne,
290
+ exactInput,
291
+ );
292
+ if (
293
+ finalState.amountSpecifiedRemaining === 0n &&
294
+ finalState.amountCalculated === 0n
295
+ ) {
296
+ isOutOfRange = true;
297
+ outputs[i] = 0n;
298
+ tickCounts[i] = 0;
299
+ continue;
300
+ }
301
+
302
+ // We use it on next step to correct state.amountSpecifiedRemaining
303
+ previousAmount = amountSpecified;
304
+
305
+ // First extract calculated values
306
+ const [amount0, amount1] =
307
+ zeroForOne === exactInput
308
+ ? [
309
+ amountSpecified - finalState.amountSpecifiedRemaining,
310
+ finalState.amountCalculated,
311
+ ]
312
+ : [
313
+ finalState.amountCalculated,
314
+ amountSpecified - finalState.amountSpecifiedRemaining,
315
+ ];
316
+
317
+ // Update for next amount
318
+ _updatePriceComputationObjects(state, latestFullCycleState);
319
+ _updatePriceComputationObjects(cache, latestFullCycleCache);
320
+
321
+ if (isSell) {
322
+ outputs[i] = BigInt.asUintN(256, -(zeroForOne ? amount1 : amount0));
323
+ tickCounts[i] = latestFullCycleCache.tickCount;
324
+ continue;
325
+ } else {
326
+ outputs[i] = zeroForOne
327
+ ? BigInt.asUintN(256, amount0)
328
+ : BigInt.asUintN(256, amount1);
329
+ tickCounts[i] = latestFullCycleCache.tickCount;
330
+ continue;
331
+ }
332
+ } else {
333
+ outputs[i] = 0n;
334
+ tickCounts[i] = 0;
335
+ }
336
+ }
337
+
338
+ return {
339
+ outputs,
340
+ tickCounts,
341
+ };
342
+ }
343
+
344
+ swapFromEvent(
345
+ poolState: PoolState,
346
+ newSqrtPriceX96: bigint,
347
+ newTick: bigint,
348
+ newLiquidity: bigint,
349
+ zeroForOne: boolean,
350
+ ): void {
351
+ const slot0Start = poolState.slot0;
352
+
353
+ const cache = {
354
+ liquidityStart: poolState.liquidity,
355
+ blockTimestamp: this._blockTimestamp(poolState),
356
+ feeProtocol: 0n,
357
+ secondsPerLiquidityCumulativeX128: 0n,
358
+ tickCumulative: 0n,
359
+ computedLatestObservation: false,
360
+ };
361
+
362
+ const state = {
363
+ // Because I don't have the exact amount user used, set this number to MAX_NUMBER to proceed
364
+ // with calculations. I think it is not a problem since in loop I don't rely on this value
365
+ amountSpecifiedRemaining: BI_MAX_INT,
366
+ amountCalculated: 0n,
367
+ sqrtPriceX96: slot0Start.sqrtPriceX96,
368
+ tick: slot0Start.tick,
369
+ protocolFee: 0n,
370
+ liquidity: cache.liquidityStart,
371
+ };
372
+
373
+ // Because I didn't have all variables, adapted loop stop with state.tick !== newTick
374
+ // condition. This cycle need only to calculate Tick.cross() function values
375
+ // It means that we are interested in cycling only if state.tick !== newTick
376
+ // When they become equivalent, we proceed with state updating part as normal
377
+ // And if assumptions regarding this cycle are correct, we don't need to process
378
+ // the last cycle when state.tick === newTick
379
+ while (state.tick !== newTick && state.sqrtPriceX96 !== newSqrtPriceX96) {
380
+ const step = {
381
+ sqrtPriceStartX96: 0n,
382
+ tickNext: 0n,
383
+ initialized: false,
384
+ sqrtPriceNextX96: 0n,
385
+ amountIn: 0n,
386
+ amountOut: 0n,
387
+ feeAmount: 0n,
388
+ };
389
+
390
+ step.sqrtPriceStartX96 = state.sqrtPriceX96;
391
+
392
+ [step.tickNext, step.initialized] =
393
+ TickBitMap.nextInitializedTickWithinOneWord(
394
+ poolState,
395
+ state.tick,
396
+ poolState.tickSpacing,
397
+ zeroForOne,
398
+ false,
399
+ );
400
+
401
+ if (step.tickNext < TickMath.MIN_TICK) {
402
+ step.tickNext = TickMath.MIN_TICK;
403
+ } else if (step.tickNext > TickMath.MAX_TICK) {
404
+ step.tickNext = TickMath.MAX_TICK;
405
+ }
406
+
407
+ step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
408
+
409
+ const swapStepResult = SwapMath.computeSwapStep(
410
+ state.sqrtPriceX96,
411
+ (
412
+ zeroForOne
413
+ ? step.sqrtPriceNextX96 < newSqrtPriceX96
414
+ : step.sqrtPriceNextX96 > newSqrtPriceX96
415
+ )
416
+ ? newSqrtPriceX96
417
+ : step.sqrtPriceNextX96,
418
+ state.liquidity,
419
+ state.amountSpecifiedRemaining,
420
+ poolState.slot0.fee,
421
+ );
422
+
423
+ state.sqrtPriceX96 = swapStepResult.sqrtRatioNextX96;
424
+
425
+ if (state.sqrtPriceX96 == step.sqrtPriceNextX96) {
426
+ if (step.initialized) {
427
+
428
+ let liquidityNet = Tick.cross(
429
+ poolState.ticks,
430
+ step.tickNext,
431
+ );
432
+
433
+ if (zeroForOne) liquidityNet = -liquidityNet;
434
+
435
+ state.liquidity = LiquidityMath.addDelta(
436
+ state.liquidity,
437
+ liquidityNet,
438
+ );
439
+ }
440
+
441
+ state.tick = zeroForOne ? step.tickNext - 1n : step.tickNext;
442
+ } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) {
443
+ state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
444
+ }
445
+ }
446
+
447
+ if (slot0Start.tick !== newTick) {
448
+ [
449
+ poolState.slot0.sqrtPriceX96,
450
+ poolState.slot0.tick,
451
+ ] = [newSqrtPriceX96, newTick];
452
+ } else {
453
+ poolState.slot0.sqrtPriceX96 = newSqrtPriceX96;
454
+ }
455
+
456
+ if (poolState.liquidity !== newLiquidity)
457
+ poolState.liquidity = newLiquidity;
458
+ }
459
+
460
+ _modifyPosition(
461
+ state: PoolState,
462
+ params: ModifyPositionParams,
463
+ ): [bigint, bigint] {
464
+ const _slot0 = state.slot0;
465
+
466
+ this._updatePosition(
467
+ state,
468
+ params.tickLower,
469
+ params.tickUpper,
470
+ params.liquidityDelta,
471
+ );
472
+
473
+ let amount0 = 0n;
474
+ let amount1 = 0n;
475
+ if (params.liquidityDelta !== 0n) {
476
+ if (_slot0.tick < params.tickLower) {
477
+ amount0 = SqrtPriceMath._getAmount0DeltaO(
478
+ TickMath.getSqrtRatioAtTick(params.tickLower),
479
+ TickMath.getSqrtRatioAtTick(params.tickUpper),
480
+ params.liquidityDelta,
481
+ );
482
+ } else if (_slot0.tick < params.tickUpper) {
483
+ const liquidityBefore = state.liquidity;
484
+
485
+ amount0 = SqrtPriceMath._getAmount0DeltaO(
486
+ _slot0.sqrtPriceX96,
487
+ TickMath.getSqrtRatioAtTick(params.tickUpper),
488
+ params.liquidityDelta,
489
+ );
490
+ amount1 = SqrtPriceMath._getAmount1DeltaO(
491
+ TickMath.getSqrtRatioAtTick(params.tickLower),
492
+ _slot0.sqrtPriceX96,
493
+ params.liquidityDelta,
494
+ );
495
+
496
+ state.liquidity = LiquidityMath.addDelta(
497
+ liquidityBefore,
498
+ params.liquidityDelta,
499
+ );
500
+ } else {
501
+ amount1 = SqrtPriceMath._getAmount1DeltaO(
502
+ TickMath.getSqrtRatioAtTick(params.tickLower),
503
+ TickMath.getSqrtRatioAtTick(params.tickUpper),
504
+ params.liquidityDelta,
505
+ );
506
+ }
507
+ }
508
+ return [amount0, amount1];
509
+ }
510
+
511
+ private _isTickToProcess(state: PoolState, tick: bigint): boolean {
512
+ return tick >= state.lowestKnownTick && tick <= state.highestKnownTick;
513
+ }
514
+
515
+ private _updatePosition(
516
+ state: PoolState,
517
+ tickLower: bigint,
518
+ tickUpper: bigint,
519
+ liquidityDelta: bigint,
520
+ ): void {
521
+ // if we need to update the ticks, do it
522
+ let flippedLower = false;
523
+ let flippedUpper = false;
524
+ if (liquidityDelta !== 0n) {
525
+ const time = this._blockTimestamp(state);
526
+
527
+ if (this._isTickToProcess(state, tickLower)) {
528
+ flippedLower = Tick.update(
529
+ state,
530
+ tickLower,
531
+ liquidityDelta,
532
+ false,
533
+ state.maxLiquidityPerTick,
534
+ );
535
+ }
536
+ if (this._isTickToProcess(state, tickUpper)) {
537
+ flippedUpper = Tick.update(
538
+ state,
539
+ tickUpper,
540
+ liquidityDelta,
541
+ true,
542
+ state.maxLiquidityPerTick,
543
+ );
544
+ }
545
+
546
+ if (flippedLower) {
547
+ TickBitMap.flipTick(state, tickLower, state.tickSpacing);
548
+ }
549
+ if (flippedUpper) {
550
+ TickBitMap.flipTick(state, tickUpper, state.tickSpacing);
551
+ }
552
+ }
553
+
554
+ // clear any tick data that is no longer needed
555
+ if (liquidityDelta < 0n) {
556
+ if (flippedLower) {
557
+ Tick.clear(state, tickLower);
558
+ }
559
+ if (flippedUpper) {
560
+ Tick.clear(state, tickUpper);
561
+ }
562
+ }
563
+ }
564
+
565
+ private _blockTimestamp(state: DeepReadonly<PoolState>) {
566
+ return BigInt.asUintN(32, state.blockTimestamp);
567
+ }
568
+ }
569
+
570
+ export const uniswapV3Math = new UniswapV3Math();
@@ -0,0 +1,50 @@
1
+ import { NumberAsString } from '@paraswap/core';
2
+ import {
3
+ TickBitMapMappingsWithBigNumber,
4
+ TickInfo,
5
+ TickInfoMappingsWithBigNumber,
6
+ } from '../types';
7
+ import { bigIntify } from '../../../utils';
8
+
9
+ export function _mulmod(x: bigint, y: bigint, m: bigint): bigint {
10
+ return m === 0n ? 0n : (x * y) % m;
11
+ }
12
+
13
+ export function _lt(x: bigint, y: bigint) {
14
+ return x < y ? 1n : 0n;
15
+ }
16
+
17
+ export function _gt(x: bigint, y: bigint) {
18
+ return x > y ? 1n : 0n;
19
+ }
20
+
21
+ export function _reduceTickBitmap(
22
+ tickBitmap: Record<NumberAsString, bigint>,
23
+ tickBitmapToReduce: TickBitMapMappingsWithBigNumber[],
24
+ ) {
25
+ return tickBitmapToReduce.reduce<Record<NumberAsString, bigint>>(
26
+ (acc, curr) => {
27
+ const { index, value } = curr;
28
+ acc[index] = bigIntify(value);
29
+ return acc;
30
+ },
31
+ tickBitmap,
32
+ );
33
+ }
34
+
35
+ export function _reduceTicks(
36
+ ticks: Record<NumberAsString, TickInfo>,
37
+ ticksToReduce: TickInfoMappingsWithBigNumber[],
38
+ ) {
39
+ return ticksToReduce.reduce<Record<string, TickInfo>>((acc, curr) => {
40
+ const { index, value } = curr;
41
+ if (value.initialized) {
42
+ acc[index] = {
43
+ liquidityGross: bigIntify(value.liquidityGross),
44
+ liquidityNet: bigIntify(value.liquidityNet),
45
+ initialized: value.initialized,
46
+ };
47
+ }
48
+ return acc;
49
+ }, ticks);
50
+ }