store.gno
17.74 Kb · 677 lines
1package staker
2
3import (
4 "errors"
5 "gno.land/p/gnoswap/store"
6 bptree "gno.land/p/nt/bptree/v0"
7 ufmt "gno.land/p/nt/ufmt/v0"
8)
9
10type StoreKey string
11
12func (s StoreKey) String() string {
13 return string(s)
14}
15
16const (
17 StoreKeyDepositGnsAmount StoreKey = "depositGnsAmount"
18 StoreKeyMinimumRewardAmount StoreKey = "minimumRewardAmount"
19 StoreKeyDeposits StoreKey = "deposits"
20 StoreKeyExternalIncentives StoreKey = "externalIncentives"
21 StoreKeyTotalEmissionSent StoreKey = "totalEmissionSent"
22 StoreKeyAllowedTokens StoreKey = "allowedTokens"
23 StoreKeyIncentiveCounter StoreKey = "incentiveCounter"
24 StoreKeyTokenSpecificMinimumRewards StoreKey = "tokenSpecificMinimumRewards"
25 StoreKeyUnstakingFee StoreKey = "unstakingFee"
26 StoreKeyPendingProtocolFees StoreKey = "pendingProtocolFees"
27 StoreKeyPools StoreKey = "pools"
28 StoreKeyPoolTierMemberships StoreKey = "poolTierMemberships"
29 StoreKeyPoolTierRatio StoreKey = "poolTierRatio"
30 StoreKeyPoolTierCounts StoreKey = "poolTierCounts"
31 StoreKeyPoolTierLastRewardCacheTimestamp StoreKey = "poolTierLastRewardCacheTimestamp"
32 StoreKeyPoolTierCurrentEmission StoreKey = "poolTierCurrentEmission"
33 StoreKeyPoolTierGetEmission StoreKey = "poolTierGetEmission"
34 StoreKeyPoolTierGetHalvingBlocksInRange StoreKey = "poolTierGetHalvingBlocksInRange"
35 StoreKeyWarmupTemplate StoreKey = "warmupTemplate"
36 StoreKeyCurrentSwapBatch StoreKey = "currentSwapBatch"
37)
38
39type stakerStore struct {
40 kvStore store.KVStore
41}
42
43// DepositGnsAmount
44func (s *stakerStore) HasDepositGnsAmountStoreKey() bool {
45 return s.kvStore.Has(StoreKeyDepositGnsAmount.String())
46}
47
48func (s *stakerStore) GetDepositGnsAmount() int64 {
49 result, err := s.kvStore.Get(StoreKeyDepositGnsAmount.String())
50 if err != nil {
51 panic(err)
52 }
53
54 amount, ok := result.(int64)
55 if !ok {
56 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
57 }
58
59 return amount
60}
61
62func (s *stakerStore) SetDepositGnsAmount(_ int, rlm realm, amount int64) error {
63 if !rlm.IsCurrent() {
64 return errors.New(ErrSpoofedRealm)
65 }
66
67 return s.kvStore.Set(0, rlm, StoreKeyDepositGnsAmount.String(), amount)
68}
69
70// MinimumRewardAmount
71func (s *stakerStore) HasMinimumRewardAmountStoreKey() bool {
72 return s.kvStore.Has(StoreKeyMinimumRewardAmount.String())
73}
74
75func (s *stakerStore) GetMinimumRewardAmount() int64 {
76 result, err := s.kvStore.Get(StoreKeyMinimumRewardAmount.String())
77 if err != nil {
78 panic(err)
79 }
80
81 amount, ok := result.(int64)
82 if !ok {
83 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
84 }
85
86 return amount
87}
88
89func (s *stakerStore) SetMinimumRewardAmount(_ int, rlm realm, amount int64) error {
90 if !rlm.IsCurrent() {
91 return errors.New(ErrSpoofedRealm)
92 }
93
94 return s.kvStore.Set(0, rlm, StoreKeyMinimumRewardAmount.String(), amount)
95}
96
97// Deposits
98func (s *stakerStore) HasDepositsStoreKey() bool {
99 return s.kvStore.Has(StoreKeyDeposits.String())
100}
101
102func (s *stakerStore) GetDeposits() *bptree.BPTree {
103 result, err := s.kvStore.Get(StoreKeyDeposits.String())
104 if err != nil {
105 panic(err)
106 }
107
108 deposits, ok := result.(*bptree.BPTree)
109 if !ok {
110 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
111 }
112
113 return deposits
114}
115
116func (s *stakerStore) SetDeposits(_ int, rlm realm, deposits *bptree.BPTree) error {
117 if !rlm.IsCurrent() {
118 return errors.New(ErrSpoofedRealm)
119 }
120
121 return s.kvStore.Set(0, rlm, StoreKeyDeposits.String(), deposits)
122}
123
124// ExternalIncentives
125func (s *stakerStore) HasExternalIncentivesStoreKey() bool {
126 return s.kvStore.Has(StoreKeyExternalIncentives.String())
127}
128
129func (s *stakerStore) GetExternalIncentives() *bptree.BPTree {
130 result, err := s.kvStore.Get(StoreKeyExternalIncentives.String())
131 if err != nil {
132 panic(err)
133 }
134
135 incentives, ok := result.(*bptree.BPTree)
136 if !ok {
137 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
138 }
139
140 return incentives
141}
142
143func (s *stakerStore) SetExternalIncentives(_ int, rlm realm, incentives *bptree.BPTree) error {
144 if !rlm.IsCurrent() {
145 return errors.New(ErrSpoofedRealm)
146 }
147
148 return s.kvStore.Set(0, rlm, StoreKeyExternalIncentives.String(), incentives)
149}
150
151// TotalEmissionSent
152func (s *stakerStore) HasTotalEmissionSentStoreKey() bool {
153 return s.kvStore.Has(StoreKeyTotalEmissionSent.String())
154}
155
156func (s *stakerStore) GetTotalEmissionSent() int64 {
157 result, err := s.kvStore.Get(StoreKeyTotalEmissionSent.String())
158 if err != nil {
159 panic(err)
160 }
161
162 amount, ok := result.(int64)
163 if !ok {
164 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
165 }
166
167 return amount
168}
169
170func (s *stakerStore) SetTotalEmissionSent(_ int, rlm realm, amount int64) error {
171 if !rlm.IsCurrent() {
172 return errors.New(ErrSpoofedRealm)
173 }
174
175 return s.kvStore.Set(0, rlm, StoreKeyTotalEmissionSent.String(), amount)
176}
177
178// AllowedTokens
179func (s *stakerStore) HasAllowedTokensStoreKey() bool {
180 return s.kvStore.Has(StoreKeyAllowedTokens.String())
181}
182
183func (s *stakerStore) GetAllowedTokens() []string {
184 result, err := s.kvStore.Get(StoreKeyAllowedTokens.String())
185 if err != nil {
186 panic(err)
187 }
188
189 tokens, ok := result.([]string)
190 if !ok {
191 panic(ufmt.Sprintf("failed to cast result to []string: %T", result))
192 }
193
194 return cloneStringSlice(tokens)
195}
196
197func (s *stakerStore) SetAllowedTokens(_ int, rlm realm, tokens []string) error {
198 if !rlm.IsCurrent() {
199 return errors.New(ErrSpoofedRealm)
200 }
201
202 return s.kvStore.Set(0, rlm, StoreKeyAllowedTokens.String(), tokens)
203}
204
205// AddAllowedToken appends tokenPath to the allowed-tokens list when absent.
206// The store-owned slice is cloned before mutation to avoid readonly-taint panics.
207func (s *stakerStore) AddAllowedToken(_ int, rlm realm, tokenPath string) error {
208 if !rlm.IsCurrent() {
209 return errors.New(ErrSpoofedRealm)
210 }
211
212 tokens := s.GetAllowedTokens()
213 if !contains(tokens, tokenPath) {
214 tokens = append(tokens, tokenPath)
215 }
216
217 return s.kvStore.Set(0, rlm, StoreKeyAllowedTokens.String(), tokens)
218}
219
220// RemoveAllowedToken removes tokenPath from the allowed-tokens list when present.
221// The store-owned slice is cloned before mutation to avoid readonly-taint panics.
222func (s *stakerStore) RemoveAllowedToken(_ int, rlm realm, tokenPath string) error {
223 if !rlm.IsCurrent() {
224 return errors.New(ErrSpoofedRealm)
225 }
226
227 tokens := s.GetAllowedTokens()
228 for i, t := range tokens {
229 if t == tokenPath {
230 tokens = append(tokens[:i], tokens[i+1:]...)
231 break
232 }
233 }
234
235 return s.kvStore.Set(0, rlm, StoreKeyAllowedTokens.String(), tokens)
236}
237
238// IncentiveCounter
239func (s *stakerStore) HasIncentiveCounterStoreKey() bool {
240 return s.kvStore.Has(StoreKeyIncentiveCounter.String())
241}
242
243func (s *stakerStore) GetIncentiveCounter() *Counter {
244 result, err := s.kvStore.Get(StoreKeyIncentiveCounter.String())
245 if err != nil {
246 panic(err)
247 }
248
249 counter, ok := result.(*Counter)
250 if !ok {
251 panic(ufmt.Sprintf("failed to cast result to *Counter: %T", result))
252 }
253
254 return counter
255}
256
257func (s *stakerStore) SetIncentiveCounter(_ int, rlm realm, counter *Counter) error {
258 if !rlm.IsCurrent() {
259 return errors.New(ErrSpoofedRealm)
260 }
261
262 return s.kvStore.Set(0, rlm, StoreKeyIncentiveCounter.String(), counter)
263}
264
265func (s *stakerStore) NextIncentiveID(creator address, timestamp int64) string {
266 counter := s.GetIncentiveCounter()
267 return makeIncentiveID(creator, timestamp, counter.Next())
268}
269
270// TokenSpecificMinimumRewards
271func (s *stakerStore) HasTokenSpecificMinimumRewardsStoreKey() bool {
272 return s.kvStore.Has(StoreKeyTokenSpecificMinimumRewards.String())
273}
274
275func (s *stakerStore) GetTokenSpecificMinimumRewards() map[string]int64 {
276 result, err := s.kvStore.Get(StoreKeyTokenSpecificMinimumRewards.String())
277 if err != nil {
278 panic(err)
279 }
280
281 rewards, ok := result.(map[string]int64)
282 if !ok {
283 panic(ufmt.Sprintf("failed to cast result to map[string]int64: %T", result))
284 }
285
286 return rewards
287}
288
289func (s *stakerStore) SetTokenSpecificMinimumRewards(_ int, rlm realm, rewards map[string]int64) error {
290 if !rlm.IsCurrent() {
291 return errors.New(ErrSpoofedRealm)
292 }
293
294 return s.kvStore.Set(0, rlm, StoreKeyTokenSpecificMinimumRewards.String(), rewards)
295}
296
297// SetTokenSpecificMinimumRewardItem sets a single token's minimum reward amount.
298func (s *stakerStore) SetTokenSpecificMinimumRewardItem(_ int, rlm realm, tokenPath string, amount int64) error {
299 if !rlm.IsCurrent() {
300 return errors.New(ErrSpoofedRealm)
301 }
302
303 rewards := s.GetTokenSpecificMinimumRewards()
304
305 owned := make(map[string]int64)
306 for k, v := range rewards {
307 owned[k] = v
308 }
309
310 owned[tokenPath] = amount
311
312 return s.kvStore.Set(0, rlm, StoreKeyTokenSpecificMinimumRewards.String(), owned)
313}
314
315// RemoveTokenSpecificMinimumRewardItem removes a single token's minimum reward entry.
316func (s *stakerStore) RemoveTokenSpecificMinimumRewardItem(_ int, rlm realm, tokenPath string) error {
317 if !rlm.IsCurrent() {
318 return errors.New(ErrSpoofedRealm)
319 }
320
321 rewards := s.GetTokenSpecificMinimumRewards()
322
323 owned := make(map[string]int64)
324 for k, v := range rewards {
325 if k == tokenPath {
326 continue
327 }
328
329 owned[k] = v
330 }
331
332 return s.kvStore.Set(0, rlm, StoreKeyTokenSpecificMinimumRewards.String(), owned)
333}
334
335// UnstakingFee
336func (s *stakerStore) HasUnstakingFeeStoreKey() bool {
337 return s.kvStore.Has(StoreKeyUnstakingFee.String())
338}
339
340func (s *stakerStore) GetUnstakingFee() uint64 {
341 result, err := s.kvStore.Get(StoreKeyUnstakingFee.String())
342 if err != nil {
343 panic(err)
344 }
345
346 fee, ok := result.(uint64)
347 if !ok {
348 panic(ufmt.Sprintf("failed to cast result to uint64: %T", result))
349 }
350
351 return fee
352}
353
354func (s *stakerStore) SetUnstakingFee(_ int, rlm realm, fee uint64) error {
355 if !rlm.IsCurrent() {
356 return errors.New(ErrSpoofedRealm)
357 }
358
359 return s.kvStore.Set(0, rlm, StoreKeyUnstakingFee.String(), fee)
360}
361
362func (s *stakerStore) HasPendingProtocolFeesStoreKey() bool {
363 return s.kvStore.Has(StoreKeyPendingProtocolFees.String())
364}
365
366func (s *stakerStore) GetPendingProtocolFees() map[string]int64 {
367 result, err := s.kvStore.Get(StoreKeyPendingProtocolFees.String())
368 if err != nil {
369 panic(err)
370 }
371
372 fees, ok := result.(map[string]int64)
373 if !ok {
374 panic(ufmt.Sprintf("failed to cast result to map[string]int64: %T", result))
375 }
376
377 return fees
378}
379
380func (s *stakerStore) SetPendingProtocolFees(_ int, rlm realm, fees map[string]int64) error {
381 if !rlm.IsCurrent() {
382 return errors.New(ErrSpoofedRealm)
383 }
384
385 return s.kvStore.Set(0, rlm, StoreKeyPendingProtocolFees.String(), fees)
386}
387
388// Pools
389func (s *stakerStore) HasPoolsStoreKey() bool {
390 return s.kvStore.Has(StoreKeyPools.String())
391}
392
393func (s *stakerStore) GetPools() *bptree.BPTree {
394 result, err := s.kvStore.Get(StoreKeyPools.String())
395 if err != nil {
396 panic(err)
397 }
398
399 pools, ok := result.(*bptree.BPTree)
400 if !ok {
401 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
402 }
403
404 return pools
405}
406
407func (s *stakerStore) SetPools(_ int, rlm realm, pools *bptree.BPTree) error {
408 if !rlm.IsCurrent() {
409 return errors.New(ErrSpoofedRealm)
410 }
411
412 return s.kvStore.Set(0, rlm, StoreKeyPools.String(), pools)
413}
414
415// PoolTierMemberships
416func (s *stakerStore) HasPoolTierMembershipsStoreKey() bool {
417 return s.kvStore.Has(StoreKeyPoolTierMemberships.String())
418}
419
420func (s *stakerStore) GetPoolTierMemberships() *bptree.BPTree {
421 result, err := s.kvStore.Get(StoreKeyPoolTierMemberships.String())
422 if err != nil {
423 panic(err)
424 }
425
426 memberships, ok := result.(*bptree.BPTree)
427 if !ok {
428 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
429 }
430
431 return memberships
432}
433
434func (s *stakerStore) SetPoolTierMemberships(_ int, rlm realm, memberships *bptree.BPTree) error {
435 if !rlm.IsCurrent() {
436 return errors.New(ErrSpoofedRealm)
437 }
438
439 return s.kvStore.Set(0, rlm, StoreKeyPoolTierMemberships.String(), memberships)
440}
441
442// PoolTierRatio
443func (s *stakerStore) HasPoolTierRatioStoreKey() bool {
444 return s.kvStore.Has(StoreKeyPoolTierRatio.String())
445}
446
447func (s *stakerStore) GetPoolTierRatio() TierRatio {
448 result, err := s.kvStore.Get(StoreKeyPoolTierRatio.String())
449 if err != nil {
450 panic(err)
451 }
452
453 ratio, ok := result.(TierRatio)
454 if !ok {
455 panic(ufmt.Sprintf("failed to cast result to TierRatio: %T", result))
456 }
457
458 return ratio
459}
460
461func (s *stakerStore) SetPoolTierRatio(_ int, rlm realm, ratio TierRatio) error {
462 if !rlm.IsCurrent() {
463 return errors.New(ErrSpoofedRealm)
464 }
465
466 return s.kvStore.Set(0, rlm, StoreKeyPoolTierRatio.String(), ratio)
467}
468
469// PoolTierCounts
470func (s *stakerStore) HasPoolTierCountsStoreKey() bool {
471 return s.kvStore.Has(StoreKeyPoolTierCounts.String())
472}
473
474func (s *stakerStore) GetPoolTierCounts() [AllTierCount]uint64 {
475 result, err := s.kvStore.Get(StoreKeyPoolTierCounts.String())
476 if err != nil {
477 panic(err)
478 }
479
480 counts, ok := result.([AllTierCount]uint64)
481 if !ok {
482 panic(ufmt.Sprintf("failed to cast result to [AllTierCount]uint64: %T", result))
483 }
484
485 return counts
486}
487
488func (s *stakerStore) SetPoolTierCounts(_ int, rlm realm, counts [AllTierCount]uint64) error {
489 if !rlm.IsCurrent() {
490 return errors.New(ErrSpoofedRealm)
491 }
492
493 return s.kvStore.Set(0, rlm, StoreKeyPoolTierCounts.String(), counts)
494}
495
496// PoolTierLastRewardCacheTimestamp
497func (s *stakerStore) HasPoolTierLastRewardCacheTimestampStoreKey() bool {
498 return s.kvStore.Has(StoreKeyPoolTierLastRewardCacheTimestamp.String())
499}
500
501func (s *stakerStore) GetPoolTierLastRewardCacheTimestamp() int64 {
502 result, err := s.kvStore.Get(StoreKeyPoolTierLastRewardCacheTimestamp.String())
503 if err != nil {
504 panic(err)
505 }
506
507 timestamp, ok := result.(int64)
508 if !ok {
509 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
510 }
511
512 return timestamp
513}
514
515func (s *stakerStore) SetPoolTierLastRewardCacheTimestamp(_ int, rlm realm, timestamp int64) error {
516 if !rlm.IsCurrent() {
517 return errors.New(ErrSpoofedRealm)
518 }
519
520 return s.kvStore.Set(0, rlm, StoreKeyPoolTierLastRewardCacheTimestamp.String(), timestamp)
521}
522
523// PoolTierCurrentEmission
524func (s *stakerStore) HasPoolTierCurrentEmissionStoreKey() bool {
525 return s.kvStore.Has(StoreKeyPoolTierCurrentEmission.String())
526}
527
528func (s *stakerStore) GetPoolTierCurrentEmission() int64 {
529 result, err := s.kvStore.Get(StoreKeyPoolTierCurrentEmission.String())
530 if err != nil {
531 panic(err)
532 }
533
534 emission, ok := result.(int64)
535 if !ok {
536 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
537 }
538
539 return emission
540}
541
542func (s *stakerStore) SetPoolTierCurrentEmission(_ int, rlm realm, emission int64) error {
543 if !rlm.IsCurrent() {
544 return errors.New(ErrSpoofedRealm)
545 }
546
547 return s.kvStore.Set(0, rlm, StoreKeyPoolTierCurrentEmission.String(), emission)
548}
549
550// PoolTierGetEmission
551func (s *stakerStore) HasPoolTierGetEmissionStoreKey() bool {
552 return s.kvStore.Has(StoreKeyPoolTierGetEmission.String())
553}
554
555func (s *stakerStore) GetPoolTierGetEmission() func() int64 {
556 result, err := s.kvStore.Get(StoreKeyPoolTierGetEmission.String())
557 if err != nil {
558 panic(err)
559 }
560
561 fn, ok := result.(func() int64)
562 if !ok {
563 panic(ufmt.Sprintf("failed to cast result to func() int64: %T", result))
564 }
565
566 return fn
567}
568
569func (s *stakerStore) SetPoolTierGetEmission(_ int, rlm realm, fn func() int64) error {
570 if !rlm.IsCurrent() {
571 return errors.New(ErrSpoofedRealm)
572 }
573
574 return s.kvStore.Set(0, rlm, StoreKeyPoolTierGetEmission.String(), fn)
575}
576
577// PoolTierGetHalvingBlocksInRange
578func (s *stakerStore) HasPoolTierGetHalvingBlocksInRangeStoreKey() bool {
579 return s.kvStore.Has(StoreKeyPoolTierGetHalvingBlocksInRange.String())
580}
581
582func (s *stakerStore) GetPoolTierGetHalvingBlocksInRange() func(start, end int64) ([]int64, []int64) {
583 result, err := s.kvStore.Get(StoreKeyPoolTierGetHalvingBlocksInRange.String())
584 if err != nil {
585 panic(err)
586 }
587
588 fn, ok := result.(func(start, end int64) ([]int64, []int64))
589 if !ok {
590 panic(ufmt.Sprintf("failed to cast result to func(start, end int64) ([]int64, []int64): %T", result))
591 }
592
593 return fn
594}
595
596func (s *stakerStore) SetPoolTierGetHalvingBlocksInRange(_ int, rlm realm, fn func(start, end int64) ([]int64, []int64)) error {
597 if !rlm.IsCurrent() {
598 return errors.New(ErrSpoofedRealm)
599 }
600
601 return s.kvStore.Set(0, rlm, StoreKeyPoolTierGetHalvingBlocksInRange.String(), fn)
602}
603
604func (s *stakerStore) HasWarmupTemplateStoreKey() bool {
605 return s.kvStore.Has(StoreKeyWarmupTemplate.String())
606}
607
608func (s *stakerStore) GetWarmupTemplate() []Warmup {
609 result, err := s.kvStore.Get(StoreKeyWarmupTemplate.String())
610 if err != nil {
611 panic(err)
612 }
613
614 warmups, ok := result.([]Warmup)
615 if !ok {
616 panic(ufmt.Sprintf("failed to cast result to []Warmup: %T", result))
617 }
618
619 return cloneWarmups(warmups)
620}
621
622func (s *stakerStore) SetWarmupTemplate(_ int, rlm realm, warmups []Warmup) error {
623 if !rlm.IsCurrent() {
624 return errors.New(ErrSpoofedRealm)
625 }
626
627 return s.kvStore.Set(0, rlm, StoreKeyWarmupTemplate.String(), warmups)
628}
629
630// CurrentSwapBatch
631func (s *stakerStore) HasCurrentSwapBatchStoreKey() bool {
632 return s.kvStore.Has(StoreKeyCurrentSwapBatch.String())
633}
634
635func (s *stakerStore) GetCurrentSwapBatch() *SwapBatchProcessor {
636 result, err := s.kvStore.Get(StoreKeyCurrentSwapBatch.String())
637 if err != nil {
638 panic(err)
639 }
640
641 batch, ok := result.(*SwapBatchProcessor)
642 if !ok {
643 panic(ufmt.Sprintf("failed to cast result to *SwapBatchProcessor: %T", result))
644 }
645
646 return batch
647}
648
649func (s *stakerStore) SetCurrentSwapBatch(_ int, rlm realm, batch *SwapBatchProcessor) error {
650 if !rlm.IsCurrent() {
651 return errors.New(ErrSpoofedRealm)
652 }
653
654 return s.kvStore.Set(0, rlm, StoreKeyCurrentSwapBatch.String(), batch)
655}
656
657// NewStakerStore creates a new staker store instance with the provided KV store.
658// This function is used by the upgrade system to create storage instances for each implementation.
659func NewStakerStore(kvStore store.KVStore) IStakerStore {
660 return &stakerStore{
661 kvStore: kvStore,
662 }
663}
664
665func makeIncentiveID(creator address, timestamp int64, index int64) string {
666 return ufmt.Sprintf("%s:%d:%d", creator.String(), timestamp, index)
667}
668
669func contains(items []string, item string) bool {
670 for _, i := range items {
671 if i == item {
672 return true
673 }
674 }
675
676 return false
677}