Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}