Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

protocol_fee_reward_manager.gno

8.49 Kb · 243 lines
  1package staker
  2
  3import (
  4	bptree "gno.land/p/nt/bptree/v0"
  5	ufmt "gno.land/p/nt/ufmt/v0"
  6
  7	u256 "gno.land/p/gnoswap/uint256/v1"
  8)
  9
 10// ProtocolFeeRewardManager distributes protocol fees to stakers.
 11//
 12// Protocol fees arrive in many tokens, so the manager keeps one accumulator per token
 13// instead of a single one. A stake change never touches those accumulators: it advances
 14// the accrual epoch, records the total stake in force from that epoch, and appends one
 15// event for an ordinary add/remove. Redelegate performs a remove plus an add and
 16// therefore appends two events. The per-token work happens when a token is collected,
 17// so stake-change cost does not depend on how many tokens ever collected a fee.
 18type ProtocolFeeRewardManager struct {
 19	// rewardStates maps a reward ID to the ProtocolFeeRewardState tracking that staker
 20	rewardStates *bptree.BPTree // rewardID -> *ProtocolFeeRewardState
 21	// tokenAccumulators maps a token path to its ProtocolFeeTokenAccumulator
 22	tokenAccumulators *bptree.BPTree // tokenPath -> *ProtocolFeeTokenAccumulator
 23	// currentEpoch is the accrual epoch in force, mirrored from protocol_fee
 24	currentEpoch int64
 25	// totalStakedAmount is the total amount currently staked
 26	totalStakedAmount int64
 27	// totalStakedHistory records the total staked amount in force from each epoch
 28	totalStakedHistory *UintTree // epoch -> int64
 29	// accumulatedTimestamp is the last timestamp at which the accrual state moved: a fold or a stake change
 30	accumulatedTimestamp int64
 31}
 32
 33// NewProtocolFeeRewardManager creates a new instance of ProtocolFeeRewardManager.
 34//
 35// Returns:
 36//   - *ProtocolFeeRewardManager: new protocol fee reward manager instance
 37func NewProtocolFeeRewardManager() *ProtocolFeeRewardManager {
 38	totalStakedHistory := NewUintTree()
 39	totalStakedHistory.Set(0, int64(0))
 40
 41	return &ProtocolFeeRewardManager{
 42		rewardStates:         bptree.NewBPTreeN(16),
 43		tokenAccumulators:    bptree.NewBPTreeN(16),
 44		currentEpoch:         0,
 45		totalStakedAmount:    0,
 46		totalStakedHistory:   totalStakedHistory,
 47		accumulatedTimestamp: 0,
 48	}
 49}
 50
 51/* Getters */
 52
 53// GetRewardState retrieves the reward state identified by rewardID.
 54// Missing IDs return nil and false; a stored value of the wrong type returns
 55// an error.
 56//
 57// Parameters:
 58//   - rewardID: identifier of the staker reward state to retrieve
 59//
 60// Returns:
 61//   - *ProtocolFeeRewardState: stored reward state, or nil when rewardID is absent or invalid
 62//   - bool: true when a correctly typed reward state was found
 63//   - error: nil when absent or found; a cast error when the stored value has the wrong type
 64func (p *ProtocolFeeRewardManager) GetRewardState(rewardID string) (*ProtocolFeeRewardState, bool, error) {
 65	ri := p.rewardStates.Get(rewardID)
 66	if ri == nil {
 67		return nil, false, nil
 68	}
 69	rs, castOk := ri.(*ProtocolFeeRewardState)
 70	if !castOk {
 71		return nil, false, ufmt.Errorf(errFailedToCastRewardState, ri)
 72	}
 73	return rs, true, nil
 74}
 75
 76// GetTokenAccumulator returns the accumulator of tokenPath, or false when the token
 77// never had a fee folded in.
 78//
 79// Parameters:
 80//   - tokenPath: token package path whose protocol-fee accumulator is requested
 81//
 82// Returns:
 83//   - *ProtocolFeeTokenAccumulator: accumulator for tokenPath, or nil when none exists
 84//   - bool: true when tokenPath has a folded-fee accumulator
 85func (p *ProtocolFeeRewardManager) GetTokenAccumulator(tokenPath string) (*ProtocolFeeTokenAccumulator, bool) {
 86	ai := p.tokenAccumulators.Get(tokenPath)
 87	if ai == nil {
 88		return nil, false
 89	}
 90	accumulator, castOk := ai.(*ProtocolFeeTokenAccumulator)
 91	if !castOk {
 92		panic(ufmt.Sprintf("failed to cast token accumulator: %T", ai))
 93	}
 94	return accumulator, true
 95}
 96
 97// GetTokenPaths returns every token path that had a fee folded in, in key order.
 98//
 99// Returns:
