difftreelog
feat(rmrk) add associated bases property
in: master
2 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,7 +24,7 @@
};
use frame_system::{pallet_prelude::*, ensure_signed};
use sp_runtime::{DispatchError, Permill, traits::StaticLookup};
-use sp_std::{vec::Vec, collections::btree_set::BTreeSet};
+use sp_std::{vec::Vec, collections::{btree_set::BTreeSet, btree_map::BTreeMap}};
use up_data_structs::{*, mapping::TokenAddressMapping};
use pallet_common::{
Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,
@@ -55,7 +55,9 @@
type PendingTarget = (CollectionId, TokenId);
type PendingChild = (RmrkCollectionId, RmrkNftId);
-type PendingChildrenMap = BTreeSet<PendingChild>;
+type PendingChildrenSet = BTreeSet<PendingChild>;
+
+type BasesMap = BTreeMap<RmrkBaseId, u32>;
#[frame_support::pallet]
pub mod pallet {
@@ -398,7 +400,8 @@
Self::rmrk_property(Equipped, &false)?,
Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
Self::rmrk_property(NextResourceId, &(0 as RmrkResourceId))?,
- Self::rmrk_property(PendingChildren, &PendingChildrenMap::new())?,
+ Self::rmrk_property(PendingChildren, &PendingChildrenSet::new())?,
+ Self::rmrk_property(AssociatedBases, &BasesMap::new())?,
]
.into_iter(),
)
@@ -816,6 +819,12 @@
resource_id_key,
);
+ if let RmrkResourceTypes::Composable(resource) = resource_info.resource {
+ let base_id = resource.base;
+
+ Self::remove_associated_base_id(collection_id, nft_id, base_id)?;
+ }
+
Self::deposit_event(Event::<T>::ResourceRemovalAccepted {
nft_id: rmrk_nft_id,
resource_id,
@@ -969,6 +978,8 @@
Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
collection.check_is_external()?;
+ let base_id = resource.base;
+
let resource_id = Self::resource_add(
sender,
collection_id,
@@ -976,6 +987,24 @@
RmrkResourceTypes::Composable(resource),
)?;
+ <PalletNft<T>>::try_mutate_token_aux_property(
+ collection_id,
+ nft_id.into(),
+ PropertyScope::Rmrk,
+ Self::rmrk_property_key(AssociatedBases)?,
+ |value| -> DispatchResult {
+ let mut bases: BasesMap = match value {
+ Some(value) => Self::decode_property(value)?,
+ None => BasesMap::new()
+ };
+
+ *bases.entry(base_id).or_insert(0) += 1;
+
+ *value = Some(Self::encode_property(&bases)?);
+ Ok(())
+ }
+ )?;
+
Self::deposit_event(Event::ResourceAdded {
nft_id,
resource_id,
@@ -1198,7 +1227,7 @@
fn mutate_pending_child(
(target_collection_id, target_nft_id): (CollectionId, TokenId),
- f: impl FnOnce(&mut PendingChildrenMap),
+ f: impl FnOnce(&mut PendingChildrenSet),
) -> DispatchResult {
<PalletNft<T>>::try_mutate_token_aux_property(
target_collection_id,
@@ -1208,7 +1237,7 @@
|pending_children| -> DispatchResult {
let mut map = match pending_children {
Some(map) => Self::decode_property(map)?,
- None => PendingChildrenMap::new(),
+ None => PendingChildrenSet::new(),
};
f(&mut map);
@@ -1230,7 +1259,7 @@
let pending_children = match property {
Some(map) => Self::decode_property(&map)?,
- None => PendingChildrenMap::new(),
+ None => PendingChildrenSet::new(),
};
Ok(pending_children.into_iter())
@@ -1312,16 +1341,14 @@
let resource_id_key = Self::rmrk_property_key(ResourceId(resource_id))?;
let scope = PropertyScope::Rmrk;
- ensure!(
- <PalletNft<T>>::token_aux_property((
- collection_id,
- nft_id,
- scope,
- resource_id_key.clone()
- ))
- .is_some(),
- <Error<T>>::ResourceDoesntExist
- );
+ let resource = <PalletNft<T>>::token_aux_property((
+ collection_id,
+ nft_id,
+ scope,
+ resource_id_key.clone()
+ )).ok_or(<Error<T>>::ResourceDoesntExist)?;
+
+ let resource_info: RmrkResourceInfo = Self::decode_property(&resource)?;
let budget = up_data_structs::budget::Value::new(NESTING_BUDGET);
let topmost_owner =
@@ -1335,6 +1362,12 @@
PropertyScope::Rmrk,
Self::rmrk_property_key(ResourceId(resource_id))?,
);
+
+ if let RmrkResourceTypes::Composable(resource) = resource_info.resource {
+ let base_id = resource.base;
+
+ Self::remove_associated_base_id(collection_id, nft_id, base_id)?;
+ }
} else {
Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {
res.pending_removal = true;
@@ -1346,6 +1379,36 @@
Ok(())
}
+ fn remove_associated_base_id(
+ collection_id: CollectionId,
+ nft_id: TokenId,
+ base_id: RmrkBaseId,
+ ) -> DispatchResult {
+ <PalletNft<T>>::try_mutate_token_aux_property(
+ collection_id,
+ nft_id,
+ PropertyScope::Rmrk,
+ Self::rmrk_property_key(AssociatedBases)?,
+ |value| -> DispatchResult {
+ let mut bases: BasesMap = match value {
+ Some(value) => Self::decode_property(value)?,
+ None => BasesMap::new()
+ };
+
+ let remaining = bases.get(&base_id);
+
+ if let Some(remaining) = remaining {
+ if let Some(0) | None = remaining.checked_sub(1) {
+ bases.remove(&base_id);
+ }
+ }
+
+ *value = Some(Self::encode_property(&bases)?);
+ Ok(())
+ }
+ )
+ }
+
fn try_mutate_resource_info(
collection_id: CollectionId,
nft_id: TokenId,
pallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use super::*;18use up_data_structs::PropertyScope;19use core::convert::AsRef;2021pub const RESOURCE_ID_PREFIX: &str = "rsid-";22pub const USER_PROPERTY_PREFIX: &str = "userprop-";2324pub enum RmrkProperty<'r> {25 Metadata,26 CollectionType,27 RmrkInternalCollectionId,28 TokenType,29 Transferable,30 RoyaltyInfo,31 Equipped,32 ResourcePriorities,33 NextResourceId,34 ResourceId(RmrkResourceId),35 PendingNftAccept,36 PendingChildren,37 Parts,38 Base,39 Src,40 EquippedNft,41 BaseType,42 ExternalPartId,43 EquippableList,44 ZIndex,45 ThemeName,46 ThemeInherit,47 UserProperty(&'r [u8]),48}4950impl<'r> RmrkProperty<'r> {51 pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {52 fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {53 container.as_ref()54 }5556 macro_rules! key {57 ($($component:expr),+) => {58 PropertyKey::try_from([$(key!(@ &$component)),+].concat())59 .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)60 };6162 (@ $key:expr) => {63 get_bytes($key)64 };65 }6667 match self {68 Self::Metadata => key!("metadata"),69 Self::CollectionType => key!("collection-type"),70 Self::RmrkInternalCollectionId => key!("internal-id"),71 Self::TokenType => key!("token-type"),72 Self::Transferable => key!("transferable"),73 Self::RoyaltyInfo => key!("royalty-info"),74 Self::Equipped => key!("equipped"),75 Self::ResourcePriorities => key!("resource-priorities"),76 Self::NextResourceId => key!("next-resource-id"),77 Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()),78 Self::PendingNftAccept => key!("pending-nft-accept"),79 Self::PendingChildren => key!("pending-children"),80 Self::Parts => key!("parts"),81 Self::Base => key!("base"),82 Self::Src => key!("src"),83 Self::EquippedNft => key!("equipped-nft"),84 Self::BaseType => key!("base-type"),85 Self::ExternalPartId => key!("ext-part-id"),86 Self::EquippableList => key!("equippable-list"),87 Self::ZIndex => key!("z-index"),88 Self::ThemeName => key!("theme-name"),89 Self::ThemeInherit => key!("theme-inherit"),90 Self::UserProperty(name) => key!(USER_PROPERTY_PREFIX, name),91 }92 }93}9495pub fn strip_key_prefix(key: &PropertyKey, prefix: &str) -> Option<PropertyKey> {96 let key_prefix = PropertyKey::try_from(prefix.as_bytes().to_vec()).ok()?;97 let key_prefix = PropertyScope::Rmrk.apply(key_prefix).ok()?;9899 key.as_slice().strip_prefix(key_prefix.as_slice())?100 .to_vec().try_into().ok()101}102103pub fn is_valid_key_prefix(key: &PropertyKey, prefix: &str) -> bool {104 strip_key_prefix(key, prefix).is_some()105}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use super::*;18use up_data_structs::PropertyScope;19use core::convert::AsRef;2021pub const RESOURCE_ID_PREFIX: &str = "rsid-";22pub const USER_PROPERTY_PREFIX: &str = "userprop-";2324pub enum RmrkProperty<'r> {25 Metadata,26 CollectionType,27 RmrkInternalCollectionId,28 TokenType,29 Transferable,30 RoyaltyInfo,31 Equipped,32 ResourcePriorities,33 NextResourceId,34 ResourceId(RmrkResourceId),35 PendingNftAccept,36 PendingChildren,37 AssociatedBases,38 Parts,39 Base,40 Src,41 EquippedNft,42 BaseType,43 ExternalPartId,44 EquippableList,45 ZIndex,46 ThemeName,47 ThemeInherit,48 UserProperty(&'r [u8]),49}5051impl<'r> RmrkProperty<'r> {52 pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {53 fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {54 container.as_ref()55 }5657 macro_rules! key {58 ($($component:expr),+) => {59 PropertyKey::try_from([$(key!(@ &$component)),+].concat())60 .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)61 };6263 (@ $key:expr) => {64 get_bytes($key)65 };66 }6768 match self {69 Self::Metadata => key!("metadata"),70 Self::CollectionType => key!("collection-type"),71 Self::RmrkInternalCollectionId => key!("internal-id"),72 Self::TokenType => key!("token-type"),73 Self::Transferable => key!("transferable"),74 Self::RoyaltyInfo => key!("royalty-info"),75 Self::Equipped => key!("equipped"),76 Self::ResourcePriorities => key!("resource-priorities"),77 Self::NextResourceId => key!("next-resource-id"),78 Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()),79 Self::PendingNftAccept => key!("pending-nft-accept"),80 Self::PendingChildren => key!("pending-children"),81 Self::AssociatedBases => key!("assoc-bases"),82 Self::Parts => key!("parts"),83 Self::Base => key!("base"),84 Self::Src => key!("src"),85 Self::EquippedNft => key!("equipped-nft"),86 Self::BaseType => key!("base-type"),87 Self::ExternalPartId => key!("ext-part-id"),88 Self::EquippableList => key!("equippable-list"),89 Self::ZIndex => key!("z-index"),90 Self::ThemeName => key!("theme-name"),91 Self::ThemeInherit => key!("theme-inherit"),92 Self::UserProperty(name) => key!(USER_PROPERTY_PREFIX, name),93 }94 }95}9697pub fn strip_key_prefix(key: &PropertyKey, prefix: &str) -> Option<PropertyKey> {98 let key_prefix = PropertyKey::try_from(prefix.as_bytes().to_vec()).ok()?;99 let key_prefix = PropertyScope::Rmrk.apply(key_prefix).ok()?;100101 key.as_slice().strip_prefix(key_prefix.as_slice())?102 .to_vec().try_into().ok()103}104105pub fn is_valid_key_prefix(key: &PropertyKey, prefix: &str) -> bool {106 strip_key_prefix(key, prefix).is_some()107}