git.delta.rocks / unique-network / refs/commits / c1189fc5c3c1

difftreelog

refactor(rmrk-proxy) better decoding

Fahrrader2022-06-02parent: #71b4dea.patch.diff
in: master

3 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
@@ -111,7 +111,7 @@
 		CorruptedCollectionType,
 		NftTypeEncodeError,
 		RmrkPropertyKeyIsTooLong,
-		RmrkPropertyValueIsTooLong, // todo utilize that in RPCs
+		RmrkPropertyValueIsTooLong,
 
 		/* RMRK compatible events */
 		CollectionNotEmpty,
@@ -518,7 +518,7 @@
 		Ok(scoped_key)
 	}
 
-	pub fn rmrk_property<E: Encode>(
+	pub fn rmrk_property<E: Encode>( // todo think about renaming this
 		rmrk_key: RmrkProperty,
 		value: &E,
 	) -> Result<Property, DispatchError> {
@@ -533,6 +533,21 @@
 
 		Ok(property)
 	}
+	
+	pub fn decode_property<D: Decode>(
+		vec: PropertyValue,
+	) -> Result<D, DispatchError> {
+		vec.decode().map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong.into())
+	}
+
+	pub fn rebind<L, S>(
+		vec: &BoundedVec<u8, L>,
+	) -> Result<BoundedVec<u8, S>, DispatchError> 
+	where 
+		BoundedVec<u8, S>: TryFrom<Vec<u8>> 
+	{
+		vec.rebind().map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong.into())
+	}
 
 	fn init_collection(
 		sender: T::CrossAccountId,
@@ -619,8 +634,7 @@
 		)?;
 
 		let resource_collection_id: CollectionId =
-			Self::get_nft_property(collection_id, token_id, ResourceCollection)?
-				.decode_or_default();
+			Self::get_nft_property_decoded(collection_id, token_id, ResourceCollection)?;
 		let resource_collection =
 			Self::get_typed_nft_collection(resource_collection_id, misc::CollectionType::Resource)?;
 
@@ -709,14 +723,19 @@
 		Ok(collection_property)
 	}
 
+	pub fn get_collection_property_decoded<V: Decode>(
+		collection_id: CollectionId,
+		key: RmrkProperty,
+	) -> Result<V, DispatchError> {
+		Self::decode_property(
+			Self::get_collection_property(collection_id, key)?
+		)
+	}
+
 	pub fn get_collection_type(
 		collection_id: CollectionId,
 	) -> Result<misc::CollectionType, DispatchError> {
-		let value = Self::get_collection_property(collection_id, CollectionType)?;
-
-		let mut value = value.as_slice();
-
-		misc::CollectionType::decode(&mut value)
+		Self::get_collection_property_decoded(collection_id, CollectionType)
 			.map_err(|_| <Error<T>>::CorruptedCollectionType.into())
 	}
 
@@ -749,12 +768,22 @@
 	) -> 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>>::NoAvailableNftId)? // todo replace with better error?
 			.clone();
 
 		Ok(nft_property)
 	}
 
+	pub fn get_nft_property_decoded<V: Decode>(
+		collection_id: CollectionId,
+		nft_id: TokenId,
+		key: RmrkProperty,
+	) -> Result<V, DispatchError> {
+		Self::decode_property(
+			Self::get_nft_property(collection_id, nft_id, key)?
+		)
+	}
+
 	pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
 		<TokenData<T>>::contains_key((collection_id, nft_id))
 	}
@@ -763,9 +792,8 @@
 		collection_id: CollectionId,
 		token_id: TokenId,
 	) -> Result<NftType, DispatchError> {
-		Ok(Self::get_nft_property(collection_id, token_id, TokenType)?.decode_or_default())
-		// todo throw error
-		// NftTypeEncodeError?
+		Self::get_nft_property_decoded(collection_id, token_id, TokenType)
+			.map_err(|_| <Error<T>>::NftTypeEncodeError.into())
 	}
 
 	pub fn ensure_nft_type(
@@ -814,18 +842,17 @@
 						let key: Key = key.try_into().ok()?;
 
 						let value = match token_id {
-							Some(token_id) => Self::get_nft_property(
+							Some(token_id) => Self::get_nft_property_decoded(
 								collection_id,
 								token_id,
 								UserProperty(key.as_ref()),
 							),
-							None => Self::get_collection_property(
+							None => Self::get_collection_property_decoded(
 								collection_id,
 								UserProperty(key.as_ref()),
 							),
 						}
-						.ok()?
-						.decode_or_default();
+						.ok()?;
 
 						Some(mapper(key, value))
 					})
@@ -862,7 +889,7 @@
 			let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;
 
 			let key: Key = key.to_vec().try_into().ok()?;
-			let value: Value = value.decode_or_default();
+			let value: Value = value.decode().ok()?;
 
 			Some(mapper(key, value))
 		});
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/misc.rs
+++ b/pallets/proxy-rmrk-core/src/misc.rs
@@ -1,6 +1,5 @@
 use super::*;
-use codec::{Encode, Decode};
-use derivative::Derivative;
+use codec::{Encode, Decode, Error};
 
 #[macro_export]
 macro_rules! map_common_err_to_proxy {
@@ -15,30 +14,30 @@
     };
 }
 
-pub trait RmrkDecode<T: Decode + Default, S> {
-	fn decode_or_default(&self) -> T;
+// Utilize the RmrkCore pallet for access to Runtime errors.
+pub trait RmrkDecode<T: Decode, S> {
+	fn decode(&self) -> Result<T, Error>;
 }
 
-// todo fail if unwrap doesn't work
-impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {
-	fn decode_or_default(&self) -> T {
+impl<T: Decode, S> RmrkDecode<T, S> for BoundedVec<u8, S> {
+	fn decode(&self) -> Result<T, Error> {
 		let mut value = self.as_slice();
 
-		T::decode(&mut value).unwrap_or_default()
+		T::decode(&mut value)
 	}
 }
 
+// Utilize the RmrkCore pallet for access to Runtime errors.
 pub trait RmrkRebind<T, S> {
-	fn rebind(&self) -> BoundedVec<u8, S>;
+	fn rebind(&self) -> Result<BoundedVec<u8, S>, Error>;
 }
 
-// todo fail if unwrap doesn't work
 impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T>
 where
 	BoundedVec<u8, S>: TryFrom<Vec<u8>>,
 {
-	fn rebind(&self) -> BoundedVec<u8, S> {
-		BoundedVec::<u8, S>::try_from(self.clone().into_inner()).unwrap_or_default()
+	fn rebind(&self) -> Result<BoundedVec<u8, S>, Error> {
+		BoundedVec::<u8, S>::try_from(self.clone().into_inner()).map_err(|_| "BoundedVec exceeds its limit".into())
 	}
 }
 
@@ -49,11 +48,8 @@
 	Base,
 }
 
-// todo remove default?
-#[derive(Encode, Decode, PartialEq, Eq, Derivative)]
-#[derivative(Default(bound = ""))]
+#[derive(Encode, Decode, PartialEq, Eq)]
 pub enum NftType {
-	#[derivative(Default)]
 	Regular,
 	Resource,
 	FixedPart,
@@ -61,11 +57,8 @@
 	Theme,
 }
 
-// todo remove default?
-#[derive(Encode, Decode, PartialEq, Eq, Derivative)]
-#[derivative(Default(bound = ""))]
+#[derive(Encode, Decode, PartialEq, Eq)]
 pub enum ResourceType {
-	#[derivative(Default)]
 	Basic,
 	Composable,
 	Slot,
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
144 }144 }
145145
146 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}};
148148
149 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) {
157157
158 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_count
164 }))164 }))
165 }165 }
185185
186 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()); }
283283
284 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)?;
287286
288 let resources = resource_collection287 let resources = resource_collection
289 .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()); }
334332
335 /*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()); }336
339337 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 property
342 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 decode
350346
351 Ok(priorities)347 Ok(priorities)
352 }348 }
353349
354 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 };
358354
359 let collection_id = RmrkCore::unique_collection_id(base_id)?;355 let collection_id = RmrkCore::unique_collection_id(base_id)?;
364360
365 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 }
371367
382378
383 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 _ => None
396 }392 }
415411
416 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 _ => None
421 }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()?;
443439
444 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::ThemeName
446 ).ok()?.decode_or_default();442 ).ok()?;
447443
448 if name == theme_name {444 if name == theme_name {
449 Some((name, token_id))445 Some((name, token_id))
467 }463 }
468 )?;464 )?;
469465
470 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::ThemeInherit
474 )?.decode_or_default();470 )?;
475471
476 let theme = RmrkTheme {472 let theme = RmrkTheme {
477 name,473 name,