From 5d82f750c78d7d2e4bf4aef669a4219a25a606d0 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Wed, 15 Jun 2022 15:16:54 +0000 Subject: [PATCH] feat(rmrk): refactor resources --- --- 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::)?, Self::rmrk_property(ResourcePriorities, &>::new())?, + Self::rmrk_property(NextResourceId, &(0 as RmrkResourceId))?, ] .into_iter(), ) @@ -653,6 +655,11 @@ collection.check_is_external()?; ensure!( + >::get((collection_id, nft_id)).is_some(), + >::NoAvailableNftId + ); + + ensure!( Self::get_nft_property_decoded( collection_id, nft_id, @@ -686,7 +693,7 @@ origin: OriginFor, 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 = >::find_topmost_owner(collection_id, nft_id, &budget) - .map_err(|_| >::ResourceDoesntExist)?; - - let resource_collection_id: Option = - Self::get_nft_property_decoded(collection_id, nft_id, ResourceCollection) .map_err(|_| >::ResourceDoesntExist)?; - let resource_collection_id = - resource_collection_id.ok_or(>::ResourceDoesntExist)?; - - let is_pending: bool = Self::get_nft_property_decoded( - resource_collection_id, - resource_id, - PendingResourceAccept, - ) - .map_err(|_| >::ResourceDoesntExist)?; + Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| { + ensure!(res.pending, >::ResourceNotPending); + ensure!(cross_sender == nft_owner, >::NoPermission); - ensure!(is_pending, >::ResourceNotPending); + res.pending = false; - ensure!(cross_sender == nft_owner, >::NoPermission); - - >::set_scoped_token_property( - resource_collection_id, - rmrk_resource_id.into(), - PropertyScope::Rmrk, - Self::rmrk_property(PendingResourceAccept, &false)?, - )?; + Ok(()) + })?; Self::deposit_event(Event::::ResourceAccepted { nft_id: rmrk_nft_id, - resource_id: rmrk_resource_id, + resource_id, }); Ok(()) @@ -746,7 +736,7 @@ origin: OriginFor, 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(|_| >::ResourceDoesntExist)?; ensure!(cross_sender == nft_owner, >::NoPermission); - - let resource_collection_id: Option = - Self::get_nft_property_decoded(collection_id, nft_id, ResourceCollection) - .map_err(|_| >::ResourceDoesntExist)?; - - let resource_collection_id = - resource_collection_id.ok_or(>::ResourceDoesntExist)?; - let is_pending: bool = Self::get_nft_property_decoded( - resource_collection_id, - resource_id, - PendingResourceRemoval, - ) - .map_err(|_| >::ResourceDoesntExist)?; + let resource_id_key = Self::rmrk_property_key(ResourceId(resource_id))?; - ensure!(is_pending, >::ResourceNotPending); - - let resource_collection = Self::get_typed_nft_collection( - resource_collection_id, - misc::CollectionType::Resource, - )?; + let resource_info = >::token_sys_property(( + collection_id, + nft_id, + PropertyScope::Rmrk, + resource_id_key.clone(), + )) + .ok_or(>::ResourceDoesntExist)?; - let resource_data = >::get((resource_collection_id, resource_id)) - .ok_or(>::ResourceDoesntExist)?; + let resource_info: RmrkResourceInfo = Self::decode_property(&resource_info)?; - let resource_owner = resource_data.owner; + ensure!( + resource_info.pending_removal, + >::ResourceNotPending + ); - >::burn( - &resource_collection, - &resource_owner, - rmrk_resource_id.into(), - ) - .map_err(Self::map_unique_err_to_proxy)?; + >::remove_token_sys_property( + collection_id, + nft_id, + PropertyScope::Rmrk, + resource_id_key, + ); Self::deposit_event(Event::::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 { let key = rmrk_key.to_key::()?; + let value = Self::encode_property(value)?; + + let property = Property { key, value }; + + Ok(property) + } + + pub fn encode_property>( + value: &E, + ) -> Result, DispatchError> { let value = value .encode() .try_into() .map_err(|_| >::RmrkPropertyValueIsTooLong)?; - let property = Property { key, value }; - - Ok(property) + Ok(value) } - pub fn decode_property(vec: PropertyValue) -> Result { + pub fn decode_property>( + vec: &BoundedBytes, + ) -> Result { vec.decode() .map_err(|_| >::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 { - 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(>::NoAvailableResourceId)?; + + >::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, + nft_id: TokenId, + resource: RmrkResourceTypes, ) -> Result { 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 = >::find_topmost_owner(collection_id, token_id, &budget) + let nft_owner = >::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 = - 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)?; - >::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)?; + >::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(_) => >::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::::NoPermission); - let resource_collection_id: Option = - Self::get_nft_property_decoded(collection_id, nft_id, ResourceCollection)?; - - let resource_collection_id = - resource_collection_id.ok_or(Error::::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!( - >::token_exists(&resource_collection, resource_id), - Error::::ResourceDoesntExist + >::token_sys_property(( + collection_id, + nft_id, + scope, + resource_id_key.clone() + )) + .is_some(), + >::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 { - >::burn(&resource_collection, &sender, resource_id) - .map_err(Self::map_unique_err_to_proxy)?; - } else { - >::set_scoped_token_property( - resource_collection_id, - resource_id, + >::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 { + >::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(>::ResourceDoesntExist.into()), + }, + ) + } + fn change_collection_owner( collection_id: CollectionId, collection_type: misc::CollectionType, @@ -1397,7 +1352,7 @@ collection_id: CollectionId, key: RmrkProperty, ) -> Result { - 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 { let nft_property = >::token_properties((collection_id, nft_id)) .get(&Self::rmrk_property_key(key)?) - .ok_or(>::NoAvailableNftId)? // todo replace with better error? + .ok_or(>::RmrkPropertyIsNotFound)? .clone(); Ok(nft_property) @@ -1461,7 +1416,7 @@ nft_id: TokenId, key: RmrkProperty, ) -> Result { - 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 { --- a/pallets/proxy-rmrk-core/src/misc.rs +++ b/pallets/proxy-rmrk-core/src/misc.rs @@ -61,22 +61,13 @@ #[derive(Encode, Decode, PartialEq, Eq)] pub enum CollectionType { Regular, - Resource, Base, } #[derive(Encode, Decode, PartialEq, Eq)] pub enum NftType { Regular, - Resource, FixedPart, SlotPart, Theme, -} - -#[derive(Encode, Decode, PartialEq, Eq)] -pub enum ResourceType { - Basic, - Composable, - Slot, } --- 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"), --- 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, 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 = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?; + let resources = >::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) } --- 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, 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 = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?; + let resources = >::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) } -- gitstuff