From bcc6ae1b8331b07e432fc47ca0a52533f6a26a82 Mon Sep 17 00:00:00 2001 From: Sergej Sakac Date: Wed, 1 Feb 2023 20:57:39 +0100 Subject: [PATCH] Introduce Entity enum --- pallets/rmrk-core/src/functions.rs | 58 +++++++++++++++++++----------- pallets/rmrk-core/src/lib.rs | 30 +++++++++++----- pallets/rmrk-core/src/tests.rs | 29 +++++++-------- traits/src/entity.rs | 19 ++++++++++ traits/src/lib.rs | 2 ++ traits/src/property.rs | 10 +++--- 6 files changed, 100 insertions(+), 48 deletions(-) create mode 100644 traits/src/entity.rs diff --git a/pallets/rmrk-core/src/functions.rs b/pallets/rmrk-core/src/functions.rs index 74174ccd..fd440198 100644 --- a/pallets/rmrk-core/src/functions.rs +++ b/pallets/rmrk-core/src/functions.rs @@ -46,7 +46,11 @@ impl priority_index += 1; } Self::deposit_event(Event::PrioritySet { collection_id, nft_id }); - Ok(Some(::WeightInfo::set_priority(priority_index, T::NestingBudget::get())).into()) + Ok(Some(::WeightInfo::set_priority( + priority_index, + T::NestingBudget::get(), + )) + .into()) } } @@ -55,40 +59,52 @@ impl Property, ValueLimitOf, T::AccountId, T::Collec { fn property_set( sender: T::AccountId, - collection_id: T::CollectionId, - maybe_nft_id: Option, + entity: EntityOf, key: KeyLimitOf, value: ValueLimitOf, ) -> DispatchResult { - let collection = - Collections::::get(&collection_id).ok_or(Error::::CollectionUnknown)?; - ensure!(collection.issuer == sender, Error::::NoPermission); - if let Some(nft_id) = &maybe_nft_id { - // Check NFT lock status - ensure!( - !Pallet::::is_locked(collection_id, *nft_id), - pallet_uniques::Error::::Locked - ); - let budget = budget::Value::new(T::NestingBudget::get()); - let (root_owner, _) = Pallet::::lookup_root_owner(collection_id, *nft_id, &budget)?; - ensure!(root_owner == collection.issuer, Error::::NoPermission); + match entity { + Entity::Collection(_collection_id) => todo!(), + Entity::Nft(collection_id, nft_id) => { + let collection = + Collections::::get(&collection_id).ok_or(Error::::CollectionUnknown)?; + ensure!(collection.issuer == sender, Error::::NoPermission); + // Check NFT lock status + ensure!( + !Pallet::::is_locked(collection_id, nft_id), + pallet_uniques::Error::::Locked + ); + let budget = budget::Value::new(T::NestingBudget::get()); + let (root_owner, _) = + Pallet::::lookup_root_owner(collection_id, nft_id, &budget)?; + ensure!(root_owner == collection.issuer, Error::::NoPermission); + + Properties::::insert((&collection_id, Some(nft_id), &key), &value); + }, + Entity::Base(_base_id) => todo!(), + Entity::Part(_part_id) => todo!(), } - Properties::::insert((&collection_id, maybe_nft_id, &key), &value); Ok(()) } // Internal function to set a property for downstream `Origin::root()` calls. fn do_set_property( - collection_id: T::CollectionId, - maybe_nft_id: Option, + entity: EntityOf, key: KeyLimitOf, value: ValueLimitOf, ) -> sp_runtime::DispatchResult { // Ensure collection exists - Collections::::get(&collection_id).ok_or(Error::::CollectionUnknown)?; - Properties::::insert((&collection_id, maybe_nft_id, &key), &value); + match entity { + Entity::Collection(_collection_id) => todo!(), + Entity::Nft(collection_id, nft_id) => { + Collections::::get(&collection_id).ok_or(Error::::CollectionUnknown)?; + Properties::::insert((&collection_id, Some(nft_id), &key), &value); + }, + Entity::Base(_base_id) => todo!(), + Entity::Part(_part_id) => todo!(), + } - Self::deposit_event(Event::PropertySet { collection_id, maybe_nft_id, key, value }); + Self::deposit_event(Event::PropertySet { entity, key, value }); Ok(()) } diff --git a/pallets/rmrk-core/src/lib.rs b/pallets/rmrk-core/src/lib.rs index 2d303ff7..9d17b76a 100644 --- a/pallets/rmrk-core/src/lib.rs +++ b/pallets/rmrk-core/src/lib.rs @@ -22,8 +22,8 @@ use rmrk_traits::{ misc::TransferHooks, primitives::{BaseId, PartId, ResourceId, SlotId}, AccountIdOrCollectionNftTuple, BasicResource, Collection, CollectionInfo, ComposableResource, - Nft, NftChild, NftInfo, PhantomType, Priority, Property, PropertyInfo, Resource, ResourceInfo, - ResourceInfoMin, ResourceTypes, RoyaltyInfo, SlotResource, + Entity, Nft, NftChild, NftInfo, PhantomType, Priority, Property, PropertyInfo, Resource, + ResourceInfo, ResourceInfoMin, ResourceTypes, RoyaltyInfo, SlotResource, }; use sp_std::result::Result; @@ -86,6 +86,13 @@ pub type BoundedResourceInfoTypeOf = BoundedVec< pub type PropertyInfoOf = PropertyInfo, ValueLimitOf>; +pub type EntityOf = Entity< + ::CollectionId, + ::ItemId, + BaseId, + PartId, +>; + pub mod types; // Re-export pallet items so that they can be accessed from the crate namespace. @@ -262,6 +269,12 @@ pub mod pallet { OptionQuery, >; + #[pallet::storage] + #[pallet::getter(fn base_properties)] + /// Arbitrary properties / metadata of a base. + pub type BaseProperties = + StorageMap<_, Twox64Concat, BaseId, ValueLimitOf, OptionQuery>; + #[pallet::storage] #[pallet::getter(fn lock)] /// Lock for NFTs @@ -331,8 +344,7 @@ pub mod pallet { collection_id: T::CollectionId, }, PropertySet { - collection_id: T::CollectionId, - maybe_nft_id: Option, + entity: EntityOf, key: KeyLimitOf, value: ValueLimitOf, }, @@ -483,7 +495,7 @@ pub mod pallet { /// - `recipient`: Receiver of the royalty /// - `royalty`: Permillage reward from each trade for the Recipient /// - `metadata`: Arbitrary data about an nft, e.g. IPFS hash - #[pallet::call_index(1)] + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::mint_nft_directly_to_nft(T::NestingBudget::get()))] #[transactional] pub fn mint_nft_directly_to_nft( @@ -705,18 +717,18 @@ pub mod pallet { #[transactional] pub fn set_property( origin: OriginFor, - collection_id: T::CollectionId, - maybe_nft_id: Option, + entity: EntityOf, key: KeyLimitOf, value: ValueLimitOf, ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::property_set(sender, collection_id, maybe_nft_id, key.clone(), value.clone())?; + Self::property_set(sender, entity.clone(), key.clone(), value.clone())?; - Self::deposit_event(Event::PropertySet { collection_id, maybe_nft_id, key, value }); + Self::deposit_event(Event::PropertySet { entity, key, value }); Ok(()) } + /// lock collection #[pallet::call_index(10)] #[pallet::weight(::WeightInfo::lock_collection())] diff --git a/pallets/rmrk-core/src/tests.rs b/pallets/rmrk-core/src/tests.rs index 41d2b312..3eae72bd 100644 --- a/pallets/rmrk-core/src/tests.rs +++ b/pallets/rmrk-core/src/tests.rs @@ -10,7 +10,6 @@ use sp_runtime::Permill; use super::*; use mock::{RuntimeEvent as MockEvent, RuntimeOrigin as Origin, *}; use pallet_uniques as UNQ; -use rmrk_traits::budget::Budget; use sp_std::convert::TryInto; type RMRKCore = Pallet; @@ -1799,9 +1798,11 @@ fn set_property_works() { let key = stbk("test-key"); // Define property value let value = stb("test-value"); + // Define the entity. + let nft = Entity::Nft(0, 0); // set_property fails without a collection (CollectionUnknown) assert_noop!( - RMRKCore::set_property(Origin::signed(ALICE), 0, Some(0), key.clone(), value.clone()), + RMRKCore::set_property(Origin::signed(ALICE), nft.clone(), key.clone(), value.clone()), Error::::CollectionUnknown ); // Create a basic collection @@ -1811,15 +1812,13 @@ fn set_property_works() { // ALICE sets property on NFT assert_ok!(RMRKCore::set_property( Origin::signed(ALICE), - 0, - Some(0), + nft.clone(), key.clone(), value.clone() )); // Successful property setting should trigger a PropertySet event System::assert_last_event(MockEvent::RmrkCore(crate::Event::PropertySet { - collection_id: 0, - maybe_nft_id: Some(0), + entity: nft.clone(), key: key.clone(), value: value.clone(), })); @@ -1827,7 +1826,7 @@ fn set_property_works() { assert_eq!(RMRKCore::properties((0, Some(0), key.clone())).unwrap(), value.clone()); // BOB does not own NFT so attempt to set property should fail assert_noop!( - RMRKCore::set_property(Origin::signed(BOB), 0, Some(0), key.clone(), value.clone()), + RMRKCore::set_property(Origin::signed(BOB), nft, key.clone(), value.clone()), Error::::NoPermission ); }); @@ -1840,9 +1839,11 @@ fn set_property_with_internal_works() { let key = stbk("test-key"); // Define property value let value = stb("test-value"); + // Define the entity. + let nft = Entity::Nft(0, 0); // set_property fails without a collection (CollectionUnknown) assert_noop!( - RMRKCore::do_set_property(0, Some(0), key.clone(), value.clone()), + RMRKCore::do_set_property(nft.clone(), key.clone(), value.clone()), Error::::CollectionUnknown ); // Create a basic collection @@ -1850,11 +1851,10 @@ fn set_property_with_internal_works() { // Mint NFT assert_ok!(basic_mint(0)); // Root sets property on NFT - assert_ok!(RMRKCore::do_set_property(0, Some(0), key.clone(), value.clone())); + assert_ok!(RMRKCore::do_set_property(nft.clone(), key.clone(), value.clone())); // Successful property setting should trigger a PropertySet event System::assert_last_event(MockEvent::RmrkCore(crate::Event::PropertySet { - collection_id: 0, - maybe_nft_id: Some(0), + entity: nft, key: key.clone(), value: value.clone(), })); @@ -1870,16 +1870,17 @@ fn remove_property_with_internal_works() { let key = stbk("test-key"); // Define property value let value = stb("test-value"); + // Define the entity. + let nft = Entity::Nft(0, 0); // Create a basic collection assert_ok!(basic_collection()); // Mint NFT assert_ok!(basic_mint(0)); // Root sets property on NFT - assert_ok!(RMRKCore::do_set_property(0, Some(0), key.clone(), value.clone())); + assert_ok!(RMRKCore::do_set_property(nft.clone(), key.clone(), value.clone())); // Successful property setting should trigger a PropertySet event System::assert_last_event(MockEvent::RmrkCore(crate::Event::PropertySet { - collection_id: 0, - maybe_nft_id: Some(0), + entity: nft, key: key.clone(), value: value.clone(), })); diff --git a/traits/src/entity.rs b/traits/src/entity.rs new file mode 100644 index 00000000..71e0546f --- /dev/null +++ b/traits/src/entity.rs @@ -0,0 +1,19 @@ +// Copyright (C) 2021-2022 RMRK +// This file is part of rmrk-substrate. +// License: Apache 2.0 modified by RMRK, see LICENSE.md + +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::*; +use scale_info::TypeInfo; + +#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen, Clone, PartialEq)] +pub enum Entity { + /// The entity is a collection + Collection(CollectionId), + /// The entity is a collection nft + Nft(CollectionId, ItemId), + /// The entity is a base + Base(BaseId), + /// The entity is a Part + Part(PartId), +} diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 2aba091f..118300bb 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -7,6 +7,7 @@ pub mod base; pub mod budget; pub mod collection; +pub mod entity; pub mod misc; pub mod nft; pub mod part; @@ -19,6 +20,7 @@ pub mod theme; pub use base::{Base, BaseInfo}; pub use collection::{Collection, CollectionInfo}; +pub use entity::Entity; pub use misc::TransferHooks; pub use nft::{AccountIdOrCollectionNftTuple, Nft, NftChild, NftInfo, RoyaltyInfo}; pub use part::{EquippableList, FixedPart, PartType, SlotPart}; diff --git a/traits/src/property.rs b/traits/src/property.rs index f1613c18..208de7b0 100644 --- a/traits/src/property.rs +++ b/traits/src/property.rs @@ -2,6 +2,10 @@ // This file is part of rmrk-substrate. // License: Apache 2.0 modified by RMRK, see LICENSE.md +use crate::{ + primitives::{BaseId, PartId}, + Entity, +}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::DispatchResult; @@ -35,16 +39,14 @@ pub struct PropertyInfo { pub trait Property { fn property_set( sender: AccountId, - collection_id: CollectionId, - maybe_nft_id: Option, + enity: Entity, key: KeyLimit, value: ValueLimit, ) -> DispatchResult; /// Internal function to set a property that can be called from `Origin::root()` downstream. fn do_set_property( - collection_id: CollectionId, - maybe_nft_id: Option, + entity: Entity, key: KeyLimit, value: ValueLimit, ) -> DispatchResult;