feat: add command line for nft module (#10505)

<!--
The default pull request template is for types feat, fix, or refactor.
For other templates, add one of the following parameters to the url:
- template=docs.md
- template=other.md
-->

## Description

Add nft module command line and unit test,refer #9826

<!-- Add a description of the changes that this PR introduces and the files that
are the most critical to review. -->

---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Zhiqiang Zhang 2021-11-10 21:00:10 +08:00 committed by GitHub
parent 3f3ca314f1
commit 4ee10b6bd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1651 additions and 74 deletions

View File

@ -7614,7 +7614,7 @@ Query defines the gRPC querier service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Balance` | [QueryBalanceRequest](#cosmos.nft.v1beta1.QueryBalanceRequest) | [QueryBalanceResponse](#cosmos.nft.v1beta1.QueryBalanceResponse) | Balance queries the number of NFTs of a given class owned by the owner, same as balanceOf in ERC721 | GET|/cosmos/nft/v1beta1/balance/{class_id}/{owner}|
| `Balance` | [QueryBalanceRequest](#cosmos.nft.v1beta1.QueryBalanceRequest) | [QueryBalanceResponse](#cosmos.nft.v1beta1.QueryBalanceResponse) | Balance queries the number of NFTs of a given class owned by the owner, same as balanceOf in ERC721 | GET|/cosmos/nft/v1beta1/balance/{owner}/{class_id}|
| `Owner` | [QueryOwnerRequest](#cosmos.nft.v1beta1.QueryOwnerRequest) | [QueryOwnerResponse](#cosmos.nft.v1beta1.QueryOwnerResponse) | Owner queries the owner of the NFT based on its class and id, same as ownerOf in ERC721 | GET|/cosmos/nft/v1beta1/owner/{class_id}/{id}|
| `Supply` | [QuerySupplyRequest](#cosmos.nft.v1beta1.QuerySupplyRequest) | [QuerySupplyResponse](#cosmos.nft.v1beta1.QuerySupplyResponse) | Supply queries the number of NFTs from the given class, same as totalSupply of ERC721. | GET|/cosmos/nft/v1beta1/supply/{class_id}|
| `NFTsOfClass` | [QueryNFTsOfClassRequest](#cosmos.nft.v1beta1.QueryNFTsOfClassRequest) | [QueryNFTsOfClassResponse](#cosmos.nft.v1beta1.QueryNFTsOfClassResponse) | NFTsOfClass queries all NFTs of a given class or optional owner, similar to tokenByIndex in ERC721Enumerable | GET|/cosmos/nft/v1beta1/nfts/{class_id}|

View File

@ -11,7 +11,7 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/nft";
service Query {
// Balance queries the number of NFTs of a given class owned by the owner, same as balanceOf in ERC721
rpc Balance(QueryBalanceRequest) returns (QueryBalanceResponse) {
option (google.api.http).get = "/cosmos/nft/v1beta1/balance/{class_id}/{owner}";
option (google.api.http).get = "/cosmos/nft/v1beta1/balance/{owner}/{class_id}";
}
// Owner queries the owner of the NFT based on its class and id, same as ownerOf in ERC721

255
x/nft/client/cli/query.go Normal file
View File

@ -0,0 +1,255 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"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/nft"
)
// Flag names and values
const (
FlagOwner = "owner"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd() *cobra.Command {
nftQueryCmd := &cobra.Command{
Use: nft.ModuleName,
Short: "Querying commands for the nft module",
Long: "",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
nftQueryCmd.AddCommand(
GetCmdQueryClass(),
GetCmdQueryClasses(),
GetCmdQueryNFT(),
GetCmdQueryNFTs(),
GetCmdQueryOwner(),
GetCmdQueryBalance(),
GetCmdQuerySupply(),
)
return nftQueryCmd
}
// GetCmdQueryClass implements the query class command.
func GetCmdQueryClass() *cobra.Command {
cmd := &cobra.Command{
Use: "class [class-id]",
Args: cobra.ExactArgs(1),
Short: "query an NFT class based on its id",
Example: fmt.Sprintf(`$ %s query %s class <class-id>`, version.AppName, nft.ModuleName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
res, err := queryClient.Class(cmd.Context(), &nft.QueryClassRequest{
ClassId: args[0],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryClasses implements the query classes command.
func GetCmdQueryClasses() *cobra.Command {
cmd := &cobra.Command{
Use: "classes",
Short: "query all NFT classes",
Example: fmt.Sprintf(`$ %s query %s classes`, version.AppName, nft.ModuleName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.Classes(cmd.Context(), &nft.QueryClassesRequest{
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "classes")
return cmd
}
// GetCmdQueryNFT implements the query nft command.
func GetCmdQueryNFT() *cobra.Command {
cmd := &cobra.Command{
Use: "nft [class-id] [nft-id]",
Args: cobra.ExactArgs(2),
Short: "query an NFT based on its class and id.",
Example: fmt.Sprintf(`$ %s query %s nft`, version.AppName, nft.ModuleName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
res, err := queryClient.NFT(cmd.Context(), &nft.QueryNFTRequest{
ClassId: args[0],
Id: args[1],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryNFTs implements the query nft command.
func GetCmdQueryNFTs() *cobra.Command {
cmd := &cobra.Command{
Use: "nfts [class-id]",
Args: cobra.ExactArgs(1),
Short: "query all NFTs of a given class or owner address.",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all NFTs of a given class or owner address. If owner
is set, all nfts that belong to the owner are filtered out.
Examples:
$ %s query %s nfts <class-id> --owner=<owner>
`,
version.AppName, nft.ModuleName),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
request := &nft.QueryNFTsOfClassRequest{
ClassId: args[0],
Pagination: pageReq,
}
owner, err := cmd.Flags().GetString(FlagOwner)
if err != nil {
return err
}
if len(owner) > 0 {
request.Owner = owner
}
res, err := queryClient.NFTsOfClass(cmd.Context(), request)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "nfts")
cmd.Flags().String(FlagOwner, "", "The owner of the nft")
return cmd
}
// GetCmdQueryOwner implements the query owner command.
func GetCmdQueryOwner() *cobra.Command {
cmd := &cobra.Command{
Use: "owner [class-id] [nft-id]",
Args: cobra.ExactArgs(2),
Short: "query the owner of the NFT based on its class and id.",
Example: fmt.Sprintf(`$ %s query %s owner <class-id> <nft-id>`, version.AppName, nft.ModuleName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
res, err := queryClient.Owner(cmd.Context(), &nft.QueryOwnerRequest{
ClassId: args[0],
Id: args[1],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryBalance implements the query balance command.
func GetCmdQueryBalance() *cobra.Command {
cmd := &cobra.Command{
Use: "balance [owner] [class-id]",
Args: cobra.ExactArgs(2),
Short: "query the number of NFTs of a given class owned by the owner.",
Example: fmt.Sprintf(`$ %s query %s balance <owner> <class-id>`, version.AppName, nft.ModuleName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
res, err := queryClient.Balance(cmd.Context(), &nft.QueryBalanceRequest{
ClassId: args[1],
Owner: args[0],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQuerySupply implements the query supply command.
func GetCmdQuerySupply() *cobra.Command {
cmd := &cobra.Command{
Use: "supply [class-id]",
Args: cobra.ExactArgs(1),
Short: "query the number of nft based on the class.",
Example: fmt.Sprintf(`$ %s query %s supply <class-id>`, version.AppName, nft.ModuleName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := nft.NewQueryClient(clientCtx)
res, err := queryClient.Supply(cmd.Context(), &nft.QuerySupplyRequest{
ClassId: args[0],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

60
x/nft/client/cli/tx.go Normal file
View File

@ -0,0 +1,60 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/nft"
)
// GetTxCmd returns the transaction commands for this module
func GetTxCmd() *cobra.Command {
nftTxCmd := &cobra.Command{
Use: nft.ModuleName,
Short: "nft transactions subcommands",
Long: "Provides the most common nft logic for upper-level applications, compatible with Ethereum's erc721 contract",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
nftTxCmd.AddCommand(
NewCmdSend(),
)
return nftTxCmd
}
func NewCmdSend() *cobra.Command {
cmd := &cobra.Command{
Use: "send [class-id] [nft-id] [receiver] --from [sender]",
Args: cobra.ExactArgs(3),
Short: "transfer ownership of nft",
Long: strings.TrimSpace(fmt.Sprintf(`
$ %s tx %s send <class-id> <nft-id> <receiver> --from <sender> --chain-id <chain-id>`, version.AppName, nft.ModuleName),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
msg := nft.MsgSend{
ClassId: args[0],
Id: args[1],
Sender: clientCtx.GetFromAddress().String(),
Receiver: args[2],
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -0,0 +1,15 @@
package testutil
import (
"testing"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/testutil/network"
)
func TestIntegrationTestSuite(t *testing.T) {
cfg := network.DefaultConfig()
cfg.NumValidators = 1
suite.Run(t, NewIntegrationTestSuite(cfg))
}

View File

@ -0,0 +1,518 @@
package testutil
import (
"fmt"
"github.com/cosmos/cosmos-sdk/testutil/rest"
"github.com/cosmos/cosmos-sdk/x/nft"
)
func (s *IntegrationTestSuite) TestQueryBalanceGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
Owner string
}
expectErr bool
errMsg string
expectValue uint64
}{
{
name: "fail not exist class id",
args: struct {
ClassId string
Owner string
}{
ClassId: "invalid_class_id",
Owner: s.owner.String(),
},
expectErr: true,
errMsg: "invalid class id",
expectValue: 0,
},
{
name: "fail not exist owner",
args: struct {
ClassId string
Owner string
}{
ClassId: ExpNFT.ClassId,
Owner: s.owner.String(),
},
expectErr: false,
expectValue: 0,
},
{
name: "success",
args: struct {
ClassId string
Owner string
}{
ClassId: ExpNFT.ClassId,
Owner: val.Address.String(),
},
expectErr: false,
expectValue: 1,
},
}
balanceURL := val.APIAddress + "/cosmos/nft/v1beta1/balance/%s/%s"
for _, tc := range testCases {
uri := fmt.Sprintf(balanceURL, tc.args.Owner, tc.args.ClassId)
s.Run(tc.name, func() {
resp, _ := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errMsg)
} else {
var g nft.QueryBalanceResponse
err := val.ClientCtx.Codec.UnmarshalJSON(resp, &g)
s.Require().NoError(err)
s.Require().Equal(tc.expectValue, g.Amount)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryOwnerGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
Id string
}
expectErr bool
errMsg string
expectResult string
}{
{
name: "class id is invalid",
args: struct {
ClassId string
Id string
}{
ClassId: "invalid_class_id",
Id: ExpNFT.Id,
},
expectErr: true,
errMsg: "invalid class id",
expectResult: "",
},
{
name: "class id does not exist",
args: struct {
ClassId string
Id string
}{
ClassId: "class-id",
Id: ExpNFT.Id,
},
expectErr: false,
expectResult: "",
},
{
name: "nft id is invalid",
args: struct {
ClassId string
Id string
}{
ClassId: ExpNFT.ClassId,
Id: "invalid_nft_id",
},
expectErr: true,
expectResult: "",
},
{
name: "nft id does not exist",
args: struct {
ClassId string
Id string
}{
ClassId: ExpNFT.ClassId,
Id: "nft-id",
},
expectErr: false,
expectResult: "",
},
{
name: "nft exist",
args: struct {
ClassId string
Id string
}{
ClassId: ExpNFT.ClassId,
Id: ExpNFT.Id,
},
expectErr: false,
expectResult: val.Address.String(),
},
}
ownerURL := val.APIAddress + "/cosmos/nft/v1beta1/owner/%s/%s"
for _, tc := range testCases {
uri := fmt.Sprintf(ownerURL, tc.args.ClassId, tc.args.Id)
s.Run(tc.name, func() {
resp, err := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errMsg)
} else {
s.Require().NoError(err)
var result nft.QueryOwnerResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
}
})
}
}
func (s *IntegrationTestSuite) TestQuerySupplyGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
}
expectErr bool
errMsg string
expectResult uint64
}{
{
name: "class id is invalid",
args: struct {
ClassId string
}{
ClassId: "invalid_class_id",
},
expectErr: true,
errMsg: "invalid class id",
expectResult: 0,
},
{
name: "class id does not exist",
args: struct {
ClassId string
}{
ClassId: "class-id",
},
expectErr: false,
expectResult: 0,
},
{
name: "class id exist",
args: struct {
ClassId string
}{
ClassId: ExpNFT.ClassId,
},
expectErr: false,
expectResult: 1,
},
}
supplyURL := val.APIAddress + "/cosmos/nft/v1beta1/supply/%s"
for _, tc := range testCases {
uri := fmt.Sprintf(supplyURL, tc.args.ClassId)
s.Run(tc.name, func() {
resp, err := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errMsg)
} else {
s.Require().NoError(err)
var result nft.QuerySupplyResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Amount)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryNFTsByOwnerGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
Owner string
}
expectErr bool
errorMsg string
expectResult []*nft.NFT
}{
{
name: "class id is invalid",
args: struct {
ClassId string
Owner string
}{
ClassId: "invalid_class_id",
Owner: s.owner.String(),
},
expectErr: true,
errorMsg: "invalid class id",
expectResult: []*nft.NFT{},
},
{
name: "class id does not exist",
args: struct {
ClassId string
Owner string
}{
ClassId: "class-id",
Owner: s.owner.String(),
},
expectErr: false,
expectResult: []*nft.NFT{},
},
{
name: "owner does not exist",
args: struct {
ClassId string
Owner string
}{
ClassId: ExpNFT.ClassId,
Owner: s.owner.String(),
},
expectErr: false,
expectResult: []*nft.NFT{},
},
{
name: "nft exist",
args: struct {
ClassId string
Owner string
}{
ClassId: ExpNFT.ClassId,
Owner: val.Address.String(),
},
expectErr: false,
expectResult: []*nft.NFT{&ExpNFT},
},
}
nftsOfClassURL := val.APIAddress + "/cosmos/nft/v1beta1/nfts/%s?owner=%s"
for _, tc := range testCases {
uri := fmt.Sprintf(nftsOfClassURL, tc.args.ClassId, tc.args.Owner)
s.Run(tc.name, func() {
resp, err := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
s.Require().NoError(err)
var result nft.QueryNFTsOfClassResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Nfts)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryNFTsOfClassGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
}
expectErr bool
errorMsg string
expectResult []*nft.NFT
}{
{
name: "class id is invalid",
args: struct {
ClassId string
}{
ClassId: "invalid_class_id",
},
expectErr: true,
expectResult: []*nft.NFT{},
},
{
name: "class id does not exist",
args: struct {
ClassId string
}{
ClassId: "class-id",
},
expectErr: false,
expectResult: []*nft.NFT{},
},
{
name: "class id exist",
args: struct {
ClassId string
}{
ClassId: ExpNFT.ClassId,
},
expectErr: false,
expectResult: []*nft.NFT{&ExpNFT},
},
}
nftsOfClassURL := val.APIAddress + "/cosmos/nft/v1beta1/nfts/%s"
for _, tc := range testCases {
uri := fmt.Sprintf(nftsOfClassURL, tc.args.ClassId)
s.Run(tc.name, func() {
resp, err := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
s.Require().NoError(err)
var result nft.QueryNFTsOfClassResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Nfts)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryNFTGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
Id string
}
expectErr bool
errorMsg string
}{
{
name: "class id is invalid",
args: struct {
ClassId string
Id string
}{
ClassId: "invalid_class_id",
Id: ExpNFT.Id,
},
expectErr: true,
errorMsg: "invalid class id",
},
{
name: "class id does not exist",
args: struct {
ClassId string
Id string
}{
ClassId: "class",
Id: ExpNFT.Id,
},
expectErr: true,
errorMsg: "not found nft",
},
{
name: "nft id is invalid",
args: struct {
ClassId string
Id string
}{
ClassId: ExpNFT.ClassId,
Id: "invalid_nft_id",
},
expectErr: true,
errorMsg: "invalid nft id",
},
{
name: "nft id does not exist",
args: struct {
ClassId string
Id string
}{
ClassId: ExpNFT.ClassId,
Id: "nft-id",
},
expectErr: true,
errorMsg: "not found nft",
},
{
name: "exist nft",
args: struct {
ClassId string
Id string
}{
ClassId: ExpNFT.ClassId,
Id: ExpNFT.Id,
},
expectErr: false,
},
}
nftURL := val.APIAddress + "/cosmos/nft/v1beta1/nfts/%s/%s"
for _, tc := range testCases {
uri := fmt.Sprintf(nftURL, tc.args.ClassId, tc.args.Id)
s.Run(tc.name, func() {
resp, err := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
s.Require().NoError(err)
var result nft.QueryNFTResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
s.Require().EqualValues(ExpNFT, *result.Nft)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryClassGRPC() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassId string
}
expectErr bool
errorMsg string
}{
{
name: "class id does not exist",
args: struct {
ClassId string
}{
ClassId: "class-id",
},
expectErr: true,
errorMsg: "not found class",
},
{
name: "class id exist",
args: struct {
ClassId string
}{
ClassId: ExpNFT.ClassId,
},
expectErr: false,
},
}
classURL := val.APIAddress + "/cosmos/nft/v1beta1/classes/%s"
for _, tc := range testCases {
uri := fmt.Sprintf(classURL, tc.args.ClassId)
s.Run(tc.name, func() {
resp, err := rest.GetRequest(uri)
if tc.expectErr {
s.Require().Contains(string(resp), tc.errorMsg)
} else {
s.Require().NoError(err)
var result nft.QueryClassResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
s.Require().EqualValues(ExpClass, *result.Class)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryClassesGRPC() {
val := s.network.Validators[0]
classURL := val.APIAddress + "/cosmos/nft/v1beta1/classes"
resp, err := rest.GetRequest(classURL)
s.Require().NoError(err)
var result nft.QueryClassesResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp, &result)
s.Require().NoError(err)
s.Require().Len(result.Classes, 1)
s.Require().EqualValues(ExpClass, *result.Classes[0])
}

View File

@ -0,0 +1,475 @@
package testutil
import (
"github.com/cosmos/cosmos-sdk/x/nft"
)
func (s *IntegrationTestSuite) TestQueryClass() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
}
expectErr bool
}{
{
name: "class id does not exist",
args: struct {
ClassID string
}{
ClassID: "class",
},
expectErr: true,
},
{
name: "class id exist",
args: struct {
ClassID string
}{
ClassID: testClassID,
},
expectErr: false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryClass(val, tc.args.ClassID)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QueryClassResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(ExpClass, *result.Class)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryClasses() {
val := s.network.Validators[0]
testCases := []struct {
name string
expectErr bool
}{
{
name: "no params",
expectErr: false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryClasses(val)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QueryClassesResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().Len(result.Classes, 1)
s.Require().EqualValues(ExpClass, *result.Classes[0])
}
})
}
}
func (s *IntegrationTestSuite) TestQueryNFT() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
ID string
}
expectErr bool
}{
{
name: "class id does not exist",
args: struct {
ClassID string
ID string
}{
ClassID: "class",
ID: testID,
},
expectErr: true,
},
{
name: "nft id does not exist",
args: struct {
ClassID string
ID string
}{
ClassID: testClassID,
ID: "id",
},
expectErr: true,
},
{
name: "exist nft",
args: struct {
ClassID string
ID string
}{
ClassID: testClassID,
ID: testID,
},
expectErr: false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryNFT(val, tc.args.ClassID, tc.args.ID)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QueryNFTResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(ExpNFT, *result.Nft)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryNFTs() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
}
expectErr bool
expectResult []*nft.NFT
}{
{
name: "class id does not exist",
args: struct {
ClassID string
}{
ClassID: "class",
},
expectErr: false,
expectResult: []*nft.NFT{},
},
{
name: "class id exist",
args: struct {
ClassID string
}{
ClassID: testClassID,
},
expectErr: false,
expectResult: []*nft.NFT{&ExpNFT},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryNFTs(val, tc.args.ClassID)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QueryNFTsOfClassResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Nfts)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryNFTsByOwner() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
Owner string
}
expectErr bool
expectResult []*nft.NFT
}{
{
name: "class id does not exist",
args: struct {
ClassID string
Owner string
}{
ClassID: "class",
Owner: val.Address.String(),
},
expectErr: false,
expectResult: []*nft.NFT{},
},
{
name: "owner does not exist",
args: struct {
ClassID string
Owner string
}{
ClassID: testClassID,
Owner: s.owner.String(),
},
expectErr: false,
expectResult: []*nft.NFT{},
},
{
name: "nft exist",
args: struct {
ClassID string
Owner string
}{
ClassID: testClassID,
Owner: val.Address.String(),
},
expectErr: false,
expectResult: []*nft.NFT{&ExpNFT},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryNFTsByOwner(val, tc.args.ClassID, tc.args.Owner)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QueryNFTsOfClassResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Nfts)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryOwner() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
ID string
}
expectErr bool
errorMsg string
expectResult string
}{
{
name: "class id is invalid",
args: struct {
ClassID string
ID string
}{
ClassID: "invalid_class_id",
ID: testID,
},
expectErr: true,
errorMsg: "invalid class id",
expectResult: "",
},
{
name: "class id does not exist",
args: struct {
ClassID string
ID string
}{
ClassID: "class",
ID: testID,
},
expectErr: false,
expectResult: "",
},
{
name: "nft id is invalid",
args: struct {
ClassID string
ID string
}{
ClassID: testClassID,
ID: "invalid_nft_id",
},
expectErr: true,
expectResult: "",
},
{
name: "nft id does not exist",
args: struct {
ClassID string
ID string
}{
ClassID: testClassID,
ID: "nft-id",
},
expectErr: false,
expectResult: "",
},
{
name: "nft exist",
args: struct {
ClassID string
ID string
}{
ClassID: testClassID,
ID: testID,
},
expectErr: false,
expectResult: val.Address.String(),
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryOwner(val, tc.args.ClassID, tc.args.ID)
if tc.expectErr {
s.Require().Contains(string(resp.Bytes()), tc.errorMsg)
} else {
s.Require().NoError(err)
var result nft.QueryOwnerResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Owner)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryBalance() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
Owner string
}
expectErr bool
errorMsg string
expectResult uint64
}{
{
name: "class id is invalid",
args: struct {
ClassID string
Owner string
}{
ClassID: "invalid_class_id",
Owner: val.Address.String(),
},
expectErr: true,
errorMsg: "invalid class id",
expectResult: 0,
},
{
name: "class id does not exist",
args: struct {
ClassID string
Owner string
}{
ClassID: "class",
Owner: val.Address.String(),
},
expectErr: false,
expectResult: 0,
},
{
name: "owner does not exist",
args: struct {
ClassID string
Owner string
}{
ClassID: testClassID,
Owner: s.owner.String(),
},
expectErr: false,
expectResult: 0,
},
{
name: "nft exist",
args: struct {
ClassID string
Owner string
}{
ClassID: testClassID,
Owner: val.Address.String(),
},
expectErr: false,
expectResult: 1,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQueryBalance(val, tc.args.ClassID, tc.args.Owner)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QueryBalanceResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Amount)
}
})
}
}
func (s *IntegrationTestSuite) TestQuerySupply() {
val := s.network.Validators[0]
testCases := []struct {
name string
args struct {
ClassID string
}
expectErr bool
errorMsg string
expectResult uint64
}{
{
name: "class id is invalid",
args: struct {
ClassID string
}{
ClassID: "invalid_class_id",
},
expectErr: true,
errorMsg: "invalid class id",
expectResult: 0,
},
{
name: "class id does not exist",
args: struct {
ClassID string
}{
ClassID: "class",
},
expectErr: false,
expectResult: 0,
},
{
name: "class id exist",
args: struct {
ClassID string
}{
ClassID: testClassID,
},
expectErr: false,
expectResult: 1,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
resp, err := ExecQuerySupply(val, tc.args.ClassID)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
var result nft.QuerySupplyResponse
err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result)
s.Require().NoError(err)
s.Require().EqualValues(tc.expectResult, result.Amount)
}
})
}
}

View File

@ -0,0 +1,84 @@
package testutil
import (
"fmt"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/x/nft/client/cli"
)
func ExecSend(val *network.Validator, args []string) (testutil.BufferWriter, error) {
cmd := cli.NewCmdSend()
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryClass(val *network.Validator, classID string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryClass()
var args []string
args = append(args, classID)
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryClasses(val *network.Validator) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryClasses()
var args []string
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryNFT(val *network.Validator, classID, nftID string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryNFT()
var args []string
args = append(args, classID)
args = append(args, nftID)
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryNFTs(val *network.Validator, classID string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryNFTs()
var args []string
args = append(args, classID)
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryNFTsByOwner(val *network.Validator, classID, owner string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryNFTs()
var args []string
args = append(args, classID)
args = append(args, fmt.Sprintf("--%s=%s", cli.FlagOwner, owner))
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryOwner(val *network.Validator, classID, nftID string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryOwner()
var args []string
args = append(args, classID)
args = append(args, nftID)
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQueryBalance(val *network.Validator, classID, owner string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQueryBalance()
var args []string
args = append(args, owner)
args = append(args, classID)
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}
func ExecQuerySupply(val *network.Validator, classID string) (testutil.BufferWriter, error) {
cmd := cli.GetCmdQuerySupply()
var args []string
args = append(args, classID)
args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag))
return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
}

166
x/nft/client/testutil/tx.go Normal file
View File

@ -0,0 +1,166 @@
package testutil
import (
"fmt"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/cosmos/cosmos-sdk/x/nft"
)
const (
OwnerName = "owner"
Owner = "cosmos1kznrznww4pd6gx0zwrpthjk68fdmqypjpkj5hp"
OwnerArmor = `-----BEGIN TENDERMINT PRIVATE KEY-----
salt: C3586B75587D2824187D2CDA22B6AFB6
type: secp256k1
kdf: bcrypt
1+15OrCKgjnwym1zO3cjo/SGe3PPqAYChQ5wMHjdUbTZM7mWsH3/ueL6swgjzI3b
DDzEQAPXBQflzNW6wbne9IfT651zCSm+j1MWaGk=
=wEHs
-----END TENDERMINT PRIVATE KEY-----`
testClassID = "kitty"
testClassName = "Crypto Kitty"
testClassSymbol = "kitty"
testClassDescription = "Crypto Kitty"
testClassURI = "class uri"
testID = "kitty1"
testURI = "kitty uri"
)
var (
ExpClass = nft.Class{
Id: testClassID,
Name: testClassName,
Symbol: testClassSymbol,
Description: testClassDescription,
Uri: testClassURI,
}
ExpNFT = nft.NFT{
ClassId: testClassID,
Id: testID,
Uri: testURI,
}
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
owner sdk.AccAddress
}
func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
return &IntegrationTestSuite{cfg: cfg}
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
genesisState := s.cfg.GenesisState
nftGenesis := nft.GenesisState{
Classes: []*nft.Class{&ExpClass},
Entries: []*nft.Entry{{
Owner: Owner,
Nfts: []*nft.NFT{&ExpNFT},
}},
}
nftDataBz, err := s.cfg.Codec.MarshalJSON(&nftGenesis)
s.Require().NoError(err)
genesisState[nft.ModuleName] = nftDataBz
s.cfg.GenesisState = genesisState
s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg)
s.Require().NoError(err)
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err)
s.initAccount()
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestCLITxSend() {
val := s.network.Validators[0]
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, OwnerName),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
}
testCases := []struct {
name string
args []string
expectedCode uint32
expectErr bool
}{
{
"valid transaction",
[]string{
testClassID,
testID,
val.Address.String(),
},
0,
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
clientCtx := val.ClientCtx
args = append(args, tc.args...)
out, err := ExecSend(
val,
args,
)
if tc.expectErr {
s.Require().Error(err)
} else {
var txResp sdk.TxResponse
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
}
}
func (s *IntegrationTestSuite) initAccount() {
val := s.network.Validators[0]
ctx := val.ClientCtx
err := ctx.Keyring.ImportPrivKey(OwnerName, OwnerArmor, "1234567890")
s.Require().NoError(err)
keyinfo, err := ctx.Keyring.Key(OwnerName)
s.Require().NoError(err)
args := []string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
}
s.owner, err = keyinfo.GetAddress()
s.Require().NoError(err)
amount := sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200)))
_, err = banktestutil.MsgSendExec(ctx, val.Address, s.owner, amount, args...)
s.Require().NoError(err)
}

