difftreelog
refactor(rmrk-proxy) better decoding
in: master
3 files changed
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth111 CorruptedCollectionType,111 CorruptedCollectionType,112 NftTypeEncodeError,112 NftTypeEncodeError,113 RmrkPropertyKeyIsTooLong,113 RmrkPropertyKeyIsTooLong,114 RmrkPropertyValueIsTooLong, // todo utilize that in RPCs114 RmrkPropertyValueIsTooLong,115115116 /* RMRK compatible events */116 /* RMRK compatible events */117 CollectionNotEmpty,117 CollectionNotEmpty,518 Ok(scoped_key)518 Ok(scoped_key)519 }519 }520520521 pub fn rmrk_property<E: Encode>(521 pub fn rmrk_property<E: Encode>( // todo think about renaming this522 rmrk_key: RmrkProperty,522 rmrk_key: RmrkProperty,523 value: &E,523 value: &E,524 ) -> Result<Property, DispatchError> {524 ) -> Result<Property, DispatchError> {534 Ok(property)534 Ok(property)535 }535 }536 537 pub fn decode_property<D: Decode>(538 vec: PropertyValue,539 ) -> Result<D, DispatchError> {540 vec.decode().map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong.into())541 }542543 pub fn rebind<L, S>(544 vec: &BoundedVec<u8, L>,545 ) -> Result<BoundedVec<u8, S>, DispatchError> 546 where 547 BoundedVec<u8, S>: TryFrom<Vec<u8>> 548 {549 vec.rebind().map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong.into())550 }536551537 fn init_collection(552 fn init_collection(538 sender: T::CrossAccountId,553 sender: T::CrossAccountId,619 )?;634 )?;620635621 let resource_collection_id: CollectionId =636 let resource_collection_id: CollectionId =622 Self::get_nft_property(collection_id, token_id, ResourceCollection)?637 Self::get_nft_property_decoded(collection_id, token_id, ResourceCollection)?;623 .decode_or_default();624 let resource_collection =638 let resource_collection =625 Self::get_typed_nft_collection(resource_collection_id, misc::CollectionType::Resource)?;639 Self::get_typed_nft_collection(resource_collection_id, misc::CollectionType::Resource)?;626640709 Ok(collection_property)723 Ok(collection_property)710 }724 }725726 pub fn get_collection_property_decoded<V: Decode>(727 collection_id: CollectionId,728 key: RmrkProperty,729 ) -> Result<V, DispatchError> {730 Self::decode_property(731 Self::get_collection_property(collection_id, key)?732 )733 }711734712 pub fn get_collection_type(735 pub fn get_collection_type(713 collection_id: CollectionId,736 collection_id: CollectionId,714 ) -> Result<misc::CollectionType, DispatchError> {737 ) -> Result<misc::CollectionType, DispatchError> {715 let value = Self::get_collection_property(collection_id, CollectionType)?;738 Self::get_collection_property_decoded(collection_id, CollectionType)716717 let mut value = value.as_slice();718719 misc::CollectionType::decode(&mut value)720 .map_err(|_| <Error<T>>::CorruptedCollectionType.into())739 .map_err(|_| <Error<T>>::CorruptedCollectionType.into())721 }740 }722741723 pub fn ensure_collection_type(742 pub fn ensure_collection_type(749 ) -> Result<PropertyValue, DispatchError> {768 ) -> Result<PropertyValue, DispatchError> {750 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))769 let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))751 .get(&Self::rmrk_property_key(key)?)770 .get(&Self::rmrk_property_key(key)?)752 .ok_or(<Error<T>>::NoAvailableNftId)? // todo replace with better error771 .ok_or(<Error<T>>::NoAvailableNftId)? // todo replace with better error?753 .clone();772 .clone();754773755 Ok(nft_property)774 Ok(nft_property)756 }775 }776777 pub fn get_nft_property_decoded<V: Decode>(778 collection_id: CollectionId,779 nft_id: TokenId,780 key: RmrkProperty,781 ) -> Result<V, DispatchError> {782 Self::decode_property(783 Self::get_nft_property(collection_id, nft_id, key)?784 )785 }757786758 pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {787 pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {759 <TokenData<T>>::contains_key((collection_id, nft_id))788 <TokenData<T>>::contains_key((collection_id, nft_id))763 collection_id: CollectionId,792 collection_id: CollectionId,764 token_id: TokenId,793 token_id: TokenId,765 ) -> Result<NftType, DispatchError> {794 ) -> Result<NftType, DispatchError> {766 Ok(Self::get_nft_property(collection_id, token_id, TokenType)?.decode_or_default())795 Self::get_nft_property_decoded(collection_id, token_id, TokenType)767 // todo throw error796 .map_err(|_| <Error<T>>::NftTypeEncodeError.into())768 // NftTypeEncodeError?769 }797 }770798771 pub fn ensure_nft_type(799 pub fn ensure_nft_type(814 let key: Key = key.try_into().ok()?;842 let key: Key = key.try_into().ok()?;815843816 let value = match token_id {844 let value = match token_id {817 Some(token_id) => Self::get_nft_property(845 Some(token_id) => Self::get_nft_property_decoded(818 collection_id,846 collection_id,819 token_id,847 token_id,820 UserProperty(key.as_ref()),848 UserProperty(key.as_ref()),821 ),849 ),822 None => Self::get_collection_property(850 None => Self::get_collection_property_decoded(823 collection_id,851 collection_id,824 UserProperty(key.as_ref()),852 UserProperty(key.as_ref()),825 ),853 ),826 }854 }827 .ok()?828 .decode_or_default();855 .ok()?;829856830 Some(mapper(key, value))857 Some(mapper(key, value))831 })858 })862 let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;889 let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;863890864 let key: Key = key.to_vec().try_into().ok()?;891 let key: Key = key.to_vec().try_into().ok()?;865 let value: Value = value.decode_or_default();892 let value: Value = value.decode().ok()?;866893867 Some(mapper(key, value))894 Some(mapper(key, value))868 });895 });pallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth1use super::*;1use super::*;2use codec::{Encode, Decode};2use codec::{Encode, Decode, Error};3use derivative::Derivative;435#[macro_export]4#[macro_export]6macro_rules! map_common_err_to_proxy {5macro_rules! map_common_err_to_proxy {15 };14 };16}15}171617// Utilize the RmrkCore pallet for access to Runtime errors.18pub trait RmrkDecode<T: Decode + Default, S> {18pub trait RmrkDecode<T: Decode, S> {19 fn decode_or_default(&self) -> T;19 fn decode(&self) -> Result<T, Error>;20}20}212122// todo fail if unwrap doesn't work23impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {22impl<T: Decode, S> RmrkDecode<T, S> for BoundedVec<u8, S> {24 fn decode_or_default(&self) -> T {23 fn decode(&self) -> Result<T, Error> {25 let mut value = self.as_slice();24 let mut value = self.as_slice();262527 T::decode(&mut value).unwrap_or_default()26 T::decode(&mut value)28 }27 }29}28}302930// Utilize the RmrkCore pallet for access to Runtime errors.31pub trait RmrkRebind<T, S> {31pub trait RmrkRebind<T, S> {32 fn rebind(&self) -> BoundedVec<u8, S>;32 fn rebind(&self) -> Result<BoundedVec<u8, S>, Error>;33}33}343435// todo fail if unwrap doesn't work36impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T>35impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T>37where36where38 BoundedVec<u8, S>: TryFrom<Vec<u8>>,37 BoundedVec<u8, S>: TryFrom<Vec<u8>>,39{38{40 fn rebind(&self) -> BoundedVec<u8, S> {39 fn rebind(&self) -> Result<BoundedVec<u8, S>, Error> {41 BoundedVec::<u8, S>::try_from(self.clone().into_inner()).unwrap_or_default()40 BoundedVec::<u8, S>::try_from(self.clone().into_inner()).map_err(|_| "BoundedVec exceeds its limit".into())42 }41 }43}42}444349 Base,48 Base,50}49}515052// todo remove default?53#[derive(Encode, Decode, PartialEq, Eq, Derivative)]51#[derive(Encode, Decode, PartialEq, Eq)]54#[derivative(Default(bound = ""))]55pub enum NftType {52pub enum NftType {56 #[derivative(Default)]57 Regular,53 Regular,58 Resource,54 Resource,59 FixedPart,55 FixedPart,60 SlotPart,56 SlotPart,61 Theme,57 Theme,62}58}635964// todo remove default?65#[derive(Encode, Decode, PartialEq, Eq, Derivative)]60#[derive(Encode, Decode, PartialEq, Eq)]66#[derivative(Default(bound = ""))]67pub enum ResourceType {61pub enum ResourceType {68 #[derivative(Default)]69 Basic,62 Basic,70 Composable,63 Composable,71 Slot,64 Slot,runtime/common/src/runtime_apis.rsdiffbeforeafterboth144 }144 }145145146 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {146 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {147 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode, RmrkRebind}};147 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType}};148148149 let collection_id = RmrkCore::unique_collection_id(collection_id)?;149 let collection_id = RmrkCore::unique_collection_id(collection_id)?;150 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {150 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {157157158 Ok(Some(RmrkCollectionInfo {158 Ok(Some(RmrkCollectionInfo {159 issuer: collection.owner.clone(),159 issuer: collection.owner.clone(),160 metadata: RmrkCore::get_collection_property(collection_id, RmrkProperty::Metadata)?.decode_or_default(),160 metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?,161 max: collection.limits.token_limit,161 max: collection.limits.token_limit,162 symbol: collection.token_prefix.rebind(),162 symbol: RmrkCore::rebind(&collection.token_prefix)?,163 nfts_count163 nfts_count164 }))164 }))165 }165 }185185186 Ok(Some(RmrkInstanceInfo {186 Ok(Some(RmrkInstanceInfo {187 owner: owner,187 owner: owner,188 royalty: RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?.decode_or_default(),188 royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?,189 metadata: RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::Metadata)?.decode_or_default(),189 metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?,190 equipped: RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::Equipped)?.decode_or_default(),190 equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?,191 pending: allowance.is_some(),191 pending: allowance.is_some(),192 }))192 }))193 }193 }281 let nft_id = TokenId(nft_id);281 let nft_id = TokenId(nft_id);282 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }282 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }283283284 let res_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)?284 let res_collection_id: CollectionId = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?;285 .decode_or_default();286 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;285 let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;287286288 let resources = resource_collection287 let resources = resource_collection289 .collection_tokens()288 .collection_tokens()290 .iter()289 .iter()291 .filter_map(|(res_id)| Some(RmrkResourceInfo {290 .filter_map(|(res_id)| Some(RmrkResourceInfo {292 id: res_id.0,291 id: res_id.0,293 pending: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).unwrap().decode_or_default(),292 pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).unwrap(),294 pending_removal: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).unwrap().decode_or_default(),293 pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).unwrap(),295 resource: match RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::ResourceType).unwrap().decode_or_default() {294 resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).unwrap() {296 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {295 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {297 src: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Src).unwrap().decode_or_default(),296 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).unwrap(),298 metadata: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap().decode_or_default(),297 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap(),299 license: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::License).unwrap().decode_or_default(),298 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).unwrap(),300 thumb: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap().decode_or_default(),299 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap(),301 }),300 }),302 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {301 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {303 parts: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Parts).unwrap().decode_or_default(),302 parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).unwrap(),304 base: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Base).unwrap().decode_or_default(),303 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).unwrap(),305 src: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Src).unwrap().decode_or_default(),304 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).unwrap(),306 metadata: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap().decode_or_default(),305 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap(),307 license: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::License).unwrap().decode_or_default(),306 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).unwrap(),308 thumb: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap().decode_or_default(),307 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap(),309 }),308 }),310 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {309 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {311 base: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Base).unwrap().decode_or_default(),310 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).unwrap(),312 src: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Src).unwrap().decode_or_default(),311 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).unwrap(),313 metadata: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap().decode_or_default(),312 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap(),314 slot: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Slot).unwrap().decode_or_default(),313 slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).unwrap(),315 license: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::License).unwrap().decode_or_default(),314 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).unwrap(),316 thumb: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap().decode_or_default(),315 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap(),317 }),316 }),318 // todo refactor :|319 },317 },320 }))318 }))321 .collect();319 .collect();332 let nft_id = TokenId(nft_id);330 let nft_id = TokenId(nft_id);333 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }331 if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }334332335 /*let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)333 /*let resource_collection_id: CollectionId = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)336 .unwrap()334 .unwrap();337 .decode_or_default();335 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }338 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }336339337 let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))340 let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))338 .filter_map(|(resource_id, properties)| Some((341 .filter_map(|(resource_id, properties)| Some((339 resource_id, // ResourceId property342 resource_id, // ResourceId property340 RmrkCore::get_nft_property_decoded(resource_collection_id, resource_id, RmrkProperty::Priority).unwrap(),343 RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::Priority).unwrap().decode_or_default(),341 )))344 )))342 .collect()345 .collect()343 .sort_by_key(|(_, index)| *index)346 .sort_by_key(|(_, index)| *index)344 .into_iter().map(|(resource_id, _)| resource_id)*/347 .into_iter().map(|(resource_id, _)| resource_id)*/348 let priorities = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourcePriorities)?.decode_or_default();345 let priorities = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?;349 // todo let it simply be default here after removing default from decode350346351 Ok(priorities)347 Ok(priorities)352 }348 }353349354 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {350 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {355 use pallet_proxy_rmrk_core::{351 use pallet_proxy_rmrk_core::{356 RmrkProperty, misc::{CollectionType, RmrkDecode, RmrkRebind},352 RmrkProperty, misc::{CollectionType},357 };353 };358354359 let collection_id = RmrkCore::unique_collection_id(base_id)?;355 let collection_id = RmrkCore::unique_collection_id(base_id)?;364360365 Ok(Some(RmrkBaseInfo {361 Ok(Some(RmrkBaseInfo {366 issuer: collection.owner.clone(),362 issuer: collection.owner.clone(),367 base_type: RmrkCore::get_collection_property(collection_id, RmrkProperty::BaseType)?.decode_or_default(),363 base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?,368 symbol: collection.token_prefix.rebind(),364 symbol: RmrkCore::rebind(&collection.token_prefix)?,369 }))365 }))370 }366 }371367382378383 match nft_type {379 match nft_type {384 NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {380 NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {385 id: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?.decode_or_default(),381 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,386 src: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::Src).ok()?.decode_or_default(),382 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,387 z: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::ZIndex).ok()?.decode_or_default(),383 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,388 })),384 })),389 NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {385 NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {390 id: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?.decode_or_default(),386 id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?,391 src: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::Src).ok()?.decode_or_default(),387 src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?,392 z: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::ZIndex).ok()?.decode_or_default(),388 z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?,393 equippable: RmrkCore::get_nft_property(collection_id, token_id, RmrkProperty::EquippableList).ok()?.decode_or_default(),389 equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?,394 })),390 })),395 _ => None391 _ => None396 }392 }415411416 match nft_type {412 match nft_type {417 Theme => Some(413 Theme => Some(418 RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::ThemeName).unwrap().decode_or_default()414 RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).unwrap()419 ),415 ),420 _ => None416 _ => None421 }417 }441 .find_map(|token_id| {437 .find_map(|token_id| {442 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;438 RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;443439444 let name: RmrkString = RmrkCore::get_nft_property(440 let name: RmrkString = RmrkCore::get_nft_property_decoded(445 collection_id, token_id, RmrkProperty::ThemeName441 collection_id, token_id, RmrkProperty::ThemeName446 ).ok()?.decode_or_default();442 ).ok()?;447443448 if name == theme_name {444 if name == theme_name {449 Some((name, token_id))445 Some((name, token_id))467 }463 }468 )?;464 )?;469465470 let inherit = RmrkCore::get_nft_property(466 let inherit = RmrkCore::get_nft_property_decoded(471 collection_id,467 collection_id,472 theme_id,468 theme_id,473 RmrkProperty::ThemeInherit469 RmrkProperty::ThemeInherit474 )?.decode_or_default();470 )?;475471476 let theme = RmrkTheme {472 let theme = RmrkTheme {477 name,473 name,