git.delta.rocks / unique-network / refs/commits / 05c459d3caac

difftreelog

fix find_parent

Daniel Shiposha2023-01-19parent: #6a7ab3b.patch.diff
in: master

14 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
28use sp_std::{vec, vec::Vec};28use sp_std::{vec, vec::Vec};
29use sp_core::U256;29use sp_core::U256;
30use up_data_structs::{30use up_data_structs::{
31 AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,31 CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property, SponsoringRateLimit,
32 SponsoringRateLimit, SponsorshipState,32 SponsorshipState,
33};33};
3434
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
80 if cross_account_id.is_canonical_substrate() {80 if cross_account_id.is_canonical_substrate() {
81 Self::from_sub::<T>(cross_account_id.as_sub())81 Self::from_sub::<T>(cross_account_id.as_sub())
82 } else {82 } else {
83 Self {83 Self::from_eth(*cross_account_id.as_eth())
84 eth: *cross_account_id.as_eth(),
85 sub: Default::default(),
86 }
87 }84 }
88 }85 }
89 /// Creates [`CrossAddress`] from Substrate account.86 /// Creates [`CrossAddress`] from Substrate account.
97 sub: U256::from_big_endian(account_id.as_ref()),94 sub: U256::from_big_endian(account_id.as_ref()),
98 }95 }
99 }96 }
97 /// Creates [`CrossAddress`] from Ethereum account.
98 pub fn from_eth(address: Address) -> Self {
99 Self {
100 eth: address,
101 sub: Default::default(),
102 }
103 }
100 /// Converts [`CrossAddress`] to `CrossAccountId`.104 /// Converts [`CrossAddress`] to `CrossAccountId`.
101 pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>105 pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>
102 where106 where
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
100 PropertyValue,100 PropertyValue,
101 PropertyPermission,101 PropertyPermission,
102 PropertiesError,102 PropertiesError,
103 TokenOwnerError,
103 PropertyKeyPermission,104 PropertyKeyPermission,
104 TokenData,105 TokenData,
105 TrySetProperty,106 TrySetProperty,
2134 /// Get the owner of the token.2135 /// Get the owner of the token.
2135 ///2136 ///
2136 /// * `token` - The token for which you need to find out the owner.2137 /// * `token` - The token for which you need to find out the owner.
2137 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;2138 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;
21382139
2139 /// Returns 10 tokens owners in no particular order.2140 /// Returns 10 tokens owners in no particular order.
2140 ///2141 ///
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
1818
19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};
20use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget, CreateItemData};20use up_data_structs::{
21 TokenId, CollectionId, CreateItemExData, budget::Budget, CreateItemData, TokenOwnerError,
22};
21use pallet_common::{23use pallet_common::{
22 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,24 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
404 TokenId::default()406 TokenId::default()
405 }407 }
406408
407 fn token_owner(&self, _token: TokenId) -> Option<T::CrossAccountId> {409 fn token_owner(&self, _token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {
408 None410 Err(TokenOwnerError::MultipleOwners)
409 }411 }
410412
411 /// Returns 10 tokens owners in no particular order.413 /// Returns 10 tokens owners in no particular order.
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
20use up_data_structs::{20use up_data_structs::{
21 TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,21 TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,
22 PropertyKeyPermission, PropertyValue,22 PropertyKeyPermission, PropertyValue, TokenOwnerError,
23};23};
24use pallet_common::{24use pallet_common::{
25 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,25 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
460 TokenId(<TokensMinted<T>>::get(self.id))460 TokenId(<TokensMinted<T>>::get(self.id))
461 }461 }
462462
463 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {463 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {
464 <TokenData<T>>::get((self.id, token)).map(|t| t.owner)464 <TokenData<T>>::get((self.id, token))
465 .map(|t| t.owner)
466 .ok_or(TokenOwnerError::NotFound)
465 }467 }
466468
467 /// Returns token owners.469 /// Returns token owners.
468 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {470 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
469 self.token_owner(token).map_or_else(|| vec![], |t| vec![t])471 self.token_owner(token).map_or_else(|_| vec![], |t| vec![t])
470 }472 }
471473
472 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {474 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
728 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {728 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {
729 Self::token_owner(&self, token_id.try_into()?)729 Self::token_owner(&self, token_id.try_into()?)
730 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))730 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))
731 .ok_or(Error::Revert("key too large".into()))731 .map_err(|_| Error::Revert("token not found".into()))
732 }732 }
733733
734 /// Returns the token properties.734 /// Returns the token properties.
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
742 &target_nft_budget,742 &target_nft_budget,
743 )743 )
744 .map_err(Self::map_unique_err_to_proxy)?;744 .map_err(Self::map_unique_err_to_proxy)?
745 .ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
745746
746 approval_required = cross_sender != target_nft_owner;747 approval_required = cross_sender != target_nft_owner;
747748
990 let nft_owner =991 let nft_owner =
991 <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)992 <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
992 .map_err(|_| <Error<T>>::ResourceDoesntExist)?;993 .map_err(|_| <Error<T>>::ResourceDoesntExist)?
994 .ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
993995
994 Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {996 Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {
995 ensure!(res.pending, <Error<T>>::ResourceNotPending);997 ensure!(res.pending, <Error<T>>::ResourceNotPending);
1045 let nft_owner =1047 let nft_owner =
1046 <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)1048 <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
1047 .map_err(|_| <Error<T>>::ResourceDoesntExist)?;1049 .map_err(|_| <Error<T>>::ResourceDoesntExist)?
1050 .ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
10481051
1049 ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);1052 ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);
10501053
16671670
1668 let nft_owner = <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)1671 let nft_owner = <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
1669 .map_err(Self::map_unique_err_to_proxy)?;1672 .map_err(Self::map_unique_err_to_proxy)?
1673 .ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
16701674
1671 let pending = sender != nft_owner;1675 let pending = sender != nft_owner;
16721676
1721 let budget = up_data_structs::budget::Value::new(NESTING_BUDGET);1725 let budget = up_data_structs::budget::Value::new(NESTING_BUDGET);
1722 let topmost_owner =1726 let topmost_owner =
1723 <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)?;1727 <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)?
1728 .ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
17241729
1725 let sender = T::CrossAccountId::from_sub(sender);1730 let sender = T::CrossAccountId::from_sub(sender);
1726 if topmost_owner == sender {1731 if topmost_owner == sender {
modifiedpallets/proxy-rmrk-core/src/rpc.rsdiffbeforeafterboth
68 }68 }
6969
70 let owner = match collection.token_owner(nft_id) {70 let owner = match collection.token_owner(nft_id) {
71 Some(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {71 Ok(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {
72 Some((col, tok)) => {72 Some((col, tok)) => {
73 let rmrk_collection = <Pallet<T>>::rmrk_collection_id(col)?;73 let rmrk_collection = <Pallet<T>>::rmrk_collection_id(col)?;
7474
75 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)75 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)
76 }76 }
77 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()),77 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()),
78 },78 },
79 None => return Ok(None),79 _ => return Ok(None),
80 };80 };
8181
82 Ok(Some(RmrkInstanceInfo {82 Ok(Some(RmrkInstanceInfo {
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
21use up_data_structs::{21use up_data_structs::{
22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,
23 PropertyKeyPermission, CollectionPropertiesVec, CreateRefungibleExMultipleOwners,23 PropertyKeyPermission, CollectionPropertiesVec, CreateRefungibleExMultipleOwners,
24 CreateRefungibleExSingleOwner,24 CreateRefungibleExSingleOwner, TokenOwnerError,
25};25};
26use pallet_common::{26use pallet_common::{
27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
478 TokenId(<TokensMinted<T>>::get(self.id))478 TokenId(<TokensMinted<T>>::get(self.id))
479 }479 }
480480
481 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {481 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {
482 <Pallet<T>>::token_owner(self.id, token)482 <Pallet<T>>::token_owner(self.id, token)
483 }483 }
484484
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
43use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};43use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};
44use up_data_structs::{44use up_data_structs::{
45 CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,45 CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,
46 PropertyKeyPermission, PropertyPermission, TokenId,46 PropertyKeyPermission, PropertyPermission, TokenId, TokenOwnerError,
47};47};
4848
49use crate::{49use crate::{
411 self.consume_store_reads(2)?;411 self.consume_store_reads(2)?;
412 let token = token_id.try_into()?;412 let token = token_id.try_into()?;
413 let owner = <Pallet<T>>::token_owner(self.id, token);413 let owner = <Pallet<T>>::token_owner(self.id, token);
414 Ok(owner414 owner
415 .map(|address| *address.as_eth())415 .map(|address| *address.as_eth())
416 .unwrap_or_else(|| ADDRESS_FOR_PARTIALLY_OWNED_TOKENS))416 .or_else(|err| match err {
417 TokenOwnerError::NotFound => Err(Error::Revert("token not found".into())),
418 TokenOwnerError::MultipleOwners => Ok(ADDRESS_FOR_PARTIALLY_OWNED_TOKENS),
419 })
417 }420 }
418421
419 /// @dev Not implemented422 /// @dev Not implemented
766 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {769 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {
767 Self::token_owner(&self, token_id.try_into()?)770 Self::token_owner(&self, token_id.try_into()?)
768 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))771 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))
769 .ok_or(Error::Revert("key too large".into()))772 .or_else(|err| match err {
773 TokenOwnerError::NotFound => Err(Error::Revert("token not found".into())),
774 TokenOwnerError::MultipleOwners => Ok(eth::CrossAddress::from_eth(
775 ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,
776 )),
777 })
770 }778 }
771779
772 /// Returns the token properties.780 /// Returns the token properties.
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
107 AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,107 AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,
108 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,108 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,
109 PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId,109 PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId,
110 TrySetProperty, PropertiesPermissionMap, CreateRefungibleExMultipleOwners,110 TrySetProperty, PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,
111};111};
112112
113pub use pallet::*;113pub use pallet::*;
480 <Balance<T>>::remove((collection.id, token, owner));480 <Balance<T>>::remove((collection.id, token, owner));
481 <AccountBalance<T>>::insert((collection.id, owner), account_balance);481 <AccountBalance<T>>::insert((collection.id, owner), account_balance);
482482
483 if let Some(user) = Self::token_owner(collection.id, token) {483 if let Ok(user) = Self::token_owner(collection.id, token) {
484 <PalletEvm<T>>::deposit_log(484 <PalletEvm<T>>::deposit_log(
485 ERC721Events::Transfer {485 ERC721Events::Transfer {
486 from: erc::ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,486 from: erc::ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,
1365 Ok(())1365 Ok(())
1366 }1366 }
13671367
1368 fn token_owner(collection_id: CollectionId, token_id: TokenId) -> Option<T::CrossAccountId> {1368 fn token_owner(
1369 collection_id: CollectionId,
1370 token_id: TokenId,
1371 ) -> Result<T::CrossAccountId, TokenOwnerError> {
1369 let mut owner = None;1372 let mut owner = None;
1370 let mut count = 0;1373 let mut count = 0;
1371 for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {1374 for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {
1372 count += 1;1375 count += 1;
1373 if count > 1 {1376 if count > 1 {
1374 return None;1377 return Err(TokenOwnerError::MultipleOwners);
1375 }1378 }
1376 owner = Some(key);1379 owner = Some(key);
1377 }1380 }
1378 owner1381 owner.ok_or(TokenOwnerError::NotFound)
1379 }1382 }
13801383
1381 fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {1384 fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
62pub use pallet::*;62pub use pallet::*;
63use pallet_common::{dispatch::CollectionDispatch, CollectionHandle};63use pallet_common::{dispatch::CollectionDispatch, CollectionHandle};
64use up_data_structs::{CollectionId, TokenId, mapping::TokenAddressMapping, budget::Budget};64use up_data_structs::{
65 CollectionId, TokenId, mapping::TokenAddressMapping, budget::Budget, TokenOwnerError,
66};
6567
66#[cfg(feature = "runtime-benchmarks")]68#[cfg(feature = "runtime-benchmarks")]
135 User(CrossAccountId),137 User(CrossAccountId),
136 /// Could not find the token provided as the owner.138 /// Could not find the token provided as the owner.
137 TokenNotFound,139 TokenNotFound,
140 /// Nested token has multiple owners.
141 MultipleOwners,
138 /// Token owner is another token (still, the target token may not exist).142 /// Token owner is another token (still, the target token may not exist).
139 Token(CollectionId, TokenId),143 Token(CollectionId, TokenId),
140}144}
159 let handle = handle.as_dyn();163 let handle = handle.as_dyn();
160164
161 Ok(match handle.token_owner(token) {165 Ok(match handle.token_owner(token) {
162 Some(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {166 Ok(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {
163 Some((collection, token)) => Parent::Token(collection, token),167 Some((collection, token)) => Parent::Token(collection, token),
164 None => Parent::User(owner),168 None => Parent::User(owner),
165 },169 },
170 Err(TokenOwnerError::MultipleOwners) => Parent::MultipleOwners,
166 None => Parent::TokenNotFound,171 Err(TokenOwnerError::NotFound) => Parent::TokenNotFound,
167 })172 })
168 }173 }
169174
202 /// Try to dereference address, until finding top level owner207 /// Try to dereference address, until finding top level owner
203 ///208 ///
204 /// May return token address if parent token not yet exists209 /// May return token address if parent token not yet exists
210 ///
211 /// Returns `None` if the token has multiple owners.
205 ///212 ///
206 /// - `budget`: Limit for searching parents in depth.213 /// - `budget`: Limit for searching parents in depth.
207 pub fn find_topmost_owner(214 pub fn find_topmost_owner(
208 collection: CollectionId,215 collection: CollectionId,
209 token: TokenId,216 token: TokenId,
210 budget: &dyn Budget,217 budget: &dyn Budget,
211 ) -> Result<T::CrossAccountId, DispatchError> {218 ) -> Result<Option<T::CrossAccountId>, DispatchError> {
212 let owner = Self::parent_chain(collection, token)219 let owner = Self::parent_chain(collection, token)
213 .take_while(|_| budget.consume())220 .take_while(|_| budget.consume())
214 .find(|p| matches!(p, Ok(Parent::User(_) | Parent::TokenNotFound)))221 .find(|p| {
222 matches!(
223 p,
224 Ok(Parent::User(_) | Parent::TokenNotFound | Parent::MultipleOwners)
225 )
226 })
215 .ok_or(<Error<T>>::DepthLimit)??;227 .ok_or(<Error<T>>::DepthLimit)??;
216228
217 Ok(match owner {229 Ok(match owner {
218 Parent::User(v) => v,230 Parent::User(v) => Some(v),
231 Parent::MultipleOwners => None,
219 _ => fail!(<Error<T>>::TokenNotFound),232 _ => fail!(<Error<T>>::TokenNotFound),
220 })233 })
221 }234 }
222235
223 /// Find the topmost parent and check that assigning `for_nest` token as a child for236 /// Find the topmost parent and check that assigning `for_nest` token as a child for
224 /// `token` wouldn't create a cycle.237 /// `token` wouldn't create a cycle.
238 ///
239 /// Returns `None` if the token has multiple owners.
225 ///240 ///
226 /// - `budget`: Limit for searching parents in depth.241 /// - `budget`: Limit for searching parents in depth.
227 pub fn get_checked_topmost_owner(242 pub fn get_checked_topmost_owner(
228 collection: CollectionId,243 collection: CollectionId,
229 token: TokenId,244 token: TokenId,
230 for_nest: Option<(CollectionId, TokenId)>,245 for_nest: Option<(CollectionId, TokenId)>,
231 budget: &dyn Budget,246 budget: &dyn Budget,
232 ) -> Result<T::CrossAccountId, DispatchError> {247 ) -> Result<Option<T::CrossAccountId>, DispatchError> {
233 // Tried to nest token in itself248 // Tried to nest token in itself
234 if Some((collection, token)) == for_nest {249 if Some((collection, token)) == for_nest {
235 return Err(<Error<T>>::OuroborosDetected.into());250 return Err(<Error<T>>::OuroborosDetected.into());
242 return Err(<Error<T>>::OuroborosDetected.into())257 return Err(<Error<T>>::OuroborosDetected.into())
243 }258 }
244 // Token is owned by other user259 // Token is owned by other user
245 Parent::User(user) => return Ok(user),260 Parent::User(user) => return Ok(Some(user)),
246 Parent::TokenNotFound => return Err(<Error<T>>::TokenNotFound.into()),261 Parent::TokenNotFound => return Err(<Error<T>>::TokenNotFound.into()),
262 Parent::MultipleOwners => return Ok(None),
247 // Continue parent chain263 // Continue parent chain
248 Parent::Token(_, _) => {}264 Parent::Token(_, _) => {}
249 }265 }
284 budget: &dyn Budget,300 budget: &dyn Budget,
285 ) -> Result<bool, DispatchError> {301 ) -> Result<bool, DispatchError> {
286 let target_parent = match T::CrossTokenAddressMapping::address_to_token(&user) {302 let target_parent = match T::CrossTokenAddressMapping::address_to_token(&user) {
287 Some((collection, token)) => Self::find_topmost_owner(collection, token, budget)?,303 Some((collection, token)) => match Self::find_topmost_owner(collection, token, budget)?
304 {
305 Some(topmost_owner) => topmost_owner,
306 None => return Ok(false),
307 },
288 None => user,308 None => user,
289 };309 };
290310
291 Self::get_checked_topmost_owner(collection, token, for_nest, budget)311 Self::get_checked_topmost_owner(collection, token, for_nest, budget).map(|indirect_owner| {
292 .map(|indirect_owner| indirect_owner == target_parent)312 indirect_owner.map_or(false, |indirect_owner| indirect_owner == target_parent)
313 })
293 }314 }
294315
295 /// Checks that `under` is valid token and that `token_id` could be nested under it316 /// Checks that `under` is valid token and that `token_id` could be nested under it
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
1099 EmptyPropertyKey,1099 EmptyPropertyKey,
1100}1100}
1101
1102/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.
1103#[derive(Debug)]
1104pub enum TokenOwnerError {
1105 NotFound,
1106 MultipleOwners,
1107}
11011108
1102/// Marker for scope of property.1109/// Marker for scope of property.
1103///1110///
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
1616
17#[macro_export]17#[macro_export]
18macro_rules! dispatch_unique_runtime {18macro_rules! dispatch_unique_runtime {
19 ($collection:ident.$method:ident($($name:ident),*)) => {{19 ($collection:ident.$method:ident($($name:ident),*) $($rest:tt)*) => {{
20 let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);20 let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
21 let dispatch = collection.as_dyn();21 let dispatch = collection.as_dyn();
2222
23 Ok::<_, DispatchError>(dispatch.$method($($name),*))23 Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)
24 }};24 }};
25}25}
2626
73 }73 }
7474
75 fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {75 fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
76 dispatch_unique_runtime!(collection.token_owner(token))76 dispatch_unique_runtime!(collection.token_owner(token).ok())
77 }77 }
7878
79 fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError> {79 fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError> {
83 fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {83 fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
84 let budget = up_data_structs::budget::Value::new(10);84 let budget = up_data_structs::budget::Value::new(10);
8585
86 Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))86 Ok(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?)
87 }87 }
88 fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {88 fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
89 Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))89 Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))