feat(bank): autocli query support (backport #16899) (#16902)

Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot] 2023-07-10 12:48:24 +00:00 committed by GitHub
parent 3fee9db359
commit c8a49b35cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 243 additions and 1160 deletions

View File

@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements
* (x/bank) [#16899](https://github.com/cosmos/cosmos-sdk/pull/16899) Align CLI queries with gRPC queries thanks to AutoCLI.
* (cli) [#16856](https://github.com/cosmos/cosmos-sdk/pull/16856) Improve `simd prune` UX by using the app default home directory and set pruning method as first variable argument (defaults to default).
* (x/authz) [#16869](https://github.com/cosmos/cosmos-sdk/pull/16869) Improve error message when grant not found.
@ -49,10 +50,17 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking Changes
* (x/auth) [#16650](https://github.com/cosmos/cosmos-sdk/pull/16650) The testutil `QueryAccountExec` has been removed from auth as it was using the CLI.
* (testutil) [#16899](https://github.com/cosmos/cosmos-sdk/pull/16899) The *cli testutil* `QueryBalancesExec` has been removed. Use the gRPC or REST query instead.
* (x/auth) [#16650](https://github.com/cosmos/cosmos-sdk/pull/16650) The *cli testutil* `QueryAccountExec` has been removed. Use the gRPC or REST query instead.
* (types/math) [#16040](https://github.com/cosmos/cosmos-sdk/pull/16798) Remove aliases in `types/math.go` (part 2).
* (x/staking) [#16795](https://github.com/cosmos/cosmos-sdk/pull/16795) `DelegationToDelegationResponse`, `DelegationsToDelegationResponses`, `RedelegationsToRedelegationResponses` are no longer exported.
## CLI Breaking Changes
* (x/bank) [#16899](https://github.com/cosmos/cosmos-sdk/pull/16899) With the migration to AutoCLI some bank commands have been split in two:
* Use `denoms-metadata` for querying all denom metadata and `denom-metadata` for querying a specific denom metadata.
* Use `total-supply` (or `total`) for querying the total supply and `total-supply-of` for querying the supply of a specific denom.
## [v0.50.0-alpha.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.0-alpha.1) - 2023-06-30
### Features

View File

@ -612,11 +612,11 @@ func (s *E2ETestSuite) TestCLISendGenerateSignAndBroadcast() {
s.Require().NoError(err)
s.Require().Equal(0, len(sigs))
resp, err := clitestutil.QueryBalancesExec(val1.ClientCtx, val1.Address, addresscodec.NewBech32Codec("cosmos"))
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, val1.Address))
s.Require().NoError(err)
var balRes banktypes.QueryAllBalancesResponse
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
startTokens := balRes.Balances.AmountOf(s.cfg.BondDenom)
@ -679,10 +679,9 @@ func (s *E2ETestSuite) TestCLISendGenerateSignAndBroadcast() {
s.Require().NoError(s.network.WaitForNextBlock())
// Ensure foo has right amount of funds
resp, err = clitestutil.QueryBalancesExec(val1.ClientCtx, val1.Address, addresscodec.NewBech32Codec("cosmos"))
resp, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, val1.Address))
s.Require().NoError(err)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
s.Require().Equal(startTokens, balRes.Balances.AmountOf(s.cfg.BondDenom))
@ -701,20 +700,20 @@ func (s *E2ETestSuite) TestCLISendGenerateSignAndBroadcast() {
// Ensure destiny account state
err = s.network.RetryForBlocks(func() error {
resp, err = clitestutil.QueryBalancesExec(val1.ClientCtx, addr, addresscodec.NewBech32Codec("cosmos"))
resp, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, addr))
s.Require().NoError(err)
return err
}, 3)
s.Require().NoError(err)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
s.Require().Equal(sendTokens.Amount, balRes.Balances.AmountOf(s.cfg.BondDenom))
// Ensure origin account state
resp, err = clitestutil.QueryBalancesExec(val1.ClientCtx, val1.Address, addresscodec.NewBech32Codec("cosmos"))
resp, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, val1.Address))
s.Require().NoError(err)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
}
@ -833,11 +832,11 @@ func (s *E2ETestSuite) TestCLIMultisignSortSignatures() {
addr, err := multisigRecord.GetAddress()
s.Require().NoError(err)
resp, err := clitestutil.QueryBalancesExec(val1.ClientCtx, addr, addresscodec.NewBech32Codec("cosmos"))
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, addr))
s.Require().NoError(err)
var balRes banktypes.QueryAllBalancesResponse
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
intialCoins := balRes.Balances
@ -851,10 +850,9 @@ func (s *E2ETestSuite) TestCLIMultisignSortSignatures() {
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
resp, err = clitestutil.QueryBalancesExec(val1.ClientCtx, addr, addresscodec.NewBech32Codec("cosmos"))
resp, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, addr))
s.Require().NoError(err)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
diff, _ := balRes.Balances.SafeSub(intialCoins...)
s.Require().Equal(sendTokens.Amount, diff.AmountOf(s.cfg.BondDenom))
@ -993,11 +991,12 @@ func (s *E2ETestSuite) TestCLIMultisign() {
var balRes banktypes.QueryAllBalancesResponse
err = s.network.RetryForBlocks(func() error {
resp, err := clitestutil.QueryBalancesExec(val1.ClientCtx, addr, addresscodec.NewBech32Codec("cosmos"))
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val1.APIAddress, addr))
s.Require().NoError(err)
if err != nil {
return err
}
return val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
return val1.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
}, 3)
s.Require().NoError(err)
s.Require().True(sendTokens.Amount.Equal(balRes.Balances.AmountOf(s.cfg.BondDenom)))
@ -1393,10 +1392,10 @@ func (s *E2ETestSuite) TestSignWithMultiSignersAminoJSON() {
require.Equal(uint32(0), txRes.Code, txRes.RawLog)
// Make sure the addr1's balance got funded.
queryResJSON, err := clitestutil.QueryBalancesExec(val0.ClientCtx, addr1, addresscodec.NewBech32Codec("cosmos"))
require.NoError(err)
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val0.APIAddress, addr1))
s.Require().NoError(err)
var queryRes banktypes.QueryAllBalancesResponse
err = val0.ClientCtx.Codec.UnmarshalJSON(queryResJSON.Bytes(), &queryRes)
err = val0.ClientCtx.Codec.UnmarshalJSON(resp, &queryRes)
require.NoError(err)
require.Equal(sdk.NewCoins(val0Coin, val1Coin), queryRes.Balances)
}
@ -1729,11 +1728,11 @@ func (s *E2ETestSuite) createBankMsg(val *network.Validator, toAddr sdk.AccAddre
}
func (s *E2ETestSuite) getBalances(clientCtx client.Context, addr sdk.AccAddress, denom string) math.Int {
resp, err := clitestutil.QueryBalancesExec(clientCtx, addr, addresscodec.NewBech32Codec("cosmos"))
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s/by_denom?denom=%s", s.cfg.APIAddress, addr.String(), denom))
s.Require().NoError(err)
var balRes banktypes.QueryAllBalancesResponse
err = clientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = clientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
startTokens := balRes.Balances.AmountOf(denom)
return startTokens

View File

@ -18,7 +18,6 @@ import (
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
@ -96,276 +95,6 @@ func (s *E2ETestSuite) TearDownSuite() {
s.network.Cleanup()
}
func (s *E2ETestSuite) TestGetBalancesCmd() {
val := s.network.Validators[0]
testCases := []struct {
name string
args []string
expectErr bool
respType proto.Message
expected proto.Message
}{
{"no address provided", []string{}, true, nil, nil},
{
"total account balance",
[]string{
val.Address.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=1", flags.FlagHeight),
},
false,
&types.QueryAllBalancesResponse{},
&types.QueryAllBalancesResponse{
Balances: sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens),
sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Sub(s.cfg.BondedTokens)),
),
Pagination: &query.PageResponse{},
},
},
{
"total account balance of a specific denom",
[]string{
val.Address.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=%s", cli.FlagDenom, s.cfg.BondDenom),
fmt.Sprintf("--%s=1", flags.FlagHeight),
},
false,
&sdk.Coin{},
NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Sub(s.cfg.BondedTokens)),
},
{
"total account balance of a bogus denom",
[]string{
val.Address.String(),
fmt.Sprintf("--%s=foobar", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
&sdk.Coin{},
NewCoin("foobar", math.ZeroInt()),
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetBalancesCmd(addresscodec.NewBech32Codec("cosmos"))
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType))
s.Require().Equal(tc.expected.String(), tc.respType.String())
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryTotalSupply() {
val := s.network.Validators[0]
testCases := []struct {
name string
args []string
expectErr bool
respType proto.Message
expected proto.Message
}{
{
name: "total supply",
args: []string{
fmt.Sprintf("--%s=1", flags.FlagHeight),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
respType: &types.QueryTotalSupplyResponse{},
expected: &types.QueryTotalSupplyResponse{
Supply: sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens),
sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(10))),
),
Pagination: &query.PageResponse{Total: 0},
},
},
{
name: "total supply of a specific denomination",
args: []string{
fmt.Sprintf("--%s=1", flags.FlagHeight),
fmt.Sprintf("--%s=%s", cli.FlagDenom, s.cfg.BondDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
respType: &sdk.Coin{},
expected: &sdk.Coin{
Denom: s.cfg.BondDenom,
Amount: s.cfg.StakingTokens.Add(math.NewInt(10)),
},
},
{
name: "total supply of a bogus denom",
args: []string{
fmt.Sprintf("--%s=1", flags.FlagHeight),
fmt.Sprintf("--%s=foobar", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
respType: &sdk.Coin{},
expected: &sdk.Coin{
Denom: "foobar",
Amount: math.ZeroInt(),
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryTotalSupply()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType))
s.Require().Equal(tc.expected, tc.respType)
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryDenomsMetadata() {
val := s.network.Validators[0]
testCases := []struct {
name string
args []string
expectErr bool
respType proto.Message
expected proto.Message
}{
{
name: "all denoms client metadata",
args: []string{
fmt.Sprintf("--%s=1", flags.FlagHeight),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
respType: &types.QueryDenomsMetadataResponse{},
expected: &types.QueryDenomsMetadataResponse{
Metadatas: []types.Metadata{
{
Name: "Cosmos Hub Atom",
Symbol: "ATOM",
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{
Denom: "uatom",
Exponent: 0,
Aliases: []string{"microatom"},
},
{
Denom: "atom",
Exponent: 6,
Aliases: []string{"ATOM"},
},
},
Base: "uatom",
Display: "atom",
},
{
Name: "Ethereum",
Symbol: "ETH",
Description: "Ethereum mainnet token",
DenomUnits: []*types.DenomUnit{
{
Denom: "wei",
Exponent: 0,
Aliases: []string{},
},
{
Denom: "eth",
Exponent: 6,
Aliases: []string{"ETH"},
},
},
Base: "wei",
Display: "eth",
},
},
Pagination: &query.PageResponse{Total: 2},
},
},
{
name: "client metadata of a specific denomination",
args: []string{
fmt.Sprintf("--%s=1", flags.FlagHeight),
fmt.Sprintf("--%s=%s", cli.FlagDenom, "uatom"),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
respType: &types.QueryDenomMetadataResponse{},
expected: &types.QueryDenomMetadataResponse{
Metadata: types.Metadata{
Name: "Cosmos Hub Atom",
Symbol: "ATOM",
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{
Denom: "uatom",
Exponent: 0,
Aliases: []string{"microatom"},
},
{
Denom: "atom",
Exponent: 6,
Aliases: []string{"ATOM"},
},
},
Base: "uatom",
Display: "atom",
},
},
},
{
name: "client metadata of a bogus denom",
args: []string{
fmt.Sprintf("--%s=1", flags.FlagHeight),
fmt.Sprintf("--%s=foobar", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
expectErr: true,
respType: &types.QueryDenomMetadataResponse{},
expected: &types.QueryDenomMetadataResponse{
Metadata: types.Metadata{
DenomUnits: []*types.DenomUnit{},
},
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdDenomsMetadata()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType))
s.Require().Equal(tc.expected, tc.respType)
}
})
}
}
func (s *E2ETestSuite) TestNewSendTxCmdGenOnly() {
val := s.network.Validators[0]

View File

@ -10,7 +10,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/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
@ -353,9 +352,9 @@ func (s *E2ETestSuite) TestNewCmdCancelProposal() {
var balRes banktypes.QueryAllBalancesResponse
var newBalance banktypes.QueryAllBalancesResponse
if !tc.expectErr && tc.expectedCode == 0 {
resp, err := clitestutil.QueryBalancesExec(clientCtx, val.Address, addresscodec.NewBech32Codec("cosmos"))
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val.APIAddress, val.Address.String()))
s.Require().NoError(err)
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
}
@ -364,14 +363,13 @@ func (s *E2ETestSuite) TestNewCmdCancelProposal() {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, tc.expectedCode))
if !tc.expectErr && tc.expectedCode == 0 {
resp, err := clitestutil.QueryBalancesExec(clientCtx, val.Address, addresscodec.NewBech32Codec("cosmos"))
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", val.APIAddress, val.Address.String()))
s.Require().NoError(err)
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &newBalance)
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &newBalance)
s.Require().NoError(err)
remainingAmount := v1.DefaultMinDepositTokens.Mul(
v1.DefaultProposalCancelRatio.Mul(math.LegacyMustNewDecFromStr("100")).TruncateInt(),

View File

@ -1242,11 +1242,11 @@ func (s *CLITestSuite) TestAuxToFeeWithTips() {
}
func (s *CLITestSuite) getBalances(clientCtx client.Context, addr sdk.AccAddress, denom string) math.Int {
resp, err := clitestutil.QueryBalancesExec(clientCtx, addr, s.ac)
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s/by_denom?denom=%s", s.baseCtx.NodeURI, addr.String(), denom))
s.Require().NoError(err)
var balRes banktypes.QueryAllBalancesResponse
err = clientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
err = clientCtx.Codec.UnmarshalJSON(resp, &balRes)
s.Require().NoError(err)
startTokens := balRes.Balances.AmountOf(denom)
return startTokens

View File

@ -9,7 +9,6 @@ import (
"cosmossdk.io/core/address"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/x/bank/client/cli"
)
@ -37,10 +36,3 @@ func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, ac add
return ExecTestCLICmd(clientCtx, cli.NewSendTxCmd(ac), args)
}
func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, ac address.Codec, extraArgs ...string) (testutil.BufferWriter, error) {
args := []string{address.String(), fmt.Sprintf("--%s=json", flags.FlagOutput)}
args = append(args, extraArgs...)
return ExecTestCLICmd(clientCtx, cli.GetBalancesCmd(ac), args)
}

91
x/bank/autocli.go Normal file
View File

@ -0,0 +1,91 @@
package bank
import (
"strings"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
)
// AutoCLIOptions implements the autocli.HasAutoCLIConfig interface.
func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
return &autocliv1.ModuleOptions{
Query: &autocliv1.ServiceCommandDescriptor{
Service: bankv1beta1.Query_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Balance",
Use: "balance [address] [denom]",
Short: "Query an account balance by address and denom",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}, {ProtoField: "denom"}},
},
{
RpcMethod: "AllBalances",
Use: "balances [address]",
Short: "Query for account balances by address",
Long: "Query the total balance of an account or of a specific denomination.",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}},
},
{
RpcMethod: "SpendableBalances",
Use: "spendable-balances [address]",
Short: "Query for account spendable balances by address",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}},
},
{
RpcMethod: "SpendableBalanceByDenom",
Use: "spendable-balances [address] [denom]",
Short: "Query the spendable balance of a single denom for a single account.",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}, {ProtoField: "denom"}},
},
{
RpcMethod: "TotalSupply",
Use: "total-supply",
Alias: []string{"total"},
Short: "Query the total supply of coins of the chain",
Long: "Query total supply of coins that are held by accounts in the chain. To query for the total supply of a specific coin denomination use --denom flag.",
},
{
RpcMethod: "SupplyOf",
Use: "total-supply-of [denom]",
Short: "Query the supply of a single coin denom",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denom"}},
},
{
RpcMethod: "Params",
Use: "params",
Short: "Query the current bank parameters",
},
{
RpcMethod: "DenomMetadata",
Use: "denom-metadata [denom]",
Short: "Query the client metadata of a given coin denomination",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denom"}},
},
{
RpcMethod: "DenomsMetadata",
Use: "denoms-metadata",
Short: "Query the client metadata for all registered coin denominations",
},
{
RpcMethod: "DenomOwners",
Use: "denom-owners [denom]",
Short: "Query for all account addresses that own a particular token denomination.",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denom"}},
},
{
RpcMethod: "SendEnabled",
Use: "send-enabled [denom1 ...]",
Short: "Query for send enabled entries",
Long: strings.TrimSpace(`Query for send enabled entries that have been specifically set.
To look up one or more specific denoms, supply them as arguments to this command.
To look up all denoms, do not provide any arguments.
`,
),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "denoms"}},
},
},
},
}
}

