PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/gnoswap/protocol_fee

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
protocol_fee
Namespace
gnoswap
Files
11 (README)(gnomod.toml)
Exported functions
29
Module
gno.land/r/gnoswap/protocol_fee
gno
0.9

Files (11)

  • README.mdmarkdown
  • gnomod.tomltoml
  • doc.gnogno
  • getter_utils.gnogno
  • getter.gnogno
  • proxy.gnogno
  • render.gnogno
  • state.gnogno
  • store.gnogno
  • types.gnogno
  • upgrade.gnogno
  • store.gnogno
    1package protocol_fee23import (4	"errors"56	bptree "gno.land/p/nt/bptree/v0"7	ufmt "gno.land/p/nt/ufmt/v0"8

    Functions

    • AddToProtocolFee(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, tokenPath string, amount int64) interface {Error func() string}

    • AdvanceAccrualEpoch(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}) int64

    • ConsumeAccrualBuckets(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, tokenPath string, limit int) ([]int64, []int64)

    • DistributeProtocolFee(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})

    • DistributeProtocolFeeByTokenPath(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, tokenPath string)

    • GetAccrualBuckets(tokenPath string, limit int) ([]int64, []int64)

    • GetAccrualEpoch() int64

    • GetAccrualPendingTokens() []string

    • GetAccuTransfersToDevOps() map[string]int64

    • GetAccuTransfersToGovStaker() map[string]int64

    • GetAccuTransferToDevOpsByTokenPath(tokenPath string) int64

    • GetAccuTransferToGovStakerByTokenPath(tokenPath string) int64

    • GetActualDistributedToDevOps() map[string]int64

    • GetActualDistributedToDevOpsByTokenPath(tokenPath string) int64

    • GetActualDistributedToGovStaker() map[string]int64

    • GetActualDistributedToGovStakerByTokenPath(tokenPath string) int64

    • GetDevOpsPct() int64

    • GetDomainPath() string

    • GetGovStakerPct() int64

    • GetImplementationPackagePath() string

    • GetReservedTokens() []string

    • GetVersionPackagePath() string

    • NewBPTreeN(fanout int) *gno.land/p/nt/bptree/v0.BPTree

    • NewProtocolFeeStore(kvStore interface {AddAuthorizedCaller func(int, .uverse.realm, .uverse.address, gno.land/p/gnoswap/store/v1.Permission) .uverse.error; Delete func(int, .uverse.realm, string) .uverse.error; Get func(string) (interface {}, .uverse.error); GetAddress func(string) (.uverse.address, .uverse.error); GetAllKeys func() ([]string, .uverse.error); GetAuthorizedCallers func() (map[.uverse.address]gno.land/p/gnoswap/store/v1.Permission, .uverse.error); GetBPTree func(string) (*gno.land/p/nt/bptree/v0.BPTree, .uverse.error); GetBool func(string) (bool, .uverse.error); GetDomainAddress func() .uverse.address; GetInt64 func(string) (int64, .uverse.error); GetString func(string) (string, .uverse.error); GetUint64 func(string) (uint64, .uverse.error); Has func(string) bool; IsWriteAuthorized func(.uverse.address) bool; RemoveAuthorizedCaller func(int, .uverse.realm, .uverse.address) .uverse.error; Set func(int, .uverse.realm, string, interface {}) .uverse.error; UpdateAuthorizedCaller func(int, .uverse.realm, .uverse.address, gno.land/p/gnoswap/store/v1.Permission) .uverse.error}) interface {AddAccrualBucket func(int, .uverse.realm, string, int64, int64) .uverse.error; AddAccrualPendingToken func(int, .uverse.realm, string) .uverse.error; AddReservedToken func(int, .uverse.realm, string) .uverse.error; GetAccrualBuckets func(string, int) ([]int64, []int64); GetAccrualEpoch func() int64; GetAccrualPendingTokens func() []string; GetAccuToDevOps func() *gno.land/p/nt/bptree/v0.BPTree; GetAccuToDevOpsItem func(string) (int64, bool); GetAccuToGovStaker func() *gno.land/p/nt/bptree/v0.BPTree; GetAccuToGovStakerItem func(string) (int64, bool); GetDevOpsPct func() int64; GetDistributedToDevOpsHistory func() *gno.land/p/nt/bptree/v0.BPTree; GetDistributedToDevOpsHistoryItem func(string) (int64, bool); GetDistributedToGovStakerHistory func() *gno.land/p/nt/bptree/v0.BPTree; GetDistributedToGovStakerHistoryItem func(string) (int64, bool); GetReservedTokens func() []string; HasAccrualBucketsStoreKey func() bool; HasAccrualEpochStoreKey func() bool; HasAccrualPendingTokensStoreKey func() bool; HasAccuToDevOpsStoreKey func() bool; HasAccuToGovStakerStoreKey func() bool; HasDevOpsPctStoreKey func() bool; HasDistributedToDevOpsHistoryStoreKey func() bool; HasDistributedToGovStakerHistoryStoreKey func() bool; HasReservedToken func(string) bool; HasReservedTokensStoreKey func() bool; InitializeAccrualBuckets func(int, .uverse.realm) .uverse.error; InitializeAccrualEpoch func(int, .uverse.realm) .uverse.error; InitializeAccrualPendingTokens func(int, .uverse.realm) .uverse.error; InitializeAccuToDevOps func(int, .uverse.realm) .uverse.error; InitializeAccuToGovStaker func(int, .uverse.realm) .uverse.error; InitializeDevOpsPct func(int, .uverse.realm) .uverse.error; InitializeDistributedToDevOpsHistory func(int, .uverse.realm) .uverse.error; InitializeDistributedToGovStakerHistory func(int, .uverse.realm) .uverse.error; InitializeReservedTokens func(int, .uverse.realm) .uverse.error; RemoveAccrualBuckets func(int, .uverse.realm, string, []int64) .uverse.error; RemoveAccrualPendingToken func(int, .uverse.realm, string) .uverse.error; RemoveReservedToken func(int, .uverse.realm, string) .uverse.error; SetAccrualEpoch func(int, .uverse.realm, int64) .uverse.error; SetAccuToDevOpsItem func(int, .uverse.realm, string, int64) .uverse.error; SetAccuToGovStakerItem func(int, .uverse.realm, string, int64) .uverse.error; SetDevOpsPct func(int, .uverse.realm, int64) .uverse.error; SetDistributedToDevOpsHistoryItem func(int, .uverse.realm, string, int64) .uverse.error; SetDistributedToGovStakerHistoryItem func(int, .uverse.realm, string, int64) .uverse.error}

    • RegisterInitializer(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, initializer func(int, .uverse.realm, gno.land/r/gnoswap/protocol_fee.IProtocolFeeStore) gno.land/r/gnoswap/protocol_fee.IProtocolFee)

    • Render(path string) string

    • SetDevOpsPct(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pct int64)

    • SetGovStakerPct(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pct int64)

    • UpgradeImpl(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, packagePath string)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    Rendered

    RenderedRawgnoweb ↗
    9 "gno.land/p/gnoswap/gnsmath/v1"
    10 "gno.land/p/gnoswap/store/v1"
    11 "gno.land/p/gnoswap/utils/v1"
    12)
    13
    14type StoreKey string
    15
    16// String returns the textual store-key value.
    17//
    18// Returns:
    19// - key: The string representation of the StoreKey.
    20func (s StoreKey) String() string {
    21 return string(s)
    22}
    23
    24const (
    25 // By default, devOps will get 0% of the protocol fee (which means gov/staker will get 100% of the protocol fee)
    26 // This percentage can be modified through governance.
    27 StoreKeyDevOpsPct StoreKey = "devOpsPct"
    28
    29 // accuToGovStaker tracks the cumulative amount allocated to GovStaker,
    30 // including allocations that are still pending distribution.
    31 StoreKeyAccuToGovStaker StoreKey = "accuToGovStaker" // tokenPath -> amount
    32 // accuToDevOps tracks the cumulative amount allocated to DevOps,
    33 // including allocations that are still pending distribution.
    34 StoreKeyAccuToDevOps StoreKey = "accuToDevOps" // tokenPath -> amount
    35
    36 // Distribution-history trees track cumulative amounts actually transferred.
    37 StoreKeyDistributedToGovStakerHistory StoreKey = "distributedToGovStakerHistory" // tokenPath -> amount
    38 StoreKeyDistributedToDevOpsHistory StoreKey = "distributedToDevOpsHistory" // tokenPath -> amount
    39
    40 // reservedTokens tracks token paths collected but not yet distributed.
    41 StoreKeyReservedTokens StoreKey = "reservedTokens"
    42
    43 // accrualEpoch, accrualBuckets and accrualPendingTokens track the gov/staker share
    44 // per token path and accrual epoch until gov/staker folds it into its accumulator.
    45 StoreKeyAccrualEpoch StoreKey = "accrualEpoch"
    46 StoreKeyAccrualBuckets StoreKey = "accrualBuckets" // tokenPath -> (epoch -> amount)
    47 StoreKeyAccrualPendingTokens StoreKey = "accrualPendingTokens" // tokenPath -> true
    48)
    49
    50const (
    51 defaultDevOpsPct = int64(0)
    52 errSpoofedRealm = "rlm does not match the current crossing frame"
    53)
    54
    55// NewBPTreeN allocates a BP-tree under /r/gnoswap/protocol_fee's realm context
    56// so tree.Set leaf-slot writes clear the readonly-taint gate regardless of
    57// which realm (protocol_fee/v1, mock, tests) calls Set. Callers must allocate
    58// protocol_fee trees through here rather than bptree.NewBPTreeN directly.
    59//
    60// Parameters:
    61// - fanout: Branching factor passed to the BP-tree constructor.
    62//
    63// Returns:
    64// - tree: A new BP-tree configured with fanout and allocated in the protocol-fee realm context.
    65func NewBPTreeN(fanout int) *bptree.BPTree {
    66 return bptree.NewBPTreeN(fanout)
    67}
    68
    69type protocolFeeStore struct {
    70 kvStore store.KVStore
    71}
    72
    73// handle devOpsPct store data
    74//
    75// Returns:
    76// - exists: True when the DevOps percentage store key is present in the KV store.
    77func (s *protocolFeeStore) HasDevOpsPctStoreKey() bool {
    78 return s.kvStore.Has(StoreKeyDevOpsPct.String())
    79}
    80
    81// InitializeDevOpsPct creates the DevOps allocation percentage entry with its default value.
    82//
    83// Parameters:
    84// - _: Crossing discriminator for the store operation; pass 0.
    85// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    86//
    87// Returns:
    88// - err: Nil when the key is initialized; otherwise the current-realm or KV-store write error.
    89func (s *protocolFeeStore) InitializeDevOpsPct(_ int, rlm realm) error {
    90 if !rlm.IsCurrent() {
    91 return errors.New(errSpoofedRealm)
    92 }
    93
    94 return s.kvStore.Set(0, rlm, StoreKeyDevOpsPct.String(), defaultDevOpsPct)
    95}
    96
    97// GetDevOpsPct reads the persisted DevOps allocation percentage.
    98//
    99// Returns:
    100// - pct: The stored DevOps allocation percentage in basis points; the method panics if the key is missing or cannot be decoded as int64.
    101func (s *protocolFeeStore) GetDevOpsPct() int64 {
    102 devOpsPct, err := s.kvStore.GetInt64(StoreKeyDevOpsPct.String())
    103 if err != nil {
    104 panic(err)
    105 }
    106
    107 return devOpsPct
    108}
    109
    110// SetDevOpsPct persists the DevOps allocation percentage.
    111//
    112// Parameters:
    113// - _: Crossing discriminator for the store operation; pass 0.
    114// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    115// - pct: DevOps share of protocol fees in basis points; the state layer constrains this value to 0 through 10000 before calling the store.
    116//
    117// Returns:
    118// - err: Nil when the percentage is persisted; otherwise the current-realm or KV-store write error.
    119func (s *protocolFeeStore) SetDevOpsPct(_ int, rlm realm, pct int64) error {
    120 if !rlm.IsCurrent() {
    121 return errors.New(errSpoofedRealm)
    122 }
    123
    124 return s.kvStore.Set(0, rlm, StoreKeyDevOpsPct.String(), pct)
    125}
    126
    127// handle accuToGovStaker store data
    128//
    129// Returns:
    130// - exists: True when the cumulative Gov/Staker allocation tree key is present in the KV store.
    131func (s *protocolFeeStore) HasAccuToGovStakerStoreKey() bool {
    132 return s.kvStore.Has(StoreKeyAccuToGovStaker.String())
    133}
    134
    135// InitializeAccuToGovStaker creates the cumulative Gov/Staker allocation tree.
    136//
    137// Parameters:
    138// - _: Crossing discriminator for the store operation; pass 0.
    139// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    140//
    141// Returns:
    142// - err: Nil when the tree is initialized; otherwise the current-realm or KV-store write error.
    143func (s *protocolFeeStore) InitializeAccuToGovStaker(_ int, rlm realm) error {
    144 if !rlm.IsCurrent() {
    145 return errors.New(errSpoofedRealm)
    146 }
    147
    148 return s.kvStore.Set(0, rlm, StoreKeyAccuToGovStaker.String(), NewBPTreeN(16))
    149}
    150
    151// GetAccuToGovStaker reads the cumulative Gov/Staker allocation tree.
    152//
    153// Returns:
    154// - tree: The BP-tree mapping token paths to cumulative amounts; the method panics if the store value is absent or has the wrong type.
    155func (s *protocolFeeStore) GetAccuToGovStaker() *bptree.BPTree {
    156 accuToGovStaker, err := s.kvStore.GetBPTree(StoreKeyAccuToGovStaker.String())
    157 if err != nil {
    158 panic(err)
    159 }
    160
    161 return accuToGovStaker
    162}
    163
    164// GetAccuToGovStakerItem reads one token's cumulative Gov/Staker allocation.
    165//
    166// Parameters:
    167// - tokenPath: Token path whose cumulative allocation should be looked up.
    168//
    169// Returns:
    170// - amount: The stored cumulative allocation for tokenPath, or zero when no entry exists.
    171// - found: True when tokenPath has an entry in the allocation tree; false when it is absent.
    172func (s *protocolFeeStore) GetAccuToGovStakerItem(tokenPath string) (int64, bool) {
    173 accuToGovStaker, err := s.kvStore.GetBPTree(StoreKeyAccuToGovStaker.String())
    174 if err != nil {
    175 panic(err)
    176 }
    177
    178 result := accuToGovStaker.Get(tokenPath)
    179 if result == nil {
    180 return 0, false
    181 }
    182
    183 amount, ok := result.(int64)
    184 if !ok {
    185 panic(ufmt.Errorf("failed to cast result to int64: %T", result))
    186 }
    187
    188 return amount, true
    189}
    190
    191// SetAccuToGovStakerItem updates one token's cumulative Gov/Staker allocation.
    192//
    193// Parameters:
    194// - _: Crossing discriminator for the store operation; pass 0.
    195// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    196// - tokenPath: Token path whose cumulative allocation is replaced.
    197// - amount: Cumulative Gov/Staker allocation to store for tokenPath.
    198//
    199// Returns:
    200// - err: Nil when the allocation tree is persisted; otherwise the current-realm, tree-read, or KV-store write error.
    201func (s *protocolFeeStore) SetAccuToGovStakerItem(_ int, rlm realm, tokenPath string, amount int64) error {
    202 if !rlm.IsCurrent() {
    203 return errors.New(errSpoofedRealm)
    204 }
    205
    206 accuToGovStaker, err := s.kvStore.GetBPTree(StoreKeyAccuToGovStaker.String())
    207 if err != nil {
    208 return err
    209 }
    210
    211 accuToGovStaker.Set(tokenPath, amount)
    212
    213 return s.kvStore.Set(0, rlm, StoreKeyAccuToGovStaker.String(), accuToGovStaker)
    214}
    215
    216// handle accuToDevOps store data
    217//
    218// Returns:
    219// - exists: True when the cumulative DevOps allocation tree key is present in the KV store.
    220func (s *protocolFeeStore) HasAccuToDevOpsStoreKey() bool {
    221 return s.kvStore.Has(StoreKeyAccuToDevOps.String())
    222}
    223
    224// InitializeAccuToDevOps creates the cumulative DevOps allocation tree.
    225//
    226// Parameters:
    227// - _: Crossing discriminator for the store operation; pass 0.
    228// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    229//
    230// Returns:
    231// - err: Nil when the tree is initialized; otherwise the current-realm or KV-store write error.
    232func (s *protocolFeeStore) InitializeAccuToDevOps(_ int, rlm realm) error {
    233 if !rlm.IsCurrent() {
    234 return errors.New(errSpoofedRealm)
    235 }
    236
    237 return s.kvStore.Set(0, rlm, StoreKeyAccuToDevOps.String(), NewBPTreeN(16))
    238}
    239
    240// GetAccuToDevOps reads the cumulative DevOps allocation tree.
    241//
    242// Returns:
    243// - tree: The BP-tree mapping token paths to cumulative amounts; the method panics if the store value is absent or has the wrong type.
    244func (s *protocolFeeStore) GetAccuToDevOps() *bptree.BPTree {
    245 accuToDevOps, err := s.kvStore.GetBPTree(StoreKeyAccuToDevOps.String())
    246 if err != nil {
    247 panic(err)
    248 }
    249
    250 return accuToDevOps
    251}
    252
    253// GetAccuToDevOpsItem reads one token's cumulative DevOps allocation.
    254//
    255// Parameters:
    256// - tokenPath: Token path whose cumulative allocation should be looked up.
    257//
    258// Returns:
    259// - amount: The stored cumulative allocation for tokenPath, or zero when no entry exists.
    260// - found: True when tokenPath has an entry in the allocation tree; false when it is absent.
    261func (s *protocolFeeStore) GetAccuToDevOpsItem(tokenPath string) (int64, bool) {
    262 accuToDevOps, err := s.kvStore.GetBPTree(StoreKeyAccuToDevOps.String())
    263 if err != nil {
    264 panic(err)
    265 }
    266
    267 result := accuToDevOps.Get(tokenPath)
    268 if result == nil {
    269 return 0, false
    270 }
    271
    272 amount, ok := result.(int64)
    273 if !ok {
    274 panic(ufmt.Errorf("failed to cast result to int64: %T", result))
    275 }
    276
    277 return amount, true
    278}
    279
    280// SetAccuToDevOpsItem updates one token's cumulative DevOps allocation.
    281//
    282// Parameters:
    283// - _: Crossing discriminator for the store operation; pass 0.
    284// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    285// - tokenPath: Token path whose cumulative allocation is replaced.
    286// - amount: Cumulative DevOps allocation to store for tokenPath.
    287//
    288// Returns:
    289// - err: Nil when the allocation tree is persisted; otherwise the current-realm, tree-read, or KV-store write error.
    290func (s *protocolFeeStore) SetAccuToDevOpsItem(_ int, rlm realm, tokenPath string, amount int64) error {
    291 if !rlm.IsCurrent() {
    292 return errors.New(errSpoofedRealm)
    293 }
    294
    295 accuToDevOps, err := s.kvStore.GetBPTree(StoreKeyAccuToDevOps.String())
    296 if err != nil {
    297 return err
    298 }
    299
    300 accuToDevOps.Set(tokenPath, amount)
    301
    302 return s.kvStore.Set(0, rlm, StoreKeyAccuToDevOps.String(), accuToDevOps)
    303}
    304
    305// handle distributedToGovStakerHistory store data
    306// HasDistributedToGovStakerHistoryStoreKey reports whether the Gov/Staker distribution-history tree exists.
    307//
    308// Returns:
    309// - exists: True when the Gov/Staker distribution-history tree key is present in the KV store.
    310func (s *protocolFeeStore) HasDistributedToGovStakerHistoryStoreKey() bool {
    311 return s.kvStore.Has(StoreKeyDistributedToGovStakerHistory.String())
    312}
    313
    314// InitializeDistributedToGovStakerHistory creates the Gov/Staker distribution-history tree.
    315//
    316// Parameters:
    317// - _: Crossing discriminator for the store operation; pass 0.
    318// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    319//
    320// Returns:
    321// - err: Nil when the history tree is initialized; otherwise the current-realm or KV-store write error.
    322func (s *protocolFeeStore) InitializeDistributedToGovStakerHistory(_ int, rlm realm) error {
    323 if !rlm.IsCurrent() {
    324 return errors.New(errSpoofedRealm)
    325 }
    326
    327 return s.kvStore.Set(0, rlm, StoreKeyDistributedToGovStakerHistory.String(), NewBPTreeN(16))
    328}
    329
    330// GetDistributedToGovStakerHistory reads the cumulative Gov/Staker distribution-history tree.
    331//
    332// Returns:
    333// - tree: The BP-tree mapping token paths to amounts actually distributed to Gov/Staker; the method panics if the stored value is absent or has the wrong type.
    334func (s *protocolFeeStore) GetDistributedToGovStakerHistory() *bptree.BPTree {
    335 distributedToGovStakerHistory, err := s.kvStore.GetBPTree(StoreKeyDistributedToGovStakerHistory.String())
    336 if err != nil {
    337 panic(err)
    338 }
    339
    340 return distributedToGovStakerHistory
    341}
    342
    343// GetDistributedToGovStakerHistoryItem reads one token's cumulative Gov/Staker distribution history.
    344//
    345// Parameters:
    346// - tokenPath: Token path whose distributed amount should be looked up.
    347//
    348// Returns:
    349// - amount: The stored cumulative amount distributed to Gov/Staker for tokenPath, or zero when no entry exists.
    350// - found: True when tokenPath has a history entry; false when it is absent.
    351func (s *protocolFeeStore) GetDistributedToGovStakerHistoryItem(tokenPath string) (int64, bool) {
    352 distributedToGovStakerHistory, err := s.kvStore.GetBPTree(StoreKeyDistributedToGovStakerHistory.String())
    353 if err != nil {
    354 panic(err)
    355 }
    356
    357 result := distributedToGovStakerHistory.Get(tokenPath)
    358 if result == nil {
    359 return 0, false
    360 }
    361
    362 amount, ok := result.(int64)
    363 if !ok {
    364 panic(ufmt.Errorf("failed to cast result to int64: %T", result))
    365 }
    366
    367 return amount, true
    368}
    369
    370// SetDistributedToGovStakerHistoryItem updates one token's cumulative Gov/Staker distribution history.
    371//
    372// Parameters:
    373// - _: Crossing discriminator for the store operation; pass 0.
    374// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    375// - tokenPath: Token path whose distributed amount is replaced.
    376// - amount: Cumulative amount actually distributed to Gov/Staker to store for tokenPath.
    377//
    378// Returns:
    379// - err: Nil when the history tree is persisted; otherwise the current-realm, tree-read, or KV-store write error.
    380func (s *protocolFeeStore) SetDistributedToGovStakerHistoryItem(_ int, rlm realm, tokenPath string, amount int64) error {
    381 if !rlm.IsCurrent() {
    382 return errors.New(errSpoofedRealm)
    383 }
    384
    385 distributedToGovStakerHistory, err := s.kvStore.GetBPTree(StoreKeyDistributedToGovStakerHistory.String())
    386 if err != nil {
    387 return err
    388 }
    389
    390 distributedToGovStakerHistory.Set(tokenPath, amount)
    391
    392 return s.kvStore.Set(0, rlm, StoreKeyDistributedToGovStakerHistory.String(), distributedToGovStakerHistory)
    393}
    394
    395// HasDistributedToDevOpsHistoryStoreKey reports whether the DevOps distribution-history tree exists.
    396//
    397// Returns:
    398// - exists: True when the DevOps distribution-history tree key is present in the KV store.
    399//
    400// handle distributedToDevOpsHistory store data
    401func (s *protocolFeeStore) HasDistributedToDevOpsHistoryStoreKey() bool {
    402 return s.kvStore.Has(StoreKeyDistributedToDevOpsHistory.String())
    403}
    404
    405// InitializeDistributedToDevOpsHistory creates the DevOps distribution-history tree.
    406//
    407// Parameters:
    408// - _: Crossing discriminator for the store operation; pass 0.
    409// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    410//
    411// Returns:
    412// - err: Nil when the history tree is initialized; otherwise the current-realm or KV-store write error.
    413func (s *protocolFeeStore) InitializeDistributedToDevOpsHistory(_ int, rlm realm) error {
    414 if !rlm.IsCurrent() {
    415 return errors.New(errSpoofedRealm)
    416 }
    417
    418 return s.kvStore.Set(0, rlm, StoreKeyDistributedToDevOpsHistory.String(), NewBPTreeN(16))
    419}
    420
    421// GetDistributedToDevOpsHistory reads the cumulative DevOps distribution-history tree.
    422//
    423// Returns:
    424// - tree: The BP-tree mapping token paths to amounts actually distributed to DevOps; the method panics if the stored value is absent or has the wrong type.
    425func (s *protocolFeeStore) GetDistributedToDevOpsHistory() *bptree.BPTree {
    426 distributedToDevOpsHistory, err := s.kvStore.GetBPTree(StoreKeyDistributedToDevOpsHistory.String())
    427 if err != nil {
    428 panic(err)
    429 }
    430
    431 return distributedToDevOpsHistory
    432}
    433
    434// GetDistributedToDevOpsHistoryItem reads one token's cumulative DevOps distribution history.
    435//
    436// Parameters:
    437// - tokenPath: Token path whose distributed amount should be looked up.
    438//
    439// Returns:
    440// - amount: The stored cumulative amount distributed to DevOps for tokenPath, or zero when no entry exists.
    441// - found: True when tokenPath has a history entry; false when it is absent.
    442func (s *protocolFeeStore) GetDistributedToDevOpsHistoryItem(tokenPath string) (int64, bool) {
    443 distributedToDevOpsHistory, err := s.kvStore.GetBPTree(StoreKeyDistributedToDevOpsHistory.String())
    444 if err != nil {
    445 panic(err)
    446 }
    447
    448 result := distributedToDevOpsHistory.Get(tokenPath)
    449 if result == nil {
    450 return 0, false
    451 }
    452
    453 amount, ok := result.(int64)
    454 if !ok {
    455 panic(ufmt.Errorf("failed to cast result to int64: %T", result))
    456 }
    457
    458 return amount, true
    459}
    460
    461// SetDistributedToDevOpsHistoryItem updates one token's cumulative DevOps distribution history.
    462//
    463// Parameters:
    464// - _: Crossing discriminator for the store operation; pass 0.
    465// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    466// - tokenPath: Token path whose distributed amount is replaced.
    467// - amount: Cumulative amount actually distributed to DevOps to store for tokenPath.
    468//
    469// Returns:
    470// - err: Nil when the history tree is persisted; otherwise the current-realm, tree-read, or KV-store write error.
    471func (s *protocolFeeStore) SetDistributedToDevOpsHistoryItem(_ int, rlm realm, tokenPath string, amount int64) error {
    472 if !rlm.IsCurrent() {
    473 return errors.New(errSpoofedRealm)
    474 }
    475
    476 distributedToDevOpsHistory, err := s.kvStore.GetBPTree(StoreKeyDistributedToDevOpsHistory.String())
    477 if err != nil {
    478 return err
    479 }
    480
    481 distributedToDevOpsHistory.Set(tokenPath, amount)
    482
    483 return s.kvStore.Set(0, rlm, StoreKeyDistributedToDevOpsHistory.String(), distributedToDevOpsHistory)
    484}
    485
    486// handle reservedTokens store data
    487//
    488// reservedTokens is the set of token paths that collected a fee not yet transferred out
    489// by DistributeProtocolFee. It is kept as a tree so that a single token can be added or
    490// settled without rewriting the whole set.
    491//
    492// Returns:
    493// - exists: True when the reserved-token index key is present in the KV store.
    494func (s *protocolFeeStore) HasReservedTokensStoreKey() bool {
    495 return s.kvStore.Has(StoreKeyReservedTokens.String())
    496}
    497
    498// InitializeReservedTokens creates the reserved-token index tree.
    499//
    500// Parameters:
    501// - _: Crossing discriminator for the store operation; pass 0.
    502// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    503//
    504// Returns:
    505// - err: Nil when the index tree is initialized; otherwise the current-realm or KV-store write error.
    506func (s *protocolFeeStore) InitializeReservedTokens(_ int, rlm realm) error {
    507 if !rlm.IsCurrent() {
    508 return errors.New(errSpoofedRealm)
    509 }
    510
    511 return s.kvStore.Set(0, rlm, StoreKeyReservedTokens.String(), NewBPTreeN(16))
    512}
    513
    514func (s *protocolFeeStore) getReservedTokenTree() *bptree.BPTree {
    515 reservedTokens, err := s.kvStore.GetBPTree(StoreKeyReservedTokens.String())
    516 if err != nil {
    517 panic(err)
    518 }
    519
    520 return reservedTokens
    521}
    522
    523// GetReservedTokens returns all token paths currently reserved for distribution.
    524//
    525// Returns:
    526// - tokenPaths: Token paths present in the reserved-token index, in BP-tree iteration order.
    527func (s *protocolFeeStore) GetReservedTokens() []string {
    528 return collectTreeKeys(s.getReservedTokenTree())
    529}
    530
    531// HasReservedToken reports whether tokenPath is currently reserved for distribution.
    532//
    533// Parameters:
    534// - tokenPath: Token path to look up in the reserved-token index.
    535//
    536// Returns:
    537// - exists: True when tokenPath is in the reserved-token index; false otherwise.
    538func (s *protocolFeeStore) HasReservedToken(tokenPath string) bool {
    539 return s.getReservedTokenTree().Has(tokenPath)
    540}
    541
    542// AddReservedToken adds tokenPath to the reserved-token index.
    543//
    544// Parameters:
    545// - _: Crossing discriminator for the store operation; pass 0.
    546// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    547// - tokenPath: Token path collected for protocol-fee distribution.
    548//
    549// Returns:
    550// - err: Nil when tokenPath is already present or has been added; otherwise the current-realm or KV-store write error.
    551func (s *protocolFeeStore) AddReservedToken(_ int, rlm realm, tokenPath string) error {
    552 if !rlm.IsCurrent() {
    553 return errors.New(errSpoofedRealm)
    554 }
    555
    556 reservedTokens := s.getReservedTokenTree()
    557 if reservedTokens.Has(tokenPath) {
    558 return nil
    559 }
    560
    561 reservedTokens.Set(tokenPath, true)
    562
    563 return s.kvStore.Set(0, rlm, StoreKeyReservedTokens.String(), reservedTokens)
    564}
    565
    566// RemoveReservedToken removes one tokenPath from the reserved-token set when present.
    567//
    568// Parameters:
    569// - _: Crossing discriminator for the store operation; pass 0.
    570// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    571// - tokenPath: Token path to remove from the reserved-token set.
    572//
    573// Returns:
    574// - err: Nil when tokenPath is absent or has been removed; otherwise the current-realm or KV-store write error.
    575func (s *protocolFeeStore) RemoveReservedToken(_ int, rlm realm, tokenPath string) error {
    576 if !rlm.IsCurrent() {
    577 return errors.New(errSpoofedRealm)
    578 }
    579
    580 reservedTokens := s.getReservedTokenTree()
    581 if _, removed := reservedTokens.Remove(tokenPath); !removed {
    582 return nil
    583 }
    584
    585 return s.kvStore.Set(0, rlm, StoreKeyReservedTokens.String(), reservedTokens)
    586}
    587
    588// handle accrualEpoch store data
    589//
    590// accrualEpoch numbers the intervals between gov/staker stake changes. gov/staker
    591// advances it on every stake change, so every fee that arrives is attributed to the
    592// stake distribution in force when it arrived.
    593//
    594// Returns:
    595// - exists: True when the accrual-epoch store key is present in the KV store.
    596func (s *protocolFeeStore) HasAccrualEpochStoreKey() bool {
    597 return s.kvStore.Has(StoreKeyAccrualEpoch.String())
    598}
    599
    600// InitializeAccrualEpoch initializes the current fee-accrual epoch to zero.
    601//
    602// Parameters:
    603// - _: Crossing discriminator for the store operation; pass 0.
    604// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    605//
    606// Returns:
    607// - err: Nil when the epoch key is initialized; otherwise the current-realm or KV-store write error.
    608func (s *protocolFeeStore) InitializeAccrualEpoch(_ int, rlm realm) error {
    609 if !rlm.IsCurrent() {
    610 return errors.New(errSpoofedRealm)
    611 }
    612
    613 return s.kvStore.Set(0, rlm, StoreKeyAccrualEpoch.String(), int64(0))
    614}
    615
    616// GetAccrualEpoch reads the epoch under which new Gov/Staker accrual buckets are recorded.
    617//
    618// Returns:
    619// - epoch: The persisted current accrual epoch; the method panics if the key is missing or cannot be decoded as int64.
    620func (s *protocolFeeStore) GetAccrualEpoch() int64 {
    621 accrualEpoch, err := s.kvStore.GetInt64(StoreKeyAccrualEpoch.String())
    622 if err != nil {
    623 panic(err)
    624 }
    625
    626 return accrualEpoch
    627}
    628
    629// SetAccrualEpoch persists the current fee-accrual epoch.
    630//
    631// Parameters:
    632// - _: Crossing discriminator for the store operation; pass 0.
    633// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    634// - accrualEpoch: Epoch number assigned to newly collected Gov/Staker accrual buckets.
    635//
    636// Returns:
    637// - err: Nil when the epoch is persisted; otherwise the current-realm or KV-store write error.
    638func (s *protocolFeeStore) SetAccrualEpoch(_ int, rlm realm, accrualEpoch int64) error {
    639 if !rlm.IsCurrent() {
    640 return errors.New(errSpoofedRealm)
    641 }
    642
    643 return s.kvStore.Set(0, rlm, StoreKeyAccrualEpoch.String(), accrualEpoch)
    644}
    645
    646// handle accrualBuckets store data
    647//
    648// accrualBuckets holds, per token path, the gov/staker share collected during each
    649// accrual epoch that gov/staker has not folded into its accumulator yet. Folding
    650// consumes the oldest buckets first, so a token is settled in epoch order.
    651//
    652// Returns:
    653// - exists: True when the accrual-bucket store key is present in the KV store.
    654func (s *protocolFeeStore) HasAccrualBucketsStoreKey() bool {
    655 return s.kvStore.Has(StoreKeyAccrualBuckets.String())
    656}
    657
    658// InitializeAccrualBuckets creates the nested accrual-bucket tree.
    659//
    660// Parameters:
    661// - _: Crossing discriminator for the store operation; pass 0.
    662// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    663//
    664// Returns:
    665// - err: Nil when the bucket tree is initialized; otherwise the current-realm or KV-store write error.
    666func (s *protocolFeeStore) InitializeAccrualBuckets(_ int, rlm realm) error {
    667 if !rlm.IsCurrent() {
    668 return errors.New(errSpoofedRealm)
    669 }
    670
    671 return s.kvStore.Set(0, rlm, StoreKeyAccrualBuckets.String(), NewBPTreeN(16))
    672}
    673
    674func (s *protocolFeeStore) getAccrualBucketTree() *bptree.BPTree {
    675 accrualBuckets, err := s.kvStore.GetBPTree(StoreKeyAccrualBuckets.String())
    676 if err != nil {
    677 panic(err)
    678 }
    679
    680 return accrualBuckets
    681}
    682
    683func (s *protocolFeeStore) getTokenAccrualBucketTree(accrualBuckets *bptree.BPTree, tokenPath string) *bptree.BPTree {
    684 result := accrualBuckets.Get(tokenPath)
    685 if result == nil {
    686 return nil
    687 }
    688
    689 tokenBuckets, ok := result.(*bptree.BPTree)
    690 if !ok {
    691 panic(ufmt.Errorf("failed to cast result to *bptree.BPTree: %T", result))
    692 }
    693
    694 return tokenBuckets
    695}
    696
    697// GetAccrualBuckets returns up to limit of the oldest pending buckets of tokenPath in
    698// epoch order. A limit of zero or less returns every pending bucket.
    699//
    700// Parameters:
    701// - tokenPath: Token path whose pending Gov/Staker accrual buckets should be read.
    702// - limit: Maximum number of buckets to return; zero or a negative value returns all pending buckets.
    703//
    704// Returns:
    705// - epochs: Epoch numbers for the returned buckets, in ascending BP-tree iteration order.
    706// - amounts: Gov/Staker amounts for the returned epochs; amounts[i] corresponds to epochs[i].
    707func (s *protocolFeeStore) GetAccrualBuckets(tokenPath string, limit int) ([]int64, []int64) {
    708 epochs := []int64{}
    709 amounts := []int64{}
    710
    711 tokenBuckets := s.getTokenAccrualBucketTree(s.getAccrualBucketTree(), tokenPath)
    712 if tokenBuckets == nil {
    713 return epochs, amounts
    714 }
    715
    716 tokenBuckets.Iterate("", "", func(key string, value any) bool {
    717 if limit > 0 && len(epochs) >= limit {
    718 return true
    719 }
    720
    721 amount, ok := value.(int64)
    722 if !ok {
    723 panic(ufmt.Errorf("failed to cast result to int64: %T", value))
    724 }
    725
    726 epochs = append(epochs, decodeEpochKey(key))
    727 amounts = append(amounts, amount)
    728
    729 return false
    730 })
    731
    732 return epochs, amounts
    733}
    734
    735// AddAccrualBucket adds amount to the bucket of tokenPath at epoch.
    736//
    737// Parameters:
    738// - _: Crossing discriminator for the store operation; pass 0.
    739// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    740// - tokenPath: Token path whose Gov/Staker accrual bucket is updated.
    741// - epoch: Non-negative accrual epoch identifying the bucket; negative epochs panic during key encoding.
    742// - amount: Amount to add to the existing bucket value.
    743//
    744// Returns:
    745// - err: Nil when the bucket tree is persisted; otherwise the current-realm or KV-store write error.
    746func (s *protocolFeeStore) AddAccrualBucket(_ int, rlm realm, tokenPath string, epoch int64, amount int64) error {
    747 if !rlm.IsCurrent() {
    748 return errors.New(errSpoofedRealm)
    749 }
    750
    751 accrualBuckets := s.getAccrualBucketTree()
    752 tokenBuckets := s.getTokenAccrualBucketTree(accrualBuckets, tokenPath)
    753 if tokenBuckets == nil {
    754 tokenBuckets = NewBPTreeN(16)
    755 accrualBuckets.Set(tokenPath, tokenBuckets)
    756 }
    757
    758 key := encodeEpochKey(epoch)
    759 existing := int64(0)
    760 if result := tokenBuckets.Get(key); result != nil {
    761 current, ok := result.(int64)
    762 if !ok {
    763 panic(ufmt.Errorf("failed to cast result to int64: %T", result))
    764 }
    765 existing = current
    766 }
    767
    768 tokenBuckets.Set(key, gnsmath.SafeAddInt64(existing, amount))
    769
    770 return s.kvStore.Set(0, rlm, StoreKeyAccrualBuckets.String(), accrualBuckets)
    771}
    772
    773// RemoveAccrualBuckets drops the buckets of tokenPath at the given epochs. The token's
    774// tree is dropped as well once no bucket remains.
    775//
    776// Parameters:
    777// - _: Crossing discriminator for the store operation; pass 0.
    778// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    779// - tokenPath: Token path whose selected accrual buckets are removed.
    780// - epochs: Epoch numbers whose buckets should be deleted; an absent token or epoch is ignored.
    781//
    782// Returns:
    783// - err: Nil when removals are applied (including an absent token); otherwise the current-realm or KV-store write error.
    784func (s *protocolFeeStore) RemoveAccrualBuckets(_ int, rlm realm, tokenPath string, epochs []int64) error {
    785 if !rlm.IsCurrent() {
    786 return errors.New(errSpoofedRealm)
    787 }
    788
    789 accrualBuckets := s.getAccrualBucketTree()
    790 tokenBuckets := s.getTokenAccrualBucketTree(accrualBuckets, tokenPath)
    791 if tokenBuckets == nil {
    792 return nil
    793 }
    794
    795 for _, epoch := range epochs {
    796 tokenBuckets.Remove(encodeEpochKey(epoch))
    797 }
    798
    799 if tokenBuckets.Size() == 0 {
    800 accrualBuckets.Remove(tokenPath)
    801 }
    802
    803 return s.kvStore.Set(0, rlm, StoreKeyAccrualBuckets.String(), accrualBuckets)
    804}
    805
    806// handle accrualPendingTokens store data
    807//
    808// accrualPendingTokens is the set of token paths that still own at least one accrual
    809// bucket, so gov/staker can enumerate what it has to fold without scanning every token.
    810//
    811// Returns:
    812// - exists: True when the pending-token index key is present in the KV store.
    813func (s *protocolFeeStore) HasAccrualPendingTokensStoreKey() bool {
    814 return s.kvStore.Has(StoreKeyAccrualPendingTokens.String())
    815}
    816
    817// InitializeAccrualPendingTokens creates the index of tokens with pending accrual buckets.
    818//
    819// Parameters:
    820// - _: Crossing discriminator for the store operation; pass 0.
    821// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    822//
    823// Returns:
    824// - err: Nil when the pending-token index is initialized; otherwise the current-realm or KV-store write error.
    825func (s *protocolFeeStore) InitializeAccrualPendingTokens(_ int, rlm realm) error {
    826 if !rlm.IsCurrent() {
    827 return errors.New(errSpoofedRealm)
    828 }
    829
    830 return s.kvStore.Set(0, rlm, StoreKeyAccrualPendingTokens.String(), NewBPTreeN(16))
    831}
    832
    833func (s *protocolFeeStore) getAccrualPendingTokenTree() *bptree.BPTree {
    834 accrualPendingTokens, err := s.kvStore.GetBPTree(StoreKeyAccrualPendingTokens.String())
    835 if err != nil {
    836 panic(err)
    837 }
    838
    839 return accrualPendingTokens
    840}
    841
    842// GetAccrualPendingTokens returns token paths that still own accrual buckets.
    843//
    844// Returns:
    845// - tokenPaths: Token paths in the pending-accrual index, in BP-tree iteration order.
    846func (s *protocolFeeStore) GetAccrualPendingTokens() []string {
    847 return collectTreeKeys(s.getAccrualPendingTokenTree())
    848}
    849
    850// AddAccrualPendingToken adds tokenPath to the pending-accrual index.
    851//
    852// Parameters:
    853// - _: Crossing discriminator for the store operation; pass 0.
    854// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    855// - tokenPath: Token path with at least one accrual bucket pending.
    856//
    857// Returns:
    858// - err: Nil when tokenPath is already present or has been added; otherwise the current-realm or KV-store write error.
    859func (s *protocolFeeStore) AddAccrualPendingToken(_ int, rlm realm, tokenPath string) error {
    860 if !rlm.IsCurrent() {
    861 return errors.New(errSpoofedRealm)
    862 }
    863
    864 accrualPendingTokens := s.getAccrualPendingTokenTree()
    865 if accrualPendingTokens.Has(tokenPath) {
    866 return nil
    867 }
    868
    869 accrualPendingTokens.Set(tokenPath, true)
    870
    871 return s.kvStore.Set(0, rlm, StoreKeyAccrualPendingTokens.String(), accrualPendingTokens)
    872}
    873
    874// RemoveAccrualPendingToken drops one token from the set. It writes only when the
    875// token was listed.
    876//
    877// Parameters:
    878// - _: Crossing discriminator for the store operation; pass 0.
    879// - rlm: Propagated realm context for this store write; it must be current (`rlm.IsCurrent()`).
    880// - tokenPath: Token path to remove from the pending-accrual index.
    881//
    882// Returns:
    883// - err: Nil when tokenPath is absent or has been removed; otherwise the current-realm or KV-store write error.
    884func (s *protocolFeeStore) RemoveAccrualPendingToken(_ int, rlm realm, tokenPath string) error {
    885 if !rlm.IsCurrent() {
    886 return errors.New(errSpoofedRealm)
    887 }
    888
    889 accrualPendingTokens := s.getAccrualPendingTokenTree()
    890 if _, removed := accrualPendingTokens.Remove(tokenPath); !removed {
    891 return nil
    892 }
    893
    894 return s.kvStore.Set(0, rlm, StoreKeyAccrualPendingTokens.String(), accrualPendingTokens)
    895}
    896
    897func collectTreeKeys(tree *bptree.BPTree) []string {
    898 keys := make([]string, 0, tree.Size())
    899 tree.Iterate("", "", func(key string, _ any) bool {
    900 keys = append(keys, key)
    901 return false
    902 })
    903
    904 return keys
    905}
    906
    907func encodeEpochKey(epoch int64) string {
    908 if epoch < 0 {
    909 panic(ufmt.Sprintf("negative epoch not supported: %d", epoch))
    910 }
    911
    912 return utils.EncodeUint64(uint64(epoch))
    913}
    914
    915func decodeEpochKey(key string) int64 {
    916 return gnsmath.SafeUint64ToInt64(utils.DecodeUint64(key))
    917}
    918
    919// NewProtocolFeeStore creates a protocol-fee store backed by the provided KV store.
    920// This function is used by the upgrade system to create storage instances for each implementation.
    921//
    922// Parameters:
    923// - kvStore: Domain KV store used to persist protocol-fee state.
    924//
    925// Returns:
    926// - protocolFeeStore: An IProtocolFeeStore implementation backed by kvStore.
    927func NewProtocolFeeStore(kvStore store.KVStore) IProtocolFeeStore {
    928 return &protocolFeeStore{
    929 kvStore: kvStore,
    930 }
    931}
    932

    vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.