git.delta.rocks / unique-network / refs/commits / 5d82f750c78d

difftreelog

feat(rmrk) refactor resources

Daniel Shiposha2022-06-15parent: #f9272dd.patch.diff
in: master

5 files changed

modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -154,6 +154,7 @@
 		NftTypeEncodeError,
 		RmrkPropertyKeyIsTooLong,
 		RmrkPropertyValueIsTooLong,
+		RmrkPropertyIsNotFound,
 		UnableToDecodeRmrkData,
 
 		/* RMRK compatible events */
@@ -169,6 +170,7 @@
 		CannotAcceptNonOwnedNft,
 		CannotRejectNonOwnedNft,
 		ResourceNotPending,
+		NoAvailableResourceId,
 	}
 
 	#[pallet::call]
@@ -381,8 +383,8 @@
 					Self::rmrk_property(RoyaltyInfo, &royalty_info)?,
 					Self::rmrk_property(Metadata, &metadata)?,
 					Self::rmrk_property(Equipped, &false)?,
-					Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,
 					Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
+					Self::rmrk_property(NextResourceId, &(0 as RmrkResourceId))?,
 				]
 				.into_iter(),
 			)
@@ -653,6 +655,11 @@
 			collection.check_is_external()?;
 
 			ensure!(
+				<TokenData<T>>::get((collection_id, nft_id)).is_some(),
+				<Error<T>>::NoAvailableNftId
+			);
+
+			ensure!(
 				Self::get_nft_property_decoded(
 					collection_id,
 					nft_id,
@@ -686,7 +693,7 @@
 			origin: OriginFor<T>,
 			rmrk_collection_id: RmrkCollectionId,
 			rmrk_nft_id: RmrkNftId,
-			rmrk_resource_id: RmrkResourceId,
+			resource_id: RmrkResourceId,
 		) -> DispatchResult {
 			let sender = ensure_signed(origin)?;
 			let cross_sender = T::CrossAccountId::from_sub(sender);
@@ -698,42 +705,25 @@
 			collection.check_is_external()?;
 
 			let nft_id = rmrk_nft_id.into();
-			let resource_id = rmrk_resource_id.into();
 
 			let budget = budget::Value::new(NESTING_BUDGET);
 
 			let nft_owner =
 				<PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
-					.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
-
-			let resource_collection_id: Option<CollectionId> =
-				Self::get_nft_property_decoded(collection_id, nft_id, ResourceCollection)
 					.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
 
-			let resource_collection_id =
-				resource_collection_id.ok_or(<Error<T>>::ResourceDoesntExist)?;
-
-			let is_pending: bool = Self::get_nft_property_decoded(
-				resource_collection_id,
-				resource_id,
-				PendingResourceAccept,
-			)
-			.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
+			Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {
+				ensure!(res.pending, <Error<T>>::ResourceNotPending);
+				ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);
 
-			ensure!(is_pending, <Error<T>>::ResourceNotPending);
+				res.pending = false;
 
-			ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);
-
-			<PalletNft<T>>::set_scoped_token_property(
-				resource_collection_id,
-				rmrk_resource_id.into(),
-				PropertyScope::Rmrk,
-				Self::rmrk_property(PendingResourceAccept, &false)?,
-			)?;
+				Ok(())
+			})?;
 
 			Self::deposit_event(Event::<T>::ResourceAccepted {
 				nft_id: rmrk_nft_id,
-				resource_id: rmrk_resource_id,
+				resource_id,
 			});
 
 			Ok(())
@@ -746,7 +736,7 @@
 			origin: OriginFor<T>,
 			rmrk_collection_id: RmrkCollectionId,
 			rmrk_nft_id: RmrkNftId,
-			rmrk_resource_id: RmrkResourceId,
+			resource_id: RmrkResourceId,
 		) -> DispatchResult {
 			let sender = ensure_signed(origin)?;
 			let cross_sender = T::CrossAccountId::from_sub(sender);
@@ -758,7 +748,6 @@
 			collection.check_is_external()?;
 
 			let nft_id = rmrk_nft_id.into();
-			let resource_id = rmrk_resource_id.into();
 
 			let budget = budget::Value::new(NESTING_BUDGET);
 
@@ -767,43 +756,34 @@
 					.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
 
 			ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);
