Skip to content

Commit

Permalink
pallet-uniques: decrement total_deposit when clearing collection …
Browse files Browse the repository at this point in the history
…metadata (paritytech#3976)

Decrements `total_deposit` when collection metadata is cleared in
`pallet-nfts` and `pallet-uniques`.
  • Loading branch information
liamaharon authored Apr 6, 2024
1 parent 1c85bfe commit 9d62618
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 2 deletions.
14 changes: 14 additions & 0 deletions prdoc/pr_3976.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Decrement total_deposit when clearing collection metadata

doc:
- audience: Runtime Dev
description: Decrements total_deposit by the appropriate amount when collection metadata is cleared.

crates:
- name: pallet-uniques
bump: patch
- name: pallet-nfts
bump: patch
4 changes: 3 additions & 1 deletion substrate/frame/nfts/src/features/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
);
}

let details =
let mut details =
Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
let collection_config = Self::get_collection_config(&collection)?;

Expand All @@ -260,6 +260,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
CollectionMetadataOf::<T, I>::try_mutate_exists(collection, |metadata| {
let deposit = metadata.take().ok_or(Error::<T, I>::UnknownCollection)?.deposit;
T::Currency::unreserve(&details.owner, deposit);
details.owner_deposit.saturating_reduce(deposit);
Collection::<T, I>::insert(&collection, details);
Self::deposit_event(Event::CollectionMetadataCleared { collection });
Ok(())
})
Expand Down
41 changes: 41 additions & 0 deletions substrate/frame/nfts/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3835,3 +3835,44 @@ fn basic_create_collection_with_id_should_work() {
);
});
}

#[test]
fn clear_collection_metadata_works() {
new_test_ext().execute_with(|| {
// Start with an account with 100 tokens, 10 of which are reserved
Balances::make_free_balance_be(&account(1), 100);
Balances::reserve(&account(1), 10).unwrap();

// Creating a collection increases owner deposit by 2
assert_ok!(Nfts::create(
RuntimeOrigin::signed(account(1)),
account(1),
collection_config_with_all_settings_enabled()
));
assert_eq!(Collection::<Test>::get(0).unwrap().owner_deposit, 2);
assert_eq!(Balances::reserved_balance(&account(1)), 12);

// Setting collection metadata increases owner deposit by 10
assert_ok!(Nfts::set_collection_metadata(
RuntimeOrigin::signed(account(1)),
0,
bvec![0, 0, 0, 0, 0, 0, 0, 0, 0],
));
assert_eq!(Collection::<Test>::get(0).unwrap().owner_deposit, 12);
assert_eq!(Balances::reserved_balance(&account(1)), 22);

// Clearing collection metadata decreases owner deposit by 10
assert_ok!(Nfts::clear_collection_metadata(RuntimeOrigin::signed(account(1)), 0));
assert_eq!(Collection::<Test>::get(0).unwrap().owner_deposit, 2);
assert_eq!(Balances::reserved_balance(&account(1)), 12);

// Destroying the collection removes it from storage
assert_ok!(Nfts::destroy(
RuntimeOrigin::signed(account(1)),
0,
DestroyWitness { item_configs: 0, item_metadatas: 0, attributes: 0 }
));
assert_eq!(Collection::<Test>::get(0), None);
assert_eq!(Balances::reserved_balance(&account(1)), 10);
});
}
4 changes: 3 additions & 1 deletion substrate/frame/uniques/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1399,7 +1399,7 @@ pub mod pallet {
.map(|_| None)
.or_else(|origin| ensure_signed(origin).map(Some))?;

let details =
let mut details =
Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
if let Some(check_owner) = &maybe_check_owner {
ensure!(check_owner == &details.owner, Error::<T, I>::NoPermission);
Expand All @@ -1411,6 +1411,8 @@ pub mod pallet {

let deposit = metadata.take().ok_or(Error::<T, I>::UnknownCollection)?.deposit;
T::Currency::unreserve(&details.owner, deposit);
details.total_deposit.saturating_reduce(deposit);
Collection::<T, I>::insert(&collection, details);
Self::deposit_event(Event::CollectionMetadataCleared { collection });
Ok(())
})
Expand Down
38 changes: 38 additions & 0 deletions substrate/frame/uniques/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,3 +1062,41 @@ fn buy_item_should_work() {
}
});
}

#[test]
fn clear_collection_metadata_works() {
new_test_ext().execute_with(|| {
// Start with an account with 100 balance, 10 of which are reserved
Balances::make_free_balance_be(&1, 100);
Balances::reserve(&1, 10).unwrap();

// Create a Unique which increases total_deposit by 2
assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 123));
assert_eq!(Collection::<Test>::get(0).unwrap().total_deposit, 2);
assert_eq!(Balances::reserved_balance(&1), 12);

// Set collection metadata which increases total_deposit by 10
assert_ok!(Uniques::set_collection_metadata(
RuntimeOrigin::signed(1),
0,
bvec![0, 0, 0, 0, 0, 0, 0, 0, 0],
false
));
assert_eq!(Collection::<Test>::get(0).unwrap().total_deposit, 12);
assert_eq!(Balances::reserved_balance(&1), 22);

// Clearing collection metadata reduces total_deposit by the expected amount
assert_ok!(Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 0));
assert_eq!(Collection::<Test>::get(0).unwrap().total_deposit, 2);
assert_eq!(Balances::reserved_balance(&1), 12);

// Destroying the collection removes it from storage
assert_ok!(Uniques::destroy(
RuntimeOrigin::signed(1),
0,
DestroyWitness { items: 0, item_metadatas: 0, attributes: 0 }
));
assert_eq!(Collection::<Test>::get(0), None);
assert_eq!(Balances::reserved_balance(&1), 10);
});
}

0 comments on commit 9d62618

Please sign in to comment.