[NFTs] Rework permissions model (#13482)

* Disallow admin to transfer or burn items he doesn't own

* lock_collection should be accessible by collection's owner only

* Allow admin to access lock_item_properties()

* Fix do_lock_item_properties

* Move update_mint_settings() to Issuer

* Rename check_owner to check_origin

* Typo

* Make admin to be in charge of managing the metadata

* Make admin the main attributes manager

* offchain mint should be signed by Issuer

* Remove the special case when the Issuer calls the mint() function

* Rework burn and destroy methods

* Return back item_metadatas

* Don't repatriate the deposit on transfer

* A bit more tests

* One more test

* Add migration

* Chore

* Clippy

* Rename to owned_item

* Address comments

* Replace .filter_map with .find_map

* Improve version validation in pre_upgrade()

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_nfts

---------

Co-authored-by: parity-processbot <>
This commit is contained in:
Jegor Sidorenko
2023-03-13 10:25:46 +02:00
committed by GitHub
parent 66f3d9e237
commit f6b9e056ae
15 changed files with 968 additions and 802 deletions
@@ -66,6 +66,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
ensure!(existing_config == item_config, Error::<T, I>::InconsistentItemConfig);
} else {
ItemConfigOf::<T, I>::insert(&collection, &item, item_config);
collection_details.item_configs.saturating_inc();
}
T::Currency::reserve(&deposit_account, deposit_amount)?;
@@ -107,7 +108,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
let collection_details =
Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
ensure!(collection_details.owner == signer, Error::<T, I>::NoPermission);
ensure!(
Self::has_role(&collection, &signer, CollectionRole::Issuer),
Error::<T, I>::NoPermission
);
let item_config = ItemConfig { settings: Self::get_default_item_settings(&collection)? };
Self::do_mint(
@@ -118,9 +123,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
item_config,
|_, _| Ok(()),
)?;
let origin = Self::find_account_by_role(&collection, CollectionRole::Admin)
.unwrap_or(collection_details.owner.clone());
for (key, value) in attributes {
Self::do_set_attribute(
collection_details.owner.clone(),
origin.clone(),
collection,
Some(item),
AttributeNamespace::CollectionOwner,
@@ -131,7 +138,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
}
if !metadata.len().is_zero() {
Self::do_set_item_metadata(
Some(collection_details.owner.clone()),
Some(origin.clone()),
collection,
item,
metadata,
@@ -148,6 +155,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
) -> DispatchResult {
ensure!(!T::Locker::is_locked(collection, item), 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
let remove_config = !item_config.has_disabled_settings();
let owner = Collection::<T, I>::try_mutate(
&collection,
|maybe_collection_details| -> Result<T::AccountId, DispatchError> {
@@ -161,6 +171,10 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
T::Currency::unreserve(&details.deposit.account, details.deposit.amount);
collection_details.items.saturating_dec();
if remove_config {
collection_details.item_configs.saturating_dec();
}
// Clear the metadata if it's not locked.
if item_config.is_setting_enabled(ItemSetting::UnlockedMetadata) {
if let Some(metadata) = ItemMetadataOf::<T, I>::take(&collection, &item) {
@@ -188,9 +202,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
PendingSwapOf::<T, I>::remove(&collection, &item);
ItemAttributesApprovalsOf::<T, I>::remove(&collection, &item);
// NOTE: if item's settings are not empty (e.g. item's metadata is locked)
// then we keep the record and don't remove it
if !item_config.has_disabled_settings() {
if remove_config {
ItemConfigOf::<T, I>::remove(&collection, &item);
}