type.gno
6.59 Kb · 188 lines
1package pool
2
3import (
4 "gno.land/p/gnoswap/gnsmath/v1"
5 i256 "gno.land/p/gnoswap/int256/v1"
6 u256 "gno.land/p/gnoswap/uint256/v1"
7
8 pl "gno.land/r/gnoswap/pool"
9)
10
11// ModifyPositionParams repersents the parameters for modifying a liquidity position.
12// This structure is used internally both `Mint` and `Burn` operation to manage
13// the liquidity positions.
14type ModifyPositionParams struct {
15 // owner is the address that owns the position
16 owner address
17
18 // tickLower and atickUpper define the price range
19 // The actual price range is calculated as 1.0001^tick
20 // This allows for precision in price range while using integer math.
21
22 tickLower int32 // lower tick of the position
23 tickUpper int32 // upper tick of the position
24
25 // liquidityDelta represents the change in liquidity
26 // Positive for minting, negative for burning
27 liquidityDelta *i256.Int
28}
29
30// newModifyPositionParams creates a new `ModifyPositionParams` instance.
31// This is used to preare parameters for the `modifyPosition` function,
32// which handles both minting and burning of liquidity positions.
33//
34// Parameters:
35// - owner: address that will own (or owns) the position
36// - tickLower: lower tick bound of the position
37// - tickUpper: upper tick bound of the position
38// - liquidityDelta: amount of liquidity to add (positive) or remove (negative)
39//
40// The tick parameters represent prices as powers of 1.0001:
41// - actual_price = 1.0001^tick
42// - For example, tick = 100 means price = 1.0001^100
43//
44// Returns:
45// - ModifyPositionParams: a new instance of ModifyPositionParams
46func newModifyPositionParams(
47 owner address,
48 tickLower int32,
49 tickUpper int32,
50 liquidityDelta *i256.Int,
51) ModifyPositionParams {
52 return ModifyPositionParams{
53 owner: owner,
54 tickLower: tickLower,
55 tickUpper: tickUpper,
56 liquidityDelta: liquidityDelta,
57 }
58}
59
60// SwapCache holds immutable swap-start inputs and oracle cumulatives that are
61// populated lazily when the swap first crosses an initialized tick.
62type SwapCache struct {
63 feeProtocol uint8 // protocol fee for the input token
64 liquidityStart *u256.Uint // liquidity at the beginning of the swap
65 blockTimestamp int64 // current block timestamp
66 tickCumulative int64 // current tick accumulator value
67 secondsPerLiquidityCumulativeX128 *u256.Uint // current seconds per liquidity accumulator
68 computedLatestObservation bool // whether we've computed the above accumulators
69 slot0Start pl.Slot0 // immutable Slot0 snapshot captured at swap start
70 readOnly bool // quote without tick accounting or hooks
71}
72
73func newSwapCache(
74 feeProtocol uint8,
75 liquidityStart *u256.Uint,
76 blockTimestamp int64,
77 slot0Start pl.Slot0,
78) *SwapCache {
79 return &SwapCache{
80 feeProtocol: feeProtocol,
81 liquidityStart: liquidityStart,
82 blockTimestamp: blockTimestamp,
83 tickCumulative: 0,
84 secondsPerLiquidityCumulativeX128: u256.Zero(),
85 computedLatestObservation: false,
86 slot0Start: slot0Start.Clone(),
87 }
88}
89
90// SwapState tracks the changing values during a swap.
91// This type helps manage the state transitions that occur as the swap progresses
92// across different price ranges.
93type SwapState struct {
94 amountSpecifiedRemaining *i256.Int // amount remaining to be swapped in/out of the input/output token
95 amountCalculated *i256.Int // amount already swapped out/in of the output/input token
96 sqrtPriceX96 *u256.Uint // current sqrt(price)
97 tick int32 // tick associated with the current sqrt(price)
98 feeGrowthGlobalX128 *u256.Uint // global fee growth of the input token
99 protocolFee *u256.Uint // amount of input token paid as protocol fee
100 liquidity *u256.Uint // current liquidity in range
101}
102
103func newSwapState(
104 amountSpecifiedRemaining *i256.Int,
105 feeGrowthGlobalX128 *u256.Uint,
106 liquidity *u256.Uint,
107 slot0 pl.Slot0,
108) SwapState {
109 return SwapState{
110 amountSpecifiedRemaining: amountSpecifiedRemaining,
111 amountCalculated: i256.Zero(),
112 sqrtPriceX96: slot0.SqrtPriceX96(),
113 tick: slot0.Tick(),
114 feeGrowthGlobalX128: feeGrowthGlobalX128,
115 protocolFee: u256.Zero(),
116 liquidity: liquidity,
117 }
118}
119
120func (s *SwapState) setSqrtPriceX96(sqrtPriceX96 *u256.Uint) {
121 s.sqrtPriceX96 = sqrtPriceX96.Clone()
122}
123
124func (s *SwapState) setTick(tick int32) {
125 s.tick = tick
126}
127
128func (s *SwapState) setFeeGrowthGlobalX128(feeGrowthGlobalX128 *u256.Uint) {
129 s.feeGrowthGlobalX128 = feeGrowthGlobalX128
130}
131
132func (s *SwapState) setProtocolFee(fee *u256.Uint) {
133 s.protocolFee = fee
134}
135
136// StepComputations holds intermediate values used during a single step of a swap.
137// Each step represents movement from the current tick to the next initialized tick
138// or the target price, whichever comes first.
139type StepComputations struct {
140 sqrtPriceStartX96 *u256.Uint // price at the beginning of the step
141 tickNext int32 // next tick to swap to from the current tick in the swap direction
142 initialized bool // whether tickNext is initialized
143 sqrtPriceNextX96 *u256.Uint // sqrt(price) for the next tick (token1/token0) Q96
144 amountIn *u256.Uint // how much being swapped in this step
145 amountOut *u256.Uint // how much is being swapped out in this step
146 feeAmount *u256.Uint // how much fee is being paid in this step
147}
148
149// init initializes the computation for a single swap step
150func (step *StepComputations) initSwapStep(state SwapState, p *pl.Pool, zeroForOne bool) {
151 step.sqrtPriceStartX96 = state.sqrtPriceX96
152 step.tickNext, step.initialized = tickBitmapNextInitializedTickWithInOneWord(
153 p,
154 state.tick,
155 p.TickSpacing(),
156 zeroForOne,
157 )
158
159 // prevent overshoot the min/max tick
160 step.clampTickNext()
161
162 // get the price for the next tick
163 step.sqrtPriceNextX96 = gnsmath.TickMathGetSqrtRatioAtTick(step.tickNext)
164}
165
166// clampTickNext ensures that `tickNext` stays within the min, max tick boundaries
167// as the tick bitmap is not aware of these bounds
168func (step *StepComputations) clampTickNext() {
169 if step.tickNext < MIN_TICK {
170 step.tickNext = MIN_TICK
171 } else if step.tickNext > MAX_TICK {
172 step.tickNext = MAX_TICK
173 }
174}
175
176func newPool(poolInfo *poolCreateConfig) *pl.Pool {
177 tick := gnsmath.TickMathGetTickAtSqrtRatio(poolInfo.SqrtPriceX96())
178
179 return pl.NewPool(
180 poolInfo.Token0Path(),
181 poolInfo.Token1Path(),
182 poolInfo.Fee(),
183 poolInfo.SqrtPriceX96(),
184 poolInfo.TickSpacing(),
185 tick,
186 poolInfo.slot0FeeProtocol,
187 )
188}