feat(x/staking): autocli tx support (#17986)

This commit is contained in:
atheeshp 2023-10-10 14:36:06 +05:30 committed by GitHub
parent 4001e2b6d8
commit f149f1baac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 87 additions and 642 deletions

View File

@ -40,7 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
* (testutil) [#17868](https://github.com/cosmos/cosmos-sdk/pull/17868) Added helper method `SubmitTestTx` in testutil to broadcast test txns to test e2e tests.
* (tests) [#17868](https://github.com/cosmos/cosmos-sdk/pull/17868) Added helper method `SubmitTestTx` in testutil to broadcast test txns to test e2e tests.
* (x/protocolpool) [#17657](https://github.com/cosmos/cosmos-sdk/pull/17657) Create a new `x/protocolpool` module that is responsible for handling community pool funds. This module is split out into a new module from x/distribution.
* (baseapp) [#16581](https://github.com/cosmos/cosmos-sdk/pull/16581) Implement Optimistic Execution as an experimental feature (not enabled by default).
* (client/keys) [#17639](https://github.com/cosmos/cosmos-sdk/pull/17639) Allows using and saving public keys encoded as base64
@ -66,6 +66,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking Changes
* (testutil) [#17986](https://github.com/cosmos/cosmos-sdk/pull/17986) `MsgRedelegateExec`, `MsgUnbondExec` has been removed because of AutoCLI migration.
* (testutil) [#17868](https://github.com/cosmos/cosmos-sdk/pull/17868) `MsgSendExec` has been removed because of AutoCLI migration.
* (x/distribution) [#17657](https://github.com/cosmos/cosmos-sdk/pull/17657) The `FundCommunityPool` and `DistributeFromFeePool` keeper methods are now removed from x/distribution.
* (x/distribution) [#17657](https://github.com/cosmos/cosmos-sdk/pull/17657) The distribution module keeper now takes a new argument `PoolKeeper` in addition.

View File

@ -12,7 +12,6 @@ import (
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil"
@ -28,7 +27,7 @@ import (
govtestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
stakingcli "github.com/cosmos/cosmos-sdk/x/staking/client/cli"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
type E2ETestSuite struct {
@ -178,12 +177,6 @@ var (
typeMsgVote = sdk.MsgTypeURL(&govv1.MsgVote{})
)
func execDelegate(val *network.Validator, args []string) (testutil.BufferWriter, error) {
cmd := stakingcli.NewDelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
clientCtx := val.ClientCtx
return clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
}
func (s *E2ETestSuite) TestExecAuthorizationWithExpiration() {
val := s.network.Validators[0]
grantee := s.grantee[0]
@ -777,17 +770,14 @@ func (s *E2ETestSuite) TestExecUndelegateAuthorization() {
s.Require().NoError(s.network.WaitForNextBlock())
// delegating stakes to validator
_, err = execDelegate(
val,
[]string{
val.ValAddress.String(),
"100stake",
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
},
)
msg := &stakingtypes.MsgDelegate{
DelegatorAddress: val.Address.String(),
ValidatorAddress: val.ValAddress.String(),
Amount: sdk.NewCoin("stake", math.NewInt(100)),
}
_, err = clitestutil.SubmitTestTx(val.ClientCtx, msg, val.Address, clitestutil.TestTxConfig{})
s.Require().NoError(err)
tokens := sdk.NewCoins(

View File

@ -13,13 +13,12 @@ import (
"github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
stakingcli "github.com/cosmos/cosmos-sdk/x/staking/client/cli"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
type WithdrawAllTestSuite struct {
@ -80,34 +79,29 @@ func (s *WithdrawAllTestSuite) TestNewWithdrawAllRewardsGenerateOnly() {
require.NoError(s.network.WaitForNextBlock())
// delegate 500 tokens to validator1
args := []string{
val.ValAddress.String(),
sdk.NewCoin(s.cfg.BondDenom, math.NewInt(500)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
msg := &stakingtypes.MsgDelegate{
DelegatorAddress: newAddr.String(),
ValidatorAddress: val.ValAddress.String(),
Amount: sdk.NewCoin("stake", math.NewInt(500)),
}
cmd := stakingcli.NewDelegateCmd(clientCtx.InterfaceRegistry.SigningContext().ValidatorAddressCodec(), clientCtx.InterfaceRegistry.SigningContext().AddressCodec())
_, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
_, err = clitestutil.SubmitTestTx(val.ClientCtx, msg, newAddr, clitestutil.TestTxConfig{})
require.NoError(err)
require.NoError(s.network.WaitForNextBlock())
// delegate 500 tokens to validator2
args = []string{
val1.ValAddress.String(),
sdk.NewCoin(s.cfg.BondDenom, math.NewInt(500)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
msg2 := &stakingtypes.MsgDelegate{
DelegatorAddress: newAddr.String(),
ValidatorAddress: val1.ValAddress.String(),
Amount: sdk.NewCoin("stake", math.NewInt(500)),
}
_, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
require.NoError(err)
var out testutil.BufferWriter
_, err = clitestutil.SubmitTestTx(val.ClientCtx, msg2, newAddr, clitestutil.TestTxConfig{})
require.NoError(err)
require.NoError(s.network.WaitForNextBlock())
err = s.network.RetryForBlocks(func() error {
args = []string{
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
@ -115,7 +109,7 @@ func (s *WithdrawAllTestSuite) TestNewWithdrawAllRewardsGenerateOnly() {
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
}
cmd = cli.NewWithdrawAllRewardsCmd(address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"))
cmd := cli.NewWithdrawAllRewardsCmd(address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"))
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
if err != nil {
return err
@ -130,7 +124,7 @@ func (s *WithdrawAllTestSuite) TestNewWithdrawAllRewardsGenerateOnly() {
}, 3)
require.NoError(err)
args = []string{
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
@ -138,8 +132,8 @@ func (s *WithdrawAllTestSuite) TestNewWithdrawAllRewardsGenerateOnly() {
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
}
cmd = cli.NewWithdrawAllRewardsCmd(address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"))
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
cmd := cli.NewWithdrawAllRewardsCmd(address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos"))
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
require.NoError(err)
// expect 1 transaction in the generated file when --max-msgs in a tx set 2, since there are only delegations.
s.Require().Equal(1, len(strings.Split(strings.Trim(out.String(), "\n"), "\n")))

View File

@ -3,7 +3,6 @@ package testutil
import (
"context"
"errors"
"fmt"
"testing"
"github.com/cometbft/cometbft/proto/tendermint/crypto"
@ -12,15 +11,13 @@ import (
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
type E2ETestSuite struct {
@ -44,44 +41,6 @@ func (s *E2ETestSuite) SetupSuite() {
var err error
s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg)
s.Require().NoError(err)
unbond, err := sdk.ParseCoinNormalized("10stake")
s.Require().NoError(err)
val := s.network.Validators[0]
val2 := s.network.Validators[1]
// redelegate
out, err := MsgRedelegateExec(
val.ClientCtx,
val.Address,
val.ValAddress,
val2.ValAddress,
unbond,
fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
)
s.Require().NoError(err)
var txRes sdk.TxResponse
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(uint32(0), txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
unbondingAmount := sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(5))
// unbonding the amount
out, err = MsgUnbondExec(val.ClientCtx, val.Address, val.ValAddress, unbondingAmount)
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(uint32(0), txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
// unbonding the amount
out, err = MsgUnbondExec(val.ClientCtx, val.Address, val.ValAddress, unbondingAmount)
s.Require().NoError(err)
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(uint32(0), txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
}
func (s *E2ETestSuite) TearDownSuite() {
@ -119,16 +78,19 @@ func (s *E2ETestSuite) TestBlockResults() {
require.NoError(err)
require.NoError(s.network.WaitForNextBlock())
// Use CLI to create a delegation from the new account to validator `val`.
cmd := cli.NewDelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
_, err = clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, []string{
val.ValAddress.String(),
sdk.NewCoin(s.cfg.BondDenom, math.NewInt(150)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
})
msgDel := &stakingtypes.MsgDelegate{
DelegatorAddress: newAddr.String(),
ValidatorAddress: val.ValAddress.String(),
Amount: sdk.NewCoin(s.cfg.BondDenom, math.NewInt(150)),
}
// create a delegation from the new account to validator `val`.
_, err = clitestutil.SubmitTestTx(
val.ClientCtx,
msgDel,
newAddr,
clitestutil.TestTxConfig{},
)
require.NoError(err)
require.NoError(s.network.WaitForNextBlock())

View File

@ -1,52 +0,0 @@
package testutil
import (
"fmt"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingcli "github.com/cosmos/cosmos-sdk/x/staking/client/cli"
)
var commonArgs = []string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))).String()),
}
// MsgRedelegateExec creates a redelegate message.
func MsgRedelegateExec(clientCtx client.Context, from, src, dst, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) {
args := []string{
src.String(),
dst.String(),
amount.String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, from.String()),
fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
}
args = append(args, extraArgs...)
args = append(args, commonArgs...)
return clitestutil.ExecTestCLICmd(clientCtx, stakingcli.NewRedelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos")), args)
}
// MsgUnbondExec creates a unbond message.
func MsgUnbondExec(clientCtx client.Context, from, valAddress,
amount fmt.Stringer,
extraArgs ...string,
) (testutil.BufferWriter, error) {
args := []string{
valAddress.String(),
amount.String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, from.String()),
}
args = append(args, commonArgs...)
args = append(args, extraArgs...)
return clitestutil.ExecTestCLICmd(clientCtx, stakingcli.NewUnbondCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos")), args)
}

View File

@ -142,6 +142,44 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
Tx: &autocliv1.ServiceCommandDescriptor{
Service: stakingv1beta.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Delegate",
Use: "delegate [validator-addr] [amount] --from [delegator_address]",
Short: "Delegate liquid tokens to a validator",
Long: "Delegate an amount of liquid coins to a validator from your wallet.",
Example: fmt.Sprintf("%s tx staking delegate cosmosvaloper... 1000stake --from mykey", version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "validator_address"}, {ProtoField: "amount"}},
},
{
RpcMethod: "BeginRedelegate",
Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount] --from [delegator]",
Short: "Generate multisig signatures for transactions generated offline",
Long: "Redelegate an amount of illiquid staking tokens from one validator to another.",
Example: fmt.Sprintf(`%s tx staking redelegate cosmosvaloper... cosmosvaloper... 100stake --from mykey`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "validator_src_address"}, {ProtoField: "validator_dst_address"}, {ProtoField: "amount"}},
},
{
RpcMethod: "Undelegate",
Use: "unbond [validator-addr] [amount] --from [delegator_address]",
Short: "Unbond shares from a validator",
Long: "Unbond an amount of bonded shares from a validator.",
Example: fmt.Sprintf(`%s tx staking unbond cosmosvaloper... 100stake --from mykey`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "validator_address"}, {ProtoField: "amount"}},
},
{
RpcMethod: "CancelUnbondingDelegation",
Use: "cancel-unbond [validator-addr] [amount] [creation-height]",
Short: "Cancel unbonding delegation and delegate back to the validator",
Example: fmt.Sprintf(`%s tx staking cancel-unbond cosmosvaloper... 100stake 2 --from mykey`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "validator_address"}, {ProtoField: "amount"}, {ProtoField: "creation_height"}},
},
{
RpcMethod: "UpdateParams",
Skip: true, // skipped because authority gated
},
},
EnhanceCustomCommand: true,
},
}
}

View File

@ -3,7 +3,6 @@ package cli
import (
"fmt"
"os"
"strconv"
"strings"
"github.com/spf13/cobra"
@ -46,16 +45,14 @@ func NewTxCmd(valAddrCodec, ac address.Codec) *cobra.Command {
stakingTxCmd.AddCommand(
NewCreateValidatorCmd(valAddrCodec),
NewEditValidatorCmd(valAddrCodec),
NewDelegateCmd(valAddrCodec, ac),
NewRedelegateCmd(valAddrCodec, ac),
NewUnbondCmd(valAddrCodec, ac),
NewCancelUnbondingDelegation(valAddrCodec, ac),
)
return stakingTxCmd
}
// NewCreateValidatorCmd returns a CLI command handler for creating a MsgCreateValidator transaction.
//
// cannot give autocli support, can be CLI breaking
func NewCreateValidatorCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "create-validator [path/to/validator.json]",
@ -119,6 +116,8 @@ where we can get the pubkey using "%s tendermint show-validator"
}
// NewEditValidatorCmd returns a CLI command handler for creating a MsgEditValidator transaction.
//
// cannot give autocli support, can be CLI breaking
func NewEditValidatorCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "edit-validator",
@ -179,206 +178,6 @@ func NewEditValidatorCmd(ac address.Codec) *cobra.Command {
return cmd
}
// NewDelegateCmd returns a CLI command handler for creating a MsgDelegate transaction.
func NewDelegateCmd(valAddrCodec, ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "delegate [validator-addr] [amount]",
Args: cobra.ExactArgs(2),
Short: "Delegate liquid tokens to a validator",
Long: strings.TrimSpace(
fmt.Sprintf(`Delegate an amount of liquid coins to a validator from your wallet.
Example:
$ %s tx staking delegate cosmosvalopers1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
amount, err := sdk.ParseCoinNormalized(args[1])
if err != nil {
return err
}
delAddr, err := ac.BytesToString(clientCtx.GetFromAddress())
if err != nil {
return err
}
_, err = valAddrCodec.StringToBytes(args[0])
if err != nil {
return err
}
msg := types.NewMsgDelegate(delAddr, args[0], amount)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewRedelegateCmd returns a CLI command handler for creating a MsgBeginRedelegate transaction.
func NewRedelegateCmd(valAddrCodec, ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "redelegate [src-validator-addr] [dst-validator-addr] [amount]",
Short: "Redelegate illiquid tokens from one validator to another",
Args: cobra.ExactArgs(3),
Long: strings.TrimSpace(
fmt.Sprintf(`Redelegate an amount of illiquid staking tokens from one validator to another.
Example:
$ %s tx staking redelegate cosmosvalopers1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvalopers1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
delAddr, err := ac.BytesToString(clientCtx.GetFromAddress())
if err != nil {
return err
}
_, err = valAddrCodec.StringToBytes(args[0])
if err != nil {
return err
}
_, err = valAddrCodec.StringToBytes(args[1])
if err != nil {
return err
}
amount, err := sdk.ParseCoinNormalized(args[2])
if err != nil {
return err
}
msg := types.NewMsgBeginRedelegate(delAddr, args[0], args[1], amount)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewUnbondCmd returns a CLI command handler for creating a MsgUndelegate transaction.
func NewUnbondCmd(valAddrCodec, ac address.Codec) *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "unbond [validator-addr] [amount]",
Short: "Unbond shares from a validator",
Args: cobra.ExactArgs(2),
Long: strings.TrimSpace(
fmt.Sprintf(`Unbond an amount of bonded shares from a validator.
Example:
$ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey
`,
version.AppName, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
delAddr, err := ac.BytesToString(clientCtx.GetFromAddress())
if err != nil {
return err
}
_, err = valAddrCodec.StringToBytes(args[0])
if err != nil {
return err
}
amount, err := sdk.ParseCoinNormalized(args[1])
if err != nil {
return err
}
msg := types.NewMsgUndelegate(delAddr, args[0], amount)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewCancelUnbondingDelegation returns a CLI command handler for creating a MsgCancelUnbondingDelegation transaction.
func NewCancelUnbondingDelegation(valAddrCodec, ac address.Codec) *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "cancel-unbond [validator-addr] [amount] [creation-height]",
Short: "Cancel unbonding delegation and delegate back to the validator",
Args: cobra.ExactArgs(3),
Long: strings.TrimSpace(
fmt.Sprintf(`Cancel Unbonding Delegation and delegate back to the validator.
Example:
$ %s tx staking cancel-unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake 2 --from mykey
`,
version.AppName, bech32PrefixValAddr,
),
),
Example: fmt.Sprintf(`$ %s tx staking cancel-unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake 2 --from mykey`,
version.AppName, bech32PrefixValAddr),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
delAddr, err := ac.BytesToString(clientCtx.GetFromAddress())
if err != nil {
return err
}
_, err = valAddrCodec.StringToBytes(args[0])
if err != nil {
return err
}
amount, err := sdk.ParseCoinNormalized(args[1])
if err != nil {
return err
}
creationHeight, err := strconv.ParseInt(args[2], 10, 64)
if err != nil {
return errorsmod.Wrap(fmt.Errorf("invalid height: %d", creationHeight), "invalid height")
}
msg := types.NewMsgCancelUnbondingDelegation(delAddr, args[0], creationHeight, amount)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet, val validator, valAc address.Codec) (tx.Factory, *types.MsgCreateValidator, error) {
valAddr := clientCtx.GetFromAddress()

View File

@ -437,290 +437,3 @@ func (s *CLITestSuite) TestNewEditValidatorCmd() {
})
}
}
func (s *CLITestSuite) TestNewDelegateCmd() {
cmd := cli.NewDelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
testCases := []struct {
name string
args []string
expectErrMsg string
}{
{
"invalid delegate amount",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
"fooCoin",
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid decimal coin expression: fooCoin",
},
{
"invalid validator address",
[]string{
"abc",
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"decoding bech32 failed",
},
{
"valid transaction of delegate",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErrMsg != "" {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
resp := &sdk.TxResponse{}
s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
}
})
}
}
func (s *CLITestSuite) TestNewRedelegateCmd() {
cmd := cli.NewRedelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
testCases := []struct {
name string
args []string
expectErrMsg string
}{
{
"invalid amount",
[]string{
sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr
sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr
"fooCoin",
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid decimal coin expression: fooCoin",
},
{
"wrong src validator",
[]string{
"invalid", // wrong src-validator-addr
sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid bech32",
},
{
"wrong dst validator",
[]string{
sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr
"invalid", // wrong dst-validator-addr
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid bech32",
},
{
"valid transaction of delegate",
[]string{
sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr
sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErrMsg != "" {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
resp := &sdk.TxResponse{}
s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
}
})
}
}
func (s *CLITestSuite) TestNewUnbondCmd() {
cmd := cli.NewUnbondCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
testCases := []struct {
name string
args []string
expectErrMsg string
}{
{
"invalid unbond amount",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
"foo",
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid decimal coin expression: foo",
},
{
"invalid validator address",
[]string{
"foo",
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"decoding bech32 failed",
},
{
"valid transaction of unbond",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErrMsg != "" {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
resp := &sdk.TxResponse{}
s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
}
})
}
}
func (s *CLITestSuite) TestNewCancelUnbondingDelegationCmd() {
cmd := cli.NewCancelUnbondingDelegation(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
testCases := []struct {
name string
args []string
expectErrMsg string
}{
{
"invalid validator address",
[]string{
"foo",
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
sdkmath.NewInt(10000).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"decoding bech32 failed",
},
{
"invalid canceling unbond delegation amount",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
"fooCoin",
sdkmath.NewInt(10000).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid decimal coin expression",
},
{
"without unbond creation height",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
"abc",
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"invalid height: invalid height: 0",
},
{
"valid transaction of canceling unbonding delegation",
[]string{
sdk.ValAddress(s.addrs[0]).String(),
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5)).String(),
sdkmath.NewInt(10000).String(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
},
"",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErrMsg != "" {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
resp := &sdk.TxResponse{}
s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
}
})
}
}