git.delta.rocks / unique-network / refs/commits / 5c5d937f9f7f

difftreelog

refactor iterate rmrk props, add rmrk proxy set_propertty

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

5 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
@@ -24,6 +24,7 @@
 use pallet_common::{Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations};
 use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};
 use pallet_evm::account::CrossAccountId;
+use core::convert::AsRef;
 
 pub use pallet::*;
 
@@ -85,6 +86,12 @@
 			owner: T::AccountId,
 			nft_id: RmrkNftId,
 		},
+        PropertySet {
+			collection_id: RmrkCollectionId,
+			maybe_nft_id: Option<RmrkNftId>,
+			key: RmrkKeyString,
+			value: RmrkValueString,
+		},
 	}
 
 	#[pallet::error]
@@ -291,7 +298,7 @@
 			collection_id: RmrkCollectionId,
 			nft_id: RmrkNftId,
 		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
+			let sender = ensure_signed(origin)?;
             let cross_sender = T::CrossAccountId::from_sub(sender.clone());
 
             Self::destroy_nft(
@@ -305,6 +312,62 @@
 
             Ok(())
         }
+
+        #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
+		#[transactional]
+		pub fn set_property(
+			origin: OriginFor<T>,
+			#[pallet::compact] rmrk_collection_id: RmrkCollectionId,
+			maybe_nft_id: Option<RmrkNftId>,
+			key: RmrkKeyString,
+			value: RmrkValueString,
+		) -> DispatchResult {
+            let sender = ensure_signed(origin)?;
+            let sender = T::CrossAccountId::from_sub(sender);
+
+            let collection_id: CollectionId = rmrk_collection_id.into();
+
+            match maybe_nft_id {
+                Some(nft_id) => {
+                    let token_id: TokenId = nft_id.into();
+
+                    Self::ensure_nft_owner(collection_id, token_id, &sender)?;
+                    Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;
+
+                    <PalletNft<T>>::set_scoped_token_property(
+                        collection_id,
+                        token_id,
+                        PropertyScope::Rmrk,
+                        Self::rmrk_property(UserProperty(key.as_slice()), &value)?
+                    )?;
+                },
+                None => {
+                    let collection = Self::get_typed_nft_collection(
+                        collection_id,
+                        misc::CollectionType::Regular
+                    )?;
+
+                    Self::check_collection_owner(&collection, &sender)?;
+
+                    <PalletCommon<T>>::set_scoped_collection_property(
+                        collection_id,
+                        PropertyScope::Rmrk,
+                        Self::rmrk_property(UserProperty(key.as_slice()), &value)?
+                    )?;
+                }
+            }
+
+            Self::deposit_event(
+                Event::PropertySet {
+                    collection_id: rmrk_collection_id,
+                    maybe_nft_id,
+                    key,
+                    value
+                }
+            );
+
+            Ok(())
+        }
 	}
 }
 
@@ -477,65 +540,91 @@
 
     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);
+        ensure!(actual_type == nft_type, <Error<T>>::NoPermission);
 
         Ok(())
     }
 
-    pub fn filter_theme_properties(
+    pub fn ensure_nft_owner(
         collection_id: CollectionId,
         token_id: TokenId,
-        filter_keys: Option<Vec<RmrkPropertyKey>>
-    ) -> Result<Vec<RmrkThemeProperty>, DispatchError> {
+        possible_owner: &T::CrossAccountId
+    ) -> DispatchResult {
+        let token_data = <TokenData<T>>::get((collection_id, token_id))
+            .ok_or(<Error<T>>::NoAvailableNftId)?;
+
+        ensure!(token_data.owner == *possible_owner, <Error<T>>::NoPermission);
+
+        Ok(())
+    }
+
+    pub fn filter_user_properties<Key, Value, R, Mapper>(
+        collection_id: CollectionId,
+        token_id: Option<TokenId>,
+        filter_keys: Option<Vec<RmrkPropertyKey>>,
+        mapper: Mapper,
+    ) -> Result<Vec<R>, DispatchError>
+    where
+        Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
+        Value: Decode + Default,
+        Mapper: Fn(Key, Value) -> R
+    {
         filter_keys.map(|keys| {
             let properties = keys.into_iter()
                 .filter_map(|key| {
-                    let key: RmrkString = key.try_into().ok()?;
+                    let key: Key = key.try_into().ok()?;
 
-                    let value = Self::get_nft_property(
-                        collection_id,
-                        token_id,
-                        ThemeProperty(&key)
-                    ).ok()?.decode_or_default();
-
-                    let property = RmrkThemeProperty {
-                        key,
-                        value
-                    };
+                    let value = match token_id {
+                        Some(token_id) => Self::get_nft_property(
+                            collection_id,
+                            token_id,
+                            UserProperty(key.as_ref())
+                        ),
+                        None => Self::get_collection_property(
+                            collection_id,
+                            UserProperty(key.as_ref())
+                        )
+                    }.ok()?.decode_or_default();
 
-                    Some(property)
+                    Some(mapper(key, value))
                 })
                 .collect();
 
             Ok(properties)
         }).unwrap_or_else(|| {
-            let properties = Self::iterate_theme_properties(collection_id, token_id)?
+            let properties = Self::iterate_user_properties(collection_id, token_id, mapper)?
                 .collect();
 
             Ok(properties)
         })
     }
 
-    pub fn iterate_theme_properties(
+    pub fn iterate_user_properties<Key, Value, R, Mapper>(
         collection_id: CollectionId,
-        token_id: TokenId
-    ) -> Result<impl Iterator<Item=RmrkThemeProperty>, DispatchError> {
-        let key_prefix = Self::rmrk_property_key(ThemeProperty(&RmrkString::default()))?;
+        token_id: Option<TokenId>,
+        mapper: Mapper,
+    ) -> Result<impl Iterator<Item=R>, DispatchError>
+    where
+        Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
+        Value: Decode + Default,
+        Mapper: Fn(Key, Value) -> R
+    {
+        let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;
 
-        let properties = <PalletNft<T>>::token_properties((collection_id, token_id))
+        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: RmrkString = key.to_vec().try_into().ok()?;
-                let value: RmrkString = value.decode_or_default();
+                let key: Key = key.to_vec().try_into().ok()?;
+                let value: Value = value.decode_or_default();
 
-                let property = RmrkThemeProperty {
-                    key,
-                    value
-                };
-
-                Some(property)
+                Some(mapper(key, value))
             });
 
         Ok(properties)
modifiedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
23 EquippableList,23 EquippableList,
24 ZIndex,24 ZIndex,
25 ThemeName,25 ThemeName,
26 ThemeInherit,
26 ThemeProperty(&'r RmrkString),27 UserProperty(&'r [u8]),
27 ThemeInherit,
28}28}
2929
30impl<'r> RmrkProperty<'r> {30impl<'r> RmrkProperty<'r> {
66 Self::EquippableList => key!("equippable-list"),66 Self::EquippableList => key!("equippable-list"),
67 Self::ZIndex => key!("z-index"),67 Self::ZIndex => key!("z-index"),
68 Self::ThemeName => key!("theme-name"),68 Self::ThemeName => key!("theme-name"),
69 Self::ThemeProperty(name) => key!("theme-property-", name),
70 Self::ThemeInherit => key!("theme-inherit"),69 Self::ThemeInherit => key!("theme-inherit"),
70 Self::UserProperty(name) => key!("userprop-", name),
71 }71 }
72 }72 }
73}73}
modifiedpallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -185,7 +185,7 @@
                     token_id,
                     PropertyScope::Rmrk,
                     <PalletCore<T>>::rmrk_property(
-                        ThemeProperty(&property.key),
+                        UserProperty(property.key.as_slice()),
                         &property.value
                     )?
                 )?;
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -934,8 +934,9 @@
 	RmrkString,
 	BoundedVec<RmrkPartId, RmrkPartsLimit>,
 >;
