/// Voting majority origin for `Instance`.
pub type VMO<Instance> =
    pallet_committee::EnsureThresholdMet<polymesh_primitives::AccountId, Instance>;

pub type GovernanceCommittee = pallet_committee::Instance1;

// Allow benchmarks to run with larger inputs.
// This is needed for extrinsics that have a `Vec<_>` parameter
// and need to make sure that the cost function is correct for
// large inputs.
#[cfg(feature = "runtime-benchmarks")]
pub const BENCHMARK_MAX_INCREASE: u32 = 1000;
#[cfg(not(feature = "runtime-benchmarks"))]
pub const BENCHMARK_MAX_INCREASE: u32 = 0;

/// Provides miscellaneous and common pallet-`Config` implementations for a `Runtime`.
#[macro_export]
macro_rules! misc_pallet_impls {
    () => {
        /// The BABE epoch configuration at genesis.
        pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
            sp_consensus_babe::BabeEpochConfiguration {
                c: PRIMARY_PROBABILITY,
                allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
            };

        /// Native version.
        #[cfg(any(feature = "std", test))]
        pub fn native_version() -> NativeVersion {
            NativeVersion {
                runtime_version: VERSION,
                can_author_with: Default::default(),
            }
        }

        use sp_runtime::{
            generic, impl_opaque_keys,
            traits::{SaturatedConversion as _, Saturating as _},
            ApplyExtrinsicResult, MultiSignature,
        };

        #[cfg(not(feature = "testing"))]
        type RuntimeBaseCallFilter = frame_support::traits::Everything;

        impl frame_system::Config for Runtime {
            /// The basic call filter to use in dispatchable.
            type BaseCallFilter = RuntimeBaseCallFilter;
            /// Block & extrinsics weights: base values and limits.
            type BlockWeights = polymesh_runtime_common::RuntimeBlockWeights;
            /// The maximum length of a block (in bytes).
            type BlockLength = polymesh_runtime_common::RuntimeBlockLength;
            /// The designated SS85 prefix of this chain.
            ///
            /// This replaces the "ss58Format" property declared in the chain spec. Reason is
            /// that the runtime should know about the prefix in order to make use of it as
            /// an identifier of the chain.
            type SS58Prefix = SS58Prefix;
            /// The identifier used to distinguish between accounts.
            type AccountId = polymesh_primitives::AccountId;
            /// The aggregated dispatch type that is available for extrinsics.
            type RuntimeCall = RuntimeCall;
            /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
            type Lookup = Indices;
            /// The index type for storing how many extrinsics an account has signed.
            type Index = polymesh_primitives::Index;
            /// The index type for blocks.
            type BlockNumber = polymesh_primitives::BlockNumber;
            /// The type for hashing blocks and tries.
            type Hash = polymesh_primitives::Hash;
            /// The hashing algorithm used.
            type Hashing = sp_runtime::traits::BlakeTwo256;
            /// The header type.
            type Header =
                sp_runtime::generic::Header<polymesh_primitives::BlockNumber, BlakeTwo256>;
            /// The ubiquitous event type.
            type RuntimeEvent = RuntimeEvent;
            /// The ubiquitous origin type.
            type RuntimeOrigin = RuntimeOrigin;
            /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
            type BlockHashCount = polymesh_runtime_common::BlockHashCount;
            /// The weight of database operations that the runtime can invoke.
            type DbWeight = polymesh_runtime_common::RocksDbWeight;
            /// Version of the runtime.
            type Version = Version;
            /// Converts a module to the index of the module in `construct_runtime!`.
            ///
            /// This type is being generated by `construct_runtime!`.
            type PalletInfo = PalletInfo;
            /// What to do if a new account is created.
            type OnNewAccount = ();
            /// What to do if an account is fully reaped from the system.
            type OnKilledAccount = ();
            /// The data to be stored in an account.
            type AccountData = polymesh_common_utilities::traits::balances::AccountData;
            type SystemWeightInfo = polymesh_weights::frame_system::SubstrateWeight;
            type OnSetCode = ();
            type MaxConsumers = frame_support::traits::ConstU32<16>;
        }

        impl pallet_base::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type MaxLen = MaxLen;
        }

        impl pallet_babe::Config for Runtime {
            type WeightInfo = polymesh_weights::pallet_babe::SubstrateWeight;
            type EpochDuration = EpochDuration;
            type ExpectedBlockTime = ExpectedBlockTime;
            type EpochChangeTrigger = pallet_babe::ExternalTrigger;
            type DisabledValidators = Session;

            type KeyOwnerProofSystem = Historical;

            type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
                sp_core::crypto::KeyTypeId,
                pallet_babe::AuthorityId,
            )>>::Proof;

            type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
                sp_core::crypto::KeyTypeId,
                pallet_babe::AuthorityId,
            )>>::IdentificationTuple;

            type HandleEquivocation = pallet_babe::EquivocationHandler<
                Self::KeyOwnerIdentification,
                Offences,
                ReportLongevity,
            >;
            type MaxAuthorities = MaxAuthorities;
        }

        impl pallet_indices::Config for Runtime {
            type AccountIndex = polymesh_primitives::AccountIndex;
            type Currency = Balances;
            type Deposit = IndexDeposit;
            type RuntimeEvent = RuntimeEvent;
            type WeightInfo = polymesh_weights::pallet_indices::SubstrateWeight;
        }

        impl<'a> core::convert::TryFrom<&'a RuntimeCall>
            for polymesh_runtime_common::fee_details::Call<'a, Runtime>
        {
            type Error = ();
            fn try_from(call: &'a RuntimeCall) -> Result<Self, ()> {
                use polymesh_runtime_common::fee_details::Call::*;
                Ok(match call {
                    RuntimeCall::Identity(x) => Identity(x),
                    RuntimeCall::MultiSig(x) => MultiSig(x),
                    RuntimeCall::Relayer(x) => Relayer(x),
                    _ => return Err(()),
                })
            }
        }

        impl RuntimeCall {
            fn get_actual_weight(&self) -> Option<Weight> {
                match self {
                    RuntimeCall::Settlement(x) => Settlement::get_actual_weight(x),
                    _ => None,
                }
            }
        }

        impl pallet_transaction_payment::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Currency = Balances;
            type OnChargeTransaction =
                pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
            type TransactionByteFee = polymesh_runtime_common::TransactionByteFee;
            type WeightToFee = polymesh_runtime_common::WeightToFee;
            type FeeMultiplierUpdate = ();
            type CddHandler = CddHandler;
            type Subsidiser = Relayer;
            type GovernanceCommittee = PolymeshCommittee;
            type CddProviders = CddServiceProviders;
            type Identity = Identity;
        }

        impl polymesh_common_utilities::traits::CommonConfig for Runtime {
            type BlockRewardsReserve = pallet_balances::Pallet<Runtime>;
        }

        impl pallet_balances::Config for Runtime {
            type MaxLocks = MaxLocks;
            type DustRemoval = ();
            type RuntimeEvent = RuntimeEvent;
            type ExistentialDeposit = ExistentialDeposit;
            type AccountStore = frame_system::Pallet<Runtime>;
            type CddChecker = polymesh_runtime_common::cdd_check::CddChecker<Runtime>;
            type WeightInfo = polymesh_weights::pallet_balances::SubstrateWeight;
        }

        impl pallet_protocol_fee::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Currency = Balances;
            type OnProtocolFeePayment = DealWithFees;
            type WeightInfo = polymesh_weights::pallet_protocol_fee::SubstrateWeight;
            type Subsidiser = Relayer;
        }

        impl pallet_timestamp::Config for Runtime {
            type Moment = polymesh_primitives::Moment;
            type OnTimestampSet = Babe;
            type MinimumPeriod = MinimumPeriod;
            type WeightInfo = polymesh_weights::pallet_timestamp::SubstrateWeight;
        }

        impl pallet_authorship::Config for Runtime {
            type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Babe>;
            type EventHandler = (Staking, ImOnline);
        }

        impl_opaque_keys! {
            pub struct SessionKeys {
                pub grandpa: Grandpa,
                pub babe: Babe,
                pub im_online: ImOnline,
                pub authority_discovery: AuthorityDiscovery,
            }
        }

        impl pallet_session::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type ValidatorId = polymesh_primitives::AccountId;
            type ValidatorIdOf = pallet_staking::StashOf<Self>;
            type ShouldEndSession = Babe;
            type NextSessionRotation = Babe;
            type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
            type SessionHandler =
                <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
            type Keys = SessionKeys;
            type WeightInfo = polymesh_weights::pallet_session::SubstrateWeight;
        }

        impl pallet_session::historical::Config for Runtime {
            type FullIdentification = pallet_staking::Exposure<
                polymesh_primitives::AccountId,
                polymesh_primitives::Balance,
            >;
            type FullIdentificationOf = pallet_staking::ExposureOf<Runtime>;
        }

        impl pallet_staking::Config for Runtime {
            type Currency = Balances;
            type CurrencyBalance = Balance;
            type UnixTime = Timestamp;
            type CurrencyToVote = frame_support::traits::U128CurrencyToVote;
            type ElectionProvider = ElectionProviderMultiPhase;
            type GenesisElectionProvider = Self::ElectionProvider;
            type MaxNominations = polymesh_runtime_common::MaxNominations;
            type HistoryDepth = polymesh_runtime_common::HistoryDepth;
            type RewardRemainder = ();
            type RuntimeEvent = RuntimeEvent;
            type Slash = Treasury; // send the slashed funds to the treasury.
            type Reward = (); // rewards are minted from the void
            type SessionsPerEra = SessionsPerEra;
            type BondingDuration = BondingDuration;
            type SlashDeferDuration = SlashDeferDuration;
            type AdminOrigin = polymesh_primitives::EnsureRoot;
            type SessionInterface = Self;
            type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
            type NextNewSession = Session;
            type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
            type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
            type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
            type TargetList = pallet_staking::UseValidatorsMap<Self>;
            type MaxUnlockingChunks = polymesh_runtime_common::MaxUnlockingChunks;
            type OnStakerSlash = pallet_staking::OnStakerSlashMock<Self>;
            type BenchmarkingConfig = pallet_staking::SampleBenchmarkingConfig;
            type WeightInfo = polymesh_weights::pallet_staking::SubstrateWeight;
            type MaxValidatorPerIdentity = polymesh_runtime_common::MaxValidatorPerIdentity;
            type MaxVariableInflationTotalIssuance = MaxVariableInflationTotalIssuance;
            type FixedYearlyReward = FixedYearlyReward;
            type Call = RuntimeCall;
            type PalletsOrigin = OriginCaller;
            type RewardScheduler = Scheduler;
        }

        impl pallet_authority_discovery::Config for Runtime {
            type MaxAuthorities = MaxAuthorities;
        }

        impl pallet_multisig::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Proposal = RuntimeCall;
            type WeightInfo = polymesh_weights::pallet_multisig::SubstrateWeight;
            type MaxSigners = MaxMultiSigSigners;
        }

        impl pallet_bridge::Config for Runtime {}

        impl pallet_portfolio::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Asset = Asset;
            type WeightInfo = polymesh_weights::pallet_portfolio::SubstrateWeight;
            type MaxNumberOfFungibleMoves = MaxNumberOfFungibleMoves;
            type MaxNumberOfNFTsMoves = MaxNumberOfNFTsMoves;
            type NFT = pallet_nft::Module<Runtime>;
        }

        impl pallet_external_agents::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type WeightInfo = polymesh_weights::pallet_external_agents::SubstrateWeight;
        }

        impl pallet_relayer::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type WeightInfo = polymesh_weights::pallet_relayer::SubstrateWeight;
        }

        impl pallet_asset::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Currency = Balances;
            type ComplianceManager = pallet_compliance_manager::Module<Runtime>;
            type UnixTime = pallet_timestamp::Pallet<Runtime>;
            type AssetNameMaxLength = AssetNameMaxLength;
            type FundingRoundNameMaxLength = FundingRoundNameMaxLength;
            type AssetMetadataNameMaxLength = AssetMetadataNameMaxLength;
            type AssetMetadataValueMaxLength = AssetMetadataValueMaxLength;
            type AssetMetadataTypeDefMaxLength = AssetMetadataTypeDefMaxLength;
            type AssetFn = Asset;
            type WeightInfo = polymesh_weights::pallet_asset::SubstrateWeight;
            type CPWeightInfo = polymesh_weights::pallet_checkpoint::SubstrateWeight;
            type NFTFn = pallet_nft::Module<Runtime>;
            type MaxAssetMediators = MaxAssetMediators;
        }

        impl polymesh_contracts::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type MaxInLen = MaxInLen;
            type MaxOutLen = MaxOutLen;
            type WeightInfo = polymesh_weights::polymesh_contracts::SubstrateWeight;
        }

        impl pallet_contracts::Config for Runtime {
            type Time = Timestamp;
            type Randomness = RandomnessCollectiveFlip;
            type Currency = Balances;
            type RuntimeEvent = RuntimeEvent;
            type RuntimeCall = RuntimeCall;
            // The `CallFilter` ends up being used in `ext.call_runtime()`,
            // via the `seal_call_runtime` feature,
            // which won't swap the current identity,
            // so we need `Nothing` to basically disable that feature.
            type CallFilter = frame_support::traits::Nothing;
            type DepositPerItem = polymesh_runtime_common::DepositPerItem;
            type DepositPerByte = polymesh_runtime_common::DepositPerByte;
            type CallStack = [pallet_contracts::Frame<Self>; 5];
            type WeightPrice = pallet_transaction_payment::Pallet<Self>;
            type WeightInfo = polymesh_weights::pallet_contracts::SubstrateWeight;
            type ChainExtension = polymesh_contracts::PolymeshExtension;
            type Schedule = Schedule;
            type DeletionQueueDepth = DeletionQueueDepth;
            type DeletionWeightLimit = DeletionWeightLimit;
            type AddressGenerator = pallet_contracts::DefaultAddressGenerator;
            #[cfg(not(feature = "runtime-benchmarks"))]
            type PolymeshHooks = polymesh_contracts::ContractPolymeshHooks;
            #[cfg(feature = "runtime-benchmarks")]
            type PolymeshHooks = polymesh_contracts::benchmarking::BenchmarkContractPolymeshHooks;
            type MaxCodeLen = frame_support::traits::ConstU32<{ 123 * 1024 }>;
            type MaxStorageKeyLen = frame_support::traits::ConstU32<128>;
            type UnsafeUnstableInterface = frame_support::traits::ConstBool<false>;
            type MaxDebugBufferLen = frame_support::traits::ConstU32<{ 2 * 1024 * 1024 }>;
        }

        impl pallet_compliance_manager::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Asset = Asset;
            type WeightInfo = polymesh_weights::pallet_compliance_manager::SubstrateWeight;
            type MaxConditionComplexity = MaxConditionComplexity;
        }

        impl pallet_corporate_actions::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type MaxTargetIds = MaxTargetIds;
            type MaxDidWhts = MaxDidWhts;
            type WeightInfo = polymesh_weights::pallet_corporate_actions::SubstrateWeight;
            type BallotWeightInfo = polymesh_weights::pallet_corporate_ballot::SubstrateWeight;
            type DistWeightInfo = polymesh_weights::pallet_capital_distribution::SubstrateWeight;
        }

        impl pallet_statistics::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Asset = Asset;
            type MaxStatsPerAsset = MaxStatsPerAsset;
            type MaxTransferConditionsPerAsset = MaxTransferConditionsPerAsset;
            type WeightInfo = polymesh_weights::pallet_statistics::SubstrateWeight;
        }

        impl pallet_utility::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type RuntimeCall = RuntimeCall;
            type PalletsOrigin = OriginCaller;
            type WeightInfo = polymesh_weights::pallet_utility::SubstrateWeight;
        }

        impl pallet_scheduler::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type RuntimeOrigin = RuntimeOrigin;
            type PalletsOrigin = OriginCaller;
            type RuntimeCall = RuntimeCall;
            type MaximumWeight = MaximumSchedulerWeight;
            type ScheduleOrigin = polymesh_primitives::EnsureRoot;
            type MaxScheduledPerBlock = MaxScheduledPerBlock;
            type WeightInfo = polymesh_weights::pallet_scheduler::SubstrateWeight;
            type OriginPrivilegeCmp = frame_support::traits::EqualPrivilegeOnly;
            type Preimages = Preimage;
        }

        parameter_types! {
            pub const PreimageMaxSize: u32 = 4096 * 1024;
            pub const PreimageBaseDeposit: Balance = polymesh_runtime_common::deposit(2, 64);
            pub const PreimageByteDeposit: Balance = polymesh_runtime_common::deposit(0, 1);
        }

        impl pallet_preimage::Config for Runtime {
            type WeightInfo = polymesh_weights::pallet_preimage::SubstrateWeight;
            type RuntimeEvent = RuntimeEvent;
            type Currency = Balances;
            type ManagerOrigin = polymesh_primitives::EnsureRoot;
            type BaseDeposit = PreimageBaseDeposit;
            type ByteDeposit = PreimageByteDeposit;
        }

        impl pallet_offences::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
            type OnOffenceHandler = Staking;
        }

        type GrandpaKey = (sp_core::crypto::KeyTypeId, pallet_grandpa::AuthorityId);

        impl pallet_im_online::Config for Runtime {
            type AuthorityId = pallet_im_online::sr25519::AuthorityId;
            type RuntimeEvent = RuntimeEvent;
            type NextSessionRotation = Babe;
            type ValidatorSet = Historical;
            type UnsignedPriority = ImOnlineUnsignedPriority;
            type ReportUnresponsiveness = Offences;
            type WeightInfo = polymesh_weights::pallet_im_online::SubstrateWeight;
            type MaxKeys = MaxKeys;
            type MaxPeerInHeartbeats = MaxPeerInHeartbeats;
            type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize;
        }

        impl pallet_grandpa::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;

            type KeyOwnerProofSystem = Historical;

            type KeyOwnerProof =
                <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<GrandpaKey>>::Proof;

            type KeyOwnerIdentification =
                <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<GrandpaKey>>::IdentificationTuple;

            type HandleEquivocation = pallet_grandpa::EquivocationHandler<
                Self::KeyOwnerIdentification,
                Offences,
                ReportLongevity,
            >;

            type WeightInfo = ();
            type MaxAuthorities = MaxAuthorities;
            type MaxSetIdSessionEntries = MaxSetIdSessionEntries;
        }

        impl pallet_insecure_randomness_collective_flip::Config for Runtime {}

        impl pallet_treasury::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Currency = Balances;
            type WeightInfo = polymesh_weights::pallet_treasury::SubstrateWeight;
        }

        impl pallet_settlement::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type Proposal = RuntimeCall;
            type Scheduler = Scheduler;
            type WeightInfo = polymesh_weights::pallet_settlement::SubstrateWeight;
            type MaxNumberOfFungibleAssets = MaxNumberOfFungibleAssets;
            type MaxNumberOfNFTsPerLeg = MaxNumberOfNFTsPerLeg;
            type MaxNumberOfNFTs = MaxNumberOfNFTs;
            type MaxNumberOfOffChainAssets = MaxNumberOfOffChainAssets;
            type MaxNumberOfPortfolios = MaxNumberOfPortfolios;
            type MaxNumberOfVenueSigners = MaxNumberOfVenueSigners;
            type MaxInstructionMediators = MaxInstructionMediators;
        }

        impl pallet_sto::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type WeightInfo = polymesh_weights::pallet_sto::SubstrateWeight;
        }

        impl polymesh_common_utilities::traits::permissions::Config for Runtime {
            type Checker = Identity;
        }

        impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
        where
            RuntimeCall: From<LocalCall>,
        {
            fn create_transaction<
                C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>,
            >(
                call: RuntimeCall,
                public: <polymesh_primitives::Signature as Verify>::Signer,
                account: polymesh_primitives::AccountId,
                nonce: polymesh_primitives::Index,
            ) -> Option<(
                RuntimeCall,
                <UncheckedExtrinsic as Extrinsic>::SignaturePayload,
            )> {
                // take the biggest period possible.
                let period = polymesh_runtime_common::BlockHashCount::get()
                    .checked_next_power_of_two()
                    .map(|c| c / 2)
                    .unwrap_or(2) as u64;
                let current_block = System::block_number()
                    .saturated_into::<u64>()
                    // The `System::block_number` is initialized with `n+1`,
                    // so the actual block number is `n`.
                    .saturating_sub(1);
                let tip = 0;
                let extra: SignedExtra = (
                    frame_system::CheckSpecVersion::new(),
                    frame_system::CheckTxVersion::new(),
                    frame_system::CheckGenesis::new(),
                    frame_system::CheckEra::from(generic::Era::mortal(period, current_block)),
                    frame_system::CheckNonce::from(nonce),
                    polymesh_extensions::CheckWeight::new(),
                    pallet_transaction_payment::ChargeTransactionPayment::from(tip),
                    pallet_permissions::StoreCallMetadata::new(),
                );
                let raw_payload = SignedPayload::new(call, extra)
                    .map_err(|e| {
                        log::warn!("Unable to create signed payload: {:?}", e);
                    })
                    .ok()?;
                let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
                let address = Indices::unlookup(account);
                let (call, extra, _) = raw_payload.deconstruct();
                Some((call, (address, signature, extra)))
            }
        }

        impl frame_system::offchain::SigningTypes for Runtime {
            type Public = <polymesh_primitives::Signature as Verify>::Signer;
            type Signature = polymesh_primitives::Signature;
        }

        impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
        where
            RuntimeCall: From<C>,
        {
            type Extrinsic = UncheckedExtrinsic;
            type OverarchingCall = RuntimeCall;
        }

        impl pallet_nft::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            type WeightInfo = polymesh_weights::pallet_nft::SubstrateWeight;
            type Compliance = pallet_compliance_manager::Module<Runtime>;
            type MaxNumberOfCollectionKeys = MaxNumberOfCollectionKeys;
            type MaxNumberOfNFTsCount = MaxNumberOfNFTsPerLeg;
        }

        impl pallet_election_provider_multi_phase::Config for Runtime {
            type RuntimeEvent = RuntimeEvent;
            // Currency type
            type Currency = Balances;
            // Something that can estimate the fee of a call (used when submitting a solution for the signed phase)
            type EstimateCallFee = polymesh_runtime_common::impls::EstimateCallFeeMax;
            // Duration of the unsigned phase
            type UnsignedPhase = UnsignedPhase;
            #[cfg(not(feature = "runtime-benchmarks"))]
            // Duration of the signed phase
            type SignedPhase = polymesh_runtime_common::SignedPhase;
            #[cfg(feature = "runtime-benchmarks")]
            type SignedPhase = polymesh_runtime_common::SignedPhaseBench;
            // The minimum amount of improvement to the solution score in the Signed phase
            type BetterSignedThreshold = ();
            // The minimum amount of improvement to the solution score in the Unsigned phase
            type BetterUnsignedThreshold = polymesh_runtime_common::BetterUnsignedThreshold;
            // The repeat threshold of the offchain worker
            type OffchainRepeat = polymesh_runtime_common::OffChainRepeat;
            // The priority of the unsigned transaction submitted in the unsigned-phase
            type MinerTxPriority = polymesh_runtime_common::MultiPhaseUnsignedPriority;
            // Configurations of the embedded miner
            type MinerConfig = Self;
            // Maximum number of signed submissions that can be queued
            type SignedMaxSubmissions = polymesh_runtime_common::SignedMaxSubmissions;
            // Maximum weight of a signed solution
            type SignedMaxWeight = polymesh_runtime_common::SignedMaxWeight;
            // The maximum amount of unchecked solutions to refund the call fee for
            type SignedMaxRefunds = polymesh_runtime_common::SignedMaxRefunds;
            // Base reward for a signed solution
            type SignedRewardBase = polymesh_runtime_common::SignedRewardBase;
            // Base deposit for a signed solution
            type SignedDepositBase = polymesh_runtime_common::SignedDepositBase;
            // Per-byte deposit for a signed solution
            type SignedDepositByte = polymesh_runtime_common::SignedDepositByte;
            // Per-weight deposit for a signed solution
            type SignedDepositWeight = ();
            // The maximum number of electing voters to put in the snapshot
            type MaxElectingVoters = polymesh_runtime_common::MaxElectingVoters;
            // The maximum number of electable targets to put in the snapshot
            type MaxElectableTargets = polymesh_runtime_common::MaxElectableTargets;
            // The maximum number of winners that can be elected by this `ElectionProvider` implementation
            type MaxWinners = polymesh_runtime_common::MaxActiveValidators;
            // Handler for the slashed deposits
            type SlashHandler = ();
            // Handler for the rewards
            type RewardHandler = ();
            // Something that will provide the election data
            type DataProvider = Staking;
            // Configuration for the fallback
            type Fallback = frame_election_provider_support::onchain::OnChainExecution<OnChainSeqPhragmen>;
            // Configuration of the governance-only fallback
            type GovernanceFallback =
                frame_election_provider_support::onchain::OnChainExecution<OnChainSeqPhragmen>;
            // OCW election solution miner algorithm implementation
            type Solver = frame_election_provider_support::SequentialPhragmen<
                polymesh_primitives::AccountId,
                pallet_election_provider_multi_phase::SolutionAccuracyOf<Self>,
                polymesh_runtime_common::impls::OffchainRandomBalancing,
            >;
            // Origin that can control this pallet
            type ForceOrigin = polymesh_primitives::EnsureRoot;
            // The configuration of benchmarking
            type BenchmarkingConfig =
                polymesh_runtime_common::impls::ElectionProviderBenchmarkConfig;
            // The weight of the pallet.
            type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight<Self>;
        }

        impl pallet_election_provider_multi_phase::MinerConfig for Runtime {
            type AccountId = polymesh_primitives::AccountId;
	        type MaxLength = polymesh_runtime_common::MinerMaxLength;
	        type MaxWeight = polymesh_runtime_common::MinerMaxWeight;
	        type Solution = polymesh_runtime_common::NposSolution16;
	        type MaxVotesPerVoter =
	            <<Self as pallet_election_provider_multi_phase::Config>::DataProvider as frame_election_provider_support::ElectionDataProvider>::MaxVotesPerVoter;

	        // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their
	        // weight estimate function is wired to this call's weight.
	        fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight {
	        	<
	        		<Self as pallet_election_provider_multi_phase::Config>::WeightInfo
	        		as
	        		pallet_election_provider_multi_phase::WeightInfo
	        	>::submit_unsigned(v, t, a, d)
	        }
        }
    };
}

