Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}