pool.gno
15.36 Kb ยท 465 lines
1package pool
2
3import (
4 "time"
5
6 "gno.land/p/nt/avl"
7 "gno.land/p/nt/ufmt"
8
9 i256 "gno.land/p/gnoswap/int256"
10 u256 "gno.land/p/gnoswap/uint256"
11)
12
13// type Pool describes a single Pool's state
14// A pool is identificed with a unique key (token0, token1, fee), where token0 < token1
15type Pool struct {
16 // token0/token1 path of the pool
17 token0Path string
18 token1Path string
19 fee uint32 // fee tier of the pool
20 tickSpacing int32 // spacing between ticks
21 slot0 Slot0
22 balances Balances // balances of the pool
23 protocolFees ProtocolFees
24 maxLiquidityPerTick *u256.Uint // the maximum amount of liquidity that can be added per tick
25 feeGrowthGlobal0X128 *u256.Uint // uint256
26 feeGrowthGlobal1X128 *u256.Uint // uint256
27 liquidity *u256.Uint // total amount of active liquidity in the pool (within current tick range)
28 ticks *avl.Tree // tick(int32) -> TickInfo
29 tickBitmaps *avl.Tree // tick(wordPos)(int16) -> bitMap(tickWord ^ mask)(*u256.Uint)
30 positions *avl.Tree // maps the key (caller, lower tick, upper tick) to a unique position
31
32 observationState *ObservationState // oracle state with historical observations
33}
34
35// Pool Getters methods
36func (p *Pool) PoolPath() string { return GetPoolPath(p.token0Path, p.token1Path, p.fee) }
37func (p *Pool) Token0Path() string { return p.token0Path }
38func (p *Pool) Token1Path() string { return p.token1Path }
39func (p *Pool) Fee() uint32 { return p.fee }
40func (p *Pool) Balances() Balances { return p.balances }
41func (p *Pool) BalanceToken0() *u256.Uint { return p.balances.token0 }
42func (p *Pool) BalanceToken1() *u256.Uint { return p.balances.token1 }
43func (p *Pool) TickSpacing() int32 { return p.tickSpacing }
44func (p *Pool) MaxLiquidityPerTick() *u256.Uint { return p.maxLiquidityPerTick }
45func (p *Pool) Slot0() Slot0 { return p.slot0 }
46func (p *Pool) Slot0SqrtPriceX96() *u256.Uint { return p.slot0.sqrtPriceX96 }
47func (p *Pool) Slot0Tick() int32 { return p.slot0.tick }
48func (p *Pool) Slot0FeeProtocol() uint8 { return p.slot0.feeProtocol }
49func (p *Pool) Slot0Unlocked() bool { return p.slot0.unlocked }
50func (p *Pool) FeeGrowthGlobal0X128() *u256.Uint { return p.feeGrowthGlobal0X128 }
51func (p *Pool) FeeGrowthGlobal1X128() *u256.Uint { return p.feeGrowthGlobal1X128 }
52func (p *Pool) ProtocolFees() ProtocolFees { return p.protocolFees }
53func (p *Pool) ProtocolFeesToken0() *u256.Uint { return p.protocolFees.token0 }
54func (p *Pool) ProtocolFeesToken1() *u256.Uint { return p.protocolFees.token1 }
55func (p *Pool) Liquidity() *u256.Uint { return p.liquidity }
56func (p *Pool) Ticks() *avl.Tree { return p.ticks }
57func (p *Pool) TickBitmaps() *avl.Tree { return p.tickBitmaps }
58func (p *Pool) Positions() *avl.Tree { return p.positions }
59func (p *Pool) ObservationState() *ObservationState { return p.observationState }
60
61// Pool Setters methods
62func (p *Pool) SetToken0Path(token0Path string) {
63 p.token0Path = token0Path
64}
65
66func (p *Pool) SetToken1Path(token1Path string) {
67 p.token1Path = token1Path
68}
69
70func (p *Pool) SetFee(fee uint32) {
71 p.fee = fee
72}
73
74func (p *Pool) SetBalances(balances Balances) {
75 p.balances = balances
76}
77
78func (p *Pool) SetBalanceToken0(token0 *u256.Uint) {
79 p.balances.token0 = token0
80}
81
82func (p *Pool) SetBalanceToken1(token1 *u256.Uint) {
83 p.balances.token1 = token1
84}
85
86func (p *Pool) SetTickSpacing(tickSpacing int32) {
87 p.tickSpacing = tickSpacing
88}
89
90func (p *Pool) SetMaxLiquidityPerTick(maxLiquidityPerTick *u256.Uint) {
91 p.maxLiquidityPerTick = maxLiquidityPerTick
92}
93
94func (p *Pool) SetSlot0(slot0 Slot0) {
95 p.slot0 = slot0
96}
97
98func (p *Pool) SetFeeGrowthGlobal0X128(feeGrowthGlobal0X128 *u256.Uint) {
99 p.feeGrowthGlobal0X128 = feeGrowthGlobal0X128
100}
101
102func (p *Pool) SetFeeGrowthGlobal1X128(feeGrowthGlobal1X128 *u256.Uint) {
103 p.feeGrowthGlobal1X128 = feeGrowthGlobal1X128
104}
105
106func (p *Pool) SetProtocolFees(protocolFees ProtocolFees) {
107 p.protocolFees = protocolFees
108}
109
110func (p *Pool) SetProtocolFeesToken0(token0 *u256.Uint) {
111 p.protocolFees.token0 = token0
112}
113
114func (p *Pool) SetProtocolFeesToken1(token1 *u256.Uint) {
115 p.protocolFees.token1 = token1
116}
117
118func (p *Pool) SetLiquidity(liquidity *u256.Uint) {
119 p.liquidity = liquidity
120}
121
122func (p *Pool) SetTicks(ticks *avl.Tree) {
123 p.ticks = ticks
124}
125
126func (p *Pool) SetTickBitmaps(tickBitmaps *avl.Tree) {
127 p.tickBitmaps = tickBitmaps
128}
129
130func (p *Pool) SetPositions(positions *avl.Tree) {
131 p.positions = positions
132}
133
134func (p *Pool) SetObservationState(observationState *ObservationState) {
135 p.observationState = observationState
136}
137
138func (p *Pool) HasTick(tick int32) bool {
139 tickKey := EncodeTickKey(tick)
140 return p.ticks.Has(tickKey)
141}
142
143func (p *Pool) GetTick(tick int32) (TickInfo, error) {
144 tickKey := EncodeTickKey(tick)
145
146 iTickInfo, ok := p.ticks.Get(tickKey)
147 if !ok {
148 return TickInfo{}, ufmt.Errorf("tick %d not found", tick)
149 }
150
151 tickInfo, ok := iTickInfo.(TickInfo)
152 if !ok {
153 panic(ufmt.Sprintf("failed to cast tickInfo to TickInfo: %T", iTickInfo))
154 }
155
156 return tickInfo, nil
157}
158
159func (p *Pool) SetTick(tick int32, tickInfo TickInfo) {
160 tickKey := EncodeTickKey(tick)
161 p.ticks.Set(tickKey, tickInfo)
162}
163
164func (p *Pool) DeleteTick(tick int32) {
165 tickKey := EncodeTickKey(tick)
166 p.ticks.Remove(tickKey)
167}
168
169func (p *Pool) IterateTicks(startTick int32, endTick int32, fn func(tick int32, tickInfo TickInfo) bool) {
170 startTickKey := EncodeTickKey(startTick)
171 endTickKey := EncodeTickKey(endTick + 1) // endTick inclusive
172
173 p.ticks.Iterate(startTickKey, endTickKey, func(key string, value any) bool {
174 tick := DecodeTickKey(key)
175
176 tickInfo, ok := value.(TickInfo)
177 if !ok {
178 return false
179 }
180
181 return fn(tick, tickInfo)
182 })
183}
184
185func (p *Pool) Clone() *Pool {
186 return &Pool{
187 token0Path: p.token0Path,
188 token1Path: p.token1Path,
189 fee: p.fee,
190 tickSpacing: p.tickSpacing,
191 slot0: Slot0{
192 sqrtPriceX96: p.slot0.sqrtPriceX96.Clone(),
193 tick: p.slot0.tick,
194 feeProtocol: p.slot0.feeProtocol,
195 unlocked: p.slot0.unlocked,
196 },
197 balances: Balances{TokenPair: p.balances.TokenPair.Clone()},
198 protocolFees: ProtocolFees{TokenPair: p.protocolFees.TokenPair.Clone()},
199 maxLiquidityPerTick: p.maxLiquidityPerTick.Clone(),
200 feeGrowthGlobal0X128: p.feeGrowthGlobal0X128.Clone(),
201 feeGrowthGlobal1X128: p.feeGrowthGlobal1X128.Clone(),
202 liquidity: p.liquidity.Clone(),
203 ticks: avl.NewTree(),
204 tickBitmaps: avl.NewTree(),
205 positions: avl.NewTree(),
206 observationState: NewObservationState(time.Now().Unix()),
207 }
208}
209
210func NewPool(
211 token0Path string,
212 token1Path string,
213 fee uint32,
214 sqrtPriceX96 *u256.Uint,
215 tickSpacing int32,
216 tick int32,
217 slot0FeeProtocol uint8,
218 maxLiquidityPerTick *u256.Uint,
219) *Pool {
220 slot0 := newSlot0(sqrtPriceX96, tick, slot0FeeProtocol, true)
221
222 return &Pool{
223 token0Path: token0Path,
224 token1Path: token1Path,
225 balances: newBalances(),
226 fee: fee,
227 tickSpacing: tickSpacing,
228 maxLiquidityPerTick: maxLiquidityPerTick,
229 slot0: slot0,
230 feeGrowthGlobal0X128: u256.Zero(),
231 feeGrowthGlobal1X128: u256.Zero(),
232 protocolFees: newProtocolFees(),
233 liquidity: u256.Zero(),
234 ticks: avl.NewTree(),
235 tickBitmaps: avl.NewTree(),
236 positions: avl.NewTree(),
237 observationState: NewObservationState(time.Now().Unix()),
238 }
239}
240
241type Balances struct{ TokenPair }
242
243func newBalances() Balances {
244 return Balances{
245 TokenPair: NewTokenPair(u256.Zero(), u256.Zero()),
246 }
247}
248
249type ProtocolFees struct{ TokenPair }
250
251func newProtocolFees() ProtocolFees {
252 return ProtocolFees{
253 TokenPair: NewTokenPair(u256.Zero(), u256.Zero()),
254 }
255}
256
257type TokenPair struct {
258 token0, token1 *u256.Uint
259}
260
261func NewTokenPair(token0, token1 *u256.Uint) TokenPair {
262 return TokenPair{
263 token0: token0,
264 token1: token1,
265 }
266}
267
268func (t *TokenPair) Token0() *u256.Uint { return t.token0 }
269func (t *TokenPair) Token1() *u256.Uint { return t.token1 }
270
271func (t *TokenPair) SetToken0(token0 *u256.Uint) { t.token0 = token0 }
272func (t *TokenPair) SetToken1(token1 *u256.Uint) { t.token1 = token1 }
273
274func (t *TokenPair) Clone() TokenPair {
275 return NewTokenPair(
276 t.token0.Clone(),
277 t.token1.Clone(),
278 )
279}
280
281type Slot0 struct {
282 sqrtPriceX96 *u256.Uint // current price of the pool as a sqrt(token1/token0) Q96 value
283 tick int32 // current tick of the pool, i.e according to the last tick transition that was run
284 feeProtocol uint8 // protocol fee for both tokens of the pool
285 unlocked bool // whether the pool is currently locked to reentrancy
286}
287
288func (s *Slot0) SqrtPriceX96() *u256.Uint { return s.sqrtPriceX96 }
289func (s *Slot0) Tick() int32 { return s.tick }
290func (s *Slot0) FeeProtocol() uint8 { return s.feeProtocol }
291func (s *Slot0) Unlocked() bool { return s.unlocked }
292
293func (s *Slot0) SetSqrtPriceX96(sqrtPriceX96 *u256.Uint) { s.sqrtPriceX96 = sqrtPriceX96 }
294func (s *Slot0) SetTick(tick int32) { s.tick = tick }
295func (s *Slot0) SetFeeProtocol(feeProtocol uint8) { s.feeProtocol = feeProtocol }
296func (s *Slot0) SetUnlocked(unlocked bool) { s.unlocked = unlocked }
297
298func newSlot0(
299 sqrtPriceX96 *u256.Uint,
300 tick int32,
301 feeProtocol uint8,
302 unlocked bool,
303) Slot0 {
304 return Slot0{
305 sqrtPriceX96: sqrtPriceX96.Clone(),
306 tick: tick,
307 feeProtocol: feeProtocol,
308 unlocked: unlocked,
309 }
310}
311
312// TickInfo stores information about a specific tick in the pool.
313// TIcks represent discrete price points that can be used as boundaries for positions.
314type TickInfo struct {
315 liquidityGross *u256.Uint // total position liquidity that references this tick
316 liquidityNet *i256.Int // amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left)
317
318 // fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick)
319 // only has relative meaning, not absolute โ the value depends on when the tick is initialized
320 feeGrowthOutside0X128 *u256.Uint
321 feeGrowthOutside1X128 *u256.Uint
322
323 tickCumulativeOutside int64 // cumulative tick value on the other side of the tick
324
325 // the seconds per unit of liquidity on the _other_ side of this tick (relative to the current tick)
326 // only has relative meaning, not absolute โ the value depends on when the tick is initialized
327 secondsPerLiquidityOutsideX128 *u256.Uint
328
329 // the seconds spent on the other side of the tick (relative to the current tick)
330 // only has relative meaning, not absolute โ the value depends on when the tick is initialized
331 secondsOutside uint32
332
333 initialized bool // whether the tick is initialized
334}
335
336// TickInfo Getters methods
337func (t *TickInfo) LiquidityGross() *u256.Uint { return t.liquidityGross }
338func (t *TickInfo) LiquidityNet() *i256.Int { return t.liquidityNet }
339func (t *TickInfo) FeeGrowthOutside0X128() *u256.Uint { return t.feeGrowthOutside0X128 }
340func (t *TickInfo) FeeGrowthOutside1X128() *u256.Uint { return t.feeGrowthOutside1X128 }
341func (t *TickInfo) SecondsPerLiquidityOutsideX128() *u256.Uint {
342 return t.secondsPerLiquidityOutsideX128
343}
344func (t *TickInfo) SecondsOutside() uint32 { return t.secondsOutside }
345func (t *TickInfo) Initialized() bool { return t.initialized }
346func (t *TickInfo) TickCumulativeOutside() int64 { return t.tickCumulativeOutside }
347
348// TickInfo Setters methods
349func (t *TickInfo) SetLiquidityGross(liquidityGross *u256.Uint) {
350 t.liquidityGross = liquidityGross
351}
352
353func (t *TickInfo) SetLiquidityNet(liquidityNet *i256.Int) {
354 t.liquidityNet = liquidityNet
355}
356
357func (t *TickInfo) SetFeeGrowthOutside0X128(feeGrowthOutside0X128 *u256.Uint) {
358 t.feeGrowthOutside0X128 = feeGrowthOutside0X128
359}
360
361func (t *TickInfo) SetFeeGrowthOutside1X128(feeGrowthOutside1X128 *u256.Uint) {
362 t.feeGrowthOutside1X128 = feeGrowthOutside1X128
363}
364
365func (t *TickInfo) SetSecondsPerLiquidityOutsideX128(secondsPerLiquidityOutsideX128 *u256.Uint) {
366 t.secondsPerLiquidityOutsideX128 = secondsPerLiquidityOutsideX128
367}
368
369func (t *TickInfo) SetSecondsOutside(secondsOutside uint32) {
370 t.secondsOutside = secondsOutside
371}
372
373func (t *TickInfo) SetInitialized(initialized bool) {
374 t.initialized = initialized
375}
376
377func (t *TickInfo) SetTickCumulativeOutside(tickCumulativeOutside int64) {
378 t.tickCumulativeOutside = tickCumulativeOutside
379}
380
381func NewTickInfo() TickInfo {
382 return TickInfo{
383 liquidityGross: u256.Zero(),
384 liquidityNet: i256.Zero(),
385 feeGrowthOutside0X128: u256.Zero(),
386 feeGrowthOutside1X128: u256.Zero(),
387 secondsPerLiquidityOutsideX128: u256.Zero(),
388 secondsOutside: 0,
389 initialized: false,
390 tickCumulativeOutside: 0,
391 }
392}
393
394func cloneTickInfo(src TickInfo) TickInfo {
395 return TickInfo{
396 feeGrowthOutside0X128: src.feeGrowthOutside0X128.Clone(),
397 feeGrowthOutside1X128: src.feeGrowthOutside1X128.Clone(),
398 liquidityGross: src.liquidityGross.Clone(),
399 liquidityNet: src.liquidityNet.Clone(),
400 tickCumulativeOutside: src.tickCumulativeOutside,
401 secondsPerLiquidityOutsideX128: src.secondsPerLiquidityOutsideX128.Clone(),
402 secondsOutside: src.secondsOutside,
403 initialized: src.initialized,
404 }
405}
406
407type PositionInfo struct {
408 liquidity *u256.Uint // amount of liquidity owned by this position
409
410 // Fee growth per unit of liquidity as of the last update
411 // Used to calculate uncollected fees for token0
412 feeGrowthInside0LastX128 *u256.Uint
413
414 // Fee growth per unit of liquidity as of the last update
415 // Used to calculate uncollected fees for token1
416 feeGrowthInside1LastX128 *u256.Uint
417
418 // accumulated fees in token0 waiting to be collected
419 tokensOwed0 *u256.Uint
420
421 // accumulated fees in token1 waiting to be collected
422 tokensOwed1 *u256.Uint
423}
424
425func (p *PositionInfo) Liquidity() *u256.Uint { return p.liquidity }
426func (p *PositionInfo) FeeGrowthInside0LastX128() *u256.Uint { return p.feeGrowthInside0LastX128 }
427func (p *PositionInfo) FeeGrowthInside1LastX128() *u256.Uint { return p.feeGrowthInside1LastX128 }
428func (p *PositionInfo) TokensOwed0() *u256.Uint { return p.tokensOwed0 }
429func (p *PositionInfo) TokensOwed1() *u256.Uint { return p.tokensOwed1 }
430
431func (p *PositionInfo) SetLiquidity(liquidity *u256.Uint) {
432 p.liquidity = liquidity
433}
434
435func (p *PositionInfo) SetFeeGrowthInside0LastX128(feeGrowthInside0LastX128 *u256.Uint) {
436 p.feeGrowthInside0LastX128 = feeGrowthInside0LastX128
437}
438
439func (p *PositionInfo) SetFeeGrowthInside1LastX128(feeGrowthInside1LastX128 *u256.Uint) {
440 p.feeGrowthInside1LastX128 = feeGrowthInside1LastX128
441}
442
443func (p *PositionInfo) SetTokensOwed0(tokensOwed0 *u256.Uint) {
444 p.tokensOwed0 = tokensOwed0
445}
446
447func (p *PositionInfo) SetTokensOwed1(tokensOwed1 *u256.Uint) {
448 p.tokensOwed1 = tokensOwed1
449}
450
451func NewPositionInfo(
452 liquidity *u256.Uint,
453 feeGrowthInside0LastX128 *u256.Uint,
454 feeGrowthInside1LastX128 *u256.Uint,
455 tokensOwed0 *u256.Uint,
456 tokensOwed1 *u256.Uint,
457) PositionInfo {
458 return PositionInfo{
459 liquidity: liquidity,
460 feeGrowthInside0LastX128: feeGrowthInside0LastX128,
461 feeGrowthInside1LastX128: feeGrowthInside1LastX128,
462 tokensOwed0: tokensOwed0,
463 tokensOwed1: tokensOwed1,
464 }
465}