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

difftreelog

feat(rmrk) add equippable extrinsic

Daniel Shiposha2022-06-20parent: #960c108.patch.diff
in: master

4 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
@@ -1298,7 +1298,7 @@
 		collection.save()
 	}
 
-	fn check_collection_owner(
+	pub fn check_collection_owner(
 		collection: &NonfungibleHandle<T>,
 		account: &T::CrossAccountId,
 	) -> DispatchResult {
@@ -1363,7 +1363,11 @@
 		collection_id: CollectionId,
 	) -> Result<misc::CollectionType, DispatchError> {
 		Self::get_collection_property_decoded(collection_id, CollectionType)
-			.map_err(|_| <Error<T>>::CorruptedCollectionType.into())
+			.map_err(|err| if err != <Error<T>>::CollectionUnknown.into() {
+				<Error<T>>::CorruptedCollectionType.into()
+			} else {
+				err
+			})
 	}
 
 	pub fn ensure_collection_type(
modifiedpallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth
before · pallets/proxy-rmrk-equip/src/lib.rs
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/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};20use frame_system::{pallet_prelude::*, ensure_signed};21use sp_runtime::DispatchError;22use up_data_structs::*;23use pallet_common::{Pallet as PalletCommon, Error as CommonError};24use pallet_rmrk_core::{25	Pallet as PalletCore,26	misc::{self, *},27	property::RmrkProperty::*,28};29use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};30use pallet_evm::account::CrossAccountId;31use weights::WeightInfo;3233pub use pallet::*;3435#[cfg(feature = "runtime-benchmarks")]36pub mod benchmarking;37pub mod rpc;38pub mod weights;3940pub type SelfWeightOf<T> = <T as Config>::WeightInfo;4142#[frame_support::pallet]43pub mod pallet {44	use super::*;4546	#[pallet::config]47	pub trait Config: frame_system::Config + pallet_rmrk_core::Config {48		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;49		type WeightInfo: WeightInfo;50	}5152	#[pallet::storage]53	#[pallet::getter(fn internal_part_id)]54	pub type InernalPartId<T: Config> =55		StorageDoubleMap<_, Twox64Concat, CollectionId, Twox64Concat, RmrkPartId, TokenId>;5657	#[pallet::storage]58	#[pallet::getter(fn base_has_default_theme)]59	pub type BaseHasDefaultTheme<T: Config> =60		StorageMap<_, Twox64Concat, CollectionId, bool, ValueQuery>;6162	#[pallet::pallet]63	#[pallet::generate_store(pub(super) trait Store)]64	pub struct Pallet<T>(_);6566	#[pallet::event]67	#[pallet::generate_deposit(pub(super) fn deposit_event)]68	pub enum Event<T: Config> {69		BaseCreated {70			issuer: T::AccountId,71			base_id: RmrkBaseId,72		},73	}7475	#[pallet::error]76	pub enum Error<T> {77		PermissionError,78		NoAvailableBaseId,79		NoAvailablePartId,80		BaseDoesntExist,81		NeedsDefaultThemeFirst,82	}8384	#[pallet::call]85	impl<T: Config> Pallet<T> {86		/// Creates a new Base.87		/// Modeled after [base interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/base.md)88		///89		/// Parameters:90		/// - origin: Caller, will be assigned as the issuer of the Base91		/// - base_type: media type, e.g. "svg"92		/// - symbol: arbitrary client-chosen symbol93		/// - parts: array of Fixed and Slot parts composing the base, confined in length by94		///   RmrkPartsLimit95		#[transactional]96		#[pallet::weight(<SelfWeightOf<T>>::create_base(parts.len() as u32))]97		pub fn create_base(98			origin: OriginFor<T>,99			base_type: RmrkString,100			symbol: RmrkBaseSymbol,101			parts: BoundedVec<RmrkPartType, RmrkPartsLimit>,102		) -> DispatchResult {103			let sender = ensure_signed(origin)?;104			let cross_sender = T::CrossAccountId::from_sub(sender.clone());105106			let data = CreateCollectionData {107				limits: None,108				token_prefix: symbol109					.into_inner()110					.try_into()111					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,112				..Default::default()113			};114115			let collection_id_res =116				<PalletNft<T>>::init_collection(cross_sender.clone(), data, true);117118			if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {119				return Err(<Error<T>>::NoAvailableBaseId.into());120			}121122			let collection_id = collection_id_res?;123124			<PalletCommon<T>>::set_scoped_collection_properties(125				collection_id,126				PropertyScope::Rmrk,127				[128					<PalletCore<T>>::rmrk_property(CollectionType, &misc::CollectionType::Base)?,129					<PalletCore<T>>::rmrk_property(BaseType, &base_type)?,130				]131				.into_iter(),132			)?;133134			let collection = <PalletCore<T>>::get_nft_collection(collection_id)?;135136			for part in parts {137				let part_id = part.id();138				let part_token_id = Self::create_part(&cross_sender, &collection, part)?;139140				<InernalPartId<T>>::insert(collection_id, part_id, part_token_id);141142				<PalletNft<T>>::set_scoped_token_property(143					collection_id,144					part_token_id,145					PropertyScope::Rmrk,146					<PalletCore<T>>::rmrk_property(ExternalPartId, &part_id)?,147				)?;148			}149150			Self::deposit_event(Event::BaseCreated {151				issuer: sender,152				base_id: collection_id.0,153			});154155			Ok(())156		}157158		/// Adds a Theme to a Base.159		/// Modeled after [themeadd interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/themeadd.md)160		/// Themes are stored in the Themes storage161		/// A Theme named "default" is required prior to adding other Themes.162		///163		/// Parameters:164		/// - origin: The caller of the function, must be issuer of the base165		/// - base_id: The Base containing the Theme to be updated166		/// - theme: The Theme to add to the Base.  A Theme has a name and properties, which are an167		///   array of [key, value, inherit].168		///   - key: arbitrary BoundedString, defined by client169		///   - value: arbitrary BoundedString, defined by client170		///   - inherit: optional bool171		#[transactional]172		#[pallet::weight(<SelfWeightOf<T>>::theme_add(theme.properties.len() as u32))]173		pub fn theme_add(174			origin: OriginFor<T>,175			base_id: RmrkBaseId,176			theme: RmrkBoundedTheme,177		) -> DispatchResult {178			let sender = ensure_signed(origin)?;179180			let sender = T::CrossAccountId::from_sub(sender);181			let owner = &sender;182183			let collection_id: CollectionId = base_id.into();184185			let collection = <PalletCore<T>>::get_typed_nft_collection(186				collection_id,187				misc::CollectionType::Base,188			)189			.map_err(|_| <Error<T>>::BaseDoesntExist)?;190			collection.check_is_external()?;191192			if theme.name.as_slice() == b"default" {193				<BaseHasDefaultTheme<T>>::insert(collection_id, true);194			} else if !Self::base_has_default_theme(collection_id) {195				return Err(<Error<T>>::NeedsDefaultThemeFirst.into());196			}197198			let token_id = <PalletCore<T>>::create_nft(199				&sender,200				owner,201				&collection,202				[203					<PalletCore<T>>::rmrk_property(TokenType, &NftType::Theme)?,204					<PalletCore<T>>::rmrk_property(ThemeName, &theme.name)?,205					<PalletCore<T>>::rmrk_property(ThemeInherit, &theme.inherit)?,206				]207				.into_iter(),208			)209			.map_err(|_| <Error<T>>::PermissionError)?;210211			for property in theme.properties {212				<PalletNft<T>>::set_scoped_token_property(213					collection_id,214					token_id,215					PropertyScope::Rmrk,216					<PalletCore<T>>::rmrk_property(217						UserProperty(property.key.as_slice()),218						&property.value,219					)?,220				)?;221			}222223			Ok(())224		}225	}226}227228impl<T: Config> Pallet<T> {229	fn create_part(230		sender: &T::CrossAccountId,231		collection: &NonfungibleHandle<T>,232		part: RmrkPartType,233	) -> Result<TokenId, DispatchError> {234		let owner = sender;235236		let src = part.src();237		let z_index = part.z_index();238239		let nft_type = match part {240			RmrkPartType::FixedPart(_) => NftType::FixedPart,241			RmrkPartType::SlotPart(_) => NftType::SlotPart,242		};243244		let token_id = <PalletCore<T>>::create_nft(245			sender,246			owner,247			collection,248			[249				<PalletCore<T>>::rmrk_property(TokenType, &nft_type)?,250				<PalletCore<T>>::rmrk_property(Src, &src)?,251				<PalletCore<T>>::rmrk_property(ZIndex, &z_index)?,252			]253			.into_iter(),254		)255		.map_err(|err| match err {256			DispatchError::Arithmetic(_) => <Error<T>>::NoAvailablePartId.into(),257			err => err,258		})?;259260		if let RmrkPartType::SlotPart(part) = part {261			<PalletNft<T>>::set_scoped_token_property(262				collection.id,263				token_id,264				PropertyScope::Rmrk,265				<PalletCore<T>>::rmrk_property(EquippableList, &part.equippable)?,266			)?;267		}268269		Ok(token_id)270	}271}
after · pallets/proxy-rmrk-equip/src/lib.rs
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/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult};20use frame_system::{pallet_prelude::*, ensure_signed};21use sp_runtime::DispatchError;22use up_data_structs::*;23use pallet_common::{Pallet as PalletCommon, Error as CommonError};24use pallet_rmrk_core::{25	Pallet as PalletCore,26	Error as CoreError,27	misc::{self, *},28	property::RmrkProperty::*,29};30use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};31use pallet_evm::account::CrossAccountId;32use weights::WeightInfo;3334pub use pallet::*;3536#[cfg(feature = "runtime-benchmarks")]37pub mod benchmarking;38pub mod rpc;39pub mod weights;4041pub type SelfWeightOf<T> = <T as Config>::WeightInfo;4243#[frame_support::pallet]44pub mod pallet {45	use super::*;4647	#[pallet::config]48	pub trait Config: frame_system::Config + pallet_rmrk_core::Config {49		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;50		type WeightInfo: WeightInfo;51	}5253	#[pallet::storage]54	#[pallet::getter(fn internal_part_id)]55	pub type InernalPartId<T: Config> =56		StorageDoubleMap<_, Twox64Concat, CollectionId, Twox64Concat, RmrkPartId, TokenId>;5758	#[pallet::storage]59	#[pallet::getter(fn base_has_default_theme)]60	pub type BaseHasDefaultTheme<T: Config> =61		StorageMap<_, Twox64Concat, CollectionId, bool, ValueQuery>;6263	#[pallet::pallet]64	#[pallet::generate_store(pub(super) trait Store)]65	pub struct Pallet<T>(_);6667	#[pallet::event]68	#[pallet::generate_deposit(pub(super) fn deposit_event)]69	pub enum Event<T: Config> {70		BaseCreated {71			issuer: T::AccountId,72			base_id: RmrkBaseId,73		},74		EquippablesUpdated {75			base_id: RmrkBaseId,76			slot_id: RmrkSlotId,77		},78	}7980	#[pallet::error]81	pub enum Error<T> {82		PermissionError,83		NoAvailableBaseId,84		NoAvailablePartId,85		BaseDoesntExist,86		NeedsDefaultThemeFirst,87		PartDoesntExist,88		NoEquippableOnFixedPart,89	}9091	#[pallet::call]92	impl<T: Config> Pallet<T> {93		/// Creates a new Base.94		/// Modeled after [base interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/base.md)95		///96		/// Parameters:97		/// - origin: Caller, will be assigned as the issuer of the Base98		/// - base_type: media type, e.g. "svg"99		/// - symbol: arbitrary client-chosen symbol100		/// - parts: array of Fixed and Slot parts composing the base, confined in length by101		///   RmrkPartsLimit102		#[transactional]103		#[pallet::weight(<SelfWeightOf<T>>::create_base(parts.len() as u32))]104		pub fn create_base(105			origin: OriginFor<T>,106			base_type: RmrkString,107			symbol: RmrkBaseSymbol,108			parts: BoundedVec<RmrkPartType, RmrkPartsLimit>,109		) -> DispatchResult {110			let sender = ensure_signed(origin)?;111			let cross_sender = T::CrossAccountId::from_sub(sender.clone());112113			let data = CreateCollectionData {114				limits: None,115				token_prefix: symbol116					.into_inner()117					.try_into()118					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,119				..Default::default()120			};121122			let collection_id_res =123				<PalletNft<T>>::init_collection(cross_sender.clone(), data, true);124125			if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {126				return Err(<Error<T>>::NoAvailableBaseId.into());127			}128129			let collection_id = collection_id_res?;130131			<PalletCommon<T>>::set_scoped_collection_properties(132				collection_id,133				PropertyScope::Rmrk,134				[135					<PalletCore<T>>::rmrk_property(CollectionType, &misc::CollectionType::Base)?,136					<PalletCore<T>>::rmrk_property(BaseType, &base_type)?,137				]138				.into_iter(),139			)?;140141			let collection = <PalletCore<T>>::get_nft_collection(collection_id)?;142143			for part in parts {144				let part_id = part.id();145				let part_token_id = Self::create_part(&cross_sender, &collection, part)?;146147				<InernalPartId<T>>::insert(collection_id, part_id, part_token_id);148149				<PalletNft<T>>::set_scoped_token_property(150					collection_id,151					part_token_id,152					PropertyScope::Rmrk,153					<PalletCore<T>>::rmrk_property(ExternalPartId, &part_id)?,154				)?;155			}156157			Self::deposit_event(Event::BaseCreated {158				issuer: sender,159				base_id: collection_id.0,160			});161162			Ok(())163		}164165		/// Adds a Theme to a Base.166		/// Modeled after [themeadd interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/themeadd.md)167		/// Themes are stored in the Themes storage168		/// A Theme named "default" is required prior to adding other Themes.169		///170		/// Parameters:171		/// - origin: The caller of the function, must be issuer of the base172		/// - base_id: The Base containing the Theme to be updated173		/// - theme: The Theme to add to the Base.  A Theme has a name and properties, which are an174		///   array of [key, value, inherit].175		///   - key: arbitrary BoundedString, defined by client176		///   - value: arbitrary BoundedString, defined by client177		///   - inherit: optional bool178		#[transactional]179		#[pallet::weight(<SelfWeightOf<T>>::theme_add(theme.properties.len() as u32))]180		pub fn theme_add(181			origin: OriginFor<T>,182			base_id: RmrkBaseId,183			theme: RmrkBoundedTheme,184		) -> DispatchResult {185			let sender = ensure_signed(origin)?;186187			let sender = T::CrossAccountId::from_sub(sender);188			let owner = &sender;189190			let collection_id: CollectionId = base_id.into();191192			let collection = Self::get_base(collection_id)?;193194			if theme.name.as_slice() == b"default" {195				<BaseHasDefaultTheme<T>>::insert(collection_id, true);196			} else if !Self::base_has_default_theme(collection_id) {197				return Err(<Error<T>>::NeedsDefaultThemeFirst.into());198			}199200			let token_id = <PalletCore<T>>::create_nft(201				&sender,202				owner,203				&collection,204				[205					<PalletCore<T>>::rmrk_property(TokenType, &NftType::Theme)?,206					<PalletCore<T>>::rmrk_property(ThemeName, &theme.name)?,207					<PalletCore<T>>::rmrk_property(ThemeInherit, &theme.inherit)?,208				]209				.into_iter(),210			)211			.map_err(|_| <Error<T>>::PermissionError)?;212213			for property in theme.properties {214				<PalletNft<T>>::set_scoped_token_property(215					collection_id,216					token_id,217					PropertyScope::Rmrk,218					<PalletCore<T>>::rmrk_property(219						UserProperty(property.key.as_slice()),220						&property.value,221					)?,222				)?;223			}224225			Ok(())226		}227228		#[transactional]229		#[pallet::weight(<SelfWeightOf<T>>::equippable())]230		pub fn equippable(231			origin: OriginFor<T>,232			base_id: RmrkBaseId,233			slot_id: RmrkSlotId,234			equippables: RmrkEquippableList,235		) -> DispatchResult {236			let sender = ensure_signed(origin)?;237238			let base_collection_id = base_id.into();239			let collection = Self::get_base(base_collection_id)?;240241			<PalletCore<T>>::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))242				.map_err(|err| if err == <CoreError<T>>::NoPermission.into() {243					<Error<T>>::PermissionError.into()244				} else {245					err246				})?;247248			let part_id = Self::internal_part_id(base_collection_id, slot_id)249				.ok_or(<Error<T>>::PartDoesntExist)?;250251			let nft_type = <PalletCore<T>>::get_nft_type(base_collection_id, part_id)252				.map_err(|_| <Error<T>>::PartDoesntExist)?;253254			match nft_type {255				NftType::Regular | NftType::Theme => return Err(<Error<T>>::PermissionError.into()),256				NftType::FixedPart => return Err(<Error<T>>::NoEquippableOnFixedPart.into()),257				NftType::SlotPart => {258					<PalletNft<T>>::set_scoped_token_property(259						base_collection_id,260						part_id,261						PropertyScope::Rmrk,262						<PalletCore<T>>::rmrk_property(EquippableList, &equippables)?,263					)?;264				}265			}266267			Self::deposit_event(Event::EquippablesUpdated {268				base_id,269				slot_id,270			});271272			Ok(())273		}274	}275}276277impl<T: Config> Pallet<T> {278	fn create_part(279		sender: &T::CrossAccountId,280		collection: &NonfungibleHandle<T>,281		part: RmrkPartType,282	) -> Result<TokenId, DispatchError> {283		let owner = sender;284285		let src = part.src();286		let z_index = part.z_index();287288		let nft_type = match part {289			RmrkPartType::FixedPart(_) => NftType::FixedPart,290			RmrkPartType::SlotPart(_) => NftType::SlotPart,291		};292293		let token_id = <PalletCore<T>>::create_nft(294			sender,295			owner,296			collection,297			[298				<PalletCore<T>>::rmrk_property(TokenType, &nft_type)?,299				<PalletCore<T>>::rmrk_property(Src, &src)?,300				<PalletCore<T>>::rmrk_property(ZIndex, &z_index)?,301			]302			.into_iter(),303		)304		.map_err(|err| match err {305			DispatchError::Arithmetic(_) => <Error<T>>::NoAvailablePartId.into(),306			err => err,307		})?;308309		if let RmrkPartType::SlotPart(part) = part {310			<PalletNft<T>>::set_scoped_token_property(311				collection.id,312				token_id,313				PropertyScope::Rmrk,314				<PalletCore<T>>::rmrk_property(EquippableList, &part.equippable)?,315			)?;316		}317318		Ok(token_id)319	}320321	fn get_base(base_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {322		let collection = <PalletCore<T>>::get_typed_nft_collection(base_id, misc::CollectionType::Base)323			.map_err(|err| if err == <CoreError<T>>::CollectionUnknown.into() {324				<Error<T>>::BaseDoesntExist.into()325			} else {326				err327			})?;328		collection.check_is_external()?;329330		Ok(collection)331	}332}
modifiedpallets/proxy-rmrk-equip/src/weights.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/weights.rs
+++ b/pallets/proxy-rmrk-equip/src/weights.rs
@@ -3,7 +3,7 @@
 //! Autogenerated weights for pallet_proxy_rmrk_equip
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-06-16, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-06-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
 
 // Executed Command:
@@ -35,6 +35,7 @@
 pub trait WeightInfo {
 	fn create_base(b: u32, ) -> Weight;
 	fn theme_add(b: u32, ) -> Weight;
+	fn equippable() -> Weight;
 }
 
 /// Weights for pallet_proxy_rmrk_equip using the Substrate node and recommended hardware.
@@ -53,13 +54,13 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: RmrkEquip InernalPartId (r:0 w:1)
 	fn create_base(b: u32, ) -> Weight {
-		(43_216_000 as Weight)
+		(44_632_000 as Weight)
 			// Standard Error: 10_000
-			.saturating_add((16_253_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((16_912_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(6 as Weight))
 			.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
-			.saturating_add(T::DbWeight::get().writes(9 as Weight))
-			.saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(b as Weight)))
+			.saturating_add(T::DbWeight::get().writes(8 as Weight))
+			.saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))
 	}
 	// Storage: Common CollectionProperties (r:1 w:0)
 	// Storage: Common CollectionById (r:1 w:0)
@@ -70,12 +71,21 @@
 	// Storage: Nonfungible TokenData (r:0 w:1)
 	// Storage: Nonfungible Owned (r:0 w:1)
 	fn theme_add(b: u32, ) -> Weight {
-		(39_467_000 as Weight)
-			// Standard Error: 15_000
-			.saturating_add((2_332_000 as Weight).saturating_mul(b as Weight))
+		(39_525_000 as Weight)
+			// Standard Error: 12_000
+			.saturating_add((2_494_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(6 as Weight))
 			.saturating_add(T::DbWeight::get().writes(5 as Weight))
 	}
+	// Storage: Common CollectionProperties (r:1 w:0)
+	// Storage: Common CollectionById (r:1 w:0)
+	// Storage: RmrkEquip InernalPartId (r:1 w:0)
+	// Storage: Nonfungible TokenProperties (r:1 w:1)
+	fn equippable() -> Weight {
+		(27_371_000 as Weight)
+			.saturating_add(T::DbWeight::get().reads(4 as Weight))
+			.saturating_add(T::DbWeight::get().writes(1 as Weight))
+	}
 }
 
 // For backwards compatibility and tests