View File

@ -1,350 +0,0 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"cosmossdk.io/core/address"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
const (
FlagDenom = "denom"
FlagResolveDenom = "resolve-denom"
)
// GetQueryCmd returns the parent command for all x/bank CLi query commands. The
// provided clientCtx should have, at a minimum, a verifier, CometBFT RPC client,
// and marshaler set.
func GetQueryCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the bank module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
cmd.AddCommand(
GetBalancesCmd(ac),
GetSpendableBalancesCmd(ac),
GetCmdQueryTotalSupply(),
GetCmdDenomsMetadata(),
GetCmdQuerySendEnabled(),
)
return cmd
}
func GetBalancesCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "balances [address]",
Short: "Query for account balances by address",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the total balance of an account or of a specific denomination.
Example:
$ %s query %s balances [address]
$ %s query %s balances [address] --denom=[denom]
$ %s query %s balances [address] --resolve-denom
`,
version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
denom, err := cmd.Flags().GetString(FlagDenom)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
addr, err := ac.StringToBytes(args[0])
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
ctx := cmd.Context()
if denom == "" {
resolveDenom, err := cmd.Flags().GetBool(FlagResolveDenom)
if err != nil {
return err
}
params := types.NewQueryAllBalancesRequest(addr, pageReq, resolveDenom)
res, err := queryClient.AllBalances(ctx, params)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
}
params := types.NewQueryBalanceRequest(addr, denom)
res, err := queryClient.Balance(ctx, params)
if err != nil {
return err
}
return clientCtx.PrintProto(res.Balance)
},
}
cmd.Flags().String(FlagDenom, "", "The specific balance denomination to query for")
cmd.Flags().Bool(FlagResolveDenom, false, "Resolve denom to human-readable denom from metadata")
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "all balances")
return cmd
}
func GetSpendableBalancesCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "spendable-balances [address]",
Short: "Query for account spendable balances by address",
Example: fmt.Sprintf("$ %s query %s spendable-balances [address]", version.AppName, types.ModuleName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
denom, err := cmd.Flags().GetString(FlagDenom)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
addr, err := ac.StringToBytes(args[0])
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
ctx := cmd.Context()
if denom == "" {
params := types.NewQuerySpendableBalancesRequest(addr, pageReq)
res, err := queryClient.SpendableBalances(ctx, params)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
}
params := types.NewQuerySpendableBalanceByDenomRequest(addr, denom)
res, err := queryClient.SpendableBalanceByDenom(ctx, params)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
cmd.Flags().String(FlagDenom, "", "The specific balance denomination to query for")
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "spendable balances")
return cmd
}
// GetCmdDenomsMetadata defines the cobra command to query client denomination metadata.
func GetCmdDenomsMetadata() *cobra.Command {
cmd := &cobra.Command{
Use: "denom-metadata",
Short: "Query the client metadata for coin denominations",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the client metadata for all the registered coin denominations
Example:
To query for the client metadata of all coin denominations use:
$ %s query %s denom-metadata
To query for the client metadata of a specific coin denomination use:
$ %s query %s denom-metadata --denom=[denom]
`,
version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
denom, err := cmd.Flags().GetString(FlagDenom)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
if denom == "" {
res, err := queryClient.DenomsMetadata(cmd.Context(), &types.QueryDenomsMetadataRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
}
res, err := queryClient.DenomMetadata(cmd.Context(), &types.QueryDenomMetadataRequest{Denom: denom})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
cmd.Flags().String(FlagDenom, "", "The specific denomination to query client metadata for")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
func GetCmdQueryTotalSupply() *cobra.Command {
cmd := &cobra.Command{
Use: "total",
Short: "Query the total supply of coins of the chain",
Args: cobra.NoArgs,
Long: strings.TrimSpace(
fmt.Sprintf(`Query total supply of coins that are held by accounts in the chain.
Example:
$ %s query %s total
To query for the total supply of a specific coin denomination use:
$ %s query %s total --denom=[denom]
`,
version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
denom, err := cmd.Flags().GetString(FlagDenom)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
ctx := cmd.Context()
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
if denom == "" {
res, err := queryClient.TotalSupply(ctx, &types.QueryTotalSupplyRequest{Pagination: pageReq})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
}
res, err := queryClient.SupplyOf(ctx, &types.QuerySupplyOfRequest{Denom: denom})
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Amount)
},
}
cmd.Flags().String(FlagDenom, "", "The specific balance denomination to query for")
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "all supply totals")
return cmd
}
func GetCmdQuerySendEnabled() *cobra.Command {
cmd := &cobra.Command{
Use: "send-enabled [denom1 ...]",
Short: "Query for send enabled entries",
Long: strings.TrimSpace(`Query for send enabled entries that have been specifically set.
To look up one or more specific denoms, supply them as arguments to this command.
To look up all denoms, do not provide any arguments.
`,
),
Example: strings.TrimSpace(
fmt.Sprintf(`Getting one specific entry:
$ %[1]s query %[2]s send-enabled foocoin
Getting two specific entries:
$ %[1]s query %[2]s send-enabled foocoin barcoin
Getting all entries:
$ %[1]s query %[2]s send-enabled
`,
version.AppName, types.ModuleName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
reqPag, err := client.ReadPageRequest(client.MustFlagSetWithPageKeyDecoded(cmd.Flags()))
if err != nil {
return err
}
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
req := &types.QuerySendEnabledRequest{
Denoms: args,
Pagination: reqPag,
}
res, err := queryClient.SendEnabled(cmd.Context(), req)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "send enabled entries")
return cmd
}

View File

@ -1,428 +0,0 @@
package cli_test
import (
"context"
"fmt"
"io"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/gogoproto/proto"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec/address"
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
func (s *CLITestSuite) TestGetBalancesCmd() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
cmd := cli.GetBalancesCmd(address.NewBech32Codec("cosmos"))
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
ctxGen func() client.Context
args []string
expectResult proto.Message
expectErr bool
}{
{
"valid query",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QueryAllBalancesResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
accounts[0].Address.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QueryAllBalancesResponse{},
false,
},
{
"valid query with denom",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QueryBalanceResponse{
Balance: &sdk.Coin{},
})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
accounts[0].Address.String(),
fmt.Sprintf("--%s=photon", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&sdk.Coin{},
false,
},
{
"invalid Address",
func() client.Context {
return s.baseCtx
},
[]string{
"foo",
},
nil,
true,
},
{
"invalid denom",
func() client.Context {
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Code: 1,
})
return s.baseCtx.WithClient(c)
},
[]string{
accounts[0].Address.String(),
fmt.Sprintf("--%s=foo", cli.FlagDenom),
},
nil,
true,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())
cmd.SetContext(ctx)
cmd.SetArgs(tc.args)
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
out, err := clitestutil.ExecTestCLICmd(tc.ctxGen(), cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(out.Bytes(), tc.expectResult))
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestGetSpendableBalancesCmd() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
cmd := cli.GetSpendableBalancesCmd(address.NewBech32Codec("cosmos"))
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
ctxGen func() client.Context
args []string
expectResult proto.Message
expectErr bool
}{
{
"valid query",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySpendableBalancesResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
accounts[0].Address.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QuerySpendableBalancesResponse{},
false,
},
{
"valid query with denom flag",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySpendableBalanceByDenomRequest{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
accounts[0].Address.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
fmt.Sprintf("--%s=photon", cli.FlagDenom),
},
&types.QuerySpendableBalanceByDenomResponse{},
false,
},
{
"invalid Address",
func() client.Context {
return s.baseCtx
},
[]string{
"foo",
},
nil,
true,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())
cmd.SetContext(ctx)
cmd.SetArgs(tc.args)
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
out, err := clitestutil.ExecTestCLICmd(tc.ctxGen(), cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(out.Bytes(), tc.expectResult))
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestGetCmdDenomsMetadata() {
cmd := cli.GetCmdDenomsMetadata()
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
ctxGen func() client.Context
args []string
expectResult proto.Message
expectErr bool
}{
{
"valid query",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QueryDenomsMetadataResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QueryDenomsMetadataResponse{},
false,
},
{
"valid query with denom",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QueryDenomMetadataResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=photon", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QueryDenomMetadataResponse{},
false,
},
{
"invalid query with denom",
func() client.Context {
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Code: 1,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=foo", cli.FlagDenom),
},
nil,
true,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())
cmd.SetContext(ctx)
cmd.SetArgs(tc.args)
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
out, err := clitestutil.ExecTestCLICmd(tc.ctxGen(), cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(out.Bytes(), tc.expectResult))
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestGetCmdQueryTotalSupply() {
cmd := cli.GetCmdQueryTotalSupply()
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
ctxGen func() client.Context
args []string
expectResult proto.Message
expectErr bool
}{
{
"valid query",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QueryTotalSupplyResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QueryTotalSupplyResponse{},
false,
},
{
"valid query with denom",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySupplyOfResponse{
Amount: sdk.Coin{},
})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=photon", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&sdk.Coin{},
false,
},
{
"invalid query with denom",
func() client.Context {
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Code: 1,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=foo", cli.FlagDenom),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
nil,
true,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())
cmd.SetContext(ctx)
cmd.SetArgs(tc.args)
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
out, err := clitestutil.ExecTestCLICmd(tc.ctxGen(), cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(out.Bytes(), tc.expectResult))
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestGetCmdQuerySendEnabled() {
cmd := cli.GetCmdQuerySendEnabled()
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
ctxGen func() client.Context
args []string
expectResult proto.Message
expectErr bool
}{
{
"valid query",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySendEnabledResponse{
SendEnabled: []*types.SendEnabled{},
})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QuerySendEnabledResponse{},
false,
},
{
"valid query with denoms",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySendEnabledResponse{
SendEnabled: []*types.SendEnabled{},
})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
[]string{
"photon",
"stake",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
&types.QuerySendEnabledResponse{},
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
ctx := svrcmd.CreateExecuteContext(context.Background())
cmd.SetContext(ctx)
cmd.SetArgs(tc.args)
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
out, err := clitestutil.ExecTestCLICmd(tc.ctxGen(), cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(out.Bytes(), tc.expectResult))
s.Require().NoError(err)
}
})
}
}

