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

init.gno

7.03 Kb · 258 lines
  1package staker
  2
  3import (
  4	"time"
  5
  6	"gno.land/r/gnoswap/access/v1"
  7
  8	"gno.land/r/gnoswap/emission"
  9
 10	sr "gno.land/r/gnoswap/staker"
 11)
 12
 13const (
 14	defaultDepositGnsAmount    = int64(100_000_000_000)
 15	defaultMinimumRewardAmount = int64(1_000_000_000)
 16
 17	// unstakingFee is the fee charged when unstaking positions.
 18	// This parameter can be modified through governance.
 19	defaultUnstakingFee = uint64(100) // 1%
 20)
 21
 22func init(cur realm) {
 23	registerStakerV1(cur)
 24}
 25
 26func registerStakerV1(cur realm) {
 27	sr.RegisterInitializer(cross(cur), func(_ int, rlm realm, stakerStore sr.IStakerStore, poolAccessor sr.PoolAccessor, emissionAccessor sr.EmissionAccessor, nftAccessor sr.NFTAccessor) sr.IStaker {
 28		access.AssertIsRlmCurrent(0, rlm)
 29
 30		err := initStoreData(0, rlm, stakerStore, emissionAccessor)
 31		if err != nil {
 32			panic(err)
 33		}
 34
 35		instance := NewStakerV1(stakerStore, poolAccessor, emissionAccessor, nftAccessor)
 36		instance.setupSwapHooks(0, rlm)
 37		emissionAccessor.SetOnDistributionPctChangeCallback(0, rlm, instance.emissionCacheUpdateHook)
 38
 39		return instance
 40	})
 41}
 42
 43func initStoreData(_ int, rlm realm, stakerStore sr.IStakerStore, emissionAccessor sr.EmissionAccessor) error {
 44	if !stakerStore.HasDepositGnsAmountStoreKey() {
 45		err := stakerStore.SetDepositGnsAmount(0, rlm, defaultDepositGnsAmount)
 46		if err != nil {
 47			return err
 48		}
 49	}
 50
 51	if !stakerStore.HasMinimumRewardAmountStoreKey() {
 52		err := stakerStore.SetMinimumRewardAmount(0, rlm, defaultMinimumRewardAmount)
 53		if err != nil {
 54			return err
 55		}
 56	}
 57
 58	if !stakerStore.HasDepositsStoreKey() {
 59		err := stakerStore.SetDeposits(0, rlm, sr.NewBPTreeN(16))
 60		if err != nil {
 61			return err
 62		}
 63	}
 64
 65	if !stakerStore.HasExternalIncentivesStoreKey() {
 66		err := stakerStore.SetExternalIncentives(0, rlm, sr.NewBPTreeN(16))
 67		if err != nil {
 68			return err
 69		}
 70	}
 71
 72	if !stakerStore.HasTotalEmissionSentStoreKey() {
 73		err := stakerStore.SetTotalEmissionSent(0, rlm, 0)
 74		if err != nil {
 75			return err
 76		}
 77	}
 78
 79	if !stakerStore.HasAllowedTokensStoreKey() {
 80		// Copy the package-level default slice so each store owns its own
 81		// allowed-tokens slice. Storing sr.DefaultAllowedTokens directly would
 82		// alias the shared (sr-owned) slice across every store, leaking
 83		// mutations and tripping the readonly-taint gate on later writes.
 84		err := stakerStore.SetAllowedTokens(0, rlm, sr.DefaultAllowedTokens())
 85		if err != nil {
 86			return err
 87		}
 88	}
 89
 90	if !stakerStore.HasIncentiveCounterStoreKey() {
 91		err := stakerStore.SetIncentiveCounter(0, rlm, sr.NewCounter())
 92		if err != nil {
 93			return err
 94		}
 95	}
 96
 97	if !stakerStore.HasTokenSpecificMinimumRewardsStoreKey() {
 98		err := stakerStore.SetTokenSpecificMinimumRewards(0, rlm, make(map[string]int64))
 99		if err != nil {
100			return err
101		}
102	}
103
104	if !stakerStore.HasUnstakingFeeStoreKey() {
105		err := stakerStore.SetUnstakingFee(0, rlm, defaultUnstakingFee)
106		if err != nil {
107			return err
108		}
109	}
110
111	pendingProtocolFees := make(map[string]int64)
112	if stakerStore.HasPendingProtocolFeesStoreKey() {
113		pendingProtocolFees = stakerStore.GetPendingProtocolFees()
114	}
115	if err := stakerStore.SetPendingProtocolFees(0, rlm, pendingProtocolFees); err != nil {
116		return err
117	}
118
119	if !stakerStore.HasUnstakedPositionsStoreKey() {
120		err := stakerStore.SetUnstakedPositions(0, rlm, sr.NewBPTreeN(16))
121		if err != nil {
122			return err
123		}
124	}
125
126	if !stakerStore.HasUncollectedIncentiveCountsStoreKey() {
127		err := stakerStore.SetUncollectedIncentiveCounts(0, rlm, sr.NewBPTreeN(16))
128		if err != nil {
129			return err
130		}
131	}
132
133	if !stakerStore.HasWarmupTemplateStoreKey() {
134		err := stakerStore.SetWarmupTemplate(0, rlm, sr.DefaultWarmupTemplate())
135		if err != nil {
136			return err
137		}
138	}
139
140	initializedPoolTier, initializedPools, initialPoolTierTime, initialTierRewards := initializePoolTier(stakerStore)
141
142	previousRealm := rlm.Previous()
143	emitSetPoolTier(
144		previousRealm.Address().String(),
145		previousRealm.PkgPath(),
146		emission.DefaultInitialPoolTierPath,
147		uint64(Tier1),
148		initializedPoolTier.currentEmission,
149		initialTierRewards,
150		initializedPoolTier.counts,
151		initialPoolTierTime,
152	)
153
154	if !stakerStore.HasPoolsStoreKey() {
155		err := stakerStore.SetPools(0, rlm, initializedPools.tree)
156		if err != nil {
157			return err
158		}
159	}
160
161	if !stakerStore.HasPoolTierMembershipsStoreKey() {
162		err := stakerStore.SetPoolTierMemberships(0, rlm, initializedPoolTier.membership)
163		if err != nil {
164			return err
165		}
166	}
167
168	if !stakerStore.HasPoolTierRatioStoreKey() {
169		err := stakerStore.SetPoolTierRatio(0, rlm, initializedPoolTier.tierRatio)
170		if err != nil {
171			return err
172		}
173	}
174
175	if !stakerStore.HasPoolTierCountsStoreKey() {
176		err := stakerStore.SetPoolTierCounts(0, rlm, initializedPoolTier.counts)
177		if err != nil {
178			return err
179		}
180	}
181
182	if !stakerStore.HasPoolTierLastRewardCacheTimestampStoreKey() {
183		err := stakerStore.SetPoolTierLastRewardCacheTimestamp(0, rlm, initializedPoolTier.lastRewardCacheTimestamp)
184		if err != nil {
185			return err
186		}
187	}
188
189	if !stakerStore.HasPoolTierCurrentEmissionStoreKey() {
190		err := stakerStore.SetPoolTierCurrentEmission(0, rlm, initializedPoolTier.currentEmission)
191		if err != nil {
192			return err
193		}
194	}
195
196	if !stakerStore.HasPoolTierGetEmissionStoreKey() {
197		getEmissionFn := func() (int64, error) {
198			return emissionAccessor.GetStakerEmissionAmountPerSecond()
199		}
200
201		err := stakerStore.SetPoolTierGetEmission(0, rlm, getEmissionFn)
202		if err != nil {
203			return err
204		}
205	}
206
207	if !stakerStore.HasPoolTierGetHalvingBlocksInRangeStoreKey() {
208		getHalvingBlocksInRangeFn := func(start, end int64) ([]int64, []int64, error) {
209			return emissionAccessor.GetStakerEmissionAmountPerSecondInRange(start, end)
210		}
211
212		err := stakerStore.SetPoolTierGetHalvingBlocksInRange(0, rlm, getHalvingBlocksInRangeFn)
213		if err != nil {
214			return err
215		}
216	}
217
218	if !stakerStore.HasCurrentSwapBatchStoreKey() {
219		err := stakerStore.SetCurrentSwapBatch(0, rlm, nil)
220		if err != nil {
221			return err
222		}
223	}
224
225	return nil
226}
227
228// initializePoolTier seeds the staker's pool tiering state on first init.
229//
230// The default pool is the canonical WUGNOT:GNS:3000 pool, sourced from the
231// emission realm's DefaultInitialPoolTierPath constant so that the staker's
232// tier-1 base pool is guaranteed to match the pool emission distributes to.
233//
234// When SetDistributionStartTime executes, emission distributes to this default
235// pool and the staker uses the same path as the base tier-1 pool for reward
236// accrual. Keeping both sides on emission's single constant structurally
237// enforces that invariant and removes any risk of the two realms drifting
238// apart on the canonical default pool identity.
239func initializePoolTier(stakerStore sr.IStakerStore) (*PoolTier, *Pools, int64, map[uint64]int64) {
240	pools := NewPools()
241	currentTime := time.Now().Unix()
242
243	pl := NewPools().GetPoolOrNil(emission.DefaultInitialPoolTierPath)
244	if pl == nil {
245		pl = sr.NewPool(emission.DefaultInitialPoolTierPath, currentTime)
246		pools.set(emission.DefaultInitialPoolTierPath, pl)
247	}
248
249	poolTier := NewPoolTier(
250		pools,
251		currentTime,
252		emission.DefaultInitialPoolTierPath,
253		emission.GetStakerEmissionAmountPerSecond,
254		emission.GetStakerEmissionAmountPerSecondInRange,
255	)
256
257	return poolTier, pools, currentTime, poolTier.computeTierRewards(poolTier.currentEmission)
258}