difftreelog
refactor iterate rmrk props, add rmrk proxy set_propertty
in: master
5 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
@@ -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)
pallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth23 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}292930impl<'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}pallets/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
)?
)?;
primitives/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>>;
runtime/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,