12345678#![cfg_attr(not(feature = "std"), no_std)]910#![recursion_limit = "256"]111213#[cfg(feature = "std")]14include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));1516use pallet_grandpa::fg_primitives;17use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};18use sp_api::impl_runtime_apis;19use sp_consensus_aura::sr25519::AuthorityId as AuraId;20use sp_core::{ crypto::KeyTypeId, crypto::Public, OpaqueMetadata };21use sp_runtime::{22 Permill, Perbill, Percent,23 ModuleId,24 create_runtime_str, generic, impl_opaque_keys,25 traits::{26 Convert, ConvertInto, BlakeTwo256, Block as BlockT, IdentifyAccount, 27 IdentityLookup, NumberFor, Verify,28 },29 transaction_validity::{TransactionSource, TransactionValidity},30 ApplyExtrinsicResult, MultiSignature,31};32#[cfg(feature = "std")]33use sp_version::NativeVersion;34use sp_version::RuntimeVersion;35pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter, FeeDetails, RuntimeDispatchInfo};3637pub use pallet_balances::Call as BalancesCall;38pub use pallet_contracts::{Schedule as ContractsSchedule };39pub use frame_support::{40 construct_runtime,41 dispatch::DispatchResult,42 parameter_types,43 StorageValue,44 traits::{45 Currency, ExistenceRequirement, Get, KeyOwnerProofSystem, OnUnbalanced, Randomness,46 LockIdentifier,47 },48 weights::{49 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},50 DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight,51 WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients52 },53};54use pallet_contracts::weights::WeightInfo;5556use frame_system::{57 self as system,58 EnsureRoot, 59 limits::{BlockWeights, BlockLength},60};61use sp_std::{prelude::*, marker::PhantomData};62use sp_arithmetic::{traits::{BaseArithmetic, Unsigned}};63use smallvec::smallvec;6465pub use pallet_timestamp::Call as TimestampCall;6667mod chain_extension;68use crate::chain_extension::{ NFTExtension, Imbalance };69707172pub struct CurrencyToVoteHandler;7374impl CurrencyToVoteHandler {75 fn factor() -> Balance {76 (Balances::total_issuance() / u64::max_value() as Balance).max(1)77 }78}7980impl Convert<Balance, u64> for CurrencyToVoteHandler {81 fn convert(x: Balance) -> u64 {82 (x / Self::factor()) as u6483 }84}8586impl Convert<u128, Balance> for CurrencyToVoteHandler {87 fn convert(x: u128) -> Balance {88 x * Self::factor()89 }90}91929394extern crate pallet_nft;95pub use pallet_nft::*;969798pub type BlockNumber = u32;99100101pub type Signature = MultiSignature;102103104105pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;106107108109pub type AccountIndex = u32;110111112pub type Balance = u128;113114115pub type Index = u32;116117118pub type Hash = sp_core::H256;119120121pub type DigestItem = generic::DigestItem<Hash>;122123mod nft_weights;124125126127128129pub mod opaque {130 use super::*;131132 pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;133134 135 pub type Header = generic::Header<BlockNumber, BlakeTwo256>;136 137 pub type Block = generic::Block<Header, UncheckedExtrinsic>;138 139 pub type BlockId = generic::BlockId<Block>;140141 impl_opaque_keys! {142 pub struct SessionKeys {143 pub aura: Aura,144 pub grandpa: Grandpa,145 }146 }147}148149150pub const VERSION: RuntimeVersion = RuntimeVersion {151 spec_name: create_runtime_str!("nft"),152 impl_name: create_runtime_str!("nft"),153 authoring_version: 1,154 spec_version: 3,155 impl_version: 1,156 apis: RUNTIME_API_VERSIONS,157 transaction_version: 1,158};159160pub const MILLISECS_PER_BLOCK: u64 = 6000;161162pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;163164165pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);166pub const HOURS: BlockNumber = MINUTES * 60;167pub const DAYS: BlockNumber = HOURS * 24;168169170#[cfg(feature = "std")]171pub fn native_version() -> NativeVersion {172 NativeVersion {173 runtime_version: VERSION,174 can_author_with: Default::default(),175 }176}177178179pub struct ValiudatorsOnly<Runtime: pallet_aura::Config>(PhantomData<Runtime>);180impl frame_support::traits::Contains<AccountId> for ValiudatorsOnly<Runtime> {181 fn contains(t: &AccountId) -> bool {182 let arr: [u8; 32] = *t.as_ref();183 let raw_key: Vec<u8> = Vec::from(arr);184185 match pallet_aura::Module::<Runtime>::authorities().iter().find(|auth| auth.to_raw_vec() == raw_key) {186 Some(_) => true,187 None => false,188 } 189 }190 fn sorted_members() -> Vec<AccountId> {191 let mut members: Vec<AccountId> = Vec::new();192 for auth in pallet_aura::Module::<Runtime>::authorities() {193 let mut arr: [u8; 32] = Default::default(); 194 let bor_arr = auth.clone().to_raw_vec();195 let slice = bor_arr.as_slice();196 arr.copy_from_slice(slice);197 members.push(AccountId::from(arr));198 }199 members 200 }201 fn count() -> usize {202 pallet_aura::Module::<Runtime>::authorities().len()203 }204}205206impl frame_support::traits::ContainsLengthBound for ValiudatorsOnly<Runtime> {207 fn min_len() -> usize {208 1209 }210 fn max_len() -> usize {211 100212 }213}214215type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;216217pub struct DealWithFees;218impl OnUnbalanced<NegativeImbalance> for DealWithFees {219 fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance>) {220 if let Some(fees) = fees_then_tips.next() {221 222 let mut split = fees.ration(100, 0);223 if let Some(tips) = fees_then_tips.next() {224 225 tips.ration_merge_into(100, 0, &mut split);226 }227 Treasury::on_unbalanced(split.0);228 229 }230 }231}232233234235236237238239240241242243244245246247248249250const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);251252253const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);254255const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND;256257parameter_types! {258 pub const BlockHashCount: BlockNumber = 2400;259 pub RuntimeBlockLength: BlockLength =260 BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);261 pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);262 pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;263 pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()264 .base_block(BlockExecutionWeight::get())265 .for_class(DispatchClass::all(), |weights| {266 weights.base_extrinsic = ExtrinsicBaseWeight::get();267 })268 .for_class(DispatchClass::Normal, |weights| {269 weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);270 })271 .for_class(DispatchClass::Operational, |weights| {272 weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);273 274 275 weights.reserved = Some(276 MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT277 );278 })279 .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)280 .build_or_panic();281 pub const Version: RuntimeVersion = VERSION;282 pub const SS58Prefix: u8 = 42;283}284285impl system::Config for Runtime {286 287 type BaseCallFilter = ();288 289 type AccountId = AccountId;290 291 type Call = Call;292 293 type Lookup = IdentityLookup<AccountId>;294 295 type Index = Index;296 297 type BlockNumber = BlockNumber;298 299 type Hash = Hash;300 301 type Hashing = BlakeTwo256;302 303 type Header = generic::Header<BlockNumber, BlakeTwo256>;304 305 type Event = Event;306 307 type Origin = Origin;308 309 type BlockHashCount = BlockHashCount;310 311 type DbWeight = RocksDbWeight;312 313 314 type BlockWeights = RuntimeBlockWeights;315 316 type Version = Version;317 318 type PalletInfo = PalletInfo;319 320 type OnNewAccount = ();321 322 type OnKilledAccount = ();323 324 type AccountData = pallet_balances::AccountData<Balance>;325 326 type SystemWeightInfo = system::weights::SubstrateWeight<Runtime>;327 328 type BlockLength = RuntimeBlockLength;329 type SS58Prefix = SS58Prefix;330}331332impl pallet_aura::Config for Runtime {333 type AuthorityId = AuraId;334}335336impl pallet_grandpa::Config for Runtime {337 type Event = Event;338 type Call = Call;339340 type KeyOwnerProofSystem = ();341342 type KeyOwnerProof =343 <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;344345 type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(346 KeyTypeId,347 GrandpaId,348 )>>::IdentificationTuple;349350 type HandleEquivocation = ();351352 type WeightInfo = ();353}354355parameter_types! {356 pub const MinimumPeriod: u64 = SLOT_DURATION / 2;357}358359impl pallet_timestamp::Config for Runtime {360 361 type Moment = u64;362 type OnTimestampSet = Aura;363 type MinimumPeriod = MinimumPeriod;364 type WeightInfo = ();365}366367parameter_types! {368 369 pub const ExistentialDeposit: u128 = 0;370 pub const MaxLocks: u32 = 50;371}372373impl pallet_balances::Config for Runtime {374 type MaxLocks = MaxLocks;375 376 type Balance = Balance;377 378 type Event = Event;379 type DustRemoval = Treasury;380 type ExistentialDeposit = ExistentialDeposit;381 type AccountStore = System;382 type WeightInfo = ();383}384385pub const MICROUNIQUE: Balance = 1_000_000_000;386pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;387pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;388pub const UNIQUE: Balance = 100 * CENTIUNIQUE;389390pub const fn deposit(items: u32, bytes: u32) -> Balance {391 items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE392}393394parameter_types! {395 pub const TombstoneDeposit: Balance = deposit(396 0,397 sp_std::mem::size_of::<pallet_contracts::ContractInfo<Runtime>>() as u32398 );399 pub const DepositPerContract: Balance = TombstoneDeposit::get();400 pub const DepositPerStorageByte: Balance = deposit(0, 1);401 pub const DepositPerStorageItem: Balance = deposit(1, 0);402 pub RentFraction: Perbill = Perbill::from_rational_approximation(1u32, 30 * DAYS);403 pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;404 pub const SignedClaimHandicap: u32 = 2;405 pub const MaxDepth: u32 = 32;406 pub const MaxValueSize: u32 = 16 * 1024;407 pub const MaxCodeSize: u32 = 1024 * 1024 * 25; 408 409 pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *410 RuntimeBlockWeights::get().max_block;411 412 413 pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (414 <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -415 <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)416 )) / 5) as u32;417}418419420impl pallet_contracts::Config for Runtime {421 type Time = Timestamp;422 type Randomness = RandomnessCollectiveFlip;423 type Currency = Balances;424 type Event = Event;425 type RentPayment = ();426 type SignedClaimHandicap = SignedClaimHandicap;427 type TombstoneDeposit = TombstoneDeposit;428 type DepositPerContract = DepositPerContract;429 type DepositPerStorageByte = DepositPerStorageByte;430 type DepositPerStorageItem = DepositPerStorageItem;431 type RentFraction = RentFraction;432 type SurchargeReward = SurchargeReward;433 type MaxDepth = MaxDepth;434 type MaxValueSize = MaxValueSize;435 type WeightPrice = pallet_transaction_payment::Module<Self>;436 type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;437 type ChainExtension = NFTExtension;438 type DeletionQueueDepth = DeletionQueueDepth;439 type DeletionWeightLimit = DeletionWeightLimit;440 type MaxCodeSize = MaxCodeSize;441}442443parameter_types! {444 pub const TransactionByteFee: Balance = 501 * MICROUNIQUE; 445}446447448pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);449450impl<T> WeightToFeePolynomial for LinearFee<T> where451 T: BaseArithmetic + From<u32> + Copy + Unsigned452{453 type Balance = T;454455 fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {456 smallvec!(WeightToFeeCoefficient {457 coeff_integer: 146_700u32.into(), 458 coeff_frac: Perbill::zero(),459 negative: false,460 degree: 1,461 })462 }463}464465impl pallet_transaction_payment::Config for Runtime {466 type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees>;467 type TransactionByteFee = TransactionByteFee;468 type WeightToFee = LinearFee<Balance>;469 type FeeMultiplierUpdate = ();470}471472parameter_types! {473 pub const ProposalBond: Permill = Permill::from_percent(5);474 pub const ProposalBondMinimum: Balance = 1 * UNIQUE;475 pub const SpendPeriod: BlockNumber = 5 * MINUTES;476 pub const Burn: Permill = Permill::from_percent(0);477 pub const TipCountdown: BlockNumber = 1 * DAYS;478 pub const TipFindersFee: Percent = Percent::from_percent(20);479 pub const TipReportDepositBase: Balance = 1 * UNIQUE;480 pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;481 pub const BountyDepositBase: Balance = 1 * UNIQUE;482 pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;483 pub const TreasuryModuleId: ModuleId = ModuleId(*b"py/trsry");484 pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;485 pub const MaximumReasonLength: u32 = 16384;486 pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);487 pub const BountyValueMinimum: Balance = 5 * UNIQUE;488}489490impl pallet_treasury::Config for Runtime {491 type ModuleId = TreasuryModuleId;492 type Currency = Balances;493 type ApproveOrigin = EnsureRoot<AccountId>;494 type RejectOrigin = EnsureRoot<AccountId>;495 type Event = Event;496 type OnSlash = ();497 type ProposalBond = ProposalBond;498 type ProposalBondMinimum = ProposalBondMinimum;499 type SpendPeriod = SpendPeriod;500 type Burn = Burn;501 type BurnDestination = ();502 type SpendFunds = ();503 type WeightInfo = pallet_treasury::weights::SubstrateWeight<Runtime>;504}505506impl pallet_sudo::Config for Runtime {507 type Event = Event;508 type Call = Call;509}510511parameter_types! {512 pub const MinVestedTransfer: Balance = 10 * UNIQUE;513 pub const CollectionCreationPrice: Balance = 100 * UNIQUE;514}515516impl pallet_vesting::Config for Runtime {517 type Event = Event;518 type Currency = Balances;519 type BlockNumberToBalance = ConvertInto;520 type MinVestedTransfer = MinVestedTransfer;521 type WeightInfo = ();522}523524525impl pallet_nft::Config for Runtime {526 type Event = Event;527 type WeightInfo = nft_weights::WeightInfo;528 type CollectionCreationPrice = CollectionCreationPrice;529}530531construct_runtime!(532 pub enum Runtime where533 Block = Block,534 NodeBlock = opaque::Block,535 UncheckedExtrinsic = UncheckedExtrinsic536 {537 System: system::{Module, Call, Config, Storage, Event<T>},538 RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},539 Contracts: pallet_contracts::{Module, Call, Config<T>, Storage, Event<T>},540 Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},541 Aura: pallet_aura::{Module, Config<T> },542 Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event},543 Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},544 TransactionPayment: pallet_transaction_payment::{Module, Storage},545 Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},546 Nft: pallet_nft::{Module, Call, Config<T>, Storage, Event<T>},547 Treasury: pallet_treasury::{Module, Call, Storage, Config, Event<T>},548 Vesting: pallet_vesting::{Module, Call, Config<T>, Storage, Event<T>},549 }550);551552553pub type Address = AccountId;554555pub type Header = generic::Header<BlockNumber, BlakeTwo256>;556557pub type Block = generic::Block<Header, UncheckedExtrinsic>;558559pub type SignedBlock = generic::SignedBlock<Block>;560561pub type BlockId = generic::BlockId<Block>;562563pub type SignedExtra = (564 system::CheckSpecVersion<Runtime>,565 system::CheckTxVersion<Runtime>,566 system::CheckGenesis<Runtime>,567 system::CheckEra<Runtime>,568 system::CheckNonce<Runtime>,569 system::CheckWeight<Runtime>,570 pallet_nft::ChargeTransactionPayment<Runtime>,571);572573pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;574575pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;576577pub type Executive =578 frame_executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;579580impl_runtime_apis! {581582 impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber>583 for Runtime584 {585 fn call(586 origin: AccountId,587 dest: AccountId,588 value: Balance,589 gas_limit: u64,590 input_data: Vec<u8>,591 ) -> pallet_contracts_primitives::ContractExecResult {592 Contracts::bare_call(origin, dest, value, gas_limit, input_data)593 }594595 fn get_storage(596 address: AccountId,597 key: [u8; 32],598 ) -> pallet_contracts_primitives::GetStorageResult {599 Contracts::get_storage(address, key)600 }601602 fn rent_projection(603 address: AccountId,604 ) -> pallet_contracts_primitives::RentProjectionResult<BlockNumber> {605 Contracts::rent_projection(address)606 }607 }608609 impl sp_api::Core<Block> for Runtime {610 fn version() -> RuntimeVersion {611 VERSION612 }613614 fn execute_block(block: Block) {615 Executive::execute_block(block)616 }617618 fn initialize_block(header: &<Block as BlockT>::Header) {619 Executive::initialize_block(header)620 }621 }622623 impl sp_api::Metadata<Block> for Runtime {624 fn metadata() -> OpaqueMetadata {625 Runtime::metadata().into()626 }627 }628629 impl sp_block_builder::BlockBuilder<Block> for Runtime {630 fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {631 Executive::apply_extrinsic(extrinsic)632 }633634 fn finalize_block() -> <Block as BlockT>::Header {635 Executive::finalize_block()636 }637638 fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {639 data.create_extrinsics()640 }641642 fn check_inherents(643 block: Block,644 data: sp_inherents::InherentData,645 ) -> sp_inherents::CheckInherentsResult {646 data.check_extrinsics(&block)647 }648649 fn random_seed() -> <Block as BlockT>::Hash {650 RandomnessCollectiveFlip::random_seed()651 }652 }653654 impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {655 fn validate_transaction(656 source: TransactionSource,657 tx: <Block as BlockT>::Extrinsic,658 ) -> TransactionValidity {659 Executive::validate_transaction(source, tx)660 }661 }662663 impl sp_offchain::OffchainWorkerApi<Block> for Runtime {664 fn offchain_worker(header: &<Block as BlockT>::Header) {665 Executive::offchain_worker(header)666 }667 }668669 impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {670 fn slot_duration() -> u64 {671 Aura::slot_duration()672 }673674 fn authorities() -> Vec<AuraId> {675 Aura::authorities()676 }677 }678679 impl sp_session::SessionKeys<Block> for Runtime {680 fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {681 opaque::SessionKeys::generate(seed)682 }683684 fn decode_session_keys(685 encoded: Vec<u8>,686 ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {687 opaque::SessionKeys::decode_into_raw_public_keys(&encoded)688 }689 }690691 impl fg_primitives::GrandpaApi<Block> for Runtime {692 fn grandpa_authorities() -> GrandpaAuthorityList {693 Grandpa::grandpa_authorities()694 }695696 fn submit_report_equivocation_unsigned_extrinsic(697 _equivocation_proof: fg_primitives::EquivocationProof<698 <Block as BlockT>::Hash,699 NumberFor<Block>,700 >,701 _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof,702 ) -> Option<()> {703 None704 }705706 fn generate_key_ownership_proof(707 _set_id: fg_primitives::SetId,708 _authority_id: GrandpaId,709 ) -> Option<fg_primitives::OpaqueKeyOwnershipProof> {710 711 712 713 None714 }715 }716 717 impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {718 fn account_nonce(account: AccountId) -> Index {719 System::account_nonce(account)720 }721 }722723 impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {724 fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {725 TransactionPayment::query_info(uxt, len)726 }727 fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> FeeDetails<Balance> {728 TransactionPayment::query_fee_details(uxt, len)729 }730 }731732 #[cfg(feature = "runtime-benchmarks")]733 impl frame_benchmarking::Benchmark<Block> for Runtime {734 fn dispatch_benchmark(735 config: frame_benchmarking::BenchmarkConfig736 ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {737 use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};738739 let whitelist: Vec<TrackedStorageKey> = vec![740 741 hex_literal::hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d").to_vec().into(),742 743 744 745 746 747 748 749 750 ];751752 let mut batches = Vec::<BenchmarkBatch>::new();753 let params = (&config, &whitelist);754755 add_benchmark!(params, batches, pallet_nft, Nft);756757 if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }758 Ok(batches)759 }760 }761}