git.delta.rocks / unique-network / refs/commits / 00b9fd625e6d

difftreelog

feat initial rmrk send impl

Daniel Shiposha2022-06-03parent: #70623cc.patch.diff
in: master

10 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1298,6 +1298,7 @@
 		spender: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
+		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
 	fn transfer_from(
 		&self,
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
226 spender: T::CrossAccountId,226 spender: T::CrossAccountId,
227 token: TokenId,227 token: TokenId,
228 amount: u128,228 amount: u128,
229 _nesting_budget: &dyn Budget,
229 ) -> DispatchResultWithPostInfo {230 ) -> DispatchResultWithPostInfo {
230 ensure!(231 ensure!(
231 token == TokenId::default(),232 token == TokenId::default(),
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -308,14 +308,15 @@
 		spender: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
+		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo {
 		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
 
 		with_weight(
 			if amount == 1 {
-				<Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))
+				<Pallet<T>>::set_allowance(self, &sender, token, Some(&spender), nesting_budget)
 			} else {
-				<Pallet<T>>::set_allowance(self, &sender, token, None)
+				<Pallet<T>>::set_allowance(self, &sender, token, None, nesting_budget)
 			},
 			<CommonWeights<T>>::approve(),
 		)
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -269,8 +269,11 @@
 		let caller = T::CrossAccountId::from_eth(caller);
 		let approved = T::CrossAccountId::from_eth(approved);
 		let token = token_id.try_into()?;
+		let budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
 
-		<Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))
+		<Pallet<T>>::set_allowance(self, &caller, token, Some(&approved), &budget)
 			.map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -878,6 +878,7 @@
 		sender: &T::CrossAccountId,
 		token: TokenId,
 		spender: Option<&T::CrossAccountId>,
+		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
 		if collection.permissions.access() == AccessMode::AllowList {
 			collection.check_allowlist(sender)?;
@@ -889,9 +890,16 @@
 		if let Some(spender) = spender {
 			<PalletCommon<T>>::ensure_correct_receiver(spender)?;
 		}
-		let token_data =
-			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
-		if &token_data.owner != sender {
+
+		let is_owned = <PalletStructure<T>>::check_indirectly_owned(
+			sender.clone(),
+			collection.id,
+			token,
+			None,
+			nesting_budget
+		)?;
+
+		if !is_owned {
 			ensure!(
 				collection.ignores_owned_amount(sender),
 				<CommonError<T>>::CantApproveMoreThanOwned
@@ -918,6 +926,9 @@
 			// `from`, `to` checked in [`transfer`]
 			collection.check_allowlist(spender)?;
 		}
+		if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {
+			return Ok(());
+		}
 		if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {
 			// TODO: should collection owner be allowed to perform this transfer?
 			ensure!(
@@ -930,9 +941,6 @@
 				)?,
 				<CommonError<T>>::ApprovedValueTooLow,
 			);
-			return Ok(());
-		}
-		if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {
 			return Ok(());
 		}
 		ensure!(
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -20,7 +20,7 @@
 use frame_system::{pallet_prelude::*, ensure_signed};
 use sp_runtime::{DispatchError, Permill, traits::StaticLookup};
 use sp_std::vec::Vec;
-use up_data_structs::*;
+use up_data_structs::{*, mapping::TokenAddressMapping};
 use pallet_common::{
 	Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,
 };
@@ -39,6 +39,8 @@
 
 use RmrkProperty::*;
 
+const NESTING_BUDGET: u32 = 5;
+
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
@@ -56,10 +58,13 @@
 	pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;
 
 	#[pallet::storage]
-	#[pallet::getter(fn collection_index_map)]
-	pub type CollectionIndexMap<T: Config> =
+	pub type UniqueCollectionId<T: Config> =
 		StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, ValueQuery>;
 
+	#[pallet::storage]
+	pub type RmrkInernalCollectionId<T: Config> =
+		StorageMap<_, Twox64Concat, CollectionId, RmrkCollectionId, ValueQuery>;
+
 	#[pallet::pallet]
 	#[pallet::generate_store(pub(super) trait Store)]
 	pub struct Pallet<T>(_);
@@ -151,10 +156,12 @@
 					.into_inner()
 					.try_into()
 					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
+				permissions: Some(CollectionPermissions {
+					nesting: Some(NestingRule::Owner),
+					..Default::default()
+				}),
 				..Default::default()
 			};
-
-			<CollectionIndex<T>>::mutate(|n| *n += 1);
 
 			let unique_collection_id = Self::init_collection(
 				T::CrossAccountId::from_sub(sender.clone()),
@@ -167,7 +174,10 @@
 			)?;
 			let rmrk_collection_id = <CollectionIndex<T>>::get();
 
-			<CollectionIndexMap<T>>::insert(rmrk_collection_id, unique_collection_id);
+			<UniqueCollectionId<T>>::insert(rmrk_collection_id, unique_collection_id);
+			<RmrkInernalCollectionId<T>>::insert(unique_collection_id, rmrk_collection_id);
+
+			<CollectionIndex<T>>::mutate(|n| *n += 1);
 
 			Self::deposit_event(Event::CollectionCreated {
 				issuer: sender,
@@ -356,6 +366,81 @@
 
 		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
 		#[transactional]
+		pub fn send(
+			origin: OriginFor<T>,
+			rmrk_collection_id: RmrkCollectionId,
+			rmrk_nft_id: RmrkNftId,
+			new_owner: RmrkAccountIdOrCollectionNftTuple<T::AccountId>,
+		) -> DispatchResult {
+			let sender = ensure_signed(origin.clone())?;
+			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
+
+			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
+			let nft_id = rmrk_nft_id.into();
+
+			let token_data = <TokenData<T>>::get((collection_id, nft_id))
+				.ok_or(<Error<T>>::NoAvailableNftId)?;
+
+			let from = token_data.owner;
+
+			let collection = Self::get_typed_nft_collection(
+				collection_id,
+				misc::CollectionType::Regular,
+			)?;
+
+			let budget = budget::Value::new(NESTING_BUDGET);
+
+			let target_owner;
+
+			match new_owner {
+				RmrkAccountIdOrCollectionNftTuple::AccountId(account_id) => {
+					target_owner = T::CrossAccountId::from_sub(account_id);
+				},
+				RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(target_collection_id, target_nft_id) => {
+					let target_collection_id = Self::unique_collection_id(target_collection_id)?;
+
+					target_owner = T::CrossTokenAddressMapping::token_to_address(
+						target_collection_id,
+						target_nft_id.into(),
+					);
+
+					let spender = <PalletStructure<T>>::get_indirect_owner(
+						target_collection_id,
+						target_nft_id.into(),
+						Some((collection_id, nft_id)),
+						&budget,
+					)?;
+
+					let is_approval_required = cross_sender != spender;
+
+					if is_approval_required {
+						<PalletNft<T>>::set_allowance(
+							&collection,
+							&cross_sender,
+							nft_id,
+							Some(&spender),
+							&budget
+						).map_err(Self::map_common_err_to_proxy)?;
+
+						return Ok(());
+					}
+				}
+			}
+
+			<PalletNft<T>>::transfer_from(
+				&collection,
+				&cross_sender,
+				&from,
+				&target_owner,
+				nft_id,
+				&budget
+			).map_err(Self::map_common_err_to_proxy)?;
+
+			Ok(())
+		}
+
+		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+		#[transactional]
 		pub fn set_property(
 			origin: OriginFor<T>,
 			#[pallet::compact] rmrk_collection_id: RmrkCollectionId,
@@ -367,12 +452,13 @@
 			let sender = T::CrossAccountId::from_sub(sender);
 
 			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
+			let budget = budget::Value::new(NESTING_BUDGET);
 
 			match maybe_nft_id {
 				Some(nft_id) => {
 					let token_id: TokenId = nft_id.into();
 
-					Self::ensure_nft_owner(collection_id, token_id, &sender)?;
+					Self::ensure_nft_owner(collection_id, token_id, &sender, &budget)?;
 					Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;
 
 					<PalletNft<T>>::set_scoped_token_property(
@@ -607,7 +693,7 @@
 			owner: owner.clone(),
 		};
 
-		let budget = budget::Value::new(2);
+		let budget = budget::Value::new(NESTING_BUDGET);
 
 		<PalletNft<T>>::create_item(collection, sender, data, &budget)?;
 
@@ -651,14 +737,8 @@
 		//ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);
 
 		let sender = T::CrossAccountId::from_sub(sender);
-		let budget = budget::Value::new(10);
-		let pending = !<PalletStructure<T>>::check_indirectly_owned(
-			sender.clone(),
-			collection_id,
-			token_id,
-			None,
-			&budget,
-		)?;
+		let budget = budget::Value::new(NESTING_BUDGET);
+		let pending = Self::ensure_nft_owner(collection_id, token_id, &sender, &budget).is_err();
 
 		let resource_collection_id: CollectionId =
 			Self::get_nft_property_decoded(collection_id, token_id, ResourceCollection)?;
@@ -757,7 +837,14 @@
 	pub fn unique_collection_id(
 		rmrk_collection_id: RmrkCollectionId,
 	) -> Result<CollectionId, DispatchError> {
-		<CollectionIndexMap<T>>::try_get(rmrk_collection_id)
+		<UniqueCollectionId<T>>::try_get(rmrk_collection_id)
+			.map_err(|_| <Error<T>>::CollectionUnknown.into())
+	}
+
+	pub fn rmrk_collection_id(
+		unique_collection_id: CollectionId
+	) -> Result<RmrkCollectionId, DispatchError> {
+		<RmrkInernalCollectionId<T>>::try_get(unique_collection_id)
 			.map_err(|_| <Error<T>>::CollectionUnknown.into())
 	}
 
@@ -873,12 +960,18 @@
 		collection_id: CollectionId,
 		token_id: TokenId,
 		possible_owner: &T::CrossAccountId,
+		nesting_budget: &dyn budget::Budget
 	) -> DispatchResult {
-		let token_data =
-			<TokenData<T>>::get((collection_id, token_id)).ok_or(<Error<T>>::NoAvailableNftId)?;
+		let is_owned = <PalletStructure<T>>::check_indirectly_owned(
+			possible_owner.clone(),
+			collection_id,
+			token_id,
+			None,
+			nesting_budget,
+		)?;
 
 		ensure!(
-			token_data.owner == *possible_owner,
+			is_owned,
 			<Error<T>>::NoPermission
 		);
 
@@ -965,7 +1058,8 @@
 				NoPermission => NoPermission,
 				CollectionTokenLimitExceeded => CollectionFullOrLocked,
 				PublicMintingNotAllowed => NoPermission,
-				TokenNotFound => NoAvailableNftId
+				TokenNotFound => NoAvailableNftId,
+				ApprovedValueTooLow => NoPermission
 			}
 		}
 	}
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -254,6 +254,7 @@
 		spender: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
+		_nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo {
 		with_weight(
 			<Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -149,19 +149,12 @@
 		})
 	}
 
-	/// Check if token indirectly owned by specified user
-	pub fn check_indirectly_owned(
-		user: T::CrossAccountId,
+	pub fn get_indirect_owner(
 		collection: CollectionId,
 		token: TokenId,
 		for_nest: Option<(CollectionId, TokenId)>,
 		budget: &dyn Budget,
-	) -> Result<bool, DispatchError> {
-		let target_parent = match T::CrossTokenAddressMapping::address_to_token(&user) {
-			Some((collection, token)) => Self::find_topmost_owner(collection, token, budget)?,
-			None => user,
-		};
-
+	) -> Result<T::CrossAccountId, DispatchError> {
 		// Tried to nest token in itself
 		if Some((collection, token)) == for_nest {
 			return Err(<Error<T>>::OuroborosDetected.into());
@@ -173,10 +166,8 @@
 				Parent::Token(collection, token) if Some((collection, token)) == for_nest => {
 					return Err(<Error<T>>::OuroborosDetected.into())
 				}
-				// Found needed parent, token is indirecty owned
-				Parent::User(user) if user == target_parent => return Ok(true),
 				// Token is owned by other user
-				Parent::User(_) => return Ok(false),
+				Parent::User(user) => return Ok(user),
 				Parent::TokenNotFound => return Err(<Error<T>>::TokenNotFound.into()),
 				// Continue parent chain
 				Parent::Token(_, _) => {}
@@ -199,6 +190,27 @@
 		dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)
 	}
 
+	/// Check if token indirectly owned by specified user
+	pub fn check_indirectly_owned(
+		user: T::CrossAccountId,
+		collection: CollectionId,
+		token: TokenId,
+		for_nest: Option<(CollectionId, TokenId)>,
+		budget: &dyn Budget,
+	) -> Result<bool, DispatchError> {
+		let target_parent = match T::CrossTokenAddressMapping::address_to_token(&user) {
+			Some((collection, token)) => Self::find_topmost_owner(collection, token, budget)?,
+			None => user,
+		};
+
+		Self::get_indirect_owner(
+			collection,
+			token,
+			for_nest,
+			budget
+		).map(|indirect_owner| indirect_owner == target_parent)
+	}
+
 	pub fn check_nesting(
 		from: T::CrossAccountId,
 		under: &T::CrossAccountId,
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -815,8 +815,9 @@
 		#[transactional]
 		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
+			let budget = budget::Value::new(NESTING_BUDGET);
 
-			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))
+			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount, &budget))
 		}
 
 		/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -147,7 +147,11 @@
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};
                     use pallet_common::CommonCollectionOperations;
 
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(None)
+                    };
+
                     let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {
                         Ok(c) => c,
                         Err(_) => return Ok(None),
@@ -169,7 +173,10 @@
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};
                     use pallet_common::CommonCollectionOperations;
 
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(None)
+                    };
                     let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {
                         Ok(c) => c,
                         Err(_) => return Ok(None),
@@ -180,7 +187,11 @@
 
                     let owner = match collection.token_owner(nft_id) {
                         Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {
-                            Some((col, tok)) => RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(col.0, tok.0),
+                            Some((col, tok)) => {
+                                let rmrk_collection = RmrkCore::rmrk_collection_id(col)?;
+
+                                RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)
+                            }
                             None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())
                         },
                         None => return Ok(None)
@@ -202,11 +213,11 @@
                     use pallet_common::CommonCollectionOperations;
 
                     let cross_account_id = CrossAccountId::from_sub(account_id);
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
-                    let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {
-                        Ok(c) => c,
-                        Err(_) => return Ok(Vec::new()),
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
                     };
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
 
                     Ok(
                         collection.account_tokens(cross_account_id)
@@ -217,28 +228,35 @@
                 }
 
                 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
+                    };
                     let nft_id = TokenId(nft_id);
                     if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }
 
                     Ok(
                         pallet_nonfungible::TokenChildren::<Runtime>::iter_prefix((collection_id, nft_id))
-                            .filter_map(|(child_id, is_child)|
-                                match is_child {
-                                    true => Some(RmrkNftChild {
-                                        collection_id: child_id.0.0,
-                                        nft_id: child_id.1.0,
-                                    }),
-                                    false => None,
-                                }
-                            ).collect()
+                            .filter_map(|((child_collection, child_token), _)| {
+                                let rmrk_child_collection = RmrkCore::rmrk_collection_id(
+                                    child_collection
+                                ).ok()?;
+
+                                Some(RmrkNftChild {
+                                    collection_id: rmrk_child_collection,
+                                    nft_id: child_token.0,
+                                })
+                            }).collect()
                     )
                 }
 
                 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
                     use pallet_proxy_rmrk_core::misc::CollectionType;
 
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
+                    };
                     if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {
                         return Ok(Vec::new());
                     }
@@ -259,7 +277,10 @@
                 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
                     use pallet_proxy_rmrk_core::misc::NftType;
 
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
+                    };
                     let token_id = TokenId(nft_id);
 
                     if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
@@ -283,7 +304,10 @@
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};
                     use pallet_common::CommonCollectionOperations;
 
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
+                    };
                     if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
 
                     let nft_id = TokenId(nft_id);
@@ -332,7 +356,10 @@
                 fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};
 
-                    let collection_id = RmrkCore::unique_collection_id(collection_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(collection_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
+                    };
                     if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
 
                     let nft_id = TokenId(nft_id);
@@ -360,7 +387,10 @@
                         RmrkProperty, misc::{CollectionType},
                     };
 
-                    let collection_id = RmrkCore::unique_collection_id(base_id)?;
+                    let collection_id = match RmrkCore::unique_collection_id(base_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(None)
+                    };
                     let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {
                         Ok(c) => c,
                         Err(_) => return Ok(None),
@@ -377,12 +407,11 @@
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};
                     use pallet_common::CommonCollectionOperations;
 
-                    let collection_id = RmrkCore::unique_collection_id(base_id)?;
-                    let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {
-                        Ok(c) => c,
-                        Err(_) => return Ok(Vec::new()),
+                    let collection_id = match RmrkCore::unique_collection_id(base_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
                     };
-
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }
 
                     let parts = collection.collection_tokens()
                         .into_iter()
@@ -413,11 +442,13 @@
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};
                     use pallet_common::CommonCollectionOperations;
 
-                    let collection_id = RmrkCore::unique_collection_id(base_id)?;
-                    let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {
-                        Ok(c) => c,
-                        Err(_) => return Ok(Vec::new()),
+                    let collection_id = match RmrkCore::unique_collection_id(base_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(Vec::new())
                     };
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {
+                        return Ok(Vec::new());
+                    }
 
 
                     let theme_names = collection.collection_tokens()
@@ -444,11 +475,13 @@
                     };
                     use pallet_common::CommonCollectionOperations;
 
-                    let collection_id = RmrkCore::unique_collection_id(base_id)?;
-                    let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {
-                        Ok(c) => c,
-                        Err(_) => return Ok(None),
+                    let collection_id = match RmrkCore::unique_collection_id(base_id) {
+                        Ok(id) => id,
+                        Err(_) => return Ok(None)
                     };
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {
+                        return Ok(None);
+                    }
 
                     let theme_info = collection.collection_tokens()
                         .into_iter()