github.com/cosmos/cosmos-sdk@v0.50.10/x/distribution/keeper/msg_server.go (about) 1 package keeper 2 3 import ( 4 "context" 5 6 "github.com/hashicorp/go-metrics" 7 8 "cosmossdk.io/errors" 9 10 "github.com/cosmos/cosmos-sdk/telemetry" 11 sdk "github.com/cosmos/cosmos-sdk/types" 12 sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 13 "github.com/cosmos/cosmos-sdk/x/distribution/types" 14 govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" 15 ) 16 17 type msgServer struct { 18 Keeper 19 } 20 21 var _ types.MsgServer = msgServer{} 22 23 // NewMsgServerImpl returns an implementation of the distribution MsgServer interface 24 // for the provided Keeper. 25 func NewMsgServerImpl(keeper Keeper) types.MsgServer { 26 return &msgServer{Keeper: keeper} 27 } 28 29 func (k msgServer) SetWithdrawAddress(ctx context.Context, msg *types.MsgSetWithdrawAddress) (*types.MsgSetWithdrawAddressResponse, error) { 30 delegatorAddress, err := k.authKeeper.AddressCodec().StringToBytes(msg.DelegatorAddress) 31 if err != nil { 32 return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid delegator address: %s", err) 33 } 34 35 withdrawAddress, err := k.authKeeper.AddressCodec().StringToBytes(msg.WithdrawAddress) 36 if err != nil { 37 return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid withdraw address: %s", err) 38 } 39 40 err = k.SetWithdrawAddr(ctx, delegatorAddress, withdrawAddress) 41 if err != nil { 42 return nil, err 43 } 44 45 return &types.MsgSetWithdrawAddressResponse{}, nil 46 } 47 48 func (k msgServer) WithdrawDelegatorReward(ctx context.Context, msg *types.MsgWithdrawDelegatorReward) (*types.MsgWithdrawDelegatorRewardResponse, error) { 49 valAddr, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(msg.ValidatorAddress) 50 if err != nil { 51 return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid validator address: %s", err) 52 } 53 54 delegatorAddress, err := k.authKeeper.AddressCodec().StringToBytes(msg.DelegatorAddress) 55 if err != nil { 56 return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid delegator address: %s", err) 57 } 58 59 amount, err := k.WithdrawDelegationRewards(ctx, delegatorAddress, valAddr) 60 if err != nil { 61 return nil, err 62 } 63 64 defer func() { 65 for _, a := range amount { 66 if a.Amount.IsInt64() { 67 telemetry.SetGaugeWithLabels( 68 []string{"tx", "msg", "withdraw_reward"}, 69 float32(a.Amount.Int64()), 70 []metrics.Label{telemetry.NewLabel("denom", a.Denom)}, 71 ) 72 } 73 } 74 }() 75 76 return &types.MsgWithdrawDelegatorRewardResponse{Amount: amount}, nil 77 } 78 79 func (k msgServer) WithdrawValidatorCommission(ctx context.Context, msg *types.MsgWithdrawValidatorCommission) (*types.MsgWithdrawValidatorCommissionResponse, error) { 80 valAddr, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(msg.ValidatorAddress) 81 if err != nil { 82 return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid validator address: %s", err) 83 } 84 85 amount, err := k.Keeper.WithdrawValidatorCommission(ctx, valAddr) 86 if err != nil { 87 return nil, err 88 } 89 90 defer func() { 91 for _, a := range amount { 92 if a.Amount.IsInt64() { 93 telemetry.SetGaugeWithLabels( 94 []string{"tx", "msg", "withdraw_commission"}, 95 float32(a.Amount.Int64()), 96 []metrics.Label{telemetry.NewLabel("denom", a.Denom)}, 97 ) 98 } 99 } 100 }() 101 102 return &types.MsgWithdrawValidatorCommissionResponse{Amount: amount}, nil 103 } 104 105 func (k msgServer) FundCommunityPool(ctx context.Context, msg *types.MsgFundCommunityPool) (*types.MsgFundCommunityPoolResponse, error) { 106 depositor, err := k.authKeeper.AddressCodec().StringToBytes(msg.Depositor) 107 if err != nil { 108 return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid depositor address: %s", err) 109 } 110 111 if err := validateAmount(msg.Amount); err != nil { 112 return nil, err 113 } 114 115 if err := k.Keeper.FundCommunityPool(ctx, msg.Amount, depositor); err != nil { 116 return nil, err 117 } 118 119 return &types.MsgFundCommunityPoolResponse{}, nil 120 } 121 122 func (k msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { 123 if err := k.validateAuthority(msg.Authority); err != nil { 124 return nil, err 125 } 126 127 if (!msg.Params.BaseProposerReward.IsNil() && !msg.Params.BaseProposerReward.IsZero()) || //nolint:staticcheck // deprecated but kept for backwards compatibility 128 (!msg.Params.BonusProposerReward.IsNil() && !msg.Params.BonusProposerReward.IsZero()) { //nolint:staticcheck // deprecated but kept for backwards compatibility 129 return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "cannot update base or bonus proposer reward because these are deprecated fields") 130 } 131 132 if err := msg.Params.ValidateBasic(); err != nil { 133 return nil, err 134 } 135 136 if err := k.Params.Set(ctx, msg.Params); err != nil { 137 return nil, err 138 } 139 140 return &types.MsgUpdateParamsResponse{}, nil 141 } 142 143 func (k msgServer) CommunityPoolSpend(ctx context.Context, msg *types.MsgCommunityPoolSpend) (*types.MsgCommunityPoolSpendResponse, error) { 144 if err := k.validateAuthority(msg.Authority); err != nil { 145 return nil, err 146 } 147 148 if err := validateAmount(msg.Amount); err != nil { 149 return nil, err 150 } 151 152 recipient, err := k.authKeeper.AddressCodec().StringToBytes(msg.Recipient) 153 if err != nil { 154 return nil, err 155 } 156 157 if k.bankKeeper.BlockedAddr(recipient) { 158 return nil, errors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive external funds", msg.Recipient) 159 } 160 161 if err := k.DistributeFromFeePool(ctx, msg.Amount, recipient); err != nil { 162 return nil, err 163 } 164 165 logger := k.Logger(ctx) 166 logger.Info("transferred from the community pool to recipient", "amount", msg.Amount.String(), "recipient", msg.Recipient) 167 168 return &types.MsgCommunityPoolSpendResponse{}, nil 169 } 170 171 func (k msgServer) DepositValidatorRewardsPool(ctx context.Context, msg *types.MsgDepositValidatorRewardsPool) (*types.MsgDepositValidatorRewardsPoolResponse, error) { 172 depositor, err := k.authKeeper.AddressCodec().StringToBytes(msg.Depositor) 173 if err != nil { 174 return nil, err 175 } 176 177 // deposit coins from depositor's account to the distribution module 178 if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, depositor, types.ModuleName, msg.Amount); err != nil { 179 return nil, err 180 } 181 182 valAddr, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(msg.ValidatorAddress) 183 if err != nil { 184 return nil, err 185 } 186 187 validator, err := k.stakingKeeper.Validator(ctx, valAddr) 188 if err != nil { 189 return nil, err 190 } 191 192 if validator == nil { 193 return nil, errors.Wrapf(types.ErrNoValidatorExists, msg.ValidatorAddress) 194 } 195 196 // Allocate tokens from the distribution module to the validator, which are 197 // then distributed to the validator's delegators. 198 reward := sdk.NewDecCoinsFromCoins(msg.Amount...) 199 if err = k.AllocateTokensToValidator(ctx, validator, reward); err != nil { 200 return nil, err 201 } 202 203 logger := k.Logger(ctx) 204 logger.Info( 205 "transferred from rewards to validator rewards pool", 206 "depositor", msg.Depositor, 207 "amount", msg.Amount.String(), 208 "validator", msg.ValidatorAddress, 209 ) 210 211 return &types.MsgDepositValidatorRewardsPoolResponse{}, nil 212 } 213 214 func (k *Keeper) validateAuthority(authority string) error { 215 if _, err := k.authKeeper.AddressCodec().StringToBytes(authority); err != nil { 216 return sdkerrors.ErrInvalidAddress.Wrapf("invalid authority address: %s", err) 217 } 218 219 if k.authority != authority { 220 return errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, authority) 221 } 222 223 return nil 224 } 225 226 func validateAmount(amount sdk.Coins) error { 227 if amount == nil { 228 return errors.Wrap(sdkerrors.ErrInvalidCoins, "amount cannot be nil") 229 } 230 231 if err := amount.Validate(); err != nil { 232 return errors.Wrap(sdkerrors.ErrInvalidCoins, amount.String()) 233 } 234 235 return nil 236 }