github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/staking/types/commission.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/tendermint/go-amino"
     8  
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  )
    11  
    12  type (
    13  	// Commission defines a commission parameters for a given validator
    14  	Commission struct {
    15  		CommissionRates `json:"commission_rates" yaml:"commission_rates"`
    16  		UpdateTime      time.Time `json:"update_time" yaml:"update_time"` // the last time the commission rate was changed
    17  	}
    18  
    19  	// CommissionRates defines the initial commission rates to be used for creating a validator
    20  	CommissionRates struct {
    21  		// the commission rate charged to delegators, as a fraction
    22  		Rate sdk.Dec `json:"rate" yaml:"rate"`
    23  		// maximum commission rate which validator can ever charge, as a fraction
    24  		MaxRate sdk.Dec `json:"max_rate" yaml:"max_rate"`
    25  		// maximum daily increase of the validator commission, as a fraction
    26  		MaxChangeRate sdk.Dec `json:"max_change_rate" yaml:"max_change_rate"`
    27  	}
    28  )
    29  
    30  // NewCommissionRates returns an initialized validator commission rates
    31  func NewCommissionRates(rate, maxRate, maxChangeRate sdk.Dec) CommissionRates {
    32  	return CommissionRates{
    33  		Rate:          rate,
    34  		MaxRate:       maxRate,
    35  		MaxChangeRate: maxChangeRate,
    36  	}
    37  }
    38  
    39  // NewCommission returns an initialized validator commission.
    40  func NewCommission(rate, maxRate, maxChangeRate sdk.Dec) Commission {
    41  	return Commission{
    42  		CommissionRates: NewCommissionRates(rate, maxRate, maxChangeRate),
    43  		UpdateTime:      time.Unix(0, 0).UTC(),
    44  	}
    45  }
    46  
    47  // NewCommissionWithTime returns an initialized validator commission with a specified update time which should be the
    48  // current block BFT time
    49  func NewCommissionWithTime(rate, maxRate, maxChangeRate sdk.Dec, updatedAt time.Time) Commission {
    50  	return Commission{
    51  		CommissionRates: NewCommissionRates(rate, maxRate, maxChangeRate),
    52  		UpdateTime:      updatedAt,
    53  	}
    54  }
    55  
    56  // Equal checks if the given Commission object is equal to the receiving Commission object
    57  func (c Commission) Equal(c2 Commission) bool {
    58  	return c.Rate.Equal(c2.Rate) &&
    59  		c.MaxRate.Equal(c2.MaxRate) &&
    60  		c.MaxChangeRate.Equal(c2.MaxChangeRate) &&
    61  		c.UpdateTime.Equal(c2.UpdateTime)
    62  }
    63  
    64  // String implements the Stringer interface for a Commission
    65  func (c Commission) String() string {
    66  	return fmt.Sprintf("rate: %s, maxRate: %s, maxChangeRate: %s, updateTime: %s",
    67  		c.Rate, c.MaxRate, c.MaxChangeRate, c.UpdateTime,
    68  	)
    69  }
    70  
    71  func (c *Commission) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error {
    72  	var dataLen uint64 = 0
    73  	var subData []byte
    74  	var timeUpdated bool
    75  
    76  	for {
    77  		data = data[dataLen:]
    78  
    79  		if len(data) == 0 {
    80  			break
    81  		}
    82  
    83  		pos, pbType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0])
    84  		if err != nil {
    85  			return err
    86  		}
    87  		data = data[1:]
    88  
    89  		if pbType != amino.Typ3_ByteLength {
    90  			return fmt.Errorf("Commission : all fields type should be 2")
    91  		}
    92  
    93  		var n int
    94  		dataLen, n, err = amino.DecodeUvarint(data)
    95  		if err != nil {
    96  			return err
    97  		}
    98  		data = data[n:]
    99  		if len(data) < int(dataLen) {
   100  			return fmt.Errorf("invalid data len")
   101  		}
   102  		subData = data[:dataLen]
   103  
   104  		switch pos {
   105  		case 1:
   106  			if err = c.CommissionRates.UnmarshalFromAmino(cdc, subData); err != nil {
   107  				return err
   108  			}
   109  		case 2:
   110  			c.UpdateTime, _, err = amino.DecodeTime(subData)
   111  			if err != nil {
   112  				return err
   113  			}
   114  			timeUpdated = true
   115  		default:
   116  			return fmt.Errorf("unexpect feild num %d", pos)
   117  		}
   118  	}
   119  	if !timeUpdated {
   120  		c.UpdateTime = amino.ZeroTime
   121  	}
   122  	return nil
   123  }
   124  
   125  // Validate performs basic sanity validation checks of initial commission parameters
   126  // If validation fails, an SDK error is returned
   127  func (c CommissionRates) Validate() sdk.Error {
   128  	switch {
   129  	case c.MaxRate.LT(sdk.ZeroDec()):
   130  		// max rate cannot be negative
   131  		return ErrCommissionNegative()
   132  
   133  	case c.MaxRate.GT(sdk.OneDec()):
   134  		// max rate cannot be greater than 1
   135  		return ErrCommissionHuge()
   136  
   137  	case c.Rate.LT(sdk.ZeroDec()):
   138  		// rate cannot be negative
   139  		return ErrCommissionNegative()
   140  
   141  	case c.Rate.GT(c.MaxRate):
   142  		// rate cannot be greater than the max rate
   143  		return ErrCommissionGTMaxRate()
   144  
   145  	case c.MaxChangeRate.LT(sdk.ZeroDec()):
   146  		// change rate cannot be negative
   147  		return ErrCommissionChangeRateNegative()
   148  
   149  	case c.MaxChangeRate.GT(c.MaxRate):
   150  		// change rate cannot be greater than the max rate
   151  		return ErrCommissionChangeRateGTMaxRate()
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // ValidateNewRate performs basic sanity validation checks of a new commission rate
   158  // If validation fails, an SDK error is returned.
   159  func (c Commission) ValidateNewRate(newRate sdk.Dec, blockTime time.Time) sdk.Error {
   160  	switch {
   161  	case blockTime.Sub(c.UpdateTime).Hours() < DefaultValidateRateUpdateInterval:
   162  		// new rate cannot be changed more than once within 24 hours
   163  		return ErrCommissionUpdateTime()
   164  
   165  	case newRate.LT(sdk.ZeroDec()):
   166  		// new rate cannot be negative
   167  		return ErrCommissionNegative()
   168  
   169  	case newRate.GT(c.MaxRate):
   170  		// new rate cannot be greater than the max rate
   171  		return ErrCommissionGTMaxRate()
   172  
   173  		//MaxChangeRate is 0,ignore it
   174  		//case newRate.Sub(c.Rate).GT(c.MaxChangeRate):
   175  		//	// new rate % points change cannot be greater than the max change rate
   176  		//	return ErrCommissionGTMaxChangeRate()
   177  	}
   178  
   179  	return nil
   180  }
   181  
   182  func (c *CommissionRates) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error {
   183  	var dataLen uint64 = 0
   184  	var subData []byte
   185  
   186  	for {
   187  		data = data[dataLen:]
   188  
   189  		if len(data) == 0 {
   190  			break
   191  		}
   192  
   193  		pos, pbType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0])
   194  		if err != nil {
   195  			return err
   196  		}
   197  		data = data[1:]
   198  
   199  		if pbType != amino.Typ3_ByteLength {
   200  			return fmt.Errorf("CommissionRatestype : all fields type should be 2")
   201  		}
   202  
   203  		var n int
   204  		dataLen, n, err = amino.DecodeUvarint(data)
   205  		if err != nil {
   206  			return err
   207  		}
   208  		data = data[n:]
   209  		if len(data) < int(dataLen) {
   210  			return fmt.Errorf("invalid data len")
   211  		}
   212  		subData = data[:dataLen]
   213  
   214  		switch pos {
   215  		case 1:
   216  			if err = c.Rate.UnmarshalFromAmino(cdc, subData); err != nil {
   217  				return err
   218  			}
   219  		case 2:
   220  			if err = c.MaxRate.UnmarshalFromAmino(cdc, subData); err != nil {
   221  				return err
   222  			}
   223  		case 3:
   224  			if err = c.MaxChangeRate.UnmarshalFromAmino(cdc, subData); err != nil {
   225  				return err
   226  			}
   227  		default:
   228  			return fmt.Errorf("unexpect feild num %d", pos)
   229  		}
   230  	}
   231  	return nil
   232  }