github.com/Finschia/finschia-sdk@v0.48.1/x/authz/client/cli/tx.go (about)

     1  package cli
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/spf13/cobra"
    10  
    11  	"github.com/Finschia/finschia-sdk/client"
    12  	"github.com/Finschia/finschia-sdk/client/flags"
    13  	"github.com/Finschia/finschia-sdk/client/tx"
    14  	sdk "github.com/Finschia/finschia-sdk/types"
    15  	"github.com/Finschia/finschia-sdk/version"
    16  	authclient "github.com/Finschia/finschia-sdk/x/auth/client"
    17  	"github.com/Finschia/finschia-sdk/x/authz"
    18  	bank "github.com/Finschia/finschia-sdk/x/bank/types"
    19  	staking "github.com/Finschia/finschia-sdk/x/staking/types"
    20  )
    21  
    22  // Flag names and values
    23  const (
    24  	FlagSpendLimit        = "spend-limit"
    25  	FlagMsgType           = "msg-type"
    26  	FlagExpiration        = "expiration"
    27  	FlagAllowedValidators = "allowed-validators"
    28  	FlagDenyValidators    = "deny-validators"
    29  	delegate              = "delegate"
    30  	redelegate            = "redelegate"
    31  	unbond                = "unbond"
    32  )
    33  
    34  // GetTxCmd returns the transaction commands for this module
    35  func GetTxCmd() *cobra.Command {
    36  	AuthorizationTxCmd := &cobra.Command{
    37  		Use:                        authz.ModuleName,
    38  		Short:                      "Authorization transactions subcommands",
    39  		Long:                       "Authorize and revoke access to execute transactions on behalf of your address",
    40  		DisableFlagParsing:         true,
    41  		SuggestionsMinimumDistance: 2,
    42  		RunE:                       client.ValidateCmd,
    43  	}
    44  
    45  	AuthorizationTxCmd.AddCommand(
    46  		NewCmdGrantAuthorization(),
    47  		NewCmdRevokeAuthorization(),
    48  		NewCmdExecAuthorization(),
    49  	)
    50  
    51  	return AuthorizationTxCmd
    52  }
    53  
    54  func NewCmdGrantAuthorization() *cobra.Command {
    55  	cmd := &cobra.Command{
    56  		Use:   "grant <grantee> <authorization_type=\"send\"|\"generic\"|\"delegate\"|\"unbond\"|\"redelegate\"> --from <granter>",
    57  		Short: "Grant authorization to an address",
    58  		Long: strings.TrimSpace(
    59  			fmt.Sprintf(`grant authorization to an address to execute a transaction on your behalf:
    60  
    61  Examples:
    62   $ %s tx %s grant link1skjw.. send %s --spend-limit=1000stake --from=link1skl..
    63   $ %s tx %s grant link1skjw.. generic --msg-type=/cosmos.gov.v1beta1.MsgVote --from=link1sk..
    64  	`, version.AppName, authz.ModuleName, bank.SendAuthorization{}.MsgTypeURL(), version.AppName, authz.ModuleName),
    65  		),
    66  		Args: cobra.ExactArgs(2),
    67  		RunE: func(cmd *cobra.Command, args []string) error {
    68  			clientCtx, err := client.GetClientTxContext(cmd)
    69  			if err != nil {
    70  				return err
    71  			}
    72  
    73  			grantee, err := sdk.AccAddressFromBech32(args[0])
    74  			if err != nil {
    75  				return err
    76  			}
    77  
    78  			exp, err := cmd.Flags().GetInt64(FlagExpiration)
    79  			if err != nil {
    80  				return err
    81  			}
    82  
    83  			var authorization authz.Authorization
    84  			switch args[1] {
    85  			case "send":
    86  				limit, err := cmd.Flags().GetString(FlagSpendLimit)
    87  				if err != nil {
    88  					return err
    89  				}
    90  
    91  				spendLimit, err := sdk.ParseCoinsNormalized(limit)
    92  				if err != nil {
    93  					return err
    94  				}
    95  
    96  				if !spendLimit.IsAllPositive() {
    97  					return fmt.Errorf("spend-limit should be greater than zero")
    98  				}
    99  
   100  				authorization = bank.NewSendAuthorization(spendLimit)
   101  			case "generic":
   102  				msgType, err := cmd.Flags().GetString(FlagMsgType)
   103  				if err != nil {
   104  					return err
   105  				}
   106  
   107  				authorization = authz.NewGenericAuthorization(msgType)
   108  			case delegate, unbond, redelegate:
   109  				limit, err := cmd.Flags().GetString(FlagSpendLimit)
   110  				if err != nil {
   111  					return err
   112  				}
   113  
   114  				allowValidators, err := cmd.Flags().GetStringSlice(FlagAllowedValidators)
   115  				if err != nil {
   116  					return err
   117  				}
   118  
   119  				denyValidators, err := cmd.Flags().GetStringSlice(FlagDenyValidators)
   120  				if err != nil {
   121  					return err
   122  				}
   123  
   124  				var delegateLimit *sdk.Coin
   125  				if limit != "" {
   126  					spendLimit, err := sdk.ParseCoinsNormalized(limit)
   127  					if err != nil {
   128  						return err
   129  					}
   130  
   131  					if !spendLimit.IsAllPositive() {
   132  						return fmt.Errorf("spend-limit should be greater than zero")
   133  					}
   134  					delegateLimit = &spendLimit[0]
   135  				}
   136  
   137  				allowed, err := bech32toValidatorAddresses(allowValidators)
   138  				if err != nil {
   139  					return err
   140  				}
   141  
   142  				denied, err := bech32toValidatorAddresses(denyValidators)
   143  				if err != nil {
   144  					return err
   145  				}
   146  
   147  				switch args[1] {
   148  				case delegate:
   149  					authorization, err = staking.NewStakeAuthorization(allowed, denied, staking.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, delegateLimit)
   150  				case unbond:
   151  					authorization, err = staking.NewStakeAuthorization(allowed, denied, staking.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, delegateLimit)
   152  				default:
   153  					authorization, err = staking.NewStakeAuthorization(allowed, denied, staking.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, delegateLimit)
   154  				}
   155  				if err != nil {
   156  					return err
   157  				}
   158  
   159  			default:
   160  				return fmt.Errorf("invalid authorization type, %s", args[1])
   161  			}
   162  
   163  			msg, err := authz.NewMsgGrant(clientCtx.GetFromAddress(), grantee, authorization, time.Unix(exp, 0))
   164  			if err != nil {
   165  				return err
   166  			}
   167  
   168  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   169  		},
   170  	}
   171  	flags.AddTxFlagsToCmd(cmd)
   172  	cmd.Flags().String(FlagMsgType, "", "The Msg method name for which we are creating a GenericAuthorization")
   173  	cmd.Flags().String(FlagSpendLimit, "", "SpendLimit for Send Authorization, an array of Coins allowed spend")
   174  	cmd.Flags().StringSlice(FlagAllowedValidators, []string{}, "Allowed validators addresses separated by ,")
   175  	cmd.Flags().StringSlice(FlagDenyValidators, []string{}, "Deny validators addresses separated by ,")
   176  	cmd.Flags().Int64(FlagExpiration, time.Now().AddDate(1, 0, 0).Unix(), "The Unix timestamp. Default is one year.")
   177  	return cmd
   178  }
   179  
   180  func NewCmdRevokeAuthorization() *cobra.Command {
   181  	cmd := &cobra.Command{
   182  		Use:   "revoke [grantee] [msg_type] --from=[granter]",
   183  		Short: "revoke authorization",
   184  		Long: strings.TrimSpace(
   185  			fmt.Sprintf(`revoke authorization from a granter to a grantee:
   186  Example:
   187   $ %s tx %s revoke link1skj.. %s --from=link1skj..
   188  			`, version.AppName, authz.ModuleName, bank.SendAuthorization{}.MsgTypeURL()),
   189  		),
   190  		Args: cobra.ExactArgs(2),
   191  		RunE: func(cmd *cobra.Command, args []string) error {
   192  			clientCtx, err := client.GetClientTxContext(cmd)
   193  			if err != nil {
   194  				return err
   195  			}
   196  
   197  			grantee, err := sdk.AccAddressFromBech32(args[0])
   198  			if err != nil {
   199  				return err
   200  			}
   201  
   202  			granter := clientCtx.GetFromAddress()
   203  			msgAuthorized := args[1]
   204  			msg := authz.NewMsgRevoke(granter, grantee, msgAuthorized)
   205  
   206  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   207  		},
   208  	}
   209  	flags.AddTxFlagsToCmd(cmd)
   210  	return cmd
   211  }
   212  
   213  func NewCmdExecAuthorization() *cobra.Command {
   214  	cmd := &cobra.Command{
   215  		Use:   "exec [msg_tx_json_file] --from [grantee]",
   216  		Short: "execute tx on behalf of granter account",
   217  		Long: strings.TrimSpace(
   218  			fmt.Sprintf(`execute tx on behalf of granter account:
   219  Example:
   220   $ %s tx %s exec tx.json --from grantee
   221   $ %s tx bank send <granter> <recipient> --from <granter> --chain-id <chain-id> --generate-only > tx.json && %s tx %s exec tx.json --from grantee
   222  			`, version.AppName, authz.ModuleName, version.AppName, version.AppName, authz.ModuleName),
   223  		),
   224  		Args: cobra.ExactArgs(1),
   225  		RunE: func(cmd *cobra.Command, args []string) error {
   226  			clientCtx, err := client.GetClientTxContext(cmd)
   227  			if err != nil {
   228  				return err
   229  			}
   230  			grantee := clientCtx.GetFromAddress()
   231  
   232  			if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline {
   233  				return errors.New("cannot broadcast tx during offline mode")
   234  			}
   235  
   236  			theTx, err := authclient.ReadTxFromFile(clientCtx, args[0])
   237  			if err != nil {
   238  				return err
   239  			}
   240  			msg := authz.NewMsgExec(grantee, theTx.GetMsgs())
   241  
   242  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   243  		},
   244  	}
   245  
   246  	flags.AddTxFlagsToCmd(cmd)
   247  
   248  	return cmd
   249  }
   250  
   251  func bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) {
   252  	vals := make([]sdk.ValAddress, len(validators))
   253  	for i, validator := range validators {
   254  		addr, err := sdk.ValAddressFromBech32(validator)
   255  		if err != nil {
   256  			return nil, err
   257  		}
   258  		vals[i] = addr
   259  	}
   260  	return vals, nil
   261  }