From 58c58c2c583c0cf7730c7b674ac28b38f5c3f9cb Mon Sep 17 00:00:00 2001 From: zjb0807 <zjb0807@qq.com> Date: Fri, 20 Nov 2020 09:03:24 +0800 Subject: [PATCH] add feature disable-tokens-by-owner (#323) --- Makefile | 2 ++ nft/Cargo.toml | 1 + nft/src/lib.rs | 56 ++++++++++++++++++++++++++++-------------------- nft/src/tests.rs | 2 +- 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 9b45dce..afee442 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ check-tests: githooks test: githooks ./scripts/run.sh test + cargo test --manifest-path nft/Cargo.toml -p orml-nft --features disable-tokens-by-owner GITHOOKS_SRC = $(wildcard githooks/*) GITHOOKS_DEST = $(patsubst githooks/%, $(GITHOOK)/%, $(GITHOOKS_SRC)) @@ -47,3 +48,4 @@ dev-check-tests: Cargo.toml dev-test: Cargo.toml cargo test --all + cargo test --manifest-path nft/Cargo.toml -p orml-nft --features disable-tokens-by-owner diff --git a/nft/Cargo.toml b/nft/Cargo.toml index eb4e8c8..96cd44b 100644 --- a/nft/Cargo.toml +++ b/nft/Cargo.toml @@ -28,3 +28,4 @@ std = [ "frame-support/std", "frame-system/std", ] +disable-tokens-by-owner = [] diff --git a/nft/src/lib.rs b/nft/src/lib.rs index c27cb50..a7a8e81 100644 --- a/nft/src/lib.rs +++ b/nft/src/lib.rs @@ -106,6 +106,7 @@ decl_storage! { /// Returns `None` if token info not set or removed. pub Tokens get(fn tokens): double_map hasher(twox_64_concat) T::ClassId, hasher(twox_64_concat) T::TokenId => Option<TokenInfoOf<T>>; /// Token existence check by owner and class ID. + #[cfg(not(feature = "disable-tokens-by-owner"))] pub TokensByOwner get(fn tokens_by_owner): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) (T::ClassId, T::TokenId) => Option<()>; } } @@ -141,21 +142,23 @@ impl<T: Trait> Module<T> { /// Transfer NFT(non fungible token) from `from` account to `to` account pub fn transfer(from: &T::AccountId, to: &T::AccountId, token: (T::ClassId, T::TokenId)) -> DispatchResult { - TokensByOwner::<T>::try_mutate_exists(from, token, |token_by_owner| -> DispatchResult { - ensure!(token_by_owner.is_some(), Error::<T>::NoPermission); + Tokens::<T>::try_mutate(token.0, token.1, |token_info| -> DispatchResult { + let mut info = token_info.as_mut().ok_or(Error::<T>::TokenNotFound)?; + ensure!(info.owner == *from, Error::<T>::NoPermission); if from == to { // no change needed return Ok(()); } - *token_by_owner = None; - TokensByOwner::<T>::insert(to, token, ()); + info.owner = to.clone(); - Tokens::<T>::try_mutate_exists(token.0, token.1, |token_info| -> DispatchResult { - let mut info = token_info.as_mut().ok_or(Error::<T>::TokenNotFound)?; - info.owner = to.clone(); - Ok(()) - }) + #[cfg(not(feature = "disable-tokens-by-owner"))] + { + TokensByOwner::<T>::remove(from, token); + TokensByOwner::<T>::insert(to, token, ()); + } + + Ok(()) }) } @@ -185,6 +188,7 @@ impl<T: Trait> Module<T> { data, }; Tokens::<T>::insert(class_id, token_id, token_info); + #[cfg(not(feature = "disable-tokens-by-owner"))] TokensByOwner::<T>::insert(owner, (class_id, token_id), ()); Ok(token_id) @@ -194,20 +198,22 @@ impl<T: Trait> Module<T> { /// Burn NFT(non fungible token) from `owner` pub fn burn(owner: &T::AccountId, token: (T::ClassId, T::TokenId)) -> DispatchResult { Tokens::<T>::try_mutate_exists(token.0, token.1, |token_info| -> DispatchResult { - ensure!(token_info.take().is_some(), Error::<T>::TokenNotFound); - - TokensByOwner::<T>::try_mutate_exists(owner, token, |info| -> DispatchResult { - ensure!(info.take().is_some(), Error::<T>::NoPermission); - - Classes::<T>::try_mutate(token.0, |class_info| -> DispatchResult { - let info = class_info.as_mut().ok_or(Error::<T>::ClassNotFound)?; - info.total_issuance = info - .total_issuance - .checked_sub(&One::one()) - .ok_or(Error::<T>::NumOverflow)?; - Ok(()) - }) - }) + let t = token_info.take().ok_or(Error::<T>::TokenNotFound)?; + ensure!(t.owner == *owner, Error::<T>::NoPermission); + + Classes::<T>::try_mutate(token.0, |class_info| -> DispatchResult { + let info = class_info.as_mut().ok_or(Error::<T>::ClassNotFound)?; + info.total_issuance = info + .total_issuance + .checked_sub(&One::one()) + .ok_or(Error::<T>::NumOverflow)?; + Ok(()) + })?; + + #[cfg(not(feature = "disable-tokens-by-owner"))] + TokensByOwner::<T>::remove(owner, token); + + Ok(()) }) } @@ -225,6 +231,10 @@ impl<T: Trait> Module<T> { } pub fn is_owner(account: &T::AccountId, token: (T::ClassId, T::TokenId)) -> bool { + #[cfg(feature = "disable-tokens-by-owner")] + return Tokens::<T>::get(token.0, token.1).map_or(false, |token| token.owner == *account); + + #[cfg(not(feature = "disable-tokens-by-owner"))] TokensByOwner::<T>::contains_key(account, token) } } diff --git a/nft/src/tests.rs b/nft/src/tests.rs index ef94784..7208292 100644 --- a/nft/src/tests.rs +++ b/nft/src/tests.rs @@ -87,7 +87,7 @@ fn transfer_should_fail() { assert_ok!(NonFungibleTokenModule::mint(&BOB, CLASS_ID, vec![1], ())); assert_noop!( NonFungibleTokenModule::transfer(&BOB, &ALICE, (CLASS_ID, TOKEN_ID_NOT_EXIST)), - Error::<Runtime>::NoPermission + Error::<Runtime>::TokenNotFound ); assert_noop!( NonFungibleTokenModule::transfer(&ALICE, &BOB, (CLASS_ID, TOKEN_ID)), -- GitLab