diff --git a/pallets/rmrk-equip/Cargo.toml b/pallets/rmrk-equip/Cargo.toml index 64dd53bc..818a7122 100644 --- a/pallets/rmrk-equip/Cargo.toml +++ b/pallets/rmrk-equip/Cargo.toml @@ -51,5 +51,8 @@ std = [ "pallet-balances/std", ] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "pallet-rmrk-core/runtime-benchmarks" +] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/rmrk-equip/src/benchmarking.rs b/pallets/rmrk-equip/src/benchmarking.rs new file mode 100644 index 00000000..031de843 --- /dev/null +++ b/pallets/rmrk-equip/src/benchmarking.rs @@ -0,0 +1,317 @@ +#![cfg(feature = "runtime-benchmarks")] + +// Benchmarks for rmrk-equip pallet + +use super::*; + +use frame_benchmarking::{account, benchmarks, whitelisted_caller}; +use frame_support::traits::Currency; +use frame_system::RawOrigin; +use pallet_rmrk_core::Pallet as RmrkCore; +use rmrk_traits::{ComposableResource, SlotPart, SlotResource}; +use sp_runtime::{traits::Bounded, Permill}; +use sp_std::vec; + +use crate::Pallet as RmrkEquip; + +pub type BalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + +const SEED: u32 = 0; + +/// Turns a string into a BoundedVec +fn stb(s: &str) -> BoundedVec { + s.as_bytes().to_vec().try_into().unwrap() +} + +macro_rules! bvec { + ($( $x:tt )*) => { + vec![$( $x )*].try_into().unwrap() + } +} + +/// Assert that the last event equals the provided one. +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn funded_account(name: &'static str, index: u32) -> T::AccountId { + let caller: T::AccountId = account(name, index, SEED); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + caller +} + +/// Creates a collection +fn create_test_collection( + caller: T::AccountId, + collection_index: u32, +) -> T::CollectionId { + let collection_id = ::Helper::collection(collection_index); + let metadata = bvec![0u8; 20]; + let max = None; + let symbol = bvec![0u8; 15]; + ::Currency::make_free_balance_be( + &caller, + BalanceOf::::max_value(), + ); + let _ = RmrkCore::::create_collection( + (RawOrigin::Signed(caller.clone())).into(), + collection_id.clone(), + metadata, + max, + symbol, + ); + + collection_id +} + +fn mint_test_nft( + owner: T::AccountId, + mint_for: Option, + collection_id: T::CollectionId, + nft_index: u32, +) -> T::ItemId { + let nft_id = ::Helper::item(nft_index); + let royalty_recipient = owner.clone(); + let royalty = Permill::from_percent(1); + let nft_metadata = bvec![0u8; 20]; + let resource = None; + let _ = RmrkCore::::mint_nft( + RawOrigin::Signed(owner.clone()).into(), + mint_for, + nft_id, + collection_id, + Some(royalty_recipient), + Some(royalty), + nft_metadata, + true, + resource, + ); + nft_id +} + +// Send nft to Account or to another nft +fn send_test_nft( + owner: T::AccountId, + collection_id: T::CollectionId, + nft_id: T::ItemId, + new_owner_enum: AccountIdOrCollectionNftTuple, +) { + let _ = + RmrkCore::::send(RawOrigin::Signed(owner).into(), collection_id, nft_id, new_owner_enum); +} + +/// Creates a base +fn base_create( + creator: T::AccountId, + parts: BoundedVec< + PartType, BoundedVec>, + T::PartsLimit, + >, +) { + let _ = RmrkEquip::::create_base( + RawOrigin::Signed(creator).into(), + bvec![0u8; 20], + bvec![0u8; 20], + parts, + ); +} + +fn hand_slot_part( + collection_id: T::CollectionId, + id: u32, +) -> SlotPart< + BoundedVec, + BoundedVec, +> { + SlotPart { + id, + z: 0, + src: Some(stb::("hand")), + equippable: EquippableList::Custom(bvec![collection_id]), + } +} + +fn add_composable_resource( + caller: T::AccountId, + collection_id: T::CollectionId, + item: T::ItemId, + base_id: BaseId, + parts: Vec, +) { + let composable_resource = ComposableResource { + parts: parts.try_into().unwrap(), + base: base_id, + metadata: None, + slot: None, + }; + + let _ = RmrkCore::::add_composable_resource( + RawOrigin::Signed(caller.clone()).into(), + collection_id, + item, + composable_resource, + 0, + ); +} + +fn add_slot_resource( + caller: T::AccountId, + collection_id: T::CollectionId, + item: T::ItemId, + base_id: BaseId, + slot: u32, +) { + let slot_resource = SlotResource { base: base_id, metadata: None, slot }; + + let _ = RmrkCore::::add_slot_resource( + RawOrigin::Signed(caller.clone()).into(), + collection_id, + item, + slot_resource, + 0, + ); +} + +benchmarks! { + change_base_issuer { + let caller: T::AccountId = whitelisted_caller(); + let new_issuer = funded_account::("new_issuer", 0); + let new_issuer_lookup = T::Lookup::unlookup(new_issuer.clone()); + base_create::(caller.clone(), bvec![]); + }: _(RawOrigin::Signed(caller.clone()), 0u32, new_issuer_lookup) + verify { + assert_last_event::(Event::BaseIssuerChanged { + old_issuer: caller, + new_issuer: new_issuer, + base_id: 0u32, + }.into()); + } + + equip { + let caller: T::AccountId = whitelisted_caller(); + let collection_id = create_test_collection::(caller.clone(), 1); + + let slot_part_hand = hand_slot_part::(collection_id, 201); + base_create::(caller.clone(), bvec![PartType::SlotPart(slot_part_hand)]); + + let character = mint_test_nft::(caller.clone(), None, collection_id, 0); + let sword = mint_test_nft::(caller.clone(), None, collection_id, 1); + let new_owner = AccountIdOrCollectionNftTuple::CollectionAndNftTuple(collection_id, character); + send_test_nft::(caller.clone(), collection_id, sword, new_owner); + + add_composable_resource::(caller.clone(), collection_id, character, 0, vec![201]); + add_slot_resource::(caller.clone(), collection_id, sword, 0, 201); + let item = (collection_id, sword); + let equipper = (collection_id, character); + }: _(RawOrigin::Signed(caller.clone()), item, equipper, 0u32, 0, 201) + verify { + assert_last_event::(Event::SlotEquipped { + item_collection: collection_id, + item_nft: item.1, + base_id: 0, + slot_id: 201, + }.into()) + } + + unequip { + let caller: T::AccountId = whitelisted_caller(); + let collection_id = create_test_collection::(caller.clone(), 1); + + let slot_part_hand = hand_slot_part::(collection_id, 201); + base_create::(caller.clone(), bvec![PartType::SlotPart(slot_part_hand)]); + + let character = mint_test_nft::(caller.clone(), None, collection_id, 0); + let sword = mint_test_nft::(caller.clone(), None, collection_id, 1); + let new_owner = AccountIdOrCollectionNftTuple::CollectionAndNftTuple(collection_id, character); + send_test_nft::(caller.clone(), collection_id, sword, new_owner); + + add_composable_resource::(caller.clone(), collection_id, character, 0, vec![201]); + add_slot_resource::(caller.clone(), collection_id, sword, 0, 201); + let item = (collection_id, sword); + // the equipper is going to be the unequipper. + let equipper = (collection_id, character); + let _ = RmrkEquip::::equip(RawOrigin::Signed(caller.clone()).into(), item, equipper, 0u32, 0, 201); + }: _(RawOrigin::Signed(caller.clone()), item, equipper, 0, 201) + verify { + assert_last_event::(Event::SlotUnequipped { + item_collection: collection_id, + item_nft: item.1, + base_id: 0, + slot_id: 201, + }.into()) + } + + equippable { + let caller: T::AccountId = whitelisted_caller(); + let collection_0 = ::Helper::collection(0); + + let slot_part_hand = hand_slot_part::(collection_0, 201); + base_create::(caller.clone(), bvec![PartType::SlotPart(slot_part_hand)]); + + let collection_1 = ::Helper::collection(1); + }: _(RawOrigin::Signed(caller.clone()), 0, 201, EquippableList::Custom(bvec![collection_1])) + verify { + assert_last_event::(Event::EquippablesUpdated { base_id: 0, slot_id: 201 }.into()) + } + + equippable_add { + let caller: T::AccountId = whitelisted_caller(); + let collection_0 = ::Helper::collection(0); + + let slot_part_hand = hand_slot_part::(collection_0, 201); + base_create::(caller.clone(), bvec![PartType::SlotPart(slot_part_hand)]); + + let collection_1 = ::Helper::collection(1); + }: _(RawOrigin::Signed(caller.clone()), 0, 201, collection_1) + verify { + assert_last_event::(Event::EquippablesUpdated { base_id: 0, slot_id: 201 }.into()) + } + + equippable_remove { + let caller: T::AccountId = whitelisted_caller(); + let collection_0 = ::Helper::collection(0); + + let slot_part_hand = hand_slot_part::(collection_0, 201); + base_create::(caller.clone(), bvec![PartType::SlotPart(slot_part_hand)]); + }: _(RawOrigin::Signed(caller.clone()), 0, 201, collection_0) + verify { + assert_last_event::(Event::EquippablesUpdated { base_id: 0, slot_id: 201 }.into()) + } + + theme_add { + let caller: T::AccountId = whitelisted_caller(); + let default_theme = Theme { + name: stb::("default"), + properties: bvec![ + ThemeProperty { key: stb::("primary_color"), value: stb::("red") }, + ThemeProperty { key: stb::("secondary_color"), value: stb::("blue") }, + ], + inherit: false, + }; + base_create::(caller.clone(), bvec![]); + }: _(RawOrigin::Signed(caller.clone()), 0, default_theme) + verify { + + } + + create_base { + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller.clone()), bvec![42u8; 20], bvec![25u8; 20], bvec![]) + verify { + assert_last_event::(Event::BaseCreated { issuer: caller, base_id: 0 }.into()) + } + + impl_benchmark_test_suite!(RmrkEquip, crate::benchmarking::tests::new_test_ext(), crate::mock::Test); +} + +#[cfg(test)] +mod tests { + use crate::mock; + use sp_io::TestExternalities; + + pub fn new_test_ext() -> TestExternalities { + mock::ExtBuilder::default().build() + } +} diff --git a/pallets/rmrk-equip/src/functions.rs b/pallets/rmrk-equip/src/functions.rs index a8cd450f..34806ae8 100644 --- a/pallets/rmrk-equip/src/functions.rs +++ b/pallets/rmrk-equip/src/functions.rs @@ -142,7 +142,7 @@ impl } /// Implementation of the base_change_issuer function for the Base trait - /// Called by the change_base_issuer extrinsic to change the issuer of a base + /// called by the change_base_issuer extrinsic to change the issuer of a base /// /// Parameters: /// - base_id: The Base ID to change the issuer of @@ -275,7 +275,7 @@ impl Error::::NoResourceForThisBaseFoundOnNft ); - // The item being equipped must be have a resource that is equippable into that base.slot + // The item being equipped must have a resource that is equippable into that base.slot ensure!( pallet_rmrk_core::Pallet::::equippable_slots(( item_collection_id, diff --git a/pallets/rmrk-equip/src/lib.rs b/pallets/rmrk-equip/src/lib.rs index 85752852..fcad042f 100644 --- a/pallets/rmrk-equip/src/lib.rs +++ b/pallets/rmrk-equip/src/lib.rs @@ -14,6 +14,9 @@ use sp_runtime::traits::StaticLookup; pub use pallet::*; +pub mod weights; +pub use weights::WeightInfo; + use rmrk_traits::{ base::EquippableOperation, primitives::{BaseId, PartId, ResourceId, SlotId}, @@ -30,6 +33,12 @@ mod mock; #[cfg(test)] mod tests; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +use pallet_rmrk_core::BenchmarkHelper; + // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; @@ -71,6 +80,12 @@ pub mod pallet { /// Maximum number of Properties allowed for any Theme #[pallet::constant] type MaxCollectionsEquippablePerPart: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + #[cfg(feature = "runtime-benchmarks")] + type Helper: BenchmarkHelper; } #[pallet::storage] @@ -240,7 +255,7 @@ pub mod pallet { /// - `base_id`: base_id to change issuer of /// - `new_issuer`: Base's new issuer #[pallet::call_index(0)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::change_base_issuer())] pub fn change_base_issuer( origin: OriginFor, base_id: BaseId, @@ -251,8 +266,6 @@ pub mod pallet { ensure!(base.issuer == sender, Error::::PermissionError); let new_owner = T::Lookup::lookup(new_issuer)?; - ensure!(Bases::::contains_key(base_id), Error::::NoAvailableBaseId); - let (new_owner, base_id) = Self::base_change_issuer(base_id, new_owner)?; Self::deposit_event(Event::BaseIssuerChanged { @@ -262,6 +275,7 @@ pub mod pallet { }); Ok(()) } + /// Equips a child NFT's resource to a parent's slot, if all are available. /// Equipping operations are maintained inside the Equippings storage. /// Modeled after [equip interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/equip.md) @@ -273,7 +287,7 @@ pub mod pallet { /// - base: ID of the base which the item and equipper must each have a resource referencing /// - slot: ID of the slot which the item and equipper must each have a resource referencing #[pallet::call_index(1)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::equip())] pub fn equip( origin: OriginFor, item: (T::CollectionId, T::ItemId), @@ -313,7 +327,7 @@ pub mod pallet { /// - base: ID of the base which the item and equipper must each have a resource referencing /// - slot: ID of the slot which the item and equipper must each have a resource referencing #[pallet::call_index(2)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::unequip())] pub fn unequip( origin: OriginFor, item: (T::CollectionId, T::ItemId), @@ -345,7 +359,7 @@ pub mod pallet { /// - part_id: The Slot Part whose Equippable List is being updated /// - equippables: The list of equippables that will override the current Equippaables list #[pallet::call_index(3)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::equippable())] pub fn equippable( origin: OriginFor, base_id: BaseId, @@ -375,7 +389,7 @@ pub mod pallet { /// - part_id: The Slot Part whose Equippable List is being updated /// - equippable: The equippable that will be added to the current Equippaables list #[pallet::call_index(4)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::equippable_add())] pub fn equippable_add( origin: OriginFor, base_id: BaseId, @@ -403,7 +417,7 @@ pub mod pallet { /// - part_id: The Slot Part whose Equippable List is being updated /// - equippable: The equippable that will be removed from the current Equippaables list #[pallet::call_index(5)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::equippable_remove())] pub fn equippable_remove( origin: OriginFor, base_id: BaseId, @@ -437,7 +451,7 @@ pub mod pallet { /// - value: arbitrary BoundedString, defined by client /// - inherit: optional bool #[pallet::call_index(6)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::theme_add())] pub fn theme_add( origin: OriginFor, base_id: BaseId, @@ -471,7 +485,7 @@ pub mod pallet { /// - parts: array of Fixed and Slot parts composing the base, confined in length by /// PartsLimit #[pallet::call_index(7)] - #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] + #[pallet::weight(::WeightInfo::create_base())] pub fn create_base( origin: OriginFor, base_type: BoundedVec, diff --git a/pallets/rmrk-equip/src/mock.rs b/pallets/rmrk-equip/src/mock.rs index 6fc435e2..cac6cee5 100644 --- a/pallets/rmrk-equip/src/mock.rs +++ b/pallets/rmrk-equip/src/mock.rs @@ -50,6 +50,9 @@ impl pallet_rmrk_equip::Config for Test { type RuntimeEvent = RuntimeEvent; type MaxPropertiesPerTheme = MaxPropertiesPerTheme; type MaxCollectionsEquippablePerPart = MaxCollectionsEquippablePerPart; + type WeightInfo = crate::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type Helper = RmrkBenchmark; } parameter_types! { diff --git a/pallets/rmrk-equip/src/weights.rs b/pallets/rmrk-equip/src/weights.rs new file mode 100644 index 00000000..dc5ca694 --- /dev/null +++ b/pallets/rmrk-equip/src/weights.rs @@ -0,0 +1,111 @@ + +//! Autogenerated weights for `pallet_rmrk_equip` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-12-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `Sergejs-MacBook-Air.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/rmrk-substrate +// benchmark +// pallet +// --chain +// dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// pallet_rmrk_equip +// --extrinsic=* +// --steps +// 50 +// --repeat +// 20 +// --output +// pallets/rmrk-equip/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for `pallet_rmrk_equip`. +pub trait WeightInfo { + fn change_base_issuer() -> Weight; + fn equip() -> Weight; + fn unequip() -> Weight; + fn equippable() -> Weight; + fn equippable_add() -> Weight; + fn equippable_remove() -> Weight; + fn theme_add() -> Weight; + fn create_base() -> Weight; +} + +/// Weight functions for `pallet_rmrk_equip`. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: RmrkEquip Bases (r:1 w:1) + fn change_base_issuer() -> Weight { + Weight::from_ref_time(16_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: RmrkCore Nfts (r:2 w:1) + // Storage: RmrkCore Lock (r:2 w:0) + // Storage: RmrkEquip Equippings (r:1 w:1) + // Storage: Uniques Asset (r:2 w:0) + // Storage: RmrkCore EquippableBases (r:1 w:0) + // Storage: RmrkCore EquippableSlots (r:1 w:0) + // Storage: RmrkEquip Parts (r:1 w:0) + fn equip() -> Weight { + Weight::from_ref_time(47_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(10 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: RmrkCore Lock (r:2 w:0) + // Storage: RmrkEquip Equippings (r:1 w:1) + // Storage: RmrkCore Nfts (r:1 w:1) + // Storage: Uniques Asset (r:2 w:0) + fn unequip() -> Weight { + Weight::from_ref_time(35_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: RmrkEquip Bases (r:1 w:0) + // Storage: RmrkEquip Parts (r:1 w:1) + fn equippable() -> Weight { + Weight::from_ref_time(16_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: RmrkEquip Bases (r:1 w:0) + // Storage: RmrkEquip Parts (r:1 w:1) + fn equippable_add() -> Weight { + Weight::from_ref_time(16_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: RmrkEquip Bases (r:1 w:0) + // Storage: RmrkEquip Parts (r:1 w:1) + fn equippable_remove() -> Weight { + Weight::from_ref_time(17_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: RmrkEquip Bases (r:1 w:0) + // Storage: RmrkEquip Themes (r:1 w:2) + fn theme_add() -> Weight { + Weight::from_ref_time(16_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: RmrkEquip NextBaseId (r:1 w:1) + // Storage: RmrkEquip Bases (r:0 w:1) + fn create_base() -> Weight { + Weight::from_ref_time(13_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index ab6e4198..f36c9e0d 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -105,6 +105,7 @@ runtime-benchmarks = [ "hex-literal", "pallet-balances/runtime-benchmarks", "pallet-rmrk-core/runtime-benchmarks", + "pallet-rmrk-equip/runtime-benchmarks", "pallet-rmrk-market/runtime-benchmarks", "pallet-template/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4b6b3f0d..aa4f83f6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -406,6 +406,8 @@ impl pallet_rmrk_equip::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MaxPropertiesPerTheme = MaxPropertiesPerTheme; type MaxCollectionsEquippablePerPart = MaxCollectionsEquippablePerPart; + type WeightInfo = pallet_rmrk_equip::weights::SubstrateWeight; + type Helper = RmrkBenchmark; } impl pallet_uniques::Config for Runtime { @@ -758,6 +760,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_timestamp, Timestamp); list_benchmark!(list, extra, pallet_template, TemplateModule); list_benchmark!(list, extra, pallet_rmrk_core, RmrkCore); + list_benchmark!(list, extra, pallet_rmrk_equip, RmrkEquip); list_benchmark!(list, extra, pallet_rmrk_market, RmrkMarket); let storage_info = AllPalletsWithSystem::storage_info(); @@ -798,6 +801,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_timestamp, Timestamp); add_benchmark!(params, batches, pallet_template, TemplateModule); add_benchmark!(params, batches, pallet_rmrk_core, RmrkCore); + add_benchmark!(params, batches, pallet_rmrk_equip, RmrkEquip); add_benchmark!(params, batches, pallet_rmrk_market, RmrkMarket); Ok(batches)