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
1298 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,
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
308 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);
313314
314 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 )
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
269 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 = self
273 .recorder
274 .weight_calls_budget(<StructureWeight<T>>::find_parent());
272275
273 <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 }
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
878 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 }
893
892 let token_data =894 let is_owned = <PalletStructure<T>>::check_indirectly_owned(
895 sender.clone(),
896 collection.id,
897 token,
898 None,
899 nesting_budget
893 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;900 )?;
901
894 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>>::CantApproveMoreThanOwned
918 // `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_budget
930 )?,
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_budget
941 )?,
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>>::ApprovedValueTooLow
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
20use 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};
3939
40use RmrkProperty::*;40use RmrkProperty::*;
41
42const NESTING_BUDGET: u32 = 5;
4143
42#[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>;
5759
58 #[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>;
63
64 #[pallet::storage]
65 pub type RmrkInernalCollectionId<T: Config> =
66 StorageMap<_, Twox64Concat, CollectionId, RmrkCollectionId, ValueQuery>;
6267
63 #[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 };
156
157 <CollectionIndex<T>>::mutate(|n| *n += 1);
158165
159 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();
169176
170 <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);
179
180 <CollectionIndex<T>>::mutate(|n| *n += 1);
171181
172 Self::deposit_event(Event::CollectionCreated {182 Self::deposit_event(Event::CollectionCreated {
173 issuer: sender,183 issuer: sender,
354 Ok(())364 Ok(())
355 }365 }
366
367 #[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());
377
378 let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
379 let nft_id = rmrk_nft_id.into();
380
381 let token_data = <TokenData<T>>::get((collection_id, nft_id))
382 .ok_or(<Error<T>>::NoAvailableNftId)?;
383
384 let from = token_data.owner;
385
386 let collection = Self::get_typed_nft_collection(
387 collection_id,
388 misc::CollectionType::Regular,
389 )?;
390
391 let budget = budget::Value::new(NESTING_BUDGET);
392
393 let target_owner;
394
395 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)?;
401
402 target_owner = T::CrossTokenAddressMapping::token_to_address(
403 target_collection_id,
404 target_nft_id.into(),
405 );
406
407 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 )?;
413
414 let is_approval_required = cross_sender != spender;
415
416 if is_approval_required {
417 <PalletNft<T>>::set_allowance(
418 &collection,
419 &cross_sender,
420 nft_id,
421 Some(&spender),
422 &budget
423 ).map_err(Self::map_common_err_to_proxy)?;
424
425 return Ok(());
426 }
427 }
428 }
429
430 <PalletNft<T>>::transfer_from(
431 &collection,
432 &cross_sender,
433 &from,
434 &target_owner,
435 nft_id,
436 &budget
437 ).map_err(Self::map_common_err_to_proxy)?;
438
439 Ok(())
440 }
356441
357 #[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);
368453
369 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);
370456
371 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();
374460
375 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)?;
377463
378 <PalletNft<T>>::set_scoped_token_property(464 <PalletNft<T>>::set_scoped_token_property(
607 owner: owner.clone(),693 owner: owner.clone(),
608 };694 };
609695
610 let budget = budget::Value::new(2);696 let budget = budget::Value::new(NESTING_BUDGET);
611697
612 <PalletNft<T>>::create_item(collection, sender, data, &budget)?;698 <PalletNft<T>>::create_item(collection, sender, data, &budget)?;
613699
651 //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);
652738
653 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 )?;
662742
663 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 }
843
844 pub fn rmrk_collection_id(
845 unique_collection_id: CollectionId
846 ) -> Result<RmrkCollectionId, DispatchError> {
847 <RmrkInernalCollectionId<T>>::try_get(unique_collection_id)
848 .map_err(|_| <Error<T>>::CollectionUnknown.into())
849 }
763850
764 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::Budget
876 ) -> 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 )?;
879972
880 ensure!(973 ensure!(
881 token_data.owner == *possible_owner,974 is_owned,
882 <Error<T>>::NoPermission975 <Error<T>>::NoPermission
883 );976 );
884977
965 NoPermission => NoPermission,1058 NoPermission => NoPermission,
966 CollectionTokenLimitExceeded => CollectionFullOrLocked,1059 CollectionTokenLimitExceeded => CollectionFullOrLocked,
967 PublicMintingNotAllowed => NoPermission,1060 PublicMintingNotAllowed => NoPermission,
968 TokenNotFound => NoAvailableNftId1061 TokenNotFound => NoAvailableNftId,
1062 ApprovedValueTooLow => NoPermission
969 }1063 }
970 }1064 }
971 }1065 }
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
254 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),
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
149 })149 })
150 }150 }
151151
152 /// Check if token indirectly owned by specified user
153 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 };
164
165 // Tried to nest token in itself158 // Tried to nest token in itself
166 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 user
177 Parent::User(user) if user == target_parent => return Ok(true),170 Parent::User(user) => return Ok(user),
178 // Token is owned by other user
179 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 chain
182 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 }
192
193 /// Check if token indirectly owned by specified user
194 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 };
205
206 Self::get_indirect_owner(
207 collection,
208 token,
209 for_nest,
210 budget
211 ).map(|indirect_owner| indirect_owner == target_parent)
212 }
201213
202 pub fn check_nesting(214 pub fn check_nesting(
203 from: T::CrossAccountId,215 from: T::CrossAccountId,
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
815 #[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);
818819
819 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 }
821822
822 /// 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.
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
147 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;
149149
150 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 };
154
151 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;
171175
172 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),
180187
181 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)?;
192
193 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;
203214
204 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 };
210221
211 Ok(222 Ok(
212 collection.account_tokens(cross_account_id)223 collection.account_tokens(cross_account_id)
217 }228 }
218229
219 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()); }
223237
224 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_collection
243 ).ok()?;
244
228 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 }
237252
238 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;
240255
241 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;
261279
262 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);
264285
265 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;
285306
286 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()); }
288312
289 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}};
334358
335 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()); }
337364
338 let nft_id = TokenId(nft_id);365 let nft_id = TokenId(nft_id);
360 RmrkProperty, misc::{CollectionType},387 RmrkProperty, misc::{CollectionType},
361 };388 };
362389
363 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;
379409
380 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 };
385
386415
387 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;
415444
416 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 }
421452
422453
423 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;
446477
447 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 }
452485
453 let theme_info = collection.collection_tokens()486 let theme_info = collection.collection_tokens()
454 .into_iter()487 .into_iter()