git.delta.rocks / unique-network / refs/commits / 4b3d05886c9a

difftreelog

feat(rmrk-proxy) add resource

Fahrrader2022-06-02parent: #47e3bf2.patch.diff
in: master

21 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6335,6 +6335,7 @@
  "pallet-common",
  "pallet-evm",
  "pallet-nonfungible",
+ "pallet-structure",
  "parity-scale-codec 3.1.2",
  "scale-info",
  "sp-core",
modifiedpallets/proxy-rmrk-core/Cargo.tomldiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/Cargo.toml
+++ b/pallets/proxy-rmrk-core/Cargo.toml
@@ -18,6 +18,7 @@
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }
 pallet-common = { default-features = false, path = '../common' }
 pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }
+pallet-structure = { default-features = false, path = "../../pallets/structure" }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
 pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.22" }
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }
@@ -33,6 +34,7 @@
     "up-data-structs/std",
     "pallet-common/std",
     "pallet-nonfungible/std",
+    "pallet-structure/std",
     "pallet-evm/std",
     'frame-benchmarking/std',
 ]
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
before · pallets/proxy-rmrk-core/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, Permill, traits::StaticLookup};22use sp_std::vec::Vec;23use up_data_structs::*;24use pallet_common::{25	Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,26};27use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};28use pallet_evm::account::CrossAccountId;29use core::convert::AsRef;3031pub use pallet::*;3233pub mod misc;34pub mod property;3536use misc::*;37pub use property::*;3839use RmrkProperty::*;4041#[frame_support::pallet]42pub mod pallet {43	use super::*;44	use pallet_evm::account;4546	#[pallet::config]47	pub trait Config:48		frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config49	{50		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;51	}5253	#[pallet::storage]54	#[pallet::getter(fn collection_index)]55	pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;5657	#[pallet::storage]58	#[pallet::getter(fn collection_index_map)]59	pub type CollectionIndexMap<T: Config> = 60		StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, 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		CollectionCreated {70			issuer: T::AccountId,71			collection_id: RmrkCollectionId,72		},73		CollectionDestroyed {74			issuer: T::AccountId,75			collection_id: RmrkCollectionId,76		},77		IssuerChanged {78			old_issuer: T::AccountId,79			new_issuer: T::AccountId,80			collection_id: RmrkCollectionId,81		},82		CollectionLocked {83			issuer: T::AccountId,84			collection_id: RmrkCollectionId,85		},86		NftMinted {87			owner: T::AccountId,88			collection_id: RmrkCollectionId,89			nft_id: RmrkNftId,90		},91		NFTBurned {92			owner: T::AccountId,93			nft_id: RmrkNftId,94		},95		PropertySet {96			collection_id: RmrkCollectionId,97			maybe_nft_id: Option<RmrkNftId>,98			key: RmrkKeyString,99			value: RmrkValueString,100		},101	}102103	#[pallet::error]104	pub enum Error<T> {105		/* Unique-specific events */106		CorruptedCollectionType,107		NftTypeEncodeError,108		RmrkPropertyKeyIsTooLong,109		RmrkPropertyValueIsTooLong,110111		/* RMRK compatible events */112		CollectionNotEmpty,113		NoAvailableCollectionId,114		NoAvailableNftId,115		CollectionUnknown,116		NoPermission,117		CollectionFullOrLocked,118	}119120	#[pallet::call]121	impl<T: Config> Pallet<T> {122		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]123		#[transactional]124		pub fn create_collection(125			origin: OriginFor<T>,126			metadata: RmrkString,127			max: Option<u32>,128			symbol: RmrkCollectionSymbol,129		) -> DispatchResult {130			let sender = ensure_signed(origin)?;131132			let limits = CollectionLimits {133				owner_can_transfer: Some(false),134				token_limit: max,135				..Default::default()136			};137138			let data = CreateCollectionData {139				limits: Some(limits),140				token_prefix: symbol141					.into_inner()142					.try_into()143					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,144				..Default::default()145			};146147			let collection_id_res =148				<PalletNft<T>>::init_collection(T::CrossAccountId::from_sub(sender.clone()), data);149150			if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {151				return Err(<Error<T>>::NoAvailableCollectionId.into());152			}153154			let unique_collection_id = collection_id_res?;155			let rmrk_collection_id = <CollectionIndex<T>>::get();156157			<CollectionIndex<T>>::mutate(|n| *n += 1);158			<CollectionIndexMap<T>>::insert(rmrk_collection_id, unique_collection_id);159160			<PalletCommon<T>>::set_scoped_collection_properties(161				unique_collection_id,162				PropertyScope::Rmrk,163				[164					Self::rmrk_property(Metadata, &metadata)?,165					Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,166				]167				.into_iter(),168			)?;169170			Self::deposit_event(Event::CollectionCreated {171				issuer: sender,172				collection_id: rmrk_collection_id,173			});174175			Ok(())176		}177178		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]179		#[transactional]180		pub fn destroy_collection(181			origin: OriginFor<T>,182			collection_id: RmrkCollectionId,183		) -> DispatchResult {184			let sender = ensure_signed(origin)?;185			let cross_sender = T::CrossAccountId::from_sub(sender.clone());186187			let collection = Self::get_typed_nft_collection(188				Self::unique_collection_id(collection_id)?,189				misc::CollectionType::Regular,190			)?;191192			ensure!(193				collection.total_supply() == 0,194				<Error<T>>::CollectionNotEmpty195			);196197			<PalletNft<T>>::destroy_collection(collection, &cross_sender)198				.map_err(Self::map_common_err_to_proxy)?;199200			Self::deposit_event(Event::CollectionDestroyed {201				issuer: sender,202				collection_id,203			});204205			Ok(())206		}207208		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]209		#[transactional]210		pub fn change_collection_issuer(211			origin: OriginFor<T>,212			collection_id: RmrkCollectionId,213			new_issuer: <T::Lookup as StaticLookup>::Source,214		) -> DispatchResult {215			let sender = ensure_signed(origin)?;216217			let new_issuer = T::Lookup::lookup(new_issuer)?;218219			Self::change_collection_owner(220				Self::unique_collection_id(collection_id)?,221				misc::CollectionType::Regular,222				sender.clone(),223				new_issuer.clone(),224			)?;225226			Self::deposit_event(Event::IssuerChanged {227				old_issuer: sender,228				new_issuer,229				collection_id,230			});231232			Ok(())233		}234235		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]236		#[transactional]237		pub fn lock_collection(238			origin: OriginFor<T>,239			collection_id: RmrkCollectionId,240		) -> DispatchResult {241			let sender = ensure_signed(origin)?;242			let cross_sender = T::CrossAccountId::from_sub(sender.clone());243244			let collection = Self::get_typed_nft_collection(245				Self::unique_collection_id(collection_id)?,246				misc::CollectionType::Regular,247			)?;248249			Self::check_collection_owner(&collection, &cross_sender)?;250251			let token_count = collection.total_supply();252253			let mut collection = collection.into_inner();254			collection.limits.token_limit = Some(token_count);255			collection.save()?;256257			Self::deposit_event(Event::CollectionLocked {258				issuer: sender,259				collection_id,260			});261262			Ok(())263		}264265		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]266		#[transactional]267		pub fn mint_nft(268			origin: OriginFor<T>,269			owner: T::AccountId,270			collection_id: RmrkCollectionId,271			recipient: Option<T::AccountId>,272			royalty_amount: Option<Permill>,273			metadata: RmrkString,274		) -> DispatchResult {275			let sender = ensure_signed(origin)?;276			let sender = T::CrossAccountId::from_sub(sender);277			let cross_owner = T::CrossAccountId::from_sub(owner.clone());278279			let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {280				recipient: recipient.unwrap_or_else(|| owner.clone()),281				amount,282			});283284			let collection = Self::get_typed_nft_collection(285				Self::unique_collection_id(collection_id)?,286				misc::CollectionType::Regular,287			)?;288289			let nft_id = Self::create_nft(290				&sender,291				&cross_owner,292				&collection,293				NftType::Regular,294				[295					Self::rmrk_property(RoyaltyInfo, &royalty_info)?,296					Self::rmrk_property(Metadata, &metadata)?,297					Self::rmrk_property(Equipped, &false)?,298					Self::rmrk_property(ResourceCollection, &None::<CollectionId>)?,299					Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,300				]301				.into_iter(),302			)303			.map_err(|err| match err {304				DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),305				err => Self::map_common_err_to_proxy(err),306			})?;307308			Self::deposit_event(Event::NftMinted {309				owner,310				collection_id,311				nft_id: nft_id.0,312			});313314			Ok(())315		}316317		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]318		#[transactional]319		pub fn burn_nft(320			origin: OriginFor<T>,321			collection_id: RmrkCollectionId,322			nft_id: RmrkNftId,323		) -> DispatchResult {324			let sender = ensure_signed(origin)?;325			let cross_sender = T::CrossAccountId::from_sub(sender.clone());326327			Self::destroy_nft(328				cross_sender,329				Self::unique_collection_id(collection_id)?,330				misc::CollectionType::Regular,331				nft_id.into(),332			)?;333334			Self::deposit_event(Event::NFTBurned {335				owner: sender,336				nft_id,337			});338339			Ok(())340		}341342		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]343		#[transactional]344		pub fn set_property(345			origin: OriginFor<T>,346			#[pallet::compact] rmrk_collection_id: RmrkCollectionId,347			maybe_nft_id: Option<RmrkNftId>,348			key: RmrkKeyString,349			value: RmrkValueString,350		) -> DispatchResult {351			let sender = ensure_signed(origin)?;352			let sender = T::CrossAccountId::from_sub(sender);353354			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;355356			match maybe_nft_id {357				Some(nft_id) => {358					let token_id: TokenId = nft_id.into();359360					Self::ensure_nft_owner(collection_id, token_id, &sender)?;361					Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;362363					<PalletNft<T>>::set_scoped_token_property(364						collection_id,365						token_id,366						PropertyScope::Rmrk,367						Self::rmrk_property(UserProperty(key.as_slice()), &value)?,368					)?;369				}370				None => {371					let collection = Self::get_typed_nft_collection(372						collection_id,373						misc::CollectionType::Regular,374					)?;375376					Self::check_collection_owner(&collection, &sender)?;377378					<PalletCommon<T>>::set_scoped_collection_property(379						collection_id,380						PropertyScope::Rmrk,381						Self::rmrk_property(UserProperty(key.as_slice()), &value)?,382					)?;383				}384			}385386			Self::deposit_event(Event::PropertySet {387				collection_id: rmrk_collection_id,388				maybe_nft_id,389				key,390				value,391			});392393			Ok(())394		}395	}396}397398impl<T: Config> Pallet<T> {399	pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {400		let key = rmrk_key.to_key::<T>()?;401402		let scoped_key = PropertyScope::Rmrk403			.apply(key)404			.map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;405406		Ok(scoped_key)407	}408409	pub fn rmrk_property<E: Encode>(410		rmrk_key: RmrkProperty,411		value: &E,412	) -> Result<Property, DispatchError> {413		let key = rmrk_key.to_key::<T>()?;414415		let value = value416			.encode()417			.try_into()418			.map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;419420		let property = Property { key, value };421422		Ok(property)423	}424425	pub fn create_nft(426		sender: &T::CrossAccountId,427		owner: &T::CrossAccountId,428		collection: &NonfungibleHandle<T>,429		nft_type: NftType,430		properties: impl Iterator<Item = Property>,431	) -> Result<TokenId, DispatchError> {432		todo!("store nft type");433		let data = CreateNftExData {434			properties: BoundedVec::default(),435			owner: owner.clone(),436		};437438		let budget = budget::Value::new(2);439440		<PalletNft<T>>::create_item(collection, sender, data, &budget)?;441442		let nft_id = <PalletNft<T>>::current_token_id(collection.id);443444		<PalletNft<T>>::set_scoped_token_properties(445			collection.id,446			nft_id,447			PropertyScope::Rmrk,448			properties,449		)?;450451		Ok(nft_id)452	}453454	fn destroy_nft(455		sender: T::CrossAccountId,456		collection_id: CollectionId,457		collection_type: misc::CollectionType,458		token_id: TokenId,459	) -> DispatchResult {460		let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;461462		<PalletNft<T>>::burn(&collection, &sender, token_id)463			.map_err(Self::map_common_err_to_proxy)?;464465		Ok(())466	}467468	fn change_collection_owner(469		collection_id: CollectionId,470		collection_type: misc::CollectionType,471		sender: T::AccountId,472		new_owner: T::AccountId,473	) -> DispatchResult {474		let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;475		Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;476477		let mut collection = collection.into_inner();478479		collection.owner = new_owner;480		collection.save()481	}482483	fn check_collection_owner(484		collection: &NonfungibleHandle<T>,485		account: &T::CrossAccountId,486	) -> DispatchResult {487		collection488			.check_is_owner(account)489			.map_err(Self::map_common_err_to_proxy)490	}491492	pub fn last_collection_idx() -> RmrkCollectionId {493		<CollectionIndex<T>>::get()494	}495496	pub fn unique_collection_id(rmrk_collection_id: RmrkCollectionId) -> Result<CollectionId, DispatchError> {497		<CollectionIndexMap<T>>::try_get(rmrk_collection_id).map_err(|_| <Error<T>>::CollectionUnknown.into())498	}499500	pub fn get_nft_collection(501		collection_id: CollectionId,502	) -> Result<NonfungibleHandle<T>, DispatchError> {503		let collection = <CollectionHandle<T>>::try_get(collection_id)504			.map_err(|_| <Error<T>>::CollectionUnknown)?;505506		match collection.mode {507			CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),508			_ => Err(<Error<T>>::CollectionUnknown.into()),509		}510	}511512	pub fn collection_exists(collection_id: CollectionId) -> bool {513		<CollectionHandle<T>>::try_get(collection_id).is_ok()514	}515516	pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {517		<TokenData<T>>::contains_key((collection_id, nft_id))518	}519520	pub fn get_collection_property(521		collection_id: CollectionId,522		key: RmrkProperty,523	) -> Result<PropertyValue, DispatchError> {524		let collection_property = <PalletCommon<T>>::collection_properties(collection_id)525			.get(&Self::rmrk_property_key(key)?)526			.ok_or(<Error<T>>::CollectionUnknown)?527			.clone();528529		Ok(collection_property)530	}531532	pub fn get_collection_type(533		collection_id: CollectionId,534	) -> Result<misc::CollectionType, DispatchError> {535		let value = Self::get_collection_property(collection_id, CollectionType)?;536537		let mut value = value.as_slice();538539		misc::CollectionType::decode(&mut value)540			.map_err(|_| <Error<T>>::CorruptedCollectionType.into())541	}542543	pub fn ensure_collection_type(544		collection_id: CollectionId,545		collection_type: misc::CollectionType,546	) -> DispatchResult {547		let actual_type = Self::get_collection_type(collection_id)?;548		ensure!(549			actual_type == collection_type,550			<CommonError<T>>::NoPermission551		);552553		Ok(())554	}555556	pub fn get_nft_property(557		collection_id: CollectionId,558		nft_id: TokenId,559		key: RmrkProperty,560	) -> Result<PropertyValue, DispatchError> {561		let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))562			.get(&Self::rmrk_property_key(key)?)563			.ok_or(<Error<T>>::NoAvailableNftId)?564			.clone();565566		Ok(nft_property)567	}568569	pub fn get_nft_type(570		_collection_id: CollectionId,571		_token_id: TokenId,572	) -> Result<NftType, DispatchError> {573		todo!("should get it from properties?")574	}575576	pub fn ensure_nft_type(577		collection_id: CollectionId,578		token_id: TokenId,579		nft_type: NftType,580	) -> DispatchResult {581		let actual_type = Self::get_nft_type(collection_id, token_id)?;582		ensure!(actual_type == nft_type, <Error<T>>::NoPermission);583584		Ok(())585	}586587	pub fn ensure_nft_owner(588		collection_id: CollectionId,589		token_id: TokenId,590		possible_owner: &T::CrossAccountId,591	) -> DispatchResult {592		let token_data =593			<TokenData<T>>::get((collection_id, token_id)).ok_or(<Error<T>>::NoAvailableNftId)?;594595		ensure!(596			token_data.owner == *possible_owner,597			<Error<T>>::NoPermission598		);599600		Ok(())601	}602603	pub fn filter_user_properties<Key, Value, R, Mapper>(604		collection_id: CollectionId,605		token_id: Option<TokenId>,606		filter_keys: Option<Vec<RmrkPropertyKey>>,607		mapper: Mapper,608	) -> Result<Vec<R>, DispatchError>609	where610		Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,611		Value: Decode + Default,612		Mapper: Fn(Key, Value) -> R,613	{614		filter_keys615			.map(|keys| {616				let properties = keys617					.into_iter()618					.filter_map(|key| {619						let key: Key = key.try_into().ok()?;620621						let value = match token_id {622							Some(token_id) => Self::get_nft_property(623								collection_id,624								token_id,625								UserProperty(key.as_ref()),626							),627							None => Self::get_collection_property(628								collection_id,629								UserProperty(key.as_ref()),630							),631						}632						.ok()?633						.decode_or_default();634635						Some(mapper(key, value))636					})637					.collect();638639				Ok(properties)640			})641			.unwrap_or_else(|| {642				let properties =643					Self::iterate_user_properties(collection_id, token_id, mapper)?.collect();644645				Ok(properties)646			})647	}648649	pub fn iterate_user_properties<Key, Value, R, Mapper>(650		collection_id: CollectionId,651		token_id: Option<TokenId>,652		mapper: Mapper,653	) -> Result<impl Iterator<Item = R>, DispatchError>654	where655		Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,656		Value: Decode + Default,657		Mapper: Fn(Key, Value) -> R,658	{659		let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;660661		let properties = match token_id {662			Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),663			None => <PalletCommon<T>>::collection_properties(collection_id),664		};665666		let properties = properties.into_iter().filter_map(move |(key, value)| {667			let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;668669			let key: Key = key.to_vec().try_into().ok()?;670			let value: Value = value.decode_or_default();671672			Some(mapper(key, value))673		});674675		Ok(properties)676	}677678	pub fn get_typed_nft_collection(679		collection_id: CollectionId,680		collection_type: misc::CollectionType,681	) -> Result<NonfungibleHandle<T>, DispatchError> {682		Self::ensure_collection_type(collection_id, collection_type)?;683684		Self::get_nft_collection(collection_id)685	}686687	fn map_common_err_to_proxy(err: DispatchError) -> DispatchError {688		map_common_err_to_proxy! {689			match err {690				NoPermission => NoPermission,691				CollectionTokenLimitExceeded => CollectionFullOrLocked,692				PublicMintingNotAllowed => NoPermission,693				TokenNotFound => NoAvailableNftId694			}695		}696	}697}
after · pallets/proxy-rmrk-core/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, Permill, traits::StaticLookup};22use sp_std::vec::Vec;23use up_data_structs::*;24use pallet_common::{25	Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,26};27use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};28use pallet_structure::Pallet as PalletStructure;29use pallet_evm::account::CrossAccountId;30use core::convert::AsRef;3132pub use pallet::*;3334pub mod misc;35pub mod property;3637use misc::*;38pub use property::*;3940use RmrkProperty::*;4142#[frame_support::pallet]43pub mod pallet {44	use super::*;45	use pallet_evm::account;4647	#[pallet::config]48	pub trait Config:49		frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config50	{51		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;52	}5354	#[pallet::storage]55	#[pallet::getter(fn collection_index)]56	pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;5758	#[pallet::storage]59	#[pallet::getter(fn collection_index_map)]60	pub type CollectionIndexMap<T: Config> =61		StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, 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		CollectionCreated {71			issuer: T::AccountId,72			collection_id: RmrkCollectionId,73		},74		CollectionDestroyed {75			issuer: T::AccountId,76			collection_id: RmrkCollectionId,77		},78		IssuerChanged {79			old_issuer: T::AccountId,80			new_issuer: T::AccountId,81			collection_id: RmrkCollectionId,82		},83		CollectionLocked {84			issuer: T::AccountId,85			collection_id: RmrkCollectionId,86		},87		NftMinted {88			owner: T::AccountId,89			collection_id: RmrkCollectionId,90			nft_id: RmrkNftId,91		},92		NFTBurned {93			owner: T::AccountId,94			nft_id: RmrkNftId,95		},96		PropertySet {97			collection_id: RmrkCollectionId,98			maybe_nft_id: Option<RmrkNftId>,99			key: RmrkKeyString,100			value: RmrkValueString,101		},102		ResourceAdded {103			nft_id: RmrkNftId,104			resource_id: RmrkResourceId,105		},106	}107108	#[pallet::error]109	pub enum Error<T> {110		/* Unique-specific events */111		CorruptedCollectionType,112		NftTypeEncodeError,113		RmrkPropertyKeyIsTooLong,114		RmrkPropertyValueIsTooLong, // todo utilize that in RPCs115116		/* RMRK compatible events */117		CollectionNotEmpty,118		NoAvailableCollectionId,119		NoAvailableNftId,120		CollectionUnknown,121		NoPermission,122		CollectionFullOrLocked,123		// todo add resource errors?124	}125126	#[pallet::call]127	impl<T: Config> Pallet<T> {128		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]129		#[transactional]130		pub fn create_collection(131			origin: OriginFor<T>,132			metadata: RmrkString,133			max: Option<u32>,134			symbol: RmrkCollectionSymbol,135		) -> DispatchResult {136			let sender = ensure_signed(origin)?;137138			let limits = CollectionLimits {139				owner_can_transfer: Some(false),140				token_limit: max,141				..Default::default()142			};143144			let data = CreateCollectionData {145				limits: Some(limits),146				token_prefix: symbol147					.into_inner()148					.try_into()149					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,150				..Default::default()151			};152153			<CollectionIndex<T>>::mutate(|n| *n += 1);154155			let unique_collection_id = Self::init_collection(156				T::CrossAccountId::from_sub(sender.clone()),157				data,158				[159					Self::rmrk_property(Metadata, &metadata)?,160					Self::rmrk_property(CollectionType, &misc::CollectionType::Regular)?,161				]162				.into_iter(),163			)?; //collection_id_res?;164			let rmrk_collection_id = <CollectionIndex<T>>::get();165166			<CollectionIndexMap<T>>::insert(rmrk_collection_id, unique_collection_id);167168			Self::deposit_event(Event::CollectionCreated {169				issuer: sender,170				collection_id: rmrk_collection_id,171			});172173			Ok(())174		}175176		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]177		#[transactional]178		pub fn destroy_collection(179			origin: OriginFor<T>,180			collection_id: RmrkCollectionId,181		) -> DispatchResult {182			let sender = ensure_signed(origin)?;183			let cross_sender = T::CrossAccountId::from_sub(sender.clone());184185			let collection = Self::get_typed_nft_collection(186				Self::unique_collection_id(collection_id)?,187				misc::CollectionType::Regular,188			)?;189190			ensure!(191				collection.total_supply() == 0,192				<Error<T>>::CollectionNotEmpty193			);194195			<PalletNft<T>>::destroy_collection(collection, &cross_sender)196				.map_err(Self::map_common_err_to_proxy)?;197198			Self::deposit_event(Event::CollectionDestroyed {199				issuer: sender,200				collection_id,201			});202203			Ok(())204		}205206		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]207		#[transactional]208		pub fn change_collection_issuer(209			origin: OriginFor<T>,210			collection_id: RmrkCollectionId,211			new_issuer: <T::Lookup as StaticLookup>::Source,212		) -> DispatchResult {213			let sender = ensure_signed(origin)?;214215			let new_issuer = T::Lookup::lookup(new_issuer)?;216217			Self::change_collection_owner(218				Self::unique_collection_id(collection_id)?,219				misc::CollectionType::Regular,220				sender.clone(),221				new_issuer.clone(),222			)?;223224			Self::deposit_event(Event::IssuerChanged {225				old_issuer: sender,226				new_issuer,227				collection_id,228			});229230			Ok(())231		}232233		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]234		#[transactional]235		pub fn lock_collection(236			origin: OriginFor<T>,237			collection_id: RmrkCollectionId,238		) -> DispatchResult {239			let sender = ensure_signed(origin)?;240			let cross_sender = T::CrossAccountId::from_sub(sender.clone());241242			let collection = Self::get_typed_nft_collection(243				Self::unique_collection_id(collection_id)?,244				misc::CollectionType::Regular,245			)?;246247			Self::check_collection_owner(&collection, &cross_sender)?;248249			let token_count = collection.total_supply();250251			let mut collection = collection.into_inner();252			collection.limits.token_limit = Some(token_count);253			collection.save()?;254255			Self::deposit_event(Event::CollectionLocked {256				issuer: sender,257				collection_id,258			});259260			Ok(())261		}262263		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]264		#[transactional]265		pub fn mint_nft(266			origin: OriginFor<T>,267			owner: T::AccountId,268			collection_id: RmrkCollectionId,269			recipient: Option<T::AccountId>,270			royalty_amount: Option<Permill>,271			metadata: RmrkString,272		) -> DispatchResult {273			let sender = ensure_signed(origin)?;274			let sender = T::CrossAccountId::from_sub(sender);275			let cross_owner = T::CrossAccountId::from_sub(owner.clone());276277			let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo {278				recipient: recipient.unwrap_or_else(|| owner.clone()),279				amount,280			});281282			let collection = Self::get_typed_nft_collection(283				Self::unique_collection_id(collection_id)?,284				misc::CollectionType::Regular,285			)?;286287			let nft_id = Self::create_nft(288				&sender,289				&cross_owner,290				&collection,291				[292					Self::rmrk_property(TokenType, &NftType::Regular)?,293					Self::rmrk_property(RoyaltyInfo, &royalty_info)?,294					Self::rmrk_property(Metadata, &metadata)?,295					Self::rmrk_property(Equipped, &false)?,296					Self::rmrk_property(297						ResourceCollection,298						&Self::init_collection(299							sender.clone(),300							CreateCollectionData {301								..Default::default()302							},303							[Self::rmrk_property(304								CollectionType,305								&misc::CollectionType::Resource,306							)?]307							.into_iter(),308						)?,309					)?, // todo possibly add limits to the collection if rmrk warrants them310					Self::rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?, // todo create resource priorities?311				]312				.into_iter(),313			)314			.map_err(|err| match err {315				DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),316				err => Self::map_common_err_to_proxy(err),317			})?;318319			Self::deposit_event(Event::NftMinted {320				owner,321				collection_id,322				nft_id: nft_id.0,323			});324325			Ok(())326		}327328		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]329		#[transactional]330		pub fn burn_nft(331			origin: OriginFor<T>,332			collection_id: RmrkCollectionId,333			nft_id: RmrkNftId,334		) -> DispatchResult {335			let sender = ensure_signed(origin)?;336			let cross_sender = T::CrossAccountId::from_sub(sender.clone());337338			Self::destroy_nft(339				cross_sender,340				Self::unique_collection_id(collection_id)?,341				misc::CollectionType::Regular,342				nft_id.into(),343			)?;344345			Self::deposit_event(Event::NFTBurned {346				owner: sender,347				nft_id,348			});349350			Ok(())351		}352353		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]354		#[transactional]355		pub fn set_property(356			origin: OriginFor<T>,357			#[pallet::compact] rmrk_collection_id: RmrkCollectionId,358			maybe_nft_id: Option<RmrkNftId>,359			key: RmrkKeyString,360			value: RmrkValueString,361		) -> DispatchResult {362			let sender = ensure_signed(origin)?;363			let sender = T::CrossAccountId::from_sub(sender);364365			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;366367			match maybe_nft_id {368				Some(nft_id) => {369					let token_id: TokenId = nft_id.into();370371					Self::ensure_nft_owner(collection_id, token_id, &sender)?;372					Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;373374					<PalletNft<T>>::set_scoped_token_property(375						collection_id,376						token_id,377						PropertyScope::Rmrk,378						Self::rmrk_property(UserProperty(key.as_slice()), &value)?,379					)?;380				}381				None => {382					let collection = Self::get_typed_nft_collection(383						collection_id,384						misc::CollectionType::Regular,385					)?;386387					Self::check_collection_owner(&collection, &sender)?;388389					<PalletCommon<T>>::set_scoped_collection_property(390						collection_id,391						PropertyScope::Rmrk,392						Self::rmrk_property(UserProperty(key.as_slice()), &value)?,393					)?;394				}395			}396397			Self::deposit_event(Event::PropertySet {398				collection_id: rmrk_collection_id,399				maybe_nft_id,400				key,401				value,402			});403404			Ok(())405		}406407		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]408		#[transactional]409		pub fn add_basic_resource(410			origin: OriginFor<T>,411			collection_id: RmrkCollectionId,412			nft_id: RmrkNftId,413			resource: RmrkBasicResource,414		) -> DispatchResult {415			let sender = ensure_signed(origin.clone())?;416417			let resource_id = Self::resource_add(418				sender,419				Self::unique_collection_id(collection_id)?,420				nft_id.into(),421				[422					Self::rmrk_property(TokenType, &NftType::Resource)?,423					Self::rmrk_property(ResourceType, &misc::ResourceType::Basic)?,424					Self::rmrk_property(Src, &resource.src)?,425					Self::rmrk_property(Metadata, &resource.metadata)?,426					Self::rmrk_property(License, &resource.license)?,427					Self::rmrk_property(Thumb, &resource.thumb)?,428				]429				.into_iter(),430			)?;431432			Self::deposit_event(Event::ResourceAdded {433				nft_id,434				resource_id,435			});436			Ok(())437		}438439		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]440		#[transactional]441		pub fn add_composable_resource(442			origin: OriginFor<T>,443			collection_id: RmrkCollectionId,444			nft_id: RmrkNftId,445			_resource_id: RmrkBoundedResource,446			resource: RmrkComposableResource,447		) -> DispatchResult {448			let sender = ensure_signed(origin.clone())?;449450			let resource_id = Self::resource_add(451				sender,452				Self::unique_collection_id(collection_id)?,453				nft_id.into(),454				[455					Self::rmrk_property(TokenType, &NftType::Resource)?,456					Self::rmrk_property(ResourceType, &misc::ResourceType::Composable)?,457					Self::rmrk_property(Parts, &resource.parts)?,458					Self::rmrk_property(Base, &resource.base)?,459					Self::rmrk_property(Src, &resource.src)?,460					Self::rmrk_property(Metadata, &resource.metadata)?,461					Self::rmrk_property(License, &resource.license)?,462					Self::rmrk_property(Thumb, &resource.thumb)?,463				]464				.into_iter(),465			)?;466467			Self::deposit_event(Event::ResourceAdded {468				nft_id,469				resource_id,470			});471			Ok(())472		}473474		#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]475		#[transactional]476		pub fn add_slot_resource(477			origin: OriginFor<T>,478			collection_id: RmrkCollectionId,479			nft_id: RmrkNftId,480			resource: RmrkSlotResource,481		) -> DispatchResult {482			let sender = ensure_signed(origin.clone())?;483484			let resource_id = Self::resource_add(485				sender,486				Self::unique_collection_id(collection_id)?,487				nft_id.into(),488				[489					Self::rmrk_property(TokenType, &NftType::Resource)?,490					Self::rmrk_property(ResourceType, &misc::ResourceType::Slot)?,491					Self::rmrk_property(Base, &resource.base)?,492					Self::rmrk_property(Src, &resource.src)?,493					Self::rmrk_property(Metadata, &resource.metadata)?,494					Self::rmrk_property(Slot, &resource.slot)?,495					Self::rmrk_property(License, &resource.license)?,496					Self::rmrk_property(Thumb, &resource.thumb)?,497				]498				.into_iter(),499			)?;500501			Self::deposit_event(Event::ResourceAdded {502				nft_id,503				resource_id,504			});505			Ok(())506		}507	}508}509510impl<T: Config> Pallet<T> {511	pub fn rmrk_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {512		let key = rmrk_key.to_key::<T>()?;513514		let scoped_key = PropertyScope::Rmrk515			.apply(key)516			.map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;517518		Ok(scoped_key)519	}520521	pub fn rmrk_property<E: Encode>(522		rmrk_key: RmrkProperty,523		value: &E,524	) -> Result<Property, DispatchError> {525		let key = rmrk_key.to_key::<T>()?;526527		let value = value528			.encode()529			.try_into()530			.map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;531532		let property = Property { key, value };533534		Ok(property)535	}536537	fn init_collection(538		sender: T::CrossAccountId,539		data: CreateCollectionData<T::AccountId>,540		properties: impl Iterator<Item = Property>,541	) -> Result<CollectionId, DispatchError> {542		let collection_id = <PalletNft<T>>::init_collection(sender, data);543544		if let Err(DispatchError::Arithmetic(_)) = &collection_id {545			return Err(<Error<T>>::NoAvailableCollectionId.into());546		}547548		<PalletCommon<T>>::set_scoped_collection_properties(549			collection_id?,550			PropertyScope::Rmrk,551			properties,552		)?;553554		collection_id555	}556557	pub fn create_nft(558		sender: &T::CrossAccountId,559		owner: &T::CrossAccountId,560		collection: &NonfungibleHandle<T>,561		properties: impl Iterator<Item = Property>,562	) -> Result<TokenId, DispatchError> {563		let data = CreateNftExData {564			properties: BoundedVec::default(),565			owner: owner.clone(),566		};567568		let budget = budget::Value::new(2);569570		<PalletNft<T>>::create_item(collection, sender, data, &budget)?;571572		let nft_id = <PalletNft<T>>::current_token_id(collection.id);573574		<PalletNft<T>>::set_scoped_token_properties(575			collection.id,576			nft_id,577			PropertyScope::Rmrk,578			properties,579		)?;580581		Ok(nft_id)582	}583584	fn destroy_nft(585		sender: T::CrossAccountId,586		collection_id: CollectionId,587		collection_type: misc::CollectionType,588		token_id: TokenId,589	) -> DispatchResult {590		let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;591592		<PalletNft<T>>::burn(&collection, &sender, token_id)593			.map_err(Self::map_common_err_to_proxy)?;594595		Ok(())596	}597598	fn resource_add(599		sender: T::AccountId,600		collection_id: CollectionId,601		token_id: TokenId,602		resource_properties: impl Iterator<Item = Property>,603	) -> Result<RmrkResourceId, DispatchError> {604		let collection =605			Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;606		ensure!(collection.owner == sender, Error::<T>::NoPermission);607608		// Check NFT lock status // todo depends on market, maybe later609		//ensure!(!Pallet::<T>::is_locked(collection_id, nft_id), pallet_uniques::Error::<T>::Locked);610611		let sender = T::CrossAccountId::from_sub(sender);612		let budget = budget::Value::new(10);613		let pending = <PalletStructure<T>>::check_indirectly_owned(614			sender.clone(),615			collection_id,616			token_id,617			None,618			&budget,619		)?;620621		let resource_collection_id: CollectionId =622			Self::get_nft_property(collection_id, token_id, ResourceCollection)?623				.decode_or_default();624		let resource_collection =625			Self::get_typed_nft_collection(resource_collection_id, misc::CollectionType::Resource)?;626627		// todo probably add extra connections to bases, slots, etc., when RMRK starts to use them628629		let resource_id = Self::create_nft(630			&sender, // todo owner of the nft?631			&sender,632			&resource_collection,633			resource_properties.chain(634				[635					Self::rmrk_property(PendingResourceAccept, &pending)?,636					Self::rmrk_property(PendingResourceRemoval, &false)?,637				]638				.into_iter(),639			),640		)641		.map_err(|err| match err {642			DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),643			err => Self::map_common_err_to_proxy(err),644		})?;645646		Ok(resource_id.0)647	}648649	fn change_collection_owner(650		collection_id: CollectionId,651		collection_type: misc::CollectionType,652		sender: T::AccountId,653		new_owner: T::AccountId,654	) -> DispatchResult {655		let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;656		Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;657658		let mut collection = collection.into_inner();659660		collection.owner = new_owner;661		collection.save()662	}663664	fn check_collection_owner(665		collection: &NonfungibleHandle<T>,666		account: &T::CrossAccountId,667	) -> DispatchResult {668		collection669			.check_is_owner(account)670			.map_err(Self::map_common_err_to_proxy)671	}672673	pub fn last_collection_idx() -> RmrkCollectionId {674		<CollectionIndex<T>>::get()675	}676677	pub fn unique_collection_id(678		rmrk_collection_id: RmrkCollectionId,679	) -> Result<CollectionId, DispatchError> {680		<CollectionIndexMap<T>>::try_get(rmrk_collection_id)681			.map_err(|_| <Error<T>>::CollectionUnknown.into())682	}683684	pub fn get_nft_collection(685		collection_id: CollectionId,686	) -> Result<NonfungibleHandle<T>, DispatchError> {687		let collection = <CollectionHandle<T>>::try_get(collection_id)688			.map_err(|_| <Error<T>>::CollectionUnknown)?;689690		match collection.mode {691			CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),692			_ => Err(<Error<T>>::CollectionUnknown.into()),693		}694	}695696	pub fn collection_exists(collection_id: CollectionId) -> bool {697		<CollectionHandle<T>>::try_get(collection_id).is_ok()698	}699700	pub fn get_collection_property(701		collection_id: CollectionId,702		key: RmrkProperty,703	) -> Result<PropertyValue, DispatchError> {704		let collection_property = <PalletCommon<T>>::collection_properties(collection_id)705			.get(&Self::rmrk_property_key(key)?)706			.ok_or(<Error<T>>::CollectionUnknown)?707			.clone();708709		Ok(collection_property)710	}711712	pub fn get_collection_type(713		collection_id: CollectionId,714	) -> Result<misc::CollectionType, DispatchError> {715		let value = Self::get_collection_property(collection_id, CollectionType)?;716717		let mut value = value.as_slice();718719		misc::CollectionType::decode(&mut value)720			.map_err(|_| <Error<T>>::CorruptedCollectionType.into())721	}722723	pub fn ensure_collection_type(724		collection_id: CollectionId,725		collection_type: misc::CollectionType,726	) -> DispatchResult {727		let actual_type = Self::get_collection_type(collection_id)?;728		ensure!(729			actual_type == collection_type,730			<CommonError<T>>::NoPermission731		);732733		Ok(())734	}735736	pub fn get_typed_nft_collection(737		collection_id: CollectionId,738		collection_type: misc::CollectionType,739	) -> Result<NonfungibleHandle<T>, DispatchError> {740		Self::ensure_collection_type(collection_id, collection_type)?;741742		Self::get_nft_collection(collection_id)743	}744745	pub fn get_nft_property(746		collection_id: CollectionId,747		nft_id: TokenId,748		key: RmrkProperty,749	) -> Result<PropertyValue, DispatchError> {750		let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))751			.get(&Self::rmrk_property_key(key)?)752			.ok_or(<Error<T>>::NoAvailableNftId)? // todo replace with better error753			.clone();754755		Ok(nft_property)756	}757758	pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {759		<TokenData<T>>::contains_key((collection_id, nft_id))760	}761762	pub fn get_nft_type(763		collection_id: CollectionId,764		token_id: TokenId,765	) -> Result<NftType, DispatchError> {766		Ok(Self::get_nft_property(collection_id, token_id, TokenType)?.decode_or_default())767		// todo throw error768		// NftTypeEncodeError?769	}770771	pub fn ensure_nft_type(772		collection_id: CollectionId,773		token_id: TokenId,774		nft_type: NftType,775	) -> DispatchResult {776		let actual_type = Self::get_nft_type(collection_id, token_id)?;777		ensure!(actual_type == nft_type, <Error<T>>::NoPermission);778779		Ok(())780	}781782	pub fn ensure_nft_owner(783		collection_id: CollectionId,784		token_id: TokenId,785		possible_owner: &T::CrossAccountId,786	) -> DispatchResult {787		let token_data =788			<TokenData<T>>::get((collection_id, token_id)).ok_or(<Error<T>>::NoAvailableNftId)?;789790		ensure!(791			token_data.owner == *possible_owner,792			<Error<T>>::NoPermission793		);794795		Ok(())796	}797798	pub fn filter_user_properties<Key, Value, R, Mapper>(799		collection_id: CollectionId,800		token_id: Option<TokenId>,801		filter_keys: Option<Vec<RmrkPropertyKey>>,802		mapper: Mapper,803	) -> Result<Vec<R>, DispatchError>804	where805		Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,806		Value: Decode + Default,807		Mapper: Fn(Key, Value) -> R,808	{809		filter_keys810			.map(|keys| {811				let properties = keys812					.into_iter()813					.filter_map(|key| {814						let key: Key = key.try_into().ok()?;815816						let value = match token_id {817							Some(token_id) => Self::get_nft_property(818								collection_id,819								token_id,820								UserProperty(key.as_ref()),821							),822							None => Self::get_collection_property(823								collection_id,824								UserProperty(key.as_ref()),825							),826						}827						.ok()?828						.decode_or_default();829830						Some(mapper(key, value))831					})832					.collect();833834				Ok(properties)835			})836			.unwrap_or_else(|| {837				let properties =838					Self::iterate_user_properties(collection_id, token_id, mapper)?.collect();839840				Ok(properties)841			})842	}843844	pub fn iterate_user_properties<Key, Value, R, Mapper>(845		collection_id: CollectionId,846		token_id: Option<TokenId>,847		mapper: Mapper,848	) -> Result<impl Iterator<Item = R>, DispatchError>849	where850		Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,851		Value: Decode + Default,852		Mapper: Fn(Key, Value) -> R,853	{854		let key_prefix = Self::rmrk_property_key(UserProperty(b""))?;855856		let properties = match token_id {857			Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),858			None => <PalletCommon<T>>::collection_properties(collection_id),859		};860861		let properties = properties.into_iter().filter_map(move |(key, value)| {862			let key = key.as_slice().strip_prefix(key_prefix.as_slice())?;863864			let key: Key = key.to_vec().try_into().ok()?;865			let value: Value = value.decode_or_default();866867			Some(mapper(key, value))868		});869870		Ok(properties)871	}872873	fn map_common_err_to_proxy(err: DispatchError) -> DispatchError {874		map_common_err_to_proxy! {875			match err {876				NoPermission => NoPermission,877				CollectionTokenLimitExceeded => CollectionFullOrLocked,878				PublicMintingNotAllowed => NoPermission,879				TokenNotFound => NoAvailableNftId880			}881		}882	}883}
modifiedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/misc.rs
+++ b/pallets/proxy-rmrk-core/src/misc.rs
@@ -18,6 +18,7 @@
 	fn decode_or_default(&self) -> T;
 }
 
+// todo fail if unwrap doesn't work
 impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {
 	fn decode_or_default(&self) -> T {
 		let mut value = self.as_slice();
@@ -30,6 +31,7 @@
 	fn rebind(&self) -> BoundedVec<u8, S>;
 }
 
+// todo fail if unwrap doesn't work
 impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T>
 where
 	BoundedVec<u8, S>: TryFrom<Vec<u8>>,
@@ -46,11 +48,22 @@
 	Base,
 }
 
-#[derive(Encode, Decode, PartialEq, Eq)]
+// todo remove default?
+#[derive(Encode, Decode, PartialEq, Eq, Default)]
 pub enum NftType {
+	#[default]
 	Regular,
 	Resource,
 	FixedPart,
 	SlotPart,
 	Theme,
 }
+
+// todo remove default?
+#[derive(Encode, Decode, PartialEq, Eq, Default)]
+pub enum ResourceType {
+	#[default]
+	Basic,
+	Composable,
+	Slot,
+}
modifiedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/property.rs
+++ b/pallets/proxy-rmrk-core/src/property.rs
@@ -4,6 +4,7 @@
 pub enum RmrkProperty<'r> {
 	Metadata,
 	CollectionType,
+	TokenType,
 	RoyaltyInfo,
 	Equipped,
 	ResourceCollection,
@@ -47,6 +48,7 @@
 		match self {
 			Self::Metadata => key!("metadata"),
 			Self::CollectionType => key!("collection-type"),
+			Self::TokenType => key!("token-type"),
 			Self::RoyaltyInfo => key!("royalty-info"),
 			Self::Equipped => key!("equipped"),
 			Self::ResourceCollection => key!("resource-collection"),
modifiedpallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -166,8 +166,8 @@
 				&sender,
 				owner,
 				&collection,
-				NftType::Theme,
 				[
+					<PalletCore<T>>::rmrk_property(TokenType, &NftType::Theme)?,
 					<PalletCore<T>>::rmrk_property(ThemeName, &theme.name)?,
 					<PalletCore<T>>::rmrk_property(ThemeInherit, &theme.inherit)?,
 				]
@@ -212,8 +212,8 @@
 			sender,
 			owner,
 			collection,
-			nft_type,
 			[
+				<PalletCore<T>>::rmrk_property(TokenType, &nft_type)?,
 				<PalletCore<T>>::rmrk_property(Src, &src)?,
 				<PalletCore<T>>::rmrk_property(ZIndex, &z_index)?,
 			]
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -41,6 +41,7 @@
 // RMRK
 use rmrk::{
 	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,
+	ResourceTypes, BasicResource, ComposableResource, SlotResource,
 };
 pub use rmrk::{
 	primitives::{
@@ -49,8 +50,6 @@
 	},
 	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
 	FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,
-	BasicResource as RmrkBasicResource, ComposableResource as RmrkComposableResource,
-	SlotResource as RmrkSlotResource,
 };
 
 mod bounded;
@@ -942,23 +941,26 @@
 pub type RmrkCollectionInfo<AccountId> =
 	CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;
 pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;
-pub type RmrkResourceInfo = ResourceInfo<RmrkBoundedResource, RmrkString, RmrkBoundedParts>;
+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 RmrkThemeProperty = ThemeProperty<RmrkString>;
 pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;
+pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;
+
+pub type RmrkBasicResource = BasicResource<RmrkString>;
+pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;
+pub type RmrkSlotResource = SlotResource<RmrkString>;
 
+pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;
 pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;
 pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
 pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
-
-type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;
-type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>;
+pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;
+pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed
 
 pub type RmrkRpcString = Vec<u8>;
 pub type RmrkThemeName = RmrkRpcString;
 pub type RmrkPropertyKey = RmrkRpcString;
-
-pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;
modifiedprimitives/data-structs/src/rmrk.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/rmrk.rs
+++ b/primitives/data-structs/src/rmrk.rs
@@ -282,17 +282,16 @@
 #[cfg_attr(
 	feature = "std",
 	serde(bound = r#"
-			BoundedResource: AsRef<[u8]>,
 			BoundedString: AsRef<[u8]>,
 			BoundedParts: AsRef<[PartId]>
 		"#)
 )]
-pub struct ResourceInfo<BoundedResource, BoundedString: Default, BoundedParts> {
+pub struct ResourceInfo<BoundedString: Default, BoundedParts> {
 	/// id is a 5-character string of reasonable uniqueness.
 	/// The combination of base ID and resource id should be unique across the entire RMRK
 	/// ecosystem which
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub id: BoundedResource,
+	//#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
+	pub id: ResourceId,
 
 	/// Resource
 	pub resource: ResourceTypes<BoundedString, BoundedParts>,
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -152,6 +152,7 @@
                         Err(_) => return Ok(None),
                     };
 
+                    // todo replace dispatch... calls with calls to rmrkcore and NFT collection. There's no point trying non-NFT collections
                     let nfts_count = dispatch_unique_runtime!(collection_id.total_supply())?;
 
                     Ok(Some(RmrkCollectionInfo {
@@ -171,6 +172,7 @@
                     let nft_id = TokenId(nft_by_id);
                     if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
 
+                    // todo replace dispatch with collection
                     let owner = match dispatch_unique_runtime!(collection_id.token_owner(nft_id))? {
                         Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {
                             Some((col, tok)) => RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(col.0, tok.0),
@@ -270,34 +272,51 @@
 
                 fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
                     use frame_support::BoundedVec;
-                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
+                    use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType, RmrkDecode}};
+                    use pallet_common::CommonCollectionOperations;
 
                     let collection_id = RmrkCore::unique_collection_id(collection_id)?;
-                    if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); } // todo make sure the collection type doesn't matter
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
 
                     let nft_id = TokenId(nft_id);
-                    if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
+                    if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
 
-                    let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)
-                        .unwrap()
+                    let res_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)?
                         .decode_or_default();
-                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
+                    let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?;
 
-                    let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))
-                        .filter_map(|(resource_id, properties)| Some(RmrkResourceInfo {
-                            id: BoundedVec::default(), // todo ResourceId property
-                            pending: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::PendingResourceAccept).unwrap().decode_or_default(),
-                            pending_removal: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::PendingResourceRemoval).unwrap().decode_or_default(),
-                            resource: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::ResourceType).unwrap().decode_or_default(),/* {
-                                RmrkResourceTypes::Basic(resource) => RmrkResourceTypes::Basic(),/*(RmrkBasicResource {
-                                    src: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Src).unwrap().decode_or_default(),
-                                    metadata: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Metadata).unwrap().decode_or_default(),
-                                    license: RmrkCore::get_nft_property_inner(properties, RmrkProperty::License).unwrap().decode_or_default(),
-                                    thumb: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Thumb).unwrap().decode_or_default(),
-                                },*///BasicResource<BoundedString>)
-                                _ => todo!(), //RmrkResourceTypes::Composable(ComposableResource<BoundedString, BoundedParts>),
-                                //RmrkResourceTypes::Slot(SlotResource<BoundedString>),
-                            },*/
+                    let resources = resource_collection
+                        .collection_tokens()
+                        .iter()
+                        .filter_map(|(res_id)| Some(RmrkResourceInfo {
+                            id: res_id.0,
+                            pending: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).unwrap().decode_or_default(),
+                            pending_removal: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).unwrap().decode_or_default(),
+                            resource: match RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::ResourceType).unwrap().decode_or_default() {
+                                ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {
+                                    src: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Src).unwrap().decode_or_default(),
+                                    metadata: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap().decode_or_default(),
+                                    license: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::License).unwrap().decode_or_default(),
+                                    thumb: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap().decode_or_default(),
+                                }),
+                                ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {
+                                    parts: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Parts).unwrap().decode_or_default(),
+                                    base: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Base).unwrap().decode_or_default(),
+                                    src: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Src).unwrap().decode_or_default(),
+                                    metadata: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap().decode_or_default(),
+                                    license: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::License).unwrap().decode_or_default(),
+                                    thumb: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap().decode_or_default(),
+                                }),
+                                ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {
+                                    base: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Base).unwrap().decode_or_default(),
+                                    src: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Src).unwrap().decode_or_default(),
+                                    metadata: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap().decode_or_default(),
+                                    slot: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Slot).unwrap().decode_or_default(),
+                                    license: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::License).unwrap().decode_or_default(),
+                                    thumb: RmrkCore::get_nft_property(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap().decode_or_default(),
+                                }),
+                                // todo refactor :|
+                            },
                         }))
                         .collect();
 
@@ -308,10 +327,10 @@
                     use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
 
                     let collection_id = RmrkCore::unique_collection_id(collection_id)?;
-                    if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); } // todo ensure the collection type doesn't matter
+                    if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
 
                     let nft_id = TokenId(nft_id);
-                    if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
+                    if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); }
 
                     /*let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)
                         .unwrap()
@@ -327,6 +346,7 @@
                         .sort_by_key(|(_, index)| *index)
                         .into_iter().map(|(resource_id, _)| resource_id)*/
                     let priorities = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourcePriorities)?.decode_or_default();
+                    // todo let it simply be default here after removing default from decode
 
                     Ok(priorities)
                 }
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -437,6 +437,33 @@
        **/
       [key: string]: AugmentedError<ApiType>;
     };
+    rmrkCore: {
+      CollectionFullOrLocked: AugmentedError<ApiType>;
+      CollectionNotEmpty: AugmentedError<ApiType>;
+      CollectionUnknown: AugmentedError<ApiType>;
+      CorruptedCollectionType: AugmentedError<ApiType>;
+      NftTypeEncodeError: AugmentedError<ApiType>;
+      NoAvailableCollectionId: AugmentedError<ApiType>;
+      NoAvailableNftId: AugmentedError<ApiType>;
+      NoPermission: AugmentedError<ApiType>;
+      RmrkPropertyKeyIsTooLong: AugmentedError<ApiType>;
+      RmrkPropertyValueIsTooLong: AugmentedError<ApiType>;
+      /**
+       * Generic error
+       **/
+      [key: string]: AugmentedError<ApiType>;
+    };
+    rmrkEquip: {
+      BaseDoesntExist: AugmentedError<ApiType>;
+      NeedsDefaultThemeFirst: AugmentedError<ApiType>;
+      NoAvailableBaseId: AugmentedError<ApiType>;
+      NoAvailablePartId: AugmentedError<ApiType>;
+      PermissionError: AugmentedError<ApiType>;
+      /**
+       * Generic error
+       **/
+      [key: string]: AugmentedError<ApiType>;
+    };
     structure: {
       /**
        * While searched for owner, encountered depth limit
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -396,6 +396,27 @@
        **/
       [key: string]: AugmentedEvent<ApiType>;
     };
+    rmrkCore: {
+      CollectionCreated: AugmentedEvent<ApiType, [AccountId32, u32]>;
+      CollectionDestroyed: AugmentedEvent<ApiType, [AccountId32, u32]>;
+      CollectionLocked: AugmentedEvent<ApiType, [AccountId32, u32]>;
+      IssuerChanged: AugmentedEvent<ApiType, [AccountId32, AccountId32, u32]>;
+      NFTBurned: AugmentedEvent<ApiType, [AccountId32, u32]>;
+      NftMinted: AugmentedEvent<ApiType, [AccountId32, u32, u32]>;
+      PropertySet: AugmentedEvent<ApiType, [u32, Option<u32>, Bytes, Bytes]>;
+      ResourceAdded: AugmentedEvent<ApiType, [u32, u32]>;
+      /**
+       * Generic event
+       **/
+      [key: string]: AugmentedEvent<ApiType>;
+    };
+    rmrkEquip: {
+      BaseCreated: AugmentedEvent<ApiType, [AccountId32, u32]>;
+      /**
+       * Generic event
+       **/
+      [key: string]: AugmentedEvent<ApiType>;
+    };
     structure: {
       /**
        * Executed call on behalf of token
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -415,6 +415,22 @@
        **/
       [key: string]: QueryableStorageEntry<ApiType>;
     };
+    rmrkCore: {
+      collectionIndex: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
+      collectionIndexMap: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+      /**
+       * Generic query
+       **/
+      [key: string]: QueryableStorageEntry<ApiType>;
+    };
+    rmrkEquip: {
+      baseHasDefaultTheme: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+      inernalPartId: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+      /**
+       * Generic query
+       **/
+      [key: string]: QueryableStorageEntry<ApiType>;
+    };
     structure: {
       /**
        * Generic query
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -22,7 +22,7 @@
 import type { StorageKind } from '@polkadot/types/interfaces/offchain';
 import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
 import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
-import type { AccountId, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';
+import type { AccountId, AccountId32, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';
 import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';
 import type { ApplyExtrinsicResult, ChainProperties, ChainType, Health, NetworkState, NodeRole, PeerInfo, SyncState } from '@polkadot/types/interfaces/system';
 import type { IExtrinsic, Observable } from '@polkadot/types/types';
@@ -397,6 +397,60 @@
        **/
       queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfo>>;
     };
+    rmrk: {
+      /**
+       * Get tokens owned by an account in a collection
+       **/
+      accountTokens: AugmentedRpc<(accountId: AccountId32 | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<u32>>>;
+      /**
+       * Get base info
+       **/
+      base: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsRmrkBaseInfo>>>;
+      /**
+       * Get all Base's parts
+       **/
+      baseParts: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsRmrkPartType>>>;
+      /**
+       * Get collection by id
+       **/
+      collectionById: AugmentedRpc<(id: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsRmrkCollectionInfo>>>;
+      /**
+       * Get collection properties
+       **/
+      collectionProperties: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, filterKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsRmrkPropertyInfo>>>;
+      /**
+       * Get the latest created collection id
+       **/
+      lastCollectionIdx: AugmentedRpc<(at?: Hash | string | Uint8Array) => Observable<u32>>;
+      /**
+       * Get NFT by collection id and NFT id
+       **/
+      nftById: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsRmrkNftInfo>>>;
+      /**
+       * Get NFT children
+       **/
+      nftChildren: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsRmrkNftChild>>>;
+      /**
+       * Get NFT properties
+       **/
+      nftProperties: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, filterKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsRmrkPropertyInfo>>>;
+      /**
+       * Get NFT resource priorities
+       **/
+      nftResourcePriorities: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<Bytes>>>;
+      /**
+       * Get NFT resources
+       **/
+      nftResources: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsRmrkResourceInfo>>>;
+      /**
+       * Get Base's theme names
+       **/
+      themeNames: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<Bytes>>>;
+      /**
+       * Get Theme's keys values
+       **/
+      themes: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, themeName: Text | string, keys: Option<Vec<Text>> | null | object | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsRmrkTheme>>>;
+    };
     rpc: {
       /**
        * Retrieves the list of RPC methods that are exposed by the node
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -4,8 +4,8 @@
 import type { ApiTypes } from '@polkadot/api-base/types';
 import type { Bytes, Compact, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types-codec';
 import type { AnyNumber, IMethod, ITuple } from '@polkadot/types-codec/types';
-import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill } from '@polkadot/types/interfaces/runtime';
+import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRmrkBasicResource, UpDataStructsRmrkComposableResource, UpDataStructsRmrkPartType, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
 
 declare module '@polkadot/api-base/types/submittable' {
   export interface AugmentedSubmittables<ApiType extends ApiTypes> {
@@ -346,6 +346,30 @@
        **/
       [key: string]: SubmittableExtrinsicFunction<ApiType>;
     };
+    rmrkCore: {
+      addBasicResource: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resource: UpDataStructsRmrkBasicResource | { src?: any; metadata?: any; license?: any; thumb?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, UpDataStructsRmrkBasicResource]>;
+      addComposableResource: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resourceId: Bytes | string | Uint8Array, resource: UpDataStructsRmrkComposableResource | { parts?: any; base?: any; src?: any; metadata?: any; license?: any; thumb?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, Bytes, UpDataStructsRmrkComposableResource]>;
+      addSlotResource: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resource: UpDataStructsRmrkSlotResource | { base?: any; src?: any; metadata?: any; slot?: any; license?: any; thumb?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, UpDataStructsRmrkSlotResource]>;
+      burnNft: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
+      changeCollectionIssuer: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newIssuer: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, MultiAddress]>;
+      createCollection: AugmentedSubmittable<(metadata: Bytes | string | Uint8Array, max: Option<u32> | null | object | string | Uint8Array, symbol: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Bytes, Option<u32>, Bytes]>;
+      destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+      lockCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
+      mintNft: AugmentedSubmittable<(owner: AccountId32 | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, recipient: Option<AccountId32> | null | object | string | Uint8Array, royaltyAmount: Option<Permill> | null | object | string | Uint8Array, metadata: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32, u32, Option<AccountId32>, Option<Permill>, Bytes]>;
+      setProperty: AugmentedSubmittable<(rmrkCollectionId: Compact<u32> | AnyNumber | Uint8Array, maybeNftId: Option<u32> | null | object | string | Uint8Array, key: Bytes | string | Uint8Array, value: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Compact<u32>, Option<u32>, Bytes, Bytes]>;
+      /**
+       * Generic tx
+       **/
+      [key: string]: SubmittableExtrinsicFunction<ApiType>;
+    };
+    rmrkEquip: {
+      createBase: AugmentedSubmittable<(baseType: Bytes | string | Uint8Array, symbol: Bytes | string | Uint8Array, parts: Vec<UpDataStructsRmrkPartType> | (UpDataStructsRmrkPartType | { FixedPart: any } | { SlotPart: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Bytes, Bytes, Vec<UpDataStructsRmrkPartType>]>;
+      themeAdd: AugmentedSubmittable<(baseId: u32 | AnyNumber | Uint8Array, theme: UpDataStructsRmrkTheme | { name?: any; properties?: any; inherit?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsRmrkTheme]>;
+      /**
+       * Generic tx
+       **/
+      [key: string]: SubmittableExtrinsicFunction<ApiType>;
+    };
     structure: {
       /**
        * Generic tx
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -788,6 +788,12 @@
     PalletNonfungibleItemData: PalletNonfungibleItemData;
     PalletRefungibleError: PalletRefungibleError;
     PalletRefungibleItemData: PalletRefungibleItemData;
+    PalletRmrkCoreCall: PalletRmrkCoreCall;
+    PalletRmrkCoreError: PalletRmrkCoreError;
+    PalletRmrkCoreEvent: PalletRmrkCoreEvent;
+    PalletRmrkEquipCall: PalletRmrkEquipCall;
+    PalletRmrkEquipError: PalletRmrkEquipError;
+    PalletRmrkEquipEvent: PalletRmrkEquipEvent;
     PalletsOrigin: PalletsOrigin;
     PalletStorageMetadataLatest: PalletStorageMetadataLatest;
     PalletStorageMetadataV14: PalletStorageMetadataV14;
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1129,6 +1129,169 @@
   readonly constData: Bytes;
 }
 
+/** @name PalletRmrkCoreCall */
+export interface PalletRmrkCoreCall extends Enum {
+  readonly isCreateCollection: boolean;
+  readonly asCreateCollection: {
+    readonly metadata: Bytes;
+    readonly max: Option<u32>;
+    readonly symbol: Bytes;
+  } & Struct;
+  readonly isDestroyCollection: boolean;
+  readonly asDestroyCollection: {
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isChangeCollectionIssuer: boolean;
+  readonly asChangeCollectionIssuer: {
+    readonly collectionId: u32;
+    readonly newIssuer: MultiAddress;
+  } & Struct;
+  readonly isLockCollection: boolean;
+  readonly asLockCollection: {
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isMintNft: boolean;
+  readonly asMintNft: {
+    readonly owner: AccountId32;
+    readonly collectionId: u32;
+    readonly recipient: Option<AccountId32>;
+    readonly royaltyAmount: Option<Permill>;
+    readonly metadata: Bytes;
+  } & Struct;
+  readonly isBurnNft: boolean;
+  readonly asBurnNft: {
+    readonly collectionId: u32;
+    readonly nftId: u32;
+  } & Struct;
+  readonly isSetProperty: boolean;
+  readonly asSetProperty: {
+    readonly rmrkCollectionId: Compact<u32>;
+    readonly maybeNftId: Option<u32>;
+    readonly key: Bytes;
+    readonly value: Bytes;
+  } & Struct;
+  readonly isAddBasicResource: boolean;
+  readonly asAddBasicResource: {
+    readonly collectionId: u32;
+    readonly nftId: u32;
+    readonly resource: UpDataStructsRmrkBasicResource;
+  } & Struct;
+  readonly isAddComposableResource: boolean;
+  readonly asAddComposableResource: {
+    readonly collectionId: u32;
+    readonly nftId: u32;
+    readonly resourceId: Bytes;
+    readonly resource: UpDataStructsRmrkComposableResource;
+  } & Struct;
+  readonly isAddSlotResource: boolean;
+  readonly asAddSlotResource: {
+    readonly collectionId: u32;
+    readonly nftId: u32;
+    readonly resource: UpDataStructsRmrkSlotResource;
+  } & Struct;
+  readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'SetProperty' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource';
+}
+
+/** @name PalletRmrkCoreError */
+export interface PalletRmrkCoreError extends Enum {
+  readonly isCorruptedCollectionType: boolean;
+  readonly isNftTypeEncodeError: boolean;
+  readonly isRmrkPropertyKeyIsTooLong: boolean;
+  readonly isRmrkPropertyValueIsTooLong: boolean;
+  readonly isCollectionNotEmpty: boolean;
+  readonly isNoAvailableCollectionId: boolean;
+  readonly isNoAvailableNftId: boolean;
+  readonly isCollectionUnknown: boolean;
+  readonly isNoPermission: boolean;
+  readonly isCollectionFullOrLocked: boolean;
+  readonly type: 'CorruptedCollectionType' | 'NftTypeEncodeError' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'CollectionFullOrLocked';
+}
+
+/** @name PalletRmrkCoreEvent */
+export interface PalletRmrkCoreEvent extends Enum {
+  readonly isCollectionCreated: boolean;
+  readonly asCollectionCreated: {
+    readonly issuer: AccountId32;
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isCollectionDestroyed: boolean;
+  readonly asCollectionDestroyed: {
+    readonly issuer: AccountId32;
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isIssuerChanged: boolean;
+  readonly asIssuerChanged: {
+    readonly oldIssuer: AccountId32;
+    readonly newIssuer: AccountId32;
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isCollectionLocked: boolean;
+  readonly asCollectionLocked: {
+    readonly issuer: AccountId32;
+    readonly collectionId: u32;
+  } & Struct;
+  readonly isNftMinted: boolean;
+  readonly asNftMinted: {
+    readonly owner: AccountId32;
+    readonly collectionId: u32;
+    readonly nftId: u32;
+  } & Struct;
+  readonly isNftBurned: boolean;
+  readonly asNftBurned: {
+    readonly owner: AccountId32;
+    readonly nftId: u32;
+  } & Struct;
+  readonly isPropertySet: boolean;
+  readonly asPropertySet: {
+    readonly collectionId: u32;
+    readonly maybeNftId: Option<u32>;
+    readonly key: Bytes;
+    readonly value: Bytes;
+  } & Struct;
+  readonly isResourceAdded: boolean;
+  readonly asResourceAdded: {
+    readonly nftId: u32;
+    readonly resourceId: u32;
+  } & Struct;
+  readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'PropertySet' | 'ResourceAdded';
+}
+
+/** @name PalletRmrkEquipCall */
+export interface PalletRmrkEquipCall extends Enum {
+  readonly isCreateBase: boolean;
+  readonly asCreateBase: {
+    readonly baseType: Bytes;
+    readonly symbol: Bytes;
+    readonly parts: Vec<UpDataStructsRmrkPartType>;
+  } & Struct;
+  readonly isThemeAdd: boolean;
+  readonly asThemeAdd: {
+    readonly baseId: u32;
+    readonly theme: UpDataStructsRmrkTheme;
+  } & Struct;
+  readonly type: 'CreateBase' | 'ThemeAdd';
+}
+
+/** @name PalletRmrkEquipError */
+export interface PalletRmrkEquipError extends Enum {
+  readonly isPermissionError: boolean;
+  readonly isNoAvailableBaseId: boolean;
+  readonly isNoAvailablePartId: boolean;
+  readonly isBaseDoesntExist: boolean;
+  readonly isNeedsDefaultThemeFirst: boolean;
+  readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst';
+}
+
+/** @name PalletRmrkEquipEvent */
+export interface PalletRmrkEquipEvent extends Enum {
+  readonly isBaseCreated: boolean;
+  readonly asBaseCreated: {
+    readonly issuer: AccountId32;
+    readonly baseId: u32;
+  } & Struct;
+  readonly type: 'BaseCreated';
+}
+
 /** @name PalletStructureCall */
 export interface PalletStructureCall extends Null {}
 
@@ -2014,7 +2177,7 @@
 
 /** @name UpDataStructsRmrkResourceInfo */
 export interface UpDataStructsRmrkResourceInfo extends Struct {
-  readonly id: Bytes;
+  readonly id: u32;
   readonly resource: UpDataStructsRmrkResourceTypes;
   readonly pending: bool;
   readonly pendingRemoval: bool;
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1528,8 +1528,161 @@
    **/
   PalletStructureCall: 'Null',
   /**
-   * Lookup206: pallet_evm::pallet::Call<T>
+   * Lookup206: pallet_rmrk_core::pallet::Call<T>
+   **/
+  PalletRmrkCoreCall: {
+    _enum: {
+      create_collection: {
+        metadata: 'Bytes',
+        max: 'Option<u32>',
+        symbol: 'Bytes',
+      },
+      destroy_collection: {
+        collectionId: 'u32',
+      },
+      change_collection_issuer: {
+        collectionId: 'u32',
+        newIssuer: 'MultiAddress',
+      },
+      lock_collection: {
+        collectionId: 'u32',
+      },
+      mint_nft: {
+        owner: 'AccountId32',
+        collectionId: 'u32',
+        recipient: 'Option<AccountId32>',
+        royaltyAmount: 'Option<Permill>',
+        metadata: 'Bytes',
+      },
+      burn_nft: {
+        collectionId: 'u32',
+        nftId: 'u32',
+      },
+      set_property: {
+        rmrkCollectionId: 'Compact<u32>',
+        maybeNftId: 'Option<u32>',
+        key: 'Bytes',
+        value: 'Bytes',
+      },
+      add_basic_resource: {
+        collectionId: 'u32',
+        nftId: 'u32',
+        resource: 'UpDataStructsRmrkBasicResource',
+      },
+      add_composable_resource: {
+        collectionId: 'u32',
+        nftId: 'u32',
+        resourceId: 'Bytes',
+        resource: 'UpDataStructsRmrkComposableResource',
+      },
+      add_slot_resource: {
+        collectionId: 'u32',
+        nftId: 'u32',
+        resource: 'UpDataStructsRmrkSlotResource'
+      }
+    }
+  },
+  /**
+   * Lookup212: up_data_structs::rmrk::BasicResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkBasicResource: {
+    src: 'Option<Bytes>',
+    metadata: 'Option<Bytes>',
+    license: 'Option<Bytes>',
+    thumb: 'Option<Bytes>'
+  },
+  /**
+   * Lookup215: up_data_structs::rmrk::ComposableResource<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkComposableResource: {
+    parts: 'Vec<u32>',
+    base: 'u32',
+    src: 'Option<Bytes>',
+    metadata: 'Option<Bytes>',
+    license: 'Option<Bytes>',
+    thumb: 'Option<Bytes>'
+  },
+  /**
+   * Lookup217: up_data_structs::rmrk::SlotResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkSlotResource: {
+    base: 'u32',
+    src: 'Option<Bytes>',
+    metadata: 'Option<Bytes>',
+    slot: 'u32',
+    license: 'Option<Bytes>',
+    thumb: 'Option<Bytes>'
+  },
+  /**
+   * Lookup218: pallet_rmrk_equip::pallet::Call<T>
+   **/
+  PalletRmrkEquipCall: {
+    _enum: {
+      create_base: {
+        baseType: 'Bytes',
+        symbol: 'Bytes',
+        parts: 'Vec<UpDataStructsRmrkPartType>',
+      },
+      theme_add: {
+        baseId: 'u32',
+        theme: 'UpDataStructsRmrkTheme'
+      }
+    }
+  },
+  /**
+   * Lookup220: up_data_structs::rmrk::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
+  UpDataStructsRmrkPartType: {
+    _enum: {
+      FixedPart: 'UpDataStructsRmrkFixedPart',
+      SlotPart: 'UpDataStructsRmrkSlotPart'
+    }
+  },
+  /**
+   * Lookup222: up_data_structs::rmrk::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkFixedPart: {
+    id: 'u32',
+    z: 'u32',
+    src: 'Bytes'
+  },
+  /**
+   * Lookup223: up_data_structs::rmrk::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkSlotPart: {
+    id: 'u32',
+    equippable: 'UpDataStructsRmrkEquippableList',
+    src: 'Bytes',
+    z: 'u32'
+  },
+  /**
+   * Lookup224: up_data_structs::rmrk::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkEquippableList: {
+    _enum: {
+      All: 'Null',
+      Empty: 'Null',
+      Custom: 'Vec<u32>'
+    }
+  },
+  /**
+   * Lookup226: up_data_structs::rmrk::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, PropertyList>
+   **/
+  UpDataStructsRmrkTheme: {
+    name: 'Bytes',
+    properties: 'Vec<UpDataStructsRmrkThemeProperty>',
+    inherit: 'bool'
+  },
+  /**
+   * Lookup228: up_data_structs::rmrk::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   **/
+  UpDataStructsRmrkThemeProperty: {
+    key: 'Bytes',
+    value: 'Bytes'
+  },
+  /**
+   * Lookup229: pallet_evm::pallet::Call<T>
+   **/
   PalletEvmCall: {
     _enum: {
       withdraw: {
@@ -1571,7 +1724,7 @@
     }
   },
   /**
-   * Lookup212: pallet_ethereum::pallet::Call<T>
+   * Lookup235: pallet_ethereum::pallet::Call<T>
    **/
   PalletEthereumCall: {
     _enum: {
@@ -1581,7 +1734,7 @@
     }
   },
   /**
-   * Lookup213: ethereum::transaction::TransactionV2
+   * Lookup236: ethereum::transaction::TransactionV2
    **/
   EthereumTransactionTransactionV2: {
     _enum: {
@@ -1591,7 +1744,7 @@
     }
   },
   /**
-   * Lookup214: ethereum::transaction::LegacyTransaction
+   * Lookup237: ethereum::transaction::LegacyTransaction
    **/
   EthereumTransactionLegacyTransaction: {
     nonce: 'U256',
@@ -1603,7 +1756,7 @@
     signature: 'EthereumTransactionTransactionSignature'
   },
   /**
-   * Lookup215: ethereum::transaction::TransactionAction
+   * Lookup238: ethereum::transaction::TransactionAction
    **/
   EthereumTransactionTransactionAction: {
     _enum: {
@@ -1612,7 +1765,7 @@
     }
   },
   /**
-   * Lookup216: ethereum::transaction::TransactionSignature
+   * Lookup239: ethereum::transaction::TransactionSignature
    **/
   EthereumTransactionTransactionSignature: {
     v: 'u64',
@@ -1620,7 +1773,7 @@
     s: 'H256'
   },
   /**
-   * Lookup218: ethereum::transaction::EIP2930Transaction
+   * Lookup241: ethereum::transaction::EIP2930Transaction
    **/
   EthereumTransactionEip2930Transaction: {
     chainId: 'u64',
@@ -1636,14 +1789,14 @@
     s: 'H256'
   },
   /**
-   * Lookup220: ethereum::transaction::AccessListItem
+   * Lookup243: ethereum::transaction::AccessListItem
    **/
   EthereumTransactionAccessListItem: {
     address: 'H160',
     storageKeys: 'Vec<H256>'
   },
   /**
-   * Lookup221: ethereum::transaction::EIP1559Transaction
+   * Lookup244: ethereum::transaction::EIP1559Transaction
    **/
   EthereumTransactionEip1559Transaction: {
     chainId: 'u64',
@@ -1660,7 +1813,7 @@
     s: 'H256'
   },
   /**
-   * Lookup222: pallet_evm_migration::pallet::Call<T>
+   * Lookup245: pallet_evm_migration::pallet::Call<T>
    **/
   PalletEvmMigrationCall: {
     _enum: {
@@ -1678,7 +1831,7 @@
     }
   },
   /**
-   * Lookup225: pallet_sudo::pallet::Event<T>
+   * Lookup248: pallet_sudo::pallet::Event<T>
    **/
   PalletSudoEvent: {
     _enum: {
@@ -1694,7 +1847,7 @@
     }
   },
   /**
-   * Lookup227: sp_runtime::DispatchError
+   * Lookup250: sp_runtime::DispatchError
    **/
   SpRuntimeDispatchError: {
     _enum: {
@@ -1711,38 +1864,38 @@
     }
   },
   /**
-   * Lookup228: sp_runtime::ModuleError
+   * Lookup251: sp_runtime::ModuleError
    **/
   SpRuntimeModuleError: {
     index: 'u8',
     error: '[u8;4]'
   },
   /**
-   * Lookup229: sp_runtime::TokenError
+   * Lookup252: sp_runtime::TokenError
    **/
   SpRuntimeTokenError: {
     _enum: ['NoFunds', 'WouldDie', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported']
   },
   /**
-   * Lookup230: sp_runtime::ArithmeticError
+   * Lookup253: sp_runtime::ArithmeticError
    **/
   SpRuntimeArithmeticError: {
     _enum: ['Underflow', 'Overflow', 'DivisionByZero']
   },
   /**
-   * Lookup231: sp_runtime::TransactionalError
+   * Lookup254: sp_runtime::TransactionalError
    **/
   SpRuntimeTransactionalError: {
     _enum: ['LimitReached', 'NoLayer']
   },
   /**
-   * Lookup232: pallet_sudo::pallet::Error<T>
+   * Lookup255: pallet_sudo::pallet::Error<T>
    **/
   PalletSudoError: {
     _enum: ['RequireSudo']
   },
   /**
-   * Lookup233: frame_system::AccountInfo<Index, pallet_balances::AccountData<Balance>>
+   * Lookup256: frame_system::AccountInfo<Index, pallet_balances::AccountData<Balance>>
    **/
   FrameSystemAccountInfo: {
     nonce: 'u32',
@@ -1752,7 +1905,7 @@
     data: 'PalletBalancesAccountData'
   },
   /**
-   * Lookup234: frame_support::weights::PerDispatchClass<T>
+   * Lookup257: frame_support::weights::PerDispatchClass<T>
    **/
   FrameSupportWeightsPerDispatchClassU64: {
     normal: 'u64',
@@ -1760,13 +1913,13 @@
     mandatory: 'u64'
   },
   /**
-   * Lookup235: sp_runtime::generic::digest::Digest
+   * Lookup258: sp_runtime::generic::digest::Digest
    **/
   SpRuntimeDigest: {
     logs: 'Vec<SpRuntimeDigestDigestItem>'
   },
   /**
-   * Lookup237: sp_runtime::generic::digest::DigestItem
+   * Lookup260: sp_runtime::generic::digest::DigestItem
    **/
   SpRuntimeDigestDigestItem: {
     _enum: {
@@ -1782,7 +1935,7 @@
     }
   },
   /**
-   * Lookup239: frame_system::EventRecord<opal_runtime::Event, primitive_types::H256>
+   * Lookup262: frame_system::EventRecord<opal_runtime::Event, primitive_types::H256>
    **/
   FrameSystemEventRecord: {
     phase: 'FrameSystemPhase',
@@ -1790,7 +1943,7 @@
     topics: 'Vec<H256>'
   },
   /**
-   * Lookup241: frame_system::pallet::Event<T>
+   * Lookup264: frame_system::pallet::Event<T>
    **/
   FrameSystemEvent: {
     _enum: {
@@ -1818,7 +1971,7 @@
     }
   },
   /**
-   * Lookup242: frame_support::weights::DispatchInfo
+   * Lookup265: frame_support::weights::DispatchInfo
    **/
   FrameSupportWeightsDispatchInfo: {
     weight: 'u64',
@@ -1826,19 +1979,19 @@
     paysFee: 'FrameSupportWeightsPays'
   },
   /**
-   * Lookup243: frame_support::weights::DispatchClass
+   * Lookup266: frame_support::weights::DispatchClass
    **/
   FrameSupportWeightsDispatchClass: {
     _enum: ['Normal', 'Operational', 'Mandatory']
   },
   /**
-   * Lookup244: frame_support::weights::Pays
+   * Lookup267: frame_support::weights::Pays
    **/
   FrameSupportWeightsPays: {
     _enum: ['Yes', 'No']
   },
   /**
-   * Lookup245: orml_vesting::module::Event<T>
+   * Lookup268: orml_vesting::module::Event<T>
    **/
   OrmlVestingModuleEvent: {
     _enum: {
@@ -1857,7 +2010,7 @@
     }
   },
   /**
-   * Lookup246: cumulus_pallet_xcmp_queue::pallet::Event<T>
+   * Lookup269: cumulus_pallet_xcmp_queue::pallet::Event<T>
    **/
   CumulusPalletXcmpQueueEvent: {
     _enum: {
@@ -1872,7 +2025,7 @@
     }
   },
   /**
-   * Lookup247: pallet_xcm::pallet::Event<T>
+   * Lookup270: pallet_xcm::pallet::Event<T>
    **/
   PalletXcmEvent: {
     _enum: {
@@ -1895,7 +2048,7 @@
     }
   },
   /**
-   * Lookup248: xcm::v2::traits::Outcome
+   * Lookup271: xcm::v2::traits::Outcome
    **/
   XcmV2TraitsOutcome: {
     _enum: {
@@ -1905,7 +2058,7 @@
     }
   },
   /**
-   * Lookup250: cumulus_pallet_xcm::pallet::Event<T>
+   * Lookup273: cumulus_pallet_xcm::pallet::Event<T>
    **/
   CumulusPalletXcmEvent: {
     _enum: {
@@ -1915,7 +2068,7 @@
     }
   },
   /**
-   * Lookup251: cumulus_pallet_dmp_queue::pallet::Event<T>
+   * Lookup274: cumulus_pallet_dmp_queue::pallet::Event<T>
    **/
   CumulusPalletDmpQueueEvent: {
     _enum: {
@@ -1928,7 +2081,7 @@
     }
   },
   /**
-   * Lookup252: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup275: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   PalletUniqueRawEvent: {
     _enum: {
@@ -1945,7 +2098,7 @@
     }
   },
   /**
-   * Lookup253: pallet_common::pallet::Event<T>
+   * Lookup276: pallet_common::pallet::Event<T>
    **/
   PalletCommonEvent: {
     _enum: {
@@ -1963,7 +2116,7 @@
     }
   },
   /**
-   * Lookup254: pallet_structure::pallet::Event<T>
+   * Lookup277: pallet_structure::pallet::Event<T>
    **/
   PalletStructureEvent: {
     _enum: {
@@ -1971,8 +2124,62 @@
     }
   },
   /**
-   * Lookup255: pallet_evm::pallet::Event<T>
+   * Lookup278: pallet_rmrk_core::pallet::Event<T>
    **/
+  PalletRmrkCoreEvent: {
+    _enum: {
+      CollectionCreated: {
+        issuer: 'AccountId32',
+        collectionId: 'u32',
+      },
+      CollectionDestroyed: {
+        issuer: 'AccountId32',
+        collectionId: 'u32',
+      },
+      IssuerChanged: {
+        oldIssuer: 'AccountId32',
+        newIssuer: 'AccountId32',
+        collectionId: 'u32',
+      },
+      CollectionLocked: {
+        issuer: 'AccountId32',
+        collectionId: 'u32',
+      },
+      NftMinted: {
+        owner: 'AccountId32',
+        collectionId: 'u32',
+        nftId: 'u32',
+      },
+      NFTBurned: {
+        owner: 'AccountId32',
+        nftId: 'u32',
+      },
+      PropertySet: {
+        collectionId: 'u32',
+        maybeNftId: 'Option<u32>',
+        key: 'Bytes',
+        value: 'Bytes',
+      },
+      ResourceAdded: {
+        nftId: 'u32',
+        resourceId: 'u32'
+      }
+    }
+  },
+  /**
+   * Lookup279: pallet_rmrk_equip::pallet::Event<T>
+   **/
+  PalletRmrkEquipEvent: {
+    _enum: {
+      BaseCreated: {
+        issuer: 'AccountId32',
+        baseId: 'u32'
+      }
+    }
+  },
+  /**
+   * Lookup280: pallet_evm::pallet::Event<T>
+   **/
   PalletEvmEvent: {
     _enum: {
       Log: 'EthereumLog',
@@ -1985,7 +2192,7 @@
     }
   },
   /**
-   * Lookup256: ethereum::log::Log
+   * Lookup281: ethereum::log::Log
    **/
   EthereumLog: {
     address: 'H160',
@@ -1993,7 +2200,7 @@
     data: 'Bytes'
   },
   /**
-   * Lookup257: pallet_ethereum::pallet::Event
+   * Lookup282: pallet_ethereum::pallet::Event
    **/
   PalletEthereumEvent: {
     _enum: {
@@ -2001,7 +2208,7 @@
     }
   },
   /**
-   * Lookup258: evm_core::error::ExitReason
+   * Lookup283: evm_core::error::ExitReason
    **/
   EvmCoreErrorExitReason: {
     _enum: {
@@ -2012,13 +2219,13 @@
     }
   },
   /**
-   * Lookup259: evm_core::error::ExitSucceed
+   * Lookup284: evm_core::error::ExitSucceed
    **/
   EvmCoreErrorExitSucceed: {
     _enum: ['Stopped', 'Returned', 'Suicided']
   },
   /**
-   * Lookup260: evm_core::error::ExitError
+   * Lookup285: evm_core::error::ExitError
    **/
   EvmCoreErrorExitError: {
     _enum: {
@@ -2040,13 +2247,13 @@
     }
   },
   /**
-   * Lookup263: evm_core::error::ExitRevert
+   * Lookup288: evm_core::error::ExitRevert
    **/
   EvmCoreErrorExitRevert: {
     _enum: ['Reverted']
   },
   /**
-   * Lookup264: evm_core::error::ExitFatal
+   * Lookup289: evm_core::error::ExitFatal
    **/
   EvmCoreErrorExitFatal: {
     _enum: {
@@ -2057,7 +2264,7 @@
     }
   },
   /**
-   * Lookup265: frame_system::Phase
+   * Lookup290: frame_system::Phase
    **/
   FrameSystemPhase: {
     _enum: {
@@ -2067,14 +2274,14 @@
     }
   },
   /**
-   * Lookup267: frame_system::LastRuntimeUpgradeInfo
+   * Lookup292: frame_system::LastRuntimeUpgradeInfo
    **/
   FrameSystemLastRuntimeUpgradeInfo: {
     specVersion: 'Compact<u32>',
     specName: 'Text'
   },
   /**
-   * Lookup268: frame_system::limits::BlockWeights
+   * Lookup293: frame_system::limits::BlockWeights
    **/
   FrameSystemLimitsBlockWeights: {
     baseBlock: 'u64',
@@ -2082,7 +2289,7 @@
     perClass: 'FrameSupportWeightsPerDispatchClassWeightsPerClass'
   },
   /**
-   * Lookup269: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>
+   * Lookup294: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>
    **/
   FrameSupportWeightsPerDispatchClassWeightsPerClass: {
     normal: 'FrameSystemLimitsWeightsPerClass',
@@ -2090,7 +2297,7 @@
     mandatory: 'FrameSystemLimitsWeightsPerClass'
   },
   /**
-   * Lookup270: frame_system::limits::WeightsPerClass
+   * Lookup295: frame_system::limits::WeightsPerClass
    **/
   FrameSystemLimitsWeightsPerClass: {
     baseExtrinsic: 'u64',
@@ -2099,13 +2306,13 @@
     reserved: 'Option<u64>'
   },
   /**
-   * Lookup272: frame_system::limits::BlockLength
+   * Lookup297: frame_system::limits::BlockLength
    **/
   FrameSystemLimitsBlockLength: {
     max: 'FrameSupportWeightsPerDispatchClassU32'
   },
   /**
-   * Lookup273: frame_support::weights::PerDispatchClass<T>
+   * Lookup298: frame_support::weights::PerDispatchClass<T>
    **/
   FrameSupportWeightsPerDispatchClassU32: {
     normal: 'u32',
@@ -2113,14 +2320,14 @@
     mandatory: 'u32'
   },
   /**
-   * Lookup274: frame_support::weights::RuntimeDbWeight
+   * Lookup299: frame_support::weights::RuntimeDbWeight
    **/
   FrameSupportWeightsRuntimeDbWeight: {
     read: 'u64',
     write: 'u64'
   },
   /**
-   * Lookup275: sp_version::RuntimeVersion
+   * Lookup300: sp_version::RuntimeVersion
    **/
   SpVersionRuntimeVersion: {
     specName: 'Text',
@@ -2133,19 +2340,19 @@
     stateVersion: 'u8'
   },
   /**
-   * Lookup279: frame_system::pallet::Error<T>
+   * Lookup304: frame_system::pallet::Error<T>
    **/
   FrameSystemError: {
     _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
   },
   /**
-   * Lookup281: orml_vesting::module::Error<T>
+   * Lookup306: orml_vesting::module::Error<T>
    **/
   OrmlVestingModuleError: {
     _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
   },
   /**
-   * Lookup283: cumulus_pallet_xcmp_queue::InboundChannelDetails
+   * Lookup308: cumulus_pallet_xcmp_queue::InboundChannelDetails
    **/
   CumulusPalletXcmpQueueInboundChannelDetails: {
     sender: 'u32',
@@ -2153,19 +2360,19 @@
     messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'
   },
   /**
-   * Lookup284: cumulus_pallet_xcmp_queue::InboundState
+   * Lookup309: cumulus_pallet_xcmp_queue::InboundState
    **/
   CumulusPalletXcmpQueueInboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup287: polkadot_parachain::primitives::XcmpMessageFormat
+   * Lookup312: polkadot_parachain::primitives::XcmpMessageFormat
    **/
   PolkadotParachainPrimitivesXcmpMessageFormat: {
     _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
   },
   /**
-   * Lookup290: cumulus_pallet_xcmp_queue::OutboundChannelDetails
+   * Lookup315: cumulus_pallet_xcmp_queue::OutboundChannelDetails
    **/
   CumulusPalletXcmpQueueOutboundChannelDetails: {
     recipient: 'u32',
@@ -2175,13 +2382,13 @@
     lastIndex: 'u16'
   },
   /**
-   * Lookup291: cumulus_pallet_xcmp_queue::OutboundState
+   * Lookup316: cumulus_pallet_xcmp_queue::OutboundState
    **/
   CumulusPalletXcmpQueueOutboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup293: cumulus_pallet_xcmp_queue::QueueConfigData
+   * Lookup318: cumulus_pallet_xcmp_queue::QueueConfigData
    **/
   CumulusPalletXcmpQueueQueueConfigData: {
     suspendThreshold: 'u32',
@@ -2192,29 +2399,29 @@
     xcmpMaxIndividualWeight: 'u64'
   },
   /**
-   * Lookup295: cumulus_pallet_xcmp_queue::pallet::Error<T>
+   * Lookup320: cumulus_pallet_xcmp_queue::pallet::Error<T>
    **/
   CumulusPalletXcmpQueueError: {
     _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
   },
   /**
-   * Lookup296: pallet_xcm::pallet::Error<T>
+   * Lookup321: pallet_xcm::pallet::Error<T>
    **/
   PalletXcmError: {
     _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']
   },
   /**
-   * Lookup297: cumulus_pallet_xcm::pallet::Error<T>
+   * Lookup322: cumulus_pallet_xcm::pallet::Error<T>
    **/
   CumulusPalletXcmError: 'Null',
   /**
-   * Lookup298: cumulus_pallet_dmp_queue::ConfigData
+   * Lookup323: cumulus_pallet_dmp_queue::ConfigData
    **/
   CumulusPalletDmpQueueConfigData: {
     maxIndividual: 'u64'
   },
   /**
-   * Lookup299: cumulus_pallet_dmp_queue::PageIndexData
+   * Lookup324: cumulus_pallet_dmp_queue::PageIndexData
    **/
   CumulusPalletDmpQueuePageIndexData: {
     beginUsed: 'u32',
@@ -2222,19 +2429,19 @@
     overweightCount: 'u64'
   },
   /**
-   * Lookup302: cumulus_pallet_dmp_queue::pallet::Error<T>
+   * Lookup327: cumulus_pallet_dmp_queue::pallet::Error<T>
    **/
   CumulusPalletDmpQueueError: {
     _enum: ['Unknown', 'OverLimit']
   },
   /**
-   * Lookup306: pallet_unique::Error<T>
+   * Lookup331: pallet_unique::Error<T>
    **/
   PalletUniqueError: {
     _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument']
   },
   /**
-   * Lookup307: up_data_structs::Collection<sp_core::crypto::AccountId32>
+   * Lookup332: up_data_structs::Collection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsCollection: {
     owner: 'AccountId32',
@@ -2247,7 +2454,7 @@
     permissions: 'UpDataStructsCollectionPermissions'
   },
   /**
-   * Lookup308: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
+   * Lookup333: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
    **/
   UpDataStructsSponsorshipState: {
     _enum: {
@@ -2257,7 +2464,7 @@
     }
   },
   /**
-   * Lookup309: up_data_structs::Properties
+   * Lookup334: up_data_structs::Properties
    **/
   UpDataStructsProperties: {
     map: 'UpDataStructsPropertiesMapBoundedVec',
@@ -2265,15 +2472,15 @@
     spaceLimit: 'u32'
   },
   /**
-   * Lookup310: up_data_structs::PropertiesMap<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup335: up_data_structs::PropertiesMap<frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
   /**
-   * Lookup315: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
+   * Lookup340: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
    **/
   UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
   /**
-   * Lookup322: up_data_structs::CollectionStats
+   * Lookup347: up_data_structs::CollectionStats
    **/
   UpDataStructsCollectionStats: {
     created: 'u32',
@@ -2353,7 +2560,7 @@
    * Lookup336: up_data_structs::rmrk::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   UpDataStructsRmrkResourceInfo: {
-    id: 'Bytes',
+    id: 'u32',
     resource: 'UpDataStructsRmrkResourceTypes',
     pending: 'bool',
     pendingRemoval: 'bool'
modifiedtests/src/interfaces/registry.tsdiffbeforeafterboth
--- a/tests/src/interfaces/registry.ts
+++ b/tests/src/interfaces/registry.ts
@@ -104,6 +104,12 @@
     PalletNonfungibleItemData: PalletNonfungibleItemData;
     PalletRefungibleError: PalletRefungibleError;
     PalletRefungibleItemData: PalletRefungibleItemData;
+    PalletRmrkCoreCall: PalletRmrkCoreCall;
+    PalletRmrkCoreError: PalletRmrkCoreError;
+    PalletRmrkCoreEvent: PalletRmrkCoreEvent;
+    PalletRmrkEquipCall: PalletRmrkEquipCall;
+    PalletRmrkEquipError: PalletRmrkEquipError;
+    PalletRmrkEquipEvent: PalletRmrkEquipEvent;
     PalletStructureCall: PalletStructureCall;
     PalletStructureError: PalletStructureError;
     PalletStructureEvent: PalletStructureEvent;
modifiedtests/src/interfaces/rmrk/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/rmrk/definitions.ts
+++ b/tests/src/interfaces/rmrk/definitions.ts
@@ -58,7 +58,10 @@
     ),
     collectionProperties: fn(
       'Get collection properties',
-      [{name: 'collectionId', type: 'u32'}],
+      [
+        {name: 'collectionId', type: 'u32'},
+        {name: 'filterKeys', type: 'Vec<String>', isOptional: true},
+      ],
       'Vec<UpDataStructsRmrkPropertyInfo>',
     ),
     nftProperties: fn(
@@ -66,6 +69,7 @@
       [
         {name: 'collectionId', type: 'u32'},
         {name: 'nftId', type: 'u32'},
+        {name: 'filterKeys', type: 'Vec<String>', isOptional: true},
       ],
       'Vec<UpDataStructsRmrkPropertyInfo>',
     ),
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1649,7 +1649,160 @@
   /** @name PalletStructureCall (205) */
   export type PalletStructureCall = Null;
 
-  /** @name PalletEvmCall (206) */
+  /** @name PalletRmrkCoreCall (206) */
+  export interface PalletRmrkCoreCall extends Enum {
+    readonly isCreateCollection: boolean;
+    readonly asCreateCollection: {
+      readonly metadata: Bytes;
+      readonly max: Option<u32>;
+      readonly symbol: Bytes;
+    } & Struct;
+    readonly isDestroyCollection: boolean;
+    readonly asDestroyCollection: {
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isChangeCollectionIssuer: boolean;
+    readonly asChangeCollectionIssuer: {
+      readonly collectionId: u32;
+      readonly newIssuer: MultiAddress;
+    } & Struct;
+    readonly isLockCollection: boolean;
+    readonly asLockCollection: {
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isMintNft: boolean;
+    readonly asMintNft: {
+      readonly owner: AccountId32;
+      readonly collectionId: u32;
+      readonly recipient: Option<AccountId32>;
+      readonly royaltyAmount: Option<Permill>;
+      readonly metadata: Bytes;
+    } & Struct;
+    readonly isBurnNft: boolean;
+    readonly asBurnNft: {
+      readonly collectionId: u32;
+      readonly nftId: u32;
+    } & Struct;
+    readonly isSetProperty: boolean;
+    readonly asSetProperty: {
+      readonly rmrkCollectionId: Compact<u32>;
+      readonly maybeNftId: Option<u32>;
+      readonly key: Bytes;
+      readonly value: Bytes;
+    } & Struct;
+    readonly isAddBasicResource: boolean;
+    readonly asAddBasicResource: {
+      readonly collectionId: u32;
+      readonly nftId: u32;
+      readonly resource: UpDataStructsRmrkBasicResource;
+    } & Struct;
+    readonly isAddComposableResource: boolean;
+    readonly asAddComposableResource: {
+      readonly collectionId: u32;
+      readonly nftId: u32;
+      readonly resourceId: Bytes;
+      readonly resource: UpDataStructsRmrkComposableResource;
+    } & Struct;
+    readonly isAddSlotResource: boolean;
+    readonly asAddSlotResource: {
+      readonly collectionId: u32;
+      readonly nftId: u32;
+      readonly resource: UpDataStructsRmrkSlotResource;
+    } & Struct;
+    readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'SetProperty' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource';
+  }
+
+  /** @name UpDataStructsRmrkBasicResource (212) */
+  export interface UpDataStructsRmrkBasicResource extends Struct {
+    readonly src: Option<Bytes>;
+    readonly metadata: Option<Bytes>;
+    readonly license: Option<Bytes>;
+    readonly thumb: Option<Bytes>;
+  }
+
+  /** @name UpDataStructsRmrkComposableResource (215) */
+  export interface UpDataStructsRmrkComposableResource extends Struct {
+    readonly parts: Vec<u32>;
+    readonly base: u32;
+    readonly src: Option<Bytes>;
+    readonly metadata: Option<Bytes>;
+    readonly license: Option<Bytes>;
+    readonly thumb: Option<Bytes>;
+  }
+
+  /** @name UpDataStructsRmrkSlotResource (217) */
+  export interface UpDataStructsRmrkSlotResource extends Struct {
+    readonly base: u32;
+    readonly src: Option<Bytes>;
+    readonly metadata: Option<Bytes>;
+    readonly slot: u32;
+    readonly license: Option<Bytes>;
+    readonly thumb: Option<Bytes>;
+  }
+
+  /** @name PalletRmrkEquipCall (218) */
+  export interface PalletRmrkEquipCall extends Enum {
+    readonly isCreateBase: boolean;
+    readonly asCreateBase: {
+      readonly baseType: Bytes;
+      readonly symbol: Bytes;
+      readonly parts: Vec<UpDataStructsRmrkPartType>;
+    } & Struct;
+    readonly isThemeAdd: boolean;
+    readonly asThemeAdd: {
+      readonly baseId: u32;
+      readonly theme: UpDataStructsRmrkTheme;
+    } & Struct;
+    readonly type: 'CreateBase' | 'ThemeAdd';
+  }
+
+  /** @name UpDataStructsRmrkPartType (220) */
+  export interface UpDataStructsRmrkPartType extends Enum {
+    readonly isFixedPart: boolean;
+    readonly asFixedPart: UpDataStructsRmrkFixedPart;
+    readonly isSlotPart: boolean;
+    readonly asSlotPart: UpDataStructsRmrkSlotPart;
+    readonly type: 'FixedPart' | 'SlotPart';
+  }
+
+  /** @name UpDataStructsRmrkFixedPart (222) */
+  export interface UpDataStructsRmrkFixedPart extends Struct {
+    readonly id: u32;
+    readonly z: u32;
+    readonly src: Bytes;
+  }
+
+  /** @name UpDataStructsRmrkSlotPart (223) */
+  export interface UpDataStructsRmrkSlotPart extends Struct {
+    readonly id: u32;
+    readonly equippable: UpDataStructsRmrkEquippableList;
+    readonly src: Bytes;
+    readonly z: u32;
+  }
+
+  /** @name UpDataStructsRmrkEquippableList (224) */
+  export interface UpDataStructsRmrkEquippableList extends Enum {
+    readonly isAll: boolean;
+    readonly isEmpty: boolean;
+    readonly isCustom: boolean;
+    readonly asCustom: Vec<u32>;
+    readonly type: 'All' | 'Empty' | 'Custom';
+  }
+
+  /** @name UpDataStructsRmrkTheme (226) */
+  export interface UpDataStructsRmrkTheme extends Struct {
+    readonly name: Bytes;
+    readonly properties: Vec<UpDataStructsRmrkThemeProperty>;
+    readonly inherit: bool;
+  }
+
+  /** @name UpDataStructsRmrkThemeProperty (228) */
+  export interface UpDataStructsRmrkThemeProperty extends Struct {
+    readonly key: Bytes;
+    readonly value: Bytes;
+  }
+
+  /** @name PalletEvmCall (229) */
   export interface PalletEvmCall extends Enum {
     readonly isWithdraw: boolean;
     readonly asWithdraw: {
@@ -1694,7 +1847,7 @@
     readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
   }
 
-  /** @name PalletEthereumCall (212) */
+  /** @name PalletEthereumCall (235) */
   export interface PalletEthereumCall extends Enum {
     readonly isTransact: boolean;
     readonly asTransact: {
@@ -1703,7 +1856,7 @@
     readonly type: 'Transact';
   }
 
-  /** @name EthereumTransactionTransactionV2 (213) */
+  /** @name EthereumTransactionTransactionV2 (236) */
   export interface EthereumTransactionTransactionV2 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumTransactionLegacyTransaction;
@@ -1714,7 +1867,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumTransactionLegacyTransaction (214) */
+  /** @name EthereumTransactionLegacyTransaction (237) */
   export interface EthereumTransactionLegacyTransaction extends Struct {
     readonly nonce: U256;
     readonly gasPrice: U256;
@@ -1725,7 +1878,7 @@
     readonly signature: EthereumTransactionTransactionSignature;
   }
 
-  /** @name EthereumTransactionTransactionAction (215) */
+  /** @name EthereumTransactionTransactionAction (238) */
   export interface EthereumTransactionTransactionAction extends Enum {
     readonly isCall: boolean;
     readonly asCall: H160;
@@ -1733,14 +1886,14 @@
     readonly type: 'Call' | 'Create';
   }
 
-  /** @name EthereumTransactionTransactionSignature (216) */
+  /** @name EthereumTransactionTransactionSignature (239) */
   export interface EthereumTransactionTransactionSignature extends Struct {
     readonly v: u64;
     readonly r: H256;
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionEip2930Transaction (218) */
+  /** @name EthereumTransactionEip2930Transaction (241) */
   export interface EthereumTransactionEip2930Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -1755,13 +1908,13 @@
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionAccessListItem (220) */
+  /** @name EthereumTransactionAccessListItem (243) */
   export interface EthereumTransactionAccessListItem extends Struct {
     readonly address: H160;
     readonly storageKeys: Vec<H256>;
   }
 
-  /** @name EthereumTransactionEip1559Transaction (221) */
+  /** @name EthereumTransactionEip1559Transaction (244) */
   export interface EthereumTransactionEip1559Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -1777,7 +1930,7 @@
     readonly s: H256;
   }
 
-  /** @name PalletEvmMigrationCall (222) */
+  /** @name PalletEvmMigrationCall (245) */
   export interface PalletEvmMigrationCall extends Enum {
     readonly isBegin: boolean;
     readonly asBegin: {
@@ -1796,7 +1949,7 @@
     readonly type: 'Begin' | 'SetData' | 'Finish';
   }
 
-  /** @name PalletSudoEvent (225) */
+  /** @name PalletSudoEvent (248) */
   export interface PalletSudoEvent extends Enum {
     readonly isSudid: boolean;
     readonly asSudid: {
@@ -1813,7 +1966,7 @@
     readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone';
   }
 
-  /** @name SpRuntimeDispatchError (227) */
+  /** @name SpRuntimeDispatchError (250) */
   export interface SpRuntimeDispatchError extends Enum {
     readonly isOther: boolean;
     readonly isCannotLookup: boolean;
@@ -1832,13 +1985,13 @@
     readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional';
   }
 
-  /** @name SpRuntimeModuleError (228) */
+  /** @name SpRuntimeModuleError (251) */
   export interface SpRuntimeModuleError extends Struct {
     readonly index: u8;
     readonly error: U8aFixed;
   }
 
-  /** @name SpRuntimeTokenError (229) */
+  /** @name SpRuntimeTokenError (252) */
   export interface SpRuntimeTokenError extends Enum {
     readonly isNoFunds: boolean;
     readonly isWouldDie: boolean;
@@ -1850,7 +2003,7 @@
     readonly type: 'NoFunds' | 'WouldDie' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported';
   }
 
-  /** @name SpRuntimeArithmeticError (230) */
+  /** @name SpRuntimeArithmeticError (253) */
   export interface SpRuntimeArithmeticError extends Enum {
     readonly isUnderflow: boolean;
     readonly isOverflow: boolean;
@@ -1858,20 +2011,20 @@
     readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero';
   }
 
-  /** @name SpRuntimeTransactionalError (231) */
+  /** @name SpRuntimeTransactionalError (254) */
   export interface SpRuntimeTransactionalError extends Enum {
     readonly isLimitReached: boolean;
     readonly isNoLayer: boolean;
     readonly type: 'LimitReached' | 'NoLayer';
   }
 
-  /** @name PalletSudoError (232) */
+  /** @name PalletSudoError (255) */
   export interface PalletSudoError extends Enum {
     readonly isRequireSudo: boolean;
     readonly type: 'RequireSudo';
   }
 
-  /** @name FrameSystemAccountInfo (233) */
+  /** @name FrameSystemAccountInfo (256) */
   export interface FrameSystemAccountInfo extends Struct {
     readonly nonce: u32;
     readonly consumers: u32;
@@ -1880,19 +2033,19 @@
     readonly data: PalletBalancesAccountData;
   }
 
-  /** @name FrameSupportWeightsPerDispatchClassU64 (234) */
+  /** @name FrameSupportWeightsPerDispatchClassU64 (257) */
   export interface FrameSupportWeightsPerDispatchClassU64 extends Struct {
     readonly normal: u64;
     readonly operational: u64;
     readonly mandatory: u64;
   }
 
-  /** @name SpRuntimeDigest (235) */
+  /** @name SpRuntimeDigest (258) */
   export interface SpRuntimeDigest extends Struct {
     readonly logs: Vec<SpRuntimeDigestDigestItem>;
   }
 
-  /** @name SpRuntimeDigestDigestItem (237) */
+  /** @name SpRuntimeDigestDigestItem (260) */
   export interface SpRuntimeDigestDigestItem extends Enum {
     readonly isOther: boolean;
     readonly asOther: Bytes;
@@ -1906,14 +2059,14 @@
     readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated';
   }
 
-  /** @name FrameSystemEventRecord (239) */
+  /** @name FrameSystemEventRecord (262) */
   export interface FrameSystemEventRecord extends Struct {
     readonly phase: FrameSystemPhase;
     readonly event: Event;
     readonly topics: Vec<H256>;
   }
 
-  /** @name FrameSystemEvent (241) */
+  /** @name FrameSystemEvent (264) */
   export interface FrameSystemEvent extends Enum {
     readonly isExtrinsicSuccess: boolean;
     readonly asExtrinsicSuccess: {
@@ -1941,14 +2094,14 @@
     readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked';
   }
 
-  /** @name FrameSupportWeightsDispatchInfo (242) */
+  /** @name FrameSupportWeightsDispatchInfo (265) */
   export interface FrameSupportWeightsDispatchInfo extends Struct {
     readonly weight: u64;
     readonly class: FrameSupportWeightsDispatchClass;
     readonly paysFee: FrameSupportWeightsPays;
   }
 
-  /** @name FrameSupportWeightsDispatchClass (243) */
+  /** @name FrameSupportWeightsDispatchClass (266) */
   export interface FrameSupportWeightsDispatchClass extends Enum {
     readonly isNormal: boolean;
     readonly isOperational: boolean;
@@ -1956,14 +2109,14 @@
     readonly type: 'Normal' | 'Operational' | 'Mandatory';
   }
 
-  /** @name FrameSupportWeightsPays (244) */
+  /** @name FrameSupportWeightsPays (267) */
   export interface FrameSupportWeightsPays extends Enum {
     readonly isYes: boolean;
     readonly isNo: boolean;
     readonly type: 'Yes' | 'No';
   }
 
-  /** @name OrmlVestingModuleEvent (245) */
+  /** @name OrmlVestingModuleEvent (268) */
   export interface OrmlVestingModuleEvent extends Enum {
     readonly isVestingScheduleAdded: boolean;
     readonly asVestingScheduleAdded: {
@@ -1983,7 +2136,7 @@
     readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated';
   }
 
-  /** @name CumulusPalletXcmpQueueEvent (246) */
+  /** @name CumulusPalletXcmpQueueEvent (269) */
   export interface CumulusPalletXcmpQueueEvent extends Enum {
     readonly isSuccess: boolean;
     readonly asSuccess: Option<H256>;
@@ -2004,7 +2157,7 @@
     readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'UpwardMessageSent' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced';
   }
 
-  /** @name PalletXcmEvent (247) */
+  /** @name PalletXcmEvent (270) */
   export interface PalletXcmEvent extends Enum {
     readonly isAttempted: boolean;
     readonly asAttempted: XcmV2TraitsOutcome;
@@ -2041,7 +2194,7 @@
     readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail';
   }
 
-  /** @name XcmV2TraitsOutcome (248) */
+  /** @name XcmV2TraitsOutcome (271) */
   export interface XcmV2TraitsOutcome extends Enum {
     readonly isComplete: boolean;
     readonly asComplete: u64;
@@ -2052,7 +2205,7 @@
     readonly type: 'Complete' | 'Incomplete' | 'Error';
   }
 
-  /** @name CumulusPalletXcmEvent (250) */
+  /** @name CumulusPalletXcmEvent (273) */
   export interface CumulusPalletXcmEvent extends Enum {
     readonly isInvalidFormat: boolean;
     readonly asInvalidFormat: U8aFixed;
@@ -2063,7 +2216,7 @@
     readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward';
   }
 
-  /** @name CumulusPalletDmpQueueEvent (251) */
+  /** @name CumulusPalletDmpQueueEvent (274) */
   export interface CumulusPalletDmpQueueEvent extends Enum {
     readonly isInvalidFormat: boolean;
     readonly asInvalidFormat: U8aFixed;
@@ -2080,7 +2233,7 @@
     readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced';
   }
 
-  /** @name PalletUniqueRawEvent (252) */
+  /** @name PalletUniqueRawEvent (275) */
   export interface PalletUniqueRawEvent extends Enum {
     readonly isCollectionSponsorRemoved: boolean;
     readonly asCollectionSponsorRemoved: u32;
@@ -2105,7 +2258,7 @@
     readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'CollectionPermissionSet';
   }
 
-  /** @name PalletCommonEvent (253) */
+  /** @name PalletCommonEvent (276) */
   export interface PalletCommonEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
@@ -2132,14 +2285,73 @@
     readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
   }
 
-  /** @name PalletStructureEvent (254) */
+  /** @name PalletStructureEvent (277) */
   export interface PalletStructureEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
     readonly type: 'Executed';
   }
 
-  /** @name PalletEvmEvent (255) */
+  /** @name PalletRmrkCoreEvent (278) */
+  export interface PalletRmrkCoreEvent extends Enum {
+    readonly isCollectionCreated: boolean;
+    readonly asCollectionCreated: {
+      readonly issuer: AccountId32;
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isCollectionDestroyed: boolean;
+    readonly asCollectionDestroyed: {
+      readonly issuer: AccountId32;
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isIssuerChanged: boolean;
+    readonly asIssuerChanged: {
+      readonly oldIssuer: AccountId32;
+      readonly newIssuer: AccountId32;
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isCollectionLocked: boolean;
+    readonly asCollectionLocked: {
+      readonly issuer: AccountId32;
+      readonly collectionId: u32;
+    } & Struct;
+    readonly isNftMinted: boolean;
+    readonly asNftMinted: {
+      readonly owner: AccountId32;
+      readonly collectionId: u32;
+      readonly nftId: u32;
+    } & Struct;
+    readonly isNftBurned: boolean;
+    readonly asNftBurned: {
+      readonly owner: AccountId32;
+      readonly nftId: u32;
+    } & Struct;
+    readonly isPropertySet: boolean;
+    readonly asPropertySet: {
+      readonly collectionId: u32;
+      readonly maybeNftId: Option<u32>;
+      readonly key: Bytes;
+      readonly value: Bytes;
+    } & Struct;
+    readonly isResourceAdded: boolean;
+    readonly asResourceAdded: {
+      readonly nftId: u32;
+      readonly resourceId: u32;
+    } & Struct;
+    readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'PropertySet' | 'ResourceAdded';
+  }
+
+  /** @name PalletRmrkEquipEvent (279) */
+  export interface PalletRmrkEquipEvent extends Enum {
+    readonly isBaseCreated: boolean;
+    readonly asBaseCreated: {
+      readonly issuer: AccountId32;
+      readonly baseId: u32;
+    } & Struct;
+    readonly type: 'BaseCreated';
+  }
+
+  /** @name PalletEvmEvent (280) */
   export interface PalletEvmEvent extends Enum {
     readonly isLog: boolean;
     readonly asLog: EthereumLog;
@@ -2158,21 +2370,21 @@
     readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw';
   }
 
-  /** @name EthereumLog (256) */
+  /** @name EthereumLog (281) */
   export interface EthereumLog extends Struct {
     readonly address: H160;
     readonly topics: Vec<H256>;
     readonly data: Bytes;
   }
 
-  /** @name PalletEthereumEvent (257) */
+  /** @name PalletEthereumEvent (282) */
   export interface PalletEthereumEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>;
     readonly type: 'Executed';
   }
 
-  /** @name EvmCoreErrorExitReason (258) */
+  /** @name EvmCoreErrorExitReason (283) */
   export interface EvmCoreErrorExitReason extends Enum {
     readonly isSucceed: boolean;
     readonly asSucceed: EvmCoreErrorExitSucceed;
@@ -2185,7 +2397,7 @@
     readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
   }
 
-  /** @name EvmCoreErrorExitSucceed (259) */
+  /** @name EvmCoreErrorExitSucceed (284) */
   export interface EvmCoreErrorExitSucceed extends Enum {
     readonly isStopped: boolean;
     readonly isReturned: boolean;
@@ -2193,7 +2405,7 @@
     readonly type: 'Stopped' | 'Returned' | 'Suicided';
   }
 
-  /** @name EvmCoreErrorExitError (260) */
+  /** @name EvmCoreErrorExitError (285) */
   export interface EvmCoreErrorExitError extends Enum {
     readonly isStackUnderflow: boolean;
     readonly isStackOverflow: boolean;
@@ -2214,13 +2426,13 @@
     readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'InvalidCode';
   }
 
-  /** @name EvmCoreErrorExitRevert (263) */
+  /** @name EvmCoreErrorExitRevert (288) */
   export interface EvmCoreErrorExitRevert extends Enum {
     readonly isReverted: boolean;
     readonly type: 'Reverted';
   }
 
-  /** @name EvmCoreErrorExitFatal (264) */
+  /** @name EvmCoreErrorExitFatal (289) */
   export interface EvmCoreErrorExitFatal extends Enum {
     readonly isNotSupported: boolean;
     readonly isUnhandledInterrupt: boolean;
@@ -2231,7 +2443,7 @@
     readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
   }
 
-  /** @name FrameSystemPhase (265) */
+  /** @name FrameSystemPhase (290) */
   export interface FrameSystemPhase extends Enum {
     readonly isApplyExtrinsic: boolean;
     readonly asApplyExtrinsic: u32;
@@ -2240,27 +2452,27 @@
     readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
   }
 
-  /** @name FrameSystemLastRuntimeUpgradeInfo (267) */
+  /** @name FrameSystemLastRuntimeUpgradeInfo (292) */
   export interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
     readonly specVersion: Compact<u32>;
     readonly specName: Text;
   }
 
-  /** @name FrameSystemLimitsBlockWeights (268) */
+  /** @name FrameSystemLimitsBlockWeights (293) */
   export interface FrameSystemLimitsBlockWeights extends Struct {
     readonly baseBlock: u64;
     readonly maxBlock: u64;
     readonly perClass: FrameSupportWeightsPerDispatchClassWeightsPerClass;
   }
 
-  /** @name FrameSupportWeightsPerDispatchClassWeightsPerClass (269) */
+  /** @name FrameSupportWeightsPerDispatchClassWeightsPerClass (294) */
   export interface FrameSupportWeightsPerDispatchClassWeightsPerClass extends Struct {
     readonly normal: FrameSystemLimitsWeightsPerClass;
     readonly operational: FrameSystemLimitsWeightsPerClass;
     readonly mandatory: FrameSystemLimitsWeightsPerClass;
   }
 
-  /** @name FrameSystemLimitsWeightsPerClass (270) */
+  /** @name FrameSystemLimitsWeightsPerClass (295) */
   export interface FrameSystemLimitsWeightsPerClass extends Struct {
     readonly baseExtrinsic: u64;
     readonly maxExtrinsic: Option<u64>;
@@ -2268,25 +2480,25 @@
     readonly reserved: Option<u64>;
   }
 
-  /** @name FrameSystemLimitsBlockLength (272) */
+  /** @name FrameSystemLimitsBlockLength (297) */
   export interface FrameSystemLimitsBlockLength extends Struct {
     readonly max: FrameSupportWeightsPerDispatchClassU32;
   }
 
-  /** @name FrameSupportWeightsPerDispatchClassU32 (273) */
+  /** @name FrameSupportWeightsPerDispatchClassU32 (298) */
   export interface FrameSupportWeightsPerDispatchClassU32 extends Struct {
     readonly normal: u32;
     readonly operational: u32;
     readonly mandatory: u32;
   }
 
-  /** @name FrameSupportWeightsRuntimeDbWeight (274) */
+  /** @name FrameSupportWeightsRuntimeDbWeight (299) */
   export interface FrameSupportWeightsRuntimeDbWeight extends Struct {
     readonly read: u64;
     readonly write: u64;
   }
 
-  /** @name SpVersionRuntimeVersion (275) */
+  /** @name SpVersionRuntimeVersion (300) */
   export interface SpVersionRuntimeVersion extends Struct {
     readonly specName: Text;
     readonly implName: Text;
@@ -2298,7 +2510,7 @@
     readonly stateVersion: u8;
   }
 
-  /** @name FrameSystemError (279) */
+  /** @name FrameSystemError (304) */
   export interface FrameSystemError extends Enum {
     readonly isInvalidSpecName: boolean;
     readonly isSpecVersionNeedsToIncrease: boolean;
@@ -2309,7 +2521,7 @@
     readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
   }
 
-  /** @name OrmlVestingModuleError (281) */
+  /** @name OrmlVestingModuleError (306) */
   export interface OrmlVestingModuleError extends Enum {
     readonly isZeroVestingPeriod: boolean;
     readonly isZeroVestingPeriodCount: boolean;
@@ -2320,21 +2532,21 @@
     readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
   }
 
-  /** @name CumulusPalletXcmpQueueInboundChannelDetails (283) */
+  /** @name CumulusPalletXcmpQueueInboundChannelDetails (308) */
   export interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
     readonly sender: u32;
     readonly state: CumulusPalletXcmpQueueInboundState;
     readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesXcmpMessageFormat]>>;
   }
 
-  /** @name CumulusPalletXcmpQueueInboundState (284) */
+  /** @name CumulusPalletXcmpQueueInboundState (309) */
   export interface CumulusPalletXcmpQueueInboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (287) */
+  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (312) */
   export interface PolkadotParachainPrimitivesXcmpMessageFormat extends Enum {
     readonly isConcatenatedVersionedXcm: boolean;
     readonly isConcatenatedEncodedBlob: boolean;
@@ -2342,7 +2554,7 @@
     readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (290) */
+  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (315) */
   export interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
     readonly recipient: u32;
     readonly state: CumulusPalletXcmpQueueOutboundState;
@@ -2351,14 +2563,14 @@
     readonly lastIndex: u16;
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundState (291) */
+  /** @name CumulusPalletXcmpQueueOutboundState (316) */
   export interface CumulusPalletXcmpQueueOutboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name CumulusPalletXcmpQueueQueueConfigData (293) */
+  /** @name CumulusPalletXcmpQueueQueueConfigData (318) */
   export interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
     readonly suspendThreshold: u32;
     readonly dropThreshold: u32;
@@ -2368,7 +2580,7 @@
     readonly xcmpMaxIndividualWeight: u64;
   }
 
-  /** @name CumulusPalletXcmpQueueError (295) */
+  /** @name CumulusPalletXcmpQueueError (320) */
   export interface CumulusPalletXcmpQueueError extends Enum {
     readonly isFailedToSend: boolean;
     readonly isBadXcmOrigin: boolean;
@@ -2378,7 +2590,7 @@
     readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
   }
 
-  /** @name PalletXcmError (296) */
+  /** @name PalletXcmError (321) */
   export interface PalletXcmError extends Enum {
     readonly isUnreachable: boolean;
     readonly isSendFailure: boolean;
@@ -2396,29 +2608,29 @@
     readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed';
   }
 
-  /** @name CumulusPalletXcmError (297) */
+  /** @name CumulusPalletXcmError (322) */
   export type CumulusPalletXcmError = Null;
 
-  /** @name CumulusPalletDmpQueueConfigData (298) */
+  /** @name CumulusPalletDmpQueueConfigData (323) */
   export interface CumulusPalletDmpQueueConfigData extends Struct {
     readonly maxIndividual: u64;
   }
 
-  /** @name CumulusPalletDmpQueuePageIndexData (299) */
+  /** @name CumulusPalletDmpQueuePageIndexData (324) */
   export interface CumulusPalletDmpQueuePageIndexData extends Struct {
     readonly beginUsed: u32;
     readonly endUsed: u32;
     readonly overweightCount: u64;
   }
 
-  /** @name CumulusPalletDmpQueueError (302) */
+  /** @name CumulusPalletDmpQueueError (327) */
   export interface CumulusPalletDmpQueueError extends Enum {
     readonly isUnknown: boolean;
     readonly isOverLimit: boolean;
     readonly type: 'Unknown' | 'OverLimit';
   }
 
-  /** @name PalletUniqueError (306) */
+  /** @name PalletUniqueError (331) */
   export interface PalletUniqueError extends Enum {
     readonly isCollectionDecimalPointLimitExceeded: boolean;
     readonly isConfirmUnsetSponsorFail: boolean;
@@ -2426,7 +2638,7 @@
     readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument';
   }
 
-  /** @name UpDataStructsCollection (307) */
+  /** @name UpDataStructsCollection (332) */
   export interface UpDataStructsCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -2438,7 +2650,7 @@
     readonly permissions: UpDataStructsCollectionPermissions;
   }
 
-  /** @name UpDataStructsSponsorshipState (308) */
+  /** @name UpDataStructsSponsorshipState (333) */
   export interface UpDataStructsSponsorshipState extends Enum {
     readonly isDisabled: boolean;
     readonly isUnconfirmed: boolean;
@@ -2448,20 +2660,20 @@
     readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
   }
 
-  /** @name UpDataStructsProperties (309) */
+  /** @name UpDataStructsProperties (334) */
   export interface UpDataStructsProperties extends Struct {
     readonly map: UpDataStructsPropertiesMapBoundedVec;
     readonly consumedSpace: u32;
     readonly spaceLimit: u32;
   }
 
-  /** @name UpDataStructsPropertiesMapBoundedVec (310) */
+  /** @name UpDataStructsPropertiesMapBoundedVec (335) */
   export interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
 
-  /** @name UpDataStructsPropertiesMapPropertyPermission (315) */
+  /** @name UpDataStructsPropertiesMapPropertyPermission (340) */
   export interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
 
-  /** @name UpDataStructsCollectionStats (322) */
+  /** @name UpDataStructsCollectionStats (347) */
   export interface UpDataStructsCollectionStats extends Struct {
     readonly created: u32;
     readonly destroyed: u32;
@@ -2532,7 +2744,7 @@
 
   /** @name UpDataStructsRmrkResourceInfo (336) */
   export interface UpDataStructsRmrkResourceInfo extends Struct {
-    readonly id: Bytes;
+    readonly id: u32;
     readonly resource: UpDataStructsRmrkResourceTypes;
     readonly pending: bool;
     readonly pendingRemoval: bool;
modifiedtests/src/interfaces/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types.ts
+++ b/tests/src/interfaces/types.ts
@@ -2,4 +2,5 @@
 /* eslint-disable */
 
 export * from './unique/types';
+export * from './rmrk/types';
 export * from './default/types';