100//   - []string: token paths present in the accumulator tree, ordered by tree key
101func (p *ProtocolFeeRewardManager) GetTokenPaths() []string {
102	tokenPaths := make([]string, 0, p.tokenAccumulators.Size())
103	p.tokenAccumulators.Iterate("", "", func(key string, _ any) bool {
104		tokenPaths = append(tokenPaths, key)
105		return false
106	})
107	return tokenPaths
108}
109
110// GetAccumulatedProtocolFeeX128PerStake returns the accumulated fee per stake of tokenPath
111// (scaled by 2^128), or nil when the token never had a fee folded in.
112//
113// Parameters:
114//   - tokenPath: token package path whose accumulated per-stake fee is requested
115//
116// Returns:
117//   - *u256.Uint: accumulated fee per stake scaled by 2^128, or nil when tokenPath has no accumulator
118func (p *ProtocolFeeRewardManager) GetAccumulatedProtocolFeeX128PerStake(tokenPath string) *u256.Uint {
119	accumulator, ok := p.GetTokenAccumulator(tokenPath)
120	if !ok {
121		return nil
122	}
123	return accumulator.GetAccumulatedX128PerStake()
124}
125
126// GetProtocolFeeAmount returns the total fee amount folded in for tokenPath.
127//
128// Parameters:
129//   - tokenPath: token package path whose folded protocol-fee amount is requested
130//
131// Returns:
132//   - int64: total fee amount folded for tokenPath, or zero when no accumulator exists
133func (p *ProtocolFeeRewardManager) GetProtocolFeeAmount(tokenPath string) int64 {
134	accumulator, ok := p.GetTokenAccumulator(tokenPath)
135	if !ok {
136		return 0
137	}
138	return accumulator.GetProtocolFeeAmount()
139}
140
141// GetCurrentEpoch returns the accrual epoch currently in force.
142//
143// Returns:
144//   - int64: current protocol-fee accrual epoch
145func (p *ProtocolFeeRewardManager) GetCurrentEpoch() int64 {
146	return p.currentEpoch
147}
148
149// GetTotalStakedAmount returns the total amount currently staked.
150//
151// Returns:
152//   - int64: current total staked amount
153func (p *ProtocolFeeRewardManager) GetTotalStakedAmount() int64 {
154	return p.totalStakedAmount
155}
156
157// GetTotalStakedAmountAt returns the total staked amount in force during epoch,
158// using the latest recorded stake amount at or before that epoch.
159//
160// Parameters:
161//   - epoch: accrual epoch whose effective total stake is requested
162//
163// Returns:
164//   - int64: total stake recorded at or before epoch, or zero for a negative epoch
165func (p *ProtocolFeeRewardManager) GetTotalStakedAmountAt(epoch int64) int64 {
166	if epoch < 0 {
167		return 0
168	}
169
170	totalStakedAmount := int64(0)
171	p.totalStakedHistory.ReverseIterate(0, epoch, func(_ int64, value any) bool {
172		amount, castOk := value.(int64)
173		if !castOk {
174			panic(ufmt.Sprintf("failed to cast total staked amount: %T", value))
175		}
176		totalStakedAmount = amount
177		return true
178	})
179
180	return totalStakedAmount
181}
182
183// GetAccumulatedTimestamp returns the last timestamp at which fee accrual
184// state moved through a fold or stake change.
185//
186// Returns:
187//   - int64: last accumulated-state update timestamp
188func (p *ProtocolFeeRewardManager) GetAccumulatedTimestamp() int64 {
189	return p.accumulatedTimestamp
190}
191
192/* Setters */
193
194// SetRewardState stores rewardState under rewardID.
195//
196// Parameters:
197//   - rewardID: identifier under which the staker reward state is stored
198//   - rewardState: reward state to associate with rewardID
199func (p *ProtocolFeeRewardManager) SetRewardState(rewardID string, rewardState *ProtocolFeeRewardState) {
200	p.rewardStates.Set(rewardID, rewardState)
201}
202
203// SetTokenAccumulator stores accumulator under tokenPath.
204//
205// Parameters:
206//   - tokenPath: token package path used as the accumulator key
207//   - accumulator: protocol-fee accumulator to store for tokenPath
208func (p *ProtocolFeeRewardManager) SetTokenAccumulator(tokenPath string, accumulator *ProtocolFeeTokenAccumulator) {
209	p.tokenAccumulators.Set(tokenPath, accumulator)
210}
211
212// SetCurrentEpoch records the accrual epoch currently in force.
213//
214// Parameters:
215//   - epoch: new current protocol-fee accrual epoch
216func (p *ProtocolFeeRewardManager) SetCurrentEpoch(epoch int64) {
217	p.currentEpoch = epoch
218}
219
220// SetTotalStakedAmount records the total amount currently staked.
221//
222// Parameters:
223//   - totalStakedAmount: new total staked amount
224func (p *ProtocolFeeRewardManager) SetTotalStakedAmount(totalStakedAmount int64) {
225	p.totalStakedAmount = totalStakedAmount
226}
227
228// SetTotalStakedAmountAt records the total staked amount in force from epoch on.
229//
230// Parameters:
231//   - epoch: first accrual epoch at which totalStakedAmount is in force
232//   - totalStakedAmount: total stake amount to record from epoch onward
233func (p *ProtocolFeeRewardManager) SetTotalStakedAmountAt(epoch int64, totalStakedAmount int64) {
234	p.totalStakedHistory.Set(epoch, totalStakedAmount)
235}
236
237// SetAccumulatedTimestamp records the timestamp at which accrual state last moved.
238//
239// Parameters:
240//   - accumulatedTimestamp: timestamp to record for the latest fold or stake change
241func (p *ProtocolFeeRewardManager) SetAccumulatedTimestamp(accumulatedTimestamp int64) {
242	p.accumulatedTimestamp = accumulatedTimestamp
243}