-pub type RmrkPropertyInfo =
-	PropertyInfo<BoundedVec<u8, RmrkKeyLimit>, BoundedVec<u8, RmrkValueLimit>>;
+pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
+pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
+pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;
 pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
 pub type RmrkPartType =
 	PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -232,78 +232,47 @@
                 }
 
                 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-                    use pallet_proxy_rmrk_core::misc::RmrkDecode;
+                    use pallet_proxy_rmrk_core::misc::CollectionType;
 
                     let collection_id = CollectionId(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 = Common::bytes_keys_to_property_keys(keys)?;
-                            let properties = keys
-                                .into_iter()
-                                .filter_map(|key| {
-                                    properties.get(&key).map(|value| RmrkPropertyInfo {
-                                        key: key.decode_or_default(),
-                                        value: value.decode_or_default(),
-                                    })
-                                })
-                                .collect();
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {
+                        return Ok(Vec::new());
+                    }
 
-                            properties
-                        }
-                        None => {
-                            properties
-                                .into_iter()
-                                .filter_map(|(key, value)| Some(RmrkPropertyInfo {
-                                    key: key.decode_or_default(),
-                                    value: value.decode_or_default(),
-                                }))
-                                .collect()
+                    let properties = RmrkCore::filter_user_properties(
+                        collection_id,
+                        /* token_id = */ None,
+                        filter_keys,
+                        |key, value| RmrkPropertyInfo {
+                            key,
+                            value
                         }
-                    });
+                    )?;
+
+                    Ok(properties)
                 }
 
                 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;
+                    use pallet_proxy_rmrk_core::misc::NftType;
 
                     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 = Nonfungible::token_properties((collection_id, token_id));
-                    // todo look into this usage of pallet_nonfungible
+                    if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
+                        return Ok(Vec::new());
+                    }
 
-                    // todo displace to a function? redundant code piece with collection props
-                    return Ok(match filter_keys {
-                        Some(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: key.decode_or_default(),
-                                        value: value.decode_or_default(),
-                                    })
-                                })
-                                .collect();
+		            let properties = RmrkCore::filter_user_properties(
+                        collection_id,
+                        Some(token_id),
+                        filter_keys,
+                        |key, value| RmrkPropertyInfo {
+                            key,
+                            value
+                        }
+                    )?;
 
-                            properties
-                        }
-                        None => {
-                            properties
-                                .into_iter()
-                                .filter_map(|(key, value)| Some(RmrkPropertyInfo {
-                                    key: key.decode_or_default(),
-                                    value: value.decode_or_default(),
-                                }))
-                                .collect()
-                        }
-                    });
+                    Ok(properties)
                 }
 
                 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
@@ -436,7 +405,15 @@
                         None => return Ok(None)
                     };
 
-                    let properties = RmrkCore::filter_theme_properties(collection_id, theme_id, filter_keys)?;
+                    let properties = RmrkCore::filter_user_properties(
+                        collection_id,
+                        Some(theme_id),
+                        filter_keys,
+                        |key, value| RmrkThemeProperty {
+                            key,
+                            value
+                        }
+                    )?;
 
                     let inherit = RmrkCore::get_nft_property(
                         collection_id,