* stake/fees spec updates * staking overview.md revisions, moving files * docs reorganization * staking spec state revisions * transaction stake updates * complete staking spec update * WIP adding unbonding/redelegation commands * added msg types for unbonding, redelegation * stake sub-package reorg * working stake reorg * modify lcd tests to not use hardcoded json strings * add description update * index keys * key managment for unbonding redelegation complete * update stake errors * completed handleMsgCompleteUnbonding fn * updated to use begin/complete unbonding/redelegation * fix token shares bug * develop docs into unbonding * got non-tests compiling after merge develop * working fixing tests * PrivlegedKeeper -> PrivilegedKeeper * tests compile * fix some tests * fixing tests * remove PrivilegedKeeper * get unbonding bug * only rpc sig verification failed tests now * move percent unbonding/redelegation to the CLI and out of handler logic * remove min unbonding height * add lcd txs * add pool sanity checks, fix a buncha tests * fix ante. set lcd log to debug (#1322) * redelegation tests, adding query functionality for bonds * add self-delegations at genesis ref #1165 * PR comments (mostly) addressed * cleanup, added Query LCD functionality * test cleanup/fixes * fix governance test * SlashValidatorSet -> ValidatorSet * changelog * stake lcd fix * x/auth: fix chainID in ante * fix lcd test * fix lint, update lint make command for spelling * lowercase error string * don't expose coinkeeper in staking * remove a few duplicate lines in changelog * chain_id in stake lcd tests * added transient redelegation * 'transient' => 'transitive' * Re-add nolint instruction * Fix tiny linter error
377 lines
11 KiB
Go
377 lines
11 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client/context"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/wire"
|
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
|
)
|
|
|
|
// create create validator command
|
|
func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "create-validator",
|
|
Short: "create new validator initialized with a self-delegation to it",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
amount, err := sdk.ParseCoin(viper.GetString(FlagAmount))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pkStr := viper.GetString(FlagPubKey)
|
|
if len(pkStr) == 0 {
|
|
return fmt.Errorf("must use --pubkey flag")
|
|
}
|
|
pk, err := sdk.GetValPubKeyBech32(pkStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if viper.GetString(FlagMoniker) == "" {
|
|
return fmt.Errorf("please enter a moniker for the validator using --moniker")
|
|
}
|
|
description := stake.Description{
|
|
Moniker: viper.GetString(FlagMoniker),
|
|
Identity: viper.GetString(FlagIdentity),
|
|
Website: viper.GetString(FlagWebsite),
|
|
Details: viper.GetString(FlagDetails),
|
|
}
|
|
msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().AddFlagSet(fsPk)
|
|
cmd.Flags().AddFlagSet(fsAmount)
|
|
cmd.Flags().AddFlagSet(fsDescription)
|
|
cmd.Flags().AddFlagSet(fsValidator)
|
|
return cmd
|
|
}
|
|
|
|
// create edit validator command
|
|
func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "edit-validator",
|
|
Short: "edit and existing validator account",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
description := stake.Description{
|
|
Moniker: viper.GetString(FlagMoniker),
|
|
Identity: viper.GetString(FlagIdentity),
|
|
Website: viper.GetString(FlagWebsite),
|
|
Details: viper.GetString(FlagDetails),
|
|
}
|
|
msg := stake.NewMsgEditValidator(validatorAddr, description)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().AddFlagSet(fsDescription)
|
|
cmd.Flags().AddFlagSet(fsValidator)
|
|
return cmd
|
|
}
|
|
|
|
// delegate command
|
|
func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "delegate",
|
|
Short: "delegate liquid tokens to an validator",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
amount, err := sdk.ParseCoin(viper.GetString(FlagAmount))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := stake.NewMsgDelegate(delegatorAddr, validatorAddr, amount)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().AddFlagSet(fsAmount)
|
|
cmd.Flags().AddFlagSet(fsDelegator)
|
|
cmd.Flags().AddFlagSet(fsValidator)
|
|
return cmd
|
|
}
|
|
|
|
// create edit validator command
|
|
func GetCmdRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "redelegate",
|
|
Short: "redelegate illiquid tokens from one validator to another",
|
|
}
|
|
cmd.AddCommand(
|
|
GetCmdBeginRedelegate(storeName, cdc),
|
|
GetCmdCompleteRedelegate(cdc),
|
|
)
|
|
return cmd
|
|
}
|
|
|
|
// redelegate command
|
|
func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "begin",
|
|
Short: "begin redelegation",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
var err error
|
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
validatorSrcAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidatorSrc))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
validatorDstAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidatorDst))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// get the shares amount
|
|
sharesAmountStr := viper.GetString(FlagSharesAmount)
|
|
sharesPercentStr := viper.GetString(FlagSharesPercent)
|
|
sharesAmount, err := getShares(storeName, cdc, sharesAmountStr, sharesPercentStr,
|
|
delegatorAddr, validatorSrcAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := stake.NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr, sharesAmount)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().AddFlagSet(fsShares)
|
|
cmd.Flags().AddFlagSet(fsDelegator)
|
|
cmd.Flags().AddFlagSet(fsRedelegation)
|
|
return cmd
|
|
}
|
|
|
|
func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercentStr string,
|
|
delegatorAddr, validatorAddr sdk.Address) (sharesAmount sdk.Rat, err error) {
|
|
|
|
switch {
|
|
case sharesAmountStr != "" && sharesPercentStr != "":
|
|
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
|
|
case sharesAmountStr == "" && sharesPercentStr == "":
|
|
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
|
|
case sharesAmountStr != "":
|
|
sharesAmount, err = sdk.NewRatFromDecimal(sharesAmountStr)
|
|
if err != nil {
|
|
return sharesAmount, err
|
|
}
|
|
if !sharesAmount.GT(sdk.ZeroRat()) {
|
|
return sharesAmount, errors.Errorf("shares amount must be positive number (ex. 123, 1.23456789)")
|
|
}
|
|
case sharesPercentStr != "":
|
|
var sharesPercent sdk.Rat
|
|
sharesPercent, err = sdk.NewRatFromDecimal(sharesPercentStr)
|
|
if err != nil {
|
|
return sharesAmount, err
|
|
}
|
|
if !sharesPercent.GT(sdk.ZeroRat()) || !sharesPercent.LTE(sdk.OneRat()) {
|
|
return sharesAmount, errors.Errorf("shares percent must be >0 and <=1 (ex. 0.01, 0.75, 1)")
|
|
}
|
|
|
|
// make a query to get the existing delegation shares
|
|
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
|
|
ctx := context.NewCoreContextFromViper()
|
|
resQuery, err := ctx.QueryStore(key, storeName)
|
|
if err != nil {
|
|
return sharesAmount, err
|
|
}
|
|
var delegation stake.Delegation
|
|
err = cdc.UnmarshalBinary(resQuery, &delegation)
|
|
if err != nil {
|
|
return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err)
|
|
}
|
|
|
|
sharesAmount = sharesPercent.Mul(delegation.Shares)
|
|
}
|
|
return
|
|
}
|
|
|
|
// redelegate command
|
|
func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "complete",
|
|
Short: "complete redelegation",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
|
validatorSrcAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidatorSrc))
|
|
validatorDstAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidatorDst))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := stake.NewMsgCompleteRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().AddFlagSet(fsDelegator)
|
|
cmd.Flags().AddFlagSet(fsRedelegation)
|
|
return cmd
|
|
}
|
|
|
|
// create edit validator command
|
|
func GetCmdUnbond(storeName string, cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "unbond",
|
|
Short: "begin or complete unbonding shares from a validator",
|
|
}
|
|
cmd.AddCommand(
|
|
GetCmdBeginUnbonding(storeName, cdc),
|
|
GetCmdCompleteUnbonding(cdc),
|
|
)
|
|
return cmd
|
|
}
|
|
|
|
// create edit validator command
|
|
func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "begin",
|
|
Short: "begin unbonding",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// get the shares amount
|
|
sharesAmountStr := viper.GetString(FlagSharesAmount)
|
|
sharesPercentStr := viper.GetString(FlagSharesPercent)
|
|
sharesAmount, err := getShares(storeName, cdc, sharesAmountStr, sharesPercentStr,
|
|
delegatorAddr, validatorAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := stake.NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sharesAmount)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
|
|
cmd.Flags().AddFlagSet(fsShares)
|
|
cmd.Flags().AddFlagSet(fsDelegator)
|
|
cmd.Flags().AddFlagSet(fsValidator)
|
|
return cmd
|
|
}
|
|
|
|
// create edit validator command
|
|
func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "complete",
|
|
Short: "complete unbonding",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := stake.NewMsgCompleteUnbonding(delegatorAddr, validatorAddr)
|
|
|
|
// build and sign the transaction, then broadcast to Tendermint
|
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
|
|
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().AddFlagSet(fsDelegator)
|
|
cmd.Flags().AddFlagSet(fsValidator)
|
|
return cmd
|
|
}
|