Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

reward_calculation_warmup.gno

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