View File

@ -1,39 +0,0 @@
package cli_test
import (
"io"
"testing"
rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/bank"
)
type CLITestSuite struct {
suite.Suite
kr keyring.Keyring
encCfg testutilmod.TestEncodingConfig
baseCtx client.Context
}
func TestCLITestSuite(t *testing.T) {
suite.Run(t, new(CLITestSuite))
}
func (s *CLITestSuite) SetupSuite() {
s.encCfg = testutilmod.MakeTestEncodingConfig(bank.AppModuleBasic{})
s.kr = keyring.NewInMemory(s.encCfg.Codec)
s.baseCtx = client.Context{}.
WithKeyring(s.kr).
WithTxConfig(s.encCfg.TxConfig).
WithCodec(s.encCfg.Codec).
WithClient(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}).
WithAccountRetriever(client.MockAccountRetriever{}).
WithOutput(io.Discard)
}

View File

@ -4,19 +4,50 @@ import (
"context"
"fmt"
"io"
"testing"
rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
"github.com/stretchr/testify/suite"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/bank/client/cli"
)
type CLITestSuite struct {
suite.Suite
kr keyring.Keyring
encCfg testutilmod.TestEncodingConfig
baseCtx client.Context
}
func TestCLITestSuite(t *testing.T) {
suite.Run(t, new(CLITestSuite))
}
func (s *CLITestSuite) SetupSuite() {
s.encCfg = testutilmod.MakeTestEncodingConfig(bank.AppModuleBasic{})
s.kr = keyring.NewInMemory(s.encCfg.Codec)
s.baseCtx = client.Context{}.
WithKeyring(s.kr).
WithTxConfig(s.encCfg.TxConfig).
WithCodec(s.encCfg.Codec).
WithClient(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}).
WithAccountRetriever(client.MockAccountRetriever{}).
WithOutput(io.Discard)
}
func (s *CLITestSuite) TestSendTxCmd() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
cmd := cli.NewSendTxCmd(address.NewBech32Codec("cosmos"))

