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

manage_pool_tier_and_warmup.gno

6.75 Kb · 239 lines
  1package staker
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"errors"
  7	"time"
  8
  9	"gno.land/p/gnoswap/utils"
 10
 11	"gno.land/r/gnoswap/access"
 12	"gno.land/r/gnoswap/halt"
 13	sr "gno.land/r/gnoswap/staker"
 14)
 15
 16const (
 17	NOT_EMISSION_TARGET_TIER uint64 = 0
 18)
 19
 20// SetPoolTier assigns a tier level to a pool for internal GNS emission rewards.
 21// Only admin or governance can call this function.
 22func (s *stakerV1) SetPoolTier(_ int, rlm realm, poolPath string, tier uint64) {
 23	if !rlm.IsCurrent() {
 24		panic(errors.New(errSpoofedRealm))
 25	}
 26
 27	halt.AssertIsNotHaltedStaker()
 28
 29	caller := rlm.Previous().Address()
 30	access.AssertIsAdminOrGovernance(caller)
 31
 32	assertIsPoolExists(s, poolPath)
 33	assertIsValidPoolTier(tier)
 34
 35	// If the tier is already set, do nothing
 36	poolTier := s.getPoolTier()
 37	previousTier := poolTier.CurrentTier(poolPath)
 38	if previousTier == tier {
 39		return
 40	}
 41
 42	currentTime := time.Now().Unix()
 43	rewardPerSecond, tierRewards := s.setPoolTier(0, rlm, poolPath, tier, currentTime)
 44
 45	previousRealm := rlm.Previous()
 46	emitSetPoolTier(
 47		previousRealm.Address().String(),
 48		previousRealm.PkgPath(),
 49		poolPath,
 50		tier,
 51		rewardPerSecond,
 52		tierRewards,
 53		poolTier.counts,
 54		currentTime,
 55	)
 56}
 57
 58// ChangePoolTier modifies the tier level of an existing pool.
 59// Only admin or governance can call this function.
 60func (s *stakerV1) ChangePoolTier(_ int, rlm realm, poolPath string, tier uint64) {
 61	if !rlm.IsCurrent() {
 62		panic(errors.New(errSpoofedRealm))
 63	}
 64
 65	halt.AssertIsNotHaltedStaker()
 66
 67	previousRealm := rlm.Previous()
 68	caller := previousRealm.Address()
 69	access.AssertIsAdminOrGovernance(caller)
 70
 71	assertIsPoolExists(s, poolPath)
 72	assertIsValidPoolTier(tier)
 73
 74	poolTier := s.getPoolTier()
 75
 76	// If the tier is already set, do nothing
 77	previousTier := poolTier.CurrentTier(poolPath)
 78	if previousTier == tier {
 79		return
 80	}
 81
 82	currentTime := time.Now().Unix()
 83	previousTier, newTier, rewardPerSecond, tierRewards := s.changePoolTier(0, rlm, poolPath, tier, currentTime)
 84
 85	chain.Emit(
 86		"ChangePoolTier",
 87		"prevAddr", caller.String(),
 88		"prevRealm", previousRealm.PkgPath(),
 89		"poolPath", poolPath,
 90		"prevTier", utils.FormatUint(previousTier),
 91		"newTier", utils.FormatUint(newTier),
 92		"rewardPerSecond", utils.FormatInt(rewardPerSecond),
 93		"tier1RewardPerSecond", utils.FormatInt(tierRewards[Tier1]),
 94		"tier2RewardPerSecond", utils.FormatInt(tierRewards[Tier2]),
 95		"tier3RewardPerSecond", utils.FormatInt(tierRewards[Tier3]),
 96		"tier1Count", utils.FormatUint(poolTier.counts[Tier1]),
 97		"tier2Count", utils.FormatUint(poolTier.counts[Tier2]),
 98		"tier3Count", utils.FormatUint(poolTier.counts[Tier3]),
 99		"currentTime", utils.FormatInt(currentTime),
100		"currentHeight", utils.FormatInt(runtime.ChainHeight()),
101	)
102}
103
104// RemovePoolTier removes a pool from internal GNS emission rewards.
105// Only admin or governance can call this function.
106func (s *stakerV1) RemovePoolTier(_ int, rlm realm, poolPath string) {
107	if !rlm.IsCurrent() {
108		panic(errors.New(errSpoofedRealm))
109	}
110
111	halt.AssertIsNotHaltedStaker()
112
113	previousRealm := rlm.Previous()
114	caller := previousRealm.Address()
115	access.AssertIsAdminOrGovernance(caller)
116
117	assertIsPoolExists(s, poolPath)
118
119	poolTier := s.getPoolTier()
120
121	// If the tier is already set, do nothing
122	previousTier := poolTier.CurrentTier(poolPath)
123	if previousTier == NOT_EMISSION_TARGET_TIER {
124		return
125	}
126
127	currentTime := time.Now().Unix()
128	rewardPerSecond, tierRewards := s.removePoolTier(0, rlm, poolPath, currentTime)
129
130	chain.Emit(
131		"RemovePoolTier",
132		"prevAddr", caller.String(),
133		"prevRealm", previousRealm.PkgPath(),
134		"poolPath", poolPath,
135		"rewardPerSecond", utils.FormatInt(rewardPerSecond),
136		"tier1RewardPerSecond", utils.FormatInt(tierRewards[Tier1]),
137		"tier2RewardPerSecond", utils.FormatInt(tierRewards[Tier2]),
138		"tier3RewardPerSecond", utils.FormatInt(tierRewards[Tier3]),
139		"tier1Count", utils.FormatUint(poolTier.counts[Tier1]),
140		"tier2Count", utils.FormatUint(poolTier.counts[Tier2]),
141		"tier3Count", utils.FormatUint(poolTier.counts[Tier3]),
142		"currentTime", utils.FormatInt(currentTime),
143		"currentHeight", utils.FormatInt(runtime.ChainHeight()),
144	)
145}
146
147// SetWarmUp configures the warm-up percentage and duration for rewards.
148// Only admin or governance can call this function.
149func (s *stakerV1) SetWarmUp(_ int, rlm realm, pct, timeDuration int64) {
150	if !rlm.IsCurrent() {
151		panic(errors.New(errSpoofedRealm))
152	}
153
154	halt.AssertIsNotHaltedStaker()
155
156	previousRealm := rlm.Previous()
157	caller := previousRealm.Address()
158	access.AssertIsAdminOrGovernance(caller)
159
160	s.setWarmUp(0, rlm, pct, timeDuration)
161
162	chain.Emit(
163		"SetWarmUp",
164		"prevAddr", caller.String(),
165		"prevRealm", previousRealm.PkgPath(),
166		"pct", utils.FormatInt(pct),
167		"timeDuration", utils.FormatInt(timeDuration),
168	)
169}
170
171// setPoolTier internally sets the pool tier.
172func (s *stakerV1) setPoolTier(_ int, rlm realm, poolPath string, tier uint64, currentTime int64) (int64, map[uint64]int64) {
173	s.emissionAccessor.MintAndDistributeGns(0, rlm)
174
175	pool := s.getPools().GetPoolOrNil(poolPath)
176	if pool == nil {
177		pool = sr.NewPool(poolPath, currentTime)
178		s.getPools().set(poolPath, pool)
179	}
180	poolTier := s.getPoolTier()
181	tierRewards := poolTier.changeTier(currentTime, s.getPools(), poolPath, tier)
182
183	s.updatePoolTier(0, rlm, poolTier)
184
185	return poolTier.currentEmission, tierRewards
186}
187
188// changePoolTier internally changes the pool tier and returns old and new tiers.
189func (s *stakerV1) changePoolTier(_ int, rlm realm, poolPath string, tier uint64, currentTime int64) (uint64, uint64, int64, map[uint64]int64) {
190	s.emissionAccessor.MintAndDistributeGns(0, rlm)
191	poolTier := s.getPoolTier()
192	previousTier := poolTier.CurrentTier(poolPath)
193
194	tierRewards := poolTier.changeTier(currentTime, s.getPools(), poolPath, tier)
195
196	s.updatePoolTier(0, rlm, poolTier)
197
198	return previousTier, tier, poolTier.currentEmission, tierRewards
199}
200
201// removePoolTier internally removes the pool from tier system.
202func (s *stakerV1) removePoolTier(_ int, rlm realm, poolPath string, currentTime int64) (int64, map[uint64]int64) {
203	s.emissionAccessor.MintAndDistributeGns(0, rlm)
204
205	poolTier := s.getPoolTier()
206	tierRewards := poolTier.changeTier(currentTime, s.getPools(), poolPath, NOT_EMISSION_TARGET_TIER)
207	s.updatePoolTier(0, rlm, poolTier)
208
209	return poolTier.currentEmission, tierRewards
210}
211
212// setWarmUp internally sets the warm-up parameters.
213func (s *stakerV1) setWarmUp(_ int, rlm realm, pct, timeDuration int64) {
214	s.emissionAccessor.MintAndDistributeGns(0, rlm)
215
216	warmupTemplate := s.store.GetWarmupTemplate()
217	warmupTemplate = modifyWarmup(warmupTemplate, pctToIndex(pct), timeDuration)
218
219	err := s.store.SetWarmupTemplate(0, rlm, warmupTemplate)
220	if err != nil {
221		panic(err)
222	}
223}
224
225// pctToIndex converts percentage to warmup index.
226func pctToIndex(pct int64) int {
227	switch pct {
228	case 30:
229		return 0
230	case 50:
231		return 1
232	case 70:
233		return 2
234	case 100:
235		return 3
236	default:
237		panic("staker.gno__pctToIndex() || pct is not valid")
238	}
239}