diff --git a/CHANGELOG.md b/CHANGELOG.md index 436e420f..e9f413d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,18 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Bug Fixes +* [\#304](https://github.com/irisnet/irismod/pull/304) Fix nft module import error. + ### Improvements +* [\#305](https://github.com/irisnet/irismod/pull/305) Remove ibc-go from project. +* [\#306](https://github.com/irisnet/irismod/pull/306) Bump up cosmos-sdk to v0.46.1. +* [\#307](https://github.com/irisnet/irismod/pull/307) Refactor proto-gen with docker. +* [\#308](https://github.com/irisnet/irismod/pull/308) Coinswap module adds unilateral injection liquidity function. +* [\#309](https://github.com/irisnet/irismod/pull/309) Refactor nft with cosmos-sdk nft module. + +### API Breaking Changes +* [\#309](https://github.com/irisnet/irismod/pull/309) GRPC method `Owner` rename to `NFTsOfOwner`, Remove deprecated `Queries` api ## [v1.6.0] - 2022-08-08 diff --git a/go.mod b/go.mod index 6ed7a19a..b6e9994f 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/tidwall/gjson v1.14.0 google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b google.golang.org/grpc v1.48.0 + google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -64,7 +65,6 @@ require ( golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/api v0.81.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/modules/mt/client/cli/tx.go b/modules/mt/client/cli/tx.go index 11ee0e5a..378d6d5d 100644 --- a/modules/mt/client/cli/tx.go +++ b/modules/mt/client/cli/tx.go @@ -38,7 +38,7 @@ func NewTxCmd() *cobra.Command { return txCmd } -// GetCmdIssueDenom is the CLI command for an IssueDenom transaction +// GetCmdIssueDenom is the CLI command for an SaveDenom transaction func GetCmdIssueDenom() *cobra.Command { cmd := &cobra.Command{ Use: "issue", diff --git a/modules/mt/types/tx.pb.go b/modules/mt/types/tx.pb.go index 44a3eb7c..4631a428 100644 --- a/modules/mt/types/tx.pb.go +++ b/modules/mt/types/tx.pb.go @@ -7,15 +7,16 @@ import ( bytes "bytes" context "context" fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - io "io" - math "math" - math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -69,7 +70,7 @@ func (m *MsgIssueDenom) XXX_DiscardUnknown() { var xxx_messageInfo_MsgIssueDenom proto.InternalMessageInfo -// MsgIssueDenomResponse defines the Msg/IssueDenom response type. +// MsgIssueDenomResponse defines the Msg/SaveDenom response type. type MsgIssueDenomResponse struct { } @@ -791,7 +792,7 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { func (c *msgClient) IssueDenom(ctx context.Context, in *MsgIssueDenom, opts ...grpc.CallOption) (*MsgIssueDenomResponse, error) { out := new(MsgIssueDenomResponse) - err := c.cc.Invoke(ctx, "/irismod.mt.Msg/IssueDenom", in, out, opts...) + err := c.cc.Invoke(ctx, "/irismod.mt.Msg/SaveDenom", in, out, opts...) if err != nil { return nil, err } @@ -865,7 +866,7 @@ type UnimplementedMsgServer struct { } func (*UnimplementedMsgServer) IssueDenom(ctx context.Context, req *MsgIssueDenom) (*MsgIssueDenomResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method IssueDenom not implemented") + return nil, status.Errorf(codes.Unimplemented, "method SaveDenom not implemented") } func (*UnimplementedMsgServer) TransferDenom(ctx context.Context, req *MsgTransferDenom) (*MsgTransferDenomResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TransferDenom not implemented") @@ -897,7 +898,7 @@ func _Msg_IssueDenom_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/irismod.mt.Msg/IssueDenom", + FullMethod: "/irismod.mt.Msg/SaveDenom", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).IssueDenom(ctx, req.(*MsgIssueDenom)) @@ -1000,7 +1001,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "IssueDenom", + MethodName: "SaveDenom", Handler: _Msg_IssueDenom_Handler, }, { diff --git a/modules/nft/client/cli/cli_test.go b/modules/nft/client/cli/cli_test.go index a68fd94b..a76de8d1 100644 --- a/modules/nft/client/cli/cli_test.go +++ b/modules/nft/client/cli/cli_test.go @@ -168,11 +168,11 @@ func (s *IntegrationTestSuite) TestNft() { s.Require().Equal(from.String(), nftItem.Owner) //------test GetCmdQueryOwner()------------- - respType = proto.Message(&nfttypes.QueryOwnerResponse{}) + respType = proto.Message(&nfttypes.QueryNFTsOfOwnerResponse{}) bz, err = nfttestutil.QueryOwnerExec(val.ClientCtx, from.String()) s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(bz.Bytes(), respType)) - ownerResp := respType.(*nfttypes.QueryOwnerResponse) + ownerResp := respType.(*nfttypes.QueryNFTsOfOwnerResponse) s.Require().Equal(from.String(), ownerResp.Owner.Address) s.Require().Equal(denom, ownerResp.Owner.IDCollections[0].DenomId) s.Require().Equal(tokenID, ownerResp.Owner.IDCollections[0].TokenIds[0]) diff --git a/modules/nft/client/cli/query.go b/modules/nft/client/cli/query.go index f2a44c22..d7627c73 100644 --- a/modules/nft/client/cli/query.go +++ b/modules/nft/client/cli/query.go @@ -102,7 +102,7 @@ func GetCmdQueryOwner() *cobra.Command { return err } queryClient := types.NewQueryClient(clientCtx) - resp, err := queryClient.Owner(context.Background(), &types.QueryOwnerRequest{ + resp, err := queryClient.NFTsOfOwner(context.Background(), &types.QueryNFTsOfOwnerRequest{ DenomId: denomID, Owner: args[0], Pagination: pageReq, diff --git a/modules/nft/client/cli/tx.go b/modules/nft/client/cli/tx.go index 70d7bd54..1e3a2c26 100644 --- a/modules/nft/client/cli/tx.go +++ b/modules/nft/client/cli/tx.go @@ -38,7 +38,7 @@ func NewTxCmd() *cobra.Command { return txCmd } -// GetCmdIssueDenom is the CLI command for an IssueDenom transaction +// GetCmdIssueDenom is the CLI command for an SaveDenom transaction func GetCmdIssueDenom() *cobra.Command { cmd := &cobra.Command{ Use: "issue [denom-id]", @@ -134,7 +134,7 @@ func GetCmdIssueDenom() *cobra.Command { return cmd } -// GetCmdMintNFT is the CLI command for a MintNFT transaction +// GetCmdMintNFT is the CLI command for a SaveNFT transaction func GetCmdMintNFT() *cobra.Command { cmd := &cobra.Command{ Use: "mint [denom-id] [nft-id]", @@ -332,7 +332,7 @@ func GetCmdTransferNFT() *cobra.Command { return cmd } -// GetCmdBurnNFT is the CLI command for sending a BurnNFT transaction +// GetCmdBurnNFT is the CLI command for sending a RemoveNFT transaction func GetCmdBurnNFT() *cobra.Command { cmd := &cobra.Command{ Use: "burn [denom-id] [nft-id]", diff --git a/modules/nft/genesis.go b/modules/nft/genesis.go deleted file mode 100644 index c4e50ff1..00000000 --- a/modules/nft/genesis.go +++ /dev/null @@ -1,34 +0,0 @@ -package nft - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/irisnet/irismod/modules/nft/keeper" - "github.com/irisnet/irismod/modules/nft/types" -) - -// InitGenesis stores the NFT genesis. -func InitGenesis(ctx sdk.Context, k keeper.Keeper, data types.GenesisState) { - if err := types.ValidateGenesis(data); err != nil { - panic(err.Error()) - } - - for _, c := range data.Collections { - if err := k.SetDenom(ctx, c.Denom); err != nil { - panic(err) - } - if err := k.SetCollection(ctx, c); err != nil { - panic(err) - } - } -} - -// ExportGenesis returns a GenesisState for a given context and keeper. -func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - return types.NewGenesisState(k.GetCollections(ctx)) -} - -// DefaultGenesisState returns a default genesis state -func DefaultGenesisState() *types.GenesisState { - return types.NewGenesisState([]types.Collection{}) -} diff --git a/modules/nft/handler.go b/modules/nft/handler.go deleted file mode 100644 index d5c9c408..00000000 --- a/modules/nft/handler.go +++ /dev/null @@ -1,47 +0,0 @@ -package nft - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/irisnet/irismod/modules/nft/keeper" - "github.com/irisnet/irismod/modules/nft/types" -) - -// NewHandler routes the messages to the handlers -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgIssueDenom: - res, err := msgServer.IssueDenom(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgMintNFT: - res, err := msgServer.MintNFT(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgTransferNFT: - res, err := msgServer.TransferNFT(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgEditNFT: - res, err := msgServer.EditNFT(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgBurnNFT: - res, err := msgServer.BurnNFT(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgTransferDenom: - res, err := msgServer.TransferDenom(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized nft message type: %T", msg) - } - } -} diff --git a/modules/nft/keeper/collection.go b/modules/nft/keeper/collection.go index 486e2e17..9736cc84 100644 --- a/modules/nft/keeper/collection.go +++ b/modules/nft/keeper/collection.go @@ -1,22 +1,15 @@ package keeper import ( - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/irisnet/irismod/modules/nft/exported" "github.com/irisnet/irismod/modules/nft/types" ) -// SetCollection saves all NFTs and returns an error if there already exists -func (k Keeper) SetCollection(ctx sdk.Context, collection types.Collection) error { +// SaveCollection saves all NFTs and returns an error if there already exists +func (k Keeper) SaveCollection(ctx sdk.Context, collection types.Collection) error { for _, nft := range collection.NFTs { - if err := k.MintNFT( + if err := k.SaveNFT( ctx, collection.Denom.Id, nft.GetID(), @@ -32,87 +25,30 @@ func (k Keeper) SetCollection(ctx sdk.Context, collection types.Collection) erro return nil } -// GetCollection returns the collection by the specified denom ID -func (k Keeper) GetCollection(ctx sdk.Context, denomID string) (types.Collection, error) { - denom, found := k.GetDenom(ctx, denomID) - if !found { - return types.Collection{}, sdkerrors.Wrapf(types.ErrInvalidDenom, "denomID %s not existed ", denomID) - } - - nfts := k.GetNFTs(ctx, denomID) - return types.NewCollection(denom, nfts), nil -} - -// GetPaginateCollection returns the collection by the specified denom ID -func (k Keeper) GetPaginateCollection(ctx sdk.Context, request *types.QueryCollectionRequest, denomID string) (types.Collection, *query.PageResponse, error) { - denom, found := k.GetDenom(ctx, denomID) - if !found { - return types.Collection{}, nil, sdkerrors.Wrapf(types.ErrInvalidDenom, "denomID %s not existed ", denomID) - } - var nfts []exported.NFT - store := ctx.KVStore(k.storeKey) - nftStore := prefix.NewStore(store, types.KeyNFT(denomID, "")) - pageRes, err := query.Paginate(nftStore, shapePageRequest(request.Pagination), func(key []byte, value []byte) error { - var baseNFT types.BaseNFT - k.cdc.MustUnmarshal(value, &baseNFT) - nfts = append(nfts, baseNFT) - return nil - }) - if err != nil { - return types.Collection{}, nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err) - } - return types.NewCollection(denom, nfts), pageRes, nil -} - // GetCollections returns all the collections -func (k Keeper) GetCollections(ctx sdk.Context) (cs []types.Collection) { - for _, denom := range k.GetDenoms(ctx) { - nfts := k.GetNFTs(ctx, denom.Id) - cs = append(cs, types.NewCollection(denom, nfts)) - } - return cs -} +func (k Keeper) GetCollections(ctx sdk.Context) (cs []types.Collection, err error) { + for _, class := range k.nk.GetClasses(ctx) { + nfts, err := k.GetNFTs(ctx, class.Id) + if err != nil { + return nil, err + } -// GetDenomSupply returns the number of NFTs by the specified denom ID -func (k Keeper) GetTotalSupply(ctx sdk.Context, denomID string) uint64 { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.KeyCollection(denomID)) - if len(bz) == 0 { - return 0 - } - return types.MustUnMarshalSupply(k.cdc, bz) -} + denom, err := k.GetDenomInfo(ctx, class.Id) + if err != nil { + return nil, err + } -// GetTotalSupplyOfOwner returns the amount of NFTs by the specified conditions -func (k Keeper) GetTotalSupplyOfOwner(ctx sdk.Context, id string, owner sdk.AccAddress) (supply uint64) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.KeyOwner(owner, id, "")) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - supply++ + cs = append(cs, types.NewCollection(*denom, nfts)) } - return supply + return cs, nil } -func (k Keeper) increaseSupply(ctx sdk.Context, denomID string) { - supply := k.GetTotalSupply(ctx, denomID) - supply++ - - store := ctx.KVStore(k.storeKey) - bz := types.MustMarshalSupply(k.cdc, supply) - store.Set(types.KeyCollection(denomID), bz) +// GetTotalSupply returns the number of NFTs by the specified denom ID +func (k Keeper) GetTotalSupply(ctx sdk.Context, denomID string) uint64 { + return k.nk.GetTotalSupply(ctx, denomID) } -func (k Keeper) decreaseSupply(ctx sdk.Context, denomID string) { - supply := k.GetTotalSupply(ctx, denomID) - supply-- - - store := ctx.KVStore(k.storeKey) - if supply == 0 { - store.Delete(types.KeyCollection(denomID)) - return - } - - bz := types.MustMarshalSupply(k.cdc, supply) - store.Set(types.KeyCollection(denomID), bz) +// GetBalance returns the amount of NFTs by the specified conditions +func (k Keeper) GetBalance(ctx sdk.Context, id string, owner sdk.AccAddress) (supply uint64) { + return k.nk.GetBalance(ctx, id, owner) } diff --git a/modules/nft/keeper/collection_test.go b/modules/nft/keeper/collection_test.go index de2ca5e0..3a3a1662 100644 --- a/modules/nft/keeper/collection_test.go +++ b/modules/nft/keeper/collection_test.go @@ -25,35 +25,17 @@ func (suite *KeeperSuite) TestSetCollection() { NFTs: []types.BaseNFT{nft2, nft}, } - err := suite.keeper.SetCollection(suite.ctx, collection2) + err := suite.keeper.SaveCollection(suite.ctx, collection2) suite.Nil(err) - collection2, err = suite.keeper.GetCollection(suite.ctx, denomID) - suite.NoError(err) - suite.Len(collection2.NFTs, 2) - - msg, fail := keeper.SupplyInvariant(suite.keeper)(suite.ctx) - suite.False(fail, msg) -} - -func (suite *KeeperSuite) TestGetCollection() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - // collection should exist - collection, err := suite.keeper.GetCollection(suite.ctx, denomID) - suite.NoError(err) - suite.NotEmpty(collection) - msg, fail := keeper.SupplyInvariant(suite.keeper)(suite.ctx) suite.False(fail, msg) } func (suite *KeeperSuite) TestGetCollections() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) msg, fail := keeper.SupplyInvariant(suite.keeper)(suite.ctx) @@ -61,16 +43,16 @@ func (suite *KeeperSuite) TestGetCollections() { } func (suite *KeeperSuite) TestGetSupply() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - // MintNFT shouldn't fail when collection does not exist - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address2) + // SaveNFT shouldn't fail when collection does not exist + err = suite.keeper.SaveNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address2) suite.NoError(err) - // MintNFT shouldn't fail when collection does not exist - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID, tokenNm2, tokenURI, tokenURIHash, tokenData, address2) + // SaveNFT shouldn't fail when collection does not exist + err = suite.keeper.SaveNFT(suite.ctx, denomID2, tokenID, tokenNm2, tokenURI, tokenURIHash, tokenData, address2) suite.NoError(err) supply := suite.keeper.GetTotalSupply(suite.ctx, denomID) @@ -79,10 +61,10 @@ func (suite *KeeperSuite) TestGetSupply() { supply = suite.keeper.GetTotalSupply(suite.ctx, denomID2) suite.Equal(uint64(1), supply) - supply = suite.keeper.GetTotalSupplyOfOwner(suite.ctx, denomID, address) + supply = suite.keeper.GetBalance(suite.ctx, denomID, address) suite.Equal(uint64(1), supply) - supply = suite.keeper.GetTotalSupplyOfOwner(suite.ctx, denomID, address2) + supply = suite.keeper.GetBalance(suite.ctx, denomID, address2) suite.Equal(uint64(1), supply) supply = suite.keeper.GetTotalSupply(suite.ctx, denomID) @@ -92,7 +74,7 @@ func (suite *KeeperSuite) TestGetSupply() { suite.Equal(uint64(1), supply) //burn nft - err = suite.keeper.BurnNFT(suite.ctx, denomID, tokenID, address) + err = suite.keeper.RemoveNFT(suite.ctx, denomID, tokenID, address) suite.NoError(err) supply = suite.keeper.GetTotalSupply(suite.ctx, denomID) @@ -102,7 +84,7 @@ func (suite *KeeperSuite) TestGetSupply() { suite.Equal(uint64(1), supply) //burn nft - err = suite.keeper.BurnNFT(suite.ctx, denomID, tokenID2, address2) + err = suite.keeper.RemoveNFT(suite.ctx, denomID, tokenID2, address2) suite.NoError(err) supply = suite.keeper.GetTotalSupply(suite.ctx, denomID) diff --git a/modules/nft/keeper/denom.go b/modules/nft/keeper/denom.go index 2a95dba5..f5f4f58e 100644 --- a/modules/nft/keeper/denom.go +++ b/modules/nft/keeper/denom.go @@ -1,66 +1,105 @@ package keeper import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/nft" "github.com/irisnet/irismod/modules/nft/types" ) -// HasDenom returns whether the specified denom ID exists -func (k Keeper) HasDenomID(ctx sdk.Context, id string) bool { - store := ctx.KVStore(k.storeKey) - return store.Has(types.KeyDenomID(id)) -} - -// SetDenom is responsible for saving the definition of denom -func (k Keeper) SetDenom(ctx sdk.Context, denom types.Denom) error { - if k.HasDenomID(ctx, denom.Id) { - return sdkerrors.Wrapf(types.ErrInvalidDenom, "denomID %s has already exists", denom.Id) +// SaveDenom issues a denom according to the given params +func (k Keeper) SaveDenom(ctx sdk.Context, id, + name, + schema, + symbol string, + creator sdk.AccAddress, + mintRestricted, + updateRestricted bool, + description, + uri, + uriHash, + data string, +) error { + denomMetadata := &types.DenomMetadata{ + Creator: creator.String(), + Schema: schema, + MintRestricted: mintRestricted, + UpdateRestricted: updateRestricted, + Data: data, } - - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshal(&denom) - store.Set(types.KeyDenomID(denom.Id), bz) - store.Set(types.KeyDenomName(denom.Name), []byte(denom.Id)) - return nil + metadata, err := codectypes.NewAnyWithValue(denomMetadata) + if err != nil { + return err + } + return k.nk.SaveClass(ctx, nft.Class{ + Id: id, + Name: name, + Symbol: symbol, + Description: description, + Uri: uri, + UriHash: uriHash, + Data: metadata, + }) } -// GetDenom returns the denom by id -func (k Keeper) GetDenom(ctx sdk.Context, id string) (denom types.Denom, found bool) { - store := ctx.KVStore(k.storeKey) - - bz := store.Get(types.KeyDenomID(id)) - if len(bz) == 0 { - return denom, false +// TransferDenomOwner transfers the ownership of the given denom to the new owner +func (k Keeper) TransferDenomOwner( + ctx sdk.Context, + denomID string, + srcOwner, + dstOwner sdk.AccAddress, +) error { + denom, err := k.GetDenomInfo(ctx, denomID) + if err != nil { + return err } - k.cdc.MustUnmarshal(bz, &denom) - return denom, true -} - -// GetDenoms returns all the denoms -func (k Keeper) GetDenoms(ctx sdk.Context) (denoms []types.Denom) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.KeyDenomID("")) - defer iterator.Close() + // authorize + if srcOwner.String() != denom.Creator { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to transfer denom %s", srcOwner.String(), denomID) + } - for ; iterator.Valid(); iterator.Next() { - var denom types.Denom - k.cdc.MustUnmarshal(iterator.Value(), &denom) - denoms = append(denoms, denom) + denomMetadata := &types.DenomMetadata{ + Creator: dstOwner.String(), + Schema: denom.Schema, + MintRestricted: denom.MintRestricted, + UpdateRestricted: denom.UpdateRestricted, } - return denoms + data, err := codectypes.NewAnyWithValue(denomMetadata) + if err != nil { + return err + } + return k.nk.UpdateClass(ctx, nft.Class{ + Id: denom.Id, + Name: denom.Name, + Symbol: denom.Symbol, + Data: data, + }) } -// UpdateDenom is responsible for updating the definition of denom -func (k Keeper) UpdateDenom(ctx sdk.Context, denom types.Denom) error { - if !k.HasDenomID(ctx, denom.Id) { - return sdkerrors.Wrapf(types.ErrInvalidDenom, "denomID %s not exists", denom.Id) +func (k Keeper) GetDenomInfo(ctx sdk.Context, denomID string) (*types.Denom, error) { + class, has := k.nk.GetClass(ctx, denomID) + if !has { + return nil, sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", denomID) } - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshal(&denom) - store.Set(types.KeyDenomID(denom.Id), bz) - return nil + var denomMetadata types.DenomMetadata + if err := k.cdc.Unmarshal(class.Data.GetValue(), &denomMetadata); err != nil { + return nil, err + } + return &types.Denom{ + Id: class.Id, + Name: class.Name, + Schema: denomMetadata.Schema, + Creator: denomMetadata.Creator, + Symbol: class.Symbol, + MintRestricted: denomMetadata.MintRestricted, + UpdateRestricted: denomMetadata.UpdateRestricted, + Description: class.Description, + Uri: class.Uri, + UriHash: class.UriHash, + Data: denomMetadata.Data, + }, nil } diff --git a/modules/nft/keeper/genesis.go b/modules/nft/keeper/genesis.go new file mode 100644 index 00000000..8ca2f88a --- /dev/null +++ b/modules/nft/keeper/genesis.go @@ -0,0 +1,49 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/irisnet/irismod/modules/nft/types" +) + +// InitGenesis stores the NFT genesis. +func (k Keeper) InitGenesis(ctx sdk.Context, data types.GenesisState) { + if err := types.ValidateGenesis(data); err != nil { + panic(err.Error()) + } + + for _, c := range data.Collections { + creator, err := sdk.AccAddressFromBech32(c.Denom.Creator) + if err != nil { + panic(err) + } + if err := k.SaveDenom(ctx, + c.Denom.Id, + c.Denom.Name, + c.Denom.Schema, + c.Denom.Symbol, + creator, + c.Denom.MintRestricted, + c.Denom.UpdateRestricted, + c.Denom.Description, + c.Denom.Uri, + c.Denom.UriHash, + c.Denom.Data, + ); err != nil { + panic(err) + } + + if err := k.SaveCollection(ctx, c); err != nil { + panic(err) + } + } +} + +// ExportGenesis returns a GenesisState for a given context and keeper. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + collections, err := k.GetCollections(ctx) + if err != nil { + panic(err) + } + return types.NewGenesisState(collections) +} diff --git a/modules/nft/keeper/grpc_query.go b/modules/nft/keeper/grpc_query.go index cfc72995..54a061f5 100644 --- a/modules/nft/keeper/grpc_query.go +++ b/modules/nft/keeper/grpc_query.go @@ -6,10 +6,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/cosmos-sdk/store/prefix" 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/nft" "github.com/irisnet/irismod/modules/nft/types" ) @@ -28,92 +27,125 @@ func (k Keeper) Supply(c context.Context, request *types.QuerySupplyRequest) (*t if err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid owner address %s", request.Owner) } - supply = k.GetTotalSupplyOfOwner(ctx, request.DenomId, owner) + supply = k.GetBalance(ctx, request.DenomId, owner) } return &types.QuerySupplyResponse{Amount: supply}, nil } -func (k Keeper) Owner(c context.Context, request *types.QueryOwnerRequest) (*types.QueryOwnerResponse, error) { - ctx := sdk.UnwrapSDKContext(c) +func (k Keeper) NFTsOfOwner(c context.Context, request *types.QueryNFTsOfOwnerRequest) (*types.QueryNFTsOfOwnerResponse, error) { + r := &nft.QueryNFTsRequest{ + ClassId: request.DenomId, + Owner: request.Owner, + Pagination: shapePageRequest(request.Pagination), + } - ownerAddress, err := sdk.AccAddressFromBech32(request.Owner) + result, err := k.nk.NFTs(c, r) if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "invalid owner address %s", request.Owner) + return nil, err } - owner := types.Owner{ - Address: ownerAddress.String(), - IDCollections: types.IDCollections{}, + var denomMap = make(map[string][]string) + var denoms = make([]string, 0, len(result.Nfts)) + for _, token := range result.Nfts { + denomMap[token.ClassId] = append(denomMap[token.ClassId], token.Id) + denoms = append(denoms, token.ClassId) } - idsMap := make(map[string][]string) - store := ctx.KVStore(k.storeKey) - nftStore := prefix.NewStore(store, types.KeyOwner(ownerAddress, request.DenomId, "")) - pageRes, err := query.Paginate(nftStore, shapePageRequest(request.Pagination), func(key []byte, value []byte) error { - denomID := request.DenomId - tokenID := string(key) - if len(request.DenomId) == 0 { - denomID, tokenID, _ = types.SplitKeyDenom(key) - } - if ids, ok := idsMap[denomID]; ok { - idsMap[denomID] = append(ids, tokenID) - } else { - idsMap[denomID] = []string{tokenID} - owner.IDCollections = append( - owner.IDCollections, - types.IDCollection{DenomId: denomID}, - ) - } - return nil - }) - if err != nil { - return nil, err + + var idc []types.IDCollection + for _, denomId := range denoms { + idc = append(idc, types.IDCollection{DenomId: denomId, TokenIds: denomMap[denomId]}) } - for i := 0; i < len(owner.IDCollections); i++ { - owner.IDCollections[i].TokenIds = idsMap[owner.IDCollections[i].DenomId] + + response := &types.QueryNFTsOfOwnerResponse{ + Owner: &types.Owner{ + Address: request.Owner, + IDCollections: idc, + }, + Pagination: result.Pagination, } - return &types.QueryOwnerResponse{Owner: &owner, Pagination: pageRes}, nil + + return response, nil } func (k Keeper) Collection(c context.Context, request *types.QueryCollectionRequest) (*types.QueryCollectionResponse, error) { ctx := sdk.UnwrapSDKContext(c) + denom, err := k.GetDenomInfo(ctx, request.DenomId) + if err != nil { + return nil, err + } - collection, pageRes, err := k.GetPaginateCollection(ctx, request, request.DenomId) + r := &nft.QueryNFTsRequest{ + ClassId: request.DenomId, + Pagination: shapePageRequest(request.Pagination), + } + + result, err := k.nk.NFTs(c, r) if err != nil { return nil, err } - return &types.QueryCollectionResponse{Collection: &collection, Pagination: pageRes}, nil + + var nfts []types.BaseNFT + for _, token := range result.Nfts { + owner := k.nk.GetOwner(ctx, request.DenomId, token.Id) + + var nftMetadata types.NFTMetadata + if err := k.cdc.Unmarshal(token.Data.GetValue(), &nftMetadata); err != nil { + return nil, err + } + + nfts = append(nfts, types.BaseNFT{ + Id: token.Id, + URI: token.Uri, + Name: nftMetadata.Name, + Owner: owner.String(), + Data: nftMetadata.Data, + }) + } + + collection := &types.Collection{ + Denom: *denom, + NFTs: nfts, + } + + response := &types.QueryCollectionResponse{ + Collection: collection, + Pagination: result.Pagination, + } + + return response, nil } func (k Keeper) Denom(c context.Context, request *types.QueryDenomRequest) (*types.QueryDenomResponse, error) { ctx := sdk.UnwrapSDKContext(c) - - denomObject, found := k.GetDenom(ctx, request.DenomId) - if !found { - return nil, sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", request.DenomId) + denom, err := k.GetDenomInfo(ctx, request.DenomId) + if err != nil { + return nil, err } - - return &types.QueryDenomResponse{Denom: &denomObject}, nil + return &types.QueryDenomResponse{Denom: denom}, nil } func (k Keeper) Denoms(c context.Context, req *types.QueryDenomsRequest) (*types.QueryDenomsResponse, error) { ctx := sdk.UnwrapSDKContext(c) - var denoms []types.Denom - store := ctx.KVStore(k.storeKey) - denomStore := prefix.NewStore(store, types.KeyDenomID("")) - pageRes, err := query.Paginate(denomStore, shapePageRequest(req.Pagination), func(key []byte, value []byte) error { - var denom types.Denom - k.cdc.MustUnmarshal(value, &denom) - denoms = append(denoms, denom) - return nil + result, err := k.nk.Classes(c, &nft.QueryClassesRequest{ + Pagination: shapePageRequest(req.Pagination), }) if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err) + return nil, err + } + + var denoms []types.Denom + for _, denom := range result.Classes { + denom, err := k.GetDenomInfo(ctx, denom.Id) + if err != nil { + return nil, err + } + denoms = append(denoms, *denom) } return &types.QueryDenomsResponse{ Denoms: denoms, - Pagination: pageRes, + Pagination: result.Pagination, }, nil } diff --git a/modules/nft/keeper/grpc_query_test.go b/modules/nft/keeper/grpc_query_test.go index f9bb549f..682b97ec 100644 --- a/modules/nft/keeper/grpc_query_test.go +++ b/modules/nft/keeper/grpc_query_test.go @@ -7,7 +7,7 @@ import ( ) func (suite *KeeperSuite) TestSupply() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) response, err := suite.queryClient.Supply(gocontext.Background(), &types.QuerySupplyRequest{ @@ -20,10 +20,10 @@ func (suite *KeeperSuite) TestSupply() { } func (suite *KeeperSuite) TestOwner() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - response, err := suite.queryClient.Owner(gocontext.Background(), &types.QueryOwnerRequest{ + response, err := suite.queryClient.NFTsOfOwner(gocontext.Background(), &types.QueryNFTsOfOwnerRequest{ DenomId: denomID, Owner: address.String(), }) @@ -34,7 +34,7 @@ func (suite *KeeperSuite) TestOwner() { } func (suite *KeeperSuite) TestCollection() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) response, err := suite.queryClient.Collection(gocontext.Background(), &types.QueryCollectionRequest{ @@ -48,7 +48,7 @@ func (suite *KeeperSuite) TestCollection() { } func (suite *KeeperSuite) TestDenom() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) response, err := suite.queryClient.Denom(gocontext.Background(), &types.QueryDenomRequest{ @@ -61,7 +61,7 @@ func (suite *KeeperSuite) TestDenom() { } func (suite *KeeperSuite) TestDenoms() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) response, err := suite.queryClient.Denoms(gocontext.Background(), &types.QueryDenomsRequest{}) @@ -72,7 +72,7 @@ func (suite *KeeperSuite) TestDenoms() { } func (suite *KeeperSuite) TestNFT() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) response, err := suite.queryClient.NFT(gocontext.Background(), &types.QueryNFTRequest{ diff --git a/modules/nft/keeper/invariants.go b/modules/nft/keeper/invariants.go index a00bda24..d63243b6 100644 --- a/modules/nft/keeper/invariants.go +++ b/modules/nft/keeper/invariants.go @@ -6,7 +6,6 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/irisnet/irismod/modules/nft/types" ) @@ -15,13 +14,6 @@ func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { ir.RegisterRoute(types.ModuleName, "supply", SupplyInvariant(k)) } -// AllInvariants runs all invariants of the NFT module. -func AllInvariants(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - return SupplyInvariant(k)(ctx) - } -} - // SupplyInvariant checks that the total amount of NFTs on collections matches the total amount owned by addresses func SupplyInvariant(k Keeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { @@ -29,10 +21,13 @@ func SupplyInvariant(k Keeper) sdk.Invariant { var msg string count := 0 - for _, owner := range k.GetOwners(ctx) { - for _, idCollection := range owner.IDCollections { - ownersCollectionsSupply[idCollection.DenomId] += uint64(idCollection.Supply()) - } + collections, err := k.GetCollections(ctx) + if err != nil { + panic(err) + } + + for _, collection := range collections { + ownersCollectionsSupply[collection.Denom.Id] = uint64(len(collection.NFTs)) } for denom, supply := range ownersCollectionsSupply { diff --git a/modules/nft/keeper/keeper.go b/modules/nft/keeper/keeper.go index 3bc5cb2f..6800a65a 100644 --- a/modules/nft/keeper/keeper.go +++ b/modules/nft/keeper/keeper.go @@ -8,7 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/nft" + nftkeeper "github.com/cosmos/cosmos-sdk/x/nft/keeper" "github.com/irisnet/irismod/modules/nft/types" ) @@ -17,191 +18,28 @@ import ( type Keeper struct { storeKey storetypes.StoreKey // Unexposed key to access store from sdk.Context cdc codec.Codec + nk nftkeeper.Keeper } // NewKeeper creates a new instance of the NFT Keeper -func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey) Keeper { +func NewKeeper(cdc codec.Codec, + storeKey storetypes.StoreKey, + ak nft.AccountKeeper, + bk nft.BankKeeper, +) Keeper { return Keeper{ storeKey: storeKey, cdc: cdc, + nk: nftkeeper.NewKeeper(storeKey, cdc, ak, bk), } } +// NFTkeeper returns a cosmos-sdk nftkeeper.Keeper. +func (k Keeper) NFTkeeper() nftkeeper.Keeper { + return k.nk +} + // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("irismod/%s", types.ModuleName)) } - -// IssueDenom issues a denom according to the given params -func (k Keeper) IssueDenom(ctx sdk.Context, - id, name, schema, symbol string, - creator sdk.AccAddress, - mintRestricted, updateRestricted bool, - description, uri, uriHash, data string, -) error { - return k.SetDenom(ctx, types.Denom{ - Id: id, - Name: name, - Schema: schema, - Creator: creator.String(), - Symbol: symbol, - MintRestricted: mintRestricted, - UpdateRestricted: updateRestricted, - Description: description, - Uri: uri, - UriHash: uriHash, - Data: data, - }) -} - -// MintNFT mints an NFT and manages the NFT's existence within Collections and Owners -func (k Keeper) MintNFT( - ctx sdk.Context, denomID, tokenID, tokenNm, - tokenURI, uriHash, tokenData string, owner sdk.AccAddress, -) error { - if k.HasNFT(ctx, denomID, tokenID) { - return sdkerrors.Wrapf(types.ErrNFTAlreadyExists, "NFT %s already exists in collection %s", tokenID, denomID) - } - - k.setNFT( - ctx, denomID, - types.NewBaseNFT( - tokenID, - tokenNm, - owner, - tokenURI, - uriHash, - tokenData, - ), - ) - k.setOwner(ctx, denomID, tokenID, owner) - k.increaseSupply(ctx, denomID) - - return nil -} - -// EditNFT updates an already existing NFT -func (k Keeper) EditNFT( - ctx sdk.Context, denomID, tokenID, tokenNm, - tokenURI, tokenURIHash, tokenData string, owner sdk.AccAddress, -) error { - denom, found := k.GetDenom(ctx, denomID) - if !found { - return sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", denomID) - } - - if denom.UpdateRestricted { - // if true , nobody can update the NFT under this denom - return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "nobody can update the NFT under this denom %s", denom.Id) - } - - // just the owner of NFT can edit - nft, err := k.Authorize(ctx, denomID, tokenID, owner) - if err != nil { - return err - } - - if types.Modified(tokenNm) { - nft.Name = tokenNm - } - - if types.Modified(tokenURI) { - nft.URI = tokenURI - } - - if types.Modified(tokenURIHash) { - nft.UriHash = tokenURIHash - } - - if types.Modified(tokenData) { - nft.Data = tokenData - } - - k.setNFT(ctx, denomID, nft) - - return nil -} - -// TransferOwner transfers the ownership of the given NFT to the new owner -func (k Keeper) TransferOwner( - ctx sdk.Context, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, - tokenData string, srcOwner, dstOwner sdk.AccAddress, -) error { - denom, found := k.GetDenom(ctx, denomID) - if !found { - return sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", denomID) - } - - if denom.UpdateRestricted && (types.Modified(tokenNm) || - types.Modified(tokenURI) || - types.Modified(tokenData) || - types.Modified(tokenURIHash)) { - return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "It is restricted to update NFT under this denom %s", denom.Id) - } - - nft, err := k.Authorize(ctx, denomID, tokenID, srcOwner) - if err != nil { - return err - } - - nft.Owner = dstOwner.String() - - if types.Modified(tokenNm) { - nft.Name = tokenNm - } - if types.Modified(tokenURI) { - nft.URI = tokenURI - } - if types.Modified(tokenURIHash) { - nft.UriHash = tokenURIHash - } - if types.Modified(tokenData) { - nft.Data = tokenData - } - - k.setNFT(ctx, denomID, nft) - k.swapOwner(ctx, denomID, tokenID, srcOwner, dstOwner) - return nil -} - -// BurnNFT deletes a specified NFT -func (k Keeper) BurnNFT(ctx sdk.Context, denomID, tokenID string, owner sdk.AccAddress) error { - if !k.HasDenomID(ctx, denomID) { - return sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", denomID) - } - - nft, err := k.Authorize(ctx, denomID, tokenID, owner) - if err != nil { - return err - } - - k.deleteNFT(ctx, denomID, nft) - k.deleteOwner(ctx, denomID, tokenID, owner) - k.decreaseSupply(ctx, denomID) - - return nil -} - -// TransferDenomOwner transfers the ownership of the given denom to the new owner -func (k Keeper) TransferDenomOwner( - ctx sdk.Context, denomID string, srcOwner, dstOwner sdk.AccAddress, -) error { - denom, found := k.GetDenom(ctx, denomID) - if !found { - return sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", denomID) - } - - // authorize - if srcOwner.String() != denom.Creator { - return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to transfer denom %s", srcOwner.String(), denomID) - } - - denom.Creator = dstOwner.String() - - err := k.UpdateDenom(ctx, denom) - if err != nil { - return err - } - - return nil -} diff --git a/modules/nft/keeper/keeper_test.go b/modules/nft/keeper/keeper_test.go index 2a59612d..2a8cae1e 100644 --- a/modules/nft/keeper/keeper_test.go +++ b/modules/nft/keeper/keeper_test.go @@ -79,18 +79,19 @@ func (suite *KeeperSuite) SetupTest() { types.RegisterQueryServer(queryHelper, app.NFTKeeper) suite.queryClient = types.NewQueryClient(queryHelper) - err := suite.keeper.IssueDenom(suite.ctx, denomID, denomNm, schema, denomSymbol, address, false, false, denomDescription, denomUri, denomUriHash, denomData) + err := suite.keeper.SaveDenom(suite.ctx, denomID, denomNm, schema, denomSymbol, address, false, false, denomDescription, denomUri, denomUriHash, denomData) suite.NoError(err) - // MintNFT shouldn't fail when collection does not exist - err = suite.keeper.IssueDenom(suite.ctx, denomID2, denomNm2, schema, denomSymbol2, address, false, false, denomDescription, denomUri, denomUriHash, denomData) + // SaveNFT shouldn't fail when collection does not exist + err = suite.keeper.SaveDenom(suite.ctx, denomID2, denomNm2, schema, denomSymbol2, address, false, false, denomDescription, denomUri, denomUriHash, denomData) suite.NoError(err) - err = suite.keeper.IssueDenom(suite.ctx, denomID3, denomNm3, schema, denomSymbol3, address3, true, true, denomDescription, denomUri, denomUriHash, denomData) + err = suite.keeper.SaveDenom(suite.ctx, denomID3, denomNm3, schema, denomSymbol3, address3, true, true, denomDescription, denomUri, denomUriHash, denomData) suite.NoError(err) // collections should equal 3 - collections := suite.keeper.GetCollections(suite.ctx) + collections, err := suite.keeper.GetCollections(suite.ctx) + suite.NoError(err) suite.NotEmpty(collections) suite.Equal(len(collections), 3) } @@ -100,35 +101,35 @@ func TestKeeperSuite(t *testing.T) { } func (suite *KeeperSuite) TestMintNFT() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - // MintNFT shouldn't fail when collection exists - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection exists + err = suite.keeper.SaveNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) } func (suite *KeeperSuite) TestUpdateNFT() { - // EditNFT should fail when NFT doesn't exists - err := suite.keeper.EditNFT(suite.ctx, denomID, tokenID, tokenNm3, tokenURI, tokenURIHash, tokenData, address) + // UpdateNFT should fail when NFT doesn't exists + err := suite.keeper.UpdateNFT(suite.ctx, denomID, tokenID, tokenNm3, tokenURI, tokenURIHash, tokenData, address) suite.Error(err) - // MintNFT shouldn't fail when collection does not exist - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err = suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - // EditNFT should fail when NFT doesn't exists - err = suite.keeper.EditNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) + // UpdateNFT should fail when NFT doesn't exists + err = suite.keeper.UpdateNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) suite.Error(err) - // EditNFT shouldn't fail when NFT exists - err = suite.keeper.EditNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI2, tokenURIHash2, tokenData, address) + // UpdateNFT shouldn't fail when NFT exists + err = suite.keeper.UpdateNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI2, tokenURIHash2, tokenData, address) suite.NoError(err) - // EditNFT should fail when NFT failed to authorize - err = suite.keeper.EditNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI2, tokenURIHash2, tokenData, address2) + // UpdateNFT should fail when NFT failed to authorize + err = suite.keeper.UpdateNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI2, tokenURIHash2, tokenData, address2) suite.Error(err) // GetNFT should get the NFT with new tokenURI @@ -136,30 +137,30 @@ func (suite *KeeperSuite) TestUpdateNFT() { suite.NoError(err) suite.Equal(receivedNFT.GetURI(), tokenURI2) - // EditNFT shouldn't fail when NFT exists - err = suite.keeper.EditNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI2, tokenURIHash2, tokenData, address2) + // UpdateNFT shouldn't fail when NFT exists + err = suite.keeper.UpdateNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI2, tokenURIHash2, tokenData, address2) suite.Error(err) - err = suite.keeper.MintNFT(suite.ctx, denomID3, denomID3, tokenID3, tokenURI, tokenURIHash, tokenData, address3) + err = suite.keeper.SaveNFT(suite.ctx, denomID3, denomID3, tokenID3, tokenURI, tokenURIHash, tokenData, address3) suite.NoError(err) - // EditNFT should fail if updateRestricted equal to true, nobody can update the NFT under this denom - err = suite.keeper.EditNFT(suite.ctx, denomID3, denomID3, tokenID3, tokenURI, tokenURIHash, tokenData, address3) + // UpdateNFT should fail if updateRestricted equal to true, nobody can update the NFT under this denom + err = suite.keeper.UpdateNFT(suite.ctx, denomID3, denomID3, tokenID3, tokenURI, tokenURIHash, tokenData, address3) suite.Error(err) } -func (suite *KeeperSuite) TestTransferOwner() { +func (suite *KeeperSuite) TestTransferOwnership() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) // invalid owner - err = suite.keeper.TransferOwner(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address2, address3) + err = suite.keeper.TransferOwnership(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address2, address3) suite.Error(err) // right - err = suite.keeper.TransferOwner(suite.ctx, denomID, tokenID, tokenNm2, tokenURI2, tokenURIHash2, tokenData, address, address2) + err = suite.keeper.TransferOwnership(suite.ctx, denomID, tokenID, tokenNm2, tokenURI2, tokenURIHash2, tokenData, address, address2) suite.NoError(err) nft, err := suite.keeper.GetNFT(suite.ctx, denomID, tokenID) @@ -177,19 +178,19 @@ func (suite *KeeperSuite) TestTransferDenom() { err = suite.keeper.TransferDenomOwner(suite.ctx, denomID, address, address3) suite.NoError(err) - denom, _ := suite.keeper.GetDenom(suite.ctx, denomID) + denom, _ := suite.keeper.GetDenomInfo(suite.ctx, denomID) // denom.Creator should equal to address3 after transfer suite.Equal(denom.Creator, address3.String()) } func (suite *KeeperSuite) TestBurnNFT() { - // MintNFT should not fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT should not fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - // BurnNFT should fail when NFT doesn't exist but collection does exist - err = suite.keeper.BurnNFT(suite.ctx, denomID, tokenID, address) + // RemoveNFT should fail when NFT doesn't exist but collection does exist + err = suite.keeper.RemoveNFT(suite.ctx, denomID, tokenID, address) suite.NoError(err) // NFT should no longer exist diff --git a/modules/nft/keeper/legacy_keeper.go b/modules/nft/keeper/legacy_keeper.go index 4399bab9..f130aa2b 100644 --- a/modules/nft/keeper/legacy_keeper.go +++ b/modules/nft/keeper/legacy_keeper.go @@ -15,27 +15,78 @@ func NewLegacyKeeper(nk Keeper) LegacyKeeper { return LegacyKeeper{nk} } -func (n LegacyKeeper) IssueDenom(ctx sdk.Context, - id, name, schema, symbol string, +func (n LegacyKeeper) IssueDenom( + ctx sdk.Context, + id, + name, + schema, + symbol string, creator sdk.AccAddress, - mintRestricted, updateRestricted bool) error { - return n.nk.IssueDenom(ctx, id, name, schema, symbol, creator, mintRestricted, updateRestricted, types.DoNotModify, types.DoNotModify, types.DoNotModify, types.DoNotModify) + mintRestricted, + updateRestricted bool, +) error { + return n.nk.SaveDenom( + ctx, + id, + name, + schema, + symbol, + creator, + mintRestricted, + updateRestricted, + types.DoNotModify, + types.DoNotModify, + types.DoNotModify, + types.DoNotModify, + ) } -func (n LegacyKeeper) MintNFT(ctx sdk.Context, - denomID, tokenID, tokenNm, tokenURI, tokenData string, - owner sdk.AccAddress) error { - return n.nk.MintNFT(ctx, denomID, tokenID, tokenNm, tokenURI, "", tokenData, owner) +func (n LegacyKeeper) MintNFT( + ctx sdk.Context, + denomID, + tokenID, + tokenNm, + tokenURI, + tokenData string, + owner sdk.AccAddress, +) error { + return n.nk.SaveNFT( + ctx, + denomID, + tokenID, + tokenNm, + tokenURI, + "", + tokenData, + owner, + ) } -func (n LegacyKeeper) TransferOwner(ctx sdk.Context, - denomID, tokenID, tokenNm, tokenURI, tokenData string, - srcOwner, dstOwner sdk.AccAddress) error { - return n.nk.TransferOwner(ctx, denomID, tokenID, tokenNm, tokenURI, types.DoNotModify, tokenData, srcOwner, dstOwner) +func (n LegacyKeeper) TransferOwner( + ctx sdk.Context, + denomID, + tokenID, + tokenNm, + tokenURI, + tokenData string, + srcOwner, + dstOwner sdk.AccAddress, +) error { + return n.nk.TransferOwnership( + ctx, + denomID, + tokenID, + tokenNm, + tokenURI, + types.DoNotModify, + tokenData, + srcOwner, + dstOwner, + ) } func (n LegacyKeeper) BurnNFT(ctx sdk.Context, denomID, tokenID string, owner sdk.AccAddress) error { - return n.nk.BurnNFT(ctx, denomID, tokenID, owner) + return n.nk.RemoveNFT(ctx, denomID, tokenID, owner) } func (n LegacyKeeper) GetNFT(ctx sdk.Context, denomID, tokenID string) (nft exported.NFT, err error) { @@ -43,5 +94,9 @@ func (n LegacyKeeper) GetNFT(ctx sdk.Context, denomID, tokenID string) (nft expo } func (n LegacyKeeper) GetDenom(ctx sdk.Context, id string) (denom types.Denom, found bool) { - return n.nk.GetDenom(ctx, id) + d, err := n.nk.GetDenomInfo(ctx, id) + if err != nil { + return denom, false + } + return *d, true } diff --git a/modules/nft/keeper/migrations.go b/modules/nft/keeper/migrations.go new file mode 100644 index 00000000..02b5f7bb --- /dev/null +++ b/modules/nft/keeper/migrations.go @@ -0,0 +1,22 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + v2 "github.com/irisnet/irismod/modules/nft/migrations/v2" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + k Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(k Keeper) Migrator { + return Migrator{k: k} +} + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.Migrate(ctx, m.k.storeKey, m.k.cdc, m.k.Logger(ctx), m.k) +} diff --git a/modules/nft/keeper/msg_server.go b/modules/nft/keeper/msg_server.go index 3aa73c93..c5679261 100644 --- a/modules/nft/keeper/msg_server.go +++ b/modules/nft/keeper/msg_server.go @@ -9,29 +9,27 @@ import ( "github.com/irisnet/irismod/modules/nft/types" ) -type msgServer struct { - Keeper -} - -var _ types.MsgServer = msgServer{} - -// NewMsgServerImpl returns an implementation of the NFT MsgServer interface -// for the provided Keeper. -func NewMsgServerImpl(keeper Keeper) types.MsgServer { - return &msgServer{Keeper: keeper} -} +var _ types.MsgServer = Keeper{} // IssueDenom issue a new denom. -func (m msgServer) IssueDenom(goCtx context.Context, msg *types.MsgIssueDenom) (*types.MsgIssueDenomResponse, error) { +func (k Keeper) IssueDenom(goCtx context.Context, msg *types.MsgIssueDenom) (*types.MsgIssueDenomResponse, error) { sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return nil, err } ctx := sdk.UnwrapSDKContext(goCtx) - if err := m.Keeper.IssueDenom(ctx, msg.Id, msg.Name, msg.Schema, msg.Symbol, sender, - msg.MintRestricted, msg.UpdateRestricted, - msg.Description, msg.Uri, msg.UriHash, msg.Data, + if err := k.SaveDenom(ctx, msg.Id, + msg.Name, + msg.Schema, + msg.Symbol, + sender, + msg.MintRestricted, + msg.UpdateRestricted, + msg.Description, + msg.Uri, + msg.UriHash, + msg.Data, ); err != nil { return nil, err } @@ -53,7 +51,7 @@ func (m msgServer) IssueDenom(goCtx context.Context, msg *types.MsgIssueDenom) ( return &types.MsgIssueDenomResponse{}, nil } -func (m msgServer) MintNFT(goCtx context.Context, msg *types.MsgMintNFT) (*types.MsgMintNFTResponse, error) { +func (k Keeper) MintNFT(goCtx context.Context, msg *types.MsgMintNFT) (*types.MsgMintNFTResponse, error) { recipient, err := sdk.AccAddressFromBech32(msg.Recipient) if err != nil { return nil, err @@ -66,16 +64,18 @@ func (m msgServer) MintNFT(goCtx context.Context, msg *types.MsgMintNFT) (*types ctx := sdk.UnwrapSDKContext(goCtx) - denom, found := m.Keeper.GetDenom(ctx, msg.DenomId) - if !found { - return nil, sdkerrors.Wrapf(types.ErrInvalidDenom, "denom ID %s not exists", msg.DenomId) + denom, err := k.GetDenomInfo(ctx, msg.DenomId) + if err != nil { + return nil, err } if denom.MintRestricted && denom.Creator != sender.String() { - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to mint NFT of denom %s", msg.Sender, msg.DenomId) + return nil, sdkerrors.Wrapf( + sdkerrors.ErrUnauthorized, "%s is not allowed to mint NFT of denom %s", sender, msg.DenomId) } - if err := m.Keeper.MintNFT(ctx, msg.DenomId, msg.Id, + if err := k.SaveNFT(ctx, msg.DenomId, + msg.Id, msg.Name, msg.URI, msg.UriHash, @@ -103,14 +103,15 @@ func (m msgServer) MintNFT(goCtx context.Context, msg *types.MsgMintNFT) (*types return &types.MsgMintNFTResponse{}, nil } -func (m msgServer) EditNFT(goCtx context.Context, msg *types.MsgEditNFT) (*types.MsgEditNFTResponse, error) { +func (k Keeper) EditNFT(goCtx context.Context, msg *types.MsgEditNFT) (*types.MsgEditNFTResponse, error) { sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return nil, err } ctx := sdk.UnwrapSDKContext(goCtx) - if err := m.Keeper.EditNFT(ctx, msg.DenomId, msg.Id, + if err := k.UpdateNFT(ctx, msg.DenomId, + msg.Id, msg.Name, msg.URI, msg.UriHash, @@ -138,7 +139,8 @@ func (m msgServer) EditNFT(goCtx context.Context, msg *types.MsgEditNFT) (*types return &types.MsgEditNFTResponse{}, nil } -func (m msgServer) TransferNFT(goCtx context.Context, msg *types.MsgTransferNFT) (*types.MsgTransferNFTResponse, error) { +func (k Keeper) TransferNFT(goCtx context.Context, + msg *types.MsgTransferNFT) (*types.MsgTransferNFTResponse, error) { sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return nil, err @@ -150,7 +152,8 @@ func (m msgServer) TransferNFT(goCtx context.Context, msg *types.MsgTransferNFT) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := m.Keeper.TransferOwner(ctx, msg.DenomId, msg.Id, + if err := k.TransferOwnership(ctx, msg.DenomId, + msg.Id, msg.Name, msg.URI, msg.UriHash, @@ -179,14 +182,14 @@ func (m msgServer) TransferNFT(goCtx context.Context, msg *types.MsgTransferNFT) return &types.MsgTransferNFTResponse{}, nil } -func (m msgServer) BurnNFT(goCtx context.Context, msg *types.MsgBurnNFT) (*types.MsgBurnNFTResponse, error) { +func (k Keeper) BurnNFT(goCtx context.Context, msg *types.MsgBurnNFT) (*types.MsgBurnNFTResponse, error) { sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return nil, err } ctx := sdk.UnwrapSDKContext(goCtx) - if err := m.Keeper.BurnNFT(ctx, msg.DenomId, msg.Id, sender); err != nil { + if err := k.RemoveNFT(ctx, msg.DenomId, msg.Id, sender); err != nil { return nil, err } @@ -207,7 +210,7 @@ func (m msgServer) BurnNFT(goCtx context.Context, msg *types.MsgBurnNFT) (*types return &types.MsgBurnNFTResponse{}, nil } -func (m msgServer) TransferDenom(goCtx context.Context, msg *types.MsgTransferDenom) (*types.MsgTransferDenomResponse, error) { +func (k Keeper) TransferDenom(goCtx context.Context, msg *types.MsgTransferDenom) (*types.MsgTransferDenomResponse, error) { sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return nil, err @@ -219,7 +222,7 @@ func (m msgServer) TransferDenom(goCtx context.Context, msg *types.MsgTransferDe } ctx := sdk.UnwrapSDKContext(goCtx) - if err := m.Keeper.TransferDenomOwner(ctx, msg.Id, sender, recipient); err != nil { + if err := k.TransferDenomOwner(ctx, msg.Id, sender, recipient); err != nil { return nil, err } diff --git a/modules/nft/keeper/nft.go b/modules/nft/keeper/nft.go index 7729c3f0..3937614a 100644 --- a/modules/nft/keeper/nft.go +++ b/modules/nft/keeper/nft.go @@ -1,73 +1,214 @@ package keeper import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/nft" "github.com/irisnet/irismod/modules/nft/exported" "github.com/irisnet/irismod/modules/nft/types" ) -// GetNFT gets the the specified NFT -func (k Keeper) GetNFT(ctx sdk.Context, denomID, tokenID string) (nft exported.NFT, err error) { - store := ctx.KVStore(k.storeKey) +// SaveNFT mints an NFT and manages the NFT's existence within Collections and Owners +func (k Keeper) SaveNFT(ctx sdk.Context, denomID, + tokenID, + tokenNm, + tokenURI, + tokenUriHash, + tokenData string, + receiver sdk.AccAddress, +) error { + nftMetadata := &types.NFTMetadata{ + Name: tokenNm, + Data: tokenData, + } + data, err := codectypes.NewAnyWithValue(nftMetadata) + if err != nil { + return err + } + return k.nk.Mint(ctx, nft.NFT{ + ClassId: denomID, + Id: tokenID, + Uri: tokenURI, + UriHash: tokenUriHash, + Data: data, + }, receiver) +} - bz := store.Get(types.KeyNFT(denomID, tokenID)) - if bz == nil { - return nil, sdkerrors.Wrapf(types.ErrUnknownNFT, "not found NFT: %s", tokenID) +// UpdateNFT updates an already existing NFT +func (k Keeper) UpdateNFT(ctx sdk.Context, denomID, + tokenID, + tokenNm, + tokenURI, + tokenURIHash, + tokenData string, + owner sdk.AccAddress, +) error { + denom, err := k.GetDenomInfo(ctx, denomID) + if err != nil { + return err } - var baseNFT types.BaseNFT - k.cdc.MustUnmarshal(bz, &baseNFT) + if denom.UpdateRestricted { + // if true , nobody can update the NFT under this denom + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "nobody can update the NFT under this denom %s", denomID) + } - return baseNFT, nil -} + // just the owner of NFT can edit + if err := k.Authorize(ctx, denomID, tokenID, owner); err != nil { + return err + } -// GetNFTs returns all NFTs by the specified denom ID -func (k Keeper) GetNFTs(ctx sdk.Context, denom string) (nfts []exported.NFT) { - store := ctx.KVStore(k.storeKey) + if !types.Modified(tokenURI) && + !types.Modified(tokenURIHash) && + !types.Modified(tokenNm) && + !types.Modified(tokenData) { + return nil + } - iterator := sdk.KVStorePrefixIterator(store, types.KeyNFT(denom, "")) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - var baseNFT types.BaseNFT - k.cdc.MustUnmarshal(iterator.Value(), &baseNFT) - nfts = append(nfts, baseNFT) + token, exist := k.nk.GetNFT(ctx, denomID, tokenID) + if !exist { + return sdkerrors.Wrapf(types.ErrUnknownNFT, "nft ID %s not exists", tokenID) } - return nfts + token.Uri = types.Modify(token.Uri, tokenURI) + token.UriHash = types.Modify(token.UriHash, tokenURIHash) + if types.Modified(tokenNm) || types.Modified(tokenData) { + var nftMetadata types.NFTMetadata + if err := k.cdc.Unmarshal(token.Data.GetValue(), &nftMetadata); err != nil { + return err + } + + nftMetadata.Name = types.Modify(nftMetadata.Name, tokenNm) + nftMetadata.Data = types.Modify(nftMetadata.Data, tokenData) + data, err := codectypes.NewAnyWithValue(&nftMetadata) + if err != nil { + return err + } + token.Data = data + } + return k.nk.Update(ctx, token) } -// Authorize checks if the sender is the owner of the given NFT -// Return the NFT if true, an error otherwise -func (k Keeper) Authorize(ctx sdk.Context, denomID, tokenID string, owner sdk.AccAddress) (types.BaseNFT, error) { - nft, err := k.GetNFT(ctx, denomID, tokenID) +// TransferOwnership transfers the ownership of the given NFT to the new owner +func (k Keeper) TransferOwnership(ctx sdk.Context, denomID, + tokenID, + tokenNm, + tokenURI, + tokenURIHash, + tokenData string, + srcOwner, + dstOwner sdk.AccAddress, +) error { + token, exist := k.nk.GetNFT(ctx, denomID, tokenID) + if !exist { + return sdkerrors.Wrapf(types.ErrInvalidTokenID, "nft ID %s not exists", tokenID) + } + + if err := k.Authorize(ctx, denomID, tokenID, srcOwner); err != nil { + return err + } + + denom, err := k.GetDenomInfo(ctx, denomID) if err != nil { - return types.BaseNFT{}, err + return err + } + + tokenChanged := types.Modified(tokenURI) || types.Modified(tokenURIHash) + tokenMetadataChanged := types.Modified(tokenNm) || types.Modified(tokenData) + + if denom.UpdateRestricted && (tokenChanged || tokenMetadataChanged) { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "It is restricted to update NFT under this denom %s", denom.Id) } - if !owner.Equals(nft.GetOwner()) { - return types.BaseNFT{}, sdkerrors.Wrap(types.ErrUnauthorized, owner.String()) + if !tokenChanged && !tokenMetadataChanged { + return k.nk.Transfer(ctx, denomID, tokenID, dstOwner) } - return nft.(types.BaseNFT), nil + token.Uri = types.Modify(token.Uri, tokenURI) + token.UriHash = types.Modify(token.UriHash, tokenURIHash) + if tokenMetadataChanged { + var nftMetadata types.NFTMetadata + if err := k.cdc.Unmarshal(token.Data.GetValue(), &nftMetadata); err != nil { + return err + } + + nftMetadata.Name = types.Modify(nftMetadata.Name, tokenNm) + nftMetadata.Data = types.Modify(nftMetadata.Data, tokenData) + data, err := codectypes.NewAnyWithValue(&nftMetadata) + if err != nil { + return err + } + token.Data = data + } + + if err := k.nk.Update(ctx, token); err != nil { + return err + } + return k.nk.Transfer(ctx, denomID, tokenID, dstOwner) } -// HasNFT checks if the specified NFT exists -func (k Keeper) HasNFT(ctx sdk.Context, denomID, tokenID string) bool { - store := ctx.KVStore(k.storeKey) - return store.Has(types.KeyNFT(denomID, tokenID)) +// RemoveNFT deletes a specified NFT +func (k Keeper) RemoveNFT(ctx sdk.Context, denomID, tokenID string, owner sdk.AccAddress) error { + if err := k.Authorize(ctx, denomID, tokenID, owner); err != nil { + return err + } + return k.nk.Burn(ctx, denomID, tokenID) } -func (k Keeper) setNFT(ctx sdk.Context, denomID string, nft types.BaseNFT) { - store := ctx.KVStore(k.storeKey) +// GetNFT gets the specified NFT +func (k Keeper) GetNFT(ctx sdk.Context, denomID, tokenID string) (nft exported.NFT, err error) { + token, exist := k.nk.GetNFT(ctx, denomID, tokenID) + if !exist { + return nil, sdkerrors.Wrapf(types.ErrUnknownNFT, "not found NFT: %s", denomID) + } - bz := k.cdc.MustMarshal(&nft) - store.Set(types.KeyNFT(denomID, nft.GetID()), bz) + var nftMetadata types.NFTMetadata + if err := k.cdc.Unmarshal(token.Data.GetValue(), &nftMetadata); err != nil { + return nil, err + } + + owner := k.nk.GetOwner(ctx, denomID, tokenID) + return types.BaseNFT{ + Id: token.Id, + Name: nftMetadata.Name, + URI: token.Uri, + Data: nftMetadata.Data, + Owner: owner.String(), + UriHash: token.UriHash, + }, nil } -// deleteNFT deletes an existing NFT from store -func (k Keeper) deleteNFT(ctx sdk.Context, denomID string, nft exported.NFT) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.KeyNFT(denomID, nft.GetID())) +// GetNFTs returns all NFTs by the specified denom ID +func (k Keeper) GetNFTs(ctx sdk.Context, denom string) (nfts []exported.NFT, err error) { + tokens := k.nk.GetNFTsOfClass(ctx, denom) + for _, token := range tokens { + var nftMetadata types.NFTMetadata + if err := k.cdc.Unmarshal(token.Data.GetValue(), &nftMetadata); err != nil { + return nil, err + } + nfts = append(nfts, types.BaseNFT{ + Id: token.GetId(), + Name: nftMetadata.Name, + URI: token.GetUri(), + Data: nftMetadata.Data, + Owner: k.nk.GetOwner(ctx, denom, token.GetId()).String(), + }) + } + return nfts, nil +} + +// Authorize checks if the sender is the owner of the given NFT +// Return the NFT if true, an error otherwise +func (k Keeper) Authorize(ctx sdk.Context, denomID, tokenID string, owner sdk.AccAddress) error { + if !owner.Equals(k.nk.GetOwner(ctx, denomID, tokenID)) { + return sdkerrors.Wrap(types.ErrUnauthorized, owner.String()) + } + return nil +} + +// HasNFT checks if the specified NFT exists +func (k Keeper) HasNFT(ctx sdk.Context, denomID, tokenID string) bool { + return k.nk.HasNFT(ctx, denomID, tokenID) } diff --git a/modules/nft/keeper/nft_test.go b/modules/nft/keeper/nft_test.go index 07f67011..0b7a7536 100644 --- a/modules/nft/keeper/nft_test.go +++ b/modules/nft/keeper/nft_test.go @@ -5,8 +5,8 @@ import ( ) func (suite *KeeperSuite) TestGetNFT() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) // GetNFT should get the NFT @@ -16,8 +16,8 @@ func (suite *KeeperSuite) TestGetNFT() { suite.True(receivedNFT.GetOwner().Equals(address)) suite.Equal(receivedNFT.GetURI(), tokenURI) - // MintNFT shouldn't fail when collection exists - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection exists + err = suite.keeper.SaveNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) // GetNFT should get the NFT when collection exists @@ -32,30 +32,31 @@ func (suite *KeeperSuite) TestGetNFT() { } func (suite *KeeperSuite) TestGetNFTs() { - err := suite.keeper.MintNFT(suite.ctx, denomID2, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID2, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) + err = suite.keeper.SaveNFT(suite.ctx, denomID2, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID3, tokenNm3, tokenURI, tokenURIHash, tokenData, address) + err = suite.keeper.SaveNFT(suite.ctx, denomID2, tokenID3, tokenNm3, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID3, tokenNm3, tokenURI, tokenURIHash, tokenData, address) + err = suite.keeper.SaveNFT(suite.ctx, denomID, tokenID3, tokenNm3, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - nfts := suite.keeper.GetNFTs(suite.ctx, denomID2) + nfts, err := suite.keeper.GetNFTs(suite.ctx, denomID2) + suite.NoError(err) suite.Len(nfts, 3) } func (suite *KeeperSuite) TestAuthorize() { - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) - _, err = suite.keeper.Authorize(suite.ctx, denomID, tokenID, address2) + err = suite.keeper.Authorize(suite.ctx, denomID, tokenID, address2) suite.Error(err) - _, err = suite.keeper.Authorize(suite.ctx, denomID, tokenID, address) + err = suite.keeper.Authorize(suite.ctx, denomID, tokenID, address) suite.NoError(err) } @@ -64,8 +65,8 @@ func (suite *KeeperSuite) TestHasNFT() { isNFT := suite.keeper.HasNFT(suite.ctx, denomID, tokenID) suite.False(isNFT) - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) + // SaveNFT shouldn't fail when collection does not exist + err := suite.keeper.SaveNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) suite.NoError(err) // IsNFT should return true diff --git a/modules/nft/keeper/owners.go b/modules/nft/keeper/owners.go deleted file mode 100644 index 38a99205..00000000 --- a/modules/nft/keeper/owners.go +++ /dev/null @@ -1,90 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/irisnet/irismod/modules/nft/types" -) - -// GetOwner gets all the ID collections owned by an address and denom ID -func (k Keeper) GetOwner(ctx sdk.Context, address sdk.AccAddress, denom string) types.Owner { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.KeyOwner(address, denom, "")) - defer iterator.Close() - - owner := types.Owner{ - Address: address.String(), - IDCollections: types.IDCollections{}, - } - idsMap := make(map[string][]string) - - for ; iterator.Valid(); iterator.Next() { - _, denomID, tokenID, _ := types.SplitKeyOwner(iterator.Key()) - if ids, ok := idsMap[denomID]; ok { - idsMap[denomID] = append(ids, tokenID) - } else { - idsMap[denomID] = []string{tokenID} - owner.IDCollections = append( - owner.IDCollections, - types.IDCollection{DenomId: denomID}, - ) - } - } - - for i := 0; i < len(owner.IDCollections); i++ { - owner.IDCollections[i].TokenIds = idsMap[owner.IDCollections[i].DenomId] - } - - return owner -} - -// GetOwners gets all the ID collections -func (k Keeper) GetOwners(ctx sdk.Context) (owners types.Owners) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStoreReversePrefixIterator(store, types.KeyOwner(nil, "", "")) - defer iterator.Close() - - idcsMap := make(map[string]types.IDCollections) - for ; iterator.Valid(); iterator.Next() { - key := iterator.Key() - address, denom, id, _ := types.SplitKeyOwner(key) - if _, ok := idcsMap[address.String()]; !ok { - idcsMap[address.String()] = types.IDCollections{} - owners = append( - owners, - types.Owner{Address: address.String()}, - ) - } - idcs := idcsMap[address.String()] - idcs = idcs.Add(denom, id) - idcsMap[address.String()] = idcs - } - for i, owner := range owners { - owners[i].IDCollections = idcsMap[owner.Address] - } - - return owners -} - -func (k Keeper) deleteOwner(ctx sdk.Context, denomID, tokenID string, owner sdk.AccAddress) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.KeyOwner(owner, denomID, tokenID)) -} - -func (k Keeper) setOwner(ctx sdk.Context, - denomID, tokenID string, - owner sdk.AccAddress) { - store := ctx.KVStore(k.storeKey) - - bz := types.MustMarshalTokenID(k.cdc, tokenID) - store.Set(types.KeyOwner(owner, denomID, tokenID), bz) -} - -func (k Keeper) swapOwner(ctx sdk.Context, denomID, tokenID string, srcOwner, dstOwner sdk.AccAddress) { - - // delete old owner key - k.deleteOwner(ctx, denomID, tokenID, srcOwner) - - // set new owner key - k.setOwner(ctx, denomID, tokenID, dstOwner) -} diff --git a/modules/nft/keeper/owners_test.go b/modules/nft/keeper/owners_test.go deleted file mode 100644 index a57db0b0..00000000 --- a/modules/nft/keeper/owners_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package keeper_test - -import ( - "github.com/irisnet/irismod/modules/nft/keeper" -) - -func (suite *KeeperSuite) TestGetOwners() { - - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address2) - suite.NoError(err) - - err = suite.keeper.MintNFT(suite.ctx, denomID, tokenID3, tokenNm3, tokenURI, tokenURIHash, tokenData, address3) - suite.NoError(err) - - owners := suite.keeper.GetOwners(suite.ctx) - suite.Equal(3, len(owners)) - - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID2, tokenNm2, tokenURI, tokenURIHash, tokenData, address2) - suite.NoError(err) - - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID3, tokenNm3, tokenURI, tokenURIHash, tokenData, address3) - suite.NoError(err) - - owners = suite.keeper.GetOwners(suite.ctx) - suite.Equal(3, len(owners)) - - msg, fail := keeper.SupplyInvariant(suite.keeper)(suite.ctx) - suite.False(fail, msg) -} diff --git a/modules/nft/keeper/pagination_test.go b/modules/nft/keeper/pagination_test.go index 892fdf1f..66d88637 100644 --- a/modules/nft/keeper/pagination_test.go +++ b/modules/nft/keeper/pagination_test.go @@ -24,7 +24,6 @@ func TestShapePageRequest(t *testing.T) { CountTotal: true, Reverse: true, } - res2 := ShapePageRequest(request) require.NotNil(t, res2) require.Equal(t, res2.Limit, defaultRequest.Limit) // limit == paginationDefaultLimit diff --git a/modules/nft/keeper/querier.go b/modules/nft/keeper/querier.go deleted file mode 100644 index 6b588530..00000000 --- a/modules/nft/keeper/querier.go +++ /dev/null @@ -1,141 +0,0 @@ -package keeper - -import ( - "encoding/binary" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/irisnet/irismod/modules/nft/types" -) - -// NewQuerier is the module level router for state queries -func NewQuerier(k Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) { - switch path[0] { - case types.QuerySupply: - return querySupply(ctx, req, k, legacyQuerierCdc) - case types.QueryOwner: - return queryOwner(ctx, req, k, legacyQuerierCdc) - case types.QueryCollection: - return queryCollection(ctx, req, k, legacyQuerierCdc) - case types.QueryDenom: - return queryDenom(ctx, req, k, legacyQuerierCdc) - case types.QueryDenoms: - return queryDenoms(ctx, req, k, legacyQuerierCdc) - case types.QueryNFT: - return queryNFT(ctx, req, k, legacyQuerierCdc) - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) - } - } -} - -func querySupply(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QuerySupplyParams - - err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) - } - - var supply uint64 - if params.Owner.Empty() && len(params.Denom) > 0 { - supply = k.GetTotalSupply(ctx, params.Denom) - } else { - supply = k.GetTotalSupplyOfOwner(ctx, params.Denom, params.Owner) - } - - bz := make([]byte, 8) - binary.LittleEndian.PutUint64(bz, supply) - return bz, nil -} - -func queryOwner(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryOwnerParams - - err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) - } - - owner := k.GetOwner(ctx, params.Owner, params.Denom) - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, owner) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} - -func queryCollection(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryCollectionParams - - err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) - } - - collection, err := k.GetCollection(ctx, params.Denom) - if err != nil { - return nil, err - } - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, collection) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} - -func queryDenom(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryDenomParams - - if err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) - } - - denom, _ := k.GetDenom(ctx, params.ID) - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, denom) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} - -func queryDenoms(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - denoms := k.GetDenoms(ctx) - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, denoms) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} - -func queryNFT(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { - var params types.QueryNFTParams - - if err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) - } - - nft, err := k.GetNFT(ctx, params.Denom, params.TokenID) - if err != nil { - return nil, sdkerrors.Wrapf(types.ErrUnknownNFT, "invalid NFT %s from collection %s", params.TokenID, params.Denom) - } - - bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, nft) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} diff --git a/modules/nft/keeper/querier_test.go b/modules/nft/keeper/querier_test.go deleted file mode 100644 index 39b5d907..00000000 --- a/modules/nft/keeper/querier_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package keeper_test - -import ( - "encoding/binary" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/irisnet/irismod/modules/nft/exported" - keep "github.com/irisnet/irismod/modules/nft/keeper" - "github.com/irisnet/irismod/modules/nft/types" -) - -func (suite *KeeperSuite) TestNewQuerier() { - querier := keep.NewQuerier(suite.keeper, suite.legacyAmino) - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - _, err := querier(suite.ctx, []string{"foo", "bar"}, query) - suite.Error(err) -} - -func (suite *KeeperSuite) TestQuerySupply() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - querier := keep.NewQuerier(suite.keeper, suite.legacyAmino) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - - query.Path = "/custom/nft/supply" - query.Data = []byte("?") - - res, err := querier(suite.ctx, []string{"supply"}, query) - suite.Error(err) - suite.Nil(res) - - queryCollectionParams := types.NewQuerySupplyParams(denomID2, nil) - bz, errRes := suite.legacyAmino.MarshalJSON(queryCollectionParams) - suite.Nil(errRes) - query.Data = bz - res, err = querier(suite.ctx, []string{"supply"}, query) - suite.NoError(err) - supplyResp := binary.LittleEndian.Uint64(res) - suite.Equal(0, int(supplyResp)) - - queryCollectionParams = types.NewQuerySupplyParams(denomID, nil) - bz, errRes = suite.legacyAmino.MarshalJSON(queryCollectionParams) - suite.Nil(errRes) - query.Data = bz - - res, err = querier(suite.ctx, []string{"supply"}, query) - suite.NoError(err) - suite.NotNil(res) - - supplyResp = binary.LittleEndian.Uint64(res) - suite.Equal(1, int(supplyResp)) -} - -func (suite *KeeperSuite) TestQueryCollection() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - querier := keep.NewQuerier(suite.keeper, suite.legacyAmino) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - - query.Path = "/custom/nft/collection" - - query.Data = []byte("?") - res, err := querier(suite.ctx, []string{"collection"}, query) - suite.Error(err) - suite.Nil(res) - - queryCollectionParams := types.NewQuerySupplyParams(denomID2, nil) - bz, errRes := suite.legacyAmino.MarshalJSON(queryCollectionParams) - suite.Nil(errRes) - - query.Data = bz - _, err = querier(suite.ctx, []string{"collection"}, query) - suite.NoError(err) - - queryCollectionParams = types.NewQuerySupplyParams(denomID, nil) - bz, errRes = suite.legacyAmino.MarshalJSON(queryCollectionParams) - suite.Nil(errRes) - - query.Data = bz - res, err = querier(suite.ctx, []string{"collection"}, query) - suite.NoError(err) - suite.NotNil(res) - - var collection types.Collection - types.ModuleCdc.MustUnmarshalJSON(res, &collection) - suite.Len(collection.NFTs, 1) -} - -func (suite *KeeperSuite) TestQueryOwner() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - querier := keep.NewQuerier(suite.keeper, suite.legacyAmino) - query := abci.RequestQuery{ - Path: "/custom/nft/owner", - Data: []byte{}, - } - - query.Data = []byte("?") - _, err = querier(suite.ctx, []string{"owner"}, query) - suite.Error(err) - - // query the balance using no denomID so that all denoms will be returns - params := types.NewQuerySupplyParams("", address) - bz, err2 := suite.legacyAmino.MarshalJSON(params) - suite.Nil(err2) - query.Data = bz - - var out types.Owner - res, err := querier(suite.ctx, []string{"owner"}, query) - suite.NoError(err) - suite.NotNil(res) - - suite.legacyAmino.MustUnmarshalJSON(res, &out) - - // build the owner using both denoms - idCollection1 := types.NewIDCollection(denomID, []string{tokenID}) - idCollection2 := types.NewIDCollection(denomID2, []string{tokenID}) - owner := types.NewOwner(address, idCollection1, idCollection2) - - suite.EqualValues(out.String(), owner.String()) -} - -func (suite *KeeperSuite) TestQueryNFT() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - querier := keep.NewQuerier(suite.keeper, suite.legacyAmino) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - query.Path = "/custom/nft/nft" - var res []byte - - query.Data = []byte("?") - res, err = querier(suite.ctx, []string{"nft"}, query) - suite.Error(err) - suite.Nil(res) - - params := types.NewQueryNFTParams(denomID2, tokenID2) - bz, err2 := suite.legacyAmino.MarshalJSON(params) - suite.Nil(err2) - - query.Data = bz - res, err = querier(suite.ctx, []string{"nft"}, query) - suite.Error(err) - suite.Nil(res) - - params = types.NewQueryNFTParams(denomID, tokenID) - bz, err2 = suite.legacyAmino.MarshalJSON(params) - suite.Nil(err2) - - query.Data = bz - res, err = querier(suite.ctx, []string{"nft"}, query) - suite.NoError(err) - suite.NotNil(res) - - var out exported.NFT - suite.legacyAmino.MustUnmarshalJSON(res, &out) - - suite.Equal(out.GetID(), tokenID) - suite.Equal(out.GetURI(), tokenURI) - suite.Equal(out.GetOwner(), address) -} - -func (suite *KeeperSuite) TestQueryDenoms() { - // MintNFT shouldn't fail when collection does not exist - err := suite.keeper.MintNFT(suite.ctx, denomID, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - err = suite.keeper.MintNFT(suite.ctx, denomID2, tokenID, tokenNm, tokenURI, tokenURIHash, tokenData, address) - suite.NoError(err) - - querier := keep.NewQuerier(suite.keeper, suite.legacyAmino) - - query := abci.RequestQuery{ - Path: "", - Data: []byte{}, - } - var res []byte - query.Path = "/custom/nft/denoms" - - res, err = querier(suite.ctx, []string{"denoms"}, query) - suite.NoError(err) - suite.NotNil(res) - - denoms := []string{denomID, denomID2, denomID3} - - var out []types.Denom - suite.legacyAmino.MustUnmarshalJSON(res, &out) - - for key, denomInQuestion := range out { - suite.Equal(denomInQuestion.Id, denoms[key]) - } -} diff --git a/modules/nft/migrations/v2/expected_keeper.go b/modules/nft/migrations/v2/expected_keeper.go new file mode 100644 index 00000000..a4845c30 --- /dev/null +++ b/modules/nft/migrations/v2/expected_keeper.go @@ -0,0 +1,27 @@ +package v2 + +import sdk "github.com/cosmos/cosmos-sdk/types" + +type NFTKeeper interface { + SaveDenom(ctx sdk.Context, id, + name, + schema, + symbol string, + creator sdk.AccAddress, + mintRestricted, + updateRestricted bool, + description, + uri, + uriHash, + data string, + ) error + + SaveNFT(ctx sdk.Context, denomID, + tokenID, + tokenNm, + tokenURI, + tokenUriHash, + tokenData string, + receiver sdk.AccAddress, + ) error +} diff --git a/modules/nft/migrations/v2/keys.go b/modules/nft/migrations/v2/keys.go new file mode 100644 index 00000000..88db65fc --- /dev/null +++ b/modules/nft/migrations/v2/keys.go @@ -0,0 +1,64 @@ +package v2 + +import sdk "github.com/cosmos/cosmos-sdk/types" + +var ( + PrefixNFT = []byte{0x01} + PrefixOwners = []byte{0x02} // key for a owner + PrefixCollection = []byte{0x03} // key for balance of NFTs held by the denom + PrefixDenom = []byte{0x04} // key for denom of the nft + PrefixDenomName = []byte{0x05} // key for denom name of the nft + + delimiter = []byte("/") +) + +// KeyDenom gets the storeKey by the denom id +func KeyDenom(id string) []byte { + key := append(PrefixDenom, delimiter...) + return append(key, []byte(id)...) +} + +// KeyDenomName gets the storeKey by the denom name +func KeyDenomName(name string) []byte { + key := append(PrefixDenomName, delimiter...) + return append(key, []byte(name)...) +} + +// KeyNFT gets the key of nft stored by an denom and id +func KeyNFT(denomID, tokenID string) []byte { + key := append(PrefixNFT, delimiter...) + if len(denomID) > 0 { + key = append(key, []byte(denomID)...) + key = append(key, delimiter...) + } + + if len(denomID) > 0 && len(tokenID) > 0 { + key = append(key, []byte(tokenID)...) + } + return key +} + +// KeyCollection gets the storeKey by the collection +func KeyCollection(denomID string) []byte { + key := append(PrefixCollection, delimiter...) + return append(key, []byte(denomID)...) +} + +// KeyOwner gets the key of a collection owned by an account address +func KeyOwner(address sdk.AccAddress, denomID, tokenID string) []byte { + key := append(PrefixOwners, delimiter...) + if address != nil { + key = append(key, []byte(address.String())...) + key = append(key, delimiter...) + } + + if address != nil && len(denomID) > 0 { + key = append(key, []byte(denomID)...) + key = append(key, delimiter...) + } + + if address != nil && len(denomID) > 0 && len(tokenID) > 0 { + key = append(key, []byte(tokenID)...) + } + return key +} diff --git a/modules/nft/migrations/v2/store.go b/modules/nft/migrations/v2/store.go new file mode 100644 index 00000000..b17218f0 --- /dev/null +++ b/modules/nft/migrations/v2/store.go @@ -0,0 +1,126 @@ +package v2 + +import ( + "time" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/irisnet/irismod/modules/nft/types" +) + +func Migrate(ctx sdk.Context, + storeKey storetypes.StoreKey, + cdc codec.Codec, + logger log.Logger, + k NFTKeeper, +) error { + logger.Info("migrate store data from version 1 to 2") + startTime := time.Now() + denoms, err := migrateDenoms(ctx, storeKey, cdc, k) + if err != nil { + return err + } + logger.Info("migrate denoms success", "denomNum", len(denoms)) + + if err := migrateTokens(ctx, storeKey, cdc, logger, denoms, k); err != nil { + return err + } + logger.Info("migrate store data success", "consume", time.Since(startTime).String()) + return nil +} + +func migrateDenoms(ctx sdk.Context, + storeKey storetypes.StoreKey, + cdc codec.Codec, + k NFTKeeper, +) (denoms []string, err error) { + store := ctx.KVStore(storeKey) + iterator := sdk.KVStorePrefixIterator(store, KeyDenom("")) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var denom types.Denom + cdc.MustUnmarshal(iterator.Value(), &denom) + + //delete unused key + store.Delete(KeyDenom(denom.Id)) + store.Delete(KeyDenomName(denom.Name)) + store.Delete(KeyCollection(denom.Id)) + + creator, err := sdk.AccAddressFromBech32(denom.Creator) + if err != nil { + return denoms, err + } + + if err := k.SaveDenom(ctx, denom.Id, + denom.Name, + denom.Schema, + denom.Symbol, + creator, + denom.MintRestricted, + denom.UpdateRestricted, + denom.Description, + denom.Uri, + denom.UriHash, + denom.Data, + ); err != nil { + return denoms, err + } + denoms = append(denoms, denom.Id) + + } + return denoms, nil +} + +func migrateTokens(ctx sdk.Context, + storeKey storetypes.StoreKey, + cdc codec.Codec, + logger log.Logger, + denoms []string, + k NFTKeeper, +) error { + store := ctx.KVStore(storeKey) + + var iterator sdk.Iterator + defer func() { + if iterator != nil { + _ = iterator.Close() + } + }() + + total := int64(0) + for _, denomID := range denoms { + iterator = sdk.KVStorePrefixIterator(store, KeyNFT(denomID, "")) + for ; iterator.Valid(); iterator.Next() { + var baseNFT types.BaseNFT + cdc.MustUnmarshal(iterator.Value(), &baseNFT) + + owner, err := sdk.AccAddressFromBech32(baseNFT.Owner) + if err != nil { + return err + } + + //delete unused key + store.Delete(KeyNFT(denomID, baseNFT.Id)) + store.Delete(KeyOwner(owner, denomID, baseNFT.Id)) + + if err := k.SaveNFT(ctx, denomID, + baseNFT.Id, + baseNFT.Name, + baseNFT.URI, + baseNFT.UriHash, + baseNFT.Data, + owner, + ); err != nil { + return err + } + total++ + } + } + logger.Info("migrate nft success", "nftNum", total) + return nil +} diff --git a/modules/nft/migrations/v2/store_test.go b/modules/nft/migrations/v2/store_test.go new file mode 100644 index 00000000..d91c0342 --- /dev/null +++ b/modules/nft/migrations/v2/store_test.go @@ -0,0 +1,153 @@ +package v2_test + +import ( + "fmt" + + gogotypes "github.com/gogo/protobuf/types" + + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/irisnet/irismod/modules/nft/keeper" + v2 "github.com/irisnet/irismod/modules/nft/migrations/v2" + "github.com/irisnet/irismod/modules/nft/types" + "github.com/irisnet/irismod/simapp" +) + +func TestMigrate(t *testing.T) { + app := simapp.Setup(t, false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + storeKey := app.GetKey(types.StoreKey) + cdc := app.AppCodec() + + collections := prepareData(ctx, storeKey, cdc) + require.NoError(t, v2.Migrate(ctx, storeKey, cdc, app.NFTKeeper.Logger(ctx), app.NFTKeeper)) + check(t, ctx, app.NFTKeeper, collections) + +} + +func prepareData(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec) (collection []types.Collection) { + addrs := simapp.CreateTestAddrs(10) + for i := 1; i <= 10; i++ { + denom := types.Denom{ + Id: fmt.Sprintf("denom%d", i), + Name: fmt.Sprintf("denomName%d", i), + Schema: fmt.Sprintf("denomSchema%d", i), + Creator: addrs[rand.Intn(len(addrs))].String(), + Symbol: fmt.Sprintf("denomSymbol%d", i), + MintRestricted: false, + UpdateRestricted: true, + Description: fmt.Sprintf("denomDescription%d", i), + Uri: fmt.Sprintf("denomUri%d", i), + UriHash: fmt.Sprintf("denomUriHash%d", i), + Data: fmt.Sprintf("denomData%d", i), + } + setDenom(ctx, storeKey, cdc, denom) + + var tokens []types.BaseNFT + for j := 1; j <= 100; j++ { + token := types.BaseNFT{ + Id: fmt.Sprintf("nft%d", j), + Name: fmt.Sprintf("nftName%d", j), + URI: fmt.Sprintf("nftURI%d", j), + Data: fmt.Sprintf("nftData%d", j), + Owner: addrs[rand.Intn(len(addrs))].String(), + UriHash: fmt.Sprintf("nftUriHash%d", j), + } + tokens = append(tokens, token) + mintNFT(ctx, storeKey, cdc, denom.Id, token) + } + collection = append(collection, types.Collection{ + Denom: denom, + NFTs: tokens, + }) + } + return +} + +func check(t *testing.T, ctx sdk.Context, k keeper.Keeper, collections []types.Collection) { + for _, collection := range collections { + denom := collection.Denom + d, err := k.GetDenomInfo(ctx, denom.Id) + require.NoError(t, err) + require.EqualValues(t, denom, *d) + + for _, token := range collection.NFTs { + nft, err := k.GetNFT(ctx, denom.Id, token.Id) + require.NoError(t, err) + require.EqualValues(t, token, nft) + } + } + keeper.SupplyInvariant(k) +} + +// SetDenom is responsible for saving the definition of denom +func setDenom(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec, denom types.Denom) { + store := ctx.KVStore(storeKey) + bz := cdc.MustMarshal(&denom) + store.Set(v2.KeyDenom(denom.Id), bz) + store.Set(v2.KeyDenomName(denom.Name), []byte(denom.Id)) +} + +// MintNFT mints an NFT and manages the NFT's existence within Collections and Owners +func mintNFT(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec, denomID string, baseToken types.BaseNFT) { + setNFT(ctx, storeKey, cdc, denomID, baseToken) + setOwner(ctx, storeKey, cdc, denomID, baseToken.Id, baseToken.Owner) + increaseSupply(ctx, storeKey, cdc, denomID) +} + +func setNFT(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec, denomID string, baseToken types.BaseNFT) { + store := ctx.KVStore(storeKey) + + bz := cdc.MustMarshal(&baseToken) + store.Set(v2.KeyNFT(denomID, baseToken.Id), bz) +} + +func setOwner(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec, denomID, tokenID, owner string) { + store := ctx.KVStore(storeKey) + bz := mustMarshalTokenID(cdc, tokenID) + ownerAddr := sdk.MustAccAddressFromBech32(owner) + store.Set(v2.KeyOwner(ownerAddr, denomID, tokenID), bz) +} + +func increaseSupply(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec, denomID string) { + supply := getTotalSupply(ctx, storeKey, cdc, denomID) + supply++ + + store := ctx.KVStore(storeKey) + bz := mustMarshalSupply(cdc, supply) + store.Set(v2.KeyCollection(denomID), bz) +} + +func getTotalSupply(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.Codec, denomID string) uint64 { + store := ctx.KVStore(storeKey) + bz := store.Get(v2.KeyCollection(denomID)) + if len(bz) == 0 { + return 0 + } + return mustUnMarshalSupply(cdc, bz) +} + +func mustMarshalSupply(cdc codec.Codec, supply uint64) []byte { + supplyWrap := gogotypes.UInt64Value{Value: supply} + return cdc.MustMarshal(&supplyWrap) +} + +func mustUnMarshalSupply(cdc codec.Codec, value []byte) uint64 { + var supplyWrap gogotypes.UInt64Value + cdc.MustUnmarshal(value, &supplyWrap) + return supplyWrap.Value +} + +func mustMarshalTokenID(cdc codec.Codec, tokenID string) []byte { + tokenIDWrap := gogotypes.StringValue{Value: tokenID} + return cdc.MustMarshal(&tokenIDWrap) +} diff --git a/modules/nft/module.go b/modules/nft/module/module.go similarity index 83% rename from modules/nft/module.go rename to modules/nft/module/module.go index 8adb3d5f..eb6a4227 100644 --- a/modules/nft/module.go +++ b/modules/nft/module/module.go @@ -1,4 +1,4 @@ -package nft +package module import ( "context" @@ -6,7 +6,6 @@ import ( "fmt" "math/rand" - "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -46,7 +45,7 @@ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // DefaultGenesis returns default genesis state as raw bytes for the NFT module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(DefaultGenesisState()) + return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis performs genesis state validation for the NFT module. @@ -59,10 +58,6 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod return types.ValidateGenesis(data) } -// RegisterRESTRoutes registers the REST routes for the NFT module. -func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { -} - // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the NFT module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { _ = types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) @@ -109,24 +104,31 @@ func (AppModule) Name() string { return types.ModuleName } // RegisterServices registers module services. func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterMsgServer(cfg.MsgServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + + m := keeper.NewMigrator(am.keeper) + if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + panic(fmt.Sprintf("failed to migrate nft from version 1 to 2: %v", err)) + } } // RegisterInvariants registers the NFT module invariants. -func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + keeper.RegisterInvariants(ir, am.keeper) +} // Route returns the message routing key for the NFT module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the NFT module's querier route name. -func (AppModule) QuerierRoute() string { return types.RouterKey } +func (AppModule) QuerierRoute() string { return "" } // LegacyQuerierHandler returns the NFT module sdk.Querier. -func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { - return keeper.NewQuerier(am.keeper, legacyQuerierCdc) +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil } // InitGenesis performs genesis initialization for the NFT module. It returns @@ -136,26 +138,18 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json. cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) + am.keeper.InitGenesis(ctx, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the exported genesis state as raw bytes for the NFT module. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) + gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 1 } - -// BeginBlock performs a no-op. -func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} - -// EndBlock returns the end blocker for the NFT module. It returns no validator updates. -func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} +func (AppModule) ConsensusVersion() uint64 { return 2 } // ____________________________________________________________________________ @@ -178,7 +172,6 @@ func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { // RegisterStoreDecoder registers a decoder for NFT module's types func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) } // WeightedOperations returns the all the NFT module operations with their respective weights. diff --git a/modules/nft/simulation/decoder.go b/modules/nft/simulation/decoder.go deleted file mode 100644 index 2d0d56f6..00000000 --- a/modules/nft/simulation/decoder.go +++ /dev/null @@ -1,40 +0,0 @@ -package simulation - -import ( - "bytes" - "fmt" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/types/kv" - - "github.com/irisnet/irismod/modules/nft/types" -) - -// DecodeStore unmarshals the KVPair's Value to the corresponding gov type -func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { - return func(kvA, kvB kv.Pair) string { - switch { - case bytes.Equal(kvA.Key[:1], types.PrefixNFT): - var nftA, nftB types.BaseNFT - cdc.MustUnmarshal(kvA.Value, &nftA) - cdc.MustUnmarshal(kvB.Value, &nftB) - return fmt.Sprintf("%v\n%v", nftA, nftB) - case bytes.Equal(kvA.Key[:1], types.PrefixOwners): - idA := types.MustUnMarshalTokenID(cdc, kvA.Value) - idB := types.MustUnMarshalTokenID(cdc, kvB.Value) - return fmt.Sprintf("%v\n%v", idA, idB) - case bytes.Equal(kvA.Key[:1], types.PrefixCollection): - supplyA := types.MustUnMarshalSupply(cdc, kvA.Value) - supplyB := types.MustUnMarshalSupply(cdc, kvB.Value) - return fmt.Sprintf("%d\n%d", supplyA, supplyB) - case bytes.Equal(kvA.Key[:1], types.PrefixDenom): - var denomA, denomB types.Denom - cdc.MustUnmarshal(kvA.Value, &denomA) - cdc.MustUnmarshal(kvB.Value, &denomB) - return fmt.Sprintf("%v\n%v", denomA, denomB) - - default: - panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1])) - } - } -} diff --git a/modules/nft/simulation/operations.go b/modules/nft/simulation/operations.go index f92baab5..8b69bc5a 100644 --- a/modules/nft/simulation/operations.go +++ b/modules/nft/simulation/operations.go @@ -115,8 +115,7 @@ func SimulateMsgTransferNFT(k keeper.Keeper, ak types.AccountKeeper, bk types.Ba ) { ownerAddr, denom, nftID := getRandomNFTFromOwner(ctx, k, r) if ownerAddr.Empty() { - err = fmt.Errorf("invalid account") - return simtypes.NoOpMsg(types.ModuleName, types.EventTypeTransfer, err.Error()), nil, err + return simtypes.NoOpMsg(types.ModuleName, types.EventTypeTransfer, "empty account"), nil, err } recipientAccount, _ := simtypes.RandomAcc(r, accs) @@ -177,8 +176,7 @@ func SimulateMsgEditNFT(k keeper.Keeper, ak types.AccountKeeper, bk types.BankKe ) { ownerAddr, denom, nftID := getRandomNFTFromOwner(ctx, k, r) if ownerAddr.Empty() { - err = fmt.Errorf("account invalid") - return simtypes.NoOpMsg(types.ModuleName, types.EventTypeEditNFT, err.Error()), nil, err + return simtypes.NoOpMsg(types.ModuleName, types.EventTypeEditNFT, "empty account"), nil, err } msg := types.NewMsgEditNFT( @@ -295,8 +293,7 @@ func SimulateMsgBurnNFT(k keeper.Keeper, ak types.AccountKeeper, bk types.BankKe ) { ownerAddr, denom, nftID := getRandomNFTFromOwner(ctx, k, r) if ownerAddr.Empty() { - err = fmt.Errorf("invalid account") - return simtypes.NoOpMsg(types.ModuleName, types.EventTypeBurnNFT, err.Error()), nil, err + return simtypes.NoOpMsg(types.ModuleName, types.EventTypeBurnNFT, "empty account"), nil, err } msg := types.NewMsgBurnNFT(ownerAddr.String(), nftID, denom) @@ -347,8 +344,8 @@ func SimulateMsgTransferDenom(k keeper.Keeper, ak types.AccountKeeper, bk types. ) { denomId := getRandomDenom(ctx, k, r) - denom, found := k.GetDenom(ctx, denomId) - if !found { + denom, err := k.GetDenomInfo(ctx, denomId) + if err != nil { return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgTransferDenom, err.Error()), nil, err } @@ -422,7 +419,7 @@ func SimulateMsgIssueDenom(k keeper.Keeper, ak types.AccountKeeper, bk types.Ban return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgTransferDenom, "invalid denom"), nil, nil } - denom, _ := k.GetDenom(ctx, denomId) + denom, _ := k.GetDenomInfo(ctx, denomId) if denom.Size() != 0 { return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgTransferDenom, "denom exist"), nil, nil } @@ -470,37 +467,28 @@ func SimulateMsgIssueDenom(k keeper.Keeper, ak types.AccountKeeper, bk types.Ban } func getRandomNFTFromOwner(ctx sdk.Context, k keeper.Keeper, r *rand.Rand) (address sdk.AccAddress, denomID, tokenID string) { - owners := k.GetOwners(ctx) + goctx := sdk.WrapSDKContext(ctx) + result, _ := k.Denoms(goctx, &types.QueryDenomsRequest{}) - ownersLen := len(owners) - if ownersLen == 0 { + denomsLen := len(result.Denoms) + if denomsLen == 0 { return nil, "", "" } // get random owner - i := r.Intn(ownersLen) - owner := owners[i] + i := r.Intn(denomsLen) + denom := result.Denoms[i] + denomID = denom.Id - idCollectionsLen := len(owner.IDCollections) - if idCollectionsLen == 0 { + nfts, err := k.GetNFTs(ctx, denomID) + if err != nil || len(nfts) == 0 { return nil, "", "" } // get random collection from owner's balance - i = r.Intn(idCollectionsLen) - idCollection := owner.IDCollections[i] // nfts IDs - denomID = idCollection.DenomId - - idsLen := len(idCollection.TokenIds) - if idsLen == 0 { - return nil, "", "" - } - - // get random nft from collection - i = r.Intn(idsLen) - tokenID = idCollection.TokenIds[i] - - ownerAddress, _ := sdk.AccAddressFromBech32(owner.Address) + i = r.Intn(len(nfts)) + tokenID = nfts[i].GetID() + ownerAddress := nfts[i].GetOwner() return ownerAddress, denomID, tokenID } diff --git a/modules/nft/types/codec.go b/modules/nft/types/codec.go index 02b9eb82..e4bb624c 100644 --- a/modules/nft/types/codec.go +++ b/modules/nft/types/codec.go @@ -3,8 +3,6 @@ package types // DONTCOVER import ( - gogotypes "github.com/gogo/protobuf/types" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -56,29 +54,3 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } - -// return supply protobuf code -func MustMarshalSupply(cdc codec.Codec, supply uint64) []byte { - supplyWrap := gogotypes.UInt64Value{Value: supply} - return cdc.MustMarshal(&supplyWrap) -} - -// return th supply -func MustUnMarshalSupply(cdc codec.Codec, value []byte) uint64 { - var supplyWrap gogotypes.UInt64Value - cdc.MustUnmarshal(value, &supplyWrap) - return supplyWrap.Value -} - -// return the tokenID protobuf code -func MustMarshalTokenID(cdc codec.Codec, tokenID string) []byte { - tokenIDWrap := gogotypes.StringValue{Value: tokenID} - return cdc.MustMarshal(&tokenIDWrap) -} - -// return th tokenID -func MustUnMarshalTokenID(cdc codec.Codec, value []byte) string { - var tokenIDWrap gogotypes.StringValue - cdc.MustUnmarshal(value, &tokenIDWrap) - return tokenIDWrap.Value -} diff --git a/modules/nft/types/denom.go b/modules/nft/types/denom.go deleted file mode 100644 index 3b6b0eea..00000000 --- a/modules/nft/types/denom.go +++ /dev/null @@ -1,26 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// NewDenom return a new denom -func NewDenom( - id, name, schema, symbol, description, uri, uriHash, data string, - creator sdk.AccAddress, - mintRestricted, updateRestricted bool, -) Denom { - return Denom{ - Id: id, - Name: name, - Schema: schema, - Creator: creator.String(), - Symbol: symbol, - MintRestricted: mintRestricted, - UpdateRestricted: updateRestricted, - Description: description, - Uri: uri, - UriHash: uriHash, - Data: data, - } -} diff --git a/modules/nft/types/errors.go b/modules/nft/types/errors.go index a95c404c..e5f77082 100644 --- a/modules/nft/types/errors.go +++ b/modules/nft/types/errors.go @@ -5,14 +5,14 @@ import ( ) var ( - ErrInvalidCollection = sdkerrors.Register(ModuleName, 2, "invalid nft collection") - ErrUnknownCollection = sdkerrors.Register(ModuleName, 3, "unknown nft collection") - ErrInvalidNFT = sdkerrors.Register(ModuleName, 4, "invalid nft") - ErrNFTAlreadyExists = sdkerrors.Register(ModuleName, 5, "nft already exists") - ErrUnknownNFT = sdkerrors.Register(ModuleName, 6, "unknown nft") - ErrEmptyTokenData = sdkerrors.Register(ModuleName, 7, "nft data can't be empty") - ErrUnauthorized = sdkerrors.Register(ModuleName, 8, "unauthorized address") - ErrInvalidDenom = sdkerrors.Register(ModuleName, 9, "invalid denom") - ErrInvalidTokenID = sdkerrors.Register(ModuleName, 10, "invalid nft id") - ErrInvalidTokenURI = sdkerrors.Register(ModuleName, 11, "invalid nft uri") + ErrInvalidCollection = sdkerrors.Register(ModuleName, 9, "invalid nft collection") + ErrUnknownCollection = sdkerrors.Register(ModuleName, 10, "unknown nft collection") + ErrInvalidNFT = sdkerrors.Register(ModuleName, 11, "invalid nft") + ErrNFTAlreadyExists = sdkerrors.Register(ModuleName, 12, "nft already exists") + ErrUnknownNFT = sdkerrors.Register(ModuleName, 13, "unknown nft") + ErrEmptyTokenData = sdkerrors.Register(ModuleName, 14, "nft data can't be empty") + ErrUnauthorized = sdkerrors.Register(ModuleName, 15, "unauthorized address") + ErrInvalidDenom = sdkerrors.Register(ModuleName, 16, "invalid denom") + ErrInvalidTokenID = sdkerrors.Register(ModuleName, 17, "invalid nft id") + ErrInvalidTokenURI = sdkerrors.Register(ModuleName, 18, "invalid nft uri") ) diff --git a/modules/nft/types/genesis.go b/modules/nft/types/genesis.go index 6e71b336..d24a46c8 100644 --- a/modules/nft/types/genesis.go +++ b/modules/nft/types/genesis.go @@ -11,6 +11,11 @@ func NewGenesisState(collections []Collection) *GenesisState { } } +// DefaultGenesisState returns a default genesis state +func DefaultGenesisState() *GenesisState { + return NewGenesisState([]Collection{}) +} + // ValidateGenesis performs basic validation of nfts genesis data returning an // error for any failed validation criteria. func ValidateGenesis(data GenesisState) error { diff --git a/modules/nft/types/keys.go b/modules/nft/types/keys.go index 6af3b975..d1b6fcda 100644 --- a/modules/nft/types/keys.go +++ b/modules/nft/types/keys.go @@ -1,16 +1,8 @@ package types -import ( - "bytes" - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - const ( // ModuleName is the name of the module - // TODO - ModuleName = "inft" + ModuleName = "nft" // StoreKey is the default store key for NFT StoreKey = ModuleName @@ -21,89 +13,3 @@ const ( // RouterKey is the message route for the NFT module RouterKey = ModuleName ) - -var ( - PrefixNFT = []byte{0x01} - PrefixOwners = []byte{0x02} // key for a owner - PrefixCollection = []byte{0x03} // key for balance of NFTs held by the denom - PrefixDenom = []byte{0x04} // key for denom of the nft - PrefixDenomName = []byte{0x05} // key for denom name of the nft - - delimiter = []byte("/") -) - -// SplitKeyOwner return the address,denom,id from the key of stored owner -func SplitKeyOwner(key []byte) (address sdk.AccAddress, denomID, tokenID string, err error) { - key = key[len(PrefixOwners)+len(delimiter):] - keys := bytes.Split(key, delimiter) - if len(keys) != 3 { - return address, denomID, tokenID, errors.New("wrong KeyBalance") - } - - address, _ = sdk.AccAddressFromBech32(string(keys[0])) - denomID = string(keys[1]) - tokenID = string(keys[2]) - return -} - -func SplitKeyDenom(key []byte) (denomID, tokenID string, err error) { - keys := bytes.Split(key, delimiter) - if len(keys) != 2 { - return denomID, tokenID, errors.New("wrong KeyBalance") - } - - denomID = string(keys[0]) - tokenID = string(keys[1]) - return -} - -// KeyBalance gets the key of a collection owned by an account address -func KeyOwner(address sdk.AccAddress, denomID, tokenID string) []byte { - key := append(PrefixOwners, delimiter...) - if address != nil { - key = append(key, []byte(address.String())...) - key = append(key, delimiter...) - } - - if address != nil && len(denomID) > 0 { - key = append(key, []byte(denomID)...) - key = append(key, delimiter...) - } - - if address != nil && len(denomID) > 0 && len(tokenID) > 0 { - key = append(key, []byte(tokenID)...) - } - return key -} - -// KeyNFT gets the key of nft stored by an denom and id -func KeyNFT(denomID, tokenID string) []byte { - key := append(PrefixNFT, delimiter...) - if len(denomID) > 0 { - key = append(key, []byte(denomID)...) - key = append(key, delimiter...) - } - - if len(denomID) > 0 && len(tokenID) > 0 { - key = append(key, []byte(tokenID)...) - } - return key -} - -// KeyCollection gets the storeKey by the collection -func KeyCollection(denomID string) []byte { - key := append(PrefixCollection, delimiter...) - return append(key, []byte(denomID)...) -} - -// KeyDenom gets the storeKey by the denom id -func KeyDenomID(id string) []byte { - key := append(PrefixDenom, delimiter...) - return append(key, []byte(id)...) -} - -// KeyDenomName gets the storeKey by the denom name -func KeyDenomName(name string) []byte { - key := append(PrefixDenomName, delimiter...) - return append(key, []byte(name)...) -} diff --git a/modules/nft/types/nft.go b/modules/nft/types/nft.go index 17aa88c6..bf5457eb 100644 --- a/modules/nft/types/nft.go +++ b/modules/nft/types/nft.go @@ -56,11 +56,3 @@ func (bnft BaseNFT) GetData() string { // NFTs define a list of NFT type NFTs []exported.NFT - -// NewNFTs creates a new set of NFTs -func NewNFTs(nfts ...exported.NFT) NFTs { - if len(nfts) == 0 { - return NFTs{} - } - return NFTs(nfts) -} diff --git a/modules/nft/types/nft.pb.go b/modules/nft/types/nft.pb.go index 50e22c75..db8953af 100644 --- a/modules/nft/types/nft.pb.go +++ b/modules/nft/types/nft.pb.go @@ -66,6 +66,44 @@ func (m *BaseNFT) XXX_DiscardUnknown() { var xxx_messageInfo_BaseNFT proto.InternalMessageInfo +type NFTMetadata struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Data string `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *NFTMetadata) Reset() { *m = NFTMetadata{} } +func (m *NFTMetadata) String() string { return proto.CompactTextString(m) } +func (*NFTMetadata) ProtoMessage() {} +func (*NFTMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_fe8ab7e15b7f0646, []int{1} +} +func (m *NFTMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NFTMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NFTMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NFTMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_NFTMetadata.Merge(m, src) +} +func (m *NFTMetadata) XXX_Size() int { + return m.Size() +} +func (m *NFTMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_NFTMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_NFTMetadata proto.InternalMessageInfo + // Denom defines a type of NFT type Denom struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -85,7 +123,7 @@ func (m *Denom) Reset() { *m = Denom{} } func (m *Denom) String() string { return proto.CompactTextString(m) } func (*Denom) ProtoMessage() {} func (*Denom) Descriptor() ([]byte, []int) { - return fileDescriptor_fe8ab7e15b7f0646, []int{1} + return fileDescriptor_fe8ab7e15b7f0646, []int{2} } func (m *Denom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -114,6 +152,47 @@ func (m *Denom) XXX_DiscardUnknown() { var xxx_messageInfo_Denom proto.InternalMessageInfo +type DenomMetadata struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Schema string `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + MintRestricted bool `protobuf:"varint,3,opt,name=mint_restricted,json=mintRestricted,proto3" json:"mint_restricted,omitempty"` + UpdateRestricted bool `protobuf:"varint,4,opt,name=update_restricted,json=updateRestricted,proto3" json:"update_restricted,omitempty"` + Data string `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *DenomMetadata) Reset() { *m = DenomMetadata{} } +func (m *DenomMetadata) String() string { return proto.CompactTextString(m) } +func (*DenomMetadata) ProtoMessage() {} +func (*DenomMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_fe8ab7e15b7f0646, []int{3} +} +func (m *DenomMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DenomMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DenomMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DenomMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_DenomMetadata.Merge(m, src) +} +func (m *DenomMetadata) XXX_Size() int { + return m.Size() +} +func (m *DenomMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_DenomMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_DenomMetadata proto.InternalMessageInfo + // IDCollection defines a type of collection with specified ID type IDCollection struct { DenomId string `protobuf:"bytes,1,opt,name=denom_id,json=denomId,proto3" json:"denom_id,omitempty" yaml:"denom_id"` @@ -124,7 +203,7 @@ func (m *IDCollection) Reset() { *m = IDCollection{} } func (m *IDCollection) String() string { return proto.CompactTextString(m) } func (*IDCollection) ProtoMessage() {} func (*IDCollection) Descriptor() ([]byte, []int) { - return fileDescriptor_fe8ab7e15b7f0646, []int{2} + return fileDescriptor_fe8ab7e15b7f0646, []int{4} } func (m *IDCollection) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -163,7 +242,7 @@ func (m *Owner) Reset() { *m = Owner{} } func (m *Owner) String() string { return proto.CompactTextString(m) } func (*Owner) ProtoMessage() {} func (*Owner) Descriptor() ([]byte, []int) { - return fileDescriptor_fe8ab7e15b7f0646, []int{3} + return fileDescriptor_fe8ab7e15b7f0646, []int{5} } func (m *Owner) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -202,7 +281,7 @@ func (m *Collection) Reset() { *m = Collection{} } func (m *Collection) String() string { return proto.CompactTextString(m) } func (*Collection) ProtoMessage() {} func (*Collection) Descriptor() ([]byte, []int) { - return fileDescriptor_fe8ab7e15b7f0646, []int{4} + return fileDescriptor_fe8ab7e15b7f0646, []int{6} } func (m *Collection) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -233,7 +312,9 @@ var xxx_messageInfo_Collection proto.InternalMessageInfo func init() { proto.RegisterType((*BaseNFT)(nil), "irismod.nft.BaseNFT") + proto.RegisterType((*NFTMetadata)(nil), "irismod.nft.NFTMetadata") proto.RegisterType((*Denom)(nil), "irismod.nft.Denom") + proto.RegisterType((*DenomMetadata)(nil), "irismod.nft.DenomMetadata") proto.RegisterType((*IDCollection)(nil), "irismod.nft.IDCollection") proto.RegisterType((*Owner)(nil), "irismod.nft.Owner") proto.RegisterType((*Collection)(nil), "irismod.nft.Collection") @@ -242,43 +323,47 @@ func init() { func init() { proto.RegisterFile("nft/nft.proto", fileDescriptor_fe8ab7e15b7f0646) } var fileDescriptor_fe8ab7e15b7f0646 = []byte{ - // 576 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xbd, 0x8e, 0xd3, 0x4c, - 0x14, 0x8d, 0x13, 0x67, 0x9d, 0x5c, 0xef, 0xdf, 0x37, 0x5f, 0x84, 0x1c, 0x0a, 0x3b, 0xb2, 0x90, - 0x58, 0x09, 0x64, 0x8b, 0x45, 0xa2, 0xd8, 0xd2, 0xac, 0x56, 0x84, 0x62, 0x91, 0xac, 0xa5, 0xa1, - 0x89, 0x1c, 0xcf, 0x24, 0x19, 0x11, 0x7b, 0xa2, 0x99, 0xb1, 0x56, 0xe1, 0x25, 0x40, 0xe2, 0x05, - 0x78, 0x08, 0x1e, 0x22, 0xe5, 0x96, 0x54, 0x16, 0x24, 0x0d, 0x75, 0x9e, 0x00, 0x79, 0xec, 0x04, - 0xa7, 0xa3, 0xbb, 0xf7, 0xdc, 0xe3, 0x39, 0xc7, 0x67, 0xe6, 0xc2, 0x49, 0x3a, 0x91, 0x7e, 0x3a, - 0x91, 0xde, 0x82, 0x33, 0xc9, 0x90, 0x49, 0x39, 0x15, 0x09, 0xc3, 0x5e, 0x3a, 0x91, 0x8f, 0x7b, - 0x53, 0x36, 0x65, 0x0a, 0xf7, 0x8b, 0xaa, 0xa4, 0xb8, 0x5f, 0x35, 0x30, 0x82, 0x48, 0x90, 0xdb, - 0x9b, 0x3b, 0x74, 0x0a, 0x4d, 0x8a, 0x2d, 0x6d, 0xa0, 0x5d, 0x74, 0xc3, 0x26, 0xc5, 0x08, 0x81, - 0x9e, 0x46, 0x09, 0xb1, 0x9a, 0x0a, 0x51, 0x35, 0xea, 0x43, 0x2b, 0xe3, 0xd4, 0x6a, 0x15, 0x50, - 0x60, 0xac, 0x73, 0xa7, 0xf5, 0x3e, 0x1c, 0x86, 0x05, 0x56, 0xd0, 0x71, 0x24, 0x23, 0x4b, 0x2f, - 0xe9, 0x45, 0x8d, 0x7a, 0xd0, 0x66, 0xf7, 0x29, 0xe1, 0x56, 0x5b, 0x81, 0x65, 0x83, 0xfa, 0xd0, - 0xc9, 0x38, 0x1d, 0xcd, 0x22, 0x31, 0xb3, 0x8e, 0xd4, 0xc0, 0xc8, 0x38, 0x7d, 0x13, 0x89, 0xd9, - 0x95, 0xfe, 0xfb, 0x9b, 0xa3, 0xb9, 0xdf, 0x9b, 0xd0, 0xbe, 0x26, 0x29, 0x4b, 0xfe, 0xc9, 0xd3, - 0x23, 0x38, 0x12, 0xf1, 0x8c, 0x24, 0x51, 0x69, 0x2b, 0xac, 0x3a, 0x64, 0x81, 0x11, 0x73, 0x12, - 0x49, 0xc6, 0x2b, 0x4f, 0xbb, 0x56, 0x7d, 0xb1, 0x4c, 0xc6, 0x6c, 0x5e, 0xf9, 0xaa, 0x3a, 0xf4, - 0x14, 0xce, 0x12, 0x9a, 0xca, 0x11, 0x27, 0x42, 0x72, 0x1a, 0x4b, 0x82, 0x95, 0xbf, 0x4e, 0x78, - 0x5a, 0xc0, 0xe1, 0x1e, 0x45, 0xcf, 0xe0, 0xbf, 0x6c, 0x81, 0x23, 0x49, 0xea, 0x54, 0x43, 0x51, - 0xcf, 0xcb, 0x41, 0x8d, 0x3c, 0x00, 0x13, 0x13, 0x11, 0x73, 0xba, 0x90, 0x94, 0xa5, 0x56, 0x47, - 0x49, 0xd6, 0x21, 0x74, 0x5e, 0xa6, 0xda, 0x55, 0x13, 0x15, 0x66, 0x3d, 0x22, 0x38, 0x88, 0x68, - 0x9f, 0xb3, 0xf9, 0x37, 0xe7, 0x2a, 0xb6, 0x7b, 0x38, 0x1e, 0x5e, 0xbf, 0x66, 0xf3, 0x39, 0x89, - 0xd5, 0xb1, 0x1e, 0x74, 0x70, 0x91, 0xe2, 0x68, 0x17, 0x61, 0xf0, 0xff, 0x36, 0x77, 0xce, 0x96, - 0x51, 0x32, 0xbf, 0x72, 0x77, 0x13, 0x37, 0x34, 0x54, 0x39, 0xc4, 0xe8, 0x05, 0x74, 0x25, 0xfb, - 0x48, 0xd2, 0x11, 0xc5, 0xc2, 0x6a, 0x0e, 0x5a, 0x17, 0xdd, 0xa0, 0xb7, 0xcd, 0x9d, 0xf3, 0xf2, - 0x83, 0xfd, 0xc8, 0x0d, 0x3b, 0xaa, 0x1e, 0x62, 0x51, 0x09, 0x7f, 0xd6, 0xa0, 0xfd, 0x4e, 0x5d, - 0xad, 0x05, 0x46, 0x84, 0x31, 0x27, 0x42, 0x54, 0x97, 0xb6, 0x6b, 0xd1, 0x04, 0x4e, 0x29, 0x1e, - 0xc5, 0x7b, 0x77, 0xa5, 0x82, 0x79, 0xd9, 0xf7, 0x6a, 0xaf, 0xd4, 0xab, 0xfb, 0x0f, 0x9e, 0xac, - 0x72, 0xa7, 0xb1, 0xce, 0x9d, 0x93, 0x3a, 0x2a, 0xb6, 0xb9, 0x63, 0x96, 0x8e, 0x28, 0x8e, 0x85, - 0x1b, 0x9e, 0x50, 0x5c, 0x9b, 0x56, 0x8e, 0x3e, 0x01, 0x1c, 0x04, 0xd1, 0x56, 0xff, 0xa8, 0x3c, - 0x99, 0x97, 0xe8, 0x40, 0x52, 0x3d, 0xb4, 0x40, 0x2f, 0xb4, 0xc2, 0x92, 0x86, 0x5e, 0x81, 0x9e, - 0x4e, 0xe4, 0xce, 0x61, 0xef, 0x80, 0x5e, 0x6d, 0x4b, 0x70, 0x5c, 0x99, 0xd3, 0x6f, 0x6f, 0xee, - 0x44, 0xa8, 0xf8, 0xa5, 0x76, 0xf0, 0x76, 0xf5, 0xcb, 0x6e, 0xac, 0xd6, 0xb6, 0xf6, 0xb0, 0xb6, - 0xb5, 0x9f, 0x6b, 0x5b, 0xfb, 0xb2, 0xb1, 0x1b, 0x0f, 0x1b, 0xbb, 0xf1, 0x63, 0x63, 0x37, 0x3e, - 0x3c, 0x9f, 0x52, 0x39, 0xcb, 0xc6, 0x5e, 0xcc, 0x12, 0xbf, 0x38, 0x37, 0x25, 0xd2, 0xaf, 0xce, - 0xf7, 0x13, 0x86, 0xb3, 0x39, 0x11, 0xc5, 0x0a, 0xfb, 0x72, 0xb9, 0x20, 0x62, 0x7c, 0xa4, 0xd6, - 0xf4, 0xe5, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x64, 0x01, 0xda, 0xf2, 0xda, 0x03, 0x00, 0x00, + // 635 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xc1, 0x6e, 0xd3, 0x4c, + 0x10, 0x8e, 0x1d, 0xa7, 0x4e, 0xc6, 0x4d, 0xdb, 0x7f, 0xff, 0x08, 0xb9, 0x1c, 0xec, 0x2a, 0x42, + 0xa2, 0x12, 0x28, 0x11, 0x45, 0xe2, 0x50, 0x6e, 0xa6, 0xaa, 0x08, 0x12, 0x45, 0xb2, 0xca, 0x85, + 0x4b, 0xb4, 0xf5, 0x6e, 0x9a, 0x15, 0xb1, 0x37, 0xda, 0xdd, 0xa8, 0x2a, 0x2f, 0x01, 0x12, 0x2f, + 0xc0, 0x2b, 0x20, 0xf1, 0x10, 0x3d, 0xf6, 0xc8, 0x29, 0x82, 0xf4, 0xc2, 0xb9, 0x4f, 0x80, 0xbc, + 0x6b, 0x07, 0x47, 0x01, 0xa9, 0xb7, 0x99, 0x6f, 0xbe, 0xdd, 0xf9, 0xe6, 0x1b, 0x7b, 0xa1, 0x9d, + 0x8d, 0x54, 0x3f, 0x1b, 0xa9, 0xde, 0x54, 0x70, 0xc5, 0x91, 0xc7, 0x04, 0x93, 0x29, 0x27, 0xbd, + 0x6c, 0xa4, 0xee, 0x77, 0xce, 0xf9, 0x39, 0xd7, 0x78, 0x3f, 0x8f, 0x0c, 0xa5, 0xfb, 0xd9, 0x02, + 0x37, 0xc2, 0x92, 0x9e, 0x1c, 0x9f, 0xa2, 0x2d, 0xb0, 0x19, 0xf1, 0xad, 0x3d, 0x6b, 0xbf, 0x15, + 0xdb, 0x8c, 0x20, 0x04, 0x4e, 0x86, 0x53, 0xea, 0xdb, 0x1a, 0xd1, 0x31, 0xda, 0x85, 0xfa, 0x4c, + 0x30, 0xbf, 0x9e, 0x43, 0x91, 0xbb, 0x98, 0x87, 0xf5, 0xb7, 0xf1, 0x20, 0xce, 0xb1, 0x9c, 0x4e, + 0xb0, 0xc2, 0xbe, 0x63, 0xe8, 0x79, 0x8c, 0x3a, 0xd0, 0xe0, 0x17, 0x19, 0x15, 0x7e, 0x43, 0x83, + 0x26, 0x41, 0xbb, 0xd0, 0x9c, 0x09, 0x36, 0x1c, 0x63, 0x39, 0xf6, 0x37, 0x74, 0xc1, 0x9d, 0x09, + 0xf6, 0x12, 0xcb, 0xf1, 0xa1, 0xf3, 0xeb, 0x4b, 0x68, 0x75, 0x9f, 0x83, 0x77, 0x72, 0x7c, 0xfa, + 0x9a, 0x2a, 0xac, 0x6f, 0x29, 0x85, 0x58, 0x15, 0x21, 0x65, 0x37, 0xfb, 0x4f, 0xb7, 0xe2, 0xf0, + 0x37, 0x1b, 0x1a, 0x47, 0x34, 0xe3, 0xe9, 0x9d, 0x06, 0xba, 0x07, 0x1b, 0x32, 0x19, 0xd3, 0x14, + 0x9b, 0x99, 0xe2, 0x22, 0x43, 0x3e, 0xb8, 0x89, 0xa0, 0x58, 0x71, 0x51, 0x0c, 0x54, 0xa6, 0xfa, + 0xc4, 0x65, 0x7a, 0xc6, 0x27, 0xc5, 0x50, 0x45, 0x86, 0x1e, 0xc2, 0x76, 0xca, 0x32, 0x35, 0x14, + 0x54, 0x2a, 0xc1, 0x12, 0x45, 0x89, 0x1e, 0xae, 0x19, 0x6f, 0xe5, 0x70, 0xbc, 0x44, 0xd1, 0x23, + 0xf8, 0x6f, 0x36, 0x25, 0x58, 0xd1, 0x2a, 0xd5, 0xd5, 0xd4, 0x1d, 0x53, 0xa8, 0x90, 0xf7, 0xc0, + 0x23, 0x54, 0x26, 0x82, 0x4d, 0x15, 0xe3, 0x99, 0xdf, 0xd4, 0x2d, 0xab, 0x10, 0xda, 0x31, 0x2b, + 0x69, 0xe9, 0x8a, 0xde, 0x44, 0xd5, 0x5f, 0x58, 0xf1, 0x77, 0x69, 0x9b, 0xb7, 0x66, 0xdb, 0x57, + 0x0b, 0xda, 0xda, 0xb6, 0xa5, 0xed, 0x15, 0x0b, 0xac, 0x75, 0x0b, 0x8c, 0x69, 0xf6, 0x8a, 0x69, + 0x7f, 0xb1, 0xa0, 0x7e, 0x77, 0x0b, 0x9c, 0x7f, 0x58, 0x50, 0x6a, 0x6e, 0xac, 0x69, 0xbe, 0x80, + 0xcd, 0xc1, 0xd1, 0x0b, 0x3e, 0x99, 0xd0, 0x44, 0x5b, 0xd1, 0x83, 0x26, 0xc9, 0x47, 0x18, 0x96, + 0x6b, 0x8f, 0xfe, 0xbf, 0x9d, 0x87, 0xdb, 0x97, 0x38, 0x9d, 0x1c, 0x76, 0xcb, 0x4a, 0x37, 0x76, + 0x75, 0x38, 0x20, 0xe8, 0x09, 0xb4, 0x14, 0x7f, 0x4f, 0xb3, 0x21, 0x23, 0xd2, 0xb7, 0xf7, 0xea, + 0xfb, 0xad, 0xa8, 0x73, 0x3b, 0x0f, 0x77, 0xcc, 0x81, 0x65, 0xa9, 0x1b, 0x37, 0x75, 0x3c, 0x20, + 0xb2, 0x68, 0xfc, 0xd1, 0x82, 0xc6, 0x1b, 0xfd, 0x2d, 0xfb, 0xe0, 0x62, 0x42, 0x04, 0x95, 0xb2, + 0x34, 0xa9, 0x48, 0xd1, 0x08, 0xb6, 0x18, 0x19, 0x26, 0x4b, 0x75, 0xa6, 0x83, 0x77, 0xb0, 0xdb, + 0xab, 0xfc, 0x96, 0xbd, 0xaa, 0xfe, 0xe8, 0xc1, 0xd5, 0x3c, 0xac, 0x2d, 0xe6, 0x61, 0xbb, 0x8a, + 0xca, 0xdb, 0x79, 0xe8, 0x19, 0x45, 0x8c, 0x24, 0xb2, 0x1b, 0xb7, 0x19, 0xa9, 0x54, 0x0b, 0x45, + 0x1f, 0x00, 0x56, 0x8c, 0x68, 0xe8, 0x19, 0xb5, 0x26, 0xef, 0x00, 0xad, 0xb4, 0xd4, 0x5b, 0x8e, + 0x9c, 0xbc, 0x57, 0x6c, 0x68, 0xe8, 0x19, 0x38, 0xd9, 0x48, 0x95, 0x0a, 0x3b, 0x2b, 0xf4, 0xe2, + 0x79, 0x88, 0x36, 0x0b, 0x71, 0xce, 0xc9, 0xf1, 0xa9, 0x8c, 0x35, 0xdf, 0xf4, 0x8e, 0x5e, 0x5d, + 0xfd, 0x0c, 0x6a, 0x57, 0x8b, 0xc0, 0xba, 0x5e, 0x04, 0xd6, 0x8f, 0x45, 0x60, 0x7d, 0xba, 0x09, + 0x6a, 0xd7, 0x37, 0x41, 0xed, 0xfb, 0x4d, 0x50, 0x7b, 0xf7, 0xf8, 0x9c, 0xa9, 0xf1, 0xec, 0xac, + 0x97, 0xf0, 0xb4, 0x9f, 0xdf, 0x9b, 0x51, 0xd5, 0x2f, 0xee, 0xef, 0xa7, 0x9c, 0xcc, 0x26, 0x54, + 0xe6, 0x6f, 0x56, 0x5f, 0x5d, 0x4e, 0xa9, 0x3c, 0xdb, 0xd0, 0xef, 0xd2, 0xd3, 0xdf, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x4a, 0x49, 0x33, 0x49, 0xcb, 0x04, 0x00, 0x00, } func (this *BaseNFT) Equal(that interface{}) bool { @@ -320,6 +405,33 @@ func (this *BaseNFT) Equal(that interface{}) bool { } return true } +func (this *NFTMetadata) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*NFTMetadata) + if !ok { + that2, ok := that.(NFTMetadata) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Name != that1.Name { + return false + } + if this.Data != that1.Data { + return false + } + return true +} func (this *Denom) Equal(that interface{}) bool { if that == nil { return this == nil @@ -374,6 +486,42 @@ func (this *Denom) Equal(that interface{}) bool { } return true } +func (this *DenomMetadata) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DenomMetadata) + if !ok { + that2, ok := that.(DenomMetadata) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Creator != that1.Creator { + return false + } + if this.Schema != that1.Schema { + return false + } + if this.MintRestricted != that1.MintRestricted { + return false + } + if this.UpdateRestricted != that1.UpdateRestricted { + return false + } + if this.Data != that1.Data { + return false + } + return true +} func (this *IDCollection) Equal(that interface{}) bool { if that == nil { return this == nil @@ -535,6 +683,43 @@ func (m *BaseNFT) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *NFTMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NFTMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NFTMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintNft(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintNft(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Denom) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -641,6 +826,70 @@ func (m *Denom) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *DenomMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DenomMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DenomMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintNft(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x2a + } + if m.UpdateRestricted { + i-- + if m.UpdateRestricted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.MintRestricted { + i-- + if m.MintRestricted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.Schema) > 0 { + i -= len(m.Schema) + copy(dAtA[i:], m.Schema) + i = encodeVarintNft(dAtA, i, uint64(len(m.Schema))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintNft(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *IDCollection) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -815,6 +1064,23 @@ func (m *BaseNFT) Size() (n int) { return n } +func (m *NFTMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovNft(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovNft(uint64(l)) + } + return n +} + func (m *Denom) Size() (n int) { if m == nil { return 0 @@ -866,6 +1132,33 @@ func (m *Denom) Size() (n int) { return n } +func (m *DenomMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovNft(uint64(l)) + } + l = len(m.Schema) + if l > 0 { + n += 1 + l + sovNft(uint64(l)) + } + if m.MintRestricted { + n += 2 + } + if m.UpdateRestricted { + n += 2 + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovNft(uint64(l)) + } + return n +} + func (m *IDCollection) Size() (n int) { if m == nil { return 0 @@ -1169,7 +1462,7 @@ func (m *BaseNFT) Unmarshal(dAtA []byte) error { } return nil } -func (m *Denom) Unmarshal(dAtA []byte) error { +func (m *NFTMetadata) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1192,15 +1485,15 @@ func (m *Denom) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Denom: wiretype end group for non-group") + return fmt.Errorf("proto: NFTMetadata: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Denom: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: NFTMetadata: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1228,11 +1521,11 @@ func (m *Denom) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Id = string(dAtA[iNdEx:postIndex]) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1260,11 +1553,125 @@ func (m *Denom) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) + m.Data = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Schema", wireType) + default: + iNdEx = preIndex + skippy, err := skipNft(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNft + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Denom) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Denom: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Denom: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNft + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNft + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNft + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNft + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Schema", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1547,6 +1954,192 @@ func (m *Denom) Unmarshal(dAtA []byte) error { } return nil } +func (m *DenomMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DenomMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DenomMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNft + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNft + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Schema", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNft + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNft + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Schema = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MintRestricted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MintRestricted = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdateRestricted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UpdateRestricted = bool(v != 0) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNft + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNft + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNft + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNft(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNft + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *IDCollection) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/nft/types/owners.go b/modules/nft/types/owners.go deleted file mode 100644 index c8099a5d..00000000 --- a/modules/nft/types/owners.go +++ /dev/null @@ -1,93 +0,0 @@ -package types - -import ( - "bytes" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// NewIDCollection creates a new IDCollection instance -func NewIDCollection(denomID string, tokenIDs []string) IDCollection { - return IDCollection{ - DenomId: denomID, - TokenIds: tokenIDs, - } -} - -// Supply return the amount of the denom -func (idc IDCollection) Supply() int { - return len(idc.TokenIds) -} - -// AddID adds an tokenID to the idCollection -func (idc IDCollection) AddID(tokenID string) IDCollection { - idc.TokenIds = append(idc.TokenIds, tokenID) - return idc -} - -// ---------------------------------------------------------------------------- -// IDCollections is an array of ID Collections -type IDCollections []IDCollection - -// Add adds an ID to the idCollection -func (idcs IDCollections) Add(denomID, tokenID string) IDCollections { - for i, idc := range idcs { - if idc.DenomId == denomID { - idcs[i] = idc.AddID(tokenID) - return idcs - } - } - return append(idcs, IDCollection{ - DenomId: denomID, - TokenIds: []string{tokenID}, - }) -} - -// String follows stringer interface -func (idcs IDCollections) String() string { - if len(idcs) == 0 { - return "" - } - - var buf bytes.Buffer - for _, idCollection := range idcs { - if buf.Len() > 0 { - buf.WriteString("\n") - } - buf.WriteString(idCollection.String()) - } - return buf.String() -} - -// Owner of non fungible tokens -//type Owner struct { -// Address sdk.AccAddress `json:"address" yaml:"address"` -// IDCollections IDCollections `json:"id_collections" yaml:"id_collections"` -//} - -// NewOwner creates a new Owner -func NewOwner(owner sdk.AccAddress, idCollections ...IDCollection) Owner { - return Owner{ - Address: owner.String(), - IDCollections: idCollections, - } -} - -type Owners []Owner - -// NewOwner creates a new Owner -func NewOwners(owner ...Owner) Owners { - return append([]Owner{}, owner...) -} - -// String follows stringer interface -func (owners Owners) String() string { - var buf bytes.Buffer - for _, owner := range owners { - if buf.Len() > 0 { - buf.WriteString("\n") - } - buf.WriteString(owner.String()) - } - return buf.String() -} diff --git a/modules/nft/types/querier.go b/modules/nft/types/querier.go deleted file mode 100644 index 1e55626c..00000000 --- a/modules/nft/types/querier.go +++ /dev/null @@ -1,88 +0,0 @@ -package types - -// DONTCOVER - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// query endpoints supported by the NFT Querier -const ( - QuerySupply = "supply" - QueryOwner = "owner" - QueryCollection = "collection" - QueryDenoms = "denoms" - QueryDenom = "denom" - QueryNFT = "nft" -) - -// QuerySupplyParams defines the params for queries: -type QuerySupplyParams struct { - Denom string - Owner sdk.AccAddress -} - -// NewQuerySupplyParams creates a new instance of QuerySupplyParams -func NewQuerySupplyParams(denom string, owner sdk.AccAddress) QuerySupplyParams { - return QuerySupplyParams{ - Denom: denom, - Owner: owner, - } -} - -// Bytes exports the Denom as bytes -func (q QuerySupplyParams) Bytes() []byte { - return []byte(q.Denom) -} - -// QueryOwnerParams defines the params for queries: -type QueryOwnerParams struct { - Denom string - Owner sdk.AccAddress -} - -// NewQuerySupplyParams creates a new instance of QuerySupplyParams -func NewQueryOwnerParams(denom string, owner sdk.AccAddress) QueryOwnerParams { - return QueryOwnerParams{ - Denom: denom, - Owner: owner, - } -} - -// QuerySupplyParams defines the params for queries: -type QueryCollectionParams struct { - Denom string -} - -// NewQueryCollectionParams creates a new instance of QueryCollectionParams -func NewQueryCollectionParams(denom string) QueryCollectionParams { - return QueryCollectionParams{ - Denom: denom, - } -} - -// QueryDenomParams defines the params for queries: -type QueryDenomParams struct { - ID string -} - -// NewQueryDenomParams creates a new instance of QueryDenomParams -func NewQueryDenomParams(id string) QueryDenomParams { - return QueryDenomParams{ - ID: id, - } -} - -// QueryNFTParams params for query 'custom/nfts/nft' -type QueryNFTParams struct { - Denom string - TokenID string -} - -// NewQueryNFTParams creates a new instance of QueryNFTParams -func NewQueryNFTParams(denom, id string) QueryNFTParams { - return QueryNFTParams{ - Denom: denom, - TokenID: id, - } -} diff --git a/modules/nft/types/query.pb.go b/modules/nft/types/query.pb.go index 1fa210a4..3c8f197f 100644 --- a/modules/nft/types/query.pb.go +++ b/modules/nft/types/query.pb.go @@ -128,26 +128,27 @@ func (m *QuerySupplyResponse) GetAmount() uint64 { return 0 } -// QueryOwnerRequest is the request type for the Query/Owner RPC method -type QueryOwnerRequest struct { +// QueryNFTsOfOwnerRequest is the request type for the Query/NFTsOfOwner RPC +// method +type QueryNFTsOfOwnerRequest struct { DenomId string `protobuf:"bytes,1,opt,name=denom_id,json=denomId,proto3" json:"denom_id,omitempty" yaml:"denom_id"` Owner string `protobuf:"bytes,2,opt,name=owner,proto3" json:"owner,omitempty" yaml:"owner"` // pagination defines an optional pagination for the request. Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` } -func (m *QueryOwnerRequest) Reset() { *m = QueryOwnerRequest{} } -func (m *QueryOwnerRequest) String() string { return proto.CompactTextString(m) } -func (*QueryOwnerRequest) ProtoMessage() {} -func (*QueryOwnerRequest) Descriptor() ([]byte, []int) { +func (m *QueryNFTsOfOwnerRequest) Reset() { *m = QueryNFTsOfOwnerRequest{} } +func (m *QueryNFTsOfOwnerRequest) String() string { return proto.CompactTextString(m) } +func (*QueryNFTsOfOwnerRequest) ProtoMessage() {} +func (*QueryNFTsOfOwnerRequest) Descriptor() ([]byte, []int) { return fileDescriptor_ce02d034d3adf2e9, []int{2} } -func (m *QueryOwnerRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryNFTsOfOwnerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryOwnerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryNFTsOfOwnerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryOwnerRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryNFTsOfOwnerRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -157,57 +158,58 @@ func (m *QueryOwnerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, e return b[:n], nil } } -func (m *QueryOwnerRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryOwnerRequest.Merge(m, src) +func (m *QueryNFTsOfOwnerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryNFTsOfOwnerRequest.Merge(m, src) } -func (m *QueryOwnerRequest) XXX_Size() int { +func (m *QueryNFTsOfOwnerRequest) XXX_Size() int { return m.Size() } -func (m *QueryOwnerRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryOwnerRequest.DiscardUnknown(m) +func (m *QueryNFTsOfOwnerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryNFTsOfOwnerRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryOwnerRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryNFTsOfOwnerRequest proto.InternalMessageInfo -func (m *QueryOwnerRequest) GetDenomId() string { +func (m *QueryNFTsOfOwnerRequest) GetDenomId() string { if m != nil { return m.DenomId } return "" } -func (m *QueryOwnerRequest) GetOwner() string { +func (m *QueryNFTsOfOwnerRequest) GetOwner() string { if m != nil { return m.Owner } return "" } -func (m *QueryOwnerRequest) GetPagination() *query.PageRequest { +func (m *QueryNFTsOfOwnerRequest) GetPagination() *query.PageRequest { if m != nil { return m.Pagination } return nil } -// QueryOwnerResponse is the response type for the Query/Owner RPC method -type QueryOwnerResponse struct { +// QueryNFTsOfOwnerResponse is the response type for the Query/NFTsOfOwner RPC +// method +type QueryNFTsOfOwnerResponse struct { Owner *Owner `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } -func (m *QueryOwnerResponse) Reset() { *m = QueryOwnerResponse{} } -func (m *QueryOwnerResponse) String() string { return proto.CompactTextString(m) } -func (*QueryOwnerResponse) ProtoMessage() {} -func (*QueryOwnerResponse) Descriptor() ([]byte, []int) { +func (m *QueryNFTsOfOwnerResponse) Reset() { *m = QueryNFTsOfOwnerResponse{} } +func (m *QueryNFTsOfOwnerResponse) String() string { return proto.CompactTextString(m) } +func (*QueryNFTsOfOwnerResponse) ProtoMessage() {} +func (*QueryNFTsOfOwnerResponse) Descriptor() ([]byte, []int) { return fileDescriptor_ce02d034d3adf2e9, []int{3} } -func (m *QueryOwnerResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryNFTsOfOwnerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryOwnerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryNFTsOfOwnerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryOwnerResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryNFTsOfOwnerResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -217,26 +219,26 @@ func (m *QueryOwnerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, return b[:n], nil } } -func (m *QueryOwnerResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryOwnerResponse.Merge(m, src) +func (m *QueryNFTsOfOwnerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryNFTsOfOwnerResponse.Merge(m, src) } -func (m *QueryOwnerResponse) XXX_Size() int { +func (m *QueryNFTsOfOwnerResponse) XXX_Size() int { return m.Size() } -func (m *QueryOwnerResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryOwnerResponse.DiscardUnknown(m) +func (m *QueryNFTsOfOwnerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryNFTsOfOwnerResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryOwnerResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryNFTsOfOwnerResponse proto.InternalMessageInfo -func (m *QueryOwnerResponse) GetOwner() *Owner { +func (m *QueryNFTsOfOwnerResponse) GetOwner() *Owner { if m != nil { return m.Owner } return nil } -func (m *QueryOwnerResponse) GetPagination() *query.PageResponse { +func (m *QueryNFTsOfOwnerResponse) GetPagination() *query.PageResponse { if m != nil { return m.Pagination } @@ -642,8 +644,8 @@ func (m *QueryNFTResponse) GetNFT() *BaseNFT { func init() { proto.RegisterType((*QuerySupplyRequest)(nil), "irismod.nft.QuerySupplyRequest") proto.RegisterType((*QuerySupplyResponse)(nil), "irismod.nft.QuerySupplyResponse") - proto.RegisterType((*QueryOwnerRequest)(nil), "irismod.nft.QueryOwnerRequest") - proto.RegisterType((*QueryOwnerResponse)(nil), "irismod.nft.QueryOwnerResponse") + proto.RegisterType((*QueryNFTsOfOwnerRequest)(nil), "irismod.nft.QueryNFTsOfOwnerRequest") + proto.RegisterType((*QueryNFTsOfOwnerResponse)(nil), "irismod.nft.QueryNFTsOfOwnerResponse") proto.RegisterType((*QueryCollectionRequest)(nil), "irismod.nft.QueryCollectionRequest") proto.RegisterType((*QueryCollectionResponse)(nil), "irismod.nft.QueryCollectionResponse") proto.RegisterType((*QueryDenomRequest)(nil), "irismod.nft.QueryDenomRequest") @@ -657,55 +659,56 @@ func init() { func init() { proto.RegisterFile("nft/query.proto", fileDescriptor_ce02d034d3adf2e9) } var fileDescriptor_ce02d034d3adf2e9 = []byte{ - // 768 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x41, 0x4f, 0x13, 0x41, - 0x18, 0xed, 0xb4, 0xb4, 0xe0, 0xa0, 0x01, 0xa6, 0x08, 0xb5, 0xe2, 0xb6, 0x59, 0x14, 0x10, 0x71, - 0x57, 0xf0, 0x60, 0xe2, 0xc1, 0x43, 0x31, 0x35, 0x5c, 0x50, 0x2b, 0x27, 0x62, 0x62, 0xb6, 0xed, - 0x74, 0xd9, 0xd8, 0x9d, 0x59, 0x3a, 0x53, 0x4d, 0x43, 0x88, 0x89, 0x31, 0xf1, 0x4a, 0xe2, 0xd1, - 0x9f, 0xe1, 0x6f, 0x30, 0xe1, 0x48, 0xe2, 0xc5, 0x53, 0x63, 0x8a, 0xbf, 0x80, 0x5f, 0x60, 0x76, - 0x66, 0x96, 0xee, 0xba, 0x2d, 0x9a, 0x86, 0xdb, 0xee, 0xce, 0x9b, 0xf7, 0xde, 0xbc, 0xef, 0xfb, - 0x26, 0x0b, 0xa7, 0x48, 0x83, 0x9b, 0xfb, 0x6d, 0xdc, 0xea, 0x18, 0x5e, 0x8b, 0x72, 0x8a, 0x26, - 0x9d, 0x96, 0xc3, 0x5c, 0x5a, 0x37, 0x48, 0x83, 0xe7, 0x67, 0x6d, 0x6a, 0x53, 0xf1, 0xdd, 0xf4, - 0x9f, 0x24, 0x24, 0xbf, 0x60, 0x53, 0x6a, 0x37, 0xb1, 0x69, 0x79, 0x8e, 0x69, 0x11, 0x42, 0xb9, - 0xc5, 0x1d, 0x4a, 0x98, 0x5a, 0xbd, 0xe6, 0x33, 0x92, 0x06, 0x57, 0xaf, 0xab, 0x35, 0xca, 0x5c, - 0xca, 0xcc, 0xaa, 0xc5, 0xb0, 0x14, 0x32, 0xdf, 0xad, 0x57, 0x31, 0xb7, 0xd6, 0x4d, 0xcf, 0xb2, - 0x1d, 0x22, 0xf6, 0x4a, 0xac, 0xbe, 0x0b, 0xd1, 0x4b, 0x1f, 0xf1, 0xaa, 0xed, 0x79, 0xcd, 0x4e, - 0x05, 0xef, 0xb7, 0x31, 0xe3, 0xc8, 0x80, 0x13, 0x75, 0x4c, 0xa8, 0xfb, 0xc6, 0xa9, 0xe7, 0x40, - 0x11, 0xac, 0x5c, 0x29, 0x65, 0xcf, 0xba, 0x85, 0xa9, 0x8e, 0xe5, 0x36, 0x1f, 0xeb, 0xc1, 0x8a, - 0x5e, 0x19, 0x17, 0x8f, 0x5b, 0x75, 0x34, 0x0b, 0xd3, 0xf4, 0x3d, 0xc1, 0xad, 0x5c, 0xd2, 0x07, - 0x57, 0xe4, 0x8b, 0x7e, 0x1f, 0x66, 0x23, 0xdc, 0xcc, 0xa3, 0x84, 0x61, 0x34, 0x07, 0x33, 0x96, - 0x4b, 0xdb, 0x84, 0x0b, 0xea, 0xb1, 0x8a, 0x7a, 0xd3, 0xbf, 0x01, 0x38, 0x23, 0xf0, 0xcf, 0xfd, - 0xdd, 0xa3, 0x5a, 0x59, 0x8a, 0x58, 0x29, 0x4d, 0x9f, 0x75, 0x0b, 0x57, 0x25, 0x58, 0x9a, 0x52, - 0xe6, 0x50, 0x19, 0xc2, 0x7e, 0x18, 0xb9, 0x54, 0x11, 0xac, 0x4c, 0x6e, 0x2c, 0x19, 0x32, 0x39, - 0xc3, 0x4f, 0xce, 0x90, 0x25, 0x52, 0xc9, 0x19, 0x2f, 0x2c, 0x1b, 0x2b, 0x4f, 0x95, 0xd0, 0x4e, - 0xfd, 0x33, 0x50, 0x09, 0x2a, 0xd7, 0xea, 0x90, 0x2b, 0x81, 0x0d, 0x20, 0x98, 0x91, 0x11, 0xaa, - 0xb1, 0x21, 0xa1, 0xca, 0xc8, 0xb3, 0x88, 0x91, 0xa4, 0x80, 0x2f, 0xff, 0xd3, 0x88, 0x94, 0x89, - 0x38, 0x39, 0x02, 0x70, 0x4e, 0x38, 0xd9, 0xa4, 0xcd, 0x26, 0xae, 0xf9, 0xdf, 0x46, 0x0d, 0xb1, - 0x3c, 0xc0, 0xd3, 0x28, 0xe1, 0x7c, 0x05, 0x70, 0x3e, 0x66, 0x49, 0x25, 0xf4, 0x08, 0xc2, 0xda, - 0xf9, 0x57, 0x15, 0xd3, 0x7c, 0x24, 0xa6, 0xd0, 0xa6, 0x10, 0xf4, 0xf2, 0x02, 0xdb, 0x54, 0xfd, - 0xf6, 0xd4, 0x3f, 0xf5, 0x88, 0x51, 0xe9, 0x4f, 0x54, 0xf9, 0x15, 0x49, 0xbf, 0xfc, 0x02, 0x30, - 0xb0, 0xfc, 0x12, 0x2a, 0x01, 0xfa, 0xeb, 0xf0, 0x7e, 0x16, 0xb8, 0x88, 0x16, 0x00, 0x8c, 0x5c, - 0x80, 0x23, 0xa0, 0x66, 0x30, 0xa0, 0x57, 0xfe, 0x1e, 0xc0, 0x8c, 0x90, 0x67, 0x39, 0x50, 0x4c, - 0x0d, 0x36, 0x58, 0x1a, 0x3b, 0xee, 0x16, 0x12, 0x15, 0x85, 0xbb, 0xbc, 0xd4, 0xf7, 0xe1, 0x94, - 0x70, 0xb4, 0x5d, 0xde, 0x19, 0xb5, 0x3d, 0x0d, 0x38, 0xc1, 0xe9, 0x5b, 0x4c, 0x7c, 0x7c, 0xf2, - 0x6f, 0x7c, 0xb0, 0xa2, 0x57, 0xc6, 0xc5, 0xe3, 0x56, 0x5d, 0xdf, 0x84, 0xd3, 0x7d, 0x49, 0x95, - 0x80, 0x09, 0x53, 0xa4, 0xc1, 0x55, 0xb4, 0xb3, 0x91, 0xe3, 0x97, 0x2c, 0x86, 0xb7, 0xcb, 0x3b, - 0xa5, 0xf1, 0x5e, 0xb7, 0x90, 0xf2, 0xf7, 0xf8, 0xc8, 0x8d, 0xef, 0x69, 0x98, 0x16, 0x2c, 0xe8, - 0x03, 0xcc, 0xc8, 0x2b, 0x0d, 0x15, 0x22, 0xfb, 0xe2, 0x17, 0x69, 0xbe, 0x38, 0x1c, 0x20, 0x7d, - 0xe8, 0x1b, 0x1f, 0x7f, 0xfc, 0xfe, 0x92, 0x5c, 0x43, 0xab, 0xa6, 0x42, 0xfa, 0x17, 0xb9, 0xd9, - 0x6f, 0x77, 0x66, 0x1e, 0x04, 0x09, 0x1c, 0x9a, 0x4c, 0xca, 0xd6, 0x60, 0x5a, 0x5c, 0x21, 0x48, - 0x8b, 0xd3, 0x87, 0x2f, 0xcf, 0x7c, 0x61, 0xe8, 0xba, 0x52, 0xbf, 0x21, 0xd4, 0xb3, 0x68, 0x26, - 0xa2, 0x4e, 0x1a, 0x9c, 0xa1, 0x4f, 0x00, 0xc2, 0xfe, 0x04, 0xa2, 0xc5, 0x38, 0x55, 0xec, 0x9e, - 0xc9, 0xdf, 0xbe, 0x18, 0xa4, 0x44, 0xef, 0x09, 0xd1, 0x3b, 0x68, 0xf1, 0x3f, 0x8e, 0x8c, 0x3c, - 0x98, 0x16, 0xed, 0x38, 0xe8, 0xac, 0xe1, 0xc1, 0x1d, 0x74, 0xd6, 0xc8, 0x4c, 0xea, 0x4b, 0x42, - 0xb6, 0x88, 0xb4, 0x88, 0xac, 0x6c, 0xef, 0xb0, 0xe2, 0x1e, 0xcc, 0xc8, 0x69, 0x41, 0xc3, 0x28, - 0xd9, 0x05, 0xe5, 0x8d, 0x0e, 0x9a, 0x7e, 0x53, 0x88, 0x5e, 0x47, 0xd9, 0x01, 0xa2, 0x88, 0x41, - 0xbf, 0xbd, 0xd0, 0x42, 0x9c, 0xa5, 0x3f, 0x1c, 0xf9, 0x5b, 0x43, 0x56, 0x95, 0x80, 0x29, 0x04, - 0xee, 0xa2, 0xe5, 0x58, 0x05, 0xc3, 0x8d, 0x73, 0x10, 0x4c, 0xc5, 0x61, 0xa9, 0x7c, 0xdc, 0xd3, - 0xc0, 0x49, 0x4f, 0x03, 0xbf, 0x7a, 0x1a, 0x38, 0x3a, 0xd5, 0x12, 0x27, 0xa7, 0x5a, 0xe2, 0xe7, - 0xa9, 0x96, 0xd8, 0x5d, 0xb3, 0x1d, 0xbe, 0xd7, 0xae, 0x1a, 0x35, 0xea, 0x0a, 0x32, 0x82, 0xf9, - 0x39, 0xa9, 0x4b, 0xeb, 0xed, 0x26, 0x66, 0x82, 0x9c, 0x77, 0x3c, 0xcc, 0xaa, 0x19, 0xf1, 0x03, - 0xf1, 0xf0, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x19, 0x80, 0xb5, 0xe7, 0xcf, 0x08, 0x00, 0x00, + // 772 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x4f, 0x13, 0x41, + 0x1c, 0xed, 0xb4, 0xb4, 0xe0, 0xa0, 0x01, 0xa6, 0x08, 0xb5, 0xe2, 0xb6, 0x59, 0xfe, 0x8a, 0xb8, + 0x2b, 0x78, 0x30, 0xf1, 0xe0, 0xa1, 0x98, 0x1a, 0x2e, 0xa0, 0x95, 0x13, 0x31, 0x31, 0xdb, 0x76, + 0x5a, 0x1a, 0xbb, 0x33, 0x4b, 0x67, 0x56, 0xd3, 0x10, 0x62, 0x62, 0xbc, 0x9a, 0x90, 0x78, 0xf4, + 0x93, 0xf8, 0x0d, 0x38, 0x92, 0x78, 0xd0, 0x53, 0x63, 0x8a, 0x9f, 0x80, 0x4f, 0x60, 0x76, 0x66, + 0x96, 0xee, 0xba, 0x2d, 0x98, 0x86, 0xdb, 0xee, 0xce, 0x9b, 0xf7, 0xde, 0xbc, 0xdf, 0xfc, 0x7e, + 0x59, 0x38, 0x41, 0x6a, 0xdc, 0x3c, 0x70, 0x71, 0xab, 0x6d, 0x38, 0x2d, 0xca, 0x29, 0x1a, 0x6f, + 0xb4, 0x1a, 0xcc, 0xa6, 0x55, 0x83, 0xd4, 0x78, 0x76, 0xba, 0x4e, 0xeb, 0x54, 0x7c, 0x37, 0xbd, + 0x27, 0x09, 0xc9, 0xce, 0xd5, 0x29, 0xad, 0x37, 0xb1, 0x69, 0x39, 0x0d, 0xd3, 0x22, 0x84, 0x72, + 0x8b, 0x37, 0x28, 0x61, 0x6a, 0xf5, 0x96, 0xc7, 0x48, 0x6a, 0x5c, 0xbd, 0xae, 0x56, 0x28, 0xb3, + 0x29, 0x33, 0xcb, 0x16, 0xc3, 0x52, 0xc8, 0x7c, 0xbf, 0x5e, 0xc6, 0xdc, 0x5a, 0x37, 0x1d, 0xab, + 0xde, 0x20, 0x62, 0xaf, 0xc4, 0xea, 0x7b, 0x10, 0xbd, 0xf2, 0x10, 0xaf, 0x5d, 0xc7, 0x69, 0xb6, + 0x4b, 0xf8, 0xc0, 0xc5, 0x8c, 0x23, 0x03, 0x8e, 0x55, 0x31, 0xa1, 0xf6, 0xdb, 0x46, 0x35, 0x03, + 0xf2, 0x60, 0xe5, 0x46, 0x21, 0x7d, 0xde, 0xc9, 0x4d, 0xb4, 0x2d, 0xbb, 0xf9, 0x54, 0xf7, 0x57, + 0xf4, 0xd2, 0xa8, 0x78, 0xdc, 0xaa, 0xa2, 0x69, 0x98, 0xa4, 0x1f, 0x08, 0x6e, 0x65, 0xe2, 0x1e, + 0xb8, 0x24, 0x5f, 0xf4, 0x87, 0x30, 0x1d, 0xe2, 0x66, 0x0e, 0x25, 0x0c, 0xa3, 0x19, 0x98, 0xb2, + 0x6c, 0xea, 0x12, 0x2e, 0xa8, 0x47, 0x4a, 0xea, 0x4d, 0xff, 0x0e, 0xe0, 0xac, 0xc0, 0x6f, 0x17, + 0x77, 0xd9, 0x4e, 0x6d, 0xc7, 0xe3, 0x18, 0xd6, 0xd0, 0x52, 0xc8, 0x50, 0x61, 0xf2, 0xbc, 0x93, + 0xbb, 0x29, 0xc1, 0xd2, 0x9a, 0xb2, 0x88, 0x8a, 0x10, 0xf6, 0x22, 0xc9, 0x24, 0xf2, 0x60, 0x65, + 0x7c, 0x63, 0xc9, 0x90, 0xf9, 0x19, 0x5e, 0x7e, 0x86, 0x2c, 0x94, 0xca, 0xcf, 0x78, 0x69, 0xd5, + 0xb1, 0xf2, 0x54, 0x0a, 0xec, 0xd4, 0xbf, 0x00, 0x98, 0x89, 0x7a, 0x57, 0x07, 0x5e, 0xf1, 0xcd, + 0x00, 0xc1, 0x8f, 0x8c, 0x40, 0xbd, 0x0d, 0x09, 0x55, 0x76, 0x5e, 0x84, 0xec, 0xc4, 0x05, 0x7c, + 0xf9, 0x4a, 0x3b, 0x52, 0x26, 0xe4, 0xe7, 0x18, 0xc0, 0x19, 0xe1, 0x67, 0x93, 0x36, 0x9b, 0xb8, + 0xe2, 0x7d, 0x1b, 0x36, 0xca, 0x62, 0x1f, 0x4f, 0xc3, 0x44, 0xf4, 0xcd, 0x2f, 0x6f, 0xd0, 0x92, + 0x4a, 0xe8, 0x09, 0x84, 0x95, 0x8b, 0xaf, 0x2a, 0xa6, 0xd9, 0x50, 0x4c, 0x81, 0x4d, 0x01, 0xe8, + 0xf5, 0x05, 0xb6, 0x09, 0xa7, 0x84, 0xb9, 0xe7, 0xde, 0xa9, 0x87, 0x8c, 0x4a, 0x7f, 0xa6, 0x9a, + 0x49, 0x91, 0xf4, 0xca, 0x2f, 0x00, 0x7d, 0xcb, 0x2f, 0xa1, 0x12, 0xa0, 0xbf, 0x09, 0xee, 0x67, + 0xbe, 0x8b, 0x70, 0x01, 0xc0, 0xd0, 0x05, 0x38, 0x06, 0xaa, 0x1f, 0x7d, 0x7a, 0xe5, 0xef, 0x11, + 0x4c, 0x09, 0x79, 0x96, 0x01, 0xf9, 0x44, 0x7f, 0x83, 0x85, 0x91, 0x93, 0x4e, 0x2e, 0x56, 0x52, + 0xb8, 0xeb, 0x4b, 0xfd, 0x00, 0x4e, 0xf8, 0x5d, 0x33, 0xec, 0xf5, 0x34, 0xe0, 0x18, 0xa7, 0xef, + 0x30, 0xf1, 0xf0, 0xf1, 0x7f, 0xf1, 0xfe, 0x8a, 0x5e, 0x1a, 0x15, 0x8f, 0x5b, 0x55, 0x7d, 0x13, + 0x4e, 0xf6, 0x24, 0x55, 0x02, 0x26, 0x4c, 0x90, 0x1a, 0x57, 0xd1, 0x4e, 0x87, 0x8e, 0x5f, 0xb0, + 0x18, 0xde, 0x2e, 0xee, 0x16, 0x46, 0xbb, 0x9d, 0x5c, 0xc2, 0xdb, 0xe3, 0x21, 0x37, 0x7e, 0x26, + 0x61, 0x52, 0xb0, 0xa0, 0x8f, 0x30, 0x25, 0xc7, 0x1b, 0xca, 0x85, 0xf6, 0x45, 0x87, 0x6a, 0x36, + 0x3f, 0x18, 0x20, 0x7d, 0xe8, 0x1b, 0x9f, 0x7e, 0xfc, 0xf9, 0x1a, 0x5f, 0x43, 0xab, 0xa6, 0x42, + 0x7a, 0x43, 0xdd, 0xec, 0x5d, 0x77, 0x66, 0x1e, 0xfa, 0x09, 0x1c, 0x99, 0x4c, 0xca, 0xba, 0x70, + 0x3c, 0x30, 0x73, 0xd0, 0x42, 0x54, 0x24, 0x3a, 0x4e, 0xb3, 0x8b, 0x57, 0xa0, 0x94, 0x9f, 0x3b, + 0xc2, 0x4f, 0x1a, 0x4d, 0x85, 0xfc, 0x90, 0x1a, 0x67, 0xe8, 0x33, 0x80, 0xb0, 0xd7, 0x93, 0x68, + 0x3e, 0x4a, 0x18, 0x99, 0x3c, 0xd9, 0x85, 0xcb, 0x41, 0x4a, 0xf4, 0x81, 0x10, 0x5d, 0x44, 0xf3, + 0xff, 0x11, 0x02, 0x72, 0x60, 0x52, 0x5c, 0x50, 0xa4, 0x45, 0xb9, 0x83, 0xad, 0x9c, 0xcd, 0x0d, + 0x5c, 0x57, 0xb2, 0x4b, 0x42, 0x36, 0x8f, 0xb4, 0x90, 0xac, 0xbc, 0xf0, 0x41, 0xc5, 0x7d, 0x98, + 0x92, 0xfd, 0x83, 0x06, 0x51, 0xb2, 0x4b, 0x0a, 0x1e, 0x6e, 0x3d, 0xfd, 0xae, 0x10, 0xbd, 0x8d, + 0xd2, 0x7d, 0x44, 0x11, 0x83, 0xde, 0x85, 0x43, 0x73, 0x7d, 0x6b, 0xe5, 0x6b, 0xdc, 0x1b, 0xb0, + 0xaa, 0x04, 0x4c, 0x21, 0x70, 0x1f, 0x2d, 0x47, 0x2a, 0x18, 0xbc, 0x4a, 0x87, 0x7e, 0x9f, 0x1c, + 0x15, 0x8a, 0x27, 0x5d, 0x0d, 0x9c, 0x76, 0x35, 0xf0, 0xbb, 0xab, 0x81, 0xe3, 0x33, 0x2d, 0x76, + 0x7a, 0xa6, 0xc5, 0x7e, 0x9d, 0x69, 0xb1, 0xbd, 0xb5, 0x7a, 0x83, 0xef, 0xbb, 0x65, 0xa3, 0x42, + 0x6d, 0x41, 0x46, 0x30, 0xbf, 0x20, 0xb5, 0x69, 0xd5, 0x6d, 0x62, 0x26, 0xc8, 0x79, 0xdb, 0xc1, + 0xac, 0x9c, 0x12, 0xbf, 0x17, 0x8f, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x30, 0x83, 0x65, 0x31, + 0xed, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -722,8 +725,8 @@ const _ = grpc.SupportPackageIsVersion4 type QueryClient interface { // Supply queries the total supply of a given denom or owner Supply(ctx context.Context, in *QuerySupplyRequest, opts ...grpc.CallOption) (*QuerySupplyResponse, error) - // Owner queries the NFTs of the specified owner - Owner(ctx context.Context, in *QueryOwnerRequest, opts ...grpc.CallOption) (*QueryOwnerResponse, error) + // NFTsOfOwner queries the NFTs of the specified owner + NFTsOfOwner(ctx context.Context, in *QueryNFTsOfOwnerRequest, opts ...grpc.CallOption) (*QueryNFTsOfOwnerResponse, error) // Collection queries the NFTs of the specified denom Collection(ctx context.Context, in *QueryCollectionRequest, opts ...grpc.CallOption) (*QueryCollectionResponse, error) // Denom queries the definition of a given denom @@ -751,9 +754,9 @@ func (c *queryClient) Supply(ctx context.Context, in *QuerySupplyRequest, opts . return out, nil } -func (c *queryClient) Owner(ctx context.Context, in *QueryOwnerRequest, opts ...grpc.CallOption) (*QueryOwnerResponse, error) { - out := new(QueryOwnerResponse) - err := c.cc.Invoke(ctx, "/irismod.nft.Query/Owner", in, out, opts...) +func (c *queryClient) NFTsOfOwner(ctx context.Context, in *QueryNFTsOfOwnerRequest, opts ...grpc.CallOption) (*QueryNFTsOfOwnerResponse, error) { + out := new(QueryNFTsOfOwnerResponse) + err := c.cc.Invoke(ctx, "/irismod.nft.Query/NFTsOfOwner", in, out, opts...) if err != nil { return nil, err } @@ -800,8 +803,8 @@ func (c *queryClient) NFT(ctx context.Context, in *QueryNFTRequest, opts ...grpc type QueryServer interface { // Supply queries the total supply of a given denom or owner Supply(context.Context, *QuerySupplyRequest) (*QuerySupplyResponse, error) - // Owner queries the NFTs of the specified owner - Owner(context.Context, *QueryOwnerRequest) (*QueryOwnerResponse, error) + // NFTsOfOwner queries the NFTs of the specified owner + NFTsOfOwner(context.Context, *QueryNFTsOfOwnerRequest) (*QueryNFTsOfOwnerResponse, error) // Collection queries the NFTs of the specified denom Collection(context.Context, *QueryCollectionRequest) (*QueryCollectionResponse, error) // Denom queries the definition of a given denom @@ -819,8 +822,8 @@ type UnimplementedQueryServer struct { func (*UnimplementedQueryServer) Supply(ctx context.Context, req *QuerySupplyRequest) (*QuerySupplyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Supply not implemented") } -func (*UnimplementedQueryServer) Owner(ctx context.Context, req *QueryOwnerRequest) (*QueryOwnerResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Owner not implemented") +func (*UnimplementedQueryServer) NFTsOfOwner(ctx context.Context, req *QueryNFTsOfOwnerRequest) (*QueryNFTsOfOwnerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method NFTsOfOwner not implemented") } func (*UnimplementedQueryServer) Collection(ctx context.Context, req *QueryCollectionRequest) (*QueryCollectionResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Collection not implemented") @@ -857,20 +860,20 @@ func _Query_Supply_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } -func _Query_Owner_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryOwnerRequest) +func _Query_NFTsOfOwner_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryNFTsOfOwnerRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).Owner(ctx, in) + return srv.(QueryServer).NFTsOfOwner(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/irismod.nft.Query/Owner", + FullMethod: "/irismod.nft.Query/NFTsOfOwner", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).Owner(ctx, req.(*QueryOwnerRequest)) + return srv.(QueryServer).NFTsOfOwner(ctx, req.(*QueryNFTsOfOwnerRequest)) } return interceptor(ctx, in, info, handler) } @@ -956,8 +959,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_Supply_Handler, }, { - MethodName: "Owner", - Handler: _Query_Owner_Handler, + MethodName: "NFTsOfOwner", + Handler: _Query_NFTsOfOwner_Handler, }, { MethodName: "Collection", @@ -1045,7 +1048,7 @@ func (m *QuerySupplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryOwnerRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryNFTsOfOwnerRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1055,12 +1058,12 @@ func (m *QueryOwnerRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryOwnerRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryNFTsOfOwnerRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryOwnerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryNFTsOfOwnerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1094,7 +1097,7 @@ func (m *QueryOwnerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryOwnerResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryNFTsOfOwnerResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1104,12 +1107,12 @@ func (m *QueryOwnerResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryOwnerResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryNFTsOfOwnerResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryOwnerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryNFTsOfOwnerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1491,7 +1494,7 @@ func (m *QuerySupplyResponse) Size() (n int) { return n } -func (m *QueryOwnerRequest) Size() (n int) { +func (m *QueryNFTsOfOwnerRequest) Size() (n int) { if m == nil { return 0 } @@ -1512,7 +1515,7 @@ func (m *QueryOwnerRequest) Size() (n int) { return n } -func (m *QueryOwnerResponse) Size() (n int) { +func (m *QueryNFTsOfOwnerResponse) Size() (n int) { if m == nil { return 0 } @@ -1840,7 +1843,7 @@ func (m *QuerySupplyResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryOwnerRequest) Unmarshal(dAtA []byte) error { +func (m *QueryNFTsOfOwnerRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1863,10 +1866,10 @@ func (m *QueryOwnerRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryOwnerRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryNFTsOfOwnerRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryOwnerRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryNFTsOfOwnerRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1990,7 +1993,7 @@ func (m *QueryOwnerRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryOwnerResponse) Unmarshal(dAtA []byte) error { +func (m *QueryNFTsOfOwnerResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2013,10 +2016,10 @@ func (m *QueryOwnerResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryOwnerResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryNFTsOfOwnerResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryOwnerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryNFTsOfOwnerResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/modules/nft/types/query.pb.gw.go b/modules/nft/types/query.pb.gw.go index 0ee6608e..30ff7df3 100644 --- a/modules/nft/types/query.pb.gw.go +++ b/modules/nft/types/query.pb.gw.go @@ -106,37 +106,37 @@ func local_request_Query_Supply_0(ctx context.Context, marshaler runtime.Marshal } var ( - filter_Query_Owner_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_Query_NFTsOfOwner_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_Query_Owner_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryOwnerRequest +func request_Query_NFTsOfOwner_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryNFTsOfOwnerRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Owner_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_NFTsOfOwner_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.Owner(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.NFTsOfOwner(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_Owner_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryOwnerRequest +func local_request_Query_NFTsOfOwner_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryNFTsOfOwnerRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Owner_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_NFTsOfOwner_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.Owner(ctx, &protoReq) + msg, err := server.NFTsOfOwner(ctx, &protoReq) return msg, metadata, err } @@ -408,7 +408,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_Owner_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_NFTsOfOwner_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -419,7 +419,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_Owner_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_NFTsOfOwner_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -427,7 +427,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_Owner_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_NFTsOfOwner_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -584,7 +584,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_Owner_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_NFTsOfOwner_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -593,14 +593,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_Owner_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_NFTsOfOwner_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_Owner_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_NFTsOfOwner_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -690,7 +690,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie var ( pattern_Query_Supply_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"irismod", "nft", "collections", "denom_id", "supply"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_Owner_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"irismod", "nft", "nfts"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_NFTsOfOwner_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"irismod", "nft", "nfts"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Collection_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"irismod", "nft", "collections", "denom_id"}, "", runtime.AssumeColonVerbOpt(false))) @@ -704,7 +704,7 @@ var ( var ( forward_Query_Supply_0 = runtime.ForwardResponseMessage - forward_Query_Owner_0 = runtime.ForwardResponseMessage + forward_Query_NFTsOfOwner_0 = runtime.ForwardResponseMessage forward_Query_Collection_0 = runtime.ForwardResponseMessage diff --git a/modules/nft/types/tx.pb.go b/modules/nft/types/tx.pb.go index 49dea56a..01772340 100644 --- a/modules/nft/types/tx.pb.go +++ b/modules/nft/types/tx.pb.go @@ -6,15 +6,16 @@ package types import ( context "context" fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - io "io" - math "math" - math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -76,7 +77,7 @@ func (m *MsgIssueDenom) XXX_DiscardUnknown() { var xxx_messageInfo_MsgIssueDenom proto.InternalMessageInfo -// MsgIssueDenomResponse defines the Msg/IssueDenom response type. +// MsgIssueDenomResponse defines the Msg/SaveDenom response type. type MsgIssueDenomResponse struct { } @@ -239,7 +240,7 @@ func (m *MsgEditNFT) XXX_DiscardUnknown() { var xxx_messageInfo_MsgEditNFT proto.InternalMessageInfo -// MsgEditNFTResponse defines the Msg/EditNFT response type. +// MsgEditNFTResponse defines the Msg/UpdateNFT response type. type MsgEditNFTResponse struct { } @@ -321,7 +322,7 @@ func (m *MsgMintNFT) XXX_DiscardUnknown() { var xxx_messageInfo_MsgMintNFT proto.InternalMessageInfo -// MsgMintNFTResponse defines the Msg/MintNFT response type. +// MsgMintNFTResponse defines the Msg/SaveNFT response type. type MsgMintNFTResponse struct { } @@ -398,7 +399,7 @@ func (m *MsgBurnNFT) XXX_DiscardUnknown() { var xxx_messageInfo_MsgBurnNFT proto.InternalMessageInfo -// MsgBurnNFTResponse defines the Msg/BurnNFT response type. +// MsgBurnNFTResponse defines the Msg/RemoveNFT response type. type MsgBurnNFTResponse struct { } @@ -858,7 +859,7 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { func (c *msgClient) IssueDenom(ctx context.Context, in *MsgIssueDenom, opts ...grpc.CallOption) (*MsgIssueDenomResponse, error) { out := new(MsgIssueDenomResponse) - err := c.cc.Invoke(ctx, "/irismod.nft.Msg/IssueDenom", in, out, opts...) + err := c.cc.Invoke(ctx, "/irismod.nft.Msg/SaveDenom", in, out, opts...) if err != nil { return nil, err } @@ -867,7 +868,7 @@ func (c *msgClient) IssueDenom(ctx context.Context, in *MsgIssueDenom, opts ...g func (c *msgClient) MintNFT(ctx context.Context, in *MsgMintNFT, opts ...grpc.CallOption) (*MsgMintNFTResponse, error) { out := new(MsgMintNFTResponse) - err := c.cc.Invoke(ctx, "/irismod.nft.Msg/MintNFT", in, out, opts...) + err := c.cc.Invoke(ctx, "/irismod.nft.Msg/SaveNFT", in, out, opts...) if err != nil { return nil, err } @@ -876,7 +877,7 @@ func (c *msgClient) MintNFT(ctx context.Context, in *MsgMintNFT, opts ...grpc.Ca func (c *msgClient) EditNFT(ctx context.Context, in *MsgEditNFT, opts ...grpc.CallOption) (*MsgEditNFTResponse, error) { out := new(MsgEditNFTResponse) - err := c.cc.Invoke(ctx, "/irismod.nft.Msg/EditNFT", in, out, opts...) + err := c.cc.Invoke(ctx, "/irismod.nft.Msg/UpdateNFT", in, out, opts...) if err != nil { return nil, err } @@ -894,7 +895,7 @@ func (c *msgClient) TransferNFT(ctx context.Context, in *MsgTransferNFT, opts .. func (c *msgClient) BurnNFT(ctx context.Context, in *MsgBurnNFT, opts ...grpc.CallOption) (*MsgBurnNFTResponse, error) { out := new(MsgBurnNFTResponse) - err := c.cc.Invoke(ctx, "/irismod.nft.Msg/BurnNFT", in, out, opts...) + err := c.cc.Invoke(ctx, "/irismod.nft.Msg/RemoveNFT", in, out, opts...) if err != nil { return nil, err } @@ -931,19 +932,19 @@ type UnimplementedMsgServer struct { } func (*UnimplementedMsgServer) IssueDenom(ctx context.Context, req *MsgIssueDenom) (*MsgIssueDenomResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method IssueDenom not implemented") + return nil, status.Errorf(codes.Unimplemented, "method SaveDenom not implemented") } func (*UnimplementedMsgServer) MintNFT(ctx context.Context, req *MsgMintNFT) (*MsgMintNFTResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method MintNFT not implemented") + return nil, status.Errorf(codes.Unimplemented, "method SaveNFT not implemented") } func (*UnimplementedMsgServer) EditNFT(ctx context.Context, req *MsgEditNFT) (*MsgEditNFTResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method EditNFT not implemented") + return nil, status.Errorf(codes.Unimplemented, "method UpdateNFT not implemented") } func (*UnimplementedMsgServer) TransferNFT(ctx context.Context, req *MsgTransferNFT) (*MsgTransferNFTResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TransferNFT not implemented") } func (*UnimplementedMsgServer) BurnNFT(ctx context.Context, req *MsgBurnNFT) (*MsgBurnNFTResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method BurnNFT not implemented") + return nil, status.Errorf(codes.Unimplemented, "method RemoveNFT not implemented") } func (*UnimplementedMsgServer) TransferDenom(ctx context.Context, req *MsgTransferDenom) (*MsgTransferDenomResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TransferDenom not implemented") @@ -963,7 +964,7 @@ func _Msg_IssueDenom_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/irismod.nft.Msg/IssueDenom", + FullMethod: "/irismod.nft.Msg/SaveDenom", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).IssueDenom(ctx, req.(*MsgIssueDenom)) @@ -981,7 +982,7 @@ func _Msg_MintNFT_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/irismod.nft.Msg/MintNFT", + FullMethod: "/irismod.nft.Msg/SaveNFT", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).MintNFT(ctx, req.(*MsgMintNFT)) @@ -999,7 +1000,7 @@ func _Msg_EditNFT_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/irismod.nft.Msg/EditNFT", + FullMethod: "/irismod.nft.Msg/UpdateNFT", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).EditNFT(ctx, req.(*MsgEditNFT)) @@ -1035,7 +1036,7 @@ func _Msg_BurnNFT_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/irismod.nft.Msg/BurnNFT", + FullMethod: "/irismod.nft.Msg/RemoveNFT", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).BurnNFT(ctx, req.(*MsgBurnNFT)) @@ -1066,15 +1067,15 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "IssueDenom", + MethodName: "SaveDenom", Handler: _Msg_IssueDenom_Handler, }, { - MethodName: "MintNFT", + MethodName: "SaveNFT", Handler: _Msg_MintNFT_Handler, }, { - MethodName: "EditNFT", + MethodName: "UpdateNFT", Handler: _Msg_EditNFT_Handler, }, { @@ -1082,7 +1083,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Handler: _Msg_TransferNFT_Handler, }, { - MethodName: "BurnNFT", + MethodName: "RemoveNFT", Handler: _Msg_BurnNFT_Handler, }, { diff --git a/modules/nft/types/validation.go b/modules/nft/types/validation.go index b033bc80..f3022419 100644 --- a/modules/nft/types/validation.go +++ b/modules/nft/types/validation.go @@ -70,6 +70,13 @@ func Modified(target string) bool { return target != types.DoNotModify } +func Modify(origin, target string) string { + if target == types.DoNotModify { + return origin + } + return target +} + // ValidateKeywords checks if the given denomId begins with `DenomKeywords` func ValidateKeywords(denomId string) error { if regexpKeyword(denomId) { diff --git a/modules/oracle/keeper/pagination_test.go b/modules/oracle/keeper/pagination_test.go index 892fdf1f..5558257c 100644 --- a/modules/oracle/keeper/pagination_test.go +++ b/modules/oracle/keeper/pagination_test.go @@ -24,7 +24,7 @@ func TestShapePageRequest(t *testing.T) { CountTotal: true, Reverse: true, } - + res2 := ShapePageRequest(request) require.NotNil(t, res2) require.Equal(t, res2.Limit, defaultRequest.Limit) // limit == paginationDefaultLimit diff --git a/modules/token/keeper/pagination_test.go b/modules/token/keeper/pagination_test.go index 892fdf1f..5558257c 100644 --- a/modules/token/keeper/pagination_test.go +++ b/modules/token/keeper/pagination_test.go @@ -24,7 +24,7 @@ func TestShapePageRequest(t *testing.T) { CountTotal: true, Reverse: true, } - + res2 := ShapePageRequest(request) require.NotNil(t, res2) require.Equal(t, res2.Limit, defaultRequest.Limit) // limit == paginationDefaultLimit diff --git a/proto/nft/nft.proto b/proto/nft/nft.proto index a74737ec..c1163cce 100644 --- a/proto/nft/nft.proto +++ b/proto/nft/nft.proto @@ -18,6 +18,13 @@ message BaseNFT { string uri_hash = 6; } +message NFTMetadata { + option (gogoproto.equal) = true; + + string name = 1; + string data = 2; +} + // Denom defines a type of NFT message Denom { option (gogoproto.equal) = true; @@ -35,6 +42,16 @@ message Denom { string data = 11; } +message DenomMetadata { + option (gogoproto.equal) = true; + + string creator = 1; + string schema = 2; + bool mint_restricted = 3; + bool update_restricted = 4; + string data = 5; +} + // IDCollection defines a type of collection with specified ID message IDCollection { option (gogoproto.equal) = true; diff --git a/proto/nft/query.proto b/proto/nft/query.proto index e5aac40e..912d5d8b 100644 --- a/proto/nft/query.proto +++ b/proto/nft/query.proto @@ -15,8 +15,8 @@ service Query { option (google.api.http).get = "/irismod/nft/collections/{denom_id}/supply"; } - // Owner queries the NFTs of the specified owner - rpc Owner(QueryOwnerRequest) returns (QueryOwnerResponse) { + // NFTsOfOwner queries the NFTs of the specified owner + rpc NFTsOfOwner(QueryNFTsOfOwnerRequest) returns (QueryNFTsOfOwnerResponse) { option (google.api.http).get = "/irismod/nft/nfts"; } @@ -50,16 +50,18 @@ message QuerySupplyRequest { // QuerySupplyResponse is the response type for the Query/Supply RPC method message QuerySupplyResponse { uint64 amount = 1; } -// QueryOwnerRequest is the request type for the Query/Owner RPC method -message QueryOwnerRequest { +// QueryNFTsOfOwnerRequest is the request type for the Query/NFTsOfOwner RPC +// method +message QueryNFTsOfOwnerRequest { string denom_id = 1 [ (gogoproto.moretags) = "yaml:\"denom_id\"" ]; string owner = 2 [ (gogoproto.moretags) = "yaml:\"owner\"" ]; // pagination defines an optional pagination for the request. cosmos.base.query.v1beta1.PageRequest pagination = 3; } -// QueryOwnerResponse is the response type for the Query/Owner RPC method -message QueryOwnerResponse { +// QueryNFTsOfOwnerResponse is the response type for the Query/NFTsOfOwner RPC +// method +message QueryNFTsOfOwnerResponse { Owner owner = 1; cosmos.base.query.v1beta1.PageResponse pagination = 2; } diff --git a/simapp/app.go b/simapp/app.go index 646be573..8650798b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -7,6 +7,8 @@ import ( "os" "path/filepath" + module2 "github.com/irisnet/irismod/modules/nft/module" + "github.com/gorilla/mux" "github.com/rakyll/statik/fs" "github.com/spf13/cast" @@ -94,7 +96,6 @@ import ( "github.com/irisnet/irismod/modules/htlc" htlckeeper "github.com/irisnet/irismod/modules/htlc/keeper" htlctypes "github.com/irisnet/irismod/modules/htlc/types" - "github.com/irisnet/irismod/modules/nft" nftkeeper "github.com/irisnet/irismod/modules/nft/keeper" nfttypes "github.com/irisnet/irismod/modules/nft/types" "github.com/irisnet/irismod/modules/oracle" @@ -152,7 +153,7 @@ var ( token.AppModuleBasic{}, record.AppModuleBasic{}, - nft.AppModuleBasic{}, + module2.AppModuleBasic{}, htlc.AppModuleBasic{}, coinswap.AppModuleBasic{}, service.AppModuleBasic{}, @@ -178,6 +179,7 @@ var ( farmtypes.ModuleName: {authtypes.Burner}, farmtypes.RewardCollector: nil, farmtypes.EscrowCollector: nil, + nfttypes.ModuleName: nil, } ) @@ -347,7 +349,12 @@ func NewSimApp( ) app.RecordKeeper = recordkeeper.NewKeeper(appCodec, keys[recordtypes.StoreKey]) - app.NFTKeeper = nftkeeper.NewKeeper(appCodec, keys[nfttypes.StoreKey]) + app.NFTKeeper = nftkeeper.NewKeeper( + appCodec, + keys[nfttypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + ) app.HTLCKeeper = htlckeeper.NewKeeper( appCodec, @@ -442,7 +449,7 @@ func NewSimApp( params.NewAppModule(app.ParamsKeeper), token.NewAppModule(appCodec, app.TokenKeeper, app.AccountKeeper, app.BankKeeper), record.NewAppModule(appCodec, app.RecordKeeper, app.AccountKeeper, app.BankKeeper), - nft.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper), + module2.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper), htlc.NewAppModule(appCodec, app.HTLCKeeper, app.AccountKeeper, app.BankKeeper), coinswap.NewAppModule(appCodec, app.CoinswapKeeper, app.AccountKeeper, app.BankKeeper), service.NewAppModule(appCodec, app.ServiceKeeper, app.AccountKeeper, app.BankKeeper), @@ -517,7 +524,7 @@ func NewSimApp( slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), token.NewAppModule(appCodec, app.TokenKeeper, app.AccountKeeper, app.BankKeeper), record.NewAppModule(appCodec, app.RecordKeeper, app.AccountKeeper, app.BankKeeper), - nft.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper), + module2.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper), htlc.NewAppModule(appCodec, app.HTLCKeeper, app.AccountKeeper, app.BankKeeper), //coinswap.NewAppModule(appCodec, app.CoinswapKeeper, app.AccountKeeper, app.BankKeeper), service.NewAppModule(appCodec, app.ServiceKeeper, app.AccountKeeper, app.BankKeeper), diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index fe1e65cb..0b4c3324 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -291,6 +291,48 @@ func createRandomAccounts(accNum int) []sdk.AccAddress { return testAddrs } +// CreateTestAddrs creates test addresses +func CreateTestAddrs(numAddrs int) []sdk.AccAddress { + var addresses []sdk.AccAddress + var buffer bytes.Buffer + + // start at 100 so we can make up to 999 test addresses with valid test addresses + for i := 100; i < (numAddrs + 100); i++ { + numString := strconv.Itoa(i) + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string + + buffer.WriteString(numString) //adding on final two digits to make addresses unique + res, _ := sdk.AccAddressFromHexUnsafe(buffer.String()) + bech := res.String() + addresses = append(addresses, testAddr(buffer.String(), bech)) + buffer.Reset() + } + + return addresses +} + +// for incode address generation +func testAddr(addr string, bech string) sdk.AccAddress { + res, err := sdk.AccAddressFromHexUnsafe(addr) + if err != nil { + panic(err) + } + bechexpected := res.String() + if bech != bechexpected { + panic("Bech encoding doesn't match reference") + } + + bechres, err := sdk.AccAddressFromBech32(bech) + if err != nil { + panic(err) + } + if !bytes.Equal(bechres, res) { + panic("Bech decode and hex decode don't match") + } + + return res +} + // createIncrementalAccounts is a strategy used by addTestAddrs() in order to generated addresses in ascending order. func createIncrementalAccounts(accNum int) []sdk.AccAddress { var addresses []sdk.AccAddress