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

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/spf13/cobra"
     9  
    10  	"github.com/Finschia/finschia-sdk/client"
    11  	"github.com/Finschia/finschia-sdk/client/flags"
    12  	"github.com/Finschia/finschia-sdk/client/tx"
    13  	sdk "github.com/Finschia/finschia-sdk/types"
    14  	"github.com/Finschia/finschia-sdk/version"
    15  	"github.com/Finschia/finschia-sdk/x/feegrant"
    16  )
    17  
    18  // flag for feegrant module
    19  const (
    20  	FlagExpiration  = "expiration"
    21  	FlagPeriod      = "period"
    22  	FlagPeriodLimit = "period-limit"
    23  	FlagSpendLimit  = "spend-limit"
    24  	FlagAllowedMsgs = "allowed-messages"
    25  )
    26  
    27  // GetTxCmd returns the transaction commands for this module
    28  func GetTxCmd() *cobra.Command {
    29  	feegrantTxCmd := &cobra.Command{
    30  		Use:                        feegrant.ModuleName,
    31  		Short:                      "Feegrant transactions subcommands",
    32  		Long:                       "Grant and revoke fee allowance for a grantee by a granter",
    33  		DisableFlagParsing:         true,
    34  		SuggestionsMinimumDistance: 2,
    35  		RunE:                       client.ValidateCmd,
    36  	}
    37  
    38  	feegrantTxCmd.AddCommand(
    39  		NewCmdFeeGrant(),
    40  		NewCmdRevokeFeegrant(),
    41  	)
    42  
    43  	return feegrantTxCmd
    44  }
    45  
    46  // NewCmdFeeGrant returns a CLI command handler for creating a MsgGrantAllowance transaction.
    47  func NewCmdFeeGrant() *cobra.Command {
    48  	cmd := &cobra.Command{
    49  		Use:   "grant [granter_key_or_address] [grantee]",
    50  		Short: "Grant Fee allowance to an address",
    51  		Long: strings.TrimSpace(
    52  			fmt.Sprintf(
    53  				`Grant authorization to pay fees from your address. Note, the'--from' flag is
    54  				ignored as it is implied from [granter].
    55  
    56  Examples:
    57  %s tx %s grant link1skjw... link1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z or
    58  %s tx %s grant link1skjw... link1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 2022-01-30T15:04:05Z or
    59  %s tx %s grant link1skjw... link1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z 
    60  	--allowed-messages "/cosmos.gov.v1beta1.MsgSubmitProposal,/cosmos.gov.v1beta1.MsgVote"
    61  				`, version.AppName, feegrant.ModuleName, version.AppName, feegrant.ModuleName, version.AppName, feegrant.ModuleName,
    62  			),
    63  		),
    64  		Args: cobra.ExactArgs(2),
    65  		RunE: func(cmd *cobra.Command, args []string) error {
    66  			if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil {
    67  				return err
    68  			}
    69  
    70  			clientCtx, err := client.GetClientTxContext(cmd)
    71  			if err != nil {
    72  				return err
    73  			}
    74  
    75  			grantee, err := sdk.AccAddressFromBech32(args[1])
    76  			if err != nil {
    77  				return err
    78  			}
    79  
    80  			granter := clientCtx.GetFromAddress()
    81  			sl, err := cmd.Flags().GetString(FlagSpendLimit)
    82  			if err != nil {
    83  				return err
    84  			}
    85  
    86  			// if `FlagSpendLimit` isn't set, limit will be nil
    87  			limit, err := sdk.ParseCoinsNormalized(sl)
    88  			if err != nil {
    89  				return err
    90  			}
    91  
    92  			exp, err := cmd.Flags().GetString(FlagExpiration)
    93  			if err != nil {
    94  				return err
    95  			}
    96  
    97  			basic := feegrant.BasicAllowance{
    98  				SpendLimit: limit,
    99  			}
   100  
   101  			var expiresAtTime time.Time
   102  			if exp != "" {
   103  				expiresAtTime, err = time.Parse(time.RFC3339, exp)
   104  				if err != nil {
   105  					return err
   106  				}
   107  				basic.Expiration = &expiresAtTime
   108  			}
   109  
   110  			var grant feegrant.FeeAllowanceI
   111  			grant = &basic
   112  
   113  			periodClock, err := cmd.Flags().GetInt64(FlagPeriod)
   114  			if err != nil {
   115  				return err
   116  			}
   117  
   118  			periodLimitVal, err := cmd.Flags().GetString(FlagPeriodLimit)
   119  			if err != nil {
   120  				return err
   121  			}
   122  
   123  			// Check any of period or periodLimit flags set, If set consider it as periodic fee allowance.
   124  			if periodClock > 0 || periodLimitVal != "" {
   125  				periodLimit, err := sdk.ParseCoinsNormalized(periodLimitVal)
   126  				if err != nil {
   127  					return err
   128  				}
   129  
   130  				if periodClock <= 0 {
   131  					return fmt.Errorf("period clock was not set")
   132  				}
   133  
   134  				if periodLimit == nil {
   135  					return fmt.Errorf("period limit was not set")
   136  				}
   137  
   138  				periodReset := getPeriodReset(periodClock)
   139  				if exp != "" && periodReset.Sub(expiresAtTime) > 0 {
   140  					return fmt.Errorf("period (%d) cannot reset after expiration (%v)", periodClock, exp)
   141  				}
   142  
   143  				periodic := feegrant.PeriodicAllowance{
   144  					Basic:            basic,
   145  					Period:           getPeriod(periodClock),
   146  					PeriodReset:      getPeriodReset(periodClock),
   147  					PeriodSpendLimit: periodLimit,
   148  					PeriodCanSpend:   periodLimit,
   149  				}
   150  
   151  				grant = &periodic
   152  			}
   153  
   154  			allowedMsgs, err := cmd.Flags().GetStringSlice(FlagAllowedMsgs)
   155  			if err != nil {
   156  				return err
   157  			}
   158  
   159  			if len(allowedMsgs) > 0 {
   160  				grant, err = feegrant.NewAllowedMsgAllowance(grant, allowedMsgs)
   161  				if err != nil {
   162  					return err
   163  				}
   164  			}
   165  
   166  			msg, err := feegrant.NewMsgGrantAllowance(grant, granter, grantee)
   167  			if err != nil {
   168  				return err
   169  			}
   170  
   171  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
   172  		},
   173  	}
   174  
   175  	flags.AddTxFlagsToCmd(cmd)
   176  	cmd.Flags().StringSlice(FlagAllowedMsgs, []string{}, "Set of allowed messages for fee allowance")
   177  	cmd.Flags().String(FlagExpiration, "", "The RFC 3339 timestamp after which the grant expires for the user")
   178  	cmd.Flags().String(FlagSpendLimit, "", "Spend limit specifies the max limit can be used, if not mentioned there is no limit")
   179  	cmd.Flags().Int64(FlagPeriod, 0, "period specifies the time duration(in seconds) in which period_limit coins can be spent before that allowance is reset (ex: 3600)")
   180  	cmd.Flags().String(FlagPeriodLimit, "", "period limit specifies the maximum number of coins that can be spent in the period")
   181  
   182  	return cmd
   183  }
   184  
   185  // NewCmdRevokeFeegrant returns a CLI command handler for creating a MsgRevokeAllowance transaction.
   186  func NewCmdRevokeFeegrant() *cobra.Command {
   187  	cmd := &cobra.Command{
   188  		Use:   "revoke [granter] [grantee]",
   189  		Short: "revoke fee-grant",
   190  		Long: strings.TrimSpace(
   191  			fmt.Sprintf(`revoke fee grant from a granter to a grantee. Note, the'--from' flag is
   192  			ignored as it is implied from [granter].
   193  
   194  Example:
   195   $ %s tx %s revoke link1skj.. link1skj..
   196  			`, version.AppName, feegrant.ModuleName),
   197  		),
   198  		Args: cobra.ExactArgs(2),
   199  		RunE: func(cmd *cobra.Command, args []string) error {
   200  			if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil {
   201  				return err
   202  			}
   203  			clientCtx, err := client.GetClientTxContext(cmd)
   204  			if err != nil {
   205  				return err
   206  			}
   207  
   208  			grantee, err := sdk.AccAddressFromBech32(args[1])
   209  			if err != nil {
   210  				return err
   211  			}
   212  
   213  			msg := feegrant.NewMsgRevokeAllowance(clientCtx.GetFromAddress(), grantee)
   214  
   215  			return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
   216  		},
   217  	}
   218  
   219  	flags.AddTxFlagsToCmd(cmd)
   220  	return cmd
   221  }
   222  
   223  func getPeriodReset(duration int64) time.Time {
   224  	return time.Now().Add(getPeriod(duration))
   225  }
   226  
   227  func getPeriod(duration int64) time.Duration {
   228  	return time.Duration(duration) * time.Second
   229  }