diff --git a/simapp/app.go b/simapp/app.go index 9f3e6e3b53..cf19ae6fc0 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -401,7 +401,7 @@ func NewSimApp( ), ) - app.NFTKeeper = nftkeeper.NewKeeper(runtime.NewKVStoreService(keys[nftkeeper.StoreKey]), appCodec, app.AuthKeeper, app.BankKeeper) + app.NFTKeeper = nftkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[nftkeeper.StoreKey])), appCodec, app.AuthKeeper, app.BankKeeper) // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( diff --git a/x/nft/CHANGELOG.md b/x/nft/CHANGELOG.md index d64a7528d6..8e939e4fe3 100644 --- a/x/nft/CHANGELOG.md +++ b/x/nft/CHANGELOG.md @@ -35,4 +35,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [#18355](https://github.com/cosmos/cosmos-sdk/pull/18355) Added new versions for `Balance`, `Owner`, `Supply`, `NFT`, `Class` queries that receives request via query string. +* [#19367](https://github.com/cosmos/cosmos-sdk/pull/19367) `appmodule.Environment` is received on the Keeper to get access to different application services + ## [v0.1.0](https://github.com/cosmos/cosmos-sdk/releases/tag/x/nft/v0.1.0) - 2023-11-07 + + diff --git a/x/nft/keeper/grpc_query.go b/x/nft/keeper/grpc_query.go index 725dd2fec1..5da5116a4c 100644 --- a/x/nft/keeper/grpc_query.go +++ b/x/nft/keeper/grpc_query.go @@ -15,7 +15,7 @@ import ( var _ nft.QueryServer = Keeper{} // Balance return the number of NFTs of a given class owned by the owner, same as balanceOf in ERC721 -func (k Keeper) Balance(goCtx context.Context, r *nft.QueryBalanceRequest) (*nft.QueryBalanceResponse, error) { +func (k Keeper) Balance(ctx context.Context, r *nft.QueryBalanceRequest) (*nft.QueryBalanceResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } @@ -29,15 +29,14 @@ func (k Keeper) Balance(goCtx context.Context, r *nft.QueryBalanceRequest) (*nft return nil, err } - ctx := sdk.UnwrapSDKContext(goCtx) balance := k.GetBalance(ctx, r.ClassId, owner) return &nft.QueryBalanceResponse{Amount: balance}, nil } // BalanceByQueryString return the number of NFTs of a given class owned by the owner, same as balanceOf in ERC721 // but receives request via query string. -func (k Keeper) BalanceByQueryString(goCtx context.Context, r *nft.QueryBalanceByQueryStringRequest) (*nft.QueryBalanceByQueryStringResponse, error) { - res, err := k.Balance(goCtx, &nft.QueryBalanceRequest{ +func (k Keeper) BalanceByQueryString(ctx context.Context, r *nft.QueryBalanceByQueryStringRequest) (*nft.QueryBalanceByQueryStringResponse, error) { + res, err := k.Balance(ctx, &nft.QueryBalanceRequest{ ClassId: r.ClassId, Owner: r.Owner, }) @@ -48,7 +47,7 @@ func (k Keeper) BalanceByQueryString(goCtx context.Context, r *nft.QueryBalanceB } // Owner return the owner of the NFT based on its class and id, same as ownerOf in ERC721 -func (k Keeper) Owner(goCtx context.Context, r *nft.QueryOwnerRequest) (*nft.QueryOwnerResponse, error) { +func (k Keeper) Owner(ctx context.Context, r *nft.QueryOwnerRequest) (*nft.QueryOwnerResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } @@ -61,7 +60,6 @@ func (k Keeper) Owner(goCtx context.Context, r *nft.QueryOwnerRequest) (*nft.Que return nil, nft.ErrEmptyNFTID } - ctx := sdk.UnwrapSDKContext(goCtx) owner := k.GetOwner(ctx, r.ClassId, r.Id) if owner.Empty() { return &nft.QueryOwnerResponse{Owner: ""}, nil @@ -75,8 +73,8 @@ func (k Keeper) Owner(goCtx context.Context, r *nft.QueryOwnerRequest) (*nft.Que // OwnerByQueryString return the owner of the NFT based on its class and id, same as ownerOf in ERC721 // but receives request via query string. -func (k Keeper) OwnerByQueryString(goCtx context.Context, r *nft.QueryOwnerByQueryStringRequest) (*nft.QueryOwnerByQueryStringResponse, error) { - res, err := k.Owner(goCtx, &nft.QueryOwnerRequest{ +func (k Keeper) OwnerByQueryString(ctx context.Context, r *nft.QueryOwnerByQueryStringRequest) (*nft.QueryOwnerByQueryStringResponse, error) { + res, err := k.Owner(ctx, &nft.QueryOwnerRequest{ ClassId: r.ClassId, Id: r.Id, }) @@ -87,7 +85,7 @@ func (k Keeper) OwnerByQueryString(goCtx context.Context, r *nft.QueryOwnerByQue } // Supply return the number of NFTs from the given class, same as totalSupply of ERC721. -func (k Keeper) Supply(goCtx context.Context, r *nft.QuerySupplyRequest) (*nft.QuerySupplyResponse, error) { +func (k Keeper) Supply(ctx context.Context, r *nft.QuerySupplyRequest) (*nft.QuerySupplyResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } @@ -95,15 +93,15 @@ func (k Keeper) Supply(goCtx context.Context, r *nft.QuerySupplyRequest) (*nft.Q if len(r.ClassId) == 0 { return nil, nft.ErrEmptyClassID } - ctx := sdk.UnwrapSDKContext(goCtx) + supply := k.GetTotalSupply(ctx, r.ClassId) return &nft.QuerySupplyResponse{Amount: supply}, nil } // SupplyByQueryString return the number of NFTs from the given class, same as totalSupply of ERC721. // but receives request via query string. -func (k Keeper) SupplyByQueryString(goCtx context.Context, r *nft.QuerySupplyByQueryStringRequest) (*nft.QuerySupplyByQueryStringResponse, error) { - res, err := k.Supply(goCtx, &nft.QuerySupplyRequest{ +func (k Keeper) SupplyByQueryString(ctx context.Context, r *nft.QuerySupplyByQueryStringRequest) (*nft.QuerySupplyByQueryStringResponse, error) { + res, err := k.Supply(ctx, &nft.QuerySupplyRequest{ ClassId: r.ClassId, }) if err != nil { @@ -113,7 +111,7 @@ func (k Keeper) SupplyByQueryString(goCtx context.Context, r *nft.QuerySupplyByQ } // NFTs queries all NFTs of a given class or owner (at least one must be provided), similar to tokenByIndex in ERC721Enumerable -func (k Keeper) NFTs(goCtx context.Context, r *nft.QueryNFTsRequest) (*nft.QueryNFTsResponse, error) { +func (k Keeper) NFTs(ctx context.Context, r *nft.QueryNFTsRequest) (*nft.QueryNFTsResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } @@ -130,7 +128,6 @@ func (k Keeper) NFTs(goCtx context.Context, r *nft.QueryNFTsRequest) (*nft.Query var nfts []*nft.NFT var pageRes *query.PageResponse - ctx := sdk.UnwrapSDKContext(goCtx) switch { case len(r.ClassId) > 0 && len(r.Owner) > 0: @@ -175,7 +172,7 @@ func (k Keeper) NFTs(goCtx context.Context, r *nft.QueryNFTsRequest) (*nft.Query } // NFT return an NFT based on its class and id. -func (k Keeper) NFT(goCtx context.Context, r *nft.QueryNFTRequest) (*nft.QueryNFTResponse, error) { +func (k Keeper) NFT(ctx context.Context, r *nft.QueryNFTRequest) (*nft.QueryNFTResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } @@ -187,7 +184,6 @@ func (k Keeper) NFT(goCtx context.Context, r *nft.QueryNFTRequest) (*nft.QueryNF return nil, nft.ErrEmptyNFTID } - ctx := sdk.UnwrapSDKContext(goCtx) n, has := k.GetNFT(ctx, r.ClassId, r.Id) if !has { return nil, nft.ErrNFTNotExists.Wrapf("not found nft: class: %s, id: %s", r.ClassId, r.Id) @@ -209,7 +205,7 @@ func (k Keeper) NFTByQueryString(goCtx context.Context, r *nft.QueryNFTByQuerySt } // Class return an NFT class based on its id -func (k Keeper) Class(goCtx context.Context, r *nft.QueryClassRequest) (*nft.QueryClassResponse, error) { +func (k Keeper) Class(ctx context.Context, r *nft.QueryClassRequest) (*nft.QueryClassResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } @@ -218,7 +214,6 @@ func (k Keeper) Class(goCtx context.Context, r *nft.QueryClassRequest) (*nft.Que return nil, nft.ErrEmptyClassID } - ctx := sdk.UnwrapSDKContext(goCtx) class, has := k.GetClass(ctx, r.ClassId) if !has { return nil, nft.ErrClassNotExists.Wrapf("not found class: %s", r.ClassId) @@ -228,8 +223,8 @@ func (k Keeper) Class(goCtx context.Context, r *nft.QueryClassRequest) (*nft.Que // ClassByQueryString return an NFT class based on its id // but receives request via query string. -func (k Keeper) ClassByQueryString(goCtx context.Context, r *nft.QueryClassByQueryStringRequest) (*nft.QueryClassByQueryStringResponse, error) { - res, err := k.Class(goCtx, &nft.QueryClassRequest{ +func (k Keeper) ClassByQueryString(ctx context.Context, r *nft.QueryClassByQueryStringRequest) (*nft.QueryClassByQueryStringResponse, error) { + res, err := k.Class(ctx, &nft.QueryClassRequest{ ClassId: r.ClassId, }) if err != nil { @@ -239,12 +234,11 @@ func (k Keeper) ClassByQueryString(goCtx context.Context, r *nft.QueryClassByQue } // Classes return all NFT classes -func (k Keeper) Classes(goCtx context.Context, r *nft.QueryClassesRequest) (*nft.QueryClassesResponse, error) { +func (k Keeper) Classes(ctx context.Context, r *nft.QueryClassesRequest) (*nft.QueryClassesResponse, error) { if r == nil { return nil, sdkerrors.ErrInvalidRequest.Wrap("empty request") } - ctx := sdk.UnwrapSDKContext(goCtx) store := k.storeService.OpenKVStore(ctx) classStore := prefix.NewStore(runtime.KVStoreAdapter(store), ClassKey) diff --git a/x/nft/keeper/keeper.go b/x/nft/keeper/keeper.go index d2718d3262..54c5874151 100644 --- a/x/nft/keeper/keeper.go +++ b/x/nft/keeper/keeper.go @@ -2,6 +2,8 @@ package keeper import ( "cosmossdk.io/core/address" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/event" store "cosmossdk.io/core/store" "cosmossdk.io/x/nft" @@ -14,12 +16,15 @@ type Keeper struct { storeService store.KVStoreService bk nft.BankKeeper ac address.Codec + eventService event.Service } // NewKeeper creates a new nft Keeper instance -func NewKeeper(storeService store.KVStoreService, +func NewKeeper(env appmodule.Environment, cdc codec.BinaryCodec, ak nft.AccountKeeper, bk nft.BankKeeper, ) Keeper { + storeService := env.KVStoreService + // ensure nft module account is set if addr := ak.GetModuleAddress(nft.ModuleName); addr == nil { panic("the nft module account has not been set") @@ -28,6 +33,7 @@ func NewKeeper(storeService store.KVStoreService, return Keeper{ cdc: cdc, storeService: storeService, + eventService: env.EventService, bk: bk, ac: ak.AddressCodec(), } diff --git a/x/nft/keeper/keeper_test.go b/x/nft/keeper/keeper_test.go index 58fe41d307..863dba3c3a 100644 --- a/x/nft/keeper/keeper_test.go +++ b/x/nft/keeper/keeper_test.go @@ -54,7 +54,6 @@ func (s *TestSuite) SetupTest() { s.encCfg = moduletestutil.MakeTestEncodingConfig(module.AppModuleBasic{}) key := storetypes.NewKVStoreKey(nft.StoreKey) - storeService := runtime.NewKVStoreService(key) testCtx := testutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test")) ctx := testCtx.Ctx.WithHeaderInfo(header.Info{Time: time.Now().Round(0).UTC()}) @@ -73,7 +72,8 @@ func (s *TestSuite) SetupTest() { s.accountKeeper = accountKeeper - nftKeeper := keeper.NewKeeper(storeService, s.encCfg.Codec, accountKeeper, bankKeeper) + env := runtime.NewEnvironment(runtime.NewKVStoreService(key)) + nftKeeper := keeper.NewKeeper(env, s.encCfg.Codec, accountKeeper, bankKeeper) queryHelper := baseapp.NewQueryServerTestHelper(ctx, s.encCfg.InterfaceRegistry) nft.RegisterQueryServer(queryHelper, nftKeeper) diff --git a/x/nft/keeper/msg_server.go b/x/nft/keeper/msg_server.go index cc24d44732..98ba890180 100644 --- a/x/nft/keeper/msg_server.go +++ b/x/nft/keeper/msg_server.go @@ -7,14 +7,13 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/x/nft" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ nft.MsgServer = Keeper{} // Send implements Send method of the types.MsgServer. -func (k Keeper) Send(goCtx context.Context, msg *nft.MsgSend) (*nft.MsgSendResponse, error) { +func (k Keeper) Send(ctx context.Context, msg *nft.MsgSend) (*nft.MsgSendResponse, error) { if len(msg.ClassId) == 0 { return nil, nft.ErrEmptyClassID } @@ -33,7 +32,6 @@ func (k Keeper) Send(goCtx context.Context, msg *nft.MsgSend) (*nft.MsgSendRespo return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid receiver address (%s)", msg.Receiver) } - ctx := sdk.UnwrapSDKContext(goCtx) owner := k.GetOwner(ctx, msg.ClassId, msg.Id) if !bytes.Equal(owner, sender) { return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not the owner of nft %s", msg.Sender, msg.Id) @@ -43,14 +41,16 @@ func (k Keeper) Send(goCtx context.Context, msg *nft.MsgSend) (*nft.MsgSendRespo return nil, err } - err = ctx.EventManager().EmitTypedEvent(&nft.EventSend{ + err = k.eventService.EventManager(ctx).Emit(&nft.EventSend{ ClassId: msg.ClassId, Id: msg.Id, Sender: msg.Sender, Receiver: msg.Receiver, }) + if err != nil { return nil, err } + return &nft.MsgSendResponse{}, nil } diff --git a/x/nft/keeper/nft.go b/x/nft/keeper/nft.go index 7123aaaf6e..cad95dde72 100644 --- a/x/nft/keeper/nft.go +++ b/x/nft/keeper/nft.go @@ -36,11 +36,18 @@ func (k Keeper) mintWithNoCheck(ctx context.Context, token nft.NFT, receiver sdk if err != nil { return err } - return sdk.UnwrapSDKContext(ctx).EventManager().EmitTypedEvent(&nft.EventMint{ + + err = k.eventService.EventManager(ctx).Emit(&nft.EventMint{ ClassId: token.ClassId, Id: token.Id, Owner: recStr, }) + + if err != nil { + return err + } + + return nil } // Burn defines a method for burning a nft from a specific account. @@ -71,16 +78,23 @@ func (k Keeper) burnWithNoCheck(ctx context.Context, classID, nftID string) erro k.deleteOwner(ctx, classID, nftID, owner) k.decrTotalSupply(ctx, classID) + ownerStr, err := k.ac.BytesToString(owner.Bytes()) if err != nil { return err } - return sdk.UnwrapSDKContext(ctx).EventManager().EmitTypedEvent(&nft.EventBurn{ + err = k.eventService.EventManager(ctx).Emit(&nft.EventBurn{ ClassId: classID, Id: nftID, Owner: ownerStr, }) + + if err != nil { + return err + } + + return nil } // Update defines a method for updating an exist nft diff --git a/x/nft/module/depinject.go b/x/nft/module/depinject.go index 468a64beb7..3c47ca5ebe 100644 --- a/x/nft/module/depinject.go +++ b/x/nft/module/depinject.go @@ -3,7 +3,6 @@ package module import ( modulev1 "cosmossdk.io/api/cosmos/nft/module/v1" "cosmossdk.io/core/appmodule" - "cosmossdk.io/core/store" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/x/nft" @@ -27,9 +26,9 @@ func init() { type ModuleInputs struct { depinject.In - StoreService store.KVStoreService - Cdc codec.Codec - Registry cdctypes.InterfaceRegistry + Environment appmodule.Environment + Cdc codec.Codec + Registry cdctypes.InterfaceRegistry AccountKeeper nft.AccountKeeper BankKeeper nft.BankKeeper @@ -43,7 +42,7 @@ type ModuleOutputs struct { } func ProvideModule(in ModuleInputs) ModuleOutputs { - k := keeper.NewKeeper(in.StoreService, in.Cdc, in.AccountKeeper, in.BankKeeper) + k := keeper.NewKeeper(in.Environment, in.Cdc, in.AccountKeeper, in.BankKeeper) m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.BankKeeper, in.Registry) return ModuleOutputs{NFTKeeper: k, Module: m}