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

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