store.gno
45.04 Kb · 1311 lines
1package staker
2
3import (
4 "errors"
5
6 "gno.land/p/gnoswap/store/v1"
7 bptree "gno.land/p/nt/bptree/v0"
8 ufmt "gno.land/p/nt/ufmt/v0"
9)
10
11type StoreKey string
12
13// StoreKey.String returns the textual key used by the KV store.
14//
15// Returns:
16// - string: Underlying storage-key text.
17func (s StoreKey) String() string {
18 return string(s)
19}
20
21const (
22 StoreKeyDepositGnsAmount StoreKey = "depositGnsAmount"
23 StoreKeyMinimumRewardAmount StoreKey = "minimumRewardAmount"
24 StoreKeyDeposits StoreKey = "deposits"
25 StoreKeyExternalIncentives StoreKey = "externalIncentives"
26 StoreKeyTotalEmissionSent StoreKey = "totalEmissionSent"
27 StoreKeyAllowedTokens StoreKey = "allowedTokens"
28 StoreKeyDeniedRewardTokens StoreKey = "deniedRewardTokens"
29 StoreKeyIncentiveCounter StoreKey = "incentiveCounter"
30 StoreKeyTokenSpecificMinimumRewards StoreKey = "tokenSpecificMinimumRewards"
31 StoreKeyUnstakingFee StoreKey = "unstakingFee"
32 StoreKeyPendingProtocolFees StoreKey = "pendingProtocolFees"
33 StoreKeyUnstakedPositions StoreKey = "unstakedPositions"
34 StoreKeyUncollectedIncentiveCounts StoreKey = "uncollectedIncentiveCounts"
35 StoreKeyPools StoreKey = "pools"
36 StoreKeyPoolTierMemberships StoreKey = "poolTierMemberships"
37 StoreKeyPoolTierRatio StoreKey = "poolTierRatio"
38 StoreKeyPoolTierCounts StoreKey = "poolTierCounts"
39 StoreKeyPoolTierLastRewardCacheTimestamp StoreKey = "poolTierLastRewardCacheTimestamp"
40 StoreKeyPoolTierCurrentEmission StoreKey = "poolTierCurrentEmission"
41 StoreKeyPoolTierGetEmission StoreKey = "poolTierGetEmission"
42 StoreKeyPoolTierGetHalvingBlocksInRange StoreKey = "poolTierGetHalvingBlocksInRange"
43 StoreKeyWarmupTemplate StoreKey = "warmupTemplate"
44 StoreKeyCurrentSwapBatch StoreKey = "currentSwapBatch"
45)
46
47type stakerStore struct {
48 kvStore store.KVStore
49}
50
51// DepositGnsAmount
52// HasDepositGnsAmountStoreKey reports whether the GNS reserve amount key exists.
53//
54// Returns:
55// - bool: True when a deposit GNS amount has been initialized in storage.
56func (s *stakerStore) HasDepositGnsAmountStoreKey() bool {
57 return s.kvStore.Has(StoreKeyDepositGnsAmount.String())
58}
59
60// GetDepositGnsAmount retrieves the GNS reserve amount deposited for the staker.
61//
62// Returns:
63// - int64: Stored GNS reserve amount; panics on read or type failure.
64func (s *stakerStore) GetDepositGnsAmount() int64 {
65 result, err := s.kvStore.Get(StoreKeyDepositGnsAmount.String())
66 if err != nil {
67 panic(err)
68 }
69
70 amount, ok := result.(int64)
71 if !ok {
72 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
73 }
74
75 return amount
76}
77
78// SetDepositGnsAmount stores the GNS amount deposited as the staker reserve.
79//
80// Parameters:
81// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
82// - rlm: Current staker realm context; it must be current before storage is written.
83// - amount: GNS reserve amount used for staker initialization and accounting.
84//
85// Returns:
86// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
87func (s *stakerStore) SetDepositGnsAmount(_ int, rlm realm, amount int64) error {
88 if !rlm.IsCurrent() {
89 return errors.New(ErrSpoofedRealm)
90 }
91
92 return s.kvStore.Set(0, rlm, StoreKeyDepositGnsAmount.String(), amount)
93}
94
95// MinimumRewardAmount
96// HasMinimumRewardAmountStoreKey reports whether the default minimum-reward key exists.
97//
98// Returns:
99// - bool: True when the default minimum reward amount has been initialized in storage.
100func (s *stakerStore) HasMinimumRewardAmountStoreKey() bool {
101 return s.kvStore.Has(StoreKeyMinimumRewardAmount.String())
102}
103
104// GetMinimumRewardAmount retrieves the default minimum external reward amount.
105//
106// Returns:
107// - int64: Stored default minimum reward amount; panics on read or type failure.
108func (s *stakerStore) GetMinimumRewardAmount() int64 {
109 result, err := s.kvStore.Get(StoreKeyMinimumRewardAmount.String())
110 if err != nil {
111 panic(err)
112 }
113
114 amount, ok := result.(int64)
115 if !ok {
116 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
117 }
118
119 return amount
120}
121
122// SetMinimumRewardAmount stores the default minimum external reward amount.
123//
124// Parameters:
125// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
126// - rlm: Current staker realm context; it must be current before storage is written.
127// - amount: Default minimum reward amount applied when no token-specific override exists.
128//
129// Returns:
130// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
131func (s *stakerStore) SetMinimumRewardAmount(_ int, rlm realm, amount int64) error {
132 if !rlm.IsCurrent() {
133 return errors.New(ErrSpoofedRealm)
134 }
135
136 return s.kvStore.Set(0, rlm, StoreKeyMinimumRewardAmount.String(), amount)
137}
138
139// Deposits
140// HasDepositsStoreKey reports whether the active-deposits key exists.
141//
142// Returns:
143// - bool: True when active deposits have been initialized in storage.
144func (s *stakerStore) HasDepositsStoreKey() bool {
145 return s.kvStore.Has(StoreKeyDeposits.String())
146}
147
148// GetDeposits retrieves the active deposit tree.
149//
150// Returns:
151// - *bptree.BPTree: Stored position-to-deposit records; panics on read or type failure.
152func (s *stakerStore) GetDeposits() *bptree.BPTree {
153 result, err := s.kvStore.Get(StoreKeyDeposits.String())
154 if err != nil {
155 panic(err)
156 }
157
158 deposits, ok := result.(*bptree.BPTree)
159 if !ok {
160 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
161 }
162
163 return deposits
164}
165
166// SetDeposits stores the deposit tree keyed by position identifier.
167//
168// Parameters:
169// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
170// - rlm: Current staker realm context; it must be current before storage is written.
171// - deposits: B+ tree containing active staking deposits.
172//
173// Returns:
174// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
175func (s *stakerStore) SetDeposits(_ int, rlm realm, deposits *bptree.BPTree) error {
176 if !rlm.IsCurrent() {
177 return errors.New(ErrSpoofedRealm)
178 }
179
180 return s.kvStore.Set(0, rlm, StoreKeyDeposits.String(), deposits)
181}
182
183// ExternalIncentives
184// HasExternalIncentivesStoreKey reports whether the external-incentives key exists.
185//
186// Returns:
187// - bool: True when external incentives have been initialized in storage.
188func (s *stakerStore) HasExternalIncentivesStoreKey() bool {
189 return s.kvStore.Has(StoreKeyExternalIncentives.String())
190}
191
192// GetExternalIncentives retrieves the external incentive tree.
193//
194// Returns:
195// - *bptree.BPTree: Stored external incentive records; panics on read or type failure.
196func (s *stakerStore) GetExternalIncentives() *bptree.BPTree {
197 result, err := s.kvStore.Get(StoreKeyExternalIncentives.String())
198 if err != nil {
199 panic(err)
200 }
201
202 incentives, ok := result.(*bptree.BPTree)
203 if !ok {
204 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
205 }
206
207 return incentives
208}
209
210// SetExternalIncentives stores the external incentive tree.
211//
212// Parameters:
213// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
214// - rlm: Current staker realm context; it must be current before storage is written.
215// - incentives: B+ tree mapping external incentive identifiers to incentive records.
216//
217// Returns:
218// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
219func (s *stakerStore) SetExternalIncentives(_ int, rlm realm, incentives *bptree.BPTree) error {
220 if !rlm.IsCurrent() {
221 return errors.New(ErrSpoofedRealm)
222 }
223
224 return s.kvStore.Set(0, rlm, StoreKeyExternalIncentives.String(), incentives)
225}
226
227// TotalEmissionSent
228// HasTotalEmissionSentStoreKey reports whether the total-emission-sent key exists.
229//
230// Returns:
231// - bool: True when cumulative sent emission has been initialized in storage.
232func (s *stakerStore) HasTotalEmissionSentStoreKey() bool {
233 return s.kvStore.Has(StoreKeyTotalEmissionSent.String())
234}
235
236// GetTotalEmissionSent retrieves the cumulative emission amount sent.
237//
238// Returns:
239// - int64: Stored cumulative emission amount; panics on read or type failure.
240func (s *stakerStore) GetTotalEmissionSent() int64 {
241 result, err := s.kvStore.Get(StoreKeyTotalEmissionSent.String())
242 if err != nil {
243 panic(err)
244 }
245
246 amount, ok := result.(int64)
247 if !ok {
248 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
249 }
250
251 return amount
252}
253
254// SetTotalEmissionSent stores the cumulative emission amount sent to staker pools.
255//
256// Parameters:
257// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
258// - rlm: Current staker realm context; it must be current before storage is written.
259// - amount: Cumulative emission amount already sent.
260//
261// Returns:
262// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
263func (s *stakerStore) SetTotalEmissionSent(_ int, rlm realm, amount int64) error {
264 if !rlm.IsCurrent() {
265 return errors.New(ErrSpoofedRealm)
266 }
267
268 return s.kvStore.Set(0, rlm, StoreKeyTotalEmissionSent.String(), amount)
269}
270
271// AllowedTokens
272// HasAllowedTokensStoreKey reports whether the allowed-token key exists.
273//
274// Returns:
275// - bool: True when the allowed external-reward token list has been initialized in storage.
276func (s *stakerStore) HasAllowedTokensStoreKey() bool {
277 return s.kvStore.Has(StoreKeyAllowedTokens.String())
278}
279
280// GetAllowedTokens retrieves a clone of the allowed external-reward token list.
281//
282// Returns:
283// - []string: Allowed token paths copied for the caller; panics on read or type failure.
284func (s *stakerStore) GetAllowedTokens() []string {
285 result, err := s.kvStore.Get(StoreKeyAllowedTokens.String())
286 if err != nil {
287 panic(err)
288 }
289
290 tokens, ok := result.([]string)
291 if !ok {
292 panic(ufmt.Sprintf("failed to cast result to []string: %T", result))
293 }
294
295 return cloneStringSlice(tokens)
296}
297
298// SetAllowedTokens replaces the allowed external-reward token list.
299//
300// Parameters:
301// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
302// - rlm: Current staker realm context; it must be current before storage is written.
303// - tokens: Registered token paths permitted as external reward tokens.
304//
305// Returns:
306// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
307func (s *stakerStore) SetAllowedTokens(_ int, rlm realm, tokens []string) error {
308 if !rlm.IsCurrent() {
309 return errors.New(ErrSpoofedRealm)
310 }
311
312 return s.kvStore.Set(0, rlm, StoreKeyAllowedTokens.String(), tokens)
313}
314
315// AddAllowedToken appends tokenPath to the allowed-tokens list when absent.
316// The store-owned slice is cloned before mutation to avoid readonly-taint panics.
317//
318// Parameters:
319// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
320// - rlm: Current staker realm context; it must be current before storage is written.
321// - tokenPath: Registered token path to add to the allowed-token list.
322//
323// Returns:
324// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
325func (s *stakerStore) AddAllowedToken(_ int, rlm realm, tokenPath string) error {
326 if !rlm.IsCurrent() {
327 return errors.New(ErrSpoofedRealm)
328 }
329
330 tokens := s.GetAllowedTokens()
331 if !contains(tokens, tokenPath) {
332 tokens = append(tokens, tokenPath)
333 }
334
335 return s.kvStore.Set(0, rlm, StoreKeyAllowedTokens.String(), tokens)
336}
337
338// RemoveAllowedToken removes tokenPath from the allowed-tokens list when present.
339// The store-owned slice is cloned before mutation to avoid readonly-taint panics.
340//
341// Parameters:
342// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
343// - rlm: Current staker realm context; it must be current before storage is written.
344// - tokenPath: Registered token path to remove from the allowed-token list.
345//
346// Returns:
347// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
348func (s *stakerStore) RemoveAllowedToken(_ int, rlm realm, tokenPath string) error {
349 if !rlm.IsCurrent() {
350 return errors.New(ErrSpoofedRealm)
351 }
352
353 tokens := s.GetAllowedTokens()
354 for i, t := range tokens {
355 if t == tokenPath {
356 tokens = append(tokens[:i], tokens[i+1:]...)
357 break
358 }
359 }
360
361 return s.kvStore.Set(0, rlm, StoreKeyAllowedTokens.String(), tokens)
362}
363
364// DeniedRewardTokens
365//
366// The deny list is the operational stop switch for the pool-pair reward-token
367// policy: pair tokens qualify as external-incentive reward tokens without going
368// through the governance allowlist (by design), so without this list there is
369// no lever to stop NEW incentives in a pair token whose issuer turned hostile.
370// A missing store key means an empty list, so no initializer seeding and no
371// upgrade migration are needed.
372// HasDeniedRewardTokensStoreKey reports whether the denied-reward-token key exists.
373//
374// Returns:
375// - bool: True when a denied-reward list has been initialized in storage.
376func (s *stakerStore) HasDeniedRewardTokensStoreKey() bool {
377 return s.kvStore.Has(StoreKeyDeniedRewardTokens.String())
378}
379
380// GetDeniedRewardTokens retrieves the denied-reward list, treating a missing key as empty.
381//
382// Returns:
383// - []string: Clone of denied reward-token paths; empty when the key is absent, and panics on read or type failure.
384func (s *stakerStore) GetDeniedRewardTokens() []string {
385 if !s.kvStore.Has(StoreKeyDeniedRewardTokens.String()) {
386 return []string{}
387 }
388
389 result, err := s.kvStore.Get(StoreKeyDeniedRewardTokens.String())
390 if err != nil {
391 panic(err)
392 }
393
394 tokens, ok := result.([]string)
395 if !ok {
396 panic(ufmt.Sprintf("failed to cast result to []string: %T", result))
397 }
398
399 return cloneStringSlice(tokens)
400}
401
402// AddDeniedRewardToken appends tokenPath to the denied-reward-tokens list when absent.
403// The store-owned slice is cloned before mutation to avoid readonly-taint panics.
404//
405// Parameters:
406// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
407// - rlm: Current staker realm context; it must be current before storage is written.
408// - tokenPath: Reward-token path to block for new external incentives.
409//
410// Returns:
411// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
412func (s *stakerStore) AddDeniedRewardToken(_ int, rlm realm, tokenPath string) error {
413 if !rlm.IsCurrent() {
414 return errors.New(ErrSpoofedRealm)
415 }
416
417 tokens := s.GetDeniedRewardTokens()
418 if !contains(tokens, tokenPath) {
419 tokens = append(tokens, tokenPath)
420 }
421
422 return s.kvStore.Set(0, rlm, StoreKeyDeniedRewardTokens.String(), tokens)
423}
424
425// RemoveDeniedRewardToken removes tokenPath from the denied-reward-tokens list when present.
426// The store-owned slice is cloned before mutation to avoid readonly-taint panics.
427//
428// Parameters:
429// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
430// - rlm: Current staker realm context; it must be current before storage is written.
431// - tokenPath: Reward-token path to remove from the deny list.
432//
433// Returns:
434// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
435func (s *stakerStore) RemoveDeniedRewardToken(_ int, rlm realm, tokenPath string) error {
436 if !rlm.IsCurrent() {
437 return errors.New(ErrSpoofedRealm)
438 }
439
440 tokens := s.GetDeniedRewardTokens()
441 for i, t := range tokens {
442 if t == tokenPath {
443 tokens = append(tokens[:i], tokens[i+1:]...)
444 break
445 }
446 }
447
448 return s.kvStore.Set(0, rlm, StoreKeyDeniedRewardTokens.String(), tokens)
449}
450
451// IncentiveCounter
452// HasIncentiveCounterStoreKey reports whether the incentive-counter key exists.
453//
454// Returns:
455// - bool: True when an incentive counter has been initialized in storage.
456func (s *stakerStore) HasIncentiveCounterStoreKey() bool {
457 return s.kvStore.Has(StoreKeyIncentiveCounter.String())
458}
459
460// GetIncentiveCounter retrieves the persistent incentive identifier counter.
461//
462// Returns:
463// - *Counter: Stored counter state; panics on read or type failure.
464func (s *stakerStore) GetIncentiveCounter() *Counter {
465 result, err := s.kvStore.Get(StoreKeyIncentiveCounter.String())
466 if err != nil {
467 panic(err)
468 }
469
470 counter, ok := result.(*Counter)
471 if !ok {
472 panic(ufmt.Sprintf("failed to cast result to *Counter: %T", result))
473 }
474
475 return counter
476}
477
478// SetIncentiveCounter stores the counter used to allocate incentive identifiers.
479//
480// Parameters:
481// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
482// - rlm: Current staker realm context; it must be current before storage is written.
483// - counter: Counter state whose next value is used by NextIncentiveID.
484//
485// Returns:
486// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
487func (s *stakerStore) SetIncentiveCounter(_ int, rlm realm, counter *Counter) error {
488 if !rlm.IsCurrent() {
489 return errors.New(ErrSpoofedRealm)
490 }
491
492 return s.kvStore.Set(0, rlm, StoreKeyIncentiveCounter.String(), counter)
493}
494
495// NextIncentiveID advances the stored counter and builds a unique incentive identifier.
496//
497// Parameters:
498// - creator: Address that created the incentive.
499// - timestamp: Incentive start or creation timestamp included in the identifier.
500//
501// Returns:
502// - string: Identifier combining creator, timestamp, and the next counter index.
503func (s *stakerStore) NextIncentiveID(creator address, timestamp int64) string {
504 counter := s.GetIncentiveCounter()
505 return makeIncentiveID(creator, timestamp, counter.Next())
506}
507
508// TokenSpecificMinimumRewards
509// HasTokenSpecificMinimumRewardsStoreKey reports whether the token-specific minimum-rewards key exists.
510//
511// Returns:
512// - bool: True when token-specific minimum rewards have been initialized in storage.
513func (s *stakerStore) HasTokenSpecificMinimumRewardsStoreKey() bool {
514 return s.kvStore.Has(StoreKeyTokenSpecificMinimumRewards.String())
515}
516
517// GetTokenSpecificMinimumRewards retrieves per-token minimum reward amounts.
518//
519// Returns:
520// - map[string]int64: Stored minimum reward overrides keyed by token path; panics on read or type failure.
521func (s *stakerStore) GetTokenSpecificMinimumRewards() map[string]int64 {
522 result, err := s.kvStore.Get(StoreKeyTokenSpecificMinimumRewards.String())
523 if err != nil {
524 panic(err)
525 }
526
527 rewards, ok := result.(map[string]int64)
528 if !ok {
529 panic(ufmt.Sprintf("failed to cast result to map[string]int64: %T", result))
530 }
531
532 return rewards
533}
534
535// SetTokenSpecificMinimumRewards replaces the token-specific minimum reward map.
536//
537// Parameters:
538// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
539// - rlm: Current staker realm context; it must be current before storage is written.
540// - rewards: Minimum reward amounts keyed by token path.
541//
542// Returns:
543// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
544func (s *stakerStore) SetTokenSpecificMinimumRewards(_ int, rlm realm, rewards map[string]int64) error {
545 if !rlm.IsCurrent() {
546 return errors.New(ErrSpoofedRealm)
547 }
548
549 return s.kvStore.Set(0, rlm, StoreKeyTokenSpecificMinimumRewards.String(), rewards)
550}
551
552// SetTokenSpecificMinimumRewardItem sets a single token's minimum reward amount.
553//
554// Parameters:
555// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
556// - rlm: Current staker realm context; it must be current before storage is written.
557// - tokenPath: Token path receiving the minimum reward override.
558// - amount: Minimum reward amount required for tokenPath.
559//
560// Returns:
561// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
562func (s *stakerStore) SetTokenSpecificMinimumRewardItem(_ int, rlm realm, tokenPath string, amount int64) error {
563 if !rlm.IsCurrent() {
564 return errors.New(ErrSpoofedRealm)
565 }
566
567 rewards := s.GetTokenSpecificMinimumRewards()
568
569 owned := make(map[string]int64)
570 for k, v := range rewards {
571 owned[k] = v
572 }
573
574 owned[tokenPath] = amount
575
576 return s.kvStore.Set(0, rlm, StoreKeyTokenSpecificMinimumRewards.String(), owned)
577}
578
579// RemoveTokenSpecificMinimumRewardItem removes a single token's minimum reward entry.
580//
581// Parameters:
582// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
583// - rlm: Current staker realm context; it must be current before storage is written.
584// - tokenPath: Token path whose override is removed.
585//
586// Returns:
587// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
588func (s *stakerStore) RemoveTokenSpecificMinimumRewardItem(_ int, rlm realm, tokenPath string) error {
589 if !rlm.IsCurrent() {
590 return errors.New(ErrSpoofedRealm)
591 }
592
593 rewards := s.GetTokenSpecificMinimumRewards()
594
595 owned := make(map[string]int64)
596 for k, v := range rewards {
597 if k == tokenPath {
598 continue
599 }
600
601 owned[k] = v
602 }
603
604 return s.kvStore.Set(0, rlm, StoreKeyTokenSpecificMinimumRewards.String(), owned)
605}
606
607// UnstakingFee
608// HasUnstakingFeeStoreKey reports whether the unstaking-fee key exists.
609//
610// Returns:
611// - bool: True when an unstaking fee has been initialized in storage.
612func (s *stakerStore) HasUnstakingFeeStoreKey() bool {
613 return s.kvStore.Has(StoreKeyUnstakingFee.String())
614}
615
616// GetUnstakingFee retrieves the configured unstaking fee rate.
617//
618// Returns:
619// - uint64: Stored unstaking fee rate in basis points; panics on read or type failure.
620func (s *stakerStore) GetUnstakingFee() uint64 {
621 result, err := s.kvStore.Get(StoreKeyUnstakingFee.String())
622 if err != nil {
623 panic(err)
624 }
625
626 fee, ok := result.(uint64)
627 if !ok {
628 panic(ufmt.Sprintf("failed to cast result to uint64: %T", result))
629 }
630
631 return fee
632}
633
634// SetUnstakingFee stores the fee charged when a position is unstaked.
635//
636// Parameters:
637// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
638// - rlm: Current staker realm context; it must be current before storage is written.
639// - fee: Unstaking fee rate in basis points.
640//
641// Returns:
642// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
643func (s *stakerStore) SetUnstakingFee(_ int, rlm realm, fee uint64) error {
644 if !rlm.IsCurrent() {
645 return errors.New(ErrSpoofedRealm)
646 }
647
648 return s.kvStore.Set(0, rlm, StoreKeyUnstakingFee.String(), fee)
649}
650
651// HasPendingProtocolFeesStoreKey reports whether the pending protocol-fees key exists.
652//
653// Returns:
654// - bool: True when pending protocol fees have been initialized in storage.
655func (s *stakerStore) HasPendingProtocolFeesStoreKey() bool {
656 return s.kvStore.Has(StoreKeyPendingProtocolFees.String())
657}
658
659// GetPendingProtocolFees retrieves pending protocol fee amounts keyed by token path.
660//
661// Returns:
662// - map[string]int64: Stored token-to-fee map; panics on read or type failure.
663func (s *stakerStore) GetPendingProtocolFees() map[string]int64 {
664 result, err := s.kvStore.Get(StoreKeyPendingProtocolFees.String())
665 if err != nil {
666 panic(err)
667 }
668
669 fees, ok := result.(map[string]int64)
670 if !ok {
671 panic(ufmt.Sprintf("failed to cast result to map[string]int64: %T", result))
672 }
673
674 return fees
675}
676
677// SetPendingProtocolFees replaces the pending protocol-fee map with a store-owned copy.
678//
679// Parameters:
680// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
681// - rlm: Current staker realm context; it must be current before storage is written.
682// - fees: Pending protocol fee amounts keyed by token path.
683//
684// Returns:
685// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
686func (s *stakerStore) SetPendingProtocolFees(_ int, rlm realm, fees map[string]int64) error {
687 if !rlm.IsCurrent() {
688 return errors.New(ErrSpoofedRealm)
689 }
690
691 // The map is copied here so it is allocated by, and therefore mutable from, this realm.
692 owned := make(map[string]int64, len(fees))
693 for tokenPath, amount := range fees {
694 owned[tokenPath] = amount
695 }
696
697 return s.kvStore.Set(0, rlm, StoreKeyPendingProtocolFees.String(), owned)
698}
699
700// GetPendingProtocolFee returns one token's pending protocol fee amount.
701//
702// Parameters:
703// - tokenPath: Token path whose pending fee is read.
704//
705// Returns:
706// - int64: Stored pending fee amount, or zero when tokenPath has no map entry.
707func (s *stakerStore) GetPendingProtocolFee(tokenPath string) int64 {
708 return s.GetPendingProtocolFees()[tokenPath]
709}
710
711// SetPendingProtocolFee updates one token's pending protocol fee in the stored fee map.
712//
713// Parameters:
714// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
715// - rlm: Current staker realm context and write-authorizing realm.
716// - tokenPath: Token path whose pending fee amount is updated.
717// - amount: Pending protocol fee amount for tokenPath.
718//
719// Returns:
720// - error: ErrSpoofedRealm or write-permission error when the realm cannot mutate this store; nil on success.
721func (s *stakerStore) SetPendingProtocolFee(_ int, rlm realm, tokenPath string, amount int64) error {
722 if !rlm.IsCurrent() {
723 return errors.New(ErrSpoofedRealm)
724 }
725
726 if rlm.IsCode() && !s.kvStore.IsWriteAuthorized(rlm.Address()) {
727 return errors.New(store.ErrWritePermissionDenied)
728 }
729
730 s.GetPendingProtocolFees()[tokenPath] = amount
731
732 return nil
733}
734
735// RemovePendingProtocolFee removes one token's pending protocol fee entry.
736//
737// Parameters:
738// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
739// - rlm: Current staker realm context and write-authorizing realm.
740// - tokenPath: Token path whose pending fee entry is deleted.
741//
742// Returns:
743// - error: ErrSpoofedRealm or write-permission error when the realm cannot mutate this store; nil on success.
744func (s *stakerStore) RemovePendingProtocolFee(_ int, rlm realm, tokenPath string) error {
745 if !rlm.IsCurrent() {
746 return errors.New(ErrSpoofedRealm)
747 }
748
749 if rlm.IsCode() && !s.kvStore.IsWriteAuthorized(rlm.Address()) {
750 return errors.New(store.ErrWritePermissionDenied)
751 }
752
753 delete(s.GetPendingProtocolFees(), tokenPath)
754
755 return nil
756}
757
758// UnstakedPositions
759// HasUnstakedPositionsStoreKey reports whether the unstaked-positions key exists.
760//
761// Returns:
762// - bool: True when unstaked positions have been initialized in storage.
763func (s *stakerStore) HasUnstakedPositionsStoreKey() bool {
764 return s.kvStore.Has(StoreKeyUnstakedPositions.String())
765}
766
767// GetUnstakedPositions retrieves the unstaked-position tree.
768//
769// Returns:
770// - *bptree.BPTree: Stored unstaked-position records; panics on read or type failure.
771func (s *stakerStore) GetUnstakedPositions() *bptree.BPTree {
772 result, err := s.kvStore.Get(StoreKeyUnstakedPositions.String())
773 if err != nil {
774 panic(err)
775 }
776
777 positions, ok := result.(*bptree.BPTree)
778 if !ok {
779 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
780 }
781
782 return positions
783}
784
785// SetUnstakedPositions stores positions that have been unstaked but retain reward checkpoints.
786//
787// Parameters:
788// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
789// - rlm: Current staker realm context; it must be current before storage is written.
790// - positions: B+ tree of unstaked position records and their exit checkpoints.
791//
792// Returns:
793// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
794func (s *stakerStore) SetUnstakedPositions(_ int, rlm realm, positions *bptree.BPTree) error {
795 if !rlm.IsCurrent() {
796 return errors.New(ErrSpoofedRealm)
797 }
798
799 return s.kvStore.Set(0, rlm, StoreKeyUnstakedPositions.String(), positions)
800}
801
802// UncollectedIncentiveCounts
803// HasUncollectedIncentiveCountsStoreKey reports whether the uncollected-counts key exists.
804//
805// Returns:
806// - bool: True when uncollected incentive counts have been initialized in storage.
807func (s *stakerStore) HasUncollectedIncentiveCountsStoreKey() bool {
808 return s.kvStore.Has(StoreKeyUncollectedIncentiveCounts.String())
809}
810
811// GetUncollectedIncentiveCounts retrieves outstanding-position counts by incentive.
812//
813// Returns:
814// - *bptree.BPTree: Stored incentive-to-count tree; panics on read or type failure.
815func (s *stakerStore) GetUncollectedIncentiveCounts() *bptree.BPTree {
816 result, err := s.kvStore.Get(StoreKeyUncollectedIncentiveCounts.String())
817 if err != nil {
818 panic(err)
819 }
820
821 counts, ok := result.(*bptree.BPTree)
822 if !ok {
823 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
824 }
825
826 return counts
827}
828
829// SetUncollectedIncentiveCounts stores counts of unstaked positions owing each incentive.
830//
831// Parameters:
832// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
833// - rlm: Current staker realm context; it must be current before storage is written.
834// - counts: B+ tree mapping incentive identifiers to outstanding position counts.
835//
836// Returns:
837// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
838func (s *stakerStore) SetUncollectedIncentiveCounts(_ int, rlm realm, counts *bptree.BPTree) error {
839 if !rlm.IsCurrent() {
840 return errors.New(ErrSpoofedRealm)
841 }
842
843 return s.kvStore.Set(0, rlm, StoreKeyUncollectedIncentiveCounts.String(), counts)
844}
845
846// Pools
847// HasPoolsStoreKey reports whether the pools key exists.
848//
849// Returns:
850// - bool: True when the pool collection has been initialized in storage.
851func (s *stakerStore) HasPoolsStoreKey() bool {
852 return s.kvStore.Has(StoreKeyPools.String())
853}
854
855// GetPools retrieves the staker's pool collection.
856//
857// Returns:
858// - *bptree.BPTree: Stored pool tree; panics on read or type failure.
859func (s *stakerStore) GetPools() *bptree.BPTree {
860 result, err := s.kvStore.Get(StoreKeyPools.String())
861 if err != nil {
862 panic(err)
863 }
864
865 pools, ok := result.(*bptree.BPTree)
866 if !ok {
867 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
868 }
869
870 return pools
871}
872
873// SetPools stores the pool collection used by the staker.
874//
875// Parameters:
876// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
877// - rlm: Current staker realm context; it must be current before storage is written.
878// - pools: Pool tree containing registered pools and their reward state.
879//
880// Returns:
881// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
882func (s *stakerStore) SetPools(_ int, rlm realm, pools *bptree.BPTree) error {
883 if !rlm.IsCurrent() {
884 return errors.New(ErrSpoofedRealm)
885 }
886
887 return s.kvStore.Set(0, rlm, StoreKeyPools.String(), pools)
888}
889
890// PoolTierMemberships
891// HasPoolTierMembershipsStoreKey reports whether the pool-tier membership key exists.
892//
893// Returns:
894// - bool: True when pool-tier memberships have been initialized in storage.
895func (s *stakerStore) HasPoolTierMembershipsStoreKey() bool {
896 return s.kvStore.Has(StoreKeyPoolTierMemberships.String())
897}
898
899// GetPoolTierMemberships retrieves the pool-to-tier membership tree.
900//
901// Returns:
902// - *bptree.BPTree: Stored mapping from pool paths to tier numbers; panics on read or type failure.
903func (s *stakerStore) GetPoolTierMemberships() *bptree.BPTree {
904 result, err := s.kvStore.Get(StoreKeyPoolTierMemberships.String())
905 if err != nil {
906 panic(err)
907 }
908
909 memberships, ok := result.(*bptree.BPTree)
910 if !ok {
911 panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
912 }
913
914 return memberships
915}
916
917// SetPoolTierMemberships stores the pool-to-tier membership tree.
918//
919// Parameters:
920// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
921// - rlm: Current staker realm context; it must be current before storage is written.
922// - memberships: Mapping from pool paths to their assigned tier numbers.
923//
924// Returns:
925// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
926func (s *stakerStore) SetPoolTierMemberships(_ int, rlm realm, memberships *bptree.BPTree) error {
927 if !rlm.IsCurrent() {
928 return errors.New(ErrSpoofedRealm)
929 }
930
931 return s.kvStore.Set(0, rlm, StoreKeyPoolTierMemberships.String(), memberships)
932}
933
934// PoolTierRatio
935// HasPoolTierRatioStoreKey reports whether the pool-tier ratio key exists.
936//
937// Returns:
938// - bool: True when a pool-tier ratio has been initialized in storage.
939func (s *stakerStore) HasPoolTierRatioStoreKey() bool {
940 return s.kvStore.Has(StoreKeyPoolTierRatio.String())
941}
942
943// GetPoolTierRatio retrieves the configured pool-tier reward-share ratio.
944//
945// Returns:
946// - TierRatio: Stored ratio distribution across tiers; panics on read or type failure.
947func (s *stakerStore) GetPoolTierRatio() TierRatio {
948 result, err := s.kvStore.Get(StoreKeyPoolTierRatio.String())
949 if err != nil {
950 panic(err)
951 }
952
953 ratio, ok := result.(TierRatio)
954 if !ok {
955 panic(ufmt.Sprintf("failed to cast result to TierRatio: %T", result))
956 }
957
958 return ratio
959}
960
961// SetPoolTierRatio stores the reward-share ratio for each pool tier.
962//
963// Parameters:
964// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
965// - rlm: Current staker realm context; it must be current before storage is written.
966// - ratio: Tier reward-share ratio used to divide current emission.
967//
968// Returns:
969// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
970func (s *stakerStore) SetPoolTierRatio(_ int, rlm realm, ratio TierRatio) error {
971 if !rlm.IsCurrent() {
972 return errors.New(ErrSpoofedRealm)
973 }
974
975 return s.kvStore.Set(0, rlm, StoreKeyPoolTierRatio.String(), ratio)
976}
977
978// PoolTierCounts
979// HasPoolTierCountsStoreKey reports whether the pool-tier counts key exists.
980//
981// Returns:
982// - bool: True when pool counts have been initialized in storage.
983func (s *stakerStore) HasPoolTierCountsStoreKey() bool {
984 return s.kvStore.Has(StoreKeyPoolTierCounts.String())
985}
986
987// GetPoolTierCounts retrieves the pool count for every tier index.
988//
989// Returns:
990// - [AllTierCount]uint64: Stored pool counts indexed by tier; panics on read or type failure.
991func (s *stakerStore) GetPoolTierCounts() [AllTierCount]uint64 {
992 result, err := s.kvStore.Get(StoreKeyPoolTierCounts.String())
993 if err != nil {
994 panic(err)
995 }
996
997 counts, ok := result.([AllTierCount]uint64)
998 if !ok {
999 panic(ufmt.Sprintf("failed to cast result to [AllTierCount]uint64: %T", result))
1000 }
1001
1002 return counts
1003}
1004
1005// SetPoolTierCounts stores the number of pools assigned to each tier index.
1006//
1007// Parameters:
1008// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1009// - rlm: Current staker realm context; it must be current before storage is written.
1010// - counts: Pool counts indexed by tier, including the reserved zero tier.
1011//
1012// Returns:
1013// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1014func (s *stakerStore) SetPoolTierCounts(_ int, rlm realm, counts [AllTierCount]uint64) error {
1015 if !rlm.IsCurrent() {
1016 return errors.New(ErrSpoofedRealm)
1017 }
1018
1019 return s.kvStore.Set(0, rlm, StoreKeyPoolTierCounts.String(), counts)
1020}
1021
1022// PoolTierLastRewardCacheTimestamp
1023// HasPoolTierLastRewardCacheTimestampStoreKey reports whether the tier reward-cache timestamp key exists.
1024//
1025// Returns:
1026// - bool: True when a tier reward-cache timestamp has been initialized in storage.
1027func (s *stakerStore) HasPoolTierLastRewardCacheTimestampStoreKey() bool {
1028 return s.kvStore.Has(StoreKeyPoolTierLastRewardCacheTimestamp.String())
1029}
1030
1031// GetPoolTierLastRewardCacheTimestamp retrieves the tier reward-cache timestamp.
1032//
1033// Returns:
1034// - int64: Stored Unix timestamp through which tier rewards are materialized; panics on read or type failure.
1035func (s *stakerStore) GetPoolTierLastRewardCacheTimestamp() int64 {
1036 result, err := s.kvStore.Get(StoreKeyPoolTierLastRewardCacheTimestamp.String())
1037 if err != nil {
1038 panic(err)
1039 }
1040
1041 timestamp, ok := result.(int64)
1042 if !ok {
1043 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
1044 }
1045
1046 return timestamp
1047}
1048
1049// SetPoolTierLastRewardCacheTimestamp stores the timestamp through which tier rewards are cached.
1050//
1051// Parameters:
1052// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1053// - rlm: Current staker realm context; it must be current before storage is written.
1054// - timestamp: Unix timestamp through which pool-tier reward caches are materialized.
1055//
1056// Returns:
1057// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1058func (s *stakerStore) SetPoolTierLastRewardCacheTimestamp(_ int, rlm realm, timestamp int64) error {
1059 if !rlm.IsCurrent() {
1060 return errors.New(ErrSpoofedRealm)
1061 }
1062
1063 return s.kvStore.Set(0, rlm, StoreKeyPoolTierLastRewardCacheTimestamp.String(), timestamp)
1064}
1065
1066// PoolTierCurrentEmission
1067// HasPoolTierCurrentEmissionStoreKey reports whether the current pool-tier emission key exists.
1068//
1069// Returns:
1070// - bool: True when the current pool-tier emission has been initialized in storage.
1071func (s *stakerStore) HasPoolTierCurrentEmissionStoreKey() bool {
1072 return s.kvStore.Has(StoreKeyPoolTierCurrentEmission.String())
1073}
1074
1075// GetPoolTierCurrentEmission retrieves the current pool-tier emission amount.
1076//
1077// Returns:
1078// - int64: Stored emission amount used for tier reward accrual; panics on read or type failure.
1079func (s *stakerStore) GetPoolTierCurrentEmission() int64 {
1080 result, err := s.kvStore.Get(StoreKeyPoolTierCurrentEmission.String())
1081 if err != nil {
1082 panic(err)
1083 }
1084
1085 emission, ok := result.(int64)
1086 if !ok {
1087 panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
1088 }
1089
1090 return emission
1091}
1092
1093// SetPoolTierCurrentEmission stores the current pool-tier emission amount.
1094//
1095// Parameters:
1096// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1097// - rlm: Current staker realm context; it must be current before storage is written.
1098// - emission: Current emission amount used for tier reward accrual.
1099//
1100// Returns:
1101// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1102func (s *stakerStore) SetPoolTierCurrentEmission(_ int, rlm realm, emission int64) error {
1103 if !rlm.IsCurrent() {
1104 return errors.New(ErrSpoofedRealm)
1105 }
1106
1107 return s.kvStore.Set(0, rlm, StoreKeyPoolTierCurrentEmission.String(), emission)
1108}
1109
1110// PoolTierGetEmission
1111// HasPoolTierGetEmissionStoreKey reports whether the pool-tier emission callback key exists.
1112//
1113// Returns:
1114// - bool: True when the current-emission callback has been initialized in storage.
1115func (s *stakerStore) HasPoolTierGetEmissionStoreKey() bool {
1116 return s.kvStore.Has(StoreKeyPoolTierGetEmission.String())
1117}
1118
1119// GetPoolTierGetEmission retrieves the current-emission callback.
1120//
1121// Returns:
1122// - func() (int64, error): Callback returning the current emission amount per second and an error; panics on read or type failure.
1123func (s *stakerStore) GetPoolTierGetEmission() func() (int64, error) {
1124 result, err := s.kvStore.Get(StoreKeyPoolTierGetEmission.String())
1125 if err != nil {
1126 panic(err)
1127 }
1128
1129 fn, ok := result.(func() (int64, error))
1130 if !ok {
1131 panic(ufmt.Sprintf("failed to cast result to func() (int64, error): %T", result))
1132 }
1133
1134 return fn
1135}
1136
1137// SetPoolTierGetEmission stores the callback used to read current staker emission.
1138//
1139// Parameters:
1140// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1141// - rlm: Current staker realm context; it must be current before storage is written.
1142// - fn: Callback returning the current emission amount per second and an error.
1143//
1144// Returns:
1145// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1146func (s *stakerStore) SetPoolTierGetEmission(_ int, rlm realm, fn func() (int64, error)) error {
1147 if !rlm.IsCurrent() {
1148 return errors.New(ErrSpoofedRealm)
1149 }
1150
1151 return s.kvStore.Set(0, rlm, StoreKeyPoolTierGetEmission.String(), fn)
1152}
1153
1154// PoolTierGetHalvingBlocksInRange
1155// HasPoolTierGetHalvingBlocksInRangeStoreKey reports whether the pool-tier halving callback key exists.
1156//
1157// Returns:
1158// - bool: True when the halving-range callback has been initialized in storage.
1159func (s *stakerStore) HasPoolTierGetHalvingBlocksInRangeStoreKey() bool {
1160 return s.kvStore.Has(StoreKeyPoolTierGetHalvingBlocksInRange.String())
1161}
1162
1163// GetPoolTierGetHalvingBlocksInRange retrieves the stored halving-range callback.
1164//
1165// Returns:
1166// - func(start, end int64) ([]int64, []int64, error): Callback returning halving timestamps and matching emissions for [start, end); panics on read or type failure.
1167func (s *stakerStore) GetPoolTierGetHalvingBlocksInRange() func(start, end int64) ([]int64, []int64, error) {
1168 result, err := s.kvStore.Get(StoreKeyPoolTierGetHalvingBlocksInRange.String())
1169 if err != nil {
1170 panic(err)
1171 }
1172
1173 fn, ok := result.(func(start, end int64) ([]int64, []int64, error))
1174 if !ok {
1175 panic(ufmt.Sprintf("failed to cast result to func(start, end int64) ([]int64, []int64, error): %T", result))
1176 }
1177
1178 return fn
1179}
1180
1181// SetPoolTierGetHalvingBlocksInRange stores the halving-range callback used by pool-tier reward caching.
1182//
1183// Parameters:
1184// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1185// - rlm: Current staker realm context; it must be current before storage is written.
1186// - fn: Callback accepting [start, end) timestamps and returning halving timestamps, emissions, and an error.
1187//
1188// Returns:
1189// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1190func (s *stakerStore) SetPoolTierGetHalvingBlocksInRange(_ int, rlm realm, fn func(start, end int64) ([]int64, []int64, error)) error {
1191 if !rlm.IsCurrent() {
1192 return errors.New(ErrSpoofedRealm)
1193 }
1194
1195 return s.kvStore.Set(0, rlm, StoreKeyPoolTierGetHalvingBlocksInRange.String(), fn)
1196}
1197
1198// HasWarmupTemplateStoreKey reports whether the warmup-template key exists.
1199//
1200// Returns:
1201// - bool: True when a warmup schedule has been initialized in storage.
1202func (s *stakerStore) HasWarmupTemplateStoreKey() bool {
1203 return s.kvStore.Has(StoreKeyWarmupTemplate.String())
1204}
1205
1206// GetWarmupTemplate retrieves a clone of the stored warmup schedule.
1207//
1208// Returns:
1209// - []Warmup: Warmup entries copied into the caller's realm; panics on read or type failure.
1210func (s *stakerStore) GetWarmupTemplate() []Warmup {
1211 result, err := s.kvStore.Get(StoreKeyWarmupTemplate.String())
1212 if err != nil {
1213 panic(err)
1214 }
1215
1216 warmups, ok := result.([]Warmup)
1217 if !ok {
1218 panic(ufmt.Sprintf("failed to cast result to []Warmup: %T", result))
1219 }
1220
1221 return cloneWarmups(warmups)
1222}
1223
1224// SetWarmupTemplate stores the warmup schedule used for external incentives.
1225//
1226// Parameters:
1227// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1228// - rlm: Current staker realm context; it must be current before storage is written.
1229// - warmups: Warmup schedule entries to persist.
1230//
1231// Returns:
1232// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1233func (s *stakerStore) SetWarmupTemplate(_ int, rlm realm, warmups []Warmup) error {
1234 if !rlm.IsCurrent() {
1235 return errors.New(ErrSpoofedRealm)
1236 }
1237
1238 return s.kvStore.Set(0, rlm, StoreKeyWarmupTemplate.String(), warmups)
1239}
1240
1241// CurrentSwapBatch
1242// HasCurrentSwapBatchStoreKey reports whether the current-swap-batch key exists.
1243//
1244// Returns:
1245// - bool: True when the current swap batch has been initialized in storage.
1246func (s *stakerStore) HasCurrentSwapBatchStoreKey() bool {
1247 return s.kvStore.Has(StoreKeyCurrentSwapBatch.String())
1248}
1249
1250// GetCurrentSwapBatch retrieves the processor for the currently active swap.
1251//
1252// Returns:
1253// - *SwapBatchProcessor: Stored swap batch, or nil when initialization has recorded no active batch; panics on read or type failure.
1254func (s *stakerStore) GetCurrentSwapBatch() *SwapBatchProcessor {
1255 result, err := s.kvStore.Get(StoreKeyCurrentSwapBatch.String())
1256 if err != nil {
1257 panic(err)
1258 }
1259
1260 batch, ok := result.(*SwapBatchProcessor)
1261 if !ok {
1262 panic(ufmt.Sprintf("failed to cast result to *SwapBatchProcessor: %T", result))
1263 }
1264
1265 return batch
1266}
1267
1268// SetCurrentSwapBatch persists the processor for the currently active swap.
1269//
1270// Parameters:
1271// - _: Leading realm-call discriminator for the forwarded store call; callers pass 0.
1272// - rlm: Current staker realm context; it must be current before storage is written.
1273// - batch: Swap-batch processor to persist, or nil when the swap has ended.
1274//
1275// Returns:
1276// - error: ErrSpoofedRealm when rlm is not current, or the underlying KV-store write error; nil on success.
1277func (s *stakerStore) SetCurrentSwapBatch(_ int, rlm realm, batch *SwapBatchProcessor) error {
1278 if !rlm.IsCurrent() {
1279 return errors.New(ErrSpoofedRealm)
1280 }
1281
1282 return s.kvStore.Set(0, rlm, StoreKeyCurrentSwapBatch.String(), batch)
1283}
1284
1285// NewStakerStore creates a new staker store instance with the provided KV store.
1286// This function is used by the upgrade system to create storage instances for each implementation.
1287//
1288// Parameters:
1289// - kvStore: Key-value store used for all staker state.
1290//
1291// Returns:
1292// - IStakerStore: Store interface backed by the supplied KV store.
1293func NewStakerStore(kvStore store.KVStore) IStakerStore {
1294 return &stakerStore{
1295 kvStore: kvStore,
1296 }
1297}
1298
1299func makeIncentiveID(creator address, timestamp int64, index int64) string {
1300 return ufmt.Sprintf("%s:%d:%d", creator.String(), timestamp, index)
1301}
1302
1303func contains(items []string, item string) bool {
1304 for _, i := range items {
1305 if i == item {
1306 return true
1307 }
1308 }
1309
1310 return false
1311}