-
-			let resource_collection_id: Option<CollectionId> =
-				Self::get_nft_property_decoded(collection_id, nft_id, ResourceCollection)
-					.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
-
-			let resource_collection_id =
-				resource_collection_id.ok_or(<Error<T>>::ResourceDoesntExist)?;
 
-			let is_pending: bool = Self::get_nft_property_decoded(
-				resource_collection_id,
-				resource_id,
-				PendingResourceRemoval,
-			)
-			.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
+			let resource_id_key = Self::rmrk_property_key(ResourceId(resource_id))?;
 
-			ensure!(is_pending, <Error<T>>::ResourceNotPending);
-
-			let resource_collection = Self::get_typed_nft_collection(
-				resource_collection_id,
-				misc::CollectionType::Resource,
-			)?;
+			let resource_info = <PalletNft<T>>::token_sys_property((
+				collection_id,
+				nft_id,
+				PropertyScope::Rmrk,
+				resource_id_key.clone(),
+			))
+			.ok_or(<Error<T>>::ResourceDoesntExist)?;
 
-			let resource_data = <TokenData<T>>::get((resource_collection_id, resource_id))
-				.ok_or(<Error<T>>::ResourceDoesntExist)?;
+			let resource_info: RmrkResourceInfo = Self::decode_property(&resource_info)?;
 
-			let resource_owner = resource_data.owner;
+			ensure!(
+				resource_info.pending_removal,
+				<Error<T>>::ResourceNotPending
+			);
 
-			<PalletNft<T>>::burn(
-				&resource_collection,
-				&resource_owner,
-				rmrk_resource_id.into(),
-			)
-			.map_err(Self::map_unique_err_to_proxy)?;
+			<PalletNft<T>>::remove_token_sys_property(
+				collection_id,
+				nft_id,
+				PropertyScope::Rmrk,
+				resource_id_key,
+			);
 
 			Self::deposit_event(Event::<T>::ResourceRemovalAccepted {
 				nft_id: rmrk_nft_id,
-				resource_id: rmrk_resource_id,
+				resource_id,
 			});
 
 			Ok(())
@@ -1014,7 +994,7 @@
 				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
 			collection.check_is_external()?;
 
-			Self::resource_remove(sender, collection_id, nft_id.into(), resource_id.into())?;
+			Self::resource_remove(sender, collection_id, nft_id.into(), resource_id)?;
 
 			Self::deposit_event(Event::ResourceRemoval {
 				nft_id,
@@ -1043,17 +1023,27 @@
 	) -> Result<Property, DispatchError> {
 		let key = rmrk_key.to_key::<T>()?;
 
+		let value = Self::encode_property(value)?;
+
+		let property = Property { key, value };
+
+		Ok(property)
+	}
+
+	pub fn encode_property<E: Encode, S: Get<u32>>(
+		value: &E,
+	) -> Result<BoundedBytes<S>, DispatchError> {
 		let value = value
 			.encode()
 			.try_into()
 			.map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;
 
-		let property = Property { key, value };
-
-		Ok(property)
+		Ok(value)
 	}
 
-	pub fn decode_property<D: Decode>(vec: PropertyValue) -> Result<D, DispatchError> {
+	pub fn decode_property<D: Decode, S: Get<u32>>(
+		vec: &BoundedBytes<S>,
+	) -> Result<D, DispatchError> {
 		vec.decode()
 			.map_err(|_| <Error<T>>::UnableToDecodeRmrkData.into())
 	}
@@ -1153,67 +1143,32 @@
 		)
 	}
 
