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_unstaking.gno

3.66 Kb · 134 lines
  1package staker
  2
  3import (
  4	"chain"
  5	"errors"
  6
  7	"gno.land/p/gnoswap/gnsmath"
  8	prbac "gno.land/p/gnoswap/rbac"
  9	"gno.land/p/gnoswap/utils"
 10	"gno.land/r/gnoswap/access"
 11	"gno.land/r/gnoswap/common"
 12	"gno.land/r/gnoswap/halt"
 13
 14	pf "gno.land/r/gnoswap/protocol_fee"
 15)
 16
 17// GetUnstakingFee returns the current unstaking fee rate in basis points.
 18func (s *stakerV1) GetUnstakingFee() uint64 { return s.store.GetUnstakingFee() }
 19
 20// handleStakingRewardFee calculates and applies the unstaking fee.
 21func (s *stakerV1) handleStakingRewardFee(
 22	_ int,
 23	rlm realm,
 24	tokenPath string,
 25	amount int64,
 26	internal bool,
 27) (int64, int64, error) {
 28	unstakingFee := s.GetUnstakingFee()
 29	if unstakingFee == 0 {
 30		s.addToProtocolFee(0, rlm)
 31		return amount, 0, nil
 32	}
 33
 34	// Do not change the order of the operation.
 35	feeAmount := gnsmath.SafeMulDivInt64(amount, gnsmath.SafeUint64ToInt64(unstakingFee), 10000)
 36	if feeAmount < 0 {
 37		return 0, 0, errors.New("fee amount cannot be negative")
 38	}
 39
 40	if feeAmount == 0 {
 41		s.addToProtocolFee(0, rlm)
 42		return amount, 0, nil
 43	}
 44
 45	if internal {
 46		tokenPath = GNS_TOKEN_KEY
 47	}
 48
 49	s.addPendingProtocolFee(0, rlm, tokenPath, feeAmount)
 50	s.addToProtocolFee(0, rlm)
 51
 52	return gnsmath.SafeSubInt64(amount, feeAmount), feeAmount, nil
 53}
 54
 55func (s *stakerV1) addPendingProtocolFee(_ int, rlm realm, tokenPath string, amount int64) {
 56	if amount <= 0 {
 57		return
 58	}
 59
 60	existingProtocolFees := s.store.GetPendingProtocolFees()
 61	pendingProtocolFees := make(map[string]int64)
 62	for pendingTokenPath, pendingAmount := range existingProtocolFees {
 63		pendingProtocolFees[pendingTokenPath] = pendingAmount
 64	}
 65	pendingProtocolFees[tokenPath] = gnsmath.SafeAddInt64(pendingProtocolFees[tokenPath], amount)
 66	if err := s.store.SetPendingProtocolFees(0, rlm, pendingProtocolFees); err != nil {
 67		panic(err)
 68	}
 69}
 70
 71// addToProtocolFee sends pending staker protocol fees to the protocol fee realm.
 72// It is best-effort: when protocol fee collection is halted, it keeps pending
 73// storage unchanged; otherwise it rebuilds pending storage with only entries
 74// that could not be added, removing successful and non-positive entries.
 75func (s *stakerV1) addToProtocolFee(_ int, rlm realm) {
 76	pendingProtocolFees := s.store.GetPendingProtocolFees()
 77	if len(pendingProtocolFees) == 0 || halt.IsHaltedProtocolFee() {
 78		return
 79	}
 80
 81	protocolFeeAddr := access.MustGetAddress(prbac.ROLE_PROTOCOL_FEE.String())
 82	remainingProtocolFees := make(map[string]int64)
 83	for tokenPath, amount := range pendingProtocolFees {
 84		if amount <= 0 {
 85			continue
 86		}
 87
 88		common.SafeGRC20Approve(cross(rlm), tokenPath, protocolFeeAddr, amount)
 89		if err := pf.AddToProtocolFee(cross(rlm), tokenPath, amount); err != nil {
 90			remainingProtocolFees[tokenPath] = amount
 91			continue
 92		}
 93	}
 94
 95	if err := s.store.SetPendingProtocolFees(0, rlm, remainingProtocolFees); err != nil {
 96		panic(err)
 97	}
 98}
 99
100// SetUnStakingFee sets the unstaking fee rate in basis points.
101// Only admin or governance can call this function.
102func (s *stakerV1) SetUnStakingFee(_ int, rlm realm, fee uint64) {
103	if !rlm.IsCurrent() {
104		panic(errors.New(errSpoofedRealm))
105	}
106
107	halt.AssertIsNotHaltedStaker()
108
109	previousRealm := rlm.Previous()
110	caller := previousRealm.Address()
111	access.AssertIsAdminOrGovernance(caller)
112
113	assertIsValidFeeRate(fee)
114
115	prevUnStakingFee := s.GetUnstakingFee()
116
117	err := s.setUnStakingFee(0, rlm, fee)
118	if err != nil {
119		panic(err)
120	}
121
122	chain.Emit(
123		"SetUnStakingFee",
124		"prevAddr", caller.String(),
125		"prevRealm", previousRealm.PkgPath(),
126		"prevFee", utils.FormatUint(prevUnStakingFee),
127		"newFee", utils.FormatUint(fee),
128	)
129}
130
131// setUnStakingFee internally updates the unstaking fee.
132func (s *stakerV1) setUnStakingFee(_ int, rlm realm, fee uint64) error {
133	return s.store.SetUnstakingFee(0, rlm, fee)
134}