Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}