Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}