difftreelog
feat initial rmrk send impl
in: master
10 files changed
pallets/common/src/lib.rsdiffbeforeafterboth1298 spender: T::CrossAccountId,1298 spender: T::CrossAccountId,1299 token: TokenId,1299 token: TokenId,1300 amount: u128,1300 amount: u128,1301 nesting_budget: &dyn Budget,1301 ) -> DispatchResultWithPostInfo;1302 ) -> DispatchResultWithPostInfo;1302 fn transfer_from(1303 fn transfer_from(1303 &self,1304 &self,pallets/fungible/src/common.rsdiffbeforeafterboth226 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(),pallets/nonfungible/src/common.rsdiffbeforeafterboth308 spender: T::CrossAccountId,308 spender: T::CrossAccountId,309 token: TokenId,309 token: TokenId,310 amount: u128,310 amount: u128,311 nesting_budget: &dyn Budget,311 ) -> DispatchResultWithPostInfo {312 ) -> DispatchResultWithPostInfo {312 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);313 ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);313314314 with_weight(315 with_weight(315 if amount == 1 {316 if amount == 1 {316 <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))317 <Pallet<T>>::set_allowance(self, &sender, token, Some(&spender), nesting_budget)317 } else {318 } else {318 <Pallet<T>>::set_allowance(self, &sender, token, None)319 <Pallet<T>>::set_allowance(self, &sender, token, None, nesting_budget)319 },320 },320 <CommonWeights<T>>::approve(),321 <CommonWeights<T>>::approve(),321 )322 )pallets/nonfungible/src/erc.rsdiffbeforeafterboth269 let caller = T::CrossAccountId::from_eth(caller);269 let caller = T::CrossAccountId::from_eth(caller);270 let approved = T::CrossAccountId::from_eth(approved);270 let approved = T::CrossAccountId::from_eth(approved);271 let token = token_id.try_into()?;271 let token = token_id.try_into()?;272 let budget = self273 .recorder274 .weight_calls_budget(<StructureWeight<T>>::find_parent());272275273 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))276 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved), &budget)274 .map_err(dispatch_to_evm::<T>)?;277 .map_err(dispatch_to_evm::<T>)?;275 Ok(())278 Ok(())276 }279 }pallets/nonfungible/src/lib.rsdiffbeforeafterboth878 sender: &T::CrossAccountId,878 sender: &T::CrossAccountId,879 token: TokenId,879 token: TokenId,880 spender: Option<&T::CrossAccountId>,880 spender: Option<&T::CrossAccountId>,881 nesting_budget: &dyn Budget,881 ) -> DispatchResult {882 ) -> DispatchResult {882 if collection.permissions.access() == AccessMode::AllowList {883 if collection.permissions.access() == AccessMode::AllowList {883 collection.check_allowlist(sender)?;884 collection.check_allowlist(sender)?;890 <PalletCommon<T>>::ensure_correct_receiver(spender)?;891 <PalletCommon<T>>::ensure_correct_receiver(spender)?;891 }892 }893892 let token_data =894 let is_owned = <PalletStructure<T>>::check_indirectly_owned(895 sender.clone(),896 collection.id,897 token,898 None,899 nesting_budget893 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;900 )?;901894 if &token_data.owner != sender {902 if !is_owned {895 ensure!(903 ensure!(896 collection.ignores_owned_amount(sender),904 collection.ignores_owned_amount(sender),897 <CommonError<T>>::CantApproveMoreThanOwned905 <CommonError<T>>::CantApproveMoreThanOwned918 // `from`, `to` checked in [`transfer`]926 // `from`, `to` checked in [`transfer`]919 collection.check_allowlist(spender)?;927 collection.check_allowlist(spender)?;920 }928 }921 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {922 // TODO: should collection owner be allowed to perform this transfer?923 ensure!(924 <PalletStructure<T>>::check_indirectly_owned(925 spender.clone(),926 source.0,927 source.1,928 None,929 nesting_budget930 )?,931 <CommonError<T>>::ApprovedValueTooLow,932 );933 return Ok(());934 }935 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {929 if <Allowance<T>>::get((collection.id, token)).as_ref() == Some(spender) {936 return Ok(());930 return Ok(());937 }931 }932 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {933 // TODO: should collection owner be allowed to perform this transfer?934 ensure!(935 <PalletStructure<T>>::check_indirectly_owned(936 spender.clone(),937 source.0,938 source.1,939 None,940 nesting_budget941 )?,942 <CommonError<T>>::ApprovedValueTooLow,943 );944 return Ok(());945 }938 ensure!(946 ensure!(939 collection.ignores_allowance(spender),947 collection.ignores_allowance(spender),940 <CommonError<T>>::ApprovedValueTooLow948 <CommonError<T>>::ApprovedValueTooLowpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth20use frame_system::{pallet_prelude::*, ensure_signed};20use frame_system::{pallet_prelude::*, ensure_signed};21use sp_runtime::{DispatchError, Permill, traits::StaticLookup};21use sp_runtime::{DispatchError, Permill, traits::StaticLookup};22use sp_std::vec::Vec;22use sp_std::vec::Vec;23use up_data_structs::*;23use up_data_structs::{*, mapping::TokenAddressMapping};24use pallet_common::{24use pallet_common::{25 Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,25 Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,26};26};393940use RmrkProperty::*;40use RmrkProperty::*;4142const NESTING_BUDGET: u32 = 5;414342#[frame_support::pallet]44#[frame_support::pallet]43pub mod pallet {45pub mod pallet {56 pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;58 pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;575958 #[pallet::storage]60 #[pallet::storage]59 #[pallet::getter(fn collection_index_map)]60 pub type CollectionIndexMap<T: Config> =61 pub type UniqueCollectionId<T: Config> =61 StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, ValueQuery>;62 StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, ValueQuery>;6364 #[pallet::storage]65 pub type RmrkInernalCollectionId<T: Config> =66 StorageMap<_, Twox64Concat, CollectionId, RmrkCollectionId, ValueQuery>;626763 #[pallet::pallet]68 #[pallet::pallet]64 #[pallet::generate_store(pub(super) trait Store)]69 #[pallet::generate_store(pub(super) trait Store)]151 .into_inner()156 .into_inner()152 .try_into()157 .try_into()153 .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,158 .map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,159 permissions: Some(CollectionPermissions {160 nesting: Some(NestingRule::Owner),161 ..Default::default()162 }),154 ..Default::default()163 ..Default::default()155 };164 };156157 <CollectionIndex<T>>::mutate(|n| *n += 1);158165159 let unique_collection_id = Self::init_collection(166 let unique_collection_id = Self::init_collection(160 T::CrossAccountId::from_sub(sender.clone()),167 T::CrossAccountId::from_sub(sender.clone()),167 )?;174 )?;168 let rmrk_collection_id = <CollectionIndex<T>>::get();175 let rmrk_collection_id = <CollectionIndex<T>>::get();169176170 <CollectionIndexMap<T>>::insert(rmrk_collection_id, unique_collection_id);177 <UniqueCollectionId<T>>::insert(rmrk_collection_id, unique_collection_id);178 <RmrkInernalCollectionId<T>>::insert(unique_collection_id, rmrk_collection_id);179180 <CollectionIndex<T>>::mutate(|n| *n += 1);171181172 Self::deposit_event(Event::CollectionCreated {182 Self::deposit_event(Event::CollectionCreated {173 issuer: sender,183 issuer: sender,354 Ok(())364 Ok(())355 }365 }366367 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]368 #[transactional]369 pub fn send(370 origin: OriginFor<T>,371 rmrk_collection_id: RmrkCollectionId,372 rmrk_nft_id: RmrkNftId,373 new_owner: RmrkAccountIdOrCollectionNftTuple<T::AccountId>,374 ) -> DispatchResult {375 let sender = ensure_signed(origin.clone())?;376 let cross_sender = T::CrossAccountId::from_sub(sender.clone());377378 let collection_id = Self::unique_collection_id(rmrk_collection_id)?;379 let nft_id = rmrk_nft_id.into();380381 let token_data = <TokenData<T>>::get((collection_id, nft_id))382 .ok_or(<Error<T>>::NoAvailableNftId)?;383384 let from = token_data.owner;385386 let collection = Self::get_typed_nft_collection(387 collection_id,388 misc::CollectionType::Regular,389 )?;390391 let budget = budget::Value::new(NESTING_BUDGET);392393 let target_owner;394395 match new_owner {396 RmrkAccountIdOrCollectionNftTuple::AccountId(account_id) => {397 target_owner = T::CrossAccountId::from_sub(account_id);398 },399 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(target_collection_id, target_nft_id) => {400 let target_collection_id = Self::unique_collection_id(target_collection_id)?;401402 target_owner = T::CrossTokenAddressMapping::token_to_address(403 target_collection_id,404 target_nft_id.into(),405 );406407 let spender = <PalletStructure<T>>::get_indirect_owner(408 target_collection_id,409 target_nft_id.into(),410 Some((collection_id, nft_id)),411 &budget,412 )?;413414 let is_approval_required = cross_sender != spender;415416 if is_approval_required {417 <PalletNft<T>>::set_allowance(418 &collection,419 &cross_sender,420 nft_id,421 Some(&spender),422 &budget423 ).map_err(Self::map_common_err_to_proxy)?;424425 return Ok(());426 }427 }428 }429430 <PalletNft<T>>::transfer_from(431 &collection,432 &cross_sender,433 &from,434 &target_owner,435 nft_id,436 &budget437 ).map_err(Self::map_common_err_to_proxy)?;438439 Ok(())440 }356441357 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]442 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]358 #[transactional]443 #[transactional]367 let sender = T::CrossAccountId::from_sub(sender);452 let sender = T::CrossAccountId::from_sub(sender);368453369 let collection_id = Self::unique_collection_id(rmrk_collection_id)?;454 let collection_id = Self::unique_collection_id(rmrk_collection_id)?;455 let budget = budget::Value::new(NESTING_BUDGET);370456371 match maybe_nft_id {457 match maybe_nft_id {372 Some(nft_id) => {458 Some(nft_id) => {373 let token_id: TokenId = nft_id.into();459 let token_id: TokenId = nft_id.into();374460375 Self::ensure_nft_owner(collection_id, token_id, &sender)?;461 Self::ensure_nft_owner(collection_id, token_id, &sender, &budget)?;376 Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;462 Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;377463378 <PalletNft<T>>::set_scoped_token_property(464 <PalletNft<T>>::set_scoped_token_property(607 owner: owner.clone(),693 owner: owner.clone(),608 };694 };609695610 let budget = budget::Value::new(2);696 let budget = budget::Value::new(NESTING_BUDGET);611697612 <PalletNft<T>>::create_item(collection, sender, data, &budget)?;698 <PalletNft<T>>::create_item(collection, sender, data, &budget)?;613699651 //ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);737 //ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);652738653 let sender = T::CrossAccountId::from_sub(sender);739 let sender = T::CrossAccountId::from_sub(sender);654 let budget = budget::Value::new(10);740 let budget = budget::Value::new(NESTING_BUDGET);655 let pending = !<PalletStructure<T>>::check_indirectly_owned(741 let pending = Self::ensure_nft_owner(collection_id, token_id, &sender, &budget).is_err();656 sender.clone(),657 collection_id,658 token_id,659 None,660 &budget,661 )?;662742663 let resource_collection_id: CollectionId =743 let resource_collection_id: CollectionId =664 Self::get_nft_property_decoded(collection_id, token_id, ResourceCollection)?;744 Self::get_nft_property_decoded(collection_id, token_id, ResourceCollection)?;757 pub fn unique_collection_id(837 pub fn unique_collection_id(758 rmrk_collection_id: RmrkCollectionId,838 rmrk_collection_id: RmrkCollectionId,759 ) -> Result<CollectionId, DispatchError> {839 ) -> Result<CollectionId, DispatchError> {760 <CollectionIndexMap<T>>::try_get(rmrk_collection_id)840 <UniqueCollectionId<T>>::try_get(rmrk_collection_id)761 .map_err(|_| <Error<T>>::CollectionUnknown.into())841 .map_err(|_| <Error<T>>::CollectionUnknown.into())762 }842 }843844 pub fn rmrk_collection_id(845 unique_collection_id: CollectionId846 ) -> Result<RmrkCollectionId, DispatchError> {847 <RmrkInernalCollectionId<T>>::try_get(unique_collection_id)848 .map_err(|_| <Error<T>>::CollectionUnknown.into())849 }763850764 pub fn get_nft_collection(851 pub fn get_nft_collection(765 collection_id: CollectionId,852 collection_id: CollectionId,873 collection_id: CollectionId,960 collection_id: CollectionId,874 token_id: TokenId,961 token_id: TokenId,875 possible_owner: &T::CrossAccountId,962 possible_owner: &T::CrossAccountId,963 nesting_budget: &dyn budget::Budget876 ) -> DispatchResult {964 ) -> DispatchResult {877 let token_data =965 let is_owned = <PalletStructure<T>>::check_indirectly_owned(966 possible_owner.clone(),967 collection_id,968 token_id,969 None,970 nesting_budget,878 <TokenData<T>>::get((collection_id, token_id)).ok_or(<Error<T>>::NoAvailableNftId)?;971 )?;879972880 ensure!(973 ensure!(881 token_data.owner == *possible_owner,974 is_owned,882 <Error<T>>::NoPermission975 <Error<T>>::NoPermission883 );976 );884977965 NoPermission => NoPermission,1058 NoPermission => NoPermission,966 CollectionTokenLimitExceeded => CollectionFullOrLocked,1059 CollectionTokenLimitExceeded => CollectionFullOrLocked,967 PublicMintingNotAllowed => NoPermission,1060 PublicMintingNotAllowed => NoPermission,968 TokenNotFound => NoAvailableNftId1061 TokenNotFound => NoAvailableNftId,1062 ApprovedValueTooLow => NoPermission969 }1063 }970 }1064 }971 }1065 }pallets/refungible/src/common.rsdiffbeforeafterboth254 spender: T::CrossAccountId,254 spender: T::CrossAccountId,255 token: TokenId,255 token: TokenId,256 amount: u128,256 amount: u128,257 _nesting_budget: &dyn Budget,257 ) -> DispatchResultWithPostInfo {258 ) -> DispatchResultWithPostInfo {258 with_weight(259 with_weight(259 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),260 <Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),pallets/structure/src/lib.rsdiffbeforeafterboth149 })149 })150 }150 }151151152 /// Check if token indirectly owned by specified user153 pub fn check_indirectly_owned(152 pub fn get_indirect_owner(154 user: T::CrossAccountId,155 collection: CollectionId,153 collection: CollectionId,156 token: TokenId,154 token: TokenId,157 for_nest: Option<(CollectionId, TokenId)>,155 for_nest: Option<(CollectionId, TokenId)>,158 budget: &dyn Budget,156 budget: &dyn Budget,159 ) -> Result<bool, DispatchError> {157 ) -> Result<T::CrossAccountId, DispatchError> {160 let target_parent = match T::CrossTokenAddressMapping::address_to_token(&user) {161 Some((collection, token)) => Self::find_topmost_owner(collection, token, budget)?,162 None => user,163 };164165 // Tried to nest token in itself158 // Tried to nest token in itself166 if Some((collection, token)) == for_nest {159 if Some((collection, token)) == for_nest {173 Parent::Token(collection, token) if Some((collection, token)) == for_nest => {166 Parent::Token(collection, token) if Some((collection, token)) == for_nest => {174 return Err(<Error<T>>::OuroborosDetected.into())167 return Err(<Error<T>>::OuroborosDetected.into())175 }168 }176 // Found needed parent, token is indirecty owned169 // Token is owned by other user177 Parent::User(user) if user == target_parent => return Ok(true),170 Parent::User(user) => return Ok(user),178 // Token is owned by other user179 Parent::User(_) => return Ok(false),180 Parent::TokenNotFound => return Err(<Error<T>>::TokenNotFound.into()),171 Parent::TokenNotFound => return Err(<Error<T>>::TokenNotFound.into()),181 // Continue parent chain172 // Continue parent chain182 Parent::Token(_, _) => {}173 Parent::Token(_, _) => {}199 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)190 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)200 }191 }192193 /// Check if token indirectly owned by specified user194 pub fn check_indirectly_owned(195 user: T::CrossAccountId,196 collection: CollectionId,197 token: TokenId,198 for_nest: Option<(CollectionId, TokenId)>,199 budget: &dyn Budget,200 ) -> Result<bool, DispatchError> {201 let target_parent = match T::CrossTokenAddressMapping::address_to_token(&user) {202 Some((collection, token)) => Self::find_topmost_owner(collection, token, budget)?,203 None => user,204 };205206 Self::get_indirect_owner(207 collection,208 token,209 for_nest,210 budget211 ).map(|indirect_owner| indirect_owner == target_parent)212 }201213202 pub fn check_nesting(214 pub fn check_nesting(203 from: T::CrossAccountId,215 from: T::CrossAccountId,pallets/unique/src/lib.rsdiffbeforeafterboth815 #[transactional]815 #[transactional]816 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {816 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {817 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);817 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);818 let budget = budget::Value::new(NESTING_BUDGET);818819819 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))820 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount, &budget))820 }821 }821822822 /// 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.823 /// 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.runtime/common/src/runtime_apis.rsdiffbeforeafterboth147 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};147 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};148 use pallet_common::CommonCollectionOperations;148 use pallet_common::CommonCollectionOperations;149149150 let collection_id = RmrkCore::unique_collection_id(collection_id)?;150 let collection_id = match RmrkCore::unique_collection_id(collection_id) {151 Ok(id) => id,152 Err(_) => return Ok(None)153 };154151 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {155 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {152 Ok(c) => c,156 Ok(c) => c,169 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};173 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};170 use pallet_common::CommonCollectionOperations;174 use pallet_common::CommonCollectionOperations;171175172 let collection_id = RmrkCore::unique_collection_id(collection_id)?;176 let collection_id = match RmrkCore::unique_collection_id(collection_id) {177 Ok(id) => id,178 Err(_) => return Ok(None)179 };173 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {180 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {174 Ok(c) => c,181 Ok(c) => c,175 Err(_) => return Ok(None),182 Err(_) => return Ok(None),180187181 let owner = match collection.token_owner(nft_id) {188 let owner = match collection.token_owner(nft_id) {182 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {189 Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {183 Some((col, tok)) => RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(col.0, tok.0),190 Some((col, tok)) => {191 let rmrk_collection = RmrkCore::rmrk_collection_id(col)?;192193 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)194 }184 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())195 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())185 },196 },186 None => return Ok(None)197 None => return Ok(None)202 use pallet_common::CommonCollectionOperations;213 use pallet_common::CommonCollectionOperations;203214204 let cross_account_id = CrossAccountId::from_sub(account_id);215 let cross_account_id = CrossAccountId::from_sub(account_id);205 let collection_id = RmrkCore::unique_collection_id(collection_id)?;216 let collection_id = match RmrkCore::unique_collection_id(collection_id) {217 Ok(id) => id,218 Err(_) => return Ok(Vec::new())219 };206 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {220 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }207 Ok(c) => c,208 Err(_) => return Ok(Vec::new()),209 };210221211 Ok(222 Ok(212 collection.account_tokens(cross_account_id)223 collection.account_tokens(cross_account_id)217 }228 }218229219 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {230 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {220 let collection_id = RmrkCore::unique_collection_id(collection_id)?;231 let collection_id = match RmrkCore::unique_collection_id(collection_id) {232 Ok(id) => id,233 Err(_) => return Ok(Vec::new())234 };221 let nft_id = TokenId(nft_id);235 let nft_id = TokenId(nft_id);222 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }236 if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }223237224 Ok(238 Ok(225 pallet_nonfungible::TokenChildren::<Runtime>::iter_prefix((collection_id, nft_id))239 pallet_nonfungible::TokenChildren::<Runtime>::iter_prefix((collection_id, nft_id))226 .filter_map(|(child_id, is_child)|240 .filter_map(|((child_collection, child_token), _)| {227 match is_child {241 let rmrk_child_collection = RmrkCore::rmrk_collection_id(242 child_collection243 ).ok()?;244228 true => Some(RmrkNftChild {245 Some(RmrkNftChild {229 collection_id: child_id.0.0,246 collection_id: rmrk_child_collection,230 nft_id: child_id.1.0,247 nft_id: child_token.0,231 }),248 })232 false => None,233 }249 }).collect()234 ).collect()235 )250 )236 }251 }237252238 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {253 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {239 use pallet_proxy_rmrk_core::misc::CollectionType;254 use pallet_proxy_rmrk_core::misc::CollectionType;240255241 let collection_id = RmrkCore::unique_collection_id(collection_id)?;256 let collection_id = match RmrkCore::unique_collection_id(collection_id) {257 Ok(id) => id,258 Err(_) => return Ok(Vec::new())259 };242 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {260 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {243 return Ok(Vec::new());261 return Ok(Vec::new());244 }262 }259 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {277 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {260 use pallet_proxy_rmrk_core::misc::NftType;278 use pallet_proxy_rmrk_core::misc::NftType;261279262 let collection_id = RmrkCore::unique_collection_id(collection_id)?;280 let collection_id = match RmrkCore::unique_collection_id(collection_id) {281 Ok(id) => id,282 Err(_) => return Ok(Vec::new())283 };263 let token_id = TokenId(nft_id);284 let token_id = TokenId(nft_id);264285265 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {286 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {283 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};304 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}};284 use pallet_common::CommonCollectionOperations;305 use pallet_common::CommonCollectionOperations;285306286 let collection_id = RmrkCore::unique_collection_id(collection_id)?;307 let collection_id = match RmrkCore::unique_collection_id(collection_id) {308 Ok(id) => id,309 Err(_) => return Ok(Vec::new())310 };287 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }311 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }288312289 let nft_id = TokenId(nft_id);313 let nft_id = TokenId(nft_id);332 fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {356 fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {333 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};357 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};334358335 let collection_id = RmrkCore::unique_collection_id(collection_id)?;359 let collection_id = match RmrkCore::unique_collection_id(collection_id) {360 Ok(id) => id,361 Err(_) => return Ok(Vec::new())362 };336 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }363 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }337364338 let nft_id = TokenId(nft_id);365 let nft_id = TokenId(nft_id);360 RmrkProperty, misc::{CollectionType},387 RmrkProperty, misc::{CollectionType},361 };388 };362389363 let collection_id = RmrkCore::unique_collection_id(base_id)?;390 let collection_id = match RmrkCore::unique_collection_id(base_id) {391 Ok(id) => id,392 Err(_) => return Ok(None)393 };364 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {394 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {365 Ok(c) => c,395 Ok(c) => c,366 Err(_) => return Ok(None),396 Err(_) => return Ok(None),377 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};407 use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};378 use pallet_common::CommonCollectionOperations;408 use pallet_common::CommonCollectionOperations;379409380 let collection_id = RmrkCore::unique_collection_id(base_id)?;410 let collection_id = match RmrkCore::unique_collection_id(base_id) {411 Ok(id) => id,412 Err(_) => return Ok(Vec::new())413 };381 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {414 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }382 Ok(c) => c,383 Err(_) => return Ok(Vec::new()),384 };385386415387 let parts = collection.collection_tokens()416 let parts = collection.collection_tokens()413 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};442 use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};414 use pallet_common::CommonCollectionOperations;443 use pallet_common::CommonCollectionOperations;415444416 let collection_id = RmrkCore::unique_collection_id(base_id)?;445 let collection_id = match RmrkCore::unique_collection_id(base_id) {446 Ok(id) => id,447 Err(_) => return Ok(Vec::new())448 };417 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {449 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {418 Ok(c) => c,419 Err(_) => return Ok(Vec::new()),450 return Ok(Vec::new());420 };451 }421452422453423 let theme_names = collection.collection_tokens()454 let theme_names = collection.collection_tokens()444 };475 };445 use pallet_common::CommonCollectionOperations;476 use pallet_common::CommonCollectionOperations;446477447 let collection_id = RmrkCore::unique_collection_id(base_id)?;478 let collection_id = match RmrkCore::unique_collection_id(base_id) {479 Ok(id) => id,480 Err(_) => return Ok(None)481 };448 let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {482 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {449 Ok(c) => c,450 Err(_) => return Ok(None),483 return Ok(None);451 };484 }452485453 let theme_info = collection.collection_tokens()486 let theme_info = collection.collection_tokens()454 .into_iter()487 .into_iter()