diff --git a/substrate/frame/nft-fractionalization/src/lib.rs b/substrate/frame/nft-fractionalization/src/lib.rs index a6417cc3857d4ccc3f6f1385ebb5a04b7c097b9d..b1663e95d855d8af6def429236e11b55ba3ab891 100644 --- a/substrate/frame/nft-fractionalization/src/lib.rs +++ b/substrate/frame/nft-fractionalization/src/lib.rs @@ -338,12 +338,12 @@ pub mod pallet { T::PalletId::get().into_account_truncating() } - /// Transfer the NFT from the account holding that NFT to the pallet's account. + /// Prevent further transferring of NFT. fn do_lock_nft(nft_collection_id: T::NftCollectionId, nft_id: T::NftId) -> DispatchResult { T::Nfts::disable_transfer(&nft_collection_id, &nft_id) } - /// Transfer the NFT to the account returning the tokens. + /// Remove the transfer lock and transfer the NFT to the account returning the tokens. fn do_unlock_nft( nft_collection_id: T::NftCollectionId, nft_id: T::NftId, diff --git a/substrate/frame/nft-fractionalization/src/tests.rs b/substrate/frame/nft-fractionalization/src/tests.rs index 8564b80533e0dacb96ad898fda2b6268ef1261b1..b82402bda1e678a34a248378424ef02be6416e10 100644 --- a/substrate/frame/nft-fractionalization/src/tests.rs +++ b/substrate/frame/nft-fractionalization/src/tests.rs @@ -122,6 +122,33 @@ fn fractionalize_should_work() { beneficiary: account(2), })); + // owner can't burn an already fractionalized NFT + assert_noop!( + Nfts::burn(RuntimeOrigin::signed(account(1)), nft_collection_id, nft_id), + DispatchError::Module(ModuleError { + index: 4, + error: [12, 0, 0, 0], + message: Some("ItemLocked") + }) + ); + + // can't fractionalize twice + assert_noop!( + NftFractionalization::fractionalize( + RuntimeOrigin::signed(account(1)), + nft_collection_id, + nft_id, + asset_id + 1, + account(2), + fractions, + ), + DispatchError::Module(ModuleError { + index: 4, + error: [12, 0, 0, 0], + message: Some("ItemLocked") + }) + ); + let nft_id = nft_id + 1; assert_noop!( NftFractionalization::fractionalize( diff --git a/substrate/frame/nfts/src/features/create_delete_item.rs b/substrate/frame/nfts/src/features/create_delete_item.rs index a757273445f13135216bbe2c15f00198e4f7a217..e3d1334d48ef5960b8e0f85caaed314e90aa3a60 100644 --- a/substrate/frame/nfts/src/features/create_delete_item.rs +++ b/substrate/frame/nfts/src/features/create_delete_item.rs @@ -169,6 +169,10 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { with_details: impl FnOnce(&ItemDetailsFor<T, I>) -> DispatchResult, ) -> DispatchResult { ensure!(!T::Locker::is_locked(collection, item), Error::<T, I>::ItemLocked); + ensure!( + !Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?, + Error::<T, I>::ItemLocked + ); let item_config = Self::get_item_config(&collection, &item)?; // NOTE: if item's settings are not empty (e.g. item's metadata is locked) // then we keep the config record and don't remove it diff --git a/substrate/frame/nfts/src/impl_nonfungibles.rs b/substrate/frame/nfts/src/impl_nonfungibles.rs index b9e3951422ff43ebacb285dccb96a3476b02f10c..090a6a372c1eb12c752714de48dd8bb0aa2b99f3 100644 --- a/substrate/frame/nfts/src/impl_nonfungibles.rs +++ b/substrate/frame/nfts/src/impl_nonfungibles.rs @@ -341,6 +341,13 @@ impl<T: Config<I>, I: 'static> Transfer<T::AccountId> for Pallet<T, I> { } fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { + let transfer_disabled = + Self::has_system_attribute(&collection, &item, PalletAttributes::TransferDisabled)?; + // Can't lock the item twice + if transfer_disabled { + return Err(Error::<T, I>::ItemLocked.into()) + } + <Self as Mutate<T::AccountId, ItemConfig>>::set_attribute( collection, item,