reward_calculation_warmup.gno
3.07 Kb ยท 104 lines
1package v1
2
3import (
4 "math"
5
6 u256 "gno.land/p/gnoswap/uint256"
7 "gno.land/p/nt/ufmt"
8 sr "gno.land/r/gnoswap/staker"
9)
10
11const maxDurationOneYear = int64(365 * 86400) // 31,536,000 seconds
12
13// expected to be called by governance
14func modifyWarmup(warmupTemplate []sr.Warmup, index int, timeDuration int64) []sr.Warmup {
15 if index >= len(warmupTemplate) {
16 panic(ufmt.Sprintf("index(%d) is out of range", index))
17 }
18
19 // Handle negative duration - panic with error
20 if timeDuration < 0 {
21 panic(ufmt.Sprintf("warmup duration cannot be negative, got %d seconds", timeDuration))
22 }
23
24 // Early return for last tier - must always be math.MaxInt64
25 if index == len(warmupTemplate)-1 {
26 if timeDuration != math.MaxInt64 {
27 panic(ufmt.Sprintf("last warmup tier must have duration of math.MaxInt64, got %d", timeDuration))
28 }
29 // No modification needed as it's already math.MaxInt64
30 return warmupTemplate
31 }
32
33 // Limit non-final tier durations to 1 year (365 days)
34 if timeDuration > maxDurationOneYear {
35 panic(ufmt.Sprintf("warmup duration cannot exceed 1 year (365 days), got %d seconds", timeDuration))
36 }
37
38 warmupTemplate[index].SetTimeDuration(timeDuration)
39
40 return warmupTemplate
41}
42
43func instantiateWarmup(warmupTemplate []sr.Warmup, currentTime int64) []sr.Warmup {
44 warmups := make([]sr.Warmup, 0, len(warmupTemplate))
45 for i, warmup := range warmupTemplate {
46 nextWarmupTime := safeAddTime(currentTime, warmup.TimeDuration)
47
48 warmups = append(warmups, sr.Warmup{
49 Index: warmup.Index,
50 TimeDuration: warmup.TimeDuration,
51 NextWarmupTime: nextWarmupTime,
52 WarmupRatio: warmup.WarmupRatio,
53 })
54
55 // Only update currentTime if not the last tier
56 if i < len(warmupTemplate)-1 {
57 currentTime = safeAddTime(currentTime, warmup.TimeDuration)
58 }
59 }
60 return warmups
61}
62
63func applyWarmup(warmup sr.Warmup, poolReward int64, positionLiquidity, stakedLiquidity *u256.Uint) (int64, int64) {
64 if stakedLiquidity.IsZero() {
65 return 0, 0
66 }
67
68 divisor := u256.NewUint(100)
69 poolRewardUint := u256.NewUintFromInt64(poolReward)
70 perPositionReward, overflow := u256.Zero().MulOverflow(poolRewardUint, positionLiquidity)
71 if overflow {
72 panic(errOverflow)
73 }
74 perPositionReward = u256.Zero().Div(perPositionReward, stakedLiquidity)
75
76 penaltyRatio := u256.NewUint(100 - warmup.WarmupRatio)
77 rewardRatio := u256.NewUint(warmup.WarmupRatio)
78 totalReward, overflow := u256.Zero().MulOverflow(perPositionReward, rewardRatio)
79 if overflow {
80 panic(errOverflow)
81 }
82 totalReward = u256.Zero().Div(totalReward, divisor)
83
84 totalPenalty, overflow := u256.Zero().MulOverflow(perPositionReward, penaltyRatio)
85 if overflow {
86 panic(errOverflow)
87 }
88 totalPenalty = u256.Zero().Div(totalPenalty, divisor)
89 return safeConvertToInt64(totalReward), safeConvertToInt64(totalPenalty)
90}
91
92// safeAddTime performs safe addition with overflow protection
93func safeAddTime(currentTime, duration int64) int64 {
94 if duration == math.MaxInt64 {
95 return math.MaxInt64
96 }
97
98 // Check for overflow before addition
99 if currentTime > 0 && duration > math.MaxInt64-currentTime {
100 return math.MaxInt64
101 }
102
103 return safeAddInt64(currentTime, duration)
104}