pool.gno
33.54 Kb · 998 lines
1package pool
2
3import (
4 bptree "gno.land/p/nt/bptree/v0"
5 ufmt "gno.land/p/nt/ufmt/v0"
6
7 u256 "gno.land/p/gnoswap/uint256/v1"
8)
9
10// Pool describes a single pool's state.
11// A pool is identified with a unique key (token0, token1, fee), where token0 < token1.
12type Pool struct {
13 // token0/token1 path of the pool
14 token0Path string
15 token1Path string
16 fee uint32 // fee tier of the pool
17 tickSpacing int32 // spacing between ticks
18 slot0 Slot0
19 balances TokenPair // balances of the pool
20 protocolFees TokenPair
21 feeGrowthGlobal0X128 *u256.Uint // uint256
22 feeGrowthGlobal1X128 *u256.Uint // uint256
23 liquidity *u256.Uint // total amount of active liquidity in the pool (within current tick range)
24 ticks *bptree.BPTree // tick(int32) -> TickInfo
25 tickBitmaps map[int16]string // tick(wordPos)(int16) -> bitMap(tickWord ^ mask)(string)
26 positions *bptree.BPTree // maps encoded lower/upper tick pairs to aggregate pool accounting
27}
28
29// Pool Getters methods
30// PoolPath returns the canonical pool path derived from token0, token1, and the fee tier.
31//
32// Returns:
33// - string: pool identifier assembled from the pool's token paths and fee.
34func (p *Pool) PoolPath() string { return GetPoolPath(p.token0Path, p.token1Path, p.fee) }
35
36// Token0Path returns the path of the pool's token0 asset.
37//
38// Returns:
39// - string: token0 path stored in the pool.
40func (p *Pool) Token0Path() string { return p.token0Path }
41
42// Token1Path returns the path of the pool's token1 asset.
43//
44// Returns:
45// - string: token1 path stored in the pool.
46func (p *Pool) Token1Path() string { return p.token1Path }
47
48// Fee returns the pool's fee tier.
49//
50// Returns:
51// - uint32: fee tier used by swaps in this pool.
52func (p *Pool) Fee() uint32 { return p.fee }
53
54// Balances returns the pool's current token balances.
55//
56// Returns:
57// - TokenPair: token0 and token1 balances tracked by the pool.
58func (p *Pool) Balances() TokenPair { return p.balances }
59
60// BalanceToken0 returns the pool's current token0 balance.
61//
62// Returns:
63// - int64: token0 balance available in the pool.
64func (p *Pool) BalanceToken0() int64 { return p.balances.token0 }
65
66// BalanceToken1 returns the pool's current token1 balance.
67//
68// Returns:
69// - int64: token1 balance available in the pool.
70func (p *Pool) BalanceToken1() int64 { return p.balances.token1 }
71
72// TickSpacing returns the permitted spacing between initialized ticks.
73//
74// Returns:
75// - int32: tick spacing configured for the pool.
76func (p *Pool) TickSpacing() int32 { return p.tickSpacing }
77
78// Slot0 returns the pool's current price, tick, lock, and oracle cursor state.
79//
80// Returns:
81// - Slot0: current slot0 state, including the price and observation metadata.
82func (p *Pool) Slot0() Slot0 { return p.slot0 }
83
84// Slot0SqrtPriceX96 returns the current square-root price in Q96 fixed-point form.
85//
86// Returns:
87// - *u256.Uint: stored sqrt(token1/token0) price scaled by 2^96.
88func (p *Pool) Slot0SqrtPriceX96() *u256.Uint { return p.slot0.sqrtPriceX96 }
89
90// Slot0Tick returns the current pool tick.
91//
92// Returns:
93// - int32: tick corresponding to the current pool price.
94func (p *Pool) Slot0Tick() int32 { return p.slot0.tick }
95
96// Slot0FeeProtocol returns the packed protocol-fee denominators from slot0.
97//
98// Returns:
99// - uint8: packed token0/token1 protocol-fee denominator configuration.
100func (p *Pool) Slot0FeeProtocol() uint8 { return p.slot0.feeProtocol }
101
102// Slot0Unlocked reports whether the pool is currently available for reentrant operations.
103//
104// Returns:
105// - bool: true when the pool is unlocked; false while its swap lock is held.
106func (p *Pool) Slot0Unlocked() bool { return p.slot0.unlocked }
107
108// FeeGrowthGlobal0X128 returns cumulative token0 fee growth per unit of liquidity.
109//
110// Returns:
111// - *u256.Uint: token0 fee-growth accumulator scaled by 2^128.
112func (p *Pool) FeeGrowthGlobal0X128() *u256.Uint { return p.feeGrowthGlobal0X128 }
113
114// FeeGrowthGlobal1X128 returns cumulative token1 fee growth per unit of liquidity.
115//
116// Returns:
117// - *u256.Uint: token1 fee-growth accumulator scaled by 2^128.
118func (p *Pool) FeeGrowthGlobal1X128() *u256.Uint { return p.feeGrowthGlobal1X128 }
119
120// ProtocolFees returns protocol fees accrued in both pool tokens.
121//
122// Returns:
123// - TokenPair: token0 and token1 protocol-fee balances.
124func (p *Pool) ProtocolFees() TokenPair { return p.protocolFees }
125
126// ProtocolFeesToken0 returns protocol fees accrued in token0.
127//
128// Returns:
129// - int64: token0 amount reserved as protocol fees.
130func (p *Pool) ProtocolFeesToken0() int64 { return p.protocolFees.token0 }
131
132// ProtocolFeesToken1 returns protocol fees accrued in token1.
133//
134// Returns:
135// - int64: token1 amount reserved as protocol fees.
136func (p *Pool) ProtocolFeesToken1() int64 { return p.protocolFees.token1 }
137
138// Liquidity returns the pool's active liquidity for the current tick range.
139//
140// Returns:
141// - *u256.Uint: active liquidity amount.
142func (p *Pool) Liquidity() *u256.Uint { return p.liquidity }
143
144// Ticks returns the tree containing tick state keyed by encoded tick.
145//
146// Returns:
147// - *bptree.BPTree: pool tick storage tree.
148func (p *Pool) Ticks() *bptree.BPTree { return p.ticks }
149
150// TickBitmaps returns the map of initialized-tick bitmap words.
151//
152// Returns:
153// - map[int16]string: bitmap words keyed by signed word position.
154func (p *Pool) TickBitmaps() map[int16]string { return p.tickBitmaps }
155
156// Positions returns the tree containing aggregate position state by range key.
157//
158// Returns:
159// - *bptree.BPTree: pool position storage tree.
160func (p *Pool) Positions() *bptree.BPTree { return p.positions }
161
162// GetPosition returns the position information for key.
163//
164// Parameters:
165// - key: encoded lower/upper tick-range key to look up.
166//
167// Returns:
168// - PositionInfo: stored aggregate position for the key.
169// - error: non-nil when the key is absent or contains a value of the wrong type.
170func (p *Pool) GetPosition(key string) (PositionInfo, error) {
171 iPositionInfo := p.positions.Get(key)
172 if iPositionInfo == nil {
173 return PositionInfo{}, ufmt.Errorf("position %s not found", key)
174 }
175
176 positionInfo, ok := iPositionInfo.(PositionInfo)
177 if !ok {
178 return PositionInfo{}, ufmt.Errorf("position %s has invalid type", key)
179 }
180
181 return positionInfo, nil
182}
183
184// Pool Setters methods
185// SetToken0Path stores the path of the pool's token0 asset.
186//
187// Parameters:
188// - token0Path: token0 asset path to store.
189func (p *Pool) SetToken0Path(token0Path string) {
190 p.token0Path = token0Path
191}
192
193// SetToken1Path stores the path of the pool's token1 asset.
194//
195// Parameters:
196// - token1Path: token1 asset path to store.
197func (p *Pool) SetToken1Path(token1Path string) {
198 p.token1Path = token1Path
199}
200
201// SetFee stores the pool's fee tier.
202//
203// Parameters:
204// - fee: fee tier to use for swaps in this pool.
205func (p *Pool) SetFee(fee uint32) {
206 p.fee = fee
207}
208
209// SetBalances replaces the pool's tracked balances for both tokens.
210//
211// Parameters:
212// - balances: token0 and token1 balances to store.
213func (p *Pool) SetBalances(balances TokenPair) {
214 p.balances = balances
215}
216
217// SetBalanceToken0 updates the pool's tracked token0 balance.
218//
219// Parameters:
220// - token0: new token0 balance.
221func (p *Pool) SetBalanceToken0(token0 int64) {
222 p.balances.token0 = token0
223}
224
225// SetBalanceToken1 updates the pool's tracked token1 balance.
226//
227// Parameters:
228// - token1: new token1 balance.
229func (p *Pool) SetBalanceToken1(token1 int64) {
230 p.balances.token1 = token1
231}
232
233// SetTickSpacing stores the permitted spacing between initialized ticks.
234//
235// Parameters:
236// - tickSpacing: tick spacing to configure for the pool.
237func (p *Pool) SetTickSpacing(tickSpacing int32) {
238 p.tickSpacing = tickSpacing
239}
240
241// SetSlot0 replaces the pool's current price, tick, lock, and oracle cursor state.
242//
243// Parameters:
244// - slot0: slot0 state to store.
245func (p *Pool) SetSlot0(slot0 Slot0) {
246 p.slot0 = slot0
247}
248
249// SetFeeGrowthGlobal0X128 stores the token0 fee-growth accumulator.
250//
251// Parameters:
252// - feeGrowthGlobal0X128: token0 fee growth per liquidity unit, scaled by 2^128.
253func (p *Pool) SetFeeGrowthGlobal0X128(feeGrowthGlobal0X128 *u256.Uint) {
254 p.feeGrowthGlobal0X128 = u256.Zero().Set(feeGrowthGlobal0X128)
255}
256
257// SetFeeGrowthGlobal1X128 stores the token1 fee-growth accumulator.
258//
259// Parameters:
260// - feeGrowthGlobal1X128: token1 fee growth per liquidity unit, scaled by 2^128.
261func (p *Pool) SetFeeGrowthGlobal1X128(feeGrowthGlobal1X128 *u256.Uint) {
262 p.feeGrowthGlobal1X128 = u256.Zero().Set(feeGrowthGlobal1X128)
263}
264
265// SetProtocolFees replaces the pool's accrued protocol fees for both tokens.
266//
267// Parameters:
268// - protocolFees: token0 and token1 protocol-fee balances to store.
269func (p *Pool) SetProtocolFees(protocolFees TokenPair) {
270 p.protocolFees = protocolFees
271}
272
273// SetProtocolFeesToken0 updates the pool's accrued token0 protocol fees.
274//
275// Parameters:
276// - token0: new token0 protocol-fee balance.
277func (p *Pool) SetProtocolFeesToken0(token0 int64) {
278 p.protocolFees.token0 = token0
279}
280
281// SetProtocolFeesToken1 updates the pool's accrued token1 protocol fees.
282//
283// Parameters:
284// - token1: new token1 protocol-fee balance.
285func (p *Pool) SetProtocolFeesToken1(token1 int64) {
286 p.protocolFees.token1 = token1
287}
288
289// SetLiquidity stores the pool's active liquidity for the current tick range.
290//
291// Parameters:
292// - liquidity: active liquidity amount to store.
293func (p *Pool) SetLiquidity(liquidity *u256.Uint) {
294 p.liquidity = u256.Zero().Set(liquidity)
295}
296
297// SetTicks replaces the tree containing pool tick state.
298//
299// Parameters:
300// - ticks: tick storage tree to use.
301func (p *Pool) SetTicks(ticks *bptree.BPTree) {
302 p.ticks = ticks
303}
304
305// SetTickBitmap stores one initialized-tick bitmap word.
306//
307// Parameters:
308// - wordPos: signed bitmap word position.
309// - tickBitmap: encoded bitmap bits for that word.
310func (p *Pool) SetTickBitmap(wordPos int16, tickBitmap string) {
311 p.tickBitmaps[wordPos] = tickBitmap
312}
313
314// DeleteTickBitmap deletes the tick bitmap for the given word position.
315//
316// Parameters:
317// - wordPos: signed bitmap word position to remove.
318func (p *Pool) DeleteTickBitmap(wordPos int16) {
319 delete(p.tickBitmaps, wordPos)
320}
321
322// SetTickBitmaps replaces the map of initialized-tick bitmap words.
323//
324// Parameters:
325// - tickBitmaps: bitmap words keyed by signed word position.
326func (p *Pool) SetTickBitmaps(tickBitmaps map[int16]string) {
327 p.tickBitmaps = tickBitmaps
328}
329
330// SetPositions replaces the tree containing aggregate position state.
331//
332// Parameters:
333// - positions: position storage tree to use.
334func (p *Pool) SetPositions(positions *bptree.BPTree) {
335 p.positions = positions
336}
337
338// SetPosition stores position information under an encoded range key.
339//
340// Parameters:
341// - posKey: encoded lower/upper tick-range key.
342// - positionInfo: aggregate position state to store.
343func (p *Pool) SetPosition(posKey string, positionInfo PositionInfo) {
344 p.positions.Set(posKey, positionInfo)
345}
346
347// HasTick reports whether a tick entry exists in the pool's tick tree.
348//
349// Parameters:
350// - tick: tick index to check.
351//
352// Returns:
353// - bool: true when the encoded tick is present; false otherwise.
354func (p *Pool) HasTick(tick int32) bool {
355 tickKey := EncodeTickKey(tick)
356 return p.ticks.Has(tickKey)
357}
358
359// GetTick returns the state stored for a tick.
360//
361// Parameters:
362// - tick: tick index to look up.
363//
364// Returns:
365// - TickInfo: stored tick state.
366// - error: non-nil when the tick is absent; a present value of the wrong type causes a panic.
367func (p *Pool) GetTick(tick int32) (TickInfo, error) {
368 tickKey := EncodeTickKey(tick)
369
370 iTickInfo := p.ticks.Get(tickKey)
371 if iTickInfo == nil {
372 return TickInfo{}, ufmt.Errorf("tick %d not found", tick)
373 }
374
375 tickInfo, ok := iTickInfo.(TickInfo)
376 if !ok {
377 panic(ufmt.Sprintf("failed to cast tickInfo to TickInfo: %T", iTickInfo))
378 }
379
380 return tickInfo, nil
381}
382
383// SetTick stores tick state under its encoded tick key.
384//
385// Parameters:
386// - tick: tick index to store.
387// - tickInfo: tick state associated with the index.
388func (p *Pool) SetTick(tick int32, tickInfo TickInfo) {
389 tickKey := EncodeTickKey(tick)
390 p.ticks.Set(tickKey, tickInfo)
391}
392
393// DeleteTick removes the tick state for the given tick index.
394//
395// Parameters:
396// - tick: tick index to remove.
397func (p *Pool) DeleteTick(tick int32) {
398 tickKey := EncodeTickKey(tick)
399 p.ticks.Remove(tickKey)
400}
401
402// IterateTicks visits pool ticks in the inclusive range [startTick, endTick].
403// Iteration stops when the callback returns true.
404//
405// Parameters:
406// - startTick: first tick index in the inclusive range.
407// - endTick: last tick index in the inclusive range.
408// - fn: callback receiving each decoded tick and its state; return true to stop iteration.
409func (p *Pool) IterateTicks(startTick int32, endTick int32, fn func(tick int32, tickInfo TickInfo) bool) {
410 startTickKey := EncodeTickKey(startTick)
411 endTickKey := EncodeTickKey(endTick + 1) // endTick inclusive
412
413 p.ticks.Iterate(startTickKey, endTickKey, func(key string, value any) bool {
414 tick := DecodeTickKey(key)
415
416 tickInfo, ok := value.(TickInfo)
417 if !ok {
418 return false
419 }
420
421 return fn(tick, tickInfo)
422 })
423}
424
425// Clone copies a pool's own fields and leaves its collections nil: ticks,
426// tickBitmaps, and positions are not copied. Oracle observations are stored
427// separately from Pool.
428//
429// The copy is shallow because the read-only pool view clones every entry a
430// caller reads, so copying the collections would walk the whole tick tree for
431// each entry on a page. Read them through their own lookups instead:
432// GetTickInfo / GetInitializedTicksInRange for ticks, GetTickBitmaps for the
433// bitmaps, GetPoolPositions for positions, and GetSlot0 / GetObservationAt for
434// oracle metadata and entries. A caller that needs a working copy of a
435// collection -- DrySwap is the only one -- assembles it from those getters.
436//
437// Returns:
438// - *Pool: shallow pool copy with scalar state and cloned numeric values; nil when the receiver is nil.
439func (p *Pool) Clone() *Pool {
440 if p == nil {
441 return nil
442 }
443
444 return &Pool{
445 token0Path: p.token0Path,
446 token1Path: p.token1Path,
447 fee: p.fee,
448 tickSpacing: p.tickSpacing,
449 slot0: p.slot0.Clone(),
450 balances: p.balances,
451 protocolFees: p.protocolFees,
452 feeGrowthGlobal0X128: p.feeGrowthGlobal0X128.Clone(),
453 feeGrowthGlobal1X128: p.feeGrowthGlobal1X128.Clone(),
454 liquidity: p.liquidity.Clone(),
455 ticks: nil,
456 tickBitmaps: nil,
457 positions: nil,
458 }
459}
460
461// NewPool constructs a pool with the supplied token pair, fee, price, and tick configuration.
462//
463// Parameters:
464// - token0Path: path of the pool's token0 asset.
465// - token1Path: path of the pool's token1 asset.
466// - fee: fee tier used by swaps.
467// - sqrtPriceX96: initial sqrt(token1/token0) price scaled by 2^96.
468// - tickSpacing: spacing between initialized ticks.
469// - tick: initial current tick.
470// - slot0FeeProtocol: packed protocol-fee denominator configuration for slot0.
471//
472// Returns:
473// - *Pool: initialized pool with empty balances, fee growth, ticks, bitmaps, and positions.
474func NewPool(
475 token0Path string,
476 token1Path string,
477 fee uint32,
478 sqrtPriceX96 *u256.Uint,
479 tickSpacing int32,
480 tick int32,
481 slot0FeeProtocol uint8,
482) *Pool {
483 slot0 := NewSlot0(sqrtPriceX96, tick, slot0FeeProtocol, true)
484
485 return &Pool{
486 token0Path: token0Path,
487 token1Path: token1Path,
488 balances: NewTokenPair(),
489 fee: fee,
490 tickSpacing: tickSpacing,
491 slot0: slot0,
492 feeGrowthGlobal0X128: u256.Zero(),
493 feeGrowthGlobal1X128: u256.Zero(),
494 protocolFees: NewTokenPair(),
495 liquidity: u256.Zero(),
496 ticks: bptree.NewBPTreeN(32),
497 tickBitmaps: make(map[int16]string),
498 positions: bptree.NewBPTreeN(16),
499 }
500}
501
502// NewPoolsTree creates the BPTree used to store pools by pool path.
503//
504// Returns:
505// - *bptree.BPTree: empty pool storage tree with fanout 32.
506func NewPoolsTree() *bptree.BPTree {
507 return bptree.NewBPTreeN(32)
508}
509
510// NewPoolTicksTree creates a BPTree for storing pool tick info (fanout 32),
511// owned by the pool domain realm so leaf-slot writes are not readonly tainted.
512//
513// Returns:
514// - *bptree.BPTree: empty tick storage tree with fanout 32.
515func NewPoolTicksTree() *bptree.BPTree {
516 return bptree.NewBPTreeN(32)
517}
518
519// NewPoolPositionsTree creates a BPTree for storing pool position info (fanout 16),
520// owned by the pool domain realm so leaf-slot writes are not readonly tainted.
521//
522// Returns:
523// - *bptree.BPTree: empty position storage tree with fanout 16.
524func NewPoolPositionsTree() *bptree.BPTree {
525 return bptree.NewBPTreeN(16)
526}
527
528type TokenPair struct {
529 token0, token1 int64
530}
531
532// NewTokenPair creates a token-pair balance value initialized to zero.
533//
534// Returns:
535// - TokenPair: zero token0 and token1 balances.
536func NewTokenPair() TokenPair {
537 return TokenPair{
538 token0: 0,
539 token1: 0,
540 }
541}
542
543// Token0 returns the token0 amount in the pair.
544//
545// Returns:
546// - int64: stored token0 amount.
547func (p *TokenPair) Token0() int64 { return p.token0 }
548
549// Token1 returns the token1 amount in the pair.
550//
551// Returns:
552// - int64: stored token1 amount.
553func (p *TokenPair) Token1() int64 { return p.token1 }
554
555// SetToken0 updates the token0 amount in the pair.
556//
557// Parameters:
558// - token0: token0 amount to store.
559func (p *TokenPair) SetToken0(token0 int64) { p.token0 = token0 }
560
561// SetToken1 updates the token1 amount in the pair.
562//
563// Parameters:
564// - token1: token1 amount to store.
565func (p *TokenPair) SetToken1(token1 int64) { p.token1 = token1 }
566
567// Slot0 mirrors Uniswap V3's slot0(): current price/tick/protocol-fee/lock
568// state and the oracle cursor/capacity metadata.
569type Slot0 struct {
570 sqrtPriceX96 *u256.Uint // current price of the pool as a sqrt(token1/token0) Q96 value
571 tick int32 // current tick of the pool, i.e according to the last tick transition that was run
572 feeProtocol uint8 // packed protocol-fee denominators: token0 low nibble, token1 high nibble
573 unlocked bool // whether the pool is currently locked to reentrancy
574 observationIndex uint16 // the index of the most-recently written observation
575 observationCardinality uint16 // the current maximum number of observations stored
576 observationCardinalityNext uint16 // the next maximum number of observations to store
577}
578
579// SqrtPriceX96 returns a copy of the current sqrt price in Q96 fixed-point form.
580//
581// Returns:
582// - *u256.Uint: cloned sqrt(token1/token0) price scaled by 2^96.
583func (s *Slot0) SqrtPriceX96() *u256.Uint { return s.sqrtPriceX96.Clone() }
584
585// Tick returns the current pool tick recorded in slot0.
586//
587// Returns:
588// - int32: current tick.
589func (s *Slot0) Tick() int32 { return s.tick }
590
591// FeeProtocol returns the packed protocol-fee denominators in slot0.
592//
593// Returns:
594// - uint8: packed token0/token1 protocol-fee denominator configuration.
595func (s *Slot0) FeeProtocol() uint8 { return s.feeProtocol }
596
597// Unlocked reports whether the pool's reentrancy lock is open.
598//
599// Returns:
600// - bool: true when unlocked and false while the pool is locked.
601func (s *Slot0) Unlocked() bool { return s.unlocked }
602
603// ObservationIndex returns the index of the most recently written observation.
604//
605// Returns:
606// - uint16: current observation ring-buffer index.
607func (s *Slot0) ObservationIndex() uint16 { return s.observationIndex }
608
609// ObservationCardinality returns the number of observation slots currently available.
610//
611// Returns:
612// - uint16: current observation capacity.
613func (s *Slot0) ObservationCardinality() uint16 { return s.observationCardinality }
614
615// ObservationCardinalityNext returns the requested future observation capacity.
616//
617// Returns:
618// - uint16: next observation capacity to use when the ring grows.
619func (s *Slot0) ObservationCardinalityNext() uint16 { return s.observationCardinalityNext }
620
621// Clone returns a value-type copy of Slot0 that shares no mutable state with
622// the original, so callers cannot reach back into pool internals through the
623// returned sqrtPriceX96 pointer.
624//
625// Returns:
626// - Slot0: value copy with a cloned sqrt-price pointer.
627func (s *Slot0) Clone() Slot0 {
628 return Slot0{
629 sqrtPriceX96: s.sqrtPriceX96.Clone(),
630 tick: s.tick,
631 feeProtocol: s.feeProtocol,
632 unlocked: s.unlocked,
633 observationIndex: s.observationIndex,
634 observationCardinality: s.observationCardinality,
635 observationCardinalityNext: s.observationCardinalityNext,
636 }
637}
638
639// SetSqrtPriceX96 updates the slot0 sqrt price.
640//
641// Parameters:
642// - sqrtPriceX96: sqrt(token1/token0) price scaled by 2^96; it is cloned before storage.
643func (s *Slot0) SetSqrtPriceX96(sqrtPriceX96 *u256.Uint) { s.sqrtPriceX96 = sqrtPriceX96.Clone() }
644
645// SetTick updates the current slot0 tick.
646//
647// Parameters:
648// - tick: current pool tick to store.
649func (s *Slot0) SetTick(tick int32) { s.tick = tick }
650
651// SetFeeProtocol updates the packed slot0 protocol-fee denominators.
652//
653// Parameters:
654// - feeProtocol: packed token0/token1 protocol-fee denominator configuration.
655func (s *Slot0) SetFeeProtocol(feeProtocol uint8) { s.feeProtocol = feeProtocol }
656
657// SetUnlocked updates the slot0 reentrancy-lock state.
658//
659// Parameters:
660// - unlocked: true to mark the pool unlocked, false to mark it locked.
661func (s *Slot0) SetUnlocked(unlocked bool) { s.unlocked = unlocked }
662
663// SetObservationIndex updates the index of the most recently written observation.
664//
665// Parameters:
666// - observationIndex: observation ring-buffer index to store.
667func (s *Slot0) SetObservationIndex(observationIndex uint16) {
668 s.observationIndex = observationIndex
669}
670
671// SetObservationCardinality updates the current observation capacity.
672//
673// Parameters:
674// - observationCardinality: current number of observation slots available.
675func (s *Slot0) SetObservationCardinality(observationCardinality uint16) {
676 s.observationCardinality = observationCardinality
677}
678
679// SetObservationCardinalityNext updates the requested future observation capacity.
680//
681// Parameters:
682// - observationCardinalityNext: next capacity to use when the ring grows.
683func (s *Slot0) SetObservationCardinalityNext(observationCardinalityNext uint16) {
684 s.observationCardinalityNext = observationCardinalityNext
685}
686
687// NewSlot0 constructs slot0 with the supplied price, tick, protocol fee, and lock state.
688// Observation metadata starts with index zero and cardinality one.
689//
690// Parameters:
691// - sqrtPriceX96: initial sqrt(token1/token0) price scaled by 2^96.
692// - tick: initial current pool tick.
693// - feeProtocol: packed token0/token1 protocol-fee denominator configuration.
694// - unlocked: initial reentrancy-lock state.
695//
696// Returns:
697// - Slot0: initialized slot0 value with one observation slot.
698func NewSlot0(
699 sqrtPriceX96 *u256.Uint,
700 tick int32,
701 feeProtocol uint8,
702 unlocked bool,
703) Slot0 {
704 return Slot0{
705 sqrtPriceX96: sqrtPriceX96.Clone(),
706 tick: tick,
707 feeProtocol: feeProtocol,
708 unlocked: unlocked,
709 observationIndex: 0,
710 observationCardinality: 1,
711 observationCardinalityNext: 1,
712 }
713}
714
715// TickInfo stores information about a specific tick in the pool.
716// TIcks represent discrete price points that can be used as boundaries for positions.
717type TickInfo struct {
718 liquidityGross string // total position liquidity that references this tick
719 liquidityNet string // amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left)
720
721 // fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick)
722 // only has relative meaning, not absolute — the value depends on when the tick is initialized
723 feeGrowthOutside0X128 string
724 feeGrowthOutside1X128 string
725
726 tickCumulativeOutside int64 // cumulative tick value on the other side of the tick
727
728 // the seconds per unit of liquidity on the _other_ side of this tick (relative to the current tick)
729 // only has relative meaning, not absolute — the value depends on when the tick is initialized
730 secondsPerLiquidityOutsideX128 string
731
732 // the seconds spent on the other side of the tick (relative to the current tick)
733 // only has relative meaning, not absolute — the value depends on when the tick is initialized
734 secondsOutside uint32
735
736 initialized bool // whether the tick is initialized
737}
738
739// TickInfo Getters methods
740// LiquidityGross returns total position liquidity referencing this tick.
741//
742// Returns:
743// - string: gross liquidity encoded as a decimal string.
744func (t *TickInfo) LiquidityGross() string { return t.liquidityGross }
745
746// LiquidityNet returns net liquidity applied when this tick is crossed.
747//
748// Returns:
749// - string: signed net liquidity encoded as a decimal string.
750func (t *TickInfo) LiquidityNet() string { return t.liquidityNet }
751
752// FeeGrowthOutside0X128 returns token0 fee growth on the side of this tick opposite the current tick.
753//
754// Returns:
755// - string: token0 outside fee-growth accumulator scaled by 2^128.
756func (t *TickInfo) FeeGrowthOutside0X128() string { return t.feeGrowthOutside0X128 }
757
758// FeeGrowthOutside1X128 returns token1 fee growth on the side of this tick opposite the current tick.
759//
760// Returns:
761// - string: token1 outside fee-growth accumulator scaled by 2^128.
762func (t *TickInfo) FeeGrowthOutside1X128() string { return t.feeGrowthOutside1X128 }
763
764// SecondsPerLiquidityOutsideX128 returns seconds per liquidity outside this tick.
765//
766// Returns:
767// - string: outside seconds-per-liquidity accumulator scaled by 2^128.
768func (t *TickInfo) SecondsPerLiquidityOutsideX128() string {
769 return t.secondsPerLiquidityOutsideX128
770}
771
772// SecondsOutside returns the time spent on the side of this tick opposite the current tick.
773//
774// Returns:
775// - uint32: seconds accumulated outside the tick.
776func (t *TickInfo) SecondsOutside() uint32 { return t.secondsOutside }
777
778// Initialized reports whether this tick has active initialized state.
779//
780// Returns:
781// - bool: true when the tick is initialized; false otherwise.
782func (t *TickInfo) Initialized() bool { return t.initialized }
783
784// TickCumulativeOutside returns cumulative tick value on the side opposite the current tick.
785//
786// Returns:
787// - int64: outside cumulative tick value.
788func (t *TickInfo) TickCumulativeOutside() int64 { return t.tickCumulativeOutside }
789
790// TickInfo Setters methods
791// SetLiquidityGross stores total position liquidity referencing this tick.
792//
793// Parameters:
794// - liquidityGross: gross liquidity encoded as a decimal string.
795func (t *TickInfo) SetLiquidityGross(liquidityGross string) {
796 t.liquidityGross = liquidityGross
797}
798
799// SetLiquidityNet stores the net liquidity change applied when crossing this tick.
800//
801// Parameters:
802// - liquidityNet: signed net liquidity encoded as a decimal string.
803func (t *TickInfo) SetLiquidityNet(liquidityNet string) {
804 t.liquidityNet = liquidityNet
805}
806
807// SetFeeGrowthOutside0X128 stores token0 outside fee growth for this tick.
808//
809// Parameters:
810// - feeGrowthOutside0X128: token0 outside fee growth scaled by 2^128, encoded as a decimal string.
811func (t *TickInfo) SetFeeGrowthOutside0X128(feeGrowthOutside0X128 string) {
812 t.feeGrowthOutside0X128 = feeGrowthOutside0X128
813}
814
815// SetFeeGrowthOutside1X128 stores token1 outside fee growth for this tick.
816//
817// Parameters:
818// - feeGrowthOutside1X128: token1 outside fee growth scaled by 2^128, encoded as a decimal string.
819func (t *TickInfo) SetFeeGrowthOutside1X128(feeGrowthOutside1X128 string) {
820 t.feeGrowthOutside1X128 = feeGrowthOutside1X128
821}
822
823// SetSecondsPerLiquidityOutsideX128 stores outside seconds-per-liquidity growth.
824//
825// Parameters:
826// - secondsPerLiquidityOutsideX128: outside seconds per liquidity scaled by 2^128, encoded as a decimal string.
827func (t *TickInfo) SetSecondsPerLiquidityOutsideX128(secondsPerLiquidityOutsideX128 string) {
828 t.secondsPerLiquidityOutsideX128 = secondsPerLiquidityOutsideX128
829}
830
831// SetSecondsOutside stores the seconds accumulated outside this tick.
832//
833// Parameters:
834// - secondsOutside: elapsed seconds outside the tick.
835func (t *TickInfo) SetSecondsOutside(secondsOutside uint32) {
836 t.secondsOutside = secondsOutside
837}
838
839// SetInitialized updates whether this tick is initialized.
840//
841// Parameters:
842// - initialized: true to mark the tick initialized, false otherwise.
843func (t *TickInfo) SetInitialized(initialized bool) {
844 t.initialized = initialized
845}
846
847// SetTickCumulativeOutside stores cumulative tick value outside this tick.
848//
849// Parameters:
850// - tickCumulativeOutside: cumulative tick value on the opposite side.
851func (t *TickInfo) SetTickCumulativeOutside(tickCumulativeOutside int64) {
852 t.tickCumulativeOutside = tickCumulativeOutside
853}
854
855// Clone returns an independent value copy of this tick's stored state.
856//
857// Returns:
858// - TickInfo: copied liquidity, fee-growth, time, and initialization fields.
859func (t *TickInfo) Clone() TickInfo {
860 return TickInfo{
861 feeGrowthOutside0X128: t.feeGrowthOutside0X128,
862 feeGrowthOutside1X128: t.feeGrowthOutside1X128,
863 liquidityGross: t.liquidityGross,
864 liquidityNet: t.liquidityNet,
865 tickCumulativeOutside: t.tickCumulativeOutside,
866 secondsPerLiquidityOutsideX128: t.secondsPerLiquidityOutsideX128,
867 secondsOutside: t.secondsOutside,
868 initialized: t.initialized,
869 }
870}
871
872// NewTickInfo creates an uninitialized tick state with zero accumulators.
873//
874// Returns:
875// - TickInfo: default tick state with all numeric fields zero and Initialized false.
876func NewTickInfo() TickInfo {
877 return TickInfo{
878 liquidityGross: "0",
879 liquidityNet: "0",
880 feeGrowthOutside0X128: "0",
881 feeGrowthOutside1X128: "0",
882 secondsPerLiquidityOutsideX128: "0",
883 secondsOutside: 0,
884 initialized: false,
885 tickCumulativeOutside: 0,
886 }
887}
888
889// PositionInfo stores aggregate liquidity, fee-growth checkpoints, and tokens
890// owed for one pool-scoped lower/upper tick key.
891type PositionInfo struct {
892 liquidity string // aggregate liquidity for this tick-range key
893 feeGrowthInside0LastX128 string // fee growth per unit of liquidity for token0 as of last update
894 feeGrowthInside1LastX128 string // fee growth per unit of liquidity for token1 as of last update
895
896 // accumulated token0 amount waiting to be collected (principal or swap fee)
897 tokensOwed0 int64
898
899 // accumulated token1 amount waiting to be collected (principal or swap fee)
900 tokensOwed1 int64
901}
902
903// Liquidity returns aggregate liquidity for this position range.
904//
905// Returns:
906// - string: position liquidity encoded as a decimal string.
907func (p *PositionInfo) Liquidity() string { return p.liquidity }
908
909// FeeGrowthInside0LastX128 returns the token0 fee-growth checkpoint for this position.
910//
911// Returns:
912// - string: token0 inside fee-growth checkpoint scaled by 2^128.
913func (p *PositionInfo) FeeGrowthInside0LastX128() string { return p.feeGrowthInside0LastX128 }
914
915// FeeGrowthInside1LastX128 returns the token1 fee-growth checkpoint for this position.
916//
917// Returns:
918// - string: token1 inside fee-growth checkpoint scaled by 2^128.
919func (p *PositionInfo) FeeGrowthInside1LastX128() string { return p.feeGrowthInside1LastX128 }
920
921// TokensOwed0 returns token0 accumulated for this position.
922//
923// Returns:
924// - int64: token0 principal or fee amount awaiting collection.
925func (p *PositionInfo) TokensOwed0() int64 { return p.tokensOwed0 }
926
927// TokensOwed1 returns token1 accumulated for this position.
928//
929// Returns:
930// - int64: token1 principal or fee amount awaiting collection.
931func (p *PositionInfo) TokensOwed1() int64 { return p.tokensOwed1 }
932
933// SetLiquidity updates aggregate liquidity for this position range.
934//
935// Parameters:
936// - liquidity: position liquidity encoded as a decimal string.
937func (p *PositionInfo) SetLiquidity(liquidity string) {
938 p.liquidity = liquidity
939}
940
941// SetFeeGrowthInside0LastX128 updates the token0 fee-growth checkpoint.
942//
943// Parameters:
944// - feeGrowthInside0LastX128: token0 inside fee-growth checkpoint scaled by 2^128, encoded as a decimal string.
945func (p *PositionInfo) SetFeeGrowthInside0LastX128(feeGrowthInside0LastX128 string) {
946 p.feeGrowthInside0LastX128 = feeGrowthInside0LastX128
947}
948
949// SetFeeGrowthInside1LastX128 updates the token1 fee-growth checkpoint.
950//
951// Parameters:
952// - feeGrowthInside1LastX128: token1 inside fee-growth checkpoint scaled by 2^128, encoded as a decimal string.
953func (p *PositionInfo) SetFeeGrowthInside1LastX128(feeGrowthInside1LastX128 string) {
954 p.feeGrowthInside1LastX128 = feeGrowthInside1LastX128
955}
956
957// SetTokensOwed0 updates token0 accumulated for this position.
958//
959// Parameters:
960// - tokensOwed0: token0 principal or fee amount awaiting collection.
961func (p *PositionInfo) SetTokensOwed0(tokensOwed0 int64) {
962 p.tokensOwed0 = tokensOwed0
963}
964
965// SetTokensOwed1 updates token1 accumulated for this position.
966//
967// Parameters:
968// - tokensOwed1: token1 principal or fee amount awaiting collection.
969func (p *PositionInfo) SetTokensOwed1(tokensOwed1 int64) {
970 p.tokensOwed1 = tokensOwed1
971}
972
973// NewPositionInfo creates a zeroed position state for a tick range.
974//
975// Returns:
976// - PositionInfo: position with zero liquidity, fee-growth checkpoints, and owed tokens.
977func NewPositionInfo() PositionInfo {
978 return PositionInfo{
979 liquidity: "0",
980 feeGrowthInside0LastX128: "0",
981 feeGrowthInside1LastX128: "0",
982 tokensOwed0: 0,
983 tokensOwed1: 0,
984 }
985}
986
987// NewDefaultFeeAmountTickSpacing returns the default tick spacing for each supported fee tier.
988//
989// Returns:
990// - map[uint32]int32: fee-tier to tick-spacing mapping for 100, 500, 3000, and 10000 tiers.
991func NewDefaultFeeAmountTickSpacing() map[uint32]int32 {
992 return map[uint32]int32{
993 100: 1,
994 500: 10,
995 3000: 60,
996 10000: 200,
997 }
998}