@@ -93,13 +103,13 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: RmrkEquip InernalPartId (r:0 w:1)
 	fn create_base(b: u32, ) -> Weight {
-		(43_216_000 as Weight)
+		(44_632_000 as Weight)
 			// Standard Error: 10_000
-			.saturating_add((16_253_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((16_912_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(6 as Weight))
 			.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
-			.saturating_add(RocksDbWeight::get().writes(9 as Weight))
-			.saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(b as Weight)))
+			.saturating_add(RocksDbWeight::get().writes(8 as Weight))
+			.saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))
 	}
 	// Storage: Common CollectionProperties (r:1 w:0)
 	// Storage: Common CollectionById (r:1 w:0)
@@ -110,10 +120,19 @@
 	// Storage: Nonfungible TokenData (r:0 w:1)
 	// Storage: Nonfungible Owned (r:0 w:1)
 	fn theme_add(b: u32, ) -> Weight {
-		(39_467_000 as Weight)
-			// Standard Error: 15_000
-			.saturating_add((2_332_000 as Weight).saturating_mul(b as Weight))
+		(39_525_000 as Weight)
+			// Standard Error: 12_000
+			.saturating_add((2_494_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(6 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(5 as Weight))
 	}
+	// Storage: Common CollectionProperties (r:1 w:0)
+	// Storage: Common CollectionById (r:1 w:0)
+	// Storage: RmrkEquip InernalPartId (r:1 w:0)
+	// Storage: Nonfungible TokenProperties (r:1 w:1)
+	fn equippable() -> Weight {
+		(27_371_000 as Weight)
+			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
+	}
 }
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -39,15 +39,15 @@
 // RMRK
 use rmrk_traits::{
 	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,
-	ResourceTypes, BasicResource, ComposableResource, SlotResource,
+	ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList,
 };
 pub use rmrk_traits::{
 	primitives::{
 		CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,
-		PartId as RmrkPartId, ResourceId as RmrkResourceId,
+		SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId,
 	},
 	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
-	FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,
+	FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart,
 };
 
 mod bounded;
@@ -987,8 +987,9 @@
 pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;
 pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;
 pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
-pub type RmrkPartType =
-	PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;
+pub type BoundedEquippableCollectionIds = BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>;
+pub type RmrkPartType = PartType<RmrkString, BoundedEquippableCollectionIds>;
+pub type RmrkEquippableList = EquippableList<BoundedEquippableCollectionIds>;
 pub type RmrkThemeProperty = ThemeProperty<RmrkString>;
 pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;
 pub type RmrkBoundedTheme = Theme<RmrkString, BoundedVec<RmrkThemeProperty, MaxPropertiesPerTheme>>;