@paraswap/dex-lib 2.28.7 → 2.28.9-ramses-v2

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