View File

@ -17,6 +17,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/nft"
"github.com/cosmos/cosmos-sdk/x/nft/client/cli"
"github.com/cosmos/cosmos-sdk/x/nft/keeper"
)
@ -39,6 +40,7 @@ func (AppModuleBasic) Name() string {
// module-specific gRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
nft.RegisterMsgServer(cfg.MsgServer(), am.keeper)
nft.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}
// RegisterLegacyAminoCodec registers the nft module's types for the given codec.
@ -71,17 +73,19 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, r *mux.Rou
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the nft module.
func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) {
nft.RegisterQueryHandlerClient(context.Background(), mux, nft.NewQueryClient(clientCtx))
if err := nft.RegisterQueryHandlerClient(context.Background(), mux, nft.NewQueryClient(clientCtx)); err != nil {
panic(err)
}
}
// GetQueryCmd returns the cli query commands for the nft module
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return nil
return cli.GetQueryCmd()
}
// GetTxCmd returns the transaction commands for the nft module
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
return cli.GetTxCmd()
}
// AppModule implements the sdk.AppModule interface

View File

@ -739,50 +739,50 @@ var fileDescriptor_0d24e0db697b0f9d = []byte{
// 734 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x96, 0x4f, 0x4f, 0x13, 0x4f,
0x18, 0xc7, 0x99, 0x96, 0xd2, 0xdf, 0xef, 0x21, 0xf1, 0xcf, 0x48, 0xa4, 0x54, 0xdd, 0x90, 0x45,
0xda, 0x42, 0x65, 0x96, 0x3f, 0x89, 0x27, 0xf4, 0x80, 0xb1, 0xc6, 0x0b, 0x68, 0xe5, 0x64, 0x62,
0xcc, 0xb6, 0xdd, 0xd6, 0x8d, 0x65, 0x67, 0x61, 0xb6, 0x2a, 0x21, 0x1c, 0xe4, 0x60, 0xf4, 0x46,
0xda, 0x42, 0x65, 0x86, 0x3f, 0x89, 0x27, 0xf4, 0x80, 0xb1, 0xc6, 0x0b, 0x68, 0xe5, 0x64, 0x62,
0xcc, 0xb6, 0xdd, 0xd6, 0x8d, 0x65, 0x77, 0x61, 0xb6, 0x2a, 0x21, 0x1c, 0xe4, 0x60, 0xf4, 0x46,
0x14, 0xdf, 0x93, 0x47, 0x12, 0x2f, 0xde, 0x34, 0xe0, 0x0b, 0x31, 0x3b, 0xf3, 0x6c, 0xd9, 0x95,
0xed, 0x6e, 0x43, 0x3c, 0x91, 0xd9, 0xf9, 0x3e, 0xcf, 0xf7, 0x33, 0xf3, 0x3c, 0xf3, 0x50, 0xd0,
0x9a, 0x5c, 0x6c, 0x71, 0x61, 0x38, 0x6d, 0xcf, 0x78, 0xb3, 0xd4, 0xb0, 0x3c, 0x73, 0xc9, 0xd8,
0xee, 0x59, 0x3b, 0xbb, 0xcc, 0xdd, 0xe1, 0x1e, 0xa7, 0x54, 0xed, 0x33, 0xa7, 0xed, 0x31, 0xdc,
0x2f, 0xce, 0x63, 0x4c, 0xc3, 0x14, 0x96, 0x12, 0xf7, 0x43, 0x5d, 0xb3, 0x63, 0x3b, 0xa6, 0x67,
0x73, 0x47, 0xc5, 0x17, 0x6f, 0x76, 0x38, 0xef, 0x74, 0x2d, 0xc3, 0x74, 0x6d, 0xc3, 0x74, 0x1c,
0xee, 0xc9, 0x4d, 0x11, 0xec, 0xc6, 0xb8, 0xfb, 0x4e, 0x72, 0x57, 0xaf, 0xc1, 0xb5, 0xa7, 0x7e,
0xf6, 0x35, 0xb3, 0x6b, 0x3a, 0x4d, 0xab, 0x6e, 0x6d, 0xf7, 0x2c, 0xe1, 0xd1, 0x29, 0xf8, 0xaf,
0xd9, 0x35, 0x85, 0x78, 0x69, 0xb7, 0x0a, 0x64, 0x9a, 0x54, 0xfe, 0xaf, 0xe7, 0xe5, 0xfa, 0x71,
0x8b, 0x4e, 0x40, 0x8e, 0xbf, 0x75, 0xac, 0x9d, 0x42, 0x46, 0x7e, 0x57, 0x0b, 0x9d, 0xc1, 0x44,
0x34, 0x8f, 0x70, 0xb9, 0x23, 0x2c, 0x7a, 0x1d, 0xc6, 0xcc, 0x2d, 0xde, 0x73, 0x3c, 0x99, 0x66,
0xb4, 0x8e, 0x2b, 0xfd, 0x3e, 0x5c, 0x95, 0xfa, 0x0d, 0x3f, 0x7a, 0x08, 0xd7, 0x4b, 0x90, 0xb1,
0x5b, 0x68, 0x99, 0xb1, 0x5b, 0xfa, 0x3c, 0xd0, 0x70, 0x3c, 0xba, 0xf5, 0xd9, 0x48, 0x98, 0xcd,
0x40, 0xed, 0xb3, 0x9e, 0xeb, 0x76, 0x77, 0xd3, 0xcd, 0xf4, 0x05, 0xbc, 0x94, 0x20, 0x20, 0xe5,
0x2c, 0x9f, 0x09, 0x4c, 0x4a, 0xfd, 0x7a, 0x6d, 0x53, 0x6c, 0xb4, 0x1f, 0xf8, 0x59, 0x2e, 0x7a,
0x91, 0xb4, 0x06, 0x70, 0x56, 0xe0, 0x42, 0x76, 0x9a, 0x54, 0xc6, 0x97, 0x4b, 0x0c, 0x3b, 0xc4,
0xef, 0x06, 0xa6, 0x5a, 0x07, 0x4b, 0xc9, 0x9e, 0x98, 0x9d, 0xa0, 0x6a, 0xf5, 0x50, 0xa4, 0x7e,
0x48, 0xa0, 0x70, 0x1e, 0x0a, 0x4f, 0x52, 0x85, 0x51, 0xa7, 0xed, 0x89, 0x02, 0x99, 0xce, 0x56,
0xc6, 0x97, 0x27, 0xd9, 0xf9, 0x06, 0x64, 0xeb, 0xb5, 0xcd, 0xba, 0x14, 0xd1, 0x47, 0x11, 0xa2,
0x8c, 0x24, 0x2a, 0xa7, 0x12, 0x29, 0xa7, 0x08, 0xd2, 0x2a, 0x5c, 0x0e, 0x88, 0x2e, 0x50, 0xf1,
0x7b, 0x70, 0xe5, 0x2c, 0x1a, 0xcf, 0x31, 0x07, 0x59, 0xa7, 0xad, 0xca, 0x91, 0x70, 0x0c, 0x5f,
0xa3, 0x33, 0x6c, 0xb8, 0x21, 0xab, 0xa3, 0x3f, 0xc4, 0xa6, 0x89, 0x5e, 0x9c, 0x01, 0x39, 0x29,
0x40, 0xcb, 0xa9, 0x38, 0x4b, 0x15, 0xa1, 0x74, 0xfa, 0x0b, 0x6c, 0x25, 0xf9, 0xd1, 0xea, 0x1b,
0x47, 0xab, 0x4c, 0x2e, 0x5c, 0xe5, 0x23, 0x82, 0xef, 0xae, 0x9f, 0x1f, 0x41, 0x57, 0x40, 0x9d,
0xc4, 0x0a, 0x8a, 0x9c, 0x80, 0x1a, 0x28, 0xff, 0x59, 0xa5, 0x97, 0x7f, 0xe6, 0x21, 0x27, 0xb1,
0xe8, 0x11, 0x81, 0x3c, 0xce, 0x04, 0x5a, 0x8e, 0x43, 0x88, 0x99, 0x3e, 0xc5, 0x4a, 0xba, 0x50,
0x99, 0xea, 0x77, 0x0f, 0xbe, 0xff, 0xfe, 0x92, 0x59, 0xa4, 0xcc, 0x88, 0x99, 0x72, 0x0d, 0x25,
0x36, 0xf6, 0x82, 0x1a, 0xef, 0x1b, 0x7b, 0xf2, 0x91, 0xed, 0xd3, 0x4f, 0x04, 0x72, 0x72, 0x74,
0xd0, 0xd9, 0x81, 0x5e, 0xe1, 0xd1, 0x54, 0x2c, 0xa5, 0xc9, 0x10, 0x68, 0x49, 0x02, 0x55, 0xe9,
0x5c, 0x1c, 0x90, 0x34, 0x8f, 0xe0, 0xd8, 0xad, 0x7d, 0xfa, 0x91, 0xc0, 0x98, 0x9a, 0x34, 0x74,
0xb0, 0x4b, 0x64, 0x76, 0x15, 0xcb, 0xa9, 0x3a, 0xc4, 0x59, 0x90, 0x38, 0x65, 0x3a, 0x1b, 0x87,
0x23, 0xa4, 0x36, 0xc4, 0x43, 0xbf, 0x12, 0x18, 0x0f, 0xcd, 0x0b, 0x5a, 0x1d, 0xe8, 0x73, 0x7e,
0xd4, 0x15, 0xef, 0x0c, 0x27, 0x46, 0xb2, 0xaa, 0x24, 0x9b, 0xa5, 0x33, 0x46, 0xfc, 0xff, 0x27,
0x11, 0xe6, 0x3a, 0x20, 0x90, 0x5d, 0xaf, 0x6d, 0xd2, 0x99, 0x24, 0x8b, 0x80, 0xe3, 0x76, 0xb2,
0x08, 0xfd, 0x17, 0xa5, 0xff, 0x3c, 0xad, 0x0c, 0xe1, 0xaf, 0xea, 0xf4, 0x81, 0x40, 0x4e, 0x5d,
0xcb, 0xe0, 0x9e, 0x89, 0x5c, 0x48, 0x29, 0x4d, 0x86, 0x28, 0x4c, 0xa2, 0x54, 0x68, 0x29, 0x0e,
0x05, 0xdf, 0x66, 0xf8, 0x36, 0xde, 0x13, 0xc8, 0xe3, 0x7b, 0x4f, 0x78, 0x53, 0xd1, 0x89, 0x93,
0xf0, 0xa6, 0xfe, 0x1a, 0x1d, 0xfa, 0x8c, 0xc4, 0xb9, 0x45, 0x6f, 0x24, 0xe0, 0xac, 0xad, 0x7e,
0x3b, 0xd1, 0xc8, 0xf1, 0x89, 0x46, 0x7e, 0x9d, 0x68, 0xe4, 0xf0, 0x54, 0x1b, 0x39, 0x3e, 0xd5,
0x46, 0x7e, 0x9c, 0x6a, 0x23, 0xcf, 0xf5, 0x8e, 0xed, 0xbd, 0xea, 0x35, 0x58, 0x93, 0x6f, 0x05,
0x09, 0xd4, 0x9f, 0x05, 0xd1, 0x7a, 0x6d, 0xbc, 0xf3, 0xb3, 0x35, 0xc6, 0xe4, 0x8f, 0x8f, 0x95,
0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x08, 0xc1, 0xd7, 0x1a, 0x09, 0x00, 0x00,
0xed, 0x6e, 0x43, 0x3c, 0x91, 0xd9, 0xf9, 0x3e, 0xf3, 0xfd, 0xcc, 0xf3, 0x3c, 0xf3, 0x50, 0xd0,
0x9a, 0x8e, 0xd8, 0x72, 0x04, 0xb7, 0xdb, 0x1e, 0x7f, 0xb3, 0xd4, 0x30, 0x3d, 0x63, 0x89, 0x6f,
0xf7, 0xcc, 0x9d, 0x5d, 0xe6, 0xee, 0x38, 0x9e, 0x43, 0xa9, 0xda, 0x67, 0x76, 0xdb, 0x63, 0xb8,
0x5f, 0x9c, 0xc7, 0x98, 0x86, 0x21, 0x4c, 0x25, 0xee, 0x87, 0xba, 0x46, 0xc7, 0xb2, 0x0d, 0xcf,
0x72, 0x6c, 0x15, 0x5f, 0xbc, 0xd9, 0x71, 0x9c, 0x4e, 0xd7, 0xe4, 0x86, 0x6b, 0x71, 0xc3, 0xb6,
0x1d, 0x4f, 0x6e, 0x8a, 0x60, 0x37, 0xc6, 0xdd, 0x77, 0x92, 0xbb, 0x7a, 0x0d, 0xae, 0x3d, 0xf5,
0x4f, 0x5f, 0x33, 0xba, 0x86, 0xdd, 0x34, 0xeb, 0xe6, 0x76, 0xcf, 0x14, 0x1e, 0x9d, 0x82, 0xff,
0x9a, 0x5d, 0x43, 0x88, 0x97, 0x56, 0xab, 0x40, 0xa6, 0x49, 0xe5, 0xff, 0x7a, 0x5e, 0xae, 0x1f,
0xb7, 0xe8, 0x04, 0xe4, 0x9c, 0xb7, 0xb6, 0xb9, 0x53, 0xc8, 0xc8, 0xef, 0x6a, 0xa1, 0x33, 0x98,
0x88, 0x9e, 0x23, 0x5c, 0xc7, 0x16, 0x26, 0xbd, 0x0e, 0x63, 0xc6, 0x96, 0xd3, 0xb3, 0x3d, 0x79,
0xcc, 0x68, 0x1d, 0x57, 0xfa, 0x7d, 0xb8, 0x2a, 0xf5, 0x1b, 0x7e, 0xf4, 0x10, 0xae, 0x97, 0x20,
0x63, 0xb5, 0xd0, 0x32, 0x63, 0xb5, 0xf4, 0x79, 0xa0, 0xe1, 0x78, 0x74, 0xeb, 0xb3, 0x91, 0x30,
0x1b, 0x47, 0xed, 0xb3, 0x9e, 0xeb, 0x76, 0x77, 0xd3, 0xcd, 0xf4, 0x05, 0x4c, 0x4a, 0x10, 0x90,
0x72, 0x97, 0xcf, 0x04, 0x26, 0xa5, 0x7e, 0xbd, 0xb6, 0x29, 0x36, 0xda, 0x0f, 0xfc, 0x53, 0x2e,
0x9a, 0x48, 0x5a, 0x03, 0x38, 0x2b, 0x70, 0x21, 0x3b, 0x4d, 0x2a, 0xe3, 0xcb, 0x25, 0x86, 0x1d,
0xe2, 0x77, 0x03, 0x53, 0xad, 0x83, 0xa5, 0x64, 0x4f, 0x8c, 0x4e, 0x50, 0xb5, 0x7a, 0x28, 0x52,
0x3f, 0x24, 0x50, 0x38, 0x0f, 0x85, 0x37, 0xa9, 0xc2, 0xa8, 0xdd, 0xf6, 0x44, 0x81, 0x4c, 0x67,
0x2b, 0xe3, 0xcb, 0x93, 0xec, 0x7c, 0x03, 0xb2, 0xf5, 0xda, 0x66, 0x5d, 0x8a, 0xe8, 0xa3, 0x08,
0x51, 0x46, 0x12, 0x95, 0x53, 0x89, 0x94, 0x53, 0x04, 0x69, 0x15, 0x2e, 0x07, 0x44, 0x17, 0xa8,
0xf8, 0x3d, 0xb8, 0x72, 0x16, 0x8d, 0xf7, 0x98, 0x83, 0xac, 0xdd, 0x56, 0xe5, 0x48, 0xb8, 0x86,
0xaf, 0xd1, 0x19, 0x36, 0xdc, 0x90, 0xd5, 0xd1, 0x1f, 0x62, 0xd3, 0x44, 0x13, 0xc7, 0x21, 0x27,
0x05, 0x68, 0x39, 0x15, 0x67, 0xa9, 0x22, 0x94, 0x4e, 0x7f, 0x81, 0xad, 0x24, 0x3f, 0x9a, 0x7d,
0xe3, 0x68, 0x95, 0xc9, 0x85, 0xab, 0x7c, 0x44, 0xf0, 0xdd, 0xf5, 0xcf, 0x47, 0xd0, 0x15, 0x50,
0x37, 0x31, 0x83, 0x22, 0x27, 0xa0, 0x06, 0xca, 0x7f, 0x56, 0xe9, 0xe5, 0x9f, 0x79, 0xc8, 0x49,
0x2c, 0x7a, 0x44, 0x20, 0x8f, 0x33, 0x81, 0x96, 0xe3, 0x10, 0x62, 0xa6, 0x4f, 0xb1, 0x92, 0x2e,
0x54, 0xa6, 0xfa, 0xdd, 0x83, 0xef, 0xbf, 0xbf, 0x64, 0x16, 0x29, 0xe3, 0x31, 0x53, 0xae, 0xa1,
0xc4, 0x7c, 0x4f, 0xbe, 0xac, 0x7d, 0xbe, 0x17, 0xd4, 0x7a, 0x9f, 0x7e, 0x22, 0x90, 0x93, 0xa3,
0x83, 0xce, 0x0e, 0xf4, 0x0a, 0x8f, 0xa6, 0x62, 0x29, 0x4d, 0x86, 0x40, 0x4b, 0x12, 0xa8, 0x4a,
0xe7, 0xe2, 0x80, 0x24, 0x47, 0x08, 0x83, 0xef, 0xf9, 0x2c, 0x1f, 0x09, 0x8c, 0xa9, 0x49, 0x43,
0x07, 0xbb, 0x44, 0x66, 0x57, 0xb1, 0x9c, 0xaa, 0x43, 0x9c, 0x05, 0x89, 0x53, 0xa6, 0xb3, 0x71,
0x38, 0x42, 0x6a, 0xc3, 0x69, 0xf9, 0x4a, 0x60, 0x3c, 0x34, 0x2f, 0x68, 0x75, 0xa0, 0xcf, 0xf9,
0x51, 0x57, 0xbc, 0x33, 0x9c, 0x18, 0xc9, 0xaa, 0x92, 0x6c, 0x96, 0xce, 0xf0, 0xf8, 0xff, 0x4f,
0x22, 0xcc, 0x75, 0x40, 0x20, 0xbb, 0x5e, 0xdb, 0xa4, 0x33, 0x49, 0x16, 0x01, 0xc7, 0xed, 0x64,
0x11, 0xfa, 0x2f, 0x4a, 0xff, 0x79, 0x5a, 0x19, 0xc2, 0x5f, 0xd5, 0xe9, 0x03, 0x81, 0x9c, 0x4a,
0xcb, 0xe0, 0x9e, 0x89, 0x24, 0xa4, 0x94, 0x26, 0x43, 0x14, 0x26, 0x51, 0x2a, 0xb4, 0x14, 0x87,
0x82, 0x6f, 0x33, 0x9c, 0x8d, 0xf7, 0x04, 0xf2, 0xf8, 0xde, 0x13, 0xde, 0x54, 0x74, 0xe2, 0x24,
0xbc, 0xa9, 0xbf, 0x46, 0x87, 0x3e, 0x23, 0x71, 0x6e, 0xd1, 0x1b, 0x09, 0x38, 0x6b, 0xab, 0xdf,
0x4e, 0x34, 0x72, 0x7c, 0xa2, 0x91, 0x5f, 0x27, 0x1a, 0x39, 0x3c, 0xd5, 0x46, 0x8e, 0x4f, 0xb5,
0x91, 0x1f, 0xa7, 0xda, 0xc8, 0x73, 0xbd, 0x63, 0x79, 0xaf, 0x7a, 0x0d, 0xd6, 0x74, 0xb6, 0x82,
0x03, 0xd4, 0x9f, 0x05, 0xd1, 0x7a, 0xcd, 0xdf, 0xf9, 0xa7, 0x35, 0xc6, 0xe4, 0x8f, 0x8f, 0x95,
0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf3, 0xed, 0xff, 0x2d, 0x1a, 0x09, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -42,17 +42,6 @@ func request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, c
_ = err
)
val, ok = pathParams["class_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "class_id")
}
protoReq.ClassId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "class_id", err)
}
val, ok = pathParams["owner"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "owner")
@ -64,6 +53,17 @@ func request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, c
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "owner", err)
}
val, ok = pathParams["class_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "class_id")
}
protoReq.ClassId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "class_id", err)
}
msg, err := client.Balance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
@ -80,17 +80,6 @@ func local_request_Query_Balance_0(ctx context.Context, marshaler runtime.Marsha
_ = err
)
val, ok = pathParams["class_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "class_id")
}
protoReq.ClassId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "class_id", err)
}
val, ok = pathParams["owner"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "owner")
@ -102,6 +91,17 @@ func local_request_Query_Balance_0(ctx context.Context, marshaler runtime.Marsha
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "owner", err)
}
val, ok = pathParams["class_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "class_id")
}
protoReq.ClassId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "class_id", err)
}
msg, err := server.Balance(ctx, &protoReq)
return msg, metadata, err
@ -806,7 +806,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
}
var (
pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "nft", "v1beta1", "balance", "class_id", "owner"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "nft", "v1beta1", "balance", "owner", "class_id"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Query_Owner_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "nft", "v1beta1", "owner", "class_id", "id"}, "", runtime.AssumeColonVerbOpt(false)))

View File

@ -9,12 +9,12 @@ import (
var (
// reClassIDString can be 3 ~ 100 characters long and support letters, followed by either
// a letter, a number or a slash ('/') or a colon (':').
reClassIDString = `[a-zA-Z][a-zA-Z0-9/-:]{2,100}`
// a letter, a number or a slash ('/') or a colon (':') or ('-').
reClassIDString = `[a-zA-Z][a-zA-Z0-9/:-]{2,100}`
reClassID = regexp.MustCompile(fmt.Sprintf(`^%s$`, reClassIDString))
// reNFTIDString can be 3 ~ 100 characters long and support letters, followed by either
// a letter, a number or a slash ('/') or a colon (':').
// a letter, a number or a slash ('/') or a colon (':') or ('-').
reNFTID = reClassID
)