deposit.gno
18.04 Kb · 533 lines
1package staker
2
3import (
4 "math"
5
6 u256 "gno.land/p/gnoswap/uint256/v1"
7)
8
9type Deposit struct {
10 warmups []Warmup // warmup information
11 liquidity *u256.Uint // liquidity
12 targetPoolPath string // staked position's pool path
13 owner address // owner address
14 stakeTime int64 // staked time
15 internalRewardLastCollectTime int64 // last collect time for internal reward
16 collectedInternalReward int64 // collected internal reward
17 collectedExternalRewards map[string]int64 // collected external reward by incentive id (incentiveID -> int64)
18 externalRewardLastCollectTimes map[string]int64 // last collect time for external rewards by incentive id (incentiveID -> int64)
19 externalIncentiveIds map[string]bool // external incentive ids for this deposit (incentiveID -> bool)
20 lastExternalIncentiveUpdatedAt int64 // last time when external incentive ids were synced
21 tickLower int32 // tick lower
22 tickUpper int32 // tick upper
23}
24
25// Owner returns the address that owns the staked position.
26//
27// Returns:
28// - owner: Address recorded as the deposit owner.
29func (d *Deposit) Owner() address {
30 return d.owner
31}
32
33// SetOwner updates the address recorded as the deposit owner.
34//
35// Parameters:
36// - owner: Address that should own the deposit.
37func (d *Deposit) SetOwner(owner address) {
38 d.owner = owner
39}
40
41// TargetPoolPath returns the pool path associated with the staked position.
42//
43// Returns:
44// - targetPoolPath: Pool identifier used to resolve the position's pool.
45func (d *Deposit) TargetPoolPath() string {
46 return d.targetPoolPath
47}
48
49// SetTargetPoolPath updates the pool path associated with the staked position.
50//
51// Parameters:
52// - targetPoolPath: Pool identifier to associate with the deposit.
53func (d *Deposit) SetTargetPoolPath(targetPoolPath string) {
54 d.targetPoolPath = targetPoolPath
55}
56
57// Liquidity returns the LP liquidity recorded for the deposit.
58//
59// Returns:
60// - liquidity: Liquidity amount represented by the staked position.
61func (d *Deposit) Liquidity() *u256.Uint {
62 return d.liquidity
63}
64
65// SetLiquidity replaces the LP liquidity recorded for the deposit.
66//
67// Parameters:
68// - liquidity: New liquidity amount; the setter copies this value into the deposit.
69func (d *Deposit) SetLiquidity(liquidity *u256.Uint) {
70 d.liquidity = u256.Zero().Set(liquidity)
71}
72
73// StakeTime returns the Unix timestamp at which the position was staked.
74//
75// Returns:
76// - stakeTime: Stake start time in Unix seconds.
77func (d *Deposit) StakeTime() int64 {
78 return d.stakeTime
79}
80
81// SetStakeTime updates the Unix timestamp at which the position was staked.
82//
83// Parameters:
84// - stakeTime: Stake start time in Unix seconds.
85func (d *Deposit) SetStakeTime(stakeTime int64) {
86 d.stakeTime = stakeTime
87}
88
89// InternalRewardLastCollectTime returns the internal-reward collection cursor.
90//
91// Returns:
92// - internalRewardLastCollectTime: Last internal reward collection time in Unix seconds.
93func (d *Deposit) InternalRewardLastCollectTime() int64 {
94 return d.internalRewardLastCollectTime
95}
96
97// SetInternalRewardLastCollectTime updates the internal-reward collection cursor.
98//
99// Parameters:
100// - internalRewardLastCollectTime: New last internal reward collection time in Unix seconds.
101func (d *Deposit) SetInternalRewardLastCollectTime(internalRewardLastCollectTime int64) {
102 d.internalRewardLastCollectTime = internalRewardLastCollectTime
103}
104
105// CollectedInternalReward returns the cumulative internal reward recorded for the deposit.
106//
107// Returns:
108// - collectedInternalReward: Accumulated internal reward amount in the reward token's smallest units.
109func (d *Deposit) CollectedInternalReward() int64 {
110 return d.collectedInternalReward
111}
112
113// SetCollectedInternalReward replaces the cumulative internal reward recorded for the deposit.
114//
115// Parameters:
116// - collectedInternalReward: Cumulative internal reward amount in the reward token's smallest units.
117func (d *Deposit) SetCollectedInternalReward(collectedInternalReward int64) {
118 d.collectedInternalReward = collectedInternalReward
119}
120
121// CollectedExternalRewards returns cumulative external rewards keyed by incentive ID.
122//
123// Returns:
124// - collectedExternalRewards: Map from incentive ID to the amount collected for that incentive.
125func (d *Deposit) CollectedExternalRewards() map[string]int64 {
126 return d.collectedExternalRewards
127}
128
129// SetCollectedExternalRewards replaces the cumulative external-reward map.
130//
131// Parameters:
132// - collectedExternalRewards: Map from incentive ID to its collected reward amount.
133func (d *Deposit) SetCollectedExternalRewards(collectedExternalRewards map[string]int64) {
134 d.collectedExternalRewards = collectedExternalRewards
135}
136
137// GetCollectedExternalReward returns the collected external reward for the given incentive ID.
138// Returns 0 if the incentive ID does not exist.
139//
140// Parameters:
141// - incentiveID: External incentive ID whose collected amount should be looked up.
142//
143// Returns:
144// - reward: Collected amount for the incentive, or 0 when the ID is absent.
145// - exists: True when the map contains incentiveID; false when it is absent.
146func (d *Deposit) GetCollectedExternalReward(incentiveID string) (int64, bool) {
147 reward, exists := d.collectedExternalRewards[incentiveID]
148 if !exists {
149 return 0, false
150 }
151
152 return reward, true
153}
154
155// SetCollectedExternalReward records the cumulative amount collected for one incentive.
156//
157// Parameters:
158// - incentiveID: External incentive ID whose collected amount should be set.
159// - reward: Cumulative collected amount for incentiveID.
160func (d *Deposit) SetCollectedExternalReward(incentiveID string, reward int64) {
161 if d.collectedExternalRewards == nil {
162 d.collectedExternalRewards = make(map[string]int64)
163 }
164
165 d.collectedExternalRewards[incentiveID] = reward
166}
167
168// ExternalRewardLastCollectTimes returns per-incentive external collection cursors.
169//
170// Returns:
171// - externalRewardLastCollectTimes: Map from incentive ID to its last collection time in Unix seconds.
172func (d *Deposit) ExternalRewardLastCollectTimes() map[string]int64 {
173 return d.externalRewardLastCollectTimes
174}
175
176// SetExternalRewardLastCollectTimes replaces the per-incentive external collection cursors.
177//
178// Parameters:
179// - externalRewardLastCollectTimes: Map from incentive ID to its last collection time in Unix seconds.
180func (d *Deposit) SetExternalRewardLastCollectTimes(externalRewardLastCollectTimes map[string]int64) {
181 d.externalRewardLastCollectTimes = externalRewardLastCollectTimes
182}
183
184// GetExternalRewardLastCollectTime returns the last collect time for the given incentive ID.
185// Returns 0 if the incentive ID does not exist.
186//
187// Parameters:
188// - incentiveID: External incentive ID whose collection cursor should be looked up.
189//
190// Returns:
191// - time: Last collection time for the incentive in Unix seconds, or 0 when the ID is absent.
192// - exists: True when the map contains incentiveID; false when it is absent.
193func (d *Deposit) GetExternalRewardLastCollectTime(incentiveID string) (int64, bool) {
194 time, exists := d.externalRewardLastCollectTimes[incentiveID]
195 if !exists {
196 return 0, false
197 }
198
199 return time, true
200}
201
202// SetExternalRewardLastCollectTime records the collection cursor for one incentive.
203//
204// Parameters:
205// - incentiveID: External incentive ID whose cursor should be set.
206// - currentTime: New collection time for incentiveID in Unix seconds.
207func (d *Deposit) SetExternalRewardLastCollectTime(incentiveID string, currentTime int64) {
208 if d.externalRewardLastCollectTimes == nil {
209 d.externalRewardLastCollectTimes = make(map[string]int64)
210 }
211
212 d.externalRewardLastCollectTimes[incentiveID] = currentTime
213}
214
215// TickLower returns the lower signed tick boundary of the staked position.
216//
217// Returns:
218// - tickLower: Lower tick boundary used by the position's price range.
219func (d *Deposit) TickLower() int32 {
220 return d.tickLower
221}
222
223// SetTickLower updates the lower signed tick boundary of the staked position.
224//
225// Parameters:
226// - tickLower: Lower tick boundary to store for the position's price range.
227func (d *Deposit) SetTickLower(tickLower int32) {
228 d.tickLower = tickLower
229}
230
231// TickUpper returns the upper signed tick boundary of the staked position.
232//
233// Returns:
234// - tickUpper: Upper tick boundary used by the position's price range.
235func (d *Deposit) TickUpper() int32 {
236 return d.tickUpper
237}
238
239// SetTickUpper updates the upper signed tick boundary of the staked position.
240//
241// Parameters:
242// - tickUpper: Upper tick boundary to store for the position's price range.
243func (d *Deposit) SetTickUpper(tickUpper int32) {
244 d.tickUpper = tickUpper
245}
246
247// ExternalIncentiveIds returns the deposit's indexed external incentive IDs.
248//
249// Returns:
250// - externalIncentiveIds: Map from each indexed incentive ID to its membership flag.
251func (d *Deposit) ExternalIncentiveIds() map[string]bool {
252 return d.externalIncentiveIds
253}
254
255// SetExternalIncentiveIds replaces the deposit's indexed external incentive IDs.
256//
257// Parameters:
258// - externalIncentiveIds: Map of incentive IDs to their membership flags.
259func (d *Deposit) SetExternalIncentiveIds(externalIncentiveIds map[string]bool) {
260 d.externalIncentiveIds = externalIncentiveIds
261}
262
263// AddExternalIncentiveId adds an external incentive id to the deposit.
264//
265// Parameters:
266// - incentiveId: External incentive ID to add to the deposit's index.
267func (d *Deposit) AddExternalIncentiveId(incentiveId string) {
268 if d.externalIncentiveIds == nil {
269 d.externalIncentiveIds = make(map[string]bool)
270 }
271
272 d.externalIncentiveIds[incentiveId] = true
273}
274
275// HasExternalIncentiveId checks if the deposit has the given external incentive id.
276//
277// Parameters:
278// - incentiveId: External incentive ID whose membership should be checked.
279//
280// Returns:
281// - hasIncentive: True when incentiveId is indexed on the deposit; false otherwise.
282func (d *Deposit) HasExternalIncentiveId(incentiveId string) bool {
283 if d.externalIncentiveIds == nil {
284 return false
285 }
286
287 return d.externalIncentiveIds[incentiveId]
288}
289
290// RemoveExternalIncentiveId removes an external incentive id from the deposit.
291//
292// Parameters:
293// - incentiveId: External incentive ID to remove from the deposit's index.
294func (d *Deposit) RemoveExternalIncentiveId(incentiveId string) {
295 if d.externalIncentiveIds == nil {
296 return
297 }
298
299 delete(d.externalIncentiveIds, incentiveId)
300}
301
302// GetExternalIncentiveIdList returns a list of external incentive ids for the deposit.
303//
304// Returns:
305// - incentiveIds: Slice containing the incentive IDs currently indexed on the deposit; order follows map iteration and is not guaranteed.
306func (d *Deposit) GetExternalIncentiveIdList() []string {
307 if d.externalIncentiveIds == nil {
308 return []string{}
309 }
310
311 ids := make([]string, 0, len(d.externalIncentiveIds))
312
313 for incentiveId := range d.externalIncentiveIds {
314 ids = append(ids, incentiveId)
315 }
316
317 return ids
318}
319
320// IterateExternalIncentiveIds iterates over external incentive IDs without allocating a slice.
321// The callback function receives each incentive ID and should return false to continue iteration,
322// or true to stop early. This method is more memory-efficient than GetExternalIncentiveIdList
323// for cases where you only need to process IDs sequentially.
324//
325// Parameters:
326// - fn: Callback invoked with each indexed incentive ID; return true to stop iteration early or false to continue.
327func (d *Deposit) IterateExternalIncentiveIds(fn func(incentiveId string) bool) {
328 if d.externalIncentiveIds == nil {
329 return
330 }
331
332 for incentiveId := range d.externalIncentiveIds {
333 if fn(incentiveId) {
334 return
335 }
336 }
337}
338
339// Warmups returns a copy of the deposit's warmup schedule.
340//
341// Returns:
342// - warmups: Warmup tiers applied to rewards for this deposit, or nil when no schedule is stored.
343func (d *Deposit) Warmups() []Warmup {
344 return cloneWarmups(d.warmups)
345}
346
347// SetWarmups replaces the deposit's warmup schedule with a copied slice.
348//
349// Parameters:
350// - warmups: Warmup tiers to use for subsequent reward calculations.
351func (d *Deposit) SetWarmups(warmups []Warmup) {
352 d.warmups = cloneWarmups(warmups)
353}
354
355// LastExternalIncentiveUpdatedAt returns the timestamp of the last external-incentive index refresh.
356//
357// Returns:
358// - timestamp: Last refresh time in Unix seconds.
359func (d *Deposit) LastExternalIncentiveUpdatedAt() int64 {
360 return d.lastExternalIncentiveUpdatedAt
361}
362
363// SetLastExternalIncentiveUpdatedAt updates the external-incentive index refresh timestamp.
364//
365// Parameters:
366// - timestamp: Refresh time to record in Unix seconds.
367func (d *Deposit) SetLastExternalIncentiveUpdatedAt(timestamp int64) {
368 d.lastExternalIncentiveUpdatedAt = timestamp
369}
370
371// Clone returns a deep copy of the deposit.
372//
373// Returns:
374// - deposit: Deep copy of the deposit, or nil when the receiver is nil.
375func (d *Deposit) Clone() *Deposit {
376 if d == nil {
377 return nil
378 }
379
380 return &Deposit{
381 warmups: cloneWarmups(d.warmups),
382 liquidity: d.liquidity.Clone(),
383 targetPoolPath: d.targetPoolPath,
384 owner: d.owner,
385 stakeTime: d.stakeTime,
386 internalRewardLastCollectTime: d.internalRewardLastCollectTime,
387 collectedInternalReward: d.collectedInternalReward,
388 collectedExternalRewards: cloneStringInt64Map(d.collectedExternalRewards),
389 externalRewardLastCollectTimes: cloneStringInt64Map(d.externalRewardLastCollectTimes),
390 externalIncentiveIds: cloneStringBoolMap(d.externalIncentiveIds),
391 lastExternalIncentiveUpdatedAt: d.lastExternalIncentiveUpdatedAt,
392 tickLower: d.tickLower,
393 tickUpper: d.tickUpper,
394 }
395}
396
397// NewDeposit creates a deposit for a staked LP position and initializes its reward cursors and maps.
398//
399// Parameters:
400// - owner: Address that owns the staked position.
401// - targetPoolPath: Pool identifier associated with the position.
402// - liquidity: LP liquidity amount represented by the position.
403// - currentTime: Staking and initial reward-cursor time in Unix seconds.
404// - tickLower: Lower signed tick boundary of the position's range.
405// - tickUpper: Upper signed tick boundary of the position's range.
406// - warmups: Warmup schedule to apply to this position's rewards.
407//
408// Returns:
409// - deposit: Newly initialized deposit containing the supplied position and warmup state.
410func NewDeposit(
411 owner address,
412 targetPoolPath string,
413 liquidity *u256.Uint,
414 currentTime int64,
415 tickLower, tickUpper int32,
416 warmups []Warmup,
417) *Deposit {
418 return &Deposit{
419 owner: owner,
420 targetPoolPath: targetPoolPath,
421 liquidity: liquidity,
422 warmups: warmups,
423 stakeTime: currentTime,
424 tickLower: tickLower,
425 tickUpper: tickUpper,
426 internalRewardLastCollectTime: currentTime,
427 externalRewardLastCollectTimes: make(map[string]int64),
428 collectedInternalReward: 0,
429 collectedExternalRewards: make(map[string]int64),
430 externalIncentiveIds: make(map[string]bool),
431 lastExternalIncentiveUpdatedAt: 0,
432 }
433}
434
435type Warmup struct {
436 TimeDuration int64
437 NextWarmupTime int64 // time when this warmup period ends
438 WarmupRatio uint64
439}
440
441// NewWarmup creates one warmup tier.
442//
443// Parameters:
444// - timeDuration: Duration of this tier in seconds.
445// - nextWarmupTime: Unix timestamp at which this tier ends.
446// - warmupRatio: Percentage of the calculated reward credited to the position, from 0 to 100.
447//
448// Returns:
449// - warmup: Warmup tier initialized with the supplied duration, end time, and ratio.
450func NewWarmup(timeDuration, nextWarmupTime int64, warmupRatio uint64) Warmup {
451 return Warmup{
452 TimeDuration: timeDuration,
453 NextWarmupTime: nextWarmupTime,
454 WarmupRatio: warmupRatio,
455 }
456}
457
458// SetNextWarmupTime updates the Unix timestamp at which this warmup tier ends.
459//
460// Parameters:
461// - nextWarmupTime: Tier end time in Unix seconds.
462func (w *Warmup) SetNextWarmupTime(nextWarmupTime int64) {
463 w.NextWarmupTime = nextWarmupTime
464}
465
466// SetWarmupRatio updates the percentage of calculated reward credited to the position.
467//
468// Parameters:
469// - warmupRatio: Reward percentage for this tier, expressed from 0 to 100.
470func (w *Warmup) SetWarmupRatio(warmupRatio uint64) {
471 w.WarmupRatio = warmupRatio
472}
473
474// SetTimeDuration updates the duration of this warmup tier.
475//
476// Parameters:
477// - timeDuration: Tier duration in seconds.
478func (w *Warmup) SetTimeDuration(timeDuration int64) {
479 w.TimeDuration = timeDuration
480}
481
482// DefaultWarmupTemplate returns the built-in four-tier warmup schedule.
483//
484// Returns:
485// - warmups: Template with 5-day, 10-day, 30-day, and final-unbounded tiers using 30%, 50%, 70%, and 100% ratios; NextWarmupTime values are zero until instantiated.
486func DefaultWarmupTemplate() []Warmup {
487 secondsInDay := int64(86400)
488 secondsIn5Days := int64(5 * secondsInDay)
489 secondsIn10Days := int64(10 * secondsInDay)
490 secondsIn30Days := int64(30 * secondsInDay)
491
492 // NextWarmupTime is set to 0 for template.
493 // They will be set by InstantiateWarmup()
494 return []Warmup{
495 {
496 TimeDuration: secondsIn5Days,
497 // NextWarmupTime will be set based on currentTime
498 // NextWarmupTime: currentTime + secondsIn5Days,
499 WarmupRatio: 30,
500 },
501 {
502 TimeDuration: secondsIn10Days,
503 // NextWarmupTime will be set based on currentTime
504 // NextWarmupTime: currentTime + secondsIn10Days,
505 WarmupRatio: 50,
506 },
507 {
508 TimeDuration: secondsIn30Days,
509 // NextWarmupTime will be set based on currentTime
510 // NextWarmupTime: currentTime + secondsIn30Days,
511 WarmupRatio: 70,
512 },
513 {
514 TimeDuration: math.MaxInt64,
515 // NextWarmupTime will be set to math.MaxInt64
516 // NextWarmupTime: math.MaxInt64,
517 WarmupRatio: 100,
518 },
519 }
520}
521
522const (
523 GNS_PATH string = "gno.land/r/gnoswap/gns.GNS"
524 WUGNOT_PATH string = "gno.land/r/gnoland/wugnot.wugnot"
525)
526
527// DefaultAllowedTokens returns the token paths accepted by the staker's default configuration.
528//
529// Returns:
530// - tokenPaths: Slice containing the GNS and wrapped-GNOT token paths.
531func DefaultAllowedTokens() []string {
532 return []string{GNS_PATH, WUGNOT_PATH}
533}