@paraswap/dex-lib 2.16.7 → 2.16.8-pancakeswapv3.0

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