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
--- a/pallets/proxy-rmrk-core/src/property.rs
+++ b/pallets/proxy-rmrk-core/src/property.rs
@@ -23,8 +23,8 @@
     EquippableList,
     ZIndex,
     ThemeName,
-    ThemeProperty(&'r RmrkString),
     ThemeInherit,
+    UserProperty(&'r [u8]),
 }
 
 impl<'r> RmrkProperty<'r> {
@@ -66,8 +66,8 @@
             Self::EquippableList => key!("equippable-list"),
             Self::ZIndex => key!("z-index"),
             Self::ThemeName => key!("theme-name"),
-            Self::ThemeProperty(name) => key!("theme-property-", name),
             Self::ThemeInherit => key!("theme-inherit"),
+            Self::UserProperty(name) => key!("userprop-", name),
         }
     }
 }
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
232 }232 }
233233
234 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {234 fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
235 use pallet_proxy_rmrk_core::misc::RmrkDecode;235 use pallet_proxy_rmrk_core::misc::CollectionType;
236236
237 let collection_id = CollectionId(collection_id);237 let collection_id = CollectionId(collection_id);
238 if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); }238 if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() {
239 return Ok(Vec::new());
240 }
239241
240 let properties = Common::collection_properties(collection_id);242 let properties = RmrkCore::filter_user_properties(
241243 collection_id,
242 // todo repeated code244 /* token_id = */ None,
243 return Ok(match filter_keys {245 filter_keys,
244 Some(keys) => {
245 let keys = Common::bytes_keys_to_property_keys(keys)?;
246 let properties = keys
247 .into_iter()
248 .filter_map(|key| {
249 properties.get(&key).map(|value| RmrkPropertyInfo {
250 key: key.decode_or_default(),
251 value: value.decode_or_default(),
252 })
253 })
254 .collect();
255
256 properties
257 }
258 None => {
259 properties
260 .into_iter()
261 .filter_map(|(key, value)| Some(RmrkPropertyInfo {246 |key, value| RmrkPropertyInfo {
262 key: key.decode_or_default(),247 key,
263 value: value.decode_or_default(),248 value
264 }))249 }
250 )?;
251
265 .collect()252 Ok(properties)
266 }
267 });
268 }253 }
269254
270 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {255 fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
271 use frame_support::BoundedVec;
272 use pallet_proxy_rmrk_core::misc::RmrkDecode;256 use pallet_proxy_rmrk_core::misc::NftType;
273257
274 let collection_id = CollectionId(collection_id);258 let collection_id = CollectionId(collection_id);
275 let token_id = TokenId(nft_id);259 let token_id = TokenId(nft_id);
260
276 if !RmrkCore::nft_exists(collection_id, token_id) { return Ok(Vec::new()); }261 if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
262 return Ok(Vec::new());
263 }
277264
278 let properties = Nonfungible::token_properties((collection_id, token_id));265 let properties = RmrkCore::filter_user_properties(
279 // todo look into this usage of pallet_nonfungible266 collection_id,
280
281 // todo displace to a function? redundant code piece with collection props
282 return Ok(match filter_keys {
283 Some(keys) => {267 Some(token_id),
284 let keys = Common::bytes_keys_to_property_keys(keys)?;
285 let properties = keys
286 .into_iter()
287 .filter_map(|key| {
288 properties.get(&key).map(|value| RmrkPropertyInfo {
289 key: key.decode_or_default(),
290 value: value.decode_or_default(),268 filter_keys,
291 })
292 })
293 .collect();
294
295 properties
296 }
297 None => {
298 properties
299 .into_iter()
300 .filter_map(|(key, value)| Some(RmrkPropertyInfo {269 |key, value| RmrkPropertyInfo {
301 key: key.decode_or_default(),270 key,
302 value: value.decode_or_default(),271 value
303 }))272 }
273 )?;
274
304 .collect()275 Ok(properties)
305 }
306 });
307 }276 }
308277
309 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {278 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
436 None => return Ok(None)405 None => return Ok(None)
437 };406 };
438407
439 let properties = RmrkCore::filter_theme_properties(collection_id, theme_id, filter_keys)?;408 let properties = RmrkCore::filter_user_properties(
409 collection_id,
410 Some(theme_id),
411 filter_keys,
412 |key, value| RmrkThemeProperty {
413 key,
414 value
415 }
416 )?;
440417
441 let inherit = RmrkCore::get_nft_property(418 let inherit = RmrkCore::get_nft_property(