View File

@ -19,31 +19,81 @@ func (suite *KeeperTestSuite) TestQueryBalance() {
ctx, queryClient := suite.ctx, suite.queryClient
_, _, addr := testdata.KeyTestPubAddr()
_, err := queryClient.Balance(gocontext.Background(), &types.QueryBalanceRequest{})
suite.Require().Error(err)
_, err = queryClient.Balance(gocontext.Background(), &types.QueryBalanceRequest{Address: addr.String()})
suite.Require().Error(err)
req := types.NewQueryBalanceRequest(addr, "0000")
_, err = queryClient.Balance(gocontext.Background(), req)
suite.Require().Error(err)
req = types.NewQueryBalanceRequest(addr, fooDenom)
res, err := queryClient.Balance(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balance.IsZero())
origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30))
origCoins := sdk.NewCoins(newBarCoin(30))
suite.mockFundAccount(addr)
suite.Require().NoError(testutil.FundAccount(ctx, suite.bankKeeper, addr, origCoins))
res, err = queryClient.Balance(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balance.IsEqual(newFooCoin(50)))
testCases := []struct {
name string
req *types.QueryBalanceRequest
expectErrMsg string
postFn func(res *types.QueryBalanceResponse)
}{
{
"empty request",
&types.QueryBalanceRequest{},
"invalid denom",
nil,
},
{
"invalid denom",
types.NewQueryBalanceRequest(addr, "0000"),
"invalid denom",
nil,
},
{
"empty address",
types.NewQueryBalanceRequest(sdk.AccAddress{}, barDenom),
"empty address string is not allowed",
nil,
},
{
"invalid address",
&types.QueryBalanceRequest{Address: "foo", Denom: barDenom},
"invalid address",
nil,
},
{
"query missing denom",
&types.QueryBalanceRequest{Address: addr.String()},
"invalid denom",
nil,
},
{
"valid query empty result",
types.NewQueryBalanceRequest(addr, fooDenom),
"",
func(res *types.QueryBalanceResponse) {
suite.True(res.Balance.IsZero())
},
},
{
"valid query",
types.NewQueryBalanceRequest(addr, barDenom),
"",
func(res *types.QueryBalanceResponse) {
suite.True(res.Balance.IsEqual(newBarCoin(30)))
},
},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
res, err := queryClient.Balance(gocontext.Background(), tc.req)
if tc.expectErrMsg == "" {
suite.Require().NoError(err)
suite.Require().NotNil(res)
} else {
suite.Require().ErrorContains(err, tc.expectErrMsg)
}
if tc.postFn != nil {
tc.postFn(res)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryAllBalances() {
@ -231,13 +281,12 @@ func (suite *KeeperTestSuite) TestQueryTotalSupply() {
ctx, queryClient := suite.ctx, suite.queryClient
res, err := queryClient.TotalSupply(gocontext.Background(), &types.QueryTotalSupplyRequest{})
suite.Require().NoError(err)
suite.Require().NotNil(res)
genesisSupply := res.Supply
testCoins := sdk.NewCoins(sdk.NewInt64Coin("test", 400000000))
suite.mockMintCoins(mintAcc)
suite.
Require().
NoError(suite.bankKeeper.MintCoins(ctx, minttypes.ModuleName, testCoins))
suite.Require().NoError(suite.bankKeeper.MintCoins(ctx, minttypes.ModuleName, testCoins))
res, err = queryClient.TotalSupply(gocontext.Background(), &types.QueryTotalSupplyRequest{})
suite.Require().NoError(err)
@ -256,9 +305,7 @@ func (suite *KeeperTestSuite) TestQueryTotalSupplyOf() {
expectedTotalSupply := sdk.NewCoins(test1Supply, test2Supply)
suite.mockMintCoins(mintAcc)
suite.
Require().
NoError(suite.bankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply))
suite.Require().NoError(suite.bankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply))
_, err := queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{})
suite.Require().Error(err)
@ -266,8 +313,13 @@ func (suite *KeeperTestSuite) TestQueryTotalSupplyOf() {
res, err := queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{Denom: test1Supply.Denom})
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(test1Supply, res.Amount)
// total supply bogus denom
res, err = queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{Denom: "bogus"})
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(sdk.NewInt64Coin("bogus", 0), res.Amount)
}
func (suite *KeeperTestSuite) TestQueryParams() {
@ -277,7 +329,7 @@ func (suite *KeeperTestSuite) TestQueryParams() {
suite.Require().Equal(suite.bankKeeper.GetParams(suite.ctx), res.GetParams())
}
func (suite *KeeperTestSuite) TestQueryDenomsMetadataRequest() {
func (suite *KeeperTestSuite) TestQueryDenomsMetadata() {
var (
req *types.QueryDenomsMetadataRequest
expMetadata = []types.Metadata(nil)
@ -379,7 +431,7 @@ func (suite *KeeperTestSuite) TestQueryDenomsMetadataRequest() {
}
}
func (suite *KeeperTestSuite) TestQueryDenomMetadataRequest() {
func (suite *KeeperTestSuite) TestQueryDenomMetadata() {
var (
req *types.QueryDenomMetadataRequest
expMetadata = types.Metadata{}
@ -456,7 +508,7 @@ func (suite *KeeperTestSuite) TestQueryDenomMetadataRequest() {
}
}
func (suite *KeeperTestSuite) TestGRPCDenomOwners() {
func (suite *KeeperTestSuite) TestQueryDenomOwners() {
ctx := suite.ctx
keeper := suite.bankKeeper

View File

@ -87,7 +87,7 @@ func (ab AppModuleBasic) GetTxCmd() *cobra.Command {
// GetQueryCmd returns no root query command for the bank module.
func (ab AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd(ab.ac)
return nil
}
// RegisterInterfaces registers interfaces and implementations of the bank module.