Add AllDenomMetadata BankQuery (#1426)
* x/wasm: add AllDenomMetadata BankQuery * x/wasm: fix AllDenomMetadata BankQuery to have pagination and add DenomMetadata BankQuery * Use simplified pagination * Fix request conversion * Add unknown denom test cases * Add test for pagination conversion * Fix nits * Use wasmvm 1.3.0-rc.0 * Fix test --------- Co-authored-by: Nikhil Suri <nikhilsuri@comcast.net>
This commit is contained in:
@@ -10,5 +10,6 @@ func AllCapabilities() []string {
|
||||
"stargate",
|
||||
"cosmwasm_1_1",
|
||||
"cosmwasm_1_2",
|
||||
"cosmwasm_1_3",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,18 @@ import (
|
||||
"fmt"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
abci "github.com/cometbft/cometbft/abci/types"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/query"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
|
||||
|
||||
"github.com/CosmWasm/wasmd/x/wasm/types"
|
||||
)
|
||||
|
||||
type QueryHandler struct {
|
||||
@@ -201,6 +202,27 @@ func BankQuerier(bankKeeper types.BankViewKeeper) func(ctx sdk.Context, request
|
||||
}
|
||||
return json.Marshal(res)
|
||||
}
|
||||
if request.DenomMetadata != nil {
|
||||
denomMetadata, ok := bankKeeper.GetDenomMetaData(ctx, request.DenomMetadata.Denom)
|
||||
if !ok {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrNotFound, request.DenomMetadata.Denom)
|
||||
}
|
||||
res := wasmvmtypes.DenomMetadataResponse{
|
||||
Metadata: ConvertSdkDenomMetadataToWasmDenomMetadata(denomMetadata),
|
||||
}
|
||||
return json.Marshal(res)
|
||||
}
|
||||
if request.AllDenomMetadata != nil {
|
||||
bankQueryRes, err := bankKeeper.DenomsMetadata(ctx, ConvertToDenomsMetadataRequest(request.AllDenomMetadata))
|
||||
if err != nil {
|
||||
return nil, sdkerrors.ErrInvalidRequest
|
||||
}
|
||||
res := wasmvmtypes.AllDenomMetadataResponse{
|
||||
Metadata: ConvertSdkDenomMetadatasToWasmDenomMetadatas(bankQueryRes.Metadatas),
|
||||
NextKey: bankQueryRes.Pagination.NextKey,
|
||||
}
|
||||
return json.Marshal(res)
|
||||
}
|
||||
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown BankQuery variant"}
|
||||
}
|
||||
}
|
||||
@@ -584,6 +606,51 @@ func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin {
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToDenomsMetadataRequest(wasmRequest *wasmvmtypes.AllDenomMetadataQuery) *banktypes.QueryDenomsMetadataRequest {
|
||||
ret := &banktypes.QueryDenomsMetadataRequest{}
|
||||
if wasmRequest.Pagination != nil {
|
||||
ret.Pagination = &query.PageRequest{
|
||||
Key: wasmRequest.Pagination.Key,
|
||||
Limit: uint64(wasmRequest.Pagination.Limit),
|
||||
Reverse: wasmRequest.Pagination.Reverse,
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func ConvertSdkDenomMetadatasToWasmDenomMetadatas(metadata []banktypes.Metadata) []wasmvmtypes.DenomMetadata {
|
||||
converted := make([]wasmvmtypes.DenomMetadata, len(metadata))
|
||||
for i, m := range metadata {
|
||||
converted[i] = ConvertSdkDenomMetadataToWasmDenomMetadata(m)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func ConvertSdkDenomMetadataToWasmDenomMetadata(metadata banktypes.Metadata) wasmvmtypes.DenomMetadata {
|
||||
return wasmvmtypes.DenomMetadata{
|
||||
Description: metadata.Description,
|
||||
DenomUnits: ConvertSdkDenomUnitsToWasmDenomUnits(metadata.DenomUnits),
|
||||
Base: metadata.Base,
|
||||
Display: metadata.Display,
|
||||
Name: metadata.Name,
|
||||
Symbol: metadata.Symbol,
|
||||
URI: metadata.URI,
|
||||
URIHash: metadata.URIHash,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertSdkDenomUnitsToWasmDenomUnits(denomUnits []*banktypes.DenomUnit) []wasmvmtypes.DenomUnit {
|
||||
converted := make([]wasmvmtypes.DenomUnit, len(denomUnits))
|
||||
for i, u := range denomUnits {
|
||||
converted[i] = wasmvmtypes.DenomUnit{
|
||||
Denom: u.Denom,
|
||||
Exponent: u.Exponent,
|
||||
Aliases: u.Aliases,
|
||||
}
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
// ConvertProtoToJSONMarshal unmarshals the given bytes into a proto message and then marshals it to json.
|
||||
// This is done so that clients calling stargate queries do not need to define their own proto unmarshalers,
|
||||
// being able to use response directly by json marshalling, which is supported in cosmwasm.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -356,6 +357,133 @@ func TestBankQuerierBalance(t *testing.T) {
|
||||
assert.Equal(t, exp, got)
|
||||
}
|
||||
|
||||
func TestBankQuerierMetadata(t *testing.T) {
|
||||
metadata := banktypes.Metadata{
|
||||
Name: "Test Token",
|
||||
Base: "utest",
|
||||
DenomUnits: []*banktypes.DenomUnit{
|
||||
{
|
||||
Denom: "utest",
|
||||
Exponent: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mock := bankKeeperMock{GetDenomMetadataFn: func(ctx sdk.Context, denom string) (banktypes.Metadata, bool) {
|
||||
if denom == "utest" {
|
||||
return metadata, true
|
||||
} else {
|
||||
return banktypes.Metadata{}, false
|
||||
}
|
||||
}}
|
||||
|
||||
ctx := sdk.Context{}
|
||||
q := keeper.BankQuerier(mock)
|
||||
gotBz, gotErr := q(ctx, &wasmvmtypes.BankQuery{
|
||||
DenomMetadata: &wasmvmtypes.DenomMetadataQuery{
|
||||
Denom: "utest",
|
||||
},
|
||||
})
|
||||
require.NoError(t, gotErr)
|
||||
var got wasmvmtypes.DenomMetadataResponse
|
||||
require.NoError(t, json.Unmarshal(gotBz, &got))
|
||||
exp := wasmvmtypes.DenomMetadata{
|
||||
Name: "Test Token",
|
||||
Base: "utest",
|
||||
DenomUnits: []wasmvmtypes.DenomUnit{
|
||||
{
|
||||
Denom: "utest",
|
||||
Exponent: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.Equal(t, exp, got.Metadata)
|
||||
|
||||
_, gotErr2 := q(ctx, &wasmvmtypes.BankQuery{
|
||||
DenomMetadata: &wasmvmtypes.DenomMetadataQuery{
|
||||
Denom: "uatom",
|
||||
},
|
||||
})
|
||||
require.Error(t, gotErr2)
|
||||
assert.Contains(t, gotErr2.Error(), "uatom: not found")
|
||||
}
|
||||
|
||||
func TestBankQuerierAllMetadata(t *testing.T) {
|
||||
metadata := []banktypes.Metadata{
|
||||
{
|
||||
Name: "Test Token",
|
||||
Base: "utest",
|
||||
DenomUnits: []*banktypes.DenomUnit{
|
||||
{
|
||||
Denom: "utest",
|
||||
Exponent: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mock := bankKeeperMock{GetDenomsMetadataFn: func(ctx context.Context, req *banktypes.QueryDenomsMetadataRequest) (*banktypes.QueryDenomsMetadataResponse, error) {
|
||||
return &banktypes.QueryDenomsMetadataResponse{
|
||||
Metadatas: metadata,
|
||||
Pagination: &query.PageResponse{},
|
||||
}, nil
|
||||
}}
|
||||
|
||||
ctx := sdk.Context{}
|
||||
q := keeper.BankQuerier(mock)
|
||||
gotBz, gotErr := q(ctx, &wasmvmtypes.BankQuery{
|
||||
AllDenomMetadata: &wasmvmtypes.AllDenomMetadataQuery{},
|
||||
})
|
||||
require.NoError(t, gotErr)
|
||||
var got wasmvmtypes.AllDenomMetadataResponse
|
||||
require.NoError(t, json.Unmarshal(gotBz, &got))
|
||||
exp := wasmvmtypes.AllDenomMetadataResponse{
|
||||
Metadata: []wasmvmtypes.DenomMetadata{
|
||||
{
|
||||
Name: "Test Token",
|
||||
Base: "utest",
|
||||
DenomUnits: []wasmvmtypes.DenomUnit{
|
||||
{
|
||||
Denom: "utest",
|
||||
Exponent: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.Equal(t, exp, got)
|
||||
}
|
||||
|
||||
func TestBankQuerierAllMetadataPagination(t *testing.T) {
|
||||
var capturedPagination *query.PageRequest
|
||||
mock := bankKeeperMock{GetDenomsMetadataFn: func(ctx context.Context, req *banktypes.QueryDenomsMetadataRequest) (*banktypes.QueryDenomsMetadataResponse, error) {
|
||||
capturedPagination = req.Pagination
|
||||
return &banktypes.QueryDenomsMetadataResponse{
|
||||
Metadatas: []banktypes.Metadata{},
|
||||
Pagination: &query.PageResponse{
|
||||
NextKey: nil,
|
||||
},
|
||||
}, nil
|
||||
}}
|
||||
|
||||
ctx := sdk.Context{}
|
||||
q := keeper.BankQuerier(mock)
|
||||
_, gotErr := q(ctx, &wasmvmtypes.BankQuery{
|
||||
AllDenomMetadata: &wasmvmtypes.AllDenomMetadataQuery{
|
||||
Pagination: &wasmvmtypes.PageRequest{
|
||||
Key: []byte("key"),
|
||||
Limit: 10,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, gotErr)
|
||||
exp := &query.PageRequest{
|
||||
Key: []byte("key"),
|
||||
Limit: 10,
|
||||
}
|
||||
assert.Equal(t, exp, capturedPagination)
|
||||
}
|
||||
|
||||
func TestContractInfoWasmQuerier(t *testing.T) {
|
||||
myValidContractAddr := keeper.RandomBech32AccountAddress(t)
|
||||
myCreatorAddr := keeper.RandomBech32AccountAddress(t)
|
||||
@@ -676,6 +804,8 @@ type bankKeeperMock struct {
|
||||
GetSupplyFn func(ctx sdk.Context, denom string) sdk.Coin
|
||||
GetBalanceFn func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
|
||||
GetAllBalancesFn func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
|
||||
GetDenomMetadataFn func(ctx sdk.Context, denom string) (banktypes.Metadata, bool)
|
||||
GetDenomsMetadataFn func(ctx context.Context, req *banktypes.QueryDenomsMetadataRequest) (*banktypes.QueryDenomsMetadataResponse, error)
|
||||
}
|
||||
|
||||
func (m bankKeeperMock) GetSupply(ctx sdk.Context, denom string) sdk.Coin {
|
||||
@@ -699,6 +829,20 @@ func (m bankKeeperMock) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk
|
||||
return m.GetAllBalancesFn(ctx, addr)
|
||||
}
|
||||
|
||||
func (m bankKeeperMock) GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) {
|
||||
if m.GetDenomMetadataFn == nil {
|
||||
panic("not expected to be called")
|
||||
}
|
||||
return m.GetDenomMetadataFn(ctx, denom)
|
||||
}
|
||||
|
||||
func (m bankKeeperMock) DenomsMetadata(ctx context.Context, req *banktypes.QueryDenomsMetadataRequest) (*banktypes.QueryDenomsMetadataResponse, error) {
|
||||
if m.GetDenomsMetadataFn == nil {
|
||||
panic("not expected to be called")
|
||||
}
|
||||
return m.GetDenomsMetadataFn(ctx, req)
|
||||
}
|
||||
|
||||
func TestConvertProtoToJSONMarshal(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
@@ -20,6 +21,8 @@ type BankViewKeeper interface {
|
||||
GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
|
||||
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
|
||||
GetSupply(ctx sdk.Context, denom string) sdk.Coin
|
||||
GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool)
|
||||
DenomsMetadata(ctx context.Context, req *banktypes.QueryDenomsMetadataRequest) (*banktypes.QueryDenomsMetadataResponse, error)
|
||||
}
|
||||
|
||||
// Burner is a subset of the sdk bank keeper methods
|
||||
|
||||
Reference in New Issue
Block a user