/// Defines API implementations, e.g., for RPCs, and type aliases, for a `Runtime`.
#[macro_export]
macro_rules! runtime_apis {
    ($($extra:item)*) => {
        use frame_support::dispatch::{GetStorageVersion, DispatchError};
        use sp_inherents::{CheckInherentsResult, InherentData};
        use frame_support::dispatch::result::Result as FrameResult;
        use node_rpc_runtime_api::asset as rpc_api_asset;

        use pallet_identity::types::{AssetDidResult, CddStatus, RpcDidRecords, DidStatus, KeyIdentityData};
        use pallet_pips::{Vote, VoteCount};
        use pallet_protocol_fee_rpc_runtime_api::CappedFee;
        use polymesh_primitives::asset::AssetId;
        use polymesh_primitives::settlement::{InstructionId, ExecuteInstructionInfo, AffirmationCount};
        use polymesh_primitives::transfer_compliance::TransferCondition;
        use polymesh_primitives::compliance_manager::{AssetComplianceResult, ComplianceReport};
        use polymesh_primitives::{
            asset::CheckpointId, IdentityId, Index, NFTs,PortfolioId, Signatory, Ticker,
            WeightMeter, IdentityClaim
        };

        /// The address format for describing accounts.
        pub type Address = <Indices as StaticLookup>::Source;
        /// Block header type as expected by this runtime.
        pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
        /// Block type as expected by this runtime.
        pub type Block = generic::Block<Header, UncheckedExtrinsic>;
        /// A Block signed with a Justification
        pub type SignedBlock = generic::SignedBlock<Block>;
        /// BlockId type as expected by this runtime.
        pub type BlockId = generic::BlockId<Block>;
        /// The SignedExtension to the basic transaction logic.
        pub type SignedExtra = (
            frame_system::CheckSpecVersion<Runtime>,
            frame_system::CheckTxVersion<Runtime>,
            frame_system::CheckGenesis<Runtime>,
            frame_system::CheckEra<Runtime>,
            frame_system::CheckNonce<Runtime>,
            polymesh_extensions::CheckWeight<Runtime>,
            pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
            pallet_permissions::StoreCallMetadata<Runtime>,
        );
        /// Unchecked extrinsic type as expected by this runtime.
        pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, RuntimeCall, polymesh_primitives::Signature, SignedExtra>;
        /// The payload being signed in transactions.
        pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
        /// Extrinsic type that has already been checked.
        pub type CheckedExtrinsic = generic::CheckedExtrinsic<polymesh_primitives::AccountId, RuntimeCall, SignedExtra>;
        /// Executive: handles dispatch to the various modules.
        pub type Executive = pallet_executive::Executive<
            Runtime,
            Block,
            frame_system::ChainContext<Runtime>,
            Runtime,
            AllPalletsWithSystem,
            (
              pallet_scheduler::migration::v4::CleanupAgendas<Runtime>,
              pallet_contracts::Migration<Runtime>,
            )
        >;

        sp_api::impl_runtime_apis! {
            impl sp_api::Core<Block> for Runtime {
                fn version() -> RuntimeVersion {
                    VERSION
                }

                fn execute_block(block: Block) {
                    Executive::execute_block(block)
                }

                fn initialize_block(header: &<Block as BlockT>::Header) {
                    Executive::initialize_block(header)
                }
            }

            impl sp_api::Metadata<Block> for Runtime {
                fn metadata() -> sp_core::OpaqueMetadata {
                    sp_core::OpaqueMetadata::new(Runtime::metadata().into())
                }
            }

            impl sp_block_builder::BlockBuilder<Block> for Runtime {
                fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
                    Executive::apply_extrinsic(extrinsic)
                }

                fn finalize_block() -> <Block as BlockT>::Header {
                    Executive::finalize_block()
                }

                fn inherent_extrinsics(data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
                    data.create_extrinsics()
                }

                fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult {
                    data.check_extrinsics(&block)
                }
            }

            impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
                fn validate_transaction(
                    source: sp_runtime::transaction_validity::TransactionSource,
                    tx: <Block as BlockT>::Extrinsic,
                    block_hash: <Block as BlockT>::Hash,
                ) -> sp_runtime::transaction_validity::TransactionValidity {
                    Executive::validate_transaction(source, tx, block_hash)
                }
            }

            impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
                fn offchain_worker(header: &<Block as BlockT>::Header) {
                    Executive::offchain_worker(header)
                }
            }

            impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
                fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList {
                    Grandpa::grandpa_authorities()
                }

                fn submit_report_equivocation_unsigned_extrinsic(
                    equivocation_proof: sp_consensus_grandpa::EquivocationProof<
                        <Block as BlockT>::Hash,
                        NumberFor<Block>,
                    >,
                    key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
                ) -> Option<()> {
                    let key_owner_proof = key_owner_proof.decode()?;

                    Grandpa::submit_unsigned_equivocation_report(
                        equivocation_proof,
                        key_owner_proof,
                    )
                }

                fn generate_key_ownership_proof(
                    _set_id: sp_consensus_grandpa::SetId,
                    authority_id: pallet_grandpa::AuthorityId,
                ) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
                    use codec::Encode;

                    Historical::prove((sp_consensus_grandpa::KEY_TYPE, authority_id))
                        .map(|p| p.encode())
                        .map(sp_consensus_grandpa::OpaqueKeyOwnershipProof::new)
                }

                fn current_set_id() -> sp_consensus_grandpa::SetId {
                    Grandpa::current_set_id()
                }
            }

            impl sp_consensus_babe::BabeApi<Block> for Runtime {
                fn configuration() -> sp_consensus_babe::BabeConfiguration {
                    let epoch_config = Babe::epoch_config().unwrap_or(BABE_GENESIS_EPOCH_CONFIG);
                    sp_consensus_babe::BabeConfiguration {
                        slot_duration: Babe::slot_duration(),
                        epoch_length: EpochDuration::get(),
                        c: epoch_config.c,
                        authorities: Babe::authorities().to_vec(),
                        randomness: Babe::randomness(),
                        allowed_slots: epoch_config.allowed_slots,
                    }
                }

                fn current_epoch_start() -> sp_consensus_babe::Slot{
                    Babe::current_epoch_start()
                }

                fn current_epoch() -> sp_consensus_babe::Epoch {
                    Babe::current_epoch()
                }

                fn next_epoch() -> sp_consensus_babe::Epoch {
                    Babe::next_epoch()
                }

                fn generate_key_ownership_proof(
                    _slot: sp_consensus_babe::Slot,
                    authority_id: sp_consensus_babe::AuthorityId,
                ) -> Option<sp_consensus_babe::OpaqueKeyOwnershipProof> {
                    use codec::Encode;

                    Historical::prove((sp_consensus_babe::KEY_TYPE, authority_id))
                        .map(|p| p.encode())
                        .map(sp_consensus_babe::OpaqueKeyOwnershipProof::new)
                }

                fn submit_report_equivocation_unsigned_extrinsic(
                    equivocation_proof: sp_consensus_babe::EquivocationProof<<Block as BlockT>::Header>,
                    key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof,
                ) -> Option<()> {
                    let key_owner_proof = key_owner_proof.decode()?;

                    Babe::submit_unsigned_equivocation_report(
                        equivocation_proof,
                        key_owner_proof,
                    )
                }
            }

            impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
                fn authorities() -> Vec<sp_authority_discovery::AuthorityId> {
                    AuthorityDiscovery::authorities()
                }
            }

            impl frame_system_rpc_runtime_api::AccountNonceApi<Block, polymesh_primitives::AccountId, Index> for Runtime {
                fn account_nonce(account: polymesh_primitives::AccountId) -> Index {
                    System::account_nonce(account)
                }
            }

            impl pallet_contracts::ContractsApi<
                Block,
                polymesh_primitives::AccountId,
                Balance,
                BlockNumber,
                polymesh_primitives::Hash,
            > for Runtime {
                fn call(
                    origin: polymesh_primitives::AccountId,
                    dest: polymesh_primitives::AccountId,
                    value: Balance,
                    gas_limit: Option<Weight>,
                    storage_deposit_limit: Option<Balance>,
                    input_data: Vec<u8>,
                ) -> pallet_contracts_primitives::ContractExecResult<Balance> {
                    let gas_limit = gas_limit.unwrap_or(polymesh_runtime_common::RuntimeBlockWeights::get().max_block);
                    Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true, pallet_contracts::Determinism::Deterministic)
                }

                fn instantiate(
                    origin: polymesh_primitives::AccountId,
                    value: Balance,
                    gas_limit: Option<Weight>,
                    storage_deposit_limit: Option<Balance>,
                    code: pallet_contracts_primitives::Code<polymesh_primitives::Hash>,
                    data: Vec<u8>,
                    salt: Vec<u8>,
                ) -> pallet_contracts_primitives::ContractInstantiateResult<polymesh_primitives::AccountId, Balance> {
                    let gas_limit = gas_limit.unwrap_or(polymesh_runtime_common::RuntimeBlockWeights::get().max_block);
                    Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true)
                }

                fn upload_code(
                    origin: polymesh_primitives::AccountId,
                    code: Vec<u8>,
                    storage_deposit_limit: Option<Balance>,
                    determinism: pallet_contracts::Determinism,
                ) -> pallet_contracts_primitives::CodeUploadResult<polymesh_primitives::Hash, Balance> {
                    Contracts::bare_upload_code(origin, code, storage_deposit_limit, determinism)
                }

                fn get_storage(
                    address: polymesh_primitives::AccountId,
                    key: Vec<u8>,
                ) -> pallet_contracts_primitives::GetStorageResult {
                    Contracts::get_storage(address, key)
                }
            }

            impl node_rpc_runtime_api::transaction_payment::TransactionPaymentApi<
                Block,
            > for Runtime {
                fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {
                    let actual = uxt.function.get_actual_weight();
                    TransactionPayment::query_info(uxt, len, actual)
                }

                fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> pallet_transaction_payment::FeeDetails<Balance> {
                    let actual = uxt.function.get_actual_weight();
                    TransactionPayment::query_fee_details(uxt, len, actual)
                }
            }

            impl node_rpc_runtime_api::transaction_payment::TransactionPaymentCallApi<Block, RuntimeCall>
                for Runtime
            {
                fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo<Balance> {
                    let actual = call.get_actual_weight();
                    TransactionPayment::query_call_info(call, len, actual)
                }
                fn query_call_fee_details(call: RuntimeCall, len: u32) -> pallet_transaction_payment::FeeDetails<Balance> {
                    let actual = call.get_actual_weight();
                    TransactionPayment::query_call_fee_details(call, len, actual)
                }
            }

            impl sp_session::SessionKeys<Block> for Runtime {
                fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
                    SessionKeys::generate(seed)
                }

                fn decode_session_keys(
                    encoded: Vec<u8>,
                ) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
                    SessionKeys::decode_into_raw_public_keys(&encoded)
                }
            }

            impl pallet_staking_rpc_runtime_api::StakingApi<Block> for Runtime {
                fn get_curve() -> Vec<(Perbill, Perbill)> {
                    RewardCurve::get().points.to_vec()
                }
            }

            impl node_rpc_runtime_api::pips::PipsApi<Block, polymesh_primitives::AccountId>
            for Runtime
            {
                /// Vote count for the PIP identified by `id`.
                fn get_votes(id: pallet_pips::PipId) -> VoteCount {
                    Pips::get_votes(id)
                }

                /// PIPs voted on by `address`.
                fn proposed_by(address: polymesh_primitives::AccountId) -> Vec<pallet_pips::PipId> {
                    Pips::proposed_by(pallet_pips::Proposer::Community(address))
                }

                /// PIPs `address` voted on.
                fn voted_on(address: polymesh_primitives::AccountId) -> Vec<pallet_pips::PipId> {
                    Pips::voted_on(address)
                }
            }

            impl pallet_protocol_fee_rpc_runtime_api::ProtocolFeeApi<
                Block,
            > for Runtime {
                fn compute_fee(op: ProtocolOp) -> CappedFee {
                    ProtocolFee::compute_fee(&[op]).into()
                }
            }

            impl
                node_rpc_runtime_api::identity::IdentityApi<
                    Block,
                    IdentityId,
                    Ticker,
                    polymesh_primitives::AccountId,
                    Moment
                > for Runtime
            {
                /// RPC call to know whether the given did has valid cdd claim or not
                fn is_identity_has_valid_cdd(did: IdentityId, leeway: Option<u64>) -> CddStatus {
                    Identity::fetch_cdd(did, leeway.unwrap_or_default())
                        .ok_or_else(|| "Either cdd claim is expired or not yet provided to give identity".into())
                }

                /// Retrieve primary key and secondary keys for a given IdentityId
                fn get_did_records(did: IdentityId) -> RpcDidRecords<polymesh_primitives::AccountId> {
                    Identity::get_did_records(did)
                }

                /// Retrieve the status of the DIDs
                fn get_did_status(dids: Vec<IdentityId>) -> Vec<DidStatus> {
                    Identity::get_did_status(dids)
                }

                fn get_key_identity_data(acc: polymesh_primitives::AccountId) -> Option<KeyIdentityData<IdentityId>> {
                    Identity::get_key_identity_data(acc)
                }

                /// Retrieve list of a authorization for a given signatory
                fn get_filtered_authorizations(
                    signatory: Signatory<polymesh_primitives::AccountId>,
                    allow_expired: bool,
                    auth_type: Option<polymesh_primitives::AuthorizationType>
                ) -> Vec<polymesh_primitives::Authorization<polymesh_primitives::AccountId, Moment>> {
                    Identity::get_filtered_authorizations(signatory, allow_expired, auth_type)
                }

                /// Returns all valid [`IdentityClaim`] of type `CustomerDueDiligence` for the given `target_identity`.
                fn valid_cdd_claims(target_identity: IdentityId, cdd_checker_leeway: Option<u64>) -> Vec<IdentityClaim> {
                    Identity::valid_cdd_claims(target_identity, cdd_checker_leeway)
                }
            }

            impl rpc_api_asset::AssetApi<Block> for Runtime {
                fn transfer_report(
                    sender_portfolio: PortfolioId,
                    receiver_portfolio: PortfolioId,
                    asset_id: AssetId,
                    transfer_value: Balance,
                    skip_locked_check: bool,
                ) -> Vec<DispatchError> {
                    let mut weight_meter = WeightMeter::max_limit_no_minimum();
                    Asset::asset_transfer_report(
                        &sender_portfolio,
                        &receiver_portfolio,
                        &asset_id,
                        transfer_value,
                        skip_locked_check,
                        &mut weight_meter
                    )
                }
            }

            impl pallet_group_rpc_runtime_api::GroupApi<Block> for Runtime {
                fn get_cdd_valid_members() -> Vec<pallet_group_rpc_runtime_api::Member> {
                    merge_active_and_inactive::<Block>(
                        CddServiceProviders::active_members(),
                        CddServiceProviders::inactive_members())
                }

                fn get_gc_valid_members() -> Vec<pallet_group_rpc_runtime_api::Member> {
                    merge_active_and_inactive::<Block>(
                        CommitteeMembership::active_members(),
                        CommitteeMembership::inactive_members())
                }
            }

            impl node_rpc_runtime_api::nft::NFTApi<Block> for Runtime {
                #[inline]
                fn transfer_report(
                    sender_portfolio: PortfolioId,
                    receiver_portfolio: PortfolioId,
                    nfts: NFTs,
                    skip_locked_check: bool,
                ) -> Vec<DispatchError> {
                    let mut weight_meter = WeightMeter::max_limit_no_minimum();
                    Nft::nft_transfer_report(
                        &sender_portfolio,
                        &receiver_portfolio,
                        &nfts,
                        skip_locked_check,
                        &mut weight_meter
                    )
                }
            }

            impl node_rpc_runtime_api::settlement::SettlementApi<Block> for Runtime {
                #[inline]
                fn get_execute_instruction_info(
                    instruction_id: &InstructionId
                ) -> Option<ExecuteInstructionInfo> {
                    Settlement::execute_instruction_info(instruction_id)
                }

                #[inline]
                fn get_affirmation_count(
                    instruction_id: InstructionId,
                    portfolios: Vec<PortfolioId>,
                ) -> AffirmationCount {
                    Settlement::affirmation_count(instruction_id, portfolios)
                }

                #[inline]
                fn get_transfer_report(leg: Leg, skip_locked_check: bool) -> Vec<DispatchError> {
                    let mut weight_meter = WeightMeter::max_limit_no_minimum();
                    Settlement::transfer_report(leg, skip_locked_check, &mut weight_meter)
                }

                #[inline]
                fn get_execute_instruction_report(instruction_id: InstructionId) -> Vec<DispatchError> {
                    let mut weight_meter = WeightMeter::max_limit_no_minimum();
                    Settlement::execute_instruction_report(&instruction_id, &mut weight_meter)
                }

            }

            impl node_rpc_runtime_api::compliance::ComplianceApi<Block> for Runtime {
                #[inline]
                fn compliance_report(
                    asset_id: &AssetId,
                    sender_identity: &IdentityId,
                    receiver_identity: &IdentityId,
                ) -> FrameResult<ComplianceReport, DispatchError> {
                    let mut weight_meter = WeightMeter::max_limit_no_minimum();
                    ComplianceManager::compliance_report(
                        asset_id,
                        sender_identity,
                        receiver_identity,
                        &mut weight_meter
                    )
                }
            }

            impl node_rpc_runtime_api::statistics::StatisticsApi<Block> for Runtime {
                #[inline]
                fn transfer_restrictions_report(
                    asset_id: AssetId,
                    sender_did: &IdentityId,
                    receiver_did: &IdentityId,
                    transfer_amount: Balance,
                ) -> FrameResult<Vec<TransferCondition>, DispatchError> {
                    let mut weight_meter = WeightMeter::max_limit_no_minimum();
                    Statistics::transfer_restrictions_report(
                        asset_id,
                        sender_did,
                        receiver_did,
                        transfer_amount,
                        &mut weight_meter
                    )
                }
            }

            $($extra)*
        }
    }
}
