Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add batch operation for x/nft module #12187

Merged
merged 15 commits into from
Jun 15, 2022
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

* [#12089](https://github.com/cosmos/cosmos-sdk/pull/12089) Mark the `TipDecorator` as beta, don't include it in simapp by default.
* [#12153](https://github.com/cosmos/cosmos-sdk/pull/12153) Add a new `NewSimulationManagerFromAppModules` constructor, to simplify simulation wiring.
* [#12187](https://github.com/cosmos/cosmos-sdk/pull/12187) Add batch operation for x/nft module.

### API Breaking Changes

Expand Down
38 changes: 36 additions & 2 deletions x/nft/keeper/nft.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ func (k Keeper) Mint(ctx sdk.Context, token nft.NFT, receiver sdk.AccAddress) er
return sdkerrors.Wrap(nft.ErrNFTExists, token.Id)
}

k.mintWithNoCheck(ctx, token, receiver)
return nil
}

// mintWithNoCheck defines a method for minting a new nft
// Note: this method does not check whether the class already exists in nft.
// The upper-layer application needs to check it when it needs to use it.
func (k Keeper) mintWithNoCheck(ctx sdk.Context, token nft.NFT, receiver sdk.AccAddress) {
k.setNFT(ctx, token)
k.setOwner(ctx, token.ClassId, token.Id, receiver)
k.incrTotalSupply(ctx, token.ClassId)
Expand All @@ -26,7 +34,6 @@ func (k Keeper) Mint(ctx sdk.Context, token nft.NFT, receiver sdk.AccAddress) er
Id: token.Id,
Owner: receiver.String(),
})
return nil
}

// Burn defines a method for burning a nft from a specific account.
Expand All @@ -40,6 +47,14 @@ func (k Keeper) Burn(ctx sdk.Context, classID string, nftID string) error {
return sdkerrors.Wrap(nft.ErrNFTNotExists, nftID)
}

k.burnWithNoCheck(ctx, classID, nftID)
return nil
}

// burnWithNoCheck defines a method for burning a nft from a specific account.
// Note: this method does not check whether the class already exists in nft.
// The upper-layer application needs to check it when it needs to use it
func (k Keeper) burnWithNoCheck(ctx sdk.Context, classID string, nftID string) error {
owner := k.GetOwner(ctx, classID, nftID)
nftStore := k.getNFTStore(ctx, classID)
nftStore.Delete([]byte(nftID))
Expand All @@ -64,10 +79,17 @@ func (k Keeper) Update(ctx sdk.Context, token nft.NFT) error {
if !k.HasNFT(ctx, token.ClassId, token.Id) {
return sdkerrors.Wrap(nft.ErrNFTNotExists, token.Id)
}
k.setNFT(ctx, token)
k.updateWithNoCheck(ctx, token)
return nil
}

// Update defines a method for updating an exist nft
// Note: this method does not check whether the class already exists in nft.
// The upper-layer application needs to check it when it needs to use it
func (k Keeper) updateWithNoCheck(ctx sdk.Context, token nft.NFT) {
k.setNFT(ctx, token)
}

// Transfer defines a method for sending a nft from one account to another account.
// Note: When the upper module uses this method, it needs to authenticate nft
func (k Keeper) Transfer(ctx sdk.Context,
Expand All @@ -83,6 +105,18 @@ func (k Keeper) Transfer(ctx sdk.Context,
return sdkerrors.Wrap(nft.ErrNFTNotExists, nftID)
}

k.transferWithNoCheck(ctx, classID, nftID, receiver)
return nil
}

// Transfer defines a method for sending a nft from one account to another account.
// Note: this method does not check whether the class already exists in nft.
// The upper-layer application needs to check it when it needs to use it
func (k Keeper) transferWithNoCheck(ctx sdk.Context,
classID string,
nftID string,
receiver sdk.AccAddress,
) error {
owner := k.GetOwner(ctx, classID, nftID)
k.deleteOwner(ctx, classID, nftID, owner)
k.setOwner(ctx, classID, nftID, receiver)
Expand Down
84 changes: 84 additions & 0 deletions x/nft/keeper/nft_batch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/nft"
)

// BatchMint defines a method for minting a batch of nfts
func (k Keeper) BatchMint(ctx sdk.Context,
tokens []nft.NFT,
receiver sdk.AccAddress,
) error {
checked := make(map[string]bool, len(tokens))
for _, token := range tokens {
if !checked[token.ClassId] && !k.HasClass(ctx, token.ClassId) {
return sdkerrors.Wrap(nft.ErrClassNotExists, token.ClassId)
}

if k.HasNFT(ctx, token.ClassId, token.Id) {
return sdkerrors.Wrap(nft.ErrNFTExists, token.Id)
}

julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
checked[token.ClassId] = true
k.mintWithNoCheck(ctx, token, receiver)
}
return nil
}

// BatchBurn defines a method for burning a batch of nfts from a specific classID.
// Note: When the upper module uses this method, it needs to authenticate nft
func (k Keeper) BatchBurn(ctx sdk.Context, classID string, nftIDs []string) error {
if !k.HasClass(ctx, classID) {
return sdkerrors.Wrap(nft.ErrClassNotExists, classID)
}
for _, nftID := range nftIDs {
if !k.HasNFT(ctx, classID, nftID) {
return sdkerrors.Wrap(nft.ErrNFTNotExists, nftID)
}
if err := k.burnWithNoCheck(ctx, classID, nftID); err != nil {
return err
}
}
return nil
}

// BatchUpdate defines a method for updating a batch of exist nfts
// Note: When the upper module uses this method, it needs to authenticate nft
func (k Keeper) BatchUpdate(ctx sdk.Context, tokens []nft.NFT) error {
checked := make(map[string]bool, len(tokens))
for _, token := range tokens {
if !checked[token.ClassId] && !k.HasClass(ctx, token.ClassId) {
return sdkerrors.Wrap(nft.ErrClassNotExists, token.ClassId)
}

if !k.HasNFT(ctx, token.ClassId, token.Id) {
return sdkerrors.Wrap(nft.ErrNFTNotExists, token.Id)
}
checked[token.ClassId] = true
k.updateWithNoCheck(ctx, token)
}
return nil
}

// BatchTransfer defines a method for sending a batch of nfts from one account to another account from a specific classID.
// Note: When the upper module uses this method, it needs to authenticate nft
func (k Keeper) BatchTransfer(ctx sdk.Context,
classID string,
nftIDs []string,
receiver sdk.AccAddress,
) error {
if !k.HasClass(ctx, classID) {
return sdkerrors.Wrap(nft.ErrClassNotExists, classID)
}
for _, nftID := range nftIDs {
if !k.HasNFT(ctx, classID, nftID) {
return sdkerrors.Wrap(nft.ErrNFTNotExists, nftID)
}
if err := k.transferWithNoCheck(ctx, classID, nftID, receiver); err != nil {
return sdkerrors.Wrap(nft.ErrNFTNotExists, nftID)
}
}
return nil
}
Loading