github.com/cosmos/cosmos-sdk@v0.50.10/x/distribution/client/cli/tx.go (about) 1 package cli 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/spf13/cobra" 8 "github.com/spf13/pflag" 9 10 "cosmossdk.io/core/address" 11 12 "github.com/cosmos/cosmos-sdk/client" 13 "github.com/cosmos/cosmos-sdk/client/flags" 14 "github.com/cosmos/cosmos-sdk/client/tx" 15 sdk "github.com/cosmos/cosmos-sdk/types" 16 "github.com/cosmos/cosmos-sdk/version" 17 "github.com/cosmos/cosmos-sdk/x/distribution/types" 18 ) 19 20 // Transaction flags for the x/distribution module 21 var ( 22 FlagCommission = "commission" 23 FlagMaxMessagesPerTx = "max-msgs" 24 ) 25 26 const ( 27 MaxMessagesPerTxDefault = 0 28 ) 29 30 // NewTxCmd returns a root CLI command handler for all x/distribution transaction commands. 31 func NewTxCmd(valAc, ac address.Codec) *cobra.Command { 32 distTxCmd := &cobra.Command{ 33 Use: types.ModuleName, 34 Short: "Distribution transactions subcommands", 35 DisableFlagParsing: true, 36 SuggestionsMinimumDistance: 2, 37 RunE: client.ValidateCmd, 38 } 39 40 distTxCmd.AddCommand( 41 NewWithdrawRewardsCmd(valAc, ac), 42 NewWithdrawAllRewardsCmd(valAc, ac), 43 NewSetWithdrawAddrCmd(ac), 44 NewFundCommunityPoolCmd(ac), 45 NewDepositValidatorRewardsPoolCmd(valAc, ac), 46 ) 47 48 return distTxCmd 49 } 50 51 type newGenerateOrBroadcastFunc func(client.Context, *pflag.FlagSet, ...sdk.Msg) error 52 53 func newSplitAndApply( 54 genOrBroadcastFn newGenerateOrBroadcastFunc, clientCtx client.Context, 55 fs *pflag.FlagSet, msgs []sdk.Msg, chunkSize int, 56 ) error { 57 if chunkSize == 0 { 58 return genOrBroadcastFn(clientCtx, fs, msgs...) 59 } 60 61 // split messages into slices of length chunkSize 62 totalMessages := len(msgs) 63 for i := 0; i < len(msgs); i += chunkSize { 64 65 sliceEnd := i + chunkSize 66 if sliceEnd > totalMessages { 67 sliceEnd = totalMessages 68 } 69 70 msgChunk := msgs[i:sliceEnd] 71 if err := genOrBroadcastFn(clientCtx, fs, msgChunk...); err != nil { 72 return err 73 } 74 } 75 76 return nil 77 } 78 79 // NewWithdrawRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. 80 func NewWithdrawRewardsCmd(valCodec, ac address.Codec) *cobra.Command { 81 bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix() 82 83 cmd := &cobra.Command{ 84 Use: "withdraw-rewards [validator-addr]", 85 Short: "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator", 86 Long: strings.TrimSpace( 87 fmt.Sprintf(`Withdraw rewards from a given delegation address, 88 and optionally withdraw validator commission if the delegation address given is a validator operator. 89 90 Example: 91 $ %s tx distribution withdraw-rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey 92 $ %s tx distribution withdraw-rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey --commission 93 `, 94 version.AppName, bech32PrefixValAddr, version.AppName, bech32PrefixValAddr, 95 ), 96 ), 97 Args: cobra.ExactArgs(1), 98 RunE: func(cmd *cobra.Command, args []string) error { 99 clientCtx, err := client.GetClientTxContext(cmd) 100 if err != nil { 101 return err 102 } 103 delAddr, err := ac.BytesToString(clientCtx.GetFromAddress()) 104 if err != nil { 105 return err 106 } 107 108 _, err = valCodec.StringToBytes(args[0]) 109 if err != nil { 110 return err 111 } 112 113 msgs := []sdk.Msg{types.NewMsgWithdrawDelegatorReward(delAddr, args[0])} 114 115 if commission, _ := cmd.Flags().GetBool(FlagCommission); commission { 116 msgs = append(msgs, types.NewMsgWithdrawValidatorCommission(args[0])) 117 } 118 119 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msgs...) 120 }, 121 } 122 123 cmd.Flags().Bool(FlagCommission, false, "Withdraw the validator's commission in addition to the rewards") 124 flags.AddTxFlagsToCmd(cmd) 125 126 return cmd 127 } 128 129 // NewWithdrawAllRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. 130 func NewWithdrawAllRewardsCmd(valCodec, ac address.Codec) *cobra.Command { 131 cmd := &cobra.Command{ 132 Use: "withdraw-all-rewards", 133 Short: "withdraw all delegations rewards for a delegator", 134 Long: strings.TrimSpace( 135 fmt.Sprintf(`Withdraw all rewards for a single delegator. 136 Note that if you use this command with --%[2]s=%[3]s or --%[2]s=%[4]s, the %[5]s flag will automatically be set to 0. 137 138 Example: 139 $ %[1]s tx distribution withdraw-all-rewards --from mykey 140 `, 141 version.AppName, flags.FlagBroadcastMode, flags.BroadcastSync, flags.BroadcastAsync, FlagMaxMessagesPerTx, 142 ), 143 ), 144 Args: cobra.NoArgs, 145 RunE: func(cmd *cobra.Command, _ []string) error { 146 clientCtx, err := client.GetClientTxContext(cmd) 147 if err != nil { 148 return err 149 } 150 delAddr, err := ac.BytesToString(clientCtx.GetFromAddress()) 151 if err != nil { 152 return err 153 } 154 155 // The transaction cannot be generated offline since it requires a query 156 // to get all the validators. 157 if clientCtx.Offline { 158 return fmt.Errorf("cannot generate tx in offline mode") 159 } 160 161 queryClient := types.NewQueryClient(clientCtx) 162 delValsRes, err := queryClient.DelegatorValidators(cmd.Context(), &types.QueryDelegatorValidatorsRequest{DelegatorAddress: delAddr}) 163 if err != nil { 164 return err 165 } 166 167 validators := delValsRes.Validators 168 // build multi-message transaction 169 msgs := make([]sdk.Msg, 0, len(validators)) 170 for _, valAddr := range validators { 171 _, err := valCodec.StringToBytes(valAddr) 172 if err != nil { 173 return err 174 } 175 176 msg := types.NewMsgWithdrawDelegatorReward(delAddr, valAddr) 177 msgs = append(msgs, msg) 178 } 179 180 chunkSize, _ := cmd.Flags().GetInt(FlagMaxMessagesPerTx) 181 182 return newSplitAndApply(tx.GenerateOrBroadcastTxCLI, clientCtx, cmd.Flags(), msgs, chunkSize) 183 }, 184 } 185 186 cmd.Flags().Int(FlagMaxMessagesPerTx, MaxMessagesPerTxDefault, "Limit the number of messages per tx (0 for unlimited)") 187 flags.AddTxFlagsToCmd(cmd) 188 189 return cmd 190 } 191 192 // NewSetWithdrawAddrCmd returns a CLI command handler for creating a MsgSetWithdrawAddress transaction. 193 func NewSetWithdrawAddrCmd(ac address.Codec) *cobra.Command { 194 bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() 195 196 cmd := &cobra.Command{ 197 Use: "set-withdraw-addr [withdraw-addr]", 198 Short: "change the default withdraw address for rewards associated with an address", 199 Long: strings.TrimSpace( 200 fmt.Sprintf(`Set the withdraw address for rewards associated with a delegator address. 201 202 Example: 203 $ %s tx distribution set-withdraw-addr %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey 204 `, 205 version.AppName, bech32PrefixAccAddr, 206 ), 207 ), 208 Args: cobra.ExactArgs(1), 209 RunE: func(cmd *cobra.Command, args []string) error { 210 clientCtx, err := client.GetClientTxContext(cmd) 211 if err != nil { 212 return err 213 } 214 delAddr := clientCtx.GetFromAddress() 215 withdrawAddr, err := ac.StringToBytes(args[0]) 216 if err != nil { 217 return err 218 } 219 220 msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr) 221 222 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 223 }, 224 } 225 226 flags.AddTxFlagsToCmd(cmd) 227 228 return cmd 229 } 230 231 // NewFundCommunityPoolCmd returns a CLI command handler for creating a MsgFundCommunityPool transaction. 232 func NewFundCommunityPoolCmd(ac address.Codec) *cobra.Command { 233 cmd := &cobra.Command{ 234 Use: "fund-community-pool [amount]", 235 Args: cobra.ExactArgs(1), 236 Short: "Funds the community pool with the specified amount", 237 Long: strings.TrimSpace( 238 fmt.Sprintf(`Funds the community pool with the specified amount 239 240 Example: 241 $ %s tx distribution fund-community-pool 100uatom --from mykey 242 `, 243 version.AppName, 244 ), 245 ), 246 RunE: func(cmd *cobra.Command, args []string) error { 247 clientCtx, err := client.GetClientTxContext(cmd) 248 if err != nil { 249 return err 250 } 251 depositorAddr, err := ac.BytesToString(clientCtx.GetFromAddress()) 252 if err != nil { 253 return err 254 } 255 amount, err := sdk.ParseCoinsNormalized(args[0]) 256 if err != nil { 257 return err 258 } 259 260 msg := types.NewMsgFundCommunityPool(amount, depositorAddr) 261 262 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 263 }, 264 } 265 266 flags.AddTxFlagsToCmd(cmd) 267 268 return cmd 269 } 270 271 // NewDepositValidatorRewardsPoolCmd returns a CLI command handler for creating 272 // a MsgDepositValidatorRewardsPool transaction. 273 func NewDepositValidatorRewardsPoolCmd(valCodec, ac address.Codec) *cobra.Command { 274 cmd := &cobra.Command{ 275 Use: "fund-validator-rewards-pool [val_addr] [amount]", 276 Args: cobra.ExactArgs(2), 277 Short: "Fund the validator rewards pool with the specified amount", 278 Example: fmt.Sprintf( 279 "%s tx distribution fund-validator-rewards-pool cosmosvaloper1x20lytyf6zkcrv5edpkfkn8sz578qg5sqfyqnp 100uatom --from mykey", 280 version.AppName, 281 ), 282 RunE: func(cmd *cobra.Command, args []string) error { 283 clientCtx, err := client.GetClientTxContext(cmd) 284 if err != nil { 285 return err 286 } 287 288 depositorAddr, err := ac.BytesToString(clientCtx.GetFromAddress()) 289 if err != nil { 290 return err 291 } 292 293 _, err = valCodec.StringToBytes(args[0]) 294 if err != nil { 295 return err 296 } 297 298 amount, err := sdk.ParseCoinsNormalized(args[1]) 299 if err != nil { 300 return err 301 } 302 303 msg := types.NewMsgDepositValidatorRewardsPool(depositorAddr, args[0], amount) 304 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 305 }, 306 } 307 308 flags.AddTxFlagsToCmd(cmd) 309 310 return cmd 311 }