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  }