git.delta.rocks / unique-network / refs/commits / 9e65253a1d22

difftreelog

feat(rmrk-rpc) rpc refactoring

Fahrrader2022-05-25parent: #d364b89.patch.diff
in: master

6 files changed

modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -22,7 +22,7 @@
 use sp_std::vec::Vec;
 use up_data_structs::*;
 use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};
-use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};
+use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};
 use pallet_evm::account::CrossAccountId;
 
 pub use pallet::*;
@@ -396,6 +396,15 @@
         Ok(collection)
     }
 
+    // should this even be here, might displace it to common/nonfungible -- but they did not need it, only rmrk does
+    pub fn collection_exists(collection_id: CollectionId) -> bool {
+        <pallet_common::CollectionById<T>>::contains_key(collection_id)
+    }
+
+    pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
+        <TokenData<T>>::contains_key((collection_id, nft_id))
+    }
+
     pub fn get_collection_property(collection_id: CollectionId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
         let collection_property = <PalletCommon<T>>::collection_properties(collection_id)
             .get(&rmrk_property!(Config=T, key)?)
@@ -414,6 +423,13 @@
         Ok(collection_type)
     }
 
+    pub fn ensure_collection_type(collection_id: CollectionId, collection_type: CollectionType) -> DispatchResult {
+        let actual_type = Self::get_collection_type(collection_id)?;
+        ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);
+
+        Ok(())
+    }
+
     pub fn get_nft_property(collection_id: CollectionId, nft_id: TokenId, key: RmrkProperty) -> Result<PropertyValue, DispatchError> {
         let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
             .get(&rmrk_property!(Config=T, key)?)
@@ -423,9 +439,16 @@
         Ok(nft_property)
     }
 
-    pub fn check_collection_type(collection_id: CollectionId, collection_type: CollectionType) -> DispatchResult {
-        let actual_type = Self::get_collection_type(collection_id)?;
-        ensure!(actual_type == collection_type, <CommonError<T>>::NoPermission);
+    pub fn get_nft_type(collection_id: CollectionId, token_id: TokenId) -> Result<NftType, DispatchError> {
+        <TokenData<T>>::get((collection_id, token_id))
+            .unwrap()
+            .rmrk_nft_type()
+            .ok_or(<Error<T>>::NoAvailableNftId.into())
+    }
+
+    pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {
+        let actual_type = Self::get_nft_type(collection_id, token_id)?;
+        ensure!(actual_type == nft_type, <CommonError<T>>::NoPermission);
 
         Ok(())
     }
@@ -434,7 +457,7 @@
         collection_id: CollectionId,
         collection_type: CollectionType
     ) -> Result<NonfungibleHandle<T>, DispatchError> {
-        Self::check_collection_type(collection_id, collection_type)?;
+        Self::ensure_collection_type(collection_id, collection_type)?;
 
         Self::get_nft_collection(collection_id)
     }
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/misc.rs
+++ b/pallets/proxy-rmrk-core/src/misc.rs
@@ -82,15 +82,27 @@
     }
 }
 
-pub trait RmrkDecode<T: Decode> {
-    fn decode_property(&self) -> Option<T>;
+pub trait RmrkDecode<T: Decode + Default, S> {
+    fn decode_or_default(&self) -> T;
 }
 
-impl<T: Decode> RmrkDecode<T> for RmrkString {
-    fn decode_property(&self) -> Option<T> { // todo access runtime errors? // but then rmrk_nft_type must have it too
+impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {
+    fn decode_or_default(&self) -> T {
         let mut value = self.as_slice();
 
-        T::decode(&mut value).ok()
+        T::decode(&mut value).unwrap_or_default()
+    }
+}
+
+pub trait RmrkRebind<T, S> {
+    fn rebind(&self) -> BoundedVec<u8, S>;
+}
+
+impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T> where BoundedVec<u8, S>: TryFrom<Vec<u8>> {
+    fn rebind(&self) -> BoundedVec<u8, S> {
+        BoundedVec::<u8, S>::try_from(
+            self.clone().into_inner()
+        ).unwrap_or_default()
     }
 }
 
modifiedprimitives/data-structs/src/rmrk.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/rmrk.rs
+++ b/primitives/data-structs/src/rmrk.rs
@@ -360,14 +360,14 @@
 }
 
 #[cfg_attr(feature = "std", derive(Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
+#[derive(Encode, Decode, Debug, Default, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
 #[cfg_attr(
 	feature = "std",
 	serde(bound = "BoundedCollectionList: AsRef<[CollectionId]>")
 )]
 pub enum EquippableList<BoundedCollectionList> {
 	All,
-	Empty,
+	#[default] Empty,
 	Custom(
 		#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
 		BoundedCollectionList
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -38,10 +38,10 @@
                     keys: Option<Vec<Vec<u8>>>
                 ) -> Result<Vec<Property>, DispatchError> {
                     let keys = keys.map(
-                        |keys| pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)
+                        |keys| Common::bytes_keys_to_property_keys(keys)
                     ).transpose()?;
 
-                    pallet_common::Pallet::<Runtime>::filter_collection_properties(collection, keys)
+                    Common::filter_collection_properties(collection, keys)
                 }
 
                 fn token_properties(
@@ -50,7 +50,7 @@
                     keys: Option<Vec<Vec<u8>>>
                 ) -> Result<Vec<Property>, DispatchError> {
                     let keys = keys.map(
-                        |keys| pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)
+                        |keys| Common::bytes_keys_to_property_keys(keys)
                     ).transpose()?;
 
                     dispatch_unique_runtime!(collection.token_properties(token_id, keys))
@@ -61,10 +61,10 @@
                     keys: Option<Vec<Vec<u8>>>
                 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
                     let keys = keys.map(
-                        |keys| pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)
+                        |keys| Common::bytes_keys_to_property_keys(keys)
                     ).transpose()?;
 
-                    pallet_common::Pallet::<Runtime>::filter_property_permissions(collection, keys)
+                    Common::filter_property_permissions(collection, keys)
                 }
 
                 fn token_data(
@@ -144,34 +144,30 @@
                 fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
                     Ok(RmrkCore::last_collection_idx())
                 }
+
                 fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
-                    // TODO decide on displacement to palettes -- does RMRK belong there, spread across common and nonfungible?
                     use frame_support::BoundedVec;
                     use scale_info::prelude::string::String;
-                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};
-
-                    // todo check if this is a rmrk standard collection? or simply trust and provide anyway?
-                    // client-is-always-right / enforce authority and order ?
+                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkRebind, RmrkDecode}};
 
                     let collection_id = CollectionId(collection_id);
-                    let collection = <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_typed_nft_collection(collection_id, CollectionType::Regular)?;
+                    let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {
+                        Ok(c) => c,
+                        Err(_) => return Ok(None),
+                    };
 
-                    let metadata = BoundedVec::try_from(
-                        <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_collection_property(collection_id, RmrkProperty::Metadata)?.into_inner()
-                    ).map_err(|_| <pallet_common::Error<Runtime>>::PropertyKeyIsTooLong)?;
-
-                    let nfts_count = (dispatch_unique_runtime!(collection_id.total_supply()) as Result<u32, DispatchError>)?; // todo? <Runtime>::total_supply(collection_id)
+                    let nfts_count = (dispatch_unique_runtime!(collection_id.total_supply()) as Result<u32, DispatchError>)?;
+                    //<Runtime as up_rpc::UniqueApi>::total_supply(collection_id); // todo can't find UniqueApi with disabled default features
 
                     Ok(Some(RmrkCollectionInfo {
                         issuer: collection.owner.clone(),
-                        metadata,
+                        metadata: RmrkCore::get_collection_property(collection_id, RmrkProperty::Metadata)?.decode_or_default(),
                         max: collection.limits.token_limit,
-                        symbol: BoundedVec::try_from(
-                            collection.token_prefix.clone().into_inner()
-                        ).map_err(|_| <pallet_common::Error<Runtime>>::PropertyKeyIsTooLong)?,
+                        symbol: collection.token_prefix.rebind(), // change
                         nfts_count
                     }))
                 }
+
                 fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
                     use frame_support::BoundedVec;
                     use up_data_structs::mapping::TokenAddressMapping;
@@ -179,6 +175,7 @@
 
                     let collection_id = CollectionId(collection_id);
                     let nft_id = TokenId(nft_by_id);
+                    if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
 
                     let owner = match (dispatch_unique_runtime!(collection_id.token_owner(nft_id)) as Result<Option<CrossAccountId>, DispatchError>)? {
                         Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {
@@ -187,36 +184,23 @@
                         },
                         None => return Ok(None)
                     };
-
-                    // todo displace querying property key array to rmrk proxy pallet
-                    let keys = [
-                        RmrkProperty::RoyaltyInfo,
-                        RmrkProperty::Metadata,
-                        RmrkProperty::Equipped,
-                        // ?? "rmrk:recipient", "rmrk:nft-type", "rmrk:resource-collection", "rmrk:resource-priorities"
-                    ];
-
-                    let properties = keys.into_iter().map(
-                        |key| BoundedVec::try_from(
-                            <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_nft_property(collection_id, nft_id, key).unwrap().into_inner()
-                        ).unwrap()
-                    )
-                    .collect::<Vec<RmrkString>>();
-
+                    
                     let allowance = pallet_nonfungible::Allowance::<Runtime>::get((collection_id, nft_id));
 
                     Ok(Some(RmrkInstanceInfo {
                         owner: owner,
-                        //recipient: , // prop?
-                        royalty: properties[0].clone().decode_property().unwrap(),
-                        metadata: properties[1].clone(),
-                        equipped: properties[2].clone().decode_property().unwrap(),
+                        royalty: RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?.decode_or_default(),
+                        metadata: RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::Metadata)?.decode_or_default(),
+                        equipped: RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::Equipped)?.decode_or_default(),
                         pending: allowance.is_some(),
                     }))
                 }
+
                 fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
                     let cross_account_id = CrossAccountId::from_sub(account_id);
                     let collection_id = CollectionId(collection_id);
+                    if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); }
+
                     Ok(
                         (dispatch_unique_runtime!(collection_id.account_tokens(cross_account_id)) as Result<Vec<TokenId>, DispatchError>)?
                         //<Runtime as up_rpc::UniqueApi<Block, CrossAccountId, AccountId>>::account_tokens(collection_id, cross_account_id)?
@@ -225,11 +209,14 @@
                             .collect::<Vec<_>>()
                     )
                 }
+
                 fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
                     use up_data_structs::mapping::TokenAddressMapping;
 
                     let collection_id = CollectionId(collection_id);
                     let nft_id = TokenId(nft_id);
+                    if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); }
+
                     let cross_account_id = CrossAccountId::from_eth(
                         EvmTokenAddressMapping::token_to_address(collection_id, nft_id)
                     );
@@ -243,21 +230,25 @@
                             .collect()
                     )
                 }
+
                 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-                    use frame_support::BoundedVec;
+                    use pallet_proxy_rmrk_core::misc::RmrkDecode;
 
                     let collection_id = CollectionId(collection_id);
-                    let properties = pallet_common::Pallet::<Runtime>::collection_properties(collection_id);
+                    if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); }
 
+                    let properties = Common::collection_properties(collection_id);
+
+                    // todo repeated code
                     return Ok(match filter_keys {
                         Some(keys) => {
-                            let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
+                            let keys = Common::bytes_keys_to_property_keys(keys)?;
                             let properties = keys
                                 .into_iter()
                                 .filter_map(|key| {
                                     properties.get(&key).map(|value| RmrkPropertyInfo {
-                                        key: BoundedVec::try_from(key.into_inner()).unwrap(),
-                                        value: BoundedVec::try_from(value.clone().into_inner()).unwrap(),
+                                        key: key.decode_or_default(),
+                                        value: value.decode_or_default(),
                                     })
                                 })
                                 .collect();
@@ -268,31 +259,35 @@
                             properties
                                 .iter()
                                 .filter_map(|(key, value)| Some(RmrkPropertyInfo {
-                                    key: BoundedVec::try_from(key.clone().into_inner()).unwrap(),
-                                    value: BoundedVec::try_from(value.clone().into_inner()).unwrap(),
+                                    key: key.decode_or_default(),
+                                    value: value.decode_or_default(),
                                 }))
                                 .collect()
                         }
                     });
                 }
+
                 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
                     use frame_support::BoundedVec;
+                    use pallet_proxy_rmrk_core::misc::RmrkDecode;
 
                     let collection_id = CollectionId(collection_id);
                     let token_id = TokenId(nft_id);
+                    if !RmrkCore::nft_exists(collection_id, token_id) { return Ok(Vec::new()); }
 
-		            let properties = pallet_nonfungible::Pallet::<Runtime>::token_properties((collection_id, token_id)); // todo look into usage of pallet_nonfungible
+		            let properties = Nonfungible::token_properties((collection_id, token_id));
+                    // todo look into this usage of pallet_nonfungible
 
                     // todo displace to a function? redundant code piece with collection props
                     return Ok(match filter_keys {
                         Some(keys) => {
-                            let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
+                            let keys = Common::bytes_keys_to_property_keys(keys)?;
                             let properties = keys
                                 .into_iter()
                                 .filter_map(|key| {
                                     properties.get(&key).map(|value| RmrkPropertyInfo {
-                                        key: BoundedVec::try_from(key.into_inner()).unwrap(),
-                                        value: BoundedVec::try_from(value.clone().into_inner()).unwrap(),
+                                        key: key.decode_or_default(),
+                                        value: value.decode_or_default(),
                                     })
                                 })
                                 .collect();
@@ -303,113 +298,76 @@
                             properties
                                 .iter()
                                 .filter_map(|(key, value)| Some(RmrkPropertyInfo {
-                                    key: BoundedVec::try_from(key.clone().into_inner()).unwrap(),
-                                    value: BoundedVec::try_from(value.clone().into_inner()).unwrap(),
+                                    key: key.decode_or_default(),
+                                    value: value.decode_or_default(),
                                 }))
                                 .collect()
                         }
                     });
                 }
+
                 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
                     use frame_support::BoundedVec;
-                    use pallet_proxy_rmrk_core::RmrkProperty;
+                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};
 
                     let collection_id = CollectionId(collection_id);
-                    let nft_id = TokenId(nft_id);
-
-                    // let keys = [
-                    //     RmrkProperty::RoyaltyInfo,
-                    //     RmrkProperty::Metadata,
-                    //     RmrkProperty::Equipped,
-                    //     RmrkProperty::Pending,
-                    //     // ?? "rmrk:recipient", "rmrk:nft-type", "rmrk:resource-collection", "rmrk:resource-priorities"
-                    // ];
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
 
-                    /*let resources = keys.into_iter().map(
-                        |key| BoundedVec::try_from(
-                            <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_nft_property(collection_id, nft_id, key).unwrap().into_inner()
-                        ).unwrap()
-                    )
-                    .collect::<Vec<RmrkString>>();*/
+                    let nft_id = TokenId(nft_id);
+                    if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
 
                     Ok(Vec::new(/*[RmrkResourceInfo {
-
+                        
                     }]*/))
                 }
+
                 fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {
                     todo!()
                 }
+
                 fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
                     use frame_support::BoundedVec;
                     use scale_info::prelude::string::String;
-                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType};
+                    use pallet_proxy_rmrk_core::{
+                        RmrkProperty, misc::{CollectionType, RmrkRebind, RmrkDecode},
+                    };
 
                     let collection_id = CollectionId(base_id);
-                    let collection = <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_typed_nft_collection(collection_id, CollectionType::Base)?;
-                    // todo check prop for being a base
-
-                    // todo export to macro? redundancy
-                    let keys = [
-                        RmrkProperty::BaseType,
-                    ];
-
-                    let properties = keys.into_iter().map(
-                        |key| BoundedVec::try_from(
-                            <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_collection_property(collection_id, key).unwrap().into_inner()
-                        )
-                    )
-                    // todo not-a-rmrk-collection error
-                    .collect::<Result<Vec<_>, _>>()
-                    .map_err(|_| <pallet_proxy_rmrk_core::Error<Runtime>>::CollectionUnknown)?;
+                    let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Base) {
+                        Ok(c) => c,
+                        Err(_) => return Ok(None),
+                    };
 
                     Ok(Some(RmrkBaseInfo {
                         issuer: collection.owner.clone(),
-                        base_type: properties[0].clone(),
-                        symbol: BoundedVec::try_from(
-                            collection.token_prefix.clone().into_inner()
-                        ).map_err(|_| <pallet_common::Error<Runtime>>::PropertyKeyIsTooLong)?,
+                        base_type: RmrkCore::get_collection_property(collection_id, RmrkProperty::BaseType)?.decode_or_default(),
+                        symbol: collection.token_prefix.rebind(),
                     }))
                 }
+
                 fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
                     use frame_support::BoundedVec;
-                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::{RmrkNft, RmrkDecode}};
+                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkNft, RmrkDecode}};
 
                     let collection_id = CollectionId(base_id);
-                    // todo check prop for being a base
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }
 
                     let parts = (dispatch_unique_runtime!(collection_id.collection_tokens()) as Result<Vec<TokenId>, DispatchError>)?
                         .iter()
                         .filter_map(|token_id| {
-                            let nft_type = <pallet_nonfungible::TokenData<Runtime>>::get((collection_id, token_id))
-                                //.map_err(|_| ) // no need, tis a filter_map
-                                .unwrap()
-                                .rmrk_nft_type()?;
-
-                            // dislocate to rmrkproxycore and simply send an array of keys
-                            let keys = [
-                                //RmrkProperty::PartId)?,
-                                RmrkProperty::Src,
-                                RmrkProperty::ZIndex,
-                                RmrkProperty::EquippableList,
-                            ];
-
-                            let properties = keys.into_iter().map(
-                                |key| BoundedVec::try_from(
-                                    <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_nft_property(collection_id, *token_id, key).unwrap().into_inner()
-                                ).unwrap()
-                            ).collect::<Vec<RmrkString>>();
+                            let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();
 
                             match nft_type {
                                 FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {
                                     id: token_id.0,
-                                    src: properties[0].clone().decode_property().unwrap(),
-                                    z: properties[1].clone().decode_property().unwrap(),
+                                    src: RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::Src).unwrap().decode_or_default(),
+                                    z: RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::ZIndex).unwrap().decode_or_default(),
                                 })),
                                 SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {
                                     id: token_id.0,
-                                    src: properties[0].clone().decode_property().unwrap(),
-                                    z: properties[1].clone().decode_property().unwrap(),
-                                    equippable: properties[2].clone().decode_property().unwrap(),
+                                    src: RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::Src).unwrap().decode_or_default(),
+                                    z: RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::ZIndex).unwrap().decode_or_default(),
+                                    equippable: RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::EquippableList).unwrap().decode_or_default(),
                                 })),
                                 _ => None
                             }
@@ -418,6 +376,7 @@
 
                     Ok(parts)
                 }
+
                 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
                     use frame_support::BoundedVec;
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::{RmrkNft, RmrkDecode}};
@@ -428,16 +387,11 @@
                     let theme_names = (dispatch_unique_runtime!(collection_id.collection_tokens()) as Result<Vec<TokenId>, DispatchError>)?
                         .iter()
                         .filter_map(|token_id| {
-                            let nft_type = <pallet_nonfungible::TokenData<Runtime>>::get((collection_id, token_id))
-                                .unwrap()
-                                .rmrk_nft_type()?;
-
+                            let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();
+                            
                             match nft_type {
                                 Theme => Some(
-                                    <pallet_proxy_rmrk_core::Pallet<Runtime>>::get_nft_property(
-                                        collection_id, *token_id, RmrkProperty::ThemeName
-                                    ).unwrap()
-                                    .into_inner()
+                                    RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::ThemeName).unwrap().decode_or_default()
                                 ),
                                 _ => None
                             }
@@ -446,6 +400,7 @@
 
                     Ok(theme_names)
                 }
+
                 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
                     use frame_support::BoundedVec;
 
@@ -457,7 +412,7 @@
                     let themes = (dispatch_unique_runtime!(collection_id.collection_tokens()) as Result<Vec<TokenId>, DispatchError>)?
                         .iter()
                         .filter_map(|token_id| {
-                            let properties = pallet_nonfungible::Pallet::<Runtime>::token_properties((collection_id, token_id));
+                            let properties = Nonfungible::token_properties((collection_id, token_id));
 
                             // todo ping properties for "rmrk:nft-type"
                             // if none, skip, None
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -37,6 +37,7 @@
     "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",
     "testStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/**.test.ts",
     "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/properties.test.ts",
+    "testGraphs": "mocha --timeout 9999999 -r ts-node/register ./**/graphs.test.ts",
     "testMigrationStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",
     "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",
     "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",
modifiedtests/src/nesting/graphs.test.tsdiffbeforeafterboth
32 return collectionId;32 return collectionId;
33}33}
3434
35describe('Graphs', () => {35describe.skip('Graphs', () => {
36 it('Ouroboros can\'t be created in a complex graph', async () => {36 it('Ouroboros can\'t be created in a complex graph', async () => {
37 await usingApi(async api => {37 await usingApi(async api => {
38 const alice = privateKey('//Alice');38 const alice = privateKey('//alice');
39 const collection = await buildComplexObjectGraph(api, alice);39 const collection = await buildComplexObjectGraph(api, alice);
4040
41 // to self41 // to self
56 });56 });
57});57});
5858
59import type { EventRecord } from '@polkadot/types/interfaces';
60import type { GenericEventData } from '@polkadot/types';
61import type { Option, Bytes } from '@polkadot/types-codec';
62import type {
63 RmrkTypesCollectionInfo as Collection,
64 RmrkTypesNftInfo as Nft,
65 RmrkTypesResourceInfo as Resource,
66 RmrkTypesBaseInfo as Base,
67 RmrkTypesPartType as PartType,
68 RmrkTypesNftChild as NftChild,
69 RmrkTypesTheme as Theme,
70 RmrkTypesPropertyInfo as Property,
71} from '@polkadot/types/lookup';
72
73interface TxResult<T> {
74 success: boolean;
75 successData: T | null;
76}
77
78export function extractTxResult<T>(
79 events: EventRecord[],
80 expectSection: string,
81 expectMethod: string,
82 extractAction: (data: GenericEventData) => T
83): TxResult<T> {
84 let success = false;
85 let successData = null;
86 events.forEach(({event: {data, method, section}}) => {
87 //console.log(expectSection + " "+ " " + section + " " + expectMethod + " " + method)
88 if (method == 'ExtrinsicSuccess') {
89 success = true;
90 } else if ((expectSection == section) && (expectMethod == method)) {
91 successData = extractAction(data);
92 }
93 });
94 const result: TxResult<T> = {
95 success,
96 successData,
97 };
98 return result;
99}
100
101export function extractRmrkCoreTxResult<T>(
102 events: EventRecord[],
103 expectMethod: string,
104 extractAction: (data: GenericEventData) => T
105): TxResult<T> {
106 return extractTxResult(events, 'rmrkCore', expectMethod, extractAction);
107}
108
109export async function expectTxFailure(expectedError: RegExp, promise: Promise<any>) {
110 await expect(promise).to.be.rejectedWith(expectedError);
111}
112
113export async function getCollectionsCount(api: ApiPromise): Promise<number> {
114 return (await api.rpc.rmrk.lastCollectionIdx()).toNumber();
115}
116
117export async function getCollection(api: ApiPromise, id: number): Promise<Option<Collection>> {
118 return api.rpc.rmrk.collectionById(id);
119}
120
121export async function createCollection(
122 api: ApiPromise,
123 issuerUri: string,
124 metadata: string,
125 max: number | null,
126 symbol: string
127): Promise<number> {
128 let collectionId = 0;
129
130 const oldCollectionCount = await getCollectionsCount(api);
131 const maxOptional = max ? max.toString() : null;
132 console.log(maxOptional)
133 console.log('right above me')
134
135 const issuer = privateKey(issuerUri);
136 const tx = api.tx.rmrkCore.createCollection(metadata, maxOptional, symbol);
137 const events = await executeTransaction(api, issuer, tx);
138
139 const collectionResult = extractRmrkCoreTxResult(
140 events, 'CollectionCreated', (data) => {
141 return parseInt(data[1].toString(), 10)
142 }
143 );
144 expect(collectionResult.success, 'Error: unable to create a collection').to.be.true;
145 const newCollectionCount = await getCollectionsCount(api);
146 expect(newCollectionCount).to.be.equal(oldCollectionCount + 1, 'Error: NFT collection count should increase');
147
148 collectionId = collectionResult.successData ?? 0;
149
150 console.log(collectionId);
151
152 const collectionOption = await getCollection(api, collectionId);
153
154 expect(collectionOption.isSome, 'Error: unable to fetch created NFT collection').to.be.true;
155
156 const collection = collectionOption.unwrap();
157
158 expect(collection.metadata.toUtf8()).to.be.equal(metadata, "Error: Invalid NFT collection metadata");
159 console.log(collection.max, max)
160 expect(collection.max.isSome).to.be.equal(max !== null, "Error: Invalid NFT collection max");
161
162 if (collection.max.isSome) {
163 expect(collection.max.unwrap().toNumber()).to.be.equal(max, "Error: Invalid NFT collection max");
164 }
165 expect(collection.symbol.toUtf8()).to.be.equal(symbol, "Error: Invalid NFT collection's symbol");
166 expect(collection.nftsCount.toNumber()).to.be.equal(0, "Error: NFT collection shoudn't have any tokens");
167 expect(collection.issuer.toString()).to.be.equal(issuer.address, "Error: Invalid NFT collection issuer");
168
169 return collectionId;
170}
171
172export async function deleteCollection(
173 api: ApiPromise,
174 issuerUri: string,
175 collectionId: string
176): Promise<number> {
177 const issuer = privateKey(issuerUri);
178 const tx = api.tx.rmrkCore.destroyCollection(collectionId);
179 const events = await executeTransaction(api, issuer, tx);
180
181 const collectionTxResult = extractRmrkCoreTxResult(
182 events,
183 "CollectionDestroy",
184 (data) => {
185 return parseInt(data[1].toString(), 10);
186 }
187 );
188 expect(collectionTxResult.success, 'Error: Unable to delete NFT collection').to.be.true;
189
190 const collection = await getCollection(
191 api,
192 parseInt(collectionId, 10)
193 );
194 expect(collection.isEmpty, 'Error: NFT collection should be deleted').to.be.true;
195
196 return 0;
197}
198
199describe('Something', () => {
200 const alice = '//Alice';
201 const bob = "//Bob";
202
203 it('create NFT collection', async () => {
204 await usingApi(async api => {
205 await createCollection(api, alice, 'test-metadata', 42, 'test-symbol');
206 //console.log((await api.rpc.rmrk.base(3)).toHuman());
207 });
208 });
209
210 it('create NFT collection without token limit', async () => {
211 await usingApi(async api => {
212 await createCollection(api, alice, 'no-limit-metadata', null, 'no-limit-symbol');
213 });
214 });
215
216 it("Delete NFT collection", async () => {
217 await usingApi(async api => {
218 await createCollection(
219 api,
220 alice,
221 "test-metadata",
222 null,
223 "test-symbol"
224 ).then(async (collectionId) => {
225 await deleteCollection(api, alice, collectionId.toString());
226 });
227 });
228 });
229
230 it("[Negative] delete non-existing NFT collection", async () => {
231 await usingApi(async api => {
232 const tx = deleteCollection(api, alice, "99999");
233 await expectTxFailure(/rmrkCore.CollectionUnknown/, tx);
234 });
235 });
236
237 it("[Negative] delete not an owner NFT collection", async () => {
238 await usingApi(async api => {
239 await createCollection(
240 api,
241 alice,
242 "test-metadata",
243 null,
244 "test-symbol"
245 ).then(async (collectionId) => {
246 const tx = deleteCollection(api, bob, collectionId.toString());
247 await expectTxFailure(/uniques.NoPermission/, tx);
248 });
249 });
250 });
251});