Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Improve NFT locking (#14510)
Browse files Browse the repository at this point in the history
* Update docs

* Prevent locking of the same NFT twice

* Validate item is not locked on burn

* Cover with tests

* chore
  • Loading branch information
jsidorenko authored Jul 5, 2023
1 parent 29ef477 commit 67b14ad
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 2 deletions.
4 changes: 2 additions & 2 deletions frame/nft-fractionalization/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
27 changes: 27 additions & 0 deletions frame/nft-fractionalization/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 4 additions & 0 deletions frame/nfts/src/features/create_delete_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions frame/nfts/src/impl_nonfungibles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 67b14ad

Please sign in to comment.