2018-09-04 23:41:17 -07:00
package cli
import (
2020-09-07 06:14:00 -07:00
"context"
2019-05-18 16:06:08 -07:00
"fmt"
2019-02-06 16:15:37 -08:00
"strings"
2018-09-04 23:41:17 -07:00
2018-09-19 16:00:21 -07:00
"github.com/spf13/cobra"
2020-07-10 07:45:46 -07:00
"github.com/spf13/pflag"
2018-09-19 16:00:21 -07:00
2018-11-19 09:02:34 -08:00
"github.com/cosmos/cosmos-sdk/client"
2019-12-23 08:05:47 -08:00
"github.com/cosmos/cosmos-sdk/client/flags"
2020-05-21 14:29:34 -07:00
"github.com/cosmos/cosmos-sdk/client/tx"
2018-09-04 23:41:17 -07:00
sdk "github.com/cosmos/cosmos-sdk/types"
2019-05-18 16:06:08 -07:00
"github.com/cosmos/cosmos-sdk/version"
2018-09-19 21:53:48 -07:00
"github.com/cosmos/cosmos-sdk/x/distribution/types"
2020-06-13 02:07:51 -07:00
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
2018-09-04 23:41:17 -07:00
)
2020-07-10 07:45:46 -07:00
// Transaction flags for the x/distribution module
2018-09-04 23:41:17 -07:00
var (
2020-07-10 07:45:46 -07:00
FlagCommission = "commission"
FlagMaxMessagesPerTx = "max-msgs"
2019-05-23 16:00:26 -07:00
)
const (
MaxMessagesPerTxDefault = 5
2018-09-04 23:41:17 -07:00
)
2020-04-08 08:05:14 -07:00
// NewTxCmd returns a root CLI command handler for all x/distribution transaction commands.
2020-07-10 07:45:46 -07:00
func NewTxCmd ( ) * cobra . Command {
2020-04-08 08:05:14 -07:00
distTxCmd := & cobra . Command {
Use : types . ModuleName ,
Short : "Distribution transactions subcommands" ,
DisableFlagParsing : true ,
SuggestionsMinimumDistance : 2 ,
RunE : client . ValidateCmd ,
}
2020-07-10 12:59:26 -07:00
distTxCmd . AddCommand (
2020-07-10 07:45:46 -07:00
NewWithdrawRewardsCmd ( ) ,
NewWithdrawAllRewardsCmd ( ) ,
NewSetWithdrawAddrCmd ( ) ,
NewFundCommunityPoolCmd ( ) ,
2020-07-10 12:59:26 -07:00
)
2020-04-08 08:05:14 -07:00
return distTxCmd
}
2020-07-10 07:45:46 -07:00
type newGenerateOrBroadcastFunc func ( client . Context , * pflag . FlagSet , ... sdk . Msg ) error
2020-04-08 08:05:14 -07:00
func newSplitAndApply (
2020-07-10 07:45:46 -07:00
genOrBroadcastFn newGenerateOrBroadcastFunc , clientCtx client . Context ,
fs * pflag . FlagSet , msgs [ ] sdk . Msg , chunkSize int ,
2020-04-08 08:05:14 -07:00
) error {
2020-07-10 07:45:46 -07:00
2020-04-08 08:05:14 -07:00
if chunkSize == 0 {
2020-07-10 07:45:46 -07:00
return genOrBroadcastFn ( clientCtx , fs , msgs ... )
2020-04-08 08:05:14 -07:00
}
// split messages into slices of length chunkSize
totalMessages := len ( msgs )
for i := 0 ; i < len ( msgs ) ; i += chunkSize {
sliceEnd := i + chunkSize
if sliceEnd > totalMessages {
sliceEnd = totalMessages
}
msgChunk := msgs [ i : sliceEnd ]
2020-07-10 07:45:46 -07:00
if err := genOrBroadcastFn ( clientCtx , fs , msgChunk ... ) ; err != nil {
2020-04-08 08:05:14 -07:00
return err
}
}
return nil
}
2020-07-10 07:45:46 -07:00
func NewWithdrawRewardsCmd ( ) * cobra . Command {
2020-08-17 02:04:50 -07:00
bech32PrefixValAddr := sdk . GetConfig ( ) . GetBech32ValidatorAddrPrefix ( )
2020-04-08 08:05:14 -07:00
cmd := & cobra . Command {
Use : "withdraw-rewards [validator-addr]" ,
Short : "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator" ,
Long : strings . TrimSpace (
fmt . Sprintf ( ` Withdraw rewards from a given delegation address ,
and optionally withdraw validator commission if the delegation address given is a validator operator .
Example :
2020-08-17 02:04:50 -07:00
$ % s tx distribution withdraw - rewards % s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -- from mykey
$ % s tx distribution withdraw - rewards % s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -- from mykey -- commission
2020-04-08 08:05:14 -07:00
` ,
2020-08-17 02:04:50 -07:00
version . AppName , bech32PrefixValAddr , version . AppName , bech32PrefixValAddr ,
2020-04-08 08:05:14 -07:00
) ,
) ,
Args : cobra . ExactArgs ( 1 ) ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2020-12-14 14:09:51 -08:00
clientCtx , err := client . GetClientTxContext ( cmd )
2020-07-10 07:45:46 -07:00
if err != nil {
return err
}
2020-06-01 05:46:03 -07:00
delAddr := clientCtx . GetFromAddress ( )
2020-04-08 08:05:14 -07:00
valAddr , err := sdk . ValAddressFromBech32 ( args [ 0 ] )
if err != nil {
return err
}
msgs := [ ] sdk . Msg { types . NewMsgWithdrawDelegatorReward ( delAddr , valAddr ) }
2020-07-06 03:12:00 -07:00
2020-07-10 07:45:46 -07:00
if commission , _ := cmd . Flags ( ) . GetBool ( FlagCommission ) ; commission {
2020-04-08 08:05:14 -07:00
msgs = append ( msgs , types . NewMsgWithdrawValidatorCommission ( valAddr ) )
}
for _ , msg := range msgs {
if err := msg . ValidateBasic ( ) ; err != nil {
return err
}
}
2020-07-10 07:45:46 -07:00
return tx . GenerateOrBroadcastTxCLI ( clientCtx , cmd . Flags ( ) , msgs ... )
2020-04-08 08:05:14 -07:00
} ,
}
2020-07-06 03:12:00 -07:00
2020-07-10 07:45:46 -07:00
cmd . Flags ( ) . Bool ( FlagCommission , false , "Withdraw the validator's commission in addition to the rewards" )
2020-07-10 12:59:26 -07:00
flags . AddTxFlagsToCmd ( cmd )
2020-07-21 06:54:07 -07:00
2020-05-21 14:29:34 -07:00
return cmd
2020-04-08 08:05:14 -07:00
}
2020-07-10 07:45:46 -07:00
func NewWithdrawAllRewardsCmd ( ) * cobra . Command {
2020-04-08 08:05:14 -07:00
cmd := & cobra . Command {
Use : "withdraw-all-rewards" ,
Short : "withdraw all delegations rewards for a delegator" ,
Long : strings . TrimSpace (
fmt . Sprintf ( ` Withdraw all rewards for a single delegator .
Example :
$ % s tx distribution withdraw - all - rewards -- from mykey
` ,
2020-07-07 08:40:46 -07:00
version . AppName ,
2020-04-08 08:05:14 -07:00
) ,
) ,
Args : cobra . NoArgs ,
2020-07-10 07:45:46 -07:00
RunE : func ( cmd * cobra . Command , _ [ ] string ) error {
2020-12-14 14:09:51 -08:00
clientCtx , err := client . GetClientTxContext ( cmd )
2020-07-10 07:45:46 -07:00
if err != nil {
return err
}
2020-06-01 05:46:03 -07:00
delAddr := clientCtx . GetFromAddress ( )
2020-04-08 08:05:14 -07:00
// The transaction cannot be generated offline since it requires a query
// to get all the validators.
2020-06-01 05:46:03 -07:00
if clientCtx . Offline {
2020-04-08 08:05:14 -07:00
return fmt . Errorf ( "cannot generate tx in offline mode" )
}
2020-09-07 06:14:00 -07:00
queryClient := types . NewQueryClient ( clientCtx )
2020-09-25 03:25:37 -07:00
delValsRes , err := queryClient . DelegatorValidators ( context . Background ( ) , & types . QueryDelegatorValidatorsRequest { DelegatorAddress : delAddr . String ( ) } )
2020-04-08 08:05:14 -07:00
if err != nil {
return err
}
2020-09-07 06:14:00 -07:00
validators := delValsRes . Validators
// build multi-message transaction
msgs := make ( [ ] sdk . Msg , 0 , len ( validators ) )
for _ , valAddr := range validators {
2020-09-25 03:25:37 -07:00
val , err := sdk . ValAddressFromBech32 ( valAddr )
if err != nil {
return err
}
msg := types . NewMsgWithdrawDelegatorReward ( delAddr , val )
2020-09-07 06:14:00 -07:00
if err := msg . ValidateBasic ( ) ; err != nil {
return err
}
msgs = append ( msgs , msg )
}
2020-07-10 07:45:46 -07:00
chunkSize , _ := cmd . Flags ( ) . GetInt ( FlagMaxMessagesPerTx )
return newSplitAndApply ( tx . GenerateOrBroadcastTxCLI , clientCtx , cmd . Flags ( ) , msgs , chunkSize )
2020-04-08 08:05:14 -07:00
} ,
}
2020-06-09 03:18:44 -07:00
2020-07-10 07:45:46 -07:00
cmd . Flags ( ) . Int ( FlagMaxMessagesPerTx , MaxMessagesPerTxDefault , "Limit the number of messages per tx (0 for unlimited)" )
2020-07-10 12:59:26 -07:00
flags . AddTxFlagsToCmd ( cmd )
2020-07-21 06:54:07 -07:00
2020-05-21 14:29:34 -07:00
return cmd
2020-04-08 08:05:14 -07:00
}
2020-07-10 07:45:46 -07:00
func NewSetWithdrawAddrCmd ( ) * cobra . Command {
2020-08-17 02:04:50 -07:00
bech32PrefixAccAddr := sdk . GetConfig ( ) . GetBech32AccountAddrPrefix ( )
2020-07-10 12:59:26 -07:00
cmd := & cobra . Command {
2020-04-08 08:05:14 -07:00
Use : "set-withdraw-addr [withdraw-addr]" ,
Short : "change the default withdraw address for rewards associated with an address" ,
Long : strings . TrimSpace (
fmt . Sprintf ( ` Set the withdraw address for rewards associated with a delegator address .
Example :
2020-08-17 02:04:50 -07:00
$ % s tx distribution set - withdraw - addr % s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p -- from mykey
2020-04-08 08:05:14 -07:00
` ,
2020-08-17 02:04:50 -07:00
version . AppName , bech32PrefixAccAddr ,
2020-04-08 08:05:14 -07:00
) ,
) ,
Args : cobra . ExactArgs ( 1 ) ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2020-12-14 14:09:51 -08:00
clientCtx , err := client . GetClientTxContext ( cmd )
2020-07-10 07:45:46 -07:00
if err != nil {
return err
}
2020-06-01 05:46:03 -07:00
delAddr := clientCtx . GetFromAddress ( )
2020-04-08 08:05:14 -07:00
withdrawAddr , err := sdk . AccAddressFromBech32 ( args [ 0 ] )
if err != nil {
return err
}
msg := types . NewMsgSetWithdrawAddress ( delAddr , withdrawAddr )
if err := msg . ValidateBasic ( ) ; err != nil {
return err
}
2020-07-10 07:45:46 -07:00
return tx . GenerateOrBroadcastTxCLI ( clientCtx , cmd . Flags ( ) , msg )
2020-04-08 08:05:14 -07:00
} ,
}
2020-07-10 12:59:26 -07:00
flags . AddTxFlagsToCmd ( cmd )
2020-07-21 06:54:07 -07:00
2020-07-10 12:59:26 -07:00
return cmd
2020-04-08 08:05:14 -07:00
}
2020-07-10 07:45:46 -07:00
func NewFundCommunityPoolCmd ( ) * cobra . Command {
2020-07-10 12:59:26 -07:00
cmd := & cobra . Command {
2020-06-09 03:18:44 -07:00
Use : "fund-community-pool [amount]" ,
2020-04-08 08:05:14 -07:00
Args : cobra . ExactArgs ( 1 ) ,
2020-06-09 03:18:44 -07:00
Short : "Funds the community pool with the specified amount" ,
2020-04-08 08:05:14 -07:00
Long : strings . TrimSpace (
2020-06-09 03:18:44 -07:00
fmt . Sprintf ( ` Funds the community pool with the specified amount
2020-04-08 08:05:14 -07:00
Example :
2020-06-09 03:18:44 -07:00
$ % s tx distribution fund - community - pool 100 uatom -- from mykey
2020-04-08 08:05:14 -07:00
` ,
2020-07-07 08:40:46 -07:00
version . AppName ,
2020-04-08 08:05:14 -07:00
) ,
) ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2020-12-14 14:09:51 -08:00
clientCtx , err := client . GetClientTxContext ( cmd )
2020-07-10 07:45:46 -07:00
if err != nil {
return err
}
2020-06-01 05:46:03 -07:00
depositorAddr := clientCtx . GetFromAddress ( )
2020-11-16 03:34:54 -08:00
amount , err := sdk . ParseCoinsNormalized ( args [ 0 ] )
2020-04-08 08:05:14 -07:00
if err != nil {
return err
}
msg := types . NewMsgFundCommunityPool ( amount , depositorAddr )
if err := msg . ValidateBasic ( ) ; err != nil {
return err
}
2020-07-10 07:45:46 -07:00
return tx . GenerateOrBroadcastTxCLI ( clientCtx , cmd . Flags ( ) , msg )
2019-02-04 16:45:18 -08:00
} ,
}
2020-07-10 12:59:26 -07:00
flags . AddTxFlagsToCmd ( cmd )
2020-07-21 06:54:07 -07:00
2020-07-10 12:59:26 -07:00
return cmd
2019-02-04 16:45:18 -08:00
}
2019-05-21 03:02:10 -07:00
// GetCmdSubmitProposal implements the command to submit a community-pool-spend proposal
2020-07-10 07:45:46 -07:00
func GetCmdSubmitProposal ( ) * cobra . Command {
2020-08-17 02:04:50 -07:00
bech32PrefixAccAddr := sdk . GetConfig ( ) . GetBech32AccountAddrPrefix ( )
2020-07-10 12:59:26 -07:00
cmd := & cobra . Command {
2019-05-21 03:02:10 -07:00
Use : "community-pool-spend [proposal-file]" ,
Args : cobra . ExactArgs ( 1 ) ,
Short : "Submit a community pool spend proposal" ,
Long : strings . TrimSpace (
fmt . Sprintf ( ` Submit a community pool spend proposal along with an initial deposit .
The proposal details must be supplied via a JSON file .
Example :
$ % s tx gov submit - proposal community - pool - spend < path / to / proposal . json > -- from = < key_or_address >
Where proposal . json contains :
{
"title" : "Community Pool Spend" ,
"description" : "Pay me some Atoms!" ,
2020-08-17 02:04:50 -07:00
"recipient" : "%s1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq" ,
2020-03-11 10:06:39 -07:00
"amount" : "1000stake" ,
"deposit" : "1000stake"
2019-05-21 03:02:10 -07:00
}
` ,
2020-08-17 02:04:50 -07:00
version . AppName , bech32PrefixAccAddr ,
2019-05-21 03:02:10 -07:00
) ,
) ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2020-12-14 14:09:51 -08:00
clientCtx , err := client . GetClientTxContext ( cmd )
2020-07-10 07:45:46 -07:00
if err != nil {
return err
}
2020-09-07 06:14:00 -07:00
proposal , err := ParseCommunityPoolSpendProposalWithDeposit ( clientCtx . JSONMarshaler , args [ 0 ] )
2019-05-21 03:02:10 -07:00
if err != nil {
return err
}
2020-11-16 03:34:54 -08:00
amount , err := sdk . ParseCoinsNormalized ( proposal . Amount )
2020-03-11 10:03:47 -07:00
if err != nil {
return err
}
2020-11-16 03:34:54 -08:00
deposit , err := sdk . ParseCoinsNormalized ( proposal . Deposit )
2020-03-11 10:03:47 -07:00
if err != nil {
return err
}
2020-07-10 07:45:46 -07:00
from := clientCtx . GetFromAddress ( )
2020-09-25 03:25:37 -07:00
recpAddr , err := sdk . AccAddressFromBech32 ( proposal . Recipient )
if err != nil {
return err
}
content := types . NewCommunityPoolSpendProposal ( proposal . Title , proposal . Description , recpAddr , amount )
2020-07-10 07:45:46 -07:00
2020-06-13 02:07:51 -07:00
msg , err := govtypes . NewMsgSubmitProposal ( content , deposit , from )
2020-05-19 13:17:29 -07:00
if err != nil {
return err
}
2020-07-10 07:45:46 -07:00
2019-05-21 03:02:10 -07:00
if err := msg . ValidateBasic ( ) ; err != nil {
return err
}
2020-07-10 07:45:46 -07:00
return tx . GenerateOrBroadcastTxCLI ( clientCtx , cmd . Flags ( ) , msg )
2019-05-21 03:02:10 -07:00
} ,
}
2020-07-10 12:59:26 -07:00
return cmd
2019-05-21 03:02:10 -07:00
}