Kind Realm (renderable)
Name v1
Namespace gnoswap / pool
Exported functions 3
Module gno.land/r/gnoswap/pool/v1
gno 0.9 tick.gno gno
⧉
1 package pool 2 3 import ( 4 "gno.land/p/gnoswap/consts/v1" 5 "gno.land/p/gnoswap/gnsmath/v1" 6 ufmt "gno.land/p/nt/ufmt/v0" 7 8 GetPoolPath (token0Path string, token1Path string, fee uint32) string
NewPoolV1 (store interface {GetFeeAmountTickSpacing func() map[uint32]int32; GetObservations func() *gno.land/p/nt/bptree/v0.BPTree; GetPendingProtocolFee func(string) int64; GetPendingProtocolFees func() map[string]int64; GetPoolCreationFee func() int64; GetPools func() *gno.land/p/nt/bptree/v0.BPTree; GetSlot0FeeProtocol func() uint8; GetSwapEndHook func() func(.uverse.realm, string) .uverse.error; GetSwapStartHook func() func(.uverse.realm, string, int64); GetTickCrossHook func() func(.uverse.realm, string, int32, bool, int64); GetUnlocked func() bool; GetWithdrawalFeeBPS func() uint64; HasFeeAmountTickSpacing func() bool; HasObservations func() bool; HasPendingProtocolFees func() bool; HasPoolCreationFee func() bool; HasPools func() bool; HasSlot0FeeProtocol func() bool; HasSwapEndHook func() bool; HasSwapStartHook func() bool; HasTickCrossHook func() bool; HasUnlocked func() bool; HasWithdrawalFeeBPS func() bool; RemovePendingProtocolFee func(int, .uverse.realm, string) .uverse.error; SetFeeAmountTickSpacing func(int, .uverse.realm, map[uint32]int32) .uverse.error; SetObservations func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetPendingProtocolFee func(int, .uverse.realm, string, int64) .uverse.error; SetPendingProtocolFees func(int, .uverse.realm, map[string]int64) .uverse.error; SetPoolCreationFee func(int, .uverse.realm, int64) .uverse.error; SetPools func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetSlot0FeeProtocol func(int, .uverse.realm, uint8) .uverse.error; SetSwapEndHook func(int, .uverse.realm, func(.uverse.realm, string) .uverse.error) .uverse.error; SetSwapStartHook func(int, .uverse.realm, func(.uverse.realm, string, int64)) .uverse.error; SetTickCrossHook func(int, .uverse.realm, func(.uverse.realm, string, int32, bool, int64)) .uverse.error; SetUnlocked func(int, .uverse.realm, bool) .uverse.error; SetWithdrawalFeeBPS func(int, .uverse.realm, uint64) .uverse.error}) interface {Burn func(int, .uverse.realm, string, string, uint32, int32, int32, string, .uverse.address) (string, string); Collect func(int, .uverse.realm, string, string, uint32, .uverse.address, int32, int32, string, string) (string, string); CollectProtocol func(int, .uverse.realm, string, string, uint32, .uverse.address, string, string) (string, string); CollectSwapFee func(int, .uverse.realm, string, string, uint32, .uverse.address, int32, int32, string, string) (string, string, string, string); CreatePool func(int, .uverse.realm, string, string, uint32, string); DrySwap func(string, string, uint32, bool, string, string) (string, string, .uverse.error); ExistsPoolPath func(string) bool; GetBalanceToken0 func(string) (int64, .uverse.error); GetBalanceToken1 func(string) (int64, .uverse.error); GetFee func(string) (uint32, .uverse.error); GetFeeAmountTickSpacing func(uint32) (int32, .uverse.error); GetFeeAmountTickSpacings func() map[uint32]int32; GetFeeGrowthGlobal0X128 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetFeeGrowthGlobal1X128 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetFeeGrowthGlobalX128 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, *gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetInitializedTicksInRange func(string, int32, int32) ([]int32, .uverse.error); GetLiquidity func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetObservationAt func(string, uint16) (gno.land/r/gnoswap/pool.Observation, .uverse.error); GetPendingProtocolFees func() map[string]int64; GetPoolCreationFee func() int64; GetPoolPositions func(string) *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetPools func() *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetPositionFeeGrowthInside0LastX128 func(string, string) (string, .uverse.error); GetPositionFeeGrowthInside1LastX128 func(string, string) (string, .uverse.error); GetPositionFeeGrowthInsideLastX128 func(string, string) (string, string, .uverse.error); GetPositionLiquidity func(string, string) (string, .uverse.error); GetPositionTokensOwed0 func(string, string) (int64, .uverse.error); GetPositionTokensOwed1 func(string, string) (int64, .uverse.error); GetProtocolFeesToken0 func(string) (int64, .uverse.error); GetProtocolFeesToken1 func(string) (int64, .uverse.error); GetSlot0 func(string) gno.land/r/gnoswap/pool.Slot0; GetSlot0FeeProtocol func(string) (uint8, .uverse.error); GetSlot0SqrtPriceX96 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetSlot0Tick func(string) (int32, .uverse.error); GetSlot0Unlocked func(string) (bool, .uverse.error); GetTickBitmaps func(string, int16) (string, .uverse.error); GetTickCumulativeOutside func(string, int32) (int64, .uverse.error); GetTickFeeGrowthOutside0X128 func(string, int32) (string, .uverse.error); GetTickFeeGrowthOutside1X128 func(string, int32) (string, .uverse.error); GetTickFeeGrowthOutsideX128 func(string, int32) (string, string, .uverse.error); GetTickInfo func(string, int32) (gno.land/r/gnoswap/pool.TickInfo, .uverse.error); GetTickInitialized func(string, int32) (bool, .uverse.error); GetTickLiquidityGross func(string, int32) (string, .uverse.error); GetTickLiquidityNet func(string, int32) (string, .uverse.error); GetTickSecondsOutside func(string, int32) (uint32, .uverse.error); GetTickSecondsPerLiquidityOutsideX128 func(string, int32) (string, .uverse.error); GetTickSpacing func(string) (int32, .uverse.error); GetToken0Path func(string) (string, .uverse.error); GetToken1Path func(string) (string, .uverse.error); GetWithdrawalFee func() uint64; IncreaseObservationCardinalityNext func(int, .uverse.realm, string, string, uint32, uint16); Mint func(int, .uverse.realm, string, string, uint32, int32, int32, string, .uverse.address) (string, string); Observe func(string, []uint32) ([]int64, []string, .uverse.error); OracleConsult func(string, uint32) (int32, *gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); Render func(string) string; SetFeeProtocol func(int, .uverse.realm, uint8, uint8); SetPoolCreationFee func(int, .uverse.realm, int64); SetSwapEndHook func(int, .uverse.realm, func(.uverse.realm, string) .uverse.error); SetSwapStartHook func(int, .uverse.realm, func(.uverse.realm, string, int64)); SetTickCrossHook func(int, .uverse.realm, func(.uverse.realm, string, int32, bool, int64)); SetWithdrawalFee func(int, .uverse.realm, uint64); SnapshotCumulativesInside func(string, int32, int32) (int64, *gno.land/p/gnoswap/uint256/v1.Uint, uint32, .uverse.error); Swap func(int, .uverse.realm, string, string, uint32, .uverse.address, bool, string, string, func(.uverse.realm, int64, int64, *gno.land/r/gnoswap/pool.CallbackMarker) .uverse.error) (string, string)}
NewTickEventInfo (tickID int32, tickInfo struct{liquidityGross string; liquidityNet string; feeGrowthOutside0X128 string; feeGrowthOutside1X128 string; tickCumulativeOutside int64; secondsPerLiquidityOutsideX128 string; secondsOutside uint32; initialized bool}) *gno.land/r/gnoswap/pool/v1.tickEventInfo
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
This realm does not provide renderable output (vm/qrender → NoRenderDeclError).
View on gnoweb ↗ vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
i256 "gno.land/p/gnoswap/int256/v1"
9 u256 "gno.land/p/gnoswap/uint256/v1"
10 pl "gno.land/r/gnoswap/pool"
11 )
12
13 // MAX_LIQUIDITY_PER_TICK_* values are spacing-specific limits returned by
14 // calculateMaxLiquidityPerTick; they are not a universal uint128 maximum.
15
16 const (
17 MAX_LIQUIDITY_PER_TICK_SPACING_1 = "191757530477355301479181766273477"
18 MAX_LIQUIDITY_PER_TICK_SPACING_10 = "1917569901783203986719870431555990"
19 MAX_LIQUIDITY_PER_TICK_SPACING_60 = "11505743598341114571880798222544994"
20 MAX_LIQUIDITY_PER_TICK_SPACING_200 = "38350317471085141830651933667504588"
21 MIN_TICK int32 = - 887272
22 MAX_TICK int32 = 887272
23 )
24
25 // maxLiquidityPerTickSpacing* return the precomputed max-liquidity-per-tick for
26 // each supported tick spacing. They are constructors (not package-level vars) so
27 // each caller receives a fresh instance — calculateMaxLiquidityPerTick returns
28 // the value directly to callers, and a shared singleton could otherwise be
29 // mutated in place and corrupt every caller. Values are built from little-endian
30 // [4]uint64 literals to avoid runtime decimal parsing.
31 func maxLiquidityPerTickSpacing1FromDec() *u256.Uint {
32 return &u256.Uint{ 3639524637645646277 , 10395196556700 , 0 , 0 } // 191757530477355301479181766273477
33 }
34
35 func maxLiquidityPerTickSpacing10FromDec() *u256.Uint {
36 return &u256.Uint{ 4727306266354938262 , 103951672670308 , 0 , 0 } // 1917569901783203986719870431555990
37 }
38
39 func maxLiquidityPerTickSpacing60FromDec() *u256.Uint {
40 return &u256.Uint{ 1428959955126579298 , 623727610269131 , 0 , 0 } // 11505743598341114571880798222544994
41 }
42
43 func maxLiquidityPerTickSpacing200FromDec() *u256.Uint {
44 return &u256.Uint{ 6592429331424883148 , 2078974875882965 , 0 , 0 } // 38350317471085141830651933667504588
45 }
46
47 // getFeeGrowthInside calculates the fee growth within a specified tick range.
48 //
49 // This function computes the accumulated fee growth for token 0 and token 1 inside a given tick range
50 // (`tickLower` to `tickUpper`) relative to the current tick position (`tickCurrent`). It isolates the fee
51 // growth within the range by subtracting the fee growth below the lower tick and above the upper tick
52 // from the global fee growth.
53 //
54 // Parameters:
55 // - tickLower: int32, the lower tick boundary of the range.
56 // - tickUpper: int32, the upper tick boundary of the range.
57 // - tickCurrent: int32, the current tick index.
58 // - feeGrowthGlobal0X128: *u256.Uint, the global fee growth for token 0 in X128 precision.
59 // - feeGrowthGlobal1X128: *u256.Uint, the global fee growth for token 1 in X128 precision.
60 //
61 // Returns:
62 // - *u256.Uint: Fee growth inside the tick range for token 0.
63 // - *u256.Uint: Fee growth inside the tick range for token 1.
64 //
65 // Workflow:
66 // 1. Retrieve the tick information (`lower` and `upper`) for the lower and upper tick boundaries
67 // using `p.getTick`.
68 // 2. Calculate the fee growth below the lower tick using `getFeeGrowthBelowX128`.
69 // 3. Calculate the fee growth above the upper tick using `getFeeGrowthAboveX128`.
70 // 4. Subtract the fee growth below and above the range from the global fee growth values:
71 // feeGrowthInside = feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove
72 // 5. Return the computed fee growth values for token 0 and token 1 within the range.
73 //
74 // Behavior:
75 // - The fee growth is isolated within the range `[tickLower, tickUpper]`.
76 // - The function ensures the calculations accurately consider the tick boundaries and the current tick position.
77 //
78 // Example:
79 //
80 // ```gno
81 //
82 // feeGrowth0, feeGrowth1 := pool.getFeeGrowthInside(
83 // 100, 200, 150, globalFeeGrowth0, globalFeeGrowth1,
84 // )
85 // println("Fee Growth Inside (Token 0):", feeGrowth0)
86 // println("Fee Growth Inside (Token 1):", feeGrowth1)
87 //
88 // ```
89 func getFeeGrowthInside(
90 p *pl.Pool,
91 tickLower int32 ,
92 tickUpper int32 ,
93 tickCurrent int32 ,
94 feeGrowthGlobal0X128 *u256.Uint,
95 feeGrowthGlobal1X128 *u256.Uint,
96 ) (*u256.Uint, *u256.Uint) {
97 lower := getTick(p, tickLower)
98 upper := getTick(p, tickUpper)
99
100 feeGrowthBelow0X128, feeGrowthBelow1X128 := getFeeGrowthBelowX128(tickLower, tickCurrent, feeGrowthGlobal0X128, feeGrowthGlobal1X128, lower)
101 feeGrowthAbove0X128, feeGrowthAbove1X128 := getFeeGrowthAboveX128(tickUpper, tickCurrent, feeGrowthGlobal0X128, feeGrowthGlobal1X128, upper)
102
103 feeGrowthInside0X128 := u256.Zero().Sub(u256.Zero().Sub(feeGrowthGlobal0X128, feeGrowthBelow0X128), feeGrowthAbove0X128)
104 feeGrowthInside1X128 := u256.Zero().Sub(u256.Zero().Sub(feeGrowthGlobal1X128, feeGrowthBelow1X128), feeGrowthAbove1X128)
105
106 return feeGrowthInside0X128, feeGrowthInside1X128
107 }
108
109 // tickUpdate updates the state of a specific tick.
110 //
111 // This function applies a given liquidity change (liquidityDelta) to the specified tick, updates
112 // the fee growth values if necessary, and adjusts the net liquidity based on whether the tick
113 // is an upper or lower boundary. It also verifies that the total liquidity does not exceed the
114 // maximum allowed value and ensures the net liquidity stays within the valid int128 range.
115 //
116 // Parameters:
117 // - tick: int32, the index of the tick to update.
118 // - tickCurrent: int32, the current active tick index.
119 // - liquidityDelta: *i256.Int, the amount of liquidity to add or remove.
120 // - feeGrowthGlobal0X128: *u256.Uint, the global fee growth value for token 0.
121 // - feeGrowthGlobal1X128: *u256.Uint, the global fee growth value for token 1.
122 // - secondsPerLiquidityCumulativeX128: *u256.Uint, the current oracle accumulator used to
123 // seed the outside accumulator of a newly initialized active tick (tick <= tickCurrent).
124 // - tickCumulative: int64, the current oracle tick accumulator used for the same seeding.
125 // - blockTimestamp: int64, the current block timestamp used for the same seeding.
126 // - upper: bool, indicates if this is the upper boundary (true for upper, false for lower).
127 // - maxLiquidity: *u256.Uint, the maximum allowed liquidity.
128 //
129 // Returns:
130 // - flipped: bool, indicates if the tick's initialization state has changed.
131 // (e.g., liquidity transitioning from zero to non-zero, or vice versa)
132 //
133 // Workflow:
134 // 1. Nil input values are replaced with zero.
135 // 2. The function retrieves the tick information for the specified tick index.
136 // 3. Applies the liquidityDelta to compute the new total liquidity (liquidityGross).
137 // - If the total liquidity exceeds the maximum allowed value, the function panics.
138 // 4. Checks whether the tick's initialized state has changed and sets the `flipped` flag.
139 // 5. If the tick was previously uninitialized and its index is less than or equal to the current tick,
140 // the fee growth values are initialized to the current global values.
141 // 6. Updates the tick's net liquidity:
142 // - For an upper boundary, it subtracts liquidityDelta.
143 // - For a lower boundary, it adds liquidityDelta.
144 // - Ensures the net liquidity remains within the int128 range using `checkOverFlowInt128`.
145 // 7. Updates the tick's state with the new values.
146 // 8. Returns whether the tick's initialized state has flipped.
147 //
148 // Panic Conditions:
149 // - The total liquidity (liquidityGross) exceeds the maximum allowed liquidity (maxLiquidity).
150 // - The net liquidity (liquidityNet) exceeds the int128 range.
151 //
152 // Example:
153 //
154 // ```gno
155 //
156 // flipped := pool.tickUpdate(10, 5, liquidityDelta, feeGrowth0, feeGrowth1, secondsPerLiquidityCumulativeX128, tickCumulative, blockTimestamp, true, maxLiquidity)
157 // println("Tick flipped:", flipped)
158 //
159 // ```
160 func tickUpdate(
161 p *pl.Pool,
162 tick int32 ,
163 tickCurrent int32 ,
164 liquidityDelta *i256.Int,
165 feeGrowthGlobal0X128 *u256.Uint,
166 feeGrowthGlobal1X128 *u256.Uint,
167 secondsPerLiquidityCumulativeX128 *u256.Uint,
168 tickCumulative int64 ,
169 blockTimestamp int64 ,
170 upper bool ,
171 maxLiquidity *u256.Uint,
172 ) (flipped bool ) {
173 tickInfo := getTick(p, tick)
174
175 liquidityGrossBefore := u256.MustFromDecimal(tickInfo.LiquidityGross())
176 liquidityGrossAfter := gnsmath.LiquidityMathAddDelta(liquidityGrossBefore, liquidityDelta)
177
178 if !liquidityGrossAfter.Lte(maxLiquidity) {
179 panic(newErrorWithDetail(
180 errLiquidityCalculation,
181 ufmt.Sprintf( "liquidityGrossAfter(%s) overflows maxLiquidity(%s)" , liquidityGrossAfter.ToString(), maxLiquidity.ToString()),
182 ))
183 }
184
185 flipped = liquidityGrossAfter.IsZero() != liquidityGrossBefore.IsZero()
186
187 if liquidityGrossBefore.IsZero() {
188 if tick <= tickCurrent {
189 tickInfo.SetFeeGrowthOutside0X128(feeGrowthGlobal0X128.ToString())
190 tickInfo.SetFeeGrowthOutside1X128(feeGrowthGlobal1X128.ToString())
191 tickInfo.SetSecondsPerLiquidityOutsideX128(secondsPerLiquidityCumulativeX128.ToString())
192 tickInfo.SetTickCumulativeOutside(tickCumulative)
193 tickInfo.SetSecondsOutside( uint32 (blockTimestamp))
194 }
195 tickInfo.SetInitialized( true )
196 }
197
198 tickInfo.SetLiquidityGross(liquidityGrossAfter.ToString())
199
200 liquidityNet := i256.MustFromDecimal(tickInfo.LiquidityNet())
201 if upper {
202 newLiquidityNet := i256.Zero().Sub(liquidityNet, liquidityDelta)
203 checkOverFlowInt128(newLiquidityNet)
204 tickInfo.SetLiquidityNet(newLiquidityNet.ToString())
205 } else {
206 newLiquidityNet := i256.Zero().Add(liquidityNet, liquidityDelta)
207 checkOverFlowInt128(newLiquidityNet)
208 tickInfo.SetLiquidityNet(newLiquidityNet.ToString())
209 }
210
211 setTick(p, tick, tickInfo)
212
213 return flipped
214 }
215
216 // tickCross updates a tick's state when it is crossed and returns the liquidity net.
217 // Updates fee growth and oracle accumulator values for the tick.
218 func tickCross(
219 p *pl.Pool,
220 tick int32 ,
221 feeGrowthGlobal0X128 *u256.Uint,
222 feeGrowthGlobal1X128 *u256.Uint,
223 secondsPerLiquidityCumulativeX128 *u256.Uint,
224 tickCumulative int64 ,
225 blockTimestamp int64 ,
226 ) *i256.Int {
227 thisTick := getTick(p, tick)
228
229 feeOutside0 := u256.MustFromDecimal(thisTick.FeeGrowthOutside0X128())
230 feeOutside1 := u256.MustFromDecimal(thisTick.FeeGrowthOutside1X128())
231 thisTick.SetFeeGrowthOutside0X128(u256.Zero().Sub(feeGrowthGlobal0X128, feeOutside0).ToString())
232 thisTick.SetFeeGrowthOutside1X128(u256.Zero().Sub(feeGrowthGlobal1X128, feeOutside1).ToString())
233
234 tickSecondsPerLiquidity := u256.MustFromDecimal(thisTick.SecondsPerLiquidityOutsideX128())
235 thisTick.SetSecondsPerLiquidityOutsideX128(u256.Zero().Sub(secondsPerLiquidityCumulativeX128, tickSecondsPerLiquidity).ToString())
236 thisTick.SetTickCumulativeOutside(tickCumulative - thisTick.TickCumulativeOutside())
237 thisTick.SetSecondsOutside( uint32 (blockTimestamp) - thisTick.SecondsOutside())
238
239 setTick(p, tick, thisTick)
240
241 return i256.MustFromDecimal(thisTick.LiquidityNet())
242 }
243
244 // setTick updates the tick data for the specified tick index in the pool.
245 func setTick(p *pl.Pool, tick int32 , newTickInfo pl.TickInfo) {
246 p.SetTick(tick, newTickInfo)
247 }
248
249 // deleteTick deletes the tick data for the specified tick index in the pool.
250 func deleteTick(p *pl.Pool, tick int32 ) {
251 p.DeleteTick(tick)
252 }
253
254 // getTick retrieves the TickInfo associated with the specified tick index from the pool.
255 // If the TickInfo contains any nil fields, they are replaced with zero values using valueOrZero.
256 //
257 // Parameters:
258 // - tick: The tick index (int32) for which the TickInfo is to be retrieved.
259 //
260 // Behavior:
261 // - Retrieves the TickInfo for the given tick from the pool's tick map.
262 // - Ensures that all fields of TickInfo are non-nil by calling valueOrZero, which replaces nil values with zero.
263 // - Returns the updated TickInfo.
264 //
265 // Returns:
266 // - TickInfo: The tick data with all fields guaranteed to have valid values (nil fields are set to zero).
267 //
268 // Use Case:
269 // This function ensures the retrieved tick data is always valid and safe for further operations,
270 // such as calculations or updates, by sanitizing nil fields in the TickInfo structure.
271 func getTick(p *pl.Pool, tick int32 ) pl.TickInfo {
272 tickInfo, err := p.GetTick(tick)
273 if err != nil {
274 return pl.NewTickInfo()
275 }
276
277 return tickInfo
278 }
279
280 // mustGetTick retrieves the TickInfo for a specific tick, panicking if the tick does not exist.
281 //
282 // This function ensures that the requested tick data exists in the pool's tick mapping.
283 // If the tick does not exist, it panics with an appropriate error message.
284 //
285 // Parameters:
286 // - tick: int32, the index of the tick to retrieve.
287 //
288 // Returns:
289 // - TickInfo: The information associated with the specified tick.
290 //
291 // Behavior:
292 // - Checks if the tick exists in the pool's tick mapping (`p.ticks`).
293 // - If the tick exists, it returns the corresponding `TickInfo`.
294 // - If the tick does not exist, the function panics with a descriptive error.
295 //
296 // Panic Conditions:
297 // - The specified tick does not exist in the pool's mapping.
298 //
299 // Example:
300 //
301 // ```gno
302 //
303 // tickInfo := pool.mustGetTick(10)
304 // ufmt.Println("Tick Info:", tickInfo)
305 //
306 // ```
307 func mustGetTick(p *pl.Pool, tick int32 ) *pl.TickInfo {
308 tickInfo, err := p.GetTick(tick)
309 if err != nil {
310 panic(err)
311 }
312
313 return &tickInfo
314 }
315
316 // calculateMaxLiquidityPerTick calculates the maximum liquidity
317 // per tick for a given tick spacing.
318 func calculateMaxLiquidityPerTick(tickSpacing int32 ) *u256.Uint {
319 switch tickSpacing {
320 case 1 :
321 return maxLiquidityPerTickSpacing1FromDec()
322 case 10 :
323 return maxLiquidityPerTickSpacing10FromDec()
324 case 60 :
325 return maxLiquidityPerTickSpacing60FromDec()
326 case 200 :
327 return maxLiquidityPerTickSpacing200FromDec()
328 default :
329 minTick := (MIN_TICK / tickSpacing) * tickSpacing
330 maxTick := (MAX_TICK / tickSpacing) * tickSpacing
331 numTicks := uint64 ((maxTick-minTick)/tickSpacing) + 1
332
333 return u256.Zero().Div(consts.MaxUint128(), u256.NewUint(numTicks))
334 }
335 }
336
337 // getFeeGrowthBelowX128 calculates the fee growth below a specified tick.
338 //
339 // This function computes the fee growth for token 0 and token 1 below a given tick (`tickLower`)
340 // relative to the current tick (`tickCurrent`). The fee growth values are adjusted based on whether
341 // the `tickCurrent` is above or below the `tickLower`.
342 //
343 // Parameters:
344 // - tickLower: int32, the lower tick boundary for fee calculation.
345 // - tickCurrent: int32, the current tick index.
346 // - feeGrowthGlobal0X128: *u256.Uint, the global fee growth for token 0 in X128 precision.
347 // - feeGrowthGlobal1X128: *u256.Uint, the global fee growth for token 1 in X128 precision.
348 // - lowerTick: TickInfo, the fee growth and liquidity details for the lower tick.
349 //
350 // Returns:
351 // - *u256.Uint: Fee growth below `tickLower` for token 0.
352 // - *u256.Uint: Fee growth below `tickLower` for token 1.
353 //
354 // Workflow:
355 // 1. If `tickCurrent` is greater than or equal to `tickLower`:
356 // - Return the `feeGrowthOutside0X128` and `feeGrowthOutside1X128` values of the `lowerTick`.
357 // 2. If `tickCurrent` is below `tickLower`:
358 // - Compute the fee growth below the lower tick by subtracting `feeGrowthOutside` values
359 // from the global fee growth values (`feeGrowthGlobal0X128` and `feeGrowthGlobal1X128`).
360 // 3. Return the calculated fee growth values for both tokens.
361 //
362 // Behavior:
363 // - If `tickCurrent >= tickLower`, the fee growth outside the lower tick is returned as-is.
364 // - If `tickCurrent < tickLower`, the fee growth is calculated as:
365 // feeGrowthBelow = feeGrowthGlobal - feeGrowthOutside
366 //
367 // Example:
368 //
369 // ```gno
370 //
371 // feeGrowth0, feeGrowth1 := getFeeGrowthBelowX128(
372 // 100, 150, globalFeeGrowth0, globalFeeGrowth1, lowerTickInfo,
373 // )
374 // println("Fee Growth Below:", feeGrowth0, feeGrowth1)
375 func getFeeGrowthBelowX128(
376 tickLower, tickCurrent int32 ,
377 feeGrowthGlobal0X128, feeGrowthGlobal1X128 *u256.Uint,
378 lowerTick pl.TickInfo,
379 ) (*u256.Uint, *u256.Uint) {
380 feeOutside0 := u256.MustFromDecimal(lowerTick.FeeGrowthOutside0X128())
381 feeOutside1 := u256.MustFromDecimal(lowerTick.FeeGrowthOutside1X128())
382
383 if tickCurrent >= tickLower {
384 return feeOutside0, feeOutside1
385 }
386
387 feeGrowthBelow0X128 := u256.Zero().Sub(feeGrowthGlobal0X128, feeOutside0)
388 feeGrowthBelow1X128 := u256.Zero().Sub(feeGrowthGlobal1X128, feeOutside1)
389
390 return feeGrowthBelow0X128, feeGrowthBelow1X128
391 }
392
393 // getFeeGrowthAboveX128 calculates the fee growth above a specified tick.
394 //
395 // This function computes the fee growth for token 0 and token 1 above a given tick (`tickUpper`)
396 // relative to the current tick (`tickCurrent`). The fee growth values are adjusted based on whether
397 // the `tickCurrent` is above or below the `tickUpper`.
398 //
399 // Parameters:
400 // - tickUpper: int32, the upper tick boundary for fee calculation.
401 // - tickCurrent: int32, the current tick index.
402 // - feeGrowthGlobal0X128: *u256.Uint, the global fee growth for token 0 in X128 precision.
403 // - feeGrowthGlobal1X128: *u256.Uint, the global fee growth for token 1 in X128 precision.
404 // - upperTick: TickInfo, the fee growth and liquidity details for the upper tick.
405 //
406 // Returns:
407 // - *u256.Uint: Fee growth above `tickUpper` for token 0.
408 // - *u256.Uint: Fee growth above `tickUpper` for token 1.
409 //
410 // Workflow:
411 // 1. If `tickCurrent` is less than `tickUpper`:
412 // - Return the `feeGrowthOutside0X128` and `feeGrowthOutside1X128` values of the `upperTick`.
413 // 2. If `tickCurrent` is greater than or equal to `tickUpper`:
414 // - Compute the fee growth above the upper tick by subtracting `feeGrowthOutside` values
415 // from the global fee growth values (`feeGrowthGlobal0X128` and `feeGrowthGlobal1X128`).
416 // 3. Return the calculated fee growth values for both tokens.
417 //
418 // Behavior:
419 // - If `tickCurrent < tickUpper`, the fee growth outside the upper tick is returned as-is.
420 // - If `tickCurrent >= tickUpper`, the fee growth is calculated as:
421 // feeGrowthAbove = feeGrowthGlobal - feeGrowthOutside
422 //
423 // Example:
424 //
425 // feeGrowth0, feeGrowth1 := getFeeGrowthAboveX128(
426 // 200, 150, globalFeeGrowth0, globalFeeGrowth1, upperTickInfo,
427 // )
428 // println("Fee Growth Above:", feeGrowth0, feeGrowth1)
429 //
430 // ```
431 func getFeeGrowthAboveX128(
432 tickUpper, tickCurrent int32 ,
433 feeGrowthGlobal0X128, feeGrowthGlobal1X128 *u256.Uint,
434 upperTick pl.TickInfo,
435 ) (*u256.Uint, *u256.Uint) {
436 feeOutside0 := u256.MustFromDecimal(upperTick.FeeGrowthOutside0X128())
437 feeOutside1 := u256.MustFromDecimal(upperTick.FeeGrowthOutside1X128())
438
439 if tickCurrent < tickUpper {
440 return feeOutside0, feeOutside1
441 }
442
443 feeGrowthAbove0X128 := u256.Zero().Sub(feeGrowthGlobal0X128, feeOutside0)
444 feeGrowthAbove1X128 := u256.Zero().Sub(feeGrowthGlobal1X128, feeOutside1)
445
446 return feeGrowthAbove0X128, feeGrowthAbove1X128
447 }
448
449 // validateTicks validates the tick range for a liquidity position.
450 //
451 // This function performs three essential checks to ensure the provided
452 // tick values are valid before creating or modifying a liquidity position.
453 func validateTicks(tickLower, tickUpper int32 ) error {
454 if tickLower >= tickUpper {
455 return makeErrorWithDetails(
456 errInvalidTickRange,
457 ufmt.Sprintf( "tickLower(%d), tickUpper(%d)" , tickLower, tickUpper),
458 )
459 }
460
461 if tickLower < MIN_TICK {
462 return makeErrorWithDetails(
463 errTickLowerInvalid,
464 ufmt.Sprintf( "tickLower(%d) < MIN_TICK(%d)" , tickLower, MIN_TICK),
465 )
466 }
467
468 if tickUpper > MAX_TICK {
469 return makeErrorWithDetails(
470 errTickUpperInvalid,
471 ufmt.Sprintf( "tickUpper(%d) > MAX_TICK(%d)" , tickUpper, MAX_TICK),
472 )
473 }
474
475 return nil
476 }
477