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}