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  }