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