Search Apps Documentation Source Content File Folder Download Copy Actions Download

protocol_fee_unstaking.gno

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