-	fn resource_add(
-		sender: T::AccountId,
+	fn acquire_next_resource_id(
 		collection_id: CollectionId,
 		nft_id: TokenId,
-		resource: RmrkResourceTypes,
 	) -> Result<RmrkResourceId, DispatchError> {
-		match resource {
-			RmrkResourceTypes::Basic(resource) => Self::resource_add_helper(
-				sender,
-				collection_id,
-				nft_id,
-				[
-					Self::rmrk_property(TokenType, &NftType::Resource)?,
-					Self::rmrk_property(ResourceType, &misc::ResourceType::Basic)?,
-					Self::rmrk_property(Src, &resource.src)?,
-					Self::rmrk_property(Metadata, &resource.metadata)?,
-					Self::rmrk_property(License, &resource.license)?,
-					Self::rmrk_property(Thumb, &resource.thumb)?,
-				]
-				.into_iter(),
-			),
-			RmrkResourceTypes::Composable(resource) => Self::resource_add_helper(
-				sender,
-				collection_id,
-				nft_id.into(),
-				[
-					Self::rmrk_property(TokenType, &NftType::Resource)?,
-					Self::rmrk_property(ResourceType, &misc::ResourceType::Composable)?,
-					Self::rmrk_property(Parts, &resource.parts)?,
-					Self::rmrk_property(Base, &resource.base)?,
-					Self::rmrk_property(Src, &resource.src)?,
-					Self::rmrk_property(Metadata, &resource.metadata)?,
-					Self::rmrk_property(License, &resource.license)?,
-					Self::rmrk_property(Thumb, &resource.thumb)?,
-				]
-				.into_iter(),
-			),
-			RmrkResourceTypes::Slot(resource) => Self::resource_add_helper(
-				sender,
-				collection_id,
-				nft_id.into(),
-				[
-					Self::rmrk_property(TokenType, &NftType::Resource)?,
-					Self::rmrk_property(ResourceType, &misc::ResourceType::Slot)?,
-					Self::rmrk_property(Base, &resource.base)?,
-					Self::rmrk_property(Src, &resource.src)?,
-					Self::rmrk_property(Metadata, &resource.metadata)?,
-					Self::rmrk_property(Slot, &resource.slot)?,
-					Self::rmrk_property(License, &resource.license)?,
-					Self::rmrk_property(Thumb, &resource.thumb)?,
-				]
-				.into_iter(),
-			),
-		}
+		let resource_id: RmrkResourceId =
+			Self::get_nft_property_decoded(collection_id, nft_id, NextResourceId)?;
+
+		let next_id = resource_id
+			.checked_add(1)
+			.ok_or(<Error<T>>::NoAvailableResourceId)?;
+
+		<PalletNft<T>>::set_scoped_token_property(
+			collection_id,
+			nft_id,
+			PropertyScope::Rmrk,
+			Self::rmrk_property(NextResourceId, &next_id)?,
+		)?;
+
+		Ok(resource_id)
 	}
 
-	fn resource_add_helper(
+	fn resource_add(
 		sender: T::AccountId,
 		collection_id: CollectionId,
-		token_id: TokenId,
-		resource_properties: impl Iterator<Item = Property>,
+		nft_id: TokenId,
+		resource: RmrkResourceTypes,
 	) -> Result<RmrkResourceId, DispatchError> {
 		let collection =
 			Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
@@ -1222,86 +1177,57 @@
 		let sender = T::CrossAccountId::from_sub(sender);
 		let budget = budget::Value::new(NESTING_BUDGET);
 
-		let nft_owner = <PalletStructure<T>>::find_topmost_owner(collection_id, token_id, &budget)
+		let nft_owner = <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
 			.map_err(Self::map_unique_err_to_proxy)?;
 
 		let pending = sender != nft_owner;
 
-		let resource_collection_id: Option<CollectionId> =
-			Self::get_nft_property_decoded(collection_id, token_id, ResourceCollection)?;
-
-		let resource_collection_id = match resource_collection_id {
-			Some(id) => id,
-			None => {
-				let resource_collection_id = Self::init_collection(
-					sender.clone(),
-					CreateCollectionData {
-						..Default::default()
-					},
-					[Self::rmrk_property(
-						CollectionType,
-						&misc::CollectionType::Resource,
-					)?]
-					.into_iter(),
-				)?;
+		let id = Self::acquire_next_resource_id(collection_id, nft_id)?;
 
-				<PalletNft<T>>::set_scoped_token_property(
-					collection_id,
-					token_id,
-					PropertyScope::Rmrk,
-					Self::rmrk_property(ResourceCollection, &Some(resource_collection_id))?,
-				)?;
-
-				resource_collection_id
-			}
+		let resource_info = RmrkResourceInfo {
+			id,
+			resource,
+			pending,
+			pending_removal: false,
 		};
 
-		let resource_collection =
-			Self::get_typed_nft_collection(resource_collection_id, misc::CollectionType::Resource)?;
+		<PalletNft<T>>::try_mutate_token_sys_property(
+			collection_id,
+			nft_id,
+			PropertyScope::Rmrk,
+			Self::rmrk_property_key(ResourceId(id))?,
+			|value| -> DispatchResult {
+				*value = Some(Self::encode_property(&resource_info)?);
 
-		// todo probably add extra connections to bases, slots, etc., when RMRK starts to use them
+				Ok(())
+			},
+		)?;
 
-		let resource_id = Self::create_nft(
-			&sender,
-			&nft_owner,
-			&resource_collection,
-			resource_properties.chain(
-				[
-					Self::rmrk_property(PendingResourceAccept, &pending)?,
-					Self::rmrk_property(PendingResourceRemoval, &false)?,
-				]
-				.into_iter(),
-			),
-		)
-		.map_err(|err| match err {
-			DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),
-			err => Self::map_unique_err_to_proxy(err),
-		})?;
-
-		Ok(resource_id.0)
+		Ok(id)
 	}
 
 	fn resource_remove(
 		sender: T::AccountId,
 		collection_id: CollectionId,
 		nft_id: TokenId,
-		resource_id: TokenId,
+		resource_id: RmrkResourceId,
 	) -> DispatchResult {
 		let collection =
 			Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
 		ensure!(collection.owner == sender, Error::<T>::NoPermission);
 
-		let resource_collection_id: Option<CollectionId> =
-			Self::get_nft_property_decoded(collection_id, nft_id, ResourceCollection)?;
-
-		let resource_collection_id =
-			resource_collection_id.ok_or(Error::<T>::ResourceDoesntExist)?;
+		let resource_id_key = Self::rmrk_property_key(ResourceId(resource_id))?;
+		let scope = PropertyScope::Rmrk;
 
-		let resource_collection =
-			Self::get_typed_nft_collection(resource_collection_id, misc::CollectionType::Resource)?;
 		ensure!(
-			<PalletNft<T>>::token_exists(&resource_collection, resource_id),
-			Error::<T>::ResourceDoesntExist
+			<PalletNft<T>>::token_sys_property((
+				collection_id,
+				nft_id,
+				scope,
+				resource_id_key.clone()
+			))
+			.is_some(),
+			<Error<T>>::ResourceDoesntExist
 		);
 
 		let budget = up_data_structs::budget::Value::new(NESTING_BUDGET);
@@ -1310,20 +1236,49 @@
 
 		let sender = T::CrossAccountId::from_sub(sender);
 		if topmost_owner == sender {
-			<PalletNft<T>>::burn(&resource_collection, &sender, resource_id)
-				.map_err(Self::map_unique_err_to_proxy)?;
-		} else {
-			<PalletNft<T>>::set_scoped_token_property(
-				resource_collection_id,
-				resource_id,
+			<PalletNft<T>>::remove_token_sys_property(
+				collection_id,
+				nft_id,
 				PropertyScope::Rmrk,
-				Self::rmrk_property(PendingResourceRemoval, &true)?,
-			)?;
+				Self::rmrk_property_key(ResourceId(resource_id))?,
+			);
+		} else {
+			Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {
+				res.pending_removal = true;
+
+				Ok(())
+			})?;
 		}
 
 		Ok(())
 	}
 
+	fn try_mutate_resource_info(
+		collection_id: CollectionId,
+		nft_id: TokenId,
+		resource_id: RmrkResourceId,
+		f: impl FnOnce(&mut RmrkResourceInfo) -> DispatchResult,
+	) -> DispatchResult {
+		<PalletNft<T>>::try_mutate_token_sys_property(
+			collection_id,
+			nft_id,
+			PropertyScope::Rmrk,
+			Self::rmrk_property_key(ResourceId(resource_id))?,
+			|value| match value {
+				Some(value) => {
+					let mut resource_info: RmrkResourceInfo = Self::decode_property(value)?;
+
+					f(&mut resource_info)?;
+
+					*value = Self::encode_property(&resource_info)?;
+
+					Ok(())
+				}
+				None => Err(<Error<T>>::ResourceDoesntExist.into()),
+			},
+		)
+	}
+
 	fn change_collection_owner(
 		collection_id: CollectionId,
 		collection_type: misc::CollectionType,
@@ -1397,7 +1352,7 @@
 		collection_id: CollectionId,
 		key: RmrkProperty,
 	) -> Result<V, DispatchError> {
-		Self::decode_property(Self::get_collection_property(collection_id, key)?)
+		Self::decode_property(&Self::get_collection_property(collection_id, key)?)
 	}
 
 	pub fn get_collection_type(
@@ -1450,7 +1405,7 @@
 	) -> Result<PropertyValue, DispatchError> {
 		let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
 			.get(&Self::rmrk_property_key(key)?)
-			.ok_or(<Error<T>>::NoAvailableNftId)? // todo replace with better error?
+			.ok_or(<Error<T>>::RmrkPropertyIsNotFound)?
 			.clone();
 
 		Ok(nft_property)
@@ -1461,7 +1416,7 @@
 		nft_id: TokenId,
 		key: RmrkProperty,
 	) -> Result<V, DispatchError> {
-		Self::decode_property(Self::get_nft_property(collection_id, nft_id, key)?)
+		Self::decode_property(&Self::get_nft_property(collection_id, nft_id, key)?)
 	}
 
 	pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
61#[derive(Encode, Decode, PartialEq, Eq)]61#[derive(Encode, Decode, PartialEq, Eq)]
62pub enum CollectionType {62pub enum CollectionType {
63 Regular,63 Regular,
64 Resource,
65 Base,64 Base,
66}65}
6766
68#[derive(Encode, Decode, PartialEq, Eq)]67#[derive(Encode, Decode, PartialEq, Eq)]
69pub enum NftType {68pub enum NftType {
70 Regular,69 Regular,
71 Resource,
72 FixedPart,70 FixedPart,
73 SlotPart,71 SlotPart,
74 Theme,72 Theme,
75}73}
76
77#[derive(Encode, Decode, PartialEq, Eq)]
78pub enum ResourceType {
79 Basic,
80 Composable,
81 Slot,
82}
8374
modifiedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/property.rs
+++ b/pallets/proxy-rmrk-core/src/property.rs
@@ -17,6 +17,8 @@
 use super::*;
 use core::convert::AsRef;
 
+const RESOURCE_ID_PREFIX: &str = "rsid-";
+
 pub enum RmrkProperty<'r> {
 	Metadata,
 	CollectionType,
@@ -25,18 +27,13 @@
 	Transferable,
 	RoyaltyInfo,
 	Equipped,
-	ResourceCollection,
 	ResourcePriorities,
-	ResourceType,
+	NextResourceId,
+	ResourceId(RmrkResourceId),
 	PendingNftAccept,
-	PendingResourceAccept,
-	PendingResourceRemoval,
 	Parts,
 	Base,
 	Src,
-	Slot,
-	License,
-	Thumb,
 	EquippedNft,
 	BaseType,
 	ExternalPartId,
@@ -72,18 +69,13 @@
 			Self::Transferable => key!("transferable"),
 			Self::RoyaltyInfo => key!("royalty-info"),
 			Self::Equipped => key!("equipped"),
-			Self::ResourceCollection => key!("resource-collection"),
 			Self::ResourcePriorities => key!("resource-priorities"),
-			Self::ResourceType => key!("resource-type"),
+			Self::NextResourceId => key!("next-resource-id"),
+			Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()),
 			Self::PendingNftAccept => key!("pending-nft-accept"),
-			Self::PendingResourceAccept => key!("pending-resource-accept"),
-			Self::PendingResourceRemoval => key!("pending-resource-removal"),
 			Self::Parts => key!("parts"),
 			Self::Base => key!("base"),
 			Self::Src => key!("src"),
-			Self::Slot => key!("slot"),
-			Self::License => key!("license"),
-			Self::Thumb => key!("thumb"),
 			Self::EquippedNft => key!("equipped-nft"),
 			Self::BaseType => key!("base-type"),
 			Self::ExternalPartId => key!("ext-part-id"),
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -75,9 +75,8 @@
 	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
 	TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
 	RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkThemeProperty, RmrkCollectionId,
-	RmrkNftId, RmrkAccountIdOrCollectionNftTuple, RmrkNftChild, RmrkPropertyKey, RmrkResourceTypes,
-	RmrkBasicResource, RmrkComposableResource, RmrkSlotResource, RmrkResourceId, RmrkBaseId,
-	RmrkFixedPart, RmrkSlotPart, RmrkString,
+	RmrkNftId, RmrkAccountIdOrCollectionNftTuple, RmrkNftChild, RmrkPropertyKey, RmrkResourceId,
+	RmrkBaseId, RmrkFixedPart, RmrkSlotPart, RmrkString,
 };
 
 // use pallet_contracts::weights::WeightInfo;
@@ -1501,8 +1500,8 @@
 		}
 
 		fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-			use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};
-			use pallet_common::CommonCollectionOperations;
+			use pallet_proxy_rmrk_core::misc::{CollectionType, NftType};
+			use up_data_structs::PropertyScope;
 
 			let collection_id = match RmrkCore::unique_collection_id(collection_id) {
 				Ok(id) => id,
@@ -1513,48 +1512,13 @@
 			let nft_id = TokenId(nft_id);
 			if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
 
-			let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;
+			let resources = <pallet_nonfungible::Pallet<Runtime>>::iterate_token_sys_properties(
+				collection_id, nft_id, PropertyScope::Rmrk
+			).filter_map(|(_, value)| {
+				let resource_info: RmrkResourceInfo = RmrkCore::decode_property(&value).ok()?;
 
-			let res_collection_id = match res_collection_id {
-				Some(id) => id,
-				None => return Ok(Vec::new())
-			};
-
-			let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;
-
-			let resources = resource_collection
-				.collection_tokens()
-				.iter()
-				.filter_map(|res_id| Some(RmrkResourceInfo {
-					id: res_id.0,
-					pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?,
-					pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?,
-					resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? {
-						ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {
-							src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,
-							metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,
-							license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,
-							thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,
-						}),
-						ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {
-							parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?,
-							base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,
-							src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,
-							metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,
-							license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,
-							thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,
-						}),
-						ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {
-							base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,
-							src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,
-							metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,
-							slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?,
-							license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,
-							thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,
-						}),
-					},
-				}))
-				.collect();
+				Some(resource_info)
+			}).collect();
 
 			Ok(resources)
 		}
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -75,9 +75,8 @@
 	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
 	TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
 	RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkThemeProperty, RmrkCollectionId,
-	RmrkNftId, RmrkAccountIdOrCollectionNftTuple, RmrkNftChild, RmrkPropertyKey, RmrkResourceTypes,
-	RmrkBasicResource, RmrkComposableResource, RmrkSlotResource, RmrkResourceId, RmrkBaseId,
-	RmrkFixedPart, RmrkSlotPart, RmrkString,
+	RmrkNftId, RmrkAccountIdOrCollectionNftTuple, RmrkNftChild, RmrkPropertyKey, RmrkResourceId,
+	RmrkBaseId, RmrkFixedPart, RmrkSlotPart, RmrkString,
 };
 
 // use pallet_contracts::weights::WeightInfo;
@@ -1501,8 +1500,8 @@
 		}
 
 		fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-			use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};
-			use pallet_common::CommonCollectionOperations;
+			use pallet_proxy_rmrk_core::misc::{CollectionType, NftType};
+			use up_data_structs::PropertyScope;
 
 			let collection_id = match RmrkCore::unique_collection_id(collection_id) {
 				Ok(id) => id,
@@ -1513,48 +1512,13 @@
 			let nft_id = TokenId(nft_id);
 			if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
 
-			let res_collection_id: Option<CollectionId> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;
+			let resources = <pallet_nonfungible::Pallet<Runtime>>::iterate_token_sys_properties(
+				collection_id, nft_id, PropertyScope::Rmrk
+			).filter_map(|(_, value)| {
+				let resource_info: RmrkResourceInfo = RmrkCore::decode_property(&value).ok()?;
 
-			let res_collection_id = match res_collection_id {
-				Some(id) => id,
-				None => return Ok(Vec::new())
-			};
-
-			let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;
-
-			let resources = resource_collection
-				.collection_tokens()
-				.iter()
-				.filter_map(|res_id| Some(RmrkResourceInfo {
-					id: res_id.0,
-					pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?,
-					pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?,
-					resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? {
-						ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {
-							src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,
-							metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,
-							license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,
-							thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,
-						}),
-						ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {
-							parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?,
-							base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,
-							src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,
-							metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,
-							license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,
-							thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,
-						}),
-						ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {
-							base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,
-							src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,
-							metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,
-							slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?,
-							license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,
-							thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,
-						}),
-					},
-				}))
-				.collect();
+				Some(resource_info)
+			}).collect();
 
 			Ok(resources)
 		}