git.delta.rocks / unique-network / refs/commits / ac4c4db2f485

difftreelog

feat implement theme RMRK RPC

Daniel Shiposha2022-05-25parent: #3cd2ab6.patch.diff
in: master

7 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
@@ -443,7 +443,7 @@
         <TokenData<T>>::get((collection_id, token_id))
             .unwrap()
             .rmrk_nft_type()
-            .ok_or(<Error<T>>::NoAvailableNftId.into())
+            .ok_or_else(|| <Error<T>>::NoAvailableNftId.into())
     }
 
     pub fn ensure_nft_type(collection_id: CollectionId, token_id: TokenId, nft_type: NftType) -> DispatchResult {
@@ -453,6 +453,65 @@
         Ok(())
     }
 
+    pub fn filter_theme_properties(
+        collection_id: CollectionId,
+        token_id: TokenId,
+        filter_keys: Option<Vec<RmrkPropertyKey>>
+    ) -> Result<Vec<RmrkThemeProperty>, DispatchError> {
+        filter_keys.map(|keys| {
+            let properties = keys.into_iter()
+                .filter_map(|key| {
+                    let key: RmrkString = key.try_into().ok()?;
+
+                    let value = Self::get_nft_property(
+                        collection_id,
+                        token_id,
+                        RmrkProperty::ThemeProperty(&key)
+                    ).ok()?.decode_or_default();
+
+                    let property = RmrkThemeProperty {
+                        key,
+                        value
+                    };
+
+                    Some(property)
+                })
+                .collect();
+
+            Ok(properties)
+        }).unwrap_or_else(|| {
+            let properties = Self::iterate_theme_properties(collection_id, token_id)?
+                .collect();
+
+            Ok(properties)
+        })
+    }
+
+    pub fn iterate_theme_properties(
+        collection_id: CollectionId,
+        token_id: TokenId
+    ) -> Result<impl Iterator<Item=RmrkThemeProperty>, DispatchError> {
+        let key_prefix = rmrk_property!(Config=T, key: ThemeProperty(&RmrkString::default()))?;
+
+        let properties = <PalletNft<T>>::token_properties((collection_id, token_id))
+            .into_iter()
+            .filter_map(move |(key, value)| {
+                let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;
+
+                let key: RmrkString = key.to_vec().try_into().ok()?;
+                let value: RmrkString = value.decode_or_default();
+
+                let property = RmrkThemeProperty {
+                    key,
+                    value
+                };
+
+                Some(property)
+            });
+
+        Ok(properties)
+    }
+
     pub fn get_typed_nft_collection(
         collection_id: CollectionId,
         collection_type: CollectionType
modifiedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
1use super::*;1use super::*;
2use core::convert::AsRef;2use core::convert::AsRef;
33
4pub enum RmrkProperty {4pub enum RmrkProperty<'r> {
5 Metadata,5 Metadata,
6 CollectionType,6 CollectionType,
7 RoyaltyInfo,7 RoyaltyInfo,
23 EquippableList,23 EquippableList,
24 ZIndex,24 ZIndex,
25 ThemeName,25 ThemeName,
26 ThemeProperty(RmrkString),26 ThemeProperty(&'r RmrkString),
27 ThemeInherit,27 ThemeInherit,
28}28}
2929
30impl RmrkProperty {30impl<'r> RmrkProperty<'r> {
31 pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {31 pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {
32 fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {32 fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {
33 container.as_ref()33 container.as_ref()
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -775,6 +775,10 @@
 		self.0.iter()
 	}
 
+	pub fn into_iter(self) -> impl Iterator<Item = (PropertyKey, Value)> {
+		self.0.into_iter()
+	}
+
 	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {
 		if key.is_empty() {
 			return Err(PropertiesError::EmptyPropertyKey);
@@ -848,6 +852,10 @@
 	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {
 		self.map.iter()
 	}
+
+	pub fn into_iter(self) -> impl Iterator<Item = (PropertyKey, PropertyValue)> {
+		self.map.into_iter()
+	}
 }
 
 impl TrySetProperty for Properties {
@@ -936,7 +944,8 @@
 pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
 pub type RmrkPartType =
 	PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;
-pub type RmrkTheme = Theme<RmrkString, Vec<ThemeProperty<RmrkString>>>;
+pub type RmrkThemeProperty = ThemeProperty<RmrkString>;
+pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;
 
 pub type RmrkRpcString = Vec<u8>;
 pub type RmrkThemeName = RmrkRpcString;
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -184,7 +184,7 @@
                         },
                         None => return Ok(None)
                     };
-                    
+
                     let allowance = pallet_nonfungible::Allowance::<Runtime>::get((collection_id, nft_id));
 
                     Ok(Some(RmrkInstanceInfo {
@@ -317,7 +317,7 @@
                     if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
 
                     Ok(Vec::new(/*[RmrkResourceInfo {
-                        
+
                     }]*/))
                 }
 
@@ -379,16 +379,18 @@
 
                 fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, 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 make sure this is theme
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {
+                        return Ok(Vec::new());
+                    }
 
-                    let theme_names = (dispatch_unique_runtime!(collection_id.collection_tokens()) as Result<Vec<TokenId>, DispatchError>)?
+                    let theme_names = (dispatch_unique_runtime!(collection_id.collection_tokens()))?
                         .iter()
                         .filter_map(|token_id| {
                             let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();
-                            
+
                             match nft_type {
                                 Theme => Some(
                                     RmrkCore::get_nft_property(collection_id, *token_id, RmrkProperty::ThemeName).unwrap().decode_or_default()
@@ -396,47 +398,59 @@
                                 _ => None
                             }
                         })
-                        .collect::<Vec<RmrkThemeName>>();
+                        .collect();
 
                     Ok(theme_names)
                 }
 
                 fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
                     use frame_support::BoundedVec;
+                    use pallet_proxy_rmrk_core::{
+                        RmrkProperty,
+                        misc::{CollectionType, NftType, RmrkNft, RmrkDecode}
+                    };
 
                     let collection_id = CollectionId(base_id);
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() {
+                        return Ok(None);
+                    }
 
-                    // todo one theme. filter collection tokens according to theme name, should result in one
-                    // (is it possible to search with iter_prefix for part of a struct that satisfies?..)
-                    // filter properties according to filter_keys and load them into resulting theme.properties
-                    let themes = (dispatch_unique_runtime!(collection_id.collection_tokens()) as Result<Vec<TokenId>, DispatchError>)?
-                        .iter()
-                        .filter_map(|token_id| {
-                            let properties = Nonfungible::token_properties((collection_id, token_id));
+                    let theme_info = (dispatch_unique_runtime!(collection_id.collection_tokens()))?
+                        .into_iter()
+                        .find_map(|token_id| {
+                            RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;
+
+                            let name: RmrkString = RmrkCore::get_nft_property(
+                                collection_id, token_id, RmrkProperty::ThemeName
+                            ).ok()?.decode_or_default();
 
-                            // todo ping properties for "rmrk:nft-type"
-                            // if none, skip, None
-                            // ugh gonna go through ALL properties, searching for matches for "rmrk:theme-property-<key>"
-                            let nft_type = "theme";
-                            match nft_type {
-                                "theme" => Some(RmrkTheme {
-                                    name: BoundedVec::try_from(
-                                        <pallet_nonfungible::TokenData<Runtime>>::get((collection_id, token_id))
-                                            .map(|t| t.const_data)
-                                            .unwrap_or_default()
-                                            .into_inner()
-                                    ).unwrap(),
-                                    // todo? (dispatch_unique_runtime!(collection_id.const_metadata(token_id)) as Result<Vec<u8>, DispatchError>)?,
-                                    properties: Vec::new(), // pain in the ass
-                                    inherit: false, // "rmrk:theme-inherit"
-                                }),
-                                _ => None
+                            if name == theme_name {
+                                Some((name, token_id))
+                            } else {
+                                None
                             }
-                        })
-                        .collect::<Vec<_>>();
+                        });
+
+                    let (name, theme_id) = match theme_info {
+                        Some((name, theme_id)) => (name, theme_id),
+                        None => return Ok(None)
+                    };
 
-                    // todo
-                    Ok(Some(themes[0].clone()))
+                    let properties = RmrkCore::filter_theme_properties(collection_id, theme_id, filter_keys)?;
+
+                    let inherit = RmrkCore::get_nft_property(
+                        collection_id,
+                        theme_id,
+                        RmrkProperty::ThemeInherit
+                    )?.decode_or_default();
+
+                    let theme = RmrkTheme {
+                        name,
+                        properties,
+                        inherit,
+                    };
+
+                    Ok(Some(theme))
                 }
             }
 
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -1149,7 +1149,7 @@
 		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
 		let dispatch = collection.as_dyn();
 
-		Ok(dispatch.$method($($name),*))
+		Ok::<_, DispatchError>(dispatch.$method($($name),*))
 	}};
 }
 
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -1122,7 +1122,7 @@
 		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
 		let dispatch = collection.as_dyn();
 
-		Ok(dispatch.$method($($name),*))
+		Ok::<_, DispatchError>(dispatch.$method($($name),*))
 	}};
 }
 
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -1127,7 +1127,7 @@
 		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
 		let dispatch = collection.as_dyn();
 
-		Ok(dispatch.$method($($name),*))
+		Ok::<_, DispatchError>(dispatch.$method($($name),*))
 	}};
 }