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 }