github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/staking/handler.go (about)

     1  package staking
     2  
     3  import (
     4  	"time"
     5  
     6  	tmstrings "github.com/fibonacci-chain/fbc/libs/tendermint/libs/strings"
     7  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
     8  
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/keeper"
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/types"
    13  )
    14  
    15  func NewHandler(k keeper.Keeper) sdk.Handler {
    16  	return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
    17  		ctx.SetEventManager(sdk.NewEventManager())
    18  
    19  		switch msg := msg.(type) {
    20  		case types.MsgCreateValidator:
    21  			return handleMsgCreateValidator(ctx, msg, k)
    22  
    23  		case types.MsgEditValidator:
    24  			return handleMsgEditValidator(ctx, msg, k)
    25  
    26  		case types.MsgDelegate:
    27  			return handleMsgDelegate(ctx, msg, k)
    28  
    29  		case types.MsgBeginRedelegate:
    30  			return handleMsgBeginRedelegate(ctx, msg, k)
    31  
    32  		case types.MsgUndelegate:
    33  			return handleMsgUndelegate(ctx, msg, k)
    34  
    35  		default:
    36  			return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
    37  		}
    38  	}
    39  }
    40  
    41  // These functions assume everything has been authenticated,
    42  // now we just perform action and save
    43  
    44  func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k keeper.Keeper) (*sdk.Result, error) {
    45  	// check to see if the pubkey or sender has been registered before
    46  	if _, found := k.GetValidator(ctx, msg.ValidatorAddress); found {
    47  		return nil, ErrValidatorOwnerExists
    48  	}
    49  
    50  	if _, found := k.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(msg.PubKey)); found {
    51  		return nil, ErrValidatorPubKeyExists
    52  	}
    53  
    54  	if msg.Value.Denom != k.BondDenom(ctx) {
    55  		return nil, ErrBadDenom
    56  	}
    57  
    58  	if _, err := msg.Description.EnsureLength(); err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	if ctx.ConsensusParams() != nil {
    63  		tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey)
    64  		if !tmstrings.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) {
    65  			return nil, sdkerrors.Wrapf(
    66  				ErrValidatorPubKeyTypeNotSupported,
    67  				"got: %s, valid: %s", tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes,
    68  			)
    69  		}
    70  	}
    71  
    72  	validator := NewValidator(msg.ValidatorAddress, msg.PubKey, msg.Description)
    73  	commission := NewCommissionWithTime(
    74  		msg.Commission.Rate, msg.Commission.MaxRate,
    75  		msg.Commission.MaxChangeRate, ctx.BlockHeader().Time,
    76  	)
    77  	validator, err := validator.SetInitialCommission(commission)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	validator.MinSelfDelegation = msg.MinSelfDelegation
    83  
    84  	k.SetValidator(ctx, validator)
    85  	k.SetValidatorByConsAddr(ctx, validator)
    86  	k.SetNewValidatorByPowerIndex(ctx, validator)
    87  
    88  	// call the after-creation hook
    89  	k.AfterValidatorCreated(ctx, validator.OperatorAddress)
    90  
    91  	// move coins from the msg.Address account to a (self-delegation) delegator account
    92  	// the validator account and global shares are updated within here
    93  	// NOTE source will always be from a wallet which are unbonded
    94  	_, err = k.Delegate(ctx, msg.DelegatorAddress, msg.Value.Amount, sdk.Unbonded, validator, true)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	ctx.EventManager().EmitEvents(sdk.Events{
   100  		sdk.NewEvent(
   101  			types.EventTypeCreateValidator,
   102  			sdk.NewAttribute(types.AttributeKeyValidator, msg.ValidatorAddress.String()),
   103  			sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Value.Amount.String()),
   104  		),
   105  		sdk.NewEvent(
   106  			sdk.EventTypeMessage,
   107  			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
   108  			sdk.NewAttribute(sdk.AttributeKeySender, msg.DelegatorAddress.String()),
   109  		),
   110  	})
   111  
   112  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   113  }
   114  
   115  func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keeper.Keeper) (*sdk.Result, error) {
   116  	// validator must already be registered
   117  	validator, found := k.GetValidator(ctx, msg.ValidatorAddress)
   118  	if !found {
   119  		return nil, ErrNoValidatorFound
   120  	}
   121  
   122  	// replace all editable fields (clients should autofill existing values)
   123  	description, err := validator.Description.UpdateDescription(msg.Description)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	validator.Description = description
   129  
   130  	if msg.CommissionRate != nil {
   131  		commission, err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate)
   132  		if err != nil {
   133  			return nil, err
   134  		}
   135  
   136  		// call the before-modification hook since we're about to update the commission
   137  		k.BeforeValidatorModified(ctx, msg.ValidatorAddress)
   138  
   139  		validator.Commission = commission
   140  	}
   141  
   142  	if msg.MinSelfDelegation != nil {
   143  		if !msg.MinSelfDelegation.GT(validator.MinSelfDelegation) {
   144  			return nil, ErrMinSelfDelegationDecreased
   145  		}
   146  		if msg.MinSelfDelegation.GT(validator.Tokens) {
   147  			return nil, ErrSelfDelegationBelowMinimum
   148  		}
   149  
   150  		validator.MinSelfDelegation = (*msg.MinSelfDelegation)
   151  	}
   152  
   153  	k.SetValidator(ctx, validator)
   154  
   155  	ctx.EventManager().EmitEvents(sdk.Events{
   156  		sdk.NewEvent(
   157  			types.EventTypeEditValidator,
   158  			sdk.NewAttribute(types.AttributeKeyCommissionRate, validator.Commission.String()),
   159  			sdk.NewAttribute(types.AttributeKeyMinSelfDelegation, validator.MinSelfDelegation.String()),
   160  		),
   161  		sdk.NewEvent(
   162  			sdk.EventTypeMessage,
   163  			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
   164  			sdk.NewAttribute(sdk.AttributeKeySender, msg.ValidatorAddress.String()),
   165  		),
   166  	})
   167  
   168  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   169  }
   170  
   171  func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) (*sdk.Result, error) {
   172  	validator, found := k.GetValidator(ctx, msg.ValidatorAddress)
   173  	if !found {
   174  		return nil, ErrNoValidatorFound
   175  	}
   176  
   177  	if msg.Amount.Denom != k.BondDenom(ctx) {
   178  		return nil, ErrBadDenom
   179  	}
   180  
   181  	// NOTE: source funds are always unbonded
   182  	_, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount.Amount, sdk.Unbonded, validator, true)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	ctx.EventManager().EmitEvents(sdk.Events{
   188  		sdk.NewEvent(
   189  			types.EventTypeDelegate,
   190  			sdk.NewAttribute(types.AttributeKeyValidator, msg.ValidatorAddress.String()),
   191  			sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.Amount.String()),
   192  		),
   193  		sdk.NewEvent(
   194  			sdk.EventTypeMessage,
   195  			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
   196  			sdk.NewAttribute(sdk.AttributeKeySender, msg.DelegatorAddress.String()),
   197  		),
   198  	})
   199  
   200  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   201  }
   202  
   203  func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) (*sdk.Result, error) {
   204  	shares, err := k.ValidateUnbondAmount(
   205  		ctx, msg.DelegatorAddress, msg.ValidatorAddress, msg.Amount.Amount,
   206  	)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	if msg.Amount.Denom != k.BondDenom(ctx) {
   212  		return nil, ErrBadDenom
   213  	}
   214  
   215  	completionTime, err := k.Undelegate(ctx, msg.DelegatorAddress, msg.ValidatorAddress, shares)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime)
   221  	ctx.EventManager().EmitEvents(sdk.Events{
   222  		sdk.NewEvent(
   223  			types.EventTypeUnbond,
   224  			sdk.NewAttribute(types.AttributeKeyValidator, msg.ValidatorAddress.String()),
   225  			sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.Amount.String()),
   226  			sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)),
   227  		),
   228  		sdk.NewEvent(
   229  			sdk.EventTypeMessage,
   230  			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
   231  			sdk.NewAttribute(sdk.AttributeKeySender, msg.DelegatorAddress.String()),
   232  		),
   233  	})
   234  
   235  	return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil
   236  }
   237  
   238  func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) (*sdk.Result, error) {
   239  	shares, err := k.ValidateUnbondAmount(
   240  		ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.Amount.Amount,
   241  	)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	if msg.Amount.Denom != k.BondDenom(ctx) {
   247  		return nil, ErrBadDenom
   248  	}
   249  
   250  	completionTime, err := k.BeginRedelegation(
   251  		ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.ValidatorDstAddress, shares,
   252  	)
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  	completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime)
   258  	ctx.EventManager().EmitEvents(sdk.Events{
   259  		sdk.NewEvent(
   260  			types.EventTypeRedelegate,
   261  			sdk.NewAttribute(types.AttributeKeySrcValidator, msg.ValidatorSrcAddress.String()),
   262  			sdk.NewAttribute(types.AttributeKeyDstValidator, msg.ValidatorDstAddress.String()),
   263  			sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.Amount.String()),
   264  			sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)),
   265  		),
   266  		sdk.NewEvent(
   267  			sdk.EventTypeMessage,
   268  			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
   269  			sdk.NewAttribute(sdk.AttributeKeySender, msg.DelegatorAddress.String()),
   270  		),
   271  	})
   272  
   273  	return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil
   274  }