github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/staking/client/cli/tx.go (about) 1 package cli 2 3 import ( 4 "bufio" 5 "fmt" 6 "os" 7 "strings" 8 9 "github.com/spf13/cobra" 10 flag "github.com/spf13/pflag" 11 "github.com/spf13/viper" 12 13 cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config" 14 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto" 15 16 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client" 17 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags" 19 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 20 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 21 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/version" 22 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth" 23 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/client/utils" 24 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/types" 25 ) 26 27 // GetTxCmd returns the transaction commands for this module 28 func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { 29 stakingTxCmd := &cobra.Command{ 30 Use: types.ModuleName, 31 Short: "Staking transaction subcommands", 32 DisableFlagParsing: true, 33 SuggestionsMinimumDistance: 2, 34 RunE: client.ValidateCmd, 35 } 36 37 stakingTxCmd.AddCommand(flags.PostCommands( 38 GetCmdCreateValidator(cdc), 39 GetCmdEditValidator(cdc), 40 GetCmdDelegate(cdc), 41 GetCmdRedelegate(storeKey, cdc), 42 GetCmdUnbond(storeKey, cdc), 43 )...) 44 45 return stakingTxCmd 46 } 47 48 // GetCmdCreateValidator implements the create validator command handler. 49 func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { 50 cmd := &cobra.Command{ 51 Use: "create-validator", 52 Short: "create new validator initialized with a self-delegation to it", 53 RunE: func(cmd *cobra.Command, args []string) error { 54 inBuf := bufio.NewReader(cmd.InOrStdin()) 55 txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) 56 cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) 57 58 txBldr, msg, err := BuildCreateValidatorMsg(cliCtx, txBldr) 59 if err != nil { 60 return err 61 } 62 63 return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) 64 }, 65 } 66 67 cmd.Flags().AddFlagSet(FsPk) 68 cmd.Flags().AddFlagSet(FsAmount) 69 cmd.Flags().AddFlagSet(fsDescriptionCreate) 70 cmd.Flags().AddFlagSet(FsCommissionCreate) 71 cmd.Flags().AddFlagSet(FsMinSelfDelegation) 72 73 cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", flags.FlagGenerateOnly)) 74 cmd.Flags().String(FlagNodeID, "", "The node's ID") 75 76 cmd.MarkFlagRequired(flags.FlagFrom) 77 cmd.MarkFlagRequired(FlagAmount) 78 cmd.MarkFlagRequired(FlagPubKey) 79 cmd.MarkFlagRequired(FlagMoniker) 80 81 return cmd 82 } 83 84 // GetCmdEditValidator implements the create edit validator command. 85 // TODO: add full description 86 func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { 87 cmd := &cobra.Command{ 88 Use: "edit-validator", 89 Short: "edit an existing validator account", 90 RunE: func(cmd *cobra.Command, args []string) error { 91 inBuf := bufio.NewReader(cmd.InOrStdin()) 92 txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) 93 cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) 94 95 valAddr := cliCtx.GetFromAddress() 96 description := types.NewDescription( 97 viper.GetString(FlagMoniker), 98 viper.GetString(FlagIdentity), 99 viper.GetString(FlagWebsite), 100 viper.GetString(FlagSecurityContact), 101 viper.GetString(FlagDetails), 102 ) 103 104 var newRate *sdk.Dec 105 106 commissionRate := viper.GetString(FlagCommissionRate) 107 if commissionRate != "" { 108 rate, err := sdk.NewDecFromStr(commissionRate) 109 if err != nil { 110 return fmt.Errorf("invalid new commission rate: %v", err) 111 } 112 113 newRate = &rate 114 } 115 116 var newMinSelfDelegation *sdk.Int 117 118 minSelfDelegationString := viper.GetString(FlagMinSelfDelegation) 119 if minSelfDelegationString != "" { 120 msb, ok := sdk.NewIntFromString(minSelfDelegationString) 121 if !ok { 122 return types.ErrMinSelfDelegationInvalid 123 } 124 125 newMinSelfDelegation = &msb 126 } 127 128 msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation) 129 130 // build and sign the transaction, then broadcast to Tendermint 131 return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) 132 }, 133 } 134 135 cmd.Flags().AddFlagSet(fsDescriptionEdit) 136 cmd.Flags().AddFlagSet(fsCommissionUpdate) 137 cmd.Flags().AddFlagSet(FsMinSelfDelegation) 138 139 return cmd 140 } 141 142 // GetCmdDelegate implements the delegate command. 143 func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { 144 return &cobra.Command{ 145 Use: "delegate [validator-addr] [amount]", 146 Args: cobra.ExactArgs(2), 147 Short: "Delegate liquid tokens to a validator", 148 Long: strings.TrimSpace( 149 fmt.Sprintf(`Delegate an amount of liquid coins to a validator from your wallet. 150 151 Example: 152 $ %s tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey 153 `, 154 version.ClientName, 155 ), 156 ), 157 RunE: func(cmd *cobra.Command, args []string) error { 158 inBuf := bufio.NewReader(cmd.InOrStdin()) 159 txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) 160 cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) 161 162 amount, err := sdk.ParseCoin(args[1]) 163 if err != nil { 164 return err 165 } 166 167 delAddr := cliCtx.GetFromAddress() 168 valAddr, err := sdk.ValAddressFromBech32(args[0]) 169 if err != nil { 170 return err 171 } 172 173 msg := types.NewMsgDelegate(delAddr, valAddr, amount) 174 return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) 175 }, 176 } 177 } 178 179 // GetCmdRedelegate the begin redelegation command. 180 func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { 181 return &cobra.Command{ 182 Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount]", 183 Short: "Redelegate illiquid tokens from one validator to another", 184 Args: cobra.ExactArgs(3), 185 Long: strings.TrimSpace( 186 fmt.Sprintf(`Redelegate an amount of illiquid staking tokens from one validator to another. 187 188 Example: 189 $ %s tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey 190 `, 191 version.ClientName, 192 ), 193 ), 194 RunE: func(cmd *cobra.Command, args []string) error { 195 inBuf := bufio.NewReader(cmd.InOrStdin()) 196 txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) 197 cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) 198 199 delAddr := cliCtx.GetFromAddress() 200 valSrcAddr, err := sdk.ValAddressFromBech32(args[0]) 201 if err != nil { 202 return err 203 } 204 205 valDstAddr, err := sdk.ValAddressFromBech32(args[1]) 206 if err != nil { 207 return err 208 } 209 210 amount, err := sdk.ParseCoin(args[2]) 211 if err != nil { 212 return err 213 } 214 215 msg := types.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, amount) 216 return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) 217 }, 218 } 219 } 220 221 // GetCmdUnbond implements the unbond validator command. 222 func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { 223 return &cobra.Command{ 224 Use: "unbond [validator-addr] [amount]", 225 Short: "Unbond shares from a validator", 226 Args: cobra.ExactArgs(2), 227 Long: strings.TrimSpace( 228 fmt.Sprintf(`Unbond an amount of bonded shares from a validator. 229 230 Example: 231 $ %s tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey 232 `, 233 version.ClientName, 234 ), 235 ), 236 RunE: func(cmd *cobra.Command, args []string) error { 237 inBuf := bufio.NewReader(cmd.InOrStdin()) 238 txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(auth.DefaultTxEncoder(cdc)) 239 cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) 240 241 delAddr := cliCtx.GetFromAddress() 242 valAddr, err := sdk.ValAddressFromBech32(args[0]) 243 if err != nil { 244 return err 245 } 246 247 amount, err := sdk.ParseCoin(args[1]) 248 if err != nil { 249 return err 250 } 251 252 msg := types.NewMsgUndelegate(delAddr, valAddr, amount) 253 return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) 254 }, 255 } 256 } 257 258 //__________________________________________________________ 259 260 var ( 261 defaultTokens = sdk.TokensFromConsensusPower(100) 262 defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom 263 defaultCommissionRate = "0.1" 264 defaultCommissionMaxRate = "0.2" 265 defaultCommissionMaxChangeRate = "0.01" 266 defaultMinSelfDelegation = "1" 267 ) 268 269 // Return the flagset, particular flags, and a description of defaults 270 // this is anticipated to be used with the gen-tx 271 func CreateValidatorMsgHelpers(ipDefault string) (fs *flag.FlagSet, nodeIDFlag, pubkeyFlag, amountFlag, defaultsDesc string) { 272 273 fsCreateValidator := flag.NewFlagSet("", flag.ContinueOnError) 274 fsCreateValidator.String(FlagIP, ipDefault, "The node's public IP") 275 fsCreateValidator.String(FlagNodeID, "", "The node's NodeID") 276 fsCreateValidator.String(FlagWebsite, "", "The validator's (optional) website") 277 fsCreateValidator.String(FlagSecurityContact, "", "The validator's (optional) security contact email") 278 fsCreateValidator.String(FlagDetails, "", "The validator's (optional) details") 279 fsCreateValidator.String(FlagIdentity, "", "The (optional) identity signature (ex. UPort or Keybase)") 280 fsCreateValidator.AddFlagSet(FsCommissionCreate) 281 fsCreateValidator.AddFlagSet(FsMinSelfDelegation) 282 fsCreateValidator.AddFlagSet(FsAmount) 283 fsCreateValidator.AddFlagSet(FsPk) 284 285 defaultsDesc = fmt.Sprintf(` 286 delegation amount: %s 287 commission rate: %s 288 commission max rate: %s 289 commission max change rate: %s 290 minimum self delegation: %s 291 `, defaultAmount, defaultCommissionRate, 292 defaultCommissionMaxRate, defaultCommissionMaxChangeRate, 293 defaultMinSelfDelegation) 294 295 return fsCreateValidator, FlagNodeID, FlagPubKey, FlagAmount, defaultsDesc 296 } 297 298 // prepare flags in config 299 func PrepareFlagsForTxCreateValidator( 300 config *cfg.Config, nodeID, chainID string, valPubKey crypto.PubKey, 301 ) { 302 303 ip := viper.GetString(FlagIP) 304 if ip == "" { 305 fmt.Fprintf(os.Stderr, "couldn't retrieve an external IP; "+ 306 "the tx's memo field will be unset") 307 } 308 309 website := viper.GetString(FlagWebsite) 310 securityContact := viper.GetString(FlagSecurityContact) 311 details := viper.GetString(FlagDetails) 312 identity := viper.GetString(FlagIdentity) 313 314 viper.Set(flags.FlagChainID, chainID) 315 viper.Set(flags.FlagFrom, viper.GetString(flags.FlagName)) 316 viper.Set(FlagNodeID, nodeID) 317 viper.Set(FlagIP, ip) 318 viper.Set(FlagPubKey, sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, valPubKey)) 319 viper.Set(FlagMoniker, config.Moniker) 320 viper.Set(FlagWebsite, website) 321 viper.Set(FlagSecurityContact, securityContact) 322 viper.Set(FlagDetails, details) 323 viper.Set(FlagIdentity, identity) 324 325 if config.Moniker == "" { 326 viper.Set(FlagMoniker, viper.GetString(flags.FlagName)) 327 } 328 if viper.GetString(FlagAmount) == "" { 329 viper.Set(FlagAmount, defaultAmount) 330 } 331 if viper.GetString(FlagCommissionRate) == "" { 332 viper.Set(FlagCommissionRate, defaultCommissionRate) 333 } 334 if viper.GetString(FlagCommissionMaxRate) == "" { 335 viper.Set(FlagCommissionMaxRate, defaultCommissionMaxRate) 336 } 337 if viper.GetString(FlagCommissionMaxChangeRate) == "" { 338 viper.Set(FlagCommissionMaxChangeRate, defaultCommissionMaxChangeRate) 339 } 340 if viper.GetString(FlagMinSelfDelegation) == "" { 341 viper.Set(FlagMinSelfDelegation, defaultMinSelfDelegation) 342 } 343 } 344 345 // BuildCreateValidatorMsg makes a new MsgCreateValidator. 346 func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (auth.TxBuilder, sdk.Msg, error) { 347 amounstStr := viper.GetString(FlagAmount) 348 amount, err := sdk.ParseCoin(amounstStr) 349 if err != nil { 350 return txBldr, nil, err 351 } 352 353 valAddr := cliCtx.GetFromAddress() 354 pkStr := viper.GetString(FlagPubKey) 355 356 pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, pkStr) 357 if err != nil { 358 return txBldr, nil, err 359 } 360 361 description := types.NewDescription( 362 viper.GetString(FlagMoniker), 363 viper.GetString(FlagIdentity), 364 viper.GetString(FlagWebsite), 365 viper.GetString(FlagSecurityContact), 366 viper.GetString(FlagDetails), 367 ) 368 369 // get the initial validator commission parameters 370 rateStr := viper.GetString(FlagCommissionRate) 371 maxRateStr := viper.GetString(FlagCommissionMaxRate) 372 maxChangeRateStr := viper.GetString(FlagCommissionMaxChangeRate) 373 commissionRates, err := buildCommissionRates(rateStr, maxRateStr, maxChangeRateStr) 374 if err != nil { 375 return txBldr, nil, err 376 } 377 378 // get the initial validator min self delegation 379 msbStr := viper.GetString(FlagMinSelfDelegation) 380 minSelfDelegation, ok := sdk.NewIntFromString(msbStr) 381 if !ok { 382 return txBldr, nil, types.ErrMinSelfDelegationInvalid 383 } 384 385 msg := types.NewMsgCreateValidator( 386 sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation, 387 ) 388 389 if viper.GetBool(flags.FlagGenerateOnly) { 390 ip := viper.GetString(FlagIP) 391 nodeID := viper.GetString(FlagNodeID) 392 if nodeID != "" && ip != "" { 393 txBldr = txBldr.WithMemo(fmt.Sprintf("%s@%s:26656", nodeID, ip)) 394 } 395 } 396 397 return txBldr, msg, nil 398 }