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 }