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

45.72 Kb · 1396 lines
   1package staker
   2
   3import (
   4	"errors"
   5	"time"
   6
   7	"gno.land/p/gnoswap/consts/v1"
   8	i256 "gno.land/p/gnoswap/int256/v1"
   9	u256 "gno.land/p/gnoswap/uint256/v1"
  10	"gno.land/p/gnoswap/utils/v1"
  11	bptree "gno.land/p/nt/bptree/v0"
  12	ufmt "gno.land/p/nt/ufmt/v0"
  13)
  14
  15const AllTierCount = 4 // 0, 1, 2, 3
  16
  17// Pool is a struct for storing an incentivized pool information
  18// Each pool stores Incentives and Ticks associated with it.
  19//
  20// Fields:
  21// - poolPath: The path of the pool.
  22//
  23//   - stakedLiquidity:
  24//     The current total staked liquidity of the in-range positions for the pool.
  25//     Updated when tick cross happens or stake/unstake happens.
  26//     Used to calculate the global reward ratio accumulation or
  27//     decide whether to enter/exit unclaimable period.
  28//
  29//   - lastUnclaimableTime:
  30//     The time at which the unclaimable period started.
  31//     Set to 0 when the pool is not in an unclaimable period.
  32//
  33//   - unclaimableAcc:
  34//     The accumulated undistributed unclaimable reward.
  35//     Reset to 0 when processUnclaimableReward is called and sent to community pool.
  36//
  37//   - rewardCache:
  38//     The cached per-second reward emitted for this pool.
  39//     Stores new entry only when the reward is changed.
  40//     PoolTier.cacheReward() updates this.
  41//
  42// - incentives: The external incentives associated with the pool.
  43//
  44// - ticks: The Ticks associated with the pool.
  45//
  46//   - globalRewardRatioAccumulation:
  47//     Global ratio of Time / TotalStake accumulation(since the pool creation)
  48//     Stores new entry only when tick cross or stake/unstake happens.
  49//     It is used to calculate the reward for a staked position at certain time.
  50//
  51//   - historicalTick:
  52//     The historical tick for the pool at a given time.
  53//     It does not reflect the exact tick at the timestamp,
  54//     but it provides correct ordering for the staked position's ticks.
  55//     Therefore, you should not compare it for equality, only for ordering.
  56//     Set when tick cross happens or a new position is created.
  57type Pool struct {
  58	poolPath string
  59
  60	stakedLiquidity *UintTree // uint64 timestamp -> *u256.Uint(Q128)
  61
  62	lastUnclaimableTime int64
  63	unclaimableAcc      int64
  64
  65	rewardCache *UintTree // uint64 timestamp -> int64 gnsReward
  66
  67	incentives *Incentives
  68
  69	ticks Ticks // int32 tickId -> Tick tick
  70
  71	globalRewardRatioAccumulation *UintTree // uint64 timestamp -> *u256.Uint(Q128) rewardRatioAccumulation
  72
  73	historicalTick *UintTree // uint64 timestamp -> int32 tickId
  74}
  75
  76// Pool Getter/Setter methods
  77
  78// PoolPath returns the pool path
  79//
  80// Returns:
  81//   - path: Pool identifier used to associate this state with a liquidity pool.
  82func (p *Pool) PoolPath() string {
  83	return p.poolPath
  84}
  85
  86// SetPoolPath sets the pool path
  87//
  88// Parameters:
  89//   - poolPath: Pool identifier to store.
  90func (p *Pool) SetPoolPath(poolPath string) {
  91	p.poolPath = poolPath
  92}
  93
  94// StakedLiquidity returns the staked liquidity tree
  95//
  96// Returns:
  97//   - tree: Historical staked-liquidity tree keyed by Unix timestamp, with Q128-scaled liquidity values.
  98func (p *Pool) StakedLiquidity() *UintTree {
  99	return p.stakedLiquidity
 100}
 101
 102// SetStakedLiquidity sets the staked liquidity tree
 103//
 104// Parameters:
 105//   - stakedLiquidity: Tree of historical total staked liquidity snapshots.
 106func (p *Pool) SetStakedLiquidity(stakedLiquidity *UintTree) {
 107	p.stakedLiquidity = stakedLiquidity
 108}
 109
 110// SetStakedLiquidityAt records the current total staked liquidity at a timestamp.
 111//
 112// Parameters:
 113//   - currentTime: Nonnegative Unix timestamp in seconds used as the snapshot key.
 114//   - delta: Total staked liquidity at currentTime, stored as a copied Q128-scaled uint value.
 115func (p *Pool) SetStakedLiquidityAt(currentTime int64, delta *u256.Uint) {
 116	p.StakedLiquidity().Set(currentTime, u256.Zero().Set(delta))
 117}
 118
 119// LastUnclaimableTime returns the last unclaimable time
 120//
 121// Returns:
 122//   - timestamp: Unix timestamp in seconds at which the pool entered its current unclaimable period, or 0 when tracking has not started.
 123func (p *Pool) LastUnclaimableTime() int64 {
 124	return p.lastUnclaimableTime
 125}
 126
 127// SetLastUnclaimableTime sets the last unclaimable time
 128//
 129// Parameters:
 130//   - lastUnclaimableTime: Unix timestamp in seconds marking the start of the current unclaimable period; use 0 when no period is active.
 131func (p *Pool) SetLastUnclaimableTime(lastUnclaimableTime int64) {
 132	p.lastUnclaimableTime = lastUnclaimableTime
 133}
 134
 135// UnclaimableAcc returns the unclaimable accumulation
 136//
 137// Returns:
 138//   - amount: Accumulated undistributed unclaimable reward amount in the pool's int64 reward units.
 139func (p *Pool) UnclaimableAcc() int64 {
 140	return p.unclaimableAcc
 141}
 142
 143// SetUnclaimableAcc sets the unclaimable accumulation
 144//
 145// Parameters:
 146//   - unclaimableAcc: Accumulated undistributed unclaimable reward amount in the pool's int64 reward units.
 147func (p *Pool) SetUnclaimableAcc(unclaimableAcc int64) {
 148	p.unclaimableAcc = unclaimableAcc
 149}
 150
 151// RewardCache returns the reward cache tree
 152//
 153// Returns:
 154//   - tree: Historical per-second GNS reward cache keyed by Unix timestamp.
 155func (p *Pool) RewardCache() *UintTree {
 156	return p.rewardCache
 157}
 158
 159// SetRewardCache sets the reward cache tree
 160//
 161// Parameters:
 162//   - rewardCache: Tree containing the pool's per-second GNS reward snapshots.
 163func (p *Pool) SetRewardCache(rewardCache *UintTree) {
 164	p.rewardCache = rewardCache
 165}
 166
 167// SetRewardCacheAt records the per-second reward rate for a timestamp.
 168//
 169// Parameters:
 170//   - currentTime: Nonnegative Unix timestamp in seconds used as the cache key.
 171//   - reward: GNS reward emitted per second from currentTime until the next cached change.
 172func (p *Pool) SetRewardCacheAt(currentTime int64, reward int64) {
 173	p.RewardCache().Set(currentTime, reward)
 174}
 175
 176// Incentives returns the incentives
 177//
 178// Returns:
 179//   - incentives: External-incentive collection associated with this pool.
 180func (p *Pool) Incentives() *Incentives {
 181	return p.incentives
 182}
 183
 184// SetIncentives sets the incentives
 185//
 186// Parameters:
 187//   - incentives: External-incentive collection to associate with the pool.
 188func (p *Pool) SetIncentives(incentives *Incentives) {
 189	p.incentives = incentives
 190}
 191
 192// Ticks returns the ticks
 193//
 194// Returns:
 195//   - ticks: Addressable tick mapping for this pool's staked positions.
 196func (p *Pool) Ticks() *Ticks {
 197	return &p.ticks
 198}
 199
 200// SetTicks sets the ticks
 201//
 202// Parameters:
 203//   - ticks: Tick mapping value to store in the pool.
 204func (p *Pool) SetTicks(ticks Ticks) {
 205	p.ticks = ticks
 206}
 207
 208// GlobalRewardRatioAccumulation returns the global reward ratio accumulation tree
 209//
 210// Returns:
 211//   - tree: Historical global time-per-total-stake accumulation keyed by Unix timestamp.
 212func (p *Pool) GlobalRewardRatioAccumulation() *UintTree {
 213	return p.globalRewardRatioAccumulation
 214}
 215
 216// SetGlobalRewardRatioAccumulation sets the global reward ratio accumulation tree
 217//
 218// Parameters:
 219//   - globalRewardRatioAccumulation: Tree of serialized Q128-scaled reward-ratio accumulation snapshots.
 220func (p *Pool) SetGlobalRewardRatioAccumulation(globalRewardRatioAccumulation *UintTree) {
 221	p.globalRewardRatioAccumulation = globalRewardRatioAccumulation
 222}
 223
 224// SetGlobalRewardRatioAccumulationAt records a serialized global reward-ratio accumulation snapshot.
 225//
 226// Parameters:
 227//   - currentTime: Nonnegative Unix timestamp in seconds used as the snapshot key.
 228//   - acc: Serialized Q128-scaled global reward-ratio accumulation value.
 229func (p *Pool) SetGlobalRewardRatioAccumulationAt(currentTime int64, acc string) {
 230	p.GlobalRewardRatioAccumulation().Set(currentTime, acc)
 231}
 232
 233// HistoricalTick returns the historical tick tree
 234//
 235// Returns:
 236//   - tree: Historical tick-ID ordering snapshots keyed by Unix timestamp.
 237func (p *Pool) HistoricalTick() *UintTree {
 238	return p.historicalTick
 239}
 240
 241// SetHistoricalTick sets the historical tick tree
 242//
 243// Parameters:
 244//   - historicalTick: Tree of tick IDs representing the ordering history of staked positions.
 245func (p *Pool) SetHistoricalTick(historicalTick *UintTree) {
 246	p.historicalTick = historicalTick
 247}
 248
 249// SetHistoricalTickAt records the tick ordering snapshot for a timestamp.
 250//
 251// Parameters:
 252//   - currentTime: Nonnegative Unix timestamp in seconds used as the snapshot key.
 253//   - tick: Tick ID representing the pool's historical ordering at currentTime.
 254func (p *Pool) SetHistoricalTickAt(currentTime int64, tick int32) {
 255	p.HistoricalTick().Set(currentTime, tick)
 256}
 257
 258// Clone returns a pool copy of the scalar state with a fresh tick container.
 259//
 260// Returns:
 261//   - pool: Pool copy carrying scalar state and a fresh tick container; backing trees and incentives are nil, and nil receiver yields nil.
 262func (p *Pool) Clone() *Pool {
 263	if p == nil {
 264		return nil
 265	}
 266
 267	return &Pool{
 268		poolPath:                      p.poolPath,
 269		stakedLiquidity:               nil,
 270		lastUnclaimableTime:           p.lastUnclaimableTime,
 271		unclaimableAcc:                p.unclaimableAcc,
 272		rewardCache:                   nil,
 273		incentives:                    nil,
 274		ticks:                         NewTicks(),
 275		globalRewardRatioAccumulation: nil,
 276		historicalTick:                nil,
 277	}
 278}
 279
 280// NewPool creates pool reward state initialized at currentTime (Unix seconds).
 281//
 282// Parameters:
 283//   - poolPath: Pool identifier to store in the new reward-state object.
 284//   - currentTime: Unix timestamp in seconds used to seed the initial accumulation, reward-cache, and liquidity snapshots.
 285//
 286// Returns:
 287//   - pool: Initialized pool with empty backing structures and zero initial reward/liquidity snapshots at currentTime.
 288func NewPool(poolPath string, currentTime int64) *Pool {
 289	pool := &Pool{
 290		poolPath:        poolPath,
 291		stakedLiquidity: NewUintTreeN(64),
 292		// lastUnclaimableTime is initialized to 0, which means "tracking not started yet".
 293		// When the pool receives a tier assignment (or external incentive), `cacheReward` will be called,
 294		// which will automatically call `startUnclaimablePeriod` if the pool has zero liquidity.
 295		// This ensures proper unclaimable period tracking from the moment rewards start emitting.
 296		lastUnclaimableTime:           0,
 297		unclaimableAcc:                0,
 298		rewardCache:                   NewUintTreeN(64),
 299		incentives:                    NewIncentives(poolPath),
 300		ticks:                         NewTicks(),
 301		globalRewardRatioAccumulation: NewUintTreeN(64),
 302		historicalTick:                NewUintTreeN(64),
 303	}
 304
 305	pool.SetGlobalRewardRatioAccumulationAt(currentTime, "0")
 306
 307	// Initialize rewardCache to 0 to ensure `cacheReward` will trigger on first tier assignment
 308	pool.SetRewardCacheAt(currentTime, int64(0))
 309	pool.SetStakedLiquidityAt(currentTime, u256.Zero())
 310
 311	return pool
 312}
 313
 314// Incentives represents a collection of external incentives for a specific pool.
 315//
 316// Fields:
 317//
 318//   - incentives: BPTree storing ExternalIncentive objects indexed by incentiveId
 319//     The incentiveId serves as the key to efficiently lookup incentive details
 320//
 321//   - targetPoolPath: String identifier for the pool this incentive collection belongs to
 322//     Used to associate incentives with their corresponding liquidity pool
 323//
 324//   - unclaimablePeriods: Tree storing periods when rewards cannot be claimed
 325//     Maps start timestamp (key) to end timestamp (value)
 326//     An end timestamp of 0 indicates an ongoing unclaimable period
 327//     Used to track intervals when staking rewards are not claimable
 328//
 329//   - byStartTime: Per-pool start-time index mapping an incentive's start
 330//     timestamp (key) to the incentive IDs that start at that timestamp
 331//     (value). This mirrors the lazy-discovery lookup previously served by a
 332//     global creation-time index, but scoped to this pool's own incentives, so
 333//     discovery cost is bounded by this pool's incentives instead of growing
 334//     with the total number of incentives system-wide.
 335type Incentives struct {
 336	incentives *bptree.BPTree // (incentiveId) => ExternalIncentive
 337
 338	targetPoolPath string // The target pool path for this incentive collection
 339
 340	unclaimablePeriods *UintTree // blockTimestamp -> any
 341
 342	byStartTime *UintTree // startTimestamp -> []incentiveId
 343}
 344
 345// Incentives Getter/Setter methods
 346
 347// Incentives returns the incentives tree
 348//
 349// Returns:
 350//   - tree: Mutable B+ tree mapping incentive IDs to ExternalIncentive records.
 351func (i *Incentives) IncentiveTrees() *bptree.BPTree {
 352	return i.incentives
 353}
 354
 355// SetIncentives sets the incentives tree
 356//
 357// Parameters:
 358//   - incentives: B+ tree to use for incentive ID lookups and storage.
 359func (i *Incentives) SetIncentives(incentives *bptree.BPTree) {
 360	i.incentives = incentives
 361}
 362
 363// TargetPoolPath returns the target pool path
 364//
 365// Returns:
 366//   - path: Pool path to which this incentive collection belongs.
 367func (i *Incentives) TargetPoolPath() string {
 368	return i.targetPoolPath
 369}
 370
 371// SetTargetPoolPath sets the target pool path
 372//
 373// Parameters:
 374//   - targetPoolPath: Pool path to associate with this incentive collection.
 375func (i *Incentives) SetTargetPoolPath(targetPoolPath string) {
 376	i.targetPoolPath = targetPoolPath
 377}
 378
 379// UnclaimablePeriods returns the unclaimable periods tree
 380//
 381// Returns:
 382//   - periods: Tree mapping unclaimable-period start timestamps to end timestamps; end 0 denotes an open period.
 383func (i *Incentives) UnclaimablePeriods() *UintTree {
 384	return i.unclaimablePeriods
 385}
 386
 387// SetUnclaimablePeriods sets the unclaimable periods tree
 388//
 389// Parameters:
 390//   - unclaimablePeriods: Tree of reward-unclaimable intervals keyed by their start timestamps.
 391func (i *Incentives) SetUnclaimablePeriods(unclaimablePeriods *UintTree) {
 392	i.unclaimablePeriods = unclaimablePeriods
 393}
 394
 395// Incentive returns an incentive by ID
 396//
 397// Parameters:
 398//   - incentiveId: Identifier used to look up the external incentive record.
 399//
 400// Returns:
 401//   - incentive: Matching ExternalIncentive pointer, or nil when no value is stored for incentiveId.
 402//   - found: True only when the stored value has ExternalIncentive type; false for a missing or mismatched value.
 403func (i *Incentives) Incentive(incentiveId string) (*ExternalIncentive, bool) {
 404	value := i.incentives.Get(incentiveId)
 405	if value == nil {
 406		return nil, false
 407	}
 408	incentive, ok := value.(*ExternalIncentive)
 409	return incentive, ok
 410}
 411
 412// SetIncentive sets an incentive by ID
 413//
 414// Parameters:
 415//   - incentiveId: Identifier under which to store the incentive.
 416//   - incentive: ExternalIncentive record to store for incentiveId.
 417func (i *Incentives) SetIncentive(incentiveId string, incentive *ExternalIncentive) {
 418	i.incentives.Set(incentiveId, incentive)
 419}
 420
 421// RemoveIncentive deletes an incentive by ID.
 422//
 423// Only an incentive that never started may be removed: once rewards begin
 424// accruing, deposits and the refund accounting reference the record, so an
 425// ended incentive is marked refunded instead of removed.
 426//
 427// Parameters:
 428//   - incentiveId: Identifier of the external incentive record to remove.
 429func (i *Incentives) RemoveIncentive(incentiveId string) {
 430	i.incentives.Remove(incentiveId)
 431}
 432
 433// SetUnclaimablePeriod records an interval during which staking rewards cannot be claimed.
 434//
 435// Parameters:
 436//   - startTimestamp: Nonnegative Unix timestamp in seconds at which the interval begins.
 437//   - endTimestamp: Unix timestamp in seconds at which the interval ends; 0 records an ongoing interval.
 438func (i *Incentives) SetUnclaimablePeriod(startTimestamp int64, endTimestamp int64) {
 439	i.unclaimablePeriods.Set(startTimestamp, endTimestamp)
 440}
 441
 442// RemoveUnclaimablePeriod removes the interval keyed by its start timestamp.
 443//
 444// Parameters:
 445//   - startTimestamp: Nonnegative Unix timestamp in seconds identifying the interval to remove.
 446func (i *Incentives) RemoveUnclaimablePeriod(startTimestamp int64) {
 447	i.unclaimablePeriods.Remove(startTimestamp)
 448}
 449
 450// IterateIncentives iterates over all incentives
 451//
 452// Parameters:
 453//   - fn: Callback receiving each incentive ID and record; returning true requests that iteration stop.
 454func (i *Incentives) IterateIncentives(fn func(incentiveId string, incentive *ExternalIncentive) bool) {
 455	i.incentives.Iterate("", "", func(key string, value interface{}) bool {
 456		if incentive, ok := value.(*ExternalIncentive); ok {
 457			return fn(key, incentive)
 458		}
 459		return false
 460	})
 461}
 462
 463// AddIncentiveByStartTime registers an incentive ID under its start timestamp
 464// in the per-pool start-time index. Multiple incentives starting at the same
 465// timestamp are accumulated as a list.
 466//
 467// Parameters:
 468//   - startTimestamp: Nonnegative Unix timestamp in seconds used as the start-time index key.
 469//   - incentiveId: Incentive identifier to append to that timestamp's bucket.
 470func (i *Incentives) AddIncentiveByStartTime(startTimestamp int64, incentiveId string) {
 471	var incentiveIds []string
 472	if value, ok := i.byStartTime.Get(startTimestamp); ok {
 473		if ids, ok := value.([]string); ok {
 474			incentiveIds = ids
 475		}
 476	}
 477	incentiveIds = append(incentiveIds, incentiveId)
 478	i.byStartTime.Set(startTimestamp, incentiveIds)
 479}
 480
 481// RemoveIncentiveByStartTime unregisters an incentive ID from the per-pool
 482// start-time index. The bucket itself is dropped once its last ID is removed,
 483// so the index never keeps an empty entry that discovery would still visit.
 484//
 485// Parameters:
 486//   - startTimestamp: Nonnegative Unix timestamp in seconds identifying the start-time bucket.
 487//   - incentiveId: Incentive identifier to remove from that bucket; all matching entries are omitted.
 488func (i *Incentives) RemoveIncentiveByStartTime(startTimestamp int64, incentiveId string) {
 489	value, ok := i.byStartTime.Get(startTimestamp)
 490	if !ok {
 491		return
 492	}
 493
 494	ids, ok := value.([]string)
 495	if !ok {
 496		return
 497	}
 498
 499	remaining := make([]string, 0, len(ids))
 500	for _, id := range ids {
 501		if id == incentiveId {
 502			continue
 503		}
 504		remaining = append(remaining, id)
 505	}
 506
 507	if len(remaining) == 0 {
 508		i.byStartTime.Remove(startTimestamp)
 509		return
 510	}
 511
 512	i.byStartTime.Set(startTimestamp, remaining)
 513}
 514
 515// IterateIncentiveIdsByTime iterates over the incentive IDs that start within
 516// the inclusive [startTime, endTime] range, visiting only the buckets that
 517// fall in the range. ReverseIterate is used because it is inclusive on both
 518// ends, matching the discovery semantics previously implemented as
 519// (startTimestamp >= startTime && startTimestamp <= endTime).
 520//
 521// Parameters:
 522//   - startTime: Inclusive lower Unix timestamp bound for incentive starts.
 523//   - endTime: Inclusive upper Unix timestamp bound for incentive starts.
 524//   - fn: Callback receiving each matching incentive ID; returning true requests that iteration stop.
 525func (i *Incentives) IterateIncentiveIdsByTime(startTime, endTime int64, fn func(incentiveId string) bool) {
 526	i.byStartTime.ReverseIterate(startTime, endTime, func(_ int64, value any) bool {
 527		incentiveIds, ok := value.([]string)
 528		if !ok {
 529			return false
 530		}
 531		for _, incentiveId := range incentiveIds {
 532			if fn(incentiveId) {
 533				return true
 534			}
 535		}
 536		return false
 537	})
 538}
 539
 540// NewIncentives creates an incentive collection for a pool and starts an open unclaimable period at the current time.
 541//
 542// Parameters:
 543//   - targetPoolPath: Pool path to associate with the new incentive collection.
 544//
 545// Returns:
 546//   - incentives: Collection with initialized incentive, start-time, and unclaimable-period trees.
 547func NewIncentives(targetPoolPath string) *Incentives {
 548	result := &Incentives{
 549		targetPoolPath:     targetPoolPath,
 550		unclaimablePeriods: NewUintTreeN(64),
 551		incentives:         bptree.NewBPTreeN(16),
 552		byStartTime:        NewUintTreeN(64),
 553	}
 554
 555	// initial unclaimable period starts, as there cannot be any staked positions yet.
 556	currentTimestamp := time.Now().Unix()
 557	result.SetUnclaimablePeriod(currentTimestamp, int64(0))
 558	return result
 559}
 560
 561type ExternalIncentive struct {
 562	incentiveId              string     // incentive id
 563	startTimestamp           int64      // start time for external reward
 564	endTimestamp             int64      // end time for external reward
 565	createdHeight            int64      // block height when the incentive was created
 566	createdTimestamp         int64      // timestamp when the incentive was created
 567	depositGnsAmount         int64      // deposited gns amount
 568	targetPoolPath           string     // external reward target pool path
 569	rewardToken              string     // external reward token path
 570	totalRewardAmount        int64      // total reward amount
 571	rewardAmount             int64      // mutable remaining reward amount
 572	rewardPerSecondX128      *u256.Uint // reward per second, scaled by 2^128 to preserve sub-second precision
 573	distributedRewardAmount  int64      // reward amount delivered to positions or refunded at incentive end
 574	accumulatedPenaltyAmount int64      // accumulated warmup penalty from CollectReward
 575	creator                  address    // creator address
 576
 577	refunded bool // whether EndExternalIncentive finalized the incentive and returned its refundable portion and GNS deposit
 578
 579	unclaimableSeconds int64 // accumulated seconds of unclaimable periods overlapping the incentive window
 580}
 581
 582// ExternalIncentive Getter/Setter methods
 583
 584// IncentiveId returns the incentive ID
 585//
 586// Returns:
 587//   - id: Identifier assigned to this external incentive.
 588func (e *ExternalIncentive) IncentiveId() string {
 589	return e.incentiveId
 590}
 591
 592// SetIncentiveId sets the incentive ID
 593//
 594// Parameters:
 595//   - incentiveId: Identifier to store on the incentive record.
 596func (e *ExternalIncentive) SetIncentiveId(incentiveId string) {
 597	e.incentiveId = incentiveId
 598}
 599
 600// StartTimestamp returns the start timestamp.
 601//
 602// It keys the byStartTime discovery index and must stay immutable after the
 603// incentive is registered, so no setter is exposed.
 604//
 605// Returns:
 606//   - timestamp: Unix timestamp in seconds at which reward distribution starts.
 607func (e *ExternalIncentive) StartTimestamp() int64 {
 608	return e.startTimestamp
 609}
 610
 611// EndTimestamp returns the end timestamp
 612//
 613// Returns:
 614//   - timestamp: Unix timestamp in seconds at which the incentive window ends.
 615func (e *ExternalIncentive) EndTimestamp() int64 {
 616	return e.endTimestamp
 617}
 618
 619// SetEndTimestamp sets the end timestamp
 620//
 621// Parameters:
 622//   - endTimestamp: Unix timestamp in seconds at which the incentive window ends.
 623func (e *ExternalIncentive) SetEndTimestamp(endTimestamp int64) {
 624	e.endTimestamp = endTimestamp
 625}
 626
 627// CreatedHeight returns the created height
 628//
 629// Returns:
 630//   - height: Block height at which the incentive record was created.
 631func (e *ExternalIncentive) CreatedHeight() int64 {
 632	return e.createdHeight
 633}
 634
 635// SetCreatedHeight sets the created height
 636//
 637// Parameters:
 638//   - createdHeight: Block height to record as the incentive's creation height.
 639func (e *ExternalIncentive) SetCreatedHeight(createdHeight int64) {
 640	e.createdHeight = createdHeight
 641}
 642
 643// CreatedTimestamp returns the created timestamp
 644//
 645// Returns:
 646//   - timestamp: Unix timestamp in seconds at which the incentive record was created.
 647func (e *ExternalIncentive) CreatedTimestamp() int64 {
 648	return e.createdTimestamp
 649}
 650
 651// SetCreatedTimestamp sets the created timestamp
 652//
 653// Parameters:
 654//   - createdTimestamp: Unix timestamp in seconds to record as the incentive creation time.
 655func (e *ExternalIncentive) SetCreatedTimestamp(createdTimestamp int64) {
 656	e.createdTimestamp = createdTimestamp
 657}
 658
 659// DepositGnsAmount returns the deposit GNS amount
 660//
 661// Returns:
 662//   - amount: GNS amount deposited to back this external incentive.
 663func (e *ExternalIncentive) DepositGnsAmount() int64 {
 664	return e.depositGnsAmount
 665}
 666
 667// SetDepositGnsAmount sets the deposit GNS amount
 668//
 669// Parameters:
 670//   - depositGnsAmount: GNS amount deposited to back this external incentive.
 671func (e *ExternalIncentive) SetDepositGnsAmount(depositGnsAmount int64) {
 672	e.depositGnsAmount = depositGnsAmount
 673}
 674
 675// TargetPoolPath returns the target pool path
 676//
 677// Returns:
 678//   - path: Pool path targeted by this external incentive.
 679func (e *ExternalIncentive) TargetPoolPath() string {
 680	return e.targetPoolPath
 681}
 682
 683// SetTargetPoolPath sets the target pool path
 684//
 685// Parameters:
 686//   - targetPoolPath: Pool path to target with this external incentive.
 687func (e *ExternalIncentive) SetTargetPoolPath(targetPoolPath string) {
 688	e.targetPoolPath = targetPoolPath
 689}
 690
 691// RewardToken returns the reward token
 692//
 693// Returns:
 694//   - token: Reward-token path distributed by this incentive.
 695func (e *ExternalIncentive) RewardToken() string {
 696	return e.rewardToken
 697}
 698
 699// SetRewardToken sets the reward token
 700//
 701// Parameters:
 702//   - rewardToken: Token path of the reward asset distributed by this incentive.
 703func (e *ExternalIncentive) SetRewardToken(rewardToken string) {
 704	e.rewardToken = rewardToken
 705}
 706
 707// TotalRewardAmount returns the total reward amount
 708//
 709// Returns:
 710//   - amount: Total reward amount configured when the incentive was created.
 711func (e *ExternalIncentive) TotalRewardAmount() int64 {
 712	return e.totalRewardAmount
 713}
 714
 715// SetTotalRewardAmount sets the total reward amount
 716//
 717// Parameters:
 718//   - totalRewardAmount: Total reward amount to record for the incentive.
 719func (e *ExternalIncentive) SetTotalRewardAmount(totalRewardAmount int64) {
 720	e.totalRewardAmount = totalRewardAmount
 721}
 722
 723// RewardAmount returns the reward amount
 724//
 725// Returns:
 726//   - amount: Mutable reward amount remaining after distributions and refunds.
 727func (e *ExternalIncentive) RewardAmount() int64 {
 728	return e.rewardAmount
 729}
 730
 731// SetRewardAmount sets the reward amount
 732//
 733// Parameters:
 734//   - rewardAmount: Remaining reward amount to store after accounting adjustments.
 735func (e *ExternalIncentive) SetRewardAmount(rewardAmount int64) {
 736	e.rewardAmount = rewardAmount
 737}
 738
 739// RewardPerSecondX128 returns the Q128-scaled reward per second.
 740// The underlying value is (rewardAmount << 128) / duration.
 741//
 742// Returns:
 743//   - rate: Reward emitted per second, scaled by 2^128 for fixed-point accounting.
 744func (e *ExternalIncentive) RewardPerSecondX128() *u256.Uint {
 745	return e.rewardPerSecondX128
 746}
 747
 748// SetRewardPerSecondX128 sets the Q128-scaled reward per second.
 749//
 750// Parameters:
 751//   - rewardPerSecondX128: Q128-scaled per-second reward rate; the value is copied before storage.
 752func (e *ExternalIncentive) SetRewardPerSecondX128(rewardPerSecondX128 *u256.Uint) {
 753	e.rewardPerSecondX128 = u256.Zero().Set(rewardPerSecondX128)
 754}
 755
 756// DistributedRewardAmount returns the distributed reward amount
 757//
 758// Returns:
 759//   - amount: Reward amount already delivered to positions or refunded at incentive end.
 760func (e *ExternalIncentive) DistributedRewardAmount() int64 {
 761	return e.distributedRewardAmount
 762}
 763
 764// SetDistributedRewardAmount sets the distributed reward amount
 765//
 766// Parameters:
 767//   - distributedRewardAmount: Reward amount delivered to positions or refunded at incentive end.
 768func (e *ExternalIncentive) SetDistributedRewardAmount(distributedRewardAmount int64) {
 769	e.distributedRewardAmount = distributedRewardAmount
 770}
 771
 772// AccumulatedPenaltyAmount returns the accumulated warmup penalty amount
 773//
 774// Returns:
 775//   - amount: Warm-up penalty accumulated from reward collections for this incentive.
 776func (e *ExternalIncentive) AccumulatedPenaltyAmount() int64 {
 777	return e.accumulatedPenaltyAmount
 778}
 779
 780// SetAccumulatedPenaltyAmount sets the accumulated warmup penalty amount
 781//
 782// Parameters:
 783//   - accumulatedPenaltyAmount: Warm-up penalty amount to store in the incentive's accumulated accounting.
 784func (e *ExternalIncentive) SetAccumulatedPenaltyAmount(accumulatedPenaltyAmount int64) {
 785	e.accumulatedPenaltyAmount = accumulatedPenaltyAmount
 786}
 787
 788// Creator returns the creator address
 789//
 790// Returns:
 791//   - creator: Address that created and funded the incentive.
 792func (e *ExternalIncentive) Creator() address {
 793	return e.creator
 794}
 795
 796// SetCreator sets the creator address
 797//
 798// Parameters:
 799//   - creator: Address to record as the incentive creator and refund recipient.
 800func (e *ExternalIncentive) SetCreator(creator address) {
 801	e.creator = creator
 802}
 803
 804// Refunded returns the refunded status
 805//
 806// Returns:
 807//   - refunded: True when incentive finalization has marked its refundable balances as returned.
 808func (e *ExternalIncentive) Refunded() bool {
 809	return e.refunded
 810}
 811
 812// SetRefunded sets the refunded status
 813//
 814// Parameters:
 815//   - refunded: Finalization status to store for the incentive.
 816func (e *ExternalIncentive) SetRefunded(refunded bool) {
 817	e.refunded = refunded
 818}
 819
 820// UnclaimableSeconds returns the accumulated seconds of unclaimable periods
 821// that overlap the incentive window. It is updated whenever an unclaimable
 822// period closes and is backfilled once from the historical unclaimable
 823// periods tree after an upgrade.
 824//
 825// Returns:
 826//   - seconds: Accumulated seconds of unclaimable periods overlapping the incentive window.
 827func (e *ExternalIncentive) UnclaimableSeconds() int64 {
 828	return e.unclaimableSeconds
 829}
 830
 831// SetUnclaimableSeconds sets the accumulated unclaimable seconds.
 832//
 833// Parameters:
 834//   - unclaimableSeconds: Overlapping unclaimable duration in seconds to store.
 835func (e *ExternalIncentive) SetUnclaimableSeconds(unclaimableSeconds int64) {
 836	e.unclaimableSeconds = unclaimableSeconds
 837}
 838
 839// Clone returns an independent ExternalIncentive value with scalar fields copied and its fixed-point rate duplicated.
 840//
 841// Returns:
 842//   - incentive: Copied external incentive record; its fixed-point rate is cloned when present and otherwise initialized to zero.
 843func (e *ExternalIncentive) Clone() *ExternalIncentive {
 844	rewardPerSecondX128 := u256.Zero()
 845
 846	if e.rewardPerSecondX128 != nil {
 847		rewardPerSecondX128 = e.rewardPerSecondX128.Clone()
 848	}
 849
 850	return &ExternalIncentive{
 851		incentiveId:              e.incentiveId,
 852		startTimestamp:           e.startTimestamp,
 853		endTimestamp:             e.endTimestamp,
 854		createdHeight:            e.createdHeight,
 855		createdTimestamp:         e.createdTimestamp,
 856		depositGnsAmount:         e.depositGnsAmount,
 857		targetPoolPath:           e.targetPoolPath,
 858		rewardToken:              e.rewardToken,
 859		totalRewardAmount:        e.totalRewardAmount,
 860		rewardAmount:             e.rewardAmount,
 861		rewardPerSecondX128:      rewardPerSecondX128,
 862		creator:                  e.creator,
 863		refunded:                 e.refunded,
 864		unclaimableSeconds:       e.unclaimableSeconds,
 865		distributedRewardAmount:  e.distributedRewardAmount,
 866		accumulatedPenaltyAmount: e.accumulatedPenaltyAmount,
 867	}
 868}
 869
 870// NewExternalIncentive creates a new external incentive
 871//
 872// Parameters:
 873//   - incentiveId: Unique identifier assigned to the external incentive.
 874//   - targetPoolPath: Pool path whose staked positions may receive this incentive.
 875//   - rewardToken: Token path of the asset deposited for distribution.
 876//   - rewardAmount: Total reward amount, also used as the initial remaining reward balance.
 877//   - startTimestamp: Unix timestamp in seconds when reward distribution starts.
 878//   - endTimestamp: Unix timestamp in seconds when reward distribution ends; duration is endTimestamp-startTimestamp and must be nonzero for the rate calculation.
 879//   - creator: Address that funds the incentive and receives refunds at finalization.
 880//   - depositGnsAmount: GNS amount deposited as the incentive's required collateral.
 881//   - createdHeight: Block height to record for incentive creation.
 882//   - currentTime: Unix timestamp in seconds recorded as the incentive creation time.
 883//
 884// Returns:
 885//   - incentive: New incentive with a Q128-scaled per-second rate and zeroed distribution, penalty, and unclaimable counters.
 886func NewExternalIncentive(
 887	incentiveId string,
 888	targetPoolPath string,
 889	rewardToken string,
 890	rewardAmount int64,
 891	startTimestamp int64, // timestamp is in unix time(seconds)
 892	endTimestamp int64,
 893	creator address,
 894	depositGnsAmount int64,
 895	createdHeight int64,
 896	currentTime int64, // current time in unix time(seconds)
 897) *ExternalIncentive {
 898	incentiveDuration := endTimestamp - startTimestamp
 899
 900	// Compute reward per second scaled by 2^128 to preserve sub-second precision.
 901	// rewardPerSecondX128 = (rewardAmount << 128) / incentiveDuration.
 902	// Consumers must divide by 2^128 when materializing back to a plain integer.
 903	rewardPerSecondX128 := u256.MulDiv(
 904		u256.NewUintFromInt64(rewardAmount),
 905		consts.Q128(),
 906		u256.NewUintFromInt64(incentiveDuration),
 907	)
 908
 909	return &ExternalIncentive{
 910		incentiveId:              incentiveId,
 911		targetPoolPath:           targetPoolPath,
 912		rewardToken:              rewardToken,
 913		totalRewardAmount:        rewardAmount,
 914		rewardAmount:             rewardAmount,
 915		startTimestamp:           startTimestamp,
 916		endTimestamp:             endTimestamp,
 917		rewardPerSecondX128:      rewardPerSecondX128,
 918		distributedRewardAmount:  0,
 919		accumulatedPenaltyAmount: 0,
 920		creator:                  creator,
 921		createdHeight:            createdHeight,
 922		createdTimestamp:         currentTime,
 923		depositGnsAmount:         depositGnsAmount,
 924		refunded:                 false,
 925		unclaimableSeconds:       0,
 926	}
 927}
 928
 929// Tick mapping for each pool
 930type Ticks struct {
 931	tree *bptree.BPTree // int32 tickId -> tick
 932}
 933
 934// Ticks Getter/Setter methods
 935
 936// Tree returns the ticks tree
 937//
 938// Returns:
 939//   - tree: Mutable B+ tree mapping encoded int32 tick IDs to Tick records.
 940func (t *Ticks) Tree() *bptree.BPTree {
 941	return t.tree
 942}
 943
 944// SetTree sets the ticks tree
 945//
 946// Parameters:
 947//   - tree: B+ tree to use for tick storage.
 948func (t *Ticks) SetTree(tree *bptree.BPTree) {
 949	t.tree = tree
 950}
 951
 952// Get returns the tick for the given tickId, or nil if it does not exist.
 953//
 954// Parameters:
 955//   - tickId: Tick index to look up.
 956//
 957// Returns:
 958//   - tick: Matching Tick record, or nil when the encoded ID is absent; panics if a stored value has the wrong type.
 959func (t *Ticks) Get(tickId int32) *Tick {
 960	v := t.tree.Get(utils.EncodeInt32(tickId))
 961	if v == nil {
 962		return nil
 963	}
 964
 965	tick, ok := v.(*Tick)
 966	if !ok {
 967		panic("failed to cast value to *Tick")
 968	}
 969	return tick
 970}
 971
 972// Has reports whether a tick ID is present in the underlying tree.
 973//
 974// Parameters:
 975//   - tickId: Tick index whose encoded key is tested.
 976//
 977// Returns:
 978//   - present: True when the encoded tick ID exists in the underlying tree.
 979func (self *Ticks) Has(tickId int32) bool {
 980	return self.tree.Has(utils.EncodeInt32(tickId))
 981}
 982
 983// SetTick sets a tick by ID
 984//
 985// Parameters:
 986//   - tickId: Tick index under which to store the record.
 987//   - tick: Non-nil Tick record to store; a zero gross staked liquidity removes the tick instead, while nil input panics during the gross-liquidity check.
 988func (t *Ticks) SetTick(tickId int32, tick *Tick) {
 989	if tick.stakedLiquidityGross.IsZero() {
 990		t.tree.Remove(utils.EncodeInt32(tickId))
 991		return
 992	}
 993
 994	t.tree.Set(utils.EncodeInt32(tickId), tick)
 995}
 996
 997// IterateTicks iterates over all ticks
 998//
 999// Parameters:
1000//   - fn: Callback receiving each stored Tick and decoded tick ID; returning true requests that iteration stop.
1001func (t *Ticks) IterateTicks(fn func(tickId int32, tick *Tick) bool) {
1002	t.tree.Iterate("", "", func(key string, value interface{}) bool {
1003		tick, ok := value.(*Tick)
1004		if !ok {
1005			return false
1006		}
1007
1008		return fn(utils.DecodeInt32(key), tick)
1009	})
1010}
1011
1012// Clone returns a deep copy of ticks.
1013//
1014// Returns:
1015//   - ticks: New Ticks value with cloned Tick records in a fresh fanout-16 tree.
1016func (t Ticks) Clone() Ticks {
1017	cloned := bptree.NewBPTreeN(16)
1018	t.tree.Iterate("", "", func(key string, value any) bool {
1019		tick, ok := value.(*Tick)
1020		if !ok {
1021			panic("failed to cast value to *Tick")
1022		}
1023		cloned.Set(key, tick.Clone())
1024		return false
1025	})
1026	return Ticks{tree: cloned}
1027}
1028
1029// NewTicks creates an empty tick mapping with a fanout-16 B+ tree.
1030//
1031// Returns:
1032//   - ticks: Empty Ticks value ready to store pool tick records.
1033func NewTicks() Ticks {
1034	return Ticks{
1035		tree: bptree.NewBPTreeN(16),
1036	}
1037}
1038
1039// Tick represents the state of a specific tick in a pool.
1040//
1041// Fields:
1042// - id (int32): The ID of the tick.
1043// - stakedLiquidityGross (*u256.Uint): Total gross staked liquidity at this tick.
1044// - stakedLiquidityDelta (*i256.Int): Net change in staked liquidity at this tick.
1045// - outsideAccumulation (*UintTree): RewardRatioAccumulation outside the tick.
1046type Tick struct {
1047	id int32
1048
1049	// conceptually equal with Pool.liquidityGross but only for the staked positions
1050	stakedLiquidityGross *u256.Uint
1051
1052	// conceptually equal with Pool.liquidityNet but only for the staked positions
1053	stakedLiquidityDelta *i256.Int
1054
1055	// currentOutsideAccumulation is the accumulation of the time / TotalStake outside the tick.
1056	// It is calculated by subtracting the current tick's currentOutsideAccumulation from the global reward ratio accumulation.
1057	outsideAccumulation *UintTree // timestamp -> fixed 32-byte big-endian string
1058}
1059
1060// Tick Getter/Setter methods
1061
1062// Id returns the tick ID
1063//
1064// Returns:
1065//   - id: Tick index represented by this record.
1066func (t *Tick) Id() int32 {
1067	return t.id
1068}
1069
1070// SetId sets the tick ID
1071//
1072// Parameters:
1073//   - id: Tick index to store in the record.
1074func (t *Tick) SetId(id int32) {
1075	t.id = id
1076}
1077
1078// StakedLiquidityGross returns the staked liquidity gross
1079//
1080// Returns:
1081//   - liquidity: Total gross staked liquidity currently associated with this tick.
1082func (t *Tick) StakedLiquidityGross() *u256.Uint {
1083	return t.stakedLiquidityGross
1084}
1085
1086// SetStakedLiquidityGross sets the staked liquidity gross
1087//
1088// Parameters:
1089//   - stakedLiquidityGross: New total gross staked liquidity; the value is copied before storage.
1090func (t *Tick) SetStakedLiquidityGross(stakedLiquidityGross *u256.Uint) {
1091	t.stakedLiquidityGross = u256.Zero().Set(stakedLiquidityGross)
1092}
1093
1094// StakedLiquidityDelta returns the staked liquidity delta
1095//
1096// Returns:
1097//   - delta: Net staked liquidity change associated with this tick.
1098func (t *Tick) StakedLiquidityDelta() *i256.Int {
1099	return t.stakedLiquidityDelta
1100}
1101
1102// SetStakedLiquidityDelta sets the staked liquidity delta
1103//
1104// Parameters:
1105//   - stakedLiquidityDelta: New net staked liquidity delta; the value is copied before storage.
1106func (t *Tick) SetStakedLiquidityDelta(stakedLiquidityDelta *i256.Int) {
1107	t.stakedLiquidityDelta = i256.Zero().Set(stakedLiquidityDelta)
1108}
1109
1110// OutsideAccumulation returns the outside accumulation tree
1111//
1112// Returns:
1113//   - tree: Historical reward-ratio accumulation observed outside this tick.
1114func (t *Tick) OutsideAccumulation() *UintTree {
1115	return t.outsideAccumulation
1116}
1117
1118// SetOutsideAccumulation sets the outside accumulation tree
1119//
1120// Parameters:
1121//   - outsideAccumulation: UintTree of outside-accumulation snapshots keyed by Unix timestamp.
1122func (t *Tick) SetOutsideAccumulation(outsideAccumulation *UintTree) {
1123	t.outsideAccumulation = outsideAccumulation
1124}
1125
1126// SetOutsideAccumulationAt sets the outside accumulation at the timestamp.
1127// SetOutsideAccumulationAt records the Q128-scaled outside accumulation at a timestamp.
1128//
1129// Parameters:
1130//   - timestamp: Nonnegative Unix timestamp in seconds used as the snapshot key.
1131//   - acc: Q128-scaled accumulation value encoded into the tree.
1132func (t *Tick) SetOutsideAccumulationAt(timestamp int64, acc *u256.Uint) {
1133	t.outsideAccumulation.Set(timestamp, utils.EncodeUint256(acc))
1134}
1135
1136// Clone returns a deep copy of the tick.
1137//
1138// Returns:
1139//   - tick: Deep copy of the tick and its outside-accumulation tree, or nil when the receiver is nil.
1140func (t *Tick) Clone() *Tick {
1141	if t == nil {
1142		return nil
1143	}
1144
1145	return &Tick{
1146		id:                   t.id,
1147		stakedLiquidityGross: t.stakedLiquidityGross.Clone(),
1148		stakedLiquidityDelta: t.stakedLiquidityDelta.Clone(),
1149		outsideAccumulation:  t.outsideAccumulation.Clone(),
1150	}
1151}
1152
1153// NewTick creates a tick with zero staked liquidity and an empty fanout-4 outside-accumulation tree.
1154//
1155// Parameters:
1156//   - tickId: Tick index to assign to the new record.
1157//
1158// Returns:
1159//   - tick: Initialized tick record.
1160func NewTick(tickId int32) *Tick {
1161	return &Tick{
1162		id:                   tickId,
1163		stakedLiquidityGross: u256.Zero(),
1164		stakedLiquidityDelta: i256.Zero(),
1165		outsideAccumulation:  NewUintTreeN(4),
1166	}
1167}
1168
1169// 100%, 0%, 0% if no tier2 and tier3
1170// 80%, 0%, 20% if no tier2
1171// 70%, 30%, 0% if no tier3
1172// 50%, 30%, 20% if has tier2 and tier3
1173type TierRatio struct {
1174	Tier1 uint64
1175	Tier2 uint64
1176	Tier3 uint64
1177}
1178
1179// NewTierRatio constructs the reward-share ratio for tiers 1 through 3.
1180//
1181// Parameters:
1182//   - tier1: Tier-1 share scaled by 100 (for example, 70 means 70%).
1183//   - tier2: Tier-2 share scaled by 100.
1184//   - tier3: Tier-3 share scaled by 100.
1185//
1186// Returns:
1187//   - ratio: TierRatio containing the supplied scaled shares.
1188func NewTierRatio(tier1, tier2, tier3 uint64) TierRatio {
1189	return TierRatio{
1190		Tier1: tier1,
1191		Tier2: tier2,
1192		Tier3: tier3,
1193	}
1194}
1195
1196// Get returns the ratio(scaled up by 100) for the given tier.
1197//
1198// Parameters:
1199//   - tier: Tier number to query; only tiers 1, 2, and 3 are supported.
1200//
1201// Returns:
1202//   - ratio: Requested tier share scaled by 100.
1203//   - err: Non-nil when tier is not 1, 2, or 3; nil for a supported tier.
1204func (ratio *TierRatio) Get(tier uint64) (uint64, error) {
1205	switch tier {
1206	case 1:
1207		return ratio.Tier1, nil
1208	case 2:
1209		return ratio.Tier2, nil
1210	case 3:
1211		return ratio.Tier3, nil
1212	default:
1213		return 0, errors.New(ufmt.Sprintf("unsupported tier(%d)", tier))
1214	}
1215}
1216
1217// SwapBatchProcessor processes tick crosses in batch for a swap
1218// This processor accumulates all tick crosses that occur during a single swap
1219// and processes them together at the end, reducing redundant calculations
1220// and state updates that would occur with individual tick processing
1221type SwapBatchProcessor struct {
1222	poolPath  string           // The pool path identifier for this swap
1223	pool      *Pool            // Reference to the pool being swapped in
1224	crosses   []*SwapTickCross // Accumulated tick crosses during the swap
1225	timestamp int64            // Timestamp when the swap started
1226	isActive  bool             // Flag to prevent accumulation after swap ends
1227}
1228
1229// PoolPath returns the pool path associated with this swap batch.
1230//
1231// Returns:
1232//   - path: Pool identifier for the swap being processed.
1233func (s *SwapBatchProcessor) PoolPath() string {
1234	return s.poolPath
1235}
1236
1237// SetPoolPath stores the pool identifier associated with this swap batch.
1238//
1239// Parameters:
1240//   - poolPath: Pool identifier to associate with the swap batch.
1241func (s *SwapBatchProcessor) SetPoolPath(poolPath string) {
1242	s.poolPath = poolPath
1243}
1244
1245// Pool returns the pool referenced by this swap batch.
1246//
1247// Returns:
1248//   - pool: Pool state used to process the accumulated tick crosses.
1249func (s *SwapBatchProcessor) Pool() *Pool {
1250	return s.pool
1251}
1252
1253// SetPool replaces the pool reference used by this swap batch.
1254//
1255// Parameters:
1256//   - pool: Pool state to reference while processing tick crosses.
1257func (s *SwapBatchProcessor) SetPool(pool *Pool) {
1258	s.pool = pool
1259}
1260
1261// Crosses returns the tick crosses accumulated by this batch.
1262//
1263// Returns:
1264//   - crosses: Slice of tick-cross records in the order they were added.
1265func (s *SwapBatchProcessor) Crosses() []*SwapTickCross {
1266	return s.crosses
1267}
1268
1269// SetCrosses replaces the batch's accumulated tick-cross sequence.
1270//
1271// Parameters:
1272//   - crosses: Tick-cross records to store as the batch's accumulated sequence.
1273func (s *SwapBatchProcessor) SetCrosses(crosses []*SwapTickCross) {
1274	s.crosses = crosses
1275}
1276
1277// Timestamp returns the Unix timestamp in seconds recorded when the swap started.
1278//
1279// Returns:
1280//   - timestamp: Swap-start timestamp in Unix seconds.
1281func (s *SwapBatchProcessor) Timestamp() int64 {
1282	return s.timestamp
1283}
1284
1285// SetTimestamp stores the swap-start timestamp for this batch.
1286//
1287// Parameters:
1288//   - timestamp: Unix timestamp in seconds to record for the swap batch.
1289func (s *SwapBatchProcessor) SetTimestamp(timestamp int64) {
1290	s.timestamp = timestamp
1291}
1292
1293// IsActive reports the processor's stored active flag.
1294//
1295// Returns:
1296//   - active: True when the batch is marked active for the swap lifecycle.
1297func (s *SwapBatchProcessor) IsActive() bool {
1298	return s.isActive
1299}
1300
1301// SetIsActive stores the processor's active lifecycle flag.
1302//
1303// Parameters:
1304//   - isActive: Active flag to store for the swap lifecycle.
1305func (s *SwapBatchProcessor) SetIsActive(isActive bool) {
1306	s.isActive = isActive
1307}
1308
1309// LastCross returns the most recently appended tick cross.
1310//
1311// Returns:
1312//   - cross: Last tick-cross record, or nil when no crosses have been added.
1313func (s *SwapBatchProcessor) LastCross() *SwapTickCross {
1314	if len(s.crosses) == 0 {
1315		return nil
1316	}
1317
1318	return s.crosses[len(s.crosses)-1]
1319}
1320
1321// AddCross appends a tick-cross record to the batch sequence.
1322//
1323// Parameters:
1324//   - tickCross: Tick-cross record to append.
1325func (s *SwapBatchProcessor) AddCross(tickCross *SwapTickCross) {
1326	s.crosses = append(s.crosses, tickCross)
1327}
1328
1329// NewSwapBatchProcessor creates an active batch for collecting tick crosses in a pool swap.
1330//
1331// Parameters:
1332//   - poolPath: Pool identifier associated with the swap.
1333//   - pool: Pool state whose tick crosses are being collected.
1334//   - timestamp: Unix timestamp in seconds when the swap began.
1335//
1336// Returns:
1337//   - processor: Active processor with an empty cross sequence.
1338func NewSwapBatchProcessor(poolPath string, pool *Pool, timestamp int64) *SwapBatchProcessor {
1339	return &SwapBatchProcessor{
1340		poolPath:  poolPath,
1341		pool:      pool,
1342		crosses:   make([]*SwapTickCross, 0),
1343		timestamp: timestamp,
1344		isActive:  true,
1345	}
1346}
1347
1348// SwapTickCross stores information about a tick cross during a swap
1349// This struct is used to accumulate tick cross events during a single swap transaction
1350// for batch processing to optimize gas usage and computational efficiency
1351type SwapTickCross struct {
1352	tickID     int32     // The tick index that was crossed
1353	zeroForOne bool      // Direction of the swap (true: token0->token1, false: token1->token0)
1354	delta      *i256.Int // Pre-calculated liquidity delta for this tick cross
1355}
1356
1357// TickID returns the index of the crossed tick.
1358//
1359// Returns:
1360//   - tickID: Tick index represented by this cross.
1361func (s *SwapTickCross) TickID() int32 {
1362	return s.tickID
1363}
1364
1365// ZeroForOne reports the swap direction represented by this cross.
1366//
1367// Returns:
1368//   - zeroForOne: True for token0-to-token1 swaps; false for token1-to-token0 swaps.
1369func (s *SwapTickCross) ZeroForOne() bool {
1370	return s.zeroForOne
1371}
1372
1373// Delta returns the precomputed net staked-liquidity change for the crossed tick.
1374//
1375// Returns:
1376//   - delta: Signed liquidity delta to apply at the crossed tick.
1377func (s *SwapTickCross) Delta() *i256.Int {
1378	return s.delta
1379}
1380
1381// NewSwapTickCross creates a tick-cross record for a swap batch.
1382//
1383// Parameters:
1384//   - tickID: Index of the tick crossed during the swap.
1385//   - zeroForOne: Swap direction; true means token0-to-token1 and false means token1-to-token0.
1386//   - delta: Precomputed signed staked-liquidity change for this tick cross.
1387//
1388// Returns:
1389//   - cross: Tick-cross record containing the supplied index, direction, and delta.
1390func NewSwapTickCross(tickID int32, zeroForOne bool, delta *i256.Int) *SwapTickCross {
1391	return &SwapTickCross{
1392		tickID:     tickID,
1393		zeroForOne: zeroForOne,
1394		delta:      delta,
1395	}
1396}