difftreelog
fix(rmrk) include pending children into nft_children RPC
in: master
3 files changed
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -16,10 +16,15 @@
#![cfg_attr(not(feature = "std"), no_std)]
-use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};
+use frame_support::{
+ pallet_prelude::*,
+ transactional,
+ BoundedVec,
+ dispatch::DispatchResult,
+};
use frame_system::{pallet_prelude::*, ensure_signed};
use sp_runtime::{DispatchError, Permill, traits::StaticLookup};
-use sp_std::vec::Vec;
+use sp_std::{vec::Vec, collections::btree_set::BTreeSet};
use up_data_structs::{*, mapping::TokenAddressMapping};
use pallet_common::{
Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,
@@ -48,6 +53,10 @@
pub const NESTING_BUDGET: u32 = 5;
+type PendingTarget = (CollectionId, TokenId);
+type PendingChild = (RmrkCollectionId, RmrkNftId);
+type PendingChildrenMap = BTreeSet<PendingChild>;
+
#[frame_support::pallet]
pub mod pallet {
use super::*;
@@ -383,12 +392,13 @@
[
Self::rmrk_property(TokenType, &NftType::Regular)?,
Self::rmrk_property(Transferable, &transferable)?,
- Self::rmrk_property(PendingNftAccept, &false)?,
+ Self::rmrk_property(PendingNftAccept, &None::<PendingTarget>)?,
Self::rmrk_property(RoyaltyInfo, &royalty_info)?,
Self::rmrk_property(Metadata, &metadata)?,
Self::rmrk_property(Equipped, &false)?,
Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
Self::rmrk_property(NextResourceId, &(0 as RmrkResourceId))?,
+ Self::rmrk_property(PendingChildren, &PendingChildrenMap::new())?,
]
.into_iter(),
)
@@ -483,11 +493,11 @@
);
ensure!(
- !Self::get_nft_property_decoded(
+ Self::get_nft_property_decoded::<Option<PendingTarget>>(
collection_id,
nft_id,
RmrkProperty::PendingNftAccept
- )?,
+ )?.is_none(),
<Error<T>>::NoPermission
);
@@ -524,7 +534,15 @@
collection.id,
nft_id,
PropertyScope::Rmrk,
- Self::rmrk_property(PendingNftAccept, &approval_required)?,
+ Self::rmrk_property::<Option<PendingTarget>>(
+ PendingNftAccept,
+ &Some((target_collection_id, target_nft_id.into()))
+ )?,
+ )?;
+
+ Self::insert_pending_child(
+ (target_collection_id, target_nft_id.into()),
+ (rmrk_collection_id, rmrk_nft_id),
)?;
} else {
target_owner = T::CrossTokenAddressMapping::token_to_address(
@@ -618,13 +636,23 @@
}
})?;
- <PalletNft<T>>::set_scoped_token_property(
- collection.id,
+ let pending_target = Self::get_nft_property_decoded::<Option<PendingTarget>>(
+ collection_id,
nft_id,
- PropertyScope::Rmrk,
- Self::rmrk_property(PendingNftAccept, &false)?,
+ RmrkProperty::PendingNftAccept
)?;
+ if let Some(pending_target) = pending_target {
+ Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?;
+
+ <PalletNft<T>>::set_scoped_token_property(
+ collection.id,
+ nft_id,
+ PropertyScope::Rmrk,
+ Self::rmrk_property(PendingNftAccept, &None::<PendingTarget>)?,
+ )?;
+ }
+
Self::deposit_event(Event::NFTAccepted {
sender,
recipient: new_owner,
@@ -663,15 +691,18 @@
<Error<T>>::NoAvailableNftId
);
- ensure!(
- Self::get_nft_property_decoded(
- collection_id,
- nft_id,
- RmrkProperty::PendingNftAccept
- )?,
- <Error<T>>::CannotRejectNonPendingNft
- );
+ let pending_target = Self::get_nft_property_decoded::<Option<PendingTarget>>(
+ collection_id,
+ nft_id,
+ RmrkProperty::PendingNftAccept
+ )?;
+
+ match pending_target {
+ Some(pending_target) => Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?,
+ None => return Err(<Error<T>>::CannotRejectNonPendingNft.into()),
+ }
+
Self::destroy_nft(
cross_sender,
collection_id,
@@ -1147,6 +1178,64 @@
)
}
+ fn insert_pending_child(
+ target: (CollectionId, TokenId),
+ child: (RmrkCollectionId, RmrkNftId),
+ ) -> DispatchResult {
+ Self::mutate_pending_child(target, |pending_children| {
+ pending_children.insert(child);
+ })
+ }
+
+ fn remove_pending_child(
+ target: (CollectionId, TokenId),
+ child: (RmrkCollectionId, RmrkNftId),
+ ) -> DispatchResult {
+ Self::mutate_pending_child(target, |pending_children| {
+ pending_children.remove(&child);
+ })
+ }
+
+ fn mutate_pending_child(
+ (target_collection_id, target_nft_id): (CollectionId, TokenId),
+ f: impl FnOnce(&mut PendingChildrenMap),
+ ) -> DispatchResult {
+ <PalletNft<T>>::try_mutate_token_aux_property(
+ target_collection_id,
+ target_nft_id,
+ PropertyScope::Rmrk,
+ Self::rmrk_property_key(PendingChildren)?,
+ |pending_children| -> DispatchResult {
+ let mut map = match pending_children {
+ Some(map) => Self::decode_property(map)?,
+ None => PendingChildrenMap::new(),
+ };
+
+ f(&mut map);
+
+ *pending_children = Some(Self::encode_property(&map)?);
+
+ Ok(())
+ },
+ )
+ }
+
+ fn iterate_pending_children(collection_id: CollectionId, nft_id: TokenId) -> Result<impl Iterator<Item=PendingChild>, DispatchError> {
+ let property = <PalletNft<T>>::token_aux_property((
+ collection_id,
+ nft_id,
+ PropertyScope::Rmrk,
+ Self::rmrk_property_key(PendingChildren)?
+ ));
+
+ let pending_children = match property {
+ Some(map) => Self::decode_property(&map)?,
+ None => PendingChildrenMap::new(),
+ };
+
+ Ok(pending_children.into_iter())
+ }
+
fn acquire_next_resource_id(
collection_id: CollectionId,
nft_id: TokenId,
@@ -1526,15 +1615,13 @@
Value: Decode + Default,
Mapper: Fn(Key, Value) -> R,
{
- let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;
-
let properties = match token_id {
Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),
None => <PalletCommon<T>>::collection_properties(collection_id),
};
let properties = properties.into_iter().filter_map(move |(key, value)| {
- let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;
+ let key = strip_key_prefix(&key, USER_PROPERTY_PREFIX)?;
let key: Key = key.to_vec().try_into().ok()?;
let value: Value = value.decode().ok()?;
pallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/property.rs
+++ b/pallets/proxy-rmrk-core/src/property.rs
@@ -15,9 +15,11 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
use super::*;
+use up_data_structs::PropertyScope;
use core::convert::AsRef;
-const RESOURCE_ID_PREFIX: &str = "rsid-";
+pub const RESOURCE_ID_PREFIX: &str = "rsid-";
+pub const USER_PROPERTY_PREFIX: &str = "userprop-";
pub enum RmrkProperty<'r> {
Metadata,
@@ -31,6 +33,7 @@
NextResourceId,
ResourceId(RmrkResourceId),
PendingNftAccept,
+ PendingChildren,
Parts,
Base,
Src,
@@ -73,6 +76,7 @@
Self::NextResourceId => key!("next-resource-id"),
Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()),
Self::PendingNftAccept => key!("pending-nft-accept"),
+ Self::PendingChildren => key!("pending-children"),
Self::Parts => key!("parts"),
Self::Base => key!("base"),
Self::Src => key!("src"),
@@ -83,7 +87,19 @@
Self::ZIndex => key!("z-index"),
Self::ThemeName => key!("theme-name"),
Self::ThemeInherit => key!("theme-inherit"),
- Self::UserProperty(name) => key!("userprop-", name),
+ Self::UserProperty(name) => key!(USER_PROPERTY_PREFIX, name),
}
}
}
+
+pub fn strip_key_prefix(key: &PropertyKey, prefix: &str) -> Option<PropertyKey> {
+ let key_prefix = PropertyKey::try_from(prefix.as_bytes().to_vec()).ok()?;
+ let key_prefix = PropertyScope::Rmrk.apply(key_prefix).ok()?;
+
+ key.as_slice().strip_prefix(key_prefix.as_slice())?
+ .to_vec().try_into().ok()
+}
+
+pub fn is_valid_key_prefix(key: &PropertyKey, prefix: &str) -> bool {
+ strip_key_prefix(key, prefix).is_some()
+}
pallets/proxy-rmrk-core/src/rpc.rsdiffbeforeafterboth1use super::*;23pub fn last_collection_idx<T: Config>() -> Result<RmrkCollectionId, DispatchError> {4 Ok(<Pallet<T>>::last_collection_idx())5}67pub fn collection_by_id<T: Config>(8 collection_id: RmrkCollectionId,9) -> Result<Option<RmrkCollectionInfo<T::AccountId>>, DispatchError> {10 let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(11 collection_id,12 misc::CollectionType::Regular,13 ) {14 Ok(c) => c,15 Err(_) => return Ok(None),16 };1718 let nfts_count = collection.total_supply();1920 Ok(Some(RmrkCollectionInfo {21 issuer: collection.owner.clone(),22 metadata: <Pallet<T>>::get_collection_property_decoded(23 collection_id,24 RmrkProperty::Metadata,25 )?,26 max: collection.limits.token_limit,27 symbol: <Pallet<T>>::rebind(&collection.token_prefix)?,28 nfts_count,29 }))30}3132pub fn nft_by_id<T: Config>(33 collection_id: RmrkCollectionId,34 nft_by_id: RmrkNftId,35) -> Result<Option<RmrkInstanceInfo<T::AccountId>>, DispatchError> {36 let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(37 collection_id,38 misc::CollectionType::Regular,39 ) {40 Ok(c) => c,41 Err(_) => return Ok(None),42 };4344 let nft_id = TokenId(nft_by_id);45 if !<Pallet<T>>::nft_exists(collection_id, nft_id) {46 return Ok(None);47 }4849 let owner = match collection.token_owner(nft_id) {50 Some(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {51 Some((col, tok)) => {52 let rmrk_collection = <Pallet<T>>::rmrk_collection_id(col)?;5354 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)55 }56 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()),57 },58 None => return Ok(None),59 };6061 Ok(Some(RmrkInstanceInfo {62 owner: owner,63 royalty: <Pallet<T>>::get_nft_property_decoded(64 collection_id,65 nft_id,66 RmrkProperty::RoyaltyInfo,67 )?,68 metadata: <Pallet<T>>::get_nft_property_decoded(69 collection_id,70 nft_id,71 RmrkProperty::Metadata,72 )?,73 equipped: <Pallet<T>>::get_nft_property_decoded(74 collection_id,75 nft_id,76 RmrkProperty::Equipped,77 )?,78 pending: <Pallet<T>>::get_nft_property_decoded(79 collection_id,80 nft_id,81 RmrkProperty::PendingNftAccept,82 )?,83 }))84}8586pub fn account_tokens<T: Config>(87 account_id: T::AccountId,88 collection_id: RmrkCollectionId,89) -> Result<Vec<RmrkNftId>, DispatchError> {90 let cross_account_id = CrossAccountId::from_sub(account_id);9192 let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(93 collection_id,94 misc::CollectionType::Regular,95 ) {96 Ok(c) => c,97 Err(_) => return Ok(Vec::new()),98 };99100 let tokens = collection101 .account_tokens(cross_account_id)102 .into_iter()103 .filter(|token| {104 let is_pending = <Pallet<T>>::get_nft_property_decoded(105 collection_id,106 *token,107 RmrkProperty::PendingNftAccept,108 )109 .unwrap_or(true);110111 !is_pending112 })113 .map(|token| token.0)114 .collect();115116 Ok(tokens)117}118119pub fn nft_children<T: Config>(120 collection_id: RmrkCollectionId,121 nft_id: RmrkNftId,122) -> Result<Vec<RmrkNftChild>, DispatchError> {123 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {124 Ok(id) => id,125 Err(_) => return Ok(Vec::new()),126 };127 let nft_id = TokenId(nft_id);128 if !<Pallet<T>>::nft_exists(collection_id, nft_id) {129 return Ok(Vec::new());130 }131132 Ok(133 pallet_nonfungible::TokenChildren::<T>::iter_prefix((collection_id, nft_id))134 .filter_map(|((child_collection, child_token), _)| {135 let is_pending = <Pallet<T>>::get_nft_property_decoded(136 child_collection,137 child_token,138 RmrkProperty::PendingNftAccept,139 )140 .ok()?;141142 if is_pending {143 return None;144 }145146 let rmrk_child_collection =147 <Pallet<T>>::rmrk_collection_id(child_collection).ok()?;148149 Some(RmrkNftChild {150 collection_id: rmrk_child_collection,151 nft_id: child_token.0,152 })153 })154 .collect(),155 )156}157158pub fn collection_properties<T: Config>(159 collection_id: RmrkCollectionId,160 filter_keys: Option<Vec<RmrkPropertyKey>>,161) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {162 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {163 Ok(id) => id,164 Err(_) => return Ok(Vec::new()),165 };166 if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {167 return Ok(Vec::new());168 }169170 let properties = <Pallet<T>>::filter_user_properties(171 collection_id,172 /* token_id = */ None,173 filter_keys,174 |key, value| RmrkPropertyInfo { key, value },175 )?;176177 Ok(properties)178}179180pub fn nft_properties<T: Config>(181 collection_id: RmrkCollectionId,182 nft_id: RmrkNftId,183 filter_keys: Option<Vec<RmrkPropertyKey>>,184) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {185 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {186 Ok(id) => id,187 Err(_) => return Ok(Vec::new()),188 };189 let token_id = TokenId(nft_id);190191 if <Pallet<T>>::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {192 return Ok(Vec::new());193 }194195 let properties = <Pallet<T>>::filter_user_properties(196 collection_id,197 Some(token_id),198 filter_keys,199 |key, value| RmrkPropertyInfo { key, value },200 )?;201202 Ok(properties)203}204205pub fn nft_resources<T: Config>(206 collection_id: RmrkCollectionId,207 nft_id: RmrkNftId,208) -> Result<Vec<RmrkResourceInfo>, DispatchError> {209 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {210 Ok(id) => id,211 Err(_) => return Ok(Vec::new()),212 };213 if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {214 return Ok(Vec::new());215 }216217 let nft_id = TokenId(nft_id);218 if <Pallet<T>>::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() {219 return Ok(Vec::new());220 }221222 let resources = <pallet_nonfungible::Pallet<T>>::iterate_token_aux_properties(223 collection_id,224 nft_id,225 PropertyScope::Rmrk,226 )227 .filter_map(|(_, value)| {228 let resource_info: RmrkResourceInfo = <Pallet<T>>::decode_property(&value).ok()?;229230 Some(resource_info)231 })232 .collect();233234 Ok(resources)235}236237pub fn nft_resource_priority<T: Config>(238 collection_id: RmrkCollectionId,239 nft_id: RmrkNftId,240 resource_id: RmrkResourceId,241) -> Result<Option<u32>, DispatchError> {242 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {243 Ok(id) => id,244 Err(_) => return Ok(None),245 };246 if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {247 return Ok(None);248 }249250 let nft_id = TokenId(nft_id);251 if <Pallet<T>>::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() {252 return Ok(None);253 }254255 let priorities: Vec<_> = <Pallet<T>>::get_nft_property_decoded(256 collection_id,257 nft_id,258 RmrkProperty::ResourcePriorities,259 )?;260 Ok(priorities261 .into_iter()262 .enumerate()263 .find(|(_, id)| *id == resource_id)264 .map(|(priority, _): (usize, RmrkResourceId)| priority as u32))265}1use super::*;23pub fn last_collection_idx<T: Config>() -> Result<RmrkCollectionId, DispatchError> {4 Ok(<Pallet<T>>::last_collection_idx())5}67pub fn collection_by_id<T: Config>(8 collection_id: RmrkCollectionId,9) -> Result<Option<RmrkCollectionInfo<T::AccountId>>, DispatchError> {10 let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(11 collection_id,12 misc::CollectionType::Regular,13 ) {14 Ok(c) => c,15 Err(_) => return Ok(None),16 };1718 let nfts_count = collection.total_supply();1920 Ok(Some(RmrkCollectionInfo {21 issuer: collection.owner.clone(),22 metadata: <Pallet<T>>::get_collection_property_decoded(23 collection_id,24 RmrkProperty::Metadata,25 )?,26 max: collection.limits.token_limit,27 symbol: <Pallet<T>>::rebind(&collection.token_prefix)?,28 nfts_count,29 }))30}3132pub fn nft_by_id<T: Config>(33 collection_id: RmrkCollectionId,34 nft_by_id: RmrkNftId,35) -> Result<Option<RmrkInstanceInfo<T::AccountId>>, DispatchError> {36 let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(37 collection_id,38 misc::CollectionType::Regular,39 ) {40 Ok(c) => c,41 Err(_) => return Ok(None),42 };4344 let nft_id = TokenId(nft_by_id);45 if !<Pallet<T>>::nft_exists(collection_id, nft_id) {46 return Ok(None);47 }4849 let owner = match collection.token_owner(nft_id) {50 Some(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {51 Some((col, tok)) => {52 let rmrk_collection = <Pallet<T>>::rmrk_collection_id(col)?;5354 RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)55 }56 None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()),57 },58 None => return Ok(None),59 };6061 Ok(Some(RmrkInstanceInfo {62 owner: owner,63 royalty: <Pallet<T>>::get_nft_property_decoded(64 collection_id,65 nft_id,66 RmrkProperty::RoyaltyInfo,67 )?,68 metadata: <Pallet<T>>::get_nft_property_decoded(69 collection_id,70 nft_id,71 RmrkProperty::Metadata,72 )?,73 equipped: <Pallet<T>>::get_nft_property_decoded(74 collection_id,75 nft_id,76 RmrkProperty::Equipped,77 )?,78 pending: <Pallet<T>>::get_nft_property_decoded(79 collection_id,80 nft_id,81 RmrkProperty::PendingNftAccept,82 )?,83 }))84}8586pub fn account_tokens<T: Config>(87 account_id: T::AccountId,88 collection_id: RmrkCollectionId,89) -> Result<Vec<RmrkNftId>, DispatchError> {90 let cross_account_id = CrossAccountId::from_sub(account_id);9192 let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(93 collection_id,94 misc::CollectionType::Regular,95 ) {96 Ok(c) => c,97 Err(_) => return Ok(Vec::new()),98 };99100 let tokens = collection101 .account_tokens(cross_account_id)102 .into_iter()103 .filter(|token| {104 let is_pending = <Pallet<T>>::get_nft_property_decoded(105 collection_id,106 *token,107 RmrkProperty::PendingNftAccept,108 )109 .unwrap_or(true);110111 !is_pending112 })113 .map(|token| token.0)114 .collect();115116 Ok(tokens)117}118119pub fn nft_children<T: Config>(120 collection_id: RmrkCollectionId,121 nft_id: RmrkNftId,122) -> Result<Vec<RmrkNftChild>, DispatchError> {123 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {124 Ok(id) => id,125 Err(_) => return Ok(Vec::new()),126 };127 let nft_id = TokenId(nft_id);128 if !<Pallet<T>>::nft_exists(collection_id, nft_id) {129 return Ok(Vec::new());130 }131132 Ok(133 pallet_nonfungible::TokenChildren::<T>::iter_prefix((collection_id, nft_id))134 .filter_map(|((child_collection, child_token), _)| {135 let rmrk_child_collection =136 <Pallet<T>>::rmrk_collection_id(child_collection).ok()?;137138 Some(RmrkNftChild {139 collection_id: rmrk_child_collection,140 nft_id: child_token.0,141 })142 })143 .chain(144 <Pallet<T>>::iterate_pending_children(collection_id, nft_id)?145 .map(|(child_collection, child_nft_id)| RmrkNftChild {146 collection_id: child_collection,147 nft_id: child_nft_id,148 })149 )150 .collect(),151 )152}153154pub fn collection_properties<T: Config>(155 collection_id: RmrkCollectionId,156 filter_keys: Option<Vec<RmrkPropertyKey>>,157) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {158 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {159 Ok(id) => id,160 Err(_) => return Ok(Vec::new()),161 };162 if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {163 return Ok(Vec::new());164 }165166 let properties = <Pallet<T>>::filter_user_properties(167 collection_id,168 /* token_id = */ None,169 filter_keys,170 |key, value| RmrkPropertyInfo { key, value },171 )?;172173 Ok(properties)174}175176pub fn nft_properties<T: Config>(177 collection_id: RmrkCollectionId,178 nft_id: RmrkNftId,179 filter_keys: Option<Vec<RmrkPropertyKey>>,180) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {181 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {182 Ok(id) => id,183 Err(_) => return Ok(Vec::new()),184 };185 let token_id = TokenId(nft_id);186187 if <Pallet<T>>::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {188 return Ok(Vec::new());189 }190191 let properties = <Pallet<T>>::filter_user_properties(192 collection_id,193 Some(token_id),194 filter_keys,195 |key, value| RmrkPropertyInfo { key, value },196 )?;197198 Ok(properties)199}200201pub fn nft_resources<T: Config>(202 collection_id: RmrkCollectionId,203 nft_id: RmrkNftId,204) -> Result<Vec<RmrkResourceInfo>, DispatchError> {205 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {206 Ok(id) => id,207 Err(_) => return Ok(Vec::new()),208 };209 if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {210 return Ok(Vec::new());211 }212213 let nft_id = TokenId(nft_id);214 if <Pallet<T>>::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() {215 return Ok(Vec::new());216 }217218 let resources = <pallet_nonfungible::Pallet<T>>::iterate_token_aux_properties(219 collection_id,220 nft_id,221 PropertyScope::Rmrk,222 )223 .filter_map(|(key, value)| {224 if !is_valid_key_prefix(&key, RESOURCE_ID_PREFIX) {225 return None;226 }227228 let resource_info: RmrkResourceInfo = <Pallet<T>>::decode_property(&value).ok()?;229230 Some(resource_info)231 })232 .collect();233234 Ok(resources)235}236237pub fn nft_resource_priority<T: Config>(238 collection_id: RmrkCollectionId,239 nft_id: RmrkNftId,240 resource_id: RmrkResourceId,241) -> Result<Option<u32>, DispatchError> {242 let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {243 Ok(id) => id,244 Err(_) => return Ok(None),245 };246 if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {247 return Ok(None);248 }249250 let nft_id = TokenId(nft_id);251 if <Pallet<T>>::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() {252 return Ok(None);253 }254255 let priorities: Vec<_> = <Pallet<T>>::get_nft_property_decoded(256 collection_id,257 nft_id,258 RmrkProperty::ResourcePriorities,259 )?;260 Ok(priorities261 .into_iter()262 .enumerate()263 .find(|(_, id)| *id == resource_id)264 .map(|(priority, _): (usize, RmrkResourceId)| priority as u32))265}