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 }