reward_calculation_warmup.gno
2.99 Kb · 99 lines
1package v1
2
3import (
4 "math"
5
6 u256 "gno.land/p/gnoswap/uint256"
7 ufmt "gno.land/p/nt/ufmt/v0"
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.NewWarmup(warmup.TimeDuration, nextWarmupTime, warmup.WarmupRatio))
49
50 // Only update currentTime if not the last tier
51 if i < len(warmupTemplate)-1 {
52 currentTime = safeAddTime(currentTime, warmup.TimeDuration)
53 }
54 }
55 return warmups
56}
57
58func applyWarmup(warmup sr.Warmup, poolReward int64, positionLiquidity, stakedLiquidity *u256.Uint) (int64, int64) {
59 if stakedLiquidity.IsZero() {
60 return 0, 0
61 }
62
63 divisor := u256.NewUint(100)
64 poolRewardUint := u256.NewUintFromInt64(poolReward)
65 perPositionReward, overflow := u256.Zero().MulOverflow(poolRewardUint, positionLiquidity)
66 if overflow {
67 panic(errOverflow)
68 }
69 perPositionReward = u256.Zero().Div(perPositionReward, stakedLiquidity)
70
71 penaltyRatio := u256.NewUint(100 - warmup.WarmupRatio)
72 rewardRatio := u256.NewUint(warmup.WarmupRatio)
73 totalReward, overflow := u256.Zero().MulOverflow(perPositionReward, rewardRatio)
74 if overflow {
75 panic(errOverflow)
76 }
77 totalReward = u256.Zero().Div(totalReward, divisor)
78
79 totalPenalty, overflow := u256.Zero().MulOverflow(perPositionReward, penaltyRatio)
80 if overflow {
81 panic(errOverflow)
82 }
83 totalPenalty = u256.Zero().Div(totalPenalty, divisor)
84 return safeConvertToInt64(totalReward), safeConvertToInt64(totalPenalty)
85}
86
87// safeAddTime performs safe addition with overflow protection
88func safeAddTime(currentTime, duration int64) int64 {
89 if duration == math.MaxInt64 {
90 return math.MaxInt64
91 }
92
93 // Check for overflow before addition
94 if currentTime > 0 && duration > math.MaxInt64-currentTime {
95 return math.MaxInt64
96 }
97
98 return safeAddInt64(currentTime, duration)
99}