code/pallets/subtensor/src/lib.rs

lib.rs

3,031 lines · 105,966 bytes · 19a6485969RawGitHub
#![cfg_attr(not(feature = "std"), no_std)]
#![recursion_limit = "512"]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::zero_prefixed_literal)]
// Edit this file to define custom logic or remove it if it is not needed.
// Learn more about FRAME and the core library of Substrate FRAME pallets:
// <https://docs.substrate.io/reference/frame-pallets/>

use frame_system::{self as system, ensure_signed};
pub use pallet::*;

use codec::{Decode, Encode};
use frame_support::{
    dispatch::{self, DispatchResult, DispatchResultWithPostInfo},
    ensure,
    pallet_macros::import_section,
    pallet_prelude::*,
    traits::tokens::fungible,
    weights::WeightMeter,
};
use scale_info::TypeInfo;
use sp_core::Get;
use sp_runtime::{DispatchError, PerU16};
use sp_std::marker::PhantomData;
use subtensor_runtime_common::{AlphaBalance, NetUid, TaoBalance, Token, TokenReserve};

// ============================
//	==== Benchmark Imports =====
// ============================
mod benchmarks;

// =========================
//	==== Pallet Imports =====
// =========================
pub mod coinbase;
pub mod epoch;
pub mod extensions;
pub mod guards;
pub mod macros;
pub mod migrations;
pub mod rpc_info;
pub mod staking;
pub mod subnets;
pub mod swap;
pub mod utils;
pub mod weights;
use crate::utils::rate_limiting::{Hyperparameter, TransactionType};
use macros::{config, dispatches, errors, events, genesis, hooks};

pub use extensions::*;
pub use guards::*;

#[cfg(test)]
pub(crate) mod tests;

// apparently this is stabilized since rust 1.36
extern crate alloc;

pub type OriginFor<T> = <T as frame_system::Config>::RuntimeOrigin;

pub const MAX_CRV3_COMMIT_SIZE_BYTES: u32 = 5000;

pub const ALPHA_MAP_BATCH_SIZE: usize = 30;

pub const MAX_NUM_ROOT_CLAIMS: u64 = 50;

pub const MAX_SUBNET_CLAIMS: usize = 5;

pub const MAX_ROOT_CLAIM_THRESHOLD: u64 = 10_000_000;

pub struct SubtensorDustRemoval<T>(PhantomData<T>);
impl<T> frame_support::traits::OnUnbalanced<pallet_balances::CreditOf<T, ()>>
    for SubtensorDustRemoval<T>
where
    T: Config + pallet_balances::Config,
    <T as pallet_balances::Config>::Balance: Into<TaoBalance> + Copy,
{
    fn on_nonzero_unbalanced(dust: pallet_balances::CreditOf<T, ()>) {
        let amount: TaoBalance = frame_support::traits::Imbalance::peek(&dust).into();
        TotalIssuance::<T>::mutate(|total| {
            *total = total.saturating_sub(amount);
        });
    }
}

/// Maximum number of UIDs (per subnet) that may be associated with a single EVM address.
///
/// This bounds the size of the `AssociatedUidsByEvmAddress` reverse-index value, keeping
/// `uid_lookup` reads and association writes cheap and their PoV footprint small. Only the
/// holder of an EVM key's private key can grow its bucket (each association requires a
/// signature from that key), so this only limits how many of one's own UIDs may point at a
/// single EVM address.
pub const MAX_ASSOCIATED_UIDS_PER_EVM_ADDRESS: u32 = 32;

/// Account flag bit that opts into receiving locked alpha transfers.
pub const ACCOUNT_FLAGS_ACCEPT_LOCKED_ALPHA: u128 = 1u128 << 0;

#[allow(deprecated)]
#[deny(missing_docs)]
#[import_section(errors::errors)]
#[import_section(events::events)]
#[import_section(dispatches::dispatches)]
#[import_section(genesis::genesis)]
#[import_section(hooks::hooks)]
#[import_section(config::config)]
#[frame_support::pallet]
#[allow(clippy::expect_used)]
pub mod pallet {
    use crate::migrations;
    use crate::staking::lock::LockState;
    use crate::subnets::dissolution::DissolveCleanupStatus;
    use crate::subnets::leasing::{LeaseId, SubnetLeaseOf};
    use crate::subnets::subnet::NetworkRegistrationInfo;
    use crate::weights::WeightInfo;
    use crate::{MAX_ASSOCIATED_UIDS_PER_EVM_ADDRESS, RateLimitKey};
    use frame_support::Twox64Concat;
    use frame_support::{
        BoundedVec,
        dispatch::GetDispatchInfo,
        pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *},
        traits::{
            OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, tokens::fungible,
        },
        weights::Weight,
    };
    use frame_system::pallet_prelude::*;
    use pallet_drand::types::RoundNumber;
    use runtime_common::prod_or_fast;
    use share_pool::SafeFloat;
    use sp_core::{ConstU32, H160, H256};
    use sp_runtime::PerU16;
    use sp_runtime::traits::{Dispatchable, TrailingZeroInput};
    use sp_std::collections::btree_map::BTreeMap;
    use sp_std::collections::btree_set::BTreeSet;
    use sp_std::collections::vec_deque::VecDeque;
    use sp_std::vec;
    use sp_std::vec::Vec;
    use substrate_fixed::types::{I64F64, I96F32, U64F64, U96F32};
    use subtensor_macros::freeze_struct;
    use subtensor_runtime_common::{
        AlphaBalance, MechId, NetUid, NetUidStorageIndex, TaoBalance, Token,
    };

    /// Origin for the pallet
    pub type PalletsOriginOf<T> =
        <<T as frame_system::Config>::RuntimeOrigin as OriginTrait>::PalletsOrigin;

    /// Call type for the pallet
    pub type CallOf<T> = <T as frame_system::Config>::RuntimeCall;

    /// Tracks version for migrations. Should be monotonic with respect to the
    /// order of migrations. (i.e. always increasing)
    const STORAGE_VERSION: StorageVersion = StorageVersion::new(7);

    /// Minimum balance required to perform a coldkey swap
    pub const MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP: TaoBalance = TaoBalance::new(100_000_000); // 0.1 TAO in RAO

    /// Minimum commit reveal periods
    pub const MIN_COMMIT_REVEAL_PEROIDS: u64 = 1;
    /// Maximum commit reveal periods
    pub const MAX_COMMIT_REVEAL_PEROIDS: u64 = 100;

    #[pallet::pallet]
    #[pallet::without_storage_info]
    #[pallet::storage_version(STORAGE_VERSION)]
    pub struct Pallet<T>(_);

    /// Alias for the account ID.
    pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;

    /// Struct for Axon.
    pub type AxonInfoOf = AxonInfo;

    /// local one
    pub type LocalCallOf<T> = <T as Config>::RuntimeCall;

    /// Data structure for Axon information.
    #[crate::freeze_struct("3545cfb0cac4c1f5")]
    #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
    pub struct AxonInfo {
        ///  Axon serving block.
        pub block: u64,
        ///  Axon version
        pub version: u32,
        ///  Axon u128 encoded ip address of type v6 or v4.
        pub ip: u128,
        ///  Axon u16 encoded port.
        pub port: u16,
        ///  Axon ip type, 4 for ipv4 and 6 for ipv6.
        pub ip_type: u8,
        ///  Axon protocol. TCP, UDP, other.
        pub protocol: u8,
        ///  Axon proto placeholder 1.
        pub placeholder1: u8,
        ///  Axon proto placeholder 2.
        pub placeholder2: u8,
    }

    /// Struct for NeuronCertificate.
    pub type NeuronCertificateOf = NeuronCertificate;
    /// Data structure for NeuronCertificate information.
    #[freeze_struct("1c232be200d9ec6c")]
    #[derive(Decode, Encode, Default, TypeInfo, PartialEq, Eq, Clone, Debug)]
    pub struct NeuronCertificate {
        ///  The neuron TLS public key
        pub public_key: BoundedVec<u8, ConstU32<64>>,
        ///  The algorithm used to generate the public key
        pub algorithm: u8,
    }

    impl TryFrom<Vec<u8>> for NeuronCertificate {
        type Error = ();

        fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
            if value.len() > 65 {
                return Err(());
            }
            // take the first byte as the algorithm
            let algorithm = value.first().ok_or(())?;
            // and the rest as the public_key
            let certificate = value.get(1..).ok_or(())?.to_vec();
            Ok(Self {
                public_key: BoundedVec::try_from(certificate).map_err(|_| ())?,
                algorithm: *algorithm,
            })
        }
    }

    ///  Struct for Prometheus.
    pub type PrometheusInfoOf = PrometheusInfo;

    /// Data structure for Prometheus information.
    #[crate::freeze_struct("5dde687e63baf0cd")]
    #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
    pub struct PrometheusInfo {
        /// Prometheus serving block.
        pub block: u64,
        /// Prometheus version.
        pub version: u32,
        ///  Prometheus u128 encoded ip address of type v6 or v4.
        pub ip: u128,
        ///  Prometheus u16 encoded port.
        pub port: u16,
        /// Prometheus ip type, 4 for ipv4 and 6 for ipv6.
        pub ip_type: u8,
    }

    ///  Struct for ChainIdentities. (DEPRECATED for V2)
    pub type ChainIdentityOf = ChainIdentity;

    /// Data structure for Chain Identities. (DEPRECATED for V2)
    #[crate::freeze_struct("bbfd00438dbe2b58")]
    #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
    pub struct ChainIdentity {
        /// The name of the chain identity
        pub name: Vec<u8>,
        /// The URL associated with the chain identity
        pub url: Vec<u8>,
        /// The image representation of the chain identity
        pub image: Vec<u8>,
        /// The Discord information for the chain identity
        pub discord: Vec<u8>,
        /// A description of the chain identity
        pub description: Vec<u8>,
        /// Additional information about the chain identity
        pub additional: Vec<u8>,
    }

    ///  Struct for ChainIdentities.
    pub type ChainIdentityOfV2 = ChainIdentityV2;

    /// Data structure for Chain Identities.
    #[crate::freeze_struct("ad72a270be7b59d7")]
    #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
    pub struct ChainIdentityV2 {
        /// The name of the chain identity
        pub name: Vec<u8>,
        /// The URL associated with the chain identity
        pub url: Vec<u8>,
        /// The github repository associated with the identity
        pub github_repo: Vec<u8>,
        /// The image representation of the chain identity
        pub image: Vec<u8>,
        /// The Discord information for the chain identity
        pub discord: Vec<u8>,
        /// A description of the chain identity
        pub description: Vec<u8>,
        /// Additional information about the chain identity
        pub additional: Vec<u8>,
    }

    ///  Struct for SubnetIdentities. (DEPRECATED for V2)
    pub type SubnetIdentityOf = SubnetIdentity;
    /// Data structure for Subnet Identities. (DEPRECATED for V2)
    #[crate::freeze_struct("f448dc3dad763108")]
    #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
    pub struct SubnetIdentity {
        /// The name of the subnet
        pub subnet_name: Vec<u8>,
        /// The github repository associated with the chain identity
        pub github_repo: Vec<u8>,
        /// The subnet's contact
        pub subnet_contact: Vec<u8>,
    }

    ///  Struct for SubnetIdentitiesV2. (DEPRECATED for V3)
    pub type SubnetIdentityOfV2 = SubnetIdentityV2;
    /// Data structure for Subnet Identities (DEPRECATED for V3)
    #[crate::freeze_struct("e002be4cd05d7b3e")]
    #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
    pub struct SubnetIdentityV2 {
        /// The name of the subnet
        pub subnet_name: Vec<u8>,
        /// The github repository associated with the subnet
        pub github_repo: Vec<u8>,
        /// The subnet's contact
        pub subnet_contact: Vec<u8>,
        /// The subnet's website
        pub subnet_url: Vec<u8>,
        /// The subnet's discord
        pub discord: Vec<u8>,
        /// The subnet's description
        pub description: Vec<u8>,
        /// Additional information about the subnet
        pub additional: Vec<u8>,
    }

    ///  Struct for SubnetIdentitiesV3.
    pub type SubnetIdentityOfV3 = SubnetIdentityV3;
    /// Data structure for Subnet Identities
    #[crate::freeze_struct("6a441335f985a0b")]
    #[derive(
        Encode, Decode, DecodeWithMemTracking, Default, TypeInfo, Clone, PartialEq, Eq, Debug,
    )]
    pub struct SubnetIdentityV3 {
        /// The name of the subnet
        pub subnet_name: Vec<u8>,
        /// The github repository associated with the subnet
        pub github_repo: Vec<u8>,
        /// The subnet's contact
        pub subnet_contact: Vec<u8>,
        /// The subnet's website
        pub subnet_url: Vec<u8>,
        /// The subnet's discord
        pub discord: Vec<u8>,
        /// The subnet's description
        pub description: Vec<u8>,
        /// The subnet's logo
        pub logo_url: Vec<u8>,
        /// Additional information about the subnet
        pub additional: Vec<u8>,
    }

    /// Enum for recycle or burn for the owner_uid(s)
    #[derive(TypeInfo, Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug)]
    pub enum RecycleOrBurnEnum {
        /// Burn the miner emission sent to the burn UID
        Burn,
        /// Recycle the miner emission sent to the recycle UID
        Recycle,
    }

    // Staking + Accounts

    #[derive(
        Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug, DecodeWithMemTracking,
    )]
    /// Enum for the per-coldkey root claim setting.
    pub enum RootClaimTypeEnum {
        /// Swap any alpha emission for TAO.
        #[default]
        Swap,
        /// Keep all alpha emission.
        Keep,
        /// Keep all alpha emission for specified subnets.
        KeepSubnets {
            /// Subnets to keep alpha emissions (swap everything else).
            subnets: BTreeSet<NetUid>,
        },
    }

    /// The Max Burn HalfLife Settable
    #[pallet::type_value]
    pub fn MaxBurnHalfLife<T: Config>() -> u16 {
        36_100
    }

    /// Default burn half-life (in blocks) for subnet registration price decay.
    #[pallet::type_value]
    pub fn DefaultBurnHalfLife<T: Config>() -> u16 {
        360
    }

    /// Default multiplier applied to the burn price after a successful registration.
    #[pallet::type_value]
    pub fn DefaultBurnIncreaseMult<T: Config>() -> U64F64 {
        U64F64::from_num(1.26)
    }

    /// Default Neuron Burn Cost
    #[pallet::type_value]
    pub fn DefaultNeuronBurnCost<T: Config>() -> TaoBalance {
        TaoBalance::from(1_000_000_000u64)
    }

    /// Default minimum root claim amount.
    /// This is the minimum amount of root claim that can be made.
    /// Any amount less than this will not be claimed.
    #[pallet::type_value]
    pub fn DefaultMinRootClaimAmount<T: Config>() -> I96F32 {
        500_000u64.into()
    }

    /// Default root claim type.
    /// This is the type of root claim that will be made.
    /// This is set by the user. Either swap to TAO or keep as alpha.
    #[pallet::type_value]
    pub fn DefaultRootClaimType<T: Config>() -> RootClaimTypeEnum {
        RootClaimTypeEnum::default()
    }

    /// Default number of root claims per claim call.
    /// Ideally this is calculated using the number of staking coldkey
    /// and the block time.
    #[pallet::type_value]
    pub fn DefaultNumRootClaim<T: Config>() -> u64 {
        // once per week (+ spare keys for skipped tries)
        5
    }

    /// Default value for zero.
    #[pallet::type_value]
    pub fn DefaultZeroU64<T: Config>() -> u64 {
        0
    }

    /// Default value for zero.
    #[pallet::type_value]
    pub fn DefaultZeroI64<T: Config>() -> i64 {
        0
    }
    /// Default value for Alpha currency.
    #[pallet::type_value]
    pub fn DefaultZeroAlpha<T: Config>() -> AlphaBalance {
        AlphaBalance::ZERO
    }

    /// Default value for Tao currency.
    #[pallet::type_value]
    pub fn DefaultZeroTao<T: Config>() -> TaoBalance {
        TaoBalance::ZERO
    }

    /// Default value for zero.
    #[pallet::type_value]
    pub fn DefaultZeroU128<T: Config>() -> u128 {
        0
    }

    /// Default value for zero.
    #[pallet::type_value]
    pub fn DefaultZeroU16<T: Config>() -> u16 {
        0
    }

    /// Default value for false.
    #[pallet::type_value]
    pub fn DefaultFalse<T: Config>() -> bool {
        false
    }

    /// Default value for true.
    #[pallet::type_value]
    pub fn DefaultTrue<T: Config>() -> bool {
        true
    }

    /// Total Rao in circulation.
    #[pallet::type_value]
    pub fn TotalSupply<T: Config>() -> u64 {
        21_000_000_000_000_000
    }

    /// Default Delegate Take.
    #[pallet::type_value]
    pub fn DefaultDelegateTake<T: Config>() -> PerU16 {
        PerU16::from_parts(T::InitialDefaultDelegateTake::get())
    }

    /// Default childkey take.
    #[pallet::type_value]
    pub fn DefaultChildKeyTake<T: Config>() -> PerU16 {
        PerU16::from_parts(T::InitialDefaultChildKeyTake::get())
    }

    /// Default minimum delegate take.
    #[pallet::type_value]
    pub fn DefaultMinDelegateTake<T: Config>() -> PerU16 {
        PerU16::from_parts(T::InitialMinDelegateTake::get())
    }

    /// Default minimum childkey take.
    #[pallet::type_value]
    pub fn DefaultMinChildKeyTake<T: Config>() -> PerU16 {
        PerU16::from_parts(T::InitialMinChildKeyTake::get())
    }

    /// Default maximum childkey take.
    #[pallet::type_value]
    pub fn DefaultMaxChildKeyTake<T: Config>() -> PerU16 {
        PerU16::from_parts(T::InitialMaxChildKeyTake::get())
    }

    /// Default account take.
    #[pallet::type_value]
    pub fn DefaultAccountTake<T: Config>() -> u64 {
        0
    }

    /// Default value for global weight.
    #[pallet::type_value]
    pub fn DefaultTaoWeight<T: Config>() -> u64 {
        T::InitialTaoWeight::get()
    }

    /// Default emission per block.
    #[pallet::type_value]
    pub fn DefaultBlockEmission<T: Config>() -> u64 {
        1_000_000_000
    }

    /// Default allowed delegation.
    #[pallet::type_value]
    pub fn DefaultAllowsDelegation<T: Config>() -> bool {
        false
    }

    /// Default total issuance.
    #[pallet::type_value]
    pub fn DefaultTotalIssuance<T: Config>() -> TaoBalance {
        T::InitialIssuance::get().into()
    }

    /// Default account, derived from zero trailing bytes.
    #[pallet::type_value]
    pub fn DefaultAccount<T: Config>() -> T::AccountId {
        #[allow(clippy::expect_used)]
        T::AccountId::decode(&mut TrailingZeroInput::zeroes())
            .expect("trailing zeroes always produce a valid account ID; qed")
    }
    // pub fn DefaultStakeInterval<T: Config>() -> u64 {
    //     360
    // } (DEPRECATED)

    /// Default account linkage
    #[pallet::type_value]
    pub fn DefaultAccountLinkage<T: Config>() -> Vec<(u64, T::AccountId)> {
        vec![]
    }

    /// Default pending childkeys
    #[pallet::type_value]
    pub fn DefaultPendingChildkeys<T: Config>() -> (Vec<(u64, T::AccountId)>, u64) {
        (vec![], 0)
    }

    /// Default account linkage
    #[pallet::type_value]
    pub fn DefaultProportion<T: Config>() -> u64 {
        0
    }

    /// Default accumulated emission for a hotkey
    #[pallet::type_value]
    pub fn DefaultAccumulatedEmission<T: Config>() -> u64 {
        0
    }

    /// Default last adjustment block.
    #[pallet::type_value]
    pub fn DefaultLastAdjustmentBlock<T: Config>() -> u64 {
        0
    }

    /// Default last adjustment block.
    #[pallet::type_value]
    pub fn DefaultRegistrationsThisBlock<T: Config>() -> u16 {
        0
    }

    /// Default EMA price halving blocks
    #[pallet::type_value]
    pub fn DefaultEMAPriceMovingBlocks<T: Config>() -> u64 {
        T::InitialEmaPriceHalvingPeriod::get()
    }

    /// Default registrations this block.
    #[pallet::type_value]
    pub fn DefaultBurn<T: Config>() -> TaoBalance {
        T::InitialBurn::get().into()
    }

    /// Default burn token.
    #[pallet::type_value]
    pub fn DefaultMinBurn<T: Config>() -> TaoBalance {
        T::InitialMinBurn::get().into()
    }

    /// Default min burn token.
    #[pallet::type_value]
    pub fn DefaultMaxBurn<T: Config>() -> TaoBalance {
        T::InitialMaxBurn::get().into()
    }

    /// Default max burn token.
    #[pallet::type_value]
    pub fn DefaultDifficulty<T: Config>() -> u64 {
        T::InitialDifficulty::get()
    }

    /// Default difficulty value.
    #[pallet::type_value]
    pub fn DefaultMinDifficulty<T: Config>() -> u64 {
        T::InitialMinDifficulty::get()
    }

    /// Default min difficulty value.
    #[pallet::type_value]
    pub fn DefaultMaxDifficulty<T: Config>() -> u64 {
        T::InitialMaxDifficulty::get()
    }

    /// Default max difficulty value.
    #[pallet::type_value]
    pub fn DefaultMaxRegistrationsPerBlock<T: Config>() -> u16 {
        T::InitialMaxRegistrationsPerBlock::get()
    }

    /// Default max registrations per block.
    #[pallet::type_value]
    pub fn DefaultRAORecycledForRegistration<T: Config>() -> TaoBalance {
        T::InitialRAORecycledForRegistration::get().into()
    }

    /// Default number of networks.
    #[pallet::type_value]
    pub fn DefaultN<T: Config>() -> u16 {
        0
    }

    /// Default value for hotkeys.
    #[pallet::type_value]
    pub fn DefaultHotkeys<T: Config>() -> Vec<u16> {
        vec![]
    }

    /// Default value if network is added.
    #[pallet::type_value]
    pub fn DefaultNeworksAdded<T: Config>() -> bool {
        false
    }

    /// Default value for network member.
    #[pallet::type_value]
    pub fn DefaultIsNetworkMember<T: Config>() -> bool {
        false
    }

    /// Default value for registration allowed.
    #[pallet::type_value]
    pub fn DefaultRegistrationAllowed<T: Config>() -> bool {
        true
    }

    /// Default value for network registered at.
    #[pallet::type_value]
    pub fn DefaultNetworkRegisteredAt<T: Config>() -> u64 {
        0
    }

    /// Default value for network immunity period.
    #[pallet::type_value]
    pub fn DefaultNetworkImmunityPeriod<T: Config>() -> u64 {
        T::InitialNetworkImmunityPeriod::get()
    }

    /// Default value for network min lock cost.
    #[pallet::type_value]
    pub fn DefaultNetworkMinLockCost<T: Config>() -> TaoBalance {
        T::InitialNetworkMinLockCost::get().into()
    }

    /// Default value for network lock reduction interval.
    #[pallet::type_value]
    pub fn DefaultNetworkLockReductionInterval<T: Config>() -> u64 {
        T::InitialNetworkLockReductionInterval::get()
    }

    /// Default value for subnet owner cut.
    #[pallet::type_value]
    pub fn DefaultSubnetOwnerCut<T: Config>() -> u16 {
        T::InitialSubnetOwnerCut::get()
    }

    /// Default value for recycle or burn.
    #[pallet::type_value]
    pub fn DefaultRecycleOrBurn<T: Config>() -> RecycleOrBurnEnum {
        RecycleOrBurnEnum::Burn // default to burn
    }

    /// Default value for network rate limit.
    #[pallet::type_value]
    pub fn DefaultNetworkRateLimit<T: Config>() -> u64 {
        if cfg!(feature = "pow-faucet") {
            return 0;
        }
        T::InitialNetworkRateLimit::get()
    }

    /// Default value for network rate limit.
    #[pallet::type_value]
    pub fn DefaultNetworkRegistrationStartBlock<T: Config>() -> u64 {
        0
    }

    /// Default value for TAO-in refund deployment block.
    #[pallet::type_value]
    pub fn DefaultTaoInRefundDeploymentBlock() -> u64 {
        0
    }

    /// Default value for weights version key rate limit.
    /// In units of tempos.
    #[pallet::type_value]
    pub fn DefaultWeightsVersionKeyRateLimit<T: Config>() -> u64 {
        5 // 5 tempos
    }

    /// Default value for pending emission.
    #[pallet::type_value]
    pub fn DefaultPendingEmission<T: Config>() -> AlphaBalance {
        0.into()
    }

    /// Default value for blocks since last step.
    #[pallet::type_value]
    pub fn DefaultBlocksSinceLastStep<T: Config>() -> u64 {
        0
    }

    /// Default value for last mechanism step block.
    #[pallet::type_value]
    pub fn DefaultLastMechanismStepBlock<T: Config>() -> u64 {
        0
    }

    /// Default value for subnet owner.
    #[pallet::type_value]
    pub fn DefaultSubnetOwner<T: Config>() -> T::AccountId {
        #[allow(clippy::expect_used)]
        T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
            .expect("trailing zeroes always produce a valid account ID; qed")
    }

    /// Default value for subnet locked.
    #[pallet::type_value]
    pub fn DefaultSubnetLocked<T: Config>() -> u64 {
        0
    }

    /// Default value for network tempo
    #[pallet::type_value]
    pub fn DefaultTempo<T: Config>() -> u16 {
        T::InitialTempo::get()
    }

    /// Default value for weights set rate limit.
    #[pallet::type_value]
    pub fn DefaultWeightsSetRateLimit<T: Config>() -> u64 {
        100
    }

    /// Default block number at registration.
    #[pallet::type_value]
    pub fn DefaultBlockAtRegistration<T: Config>() -> u64 {
        0
    }

    /// Default value for rho parameter.
    #[pallet::type_value]
    pub fn DefaultRho<T: Config>() -> u16 {
        T::InitialRho::get()
    }

    /// Default value for alpha sigmoid steepness.
    #[pallet::type_value]
    pub fn DefaultAlphaSigmoidSteepness<T: Config>() -> i16 {
        T::InitialAlphaSigmoidSteepness::get()
    }

    /// Default value for kappa parameter.
    #[pallet::type_value]
    pub fn DefaultKappa<T: Config>() -> u16 {
        T::InitialKappa::get()
    }

    /// Default value for network min allowed UIDs.
    #[pallet::type_value]
    pub fn DefaultMinAllowedUids<T: Config>() -> u16 {
        T::InitialMinAllowedUids::get()
    }

    /// Default maximum allowed UIDs.
    #[pallet::type_value]
    pub fn DefaultMaxAllowedUids<T: Config>() -> u16 {
        T::InitialMaxAllowedUids::get()
    }

    /// Rate limit for set max allowed UIDs
    #[pallet::type_value]
    pub fn MaxUidsTrimmingRateLimit<T: Config>() -> u64 {
        prod_or_fast!(30 * 7200, 1)
    }

    /// Default immunity period.
    #[pallet::type_value]
    pub fn DefaultImmunityPeriod<T: Config>() -> u16 {
        T::InitialImmunityPeriod::get()
    }

    /// Default activity cutoff.
    #[pallet::type_value]
    pub fn DefaultActivityCutoff<T: Config>() -> u16 {
        T::InitialActivityCutoff::get()
    }

    /// Default weights version key.
    #[pallet::type_value]
    pub fn DefaultWeightsVersionKey<T: Config>() -> u64 {
        T::InitialWeightsVersionKey::get()
    }

    /// Default minimum allowed weights.
    #[pallet::type_value]
    pub fn DefaultMinAllowedWeights<T: Config>() -> u16 {
        T::InitialMinAllowedWeights::get()
    }
    /// Default maximum allowed validators.
    #[pallet::type_value]
    pub fn DefaultMaxAllowedValidators<T: Config>() -> u16 {
        T::InitialMaxAllowedValidators::get()
    }

    /// Default adjustment interval.
    #[pallet::type_value]
    pub fn DefaultAdjustmentInterval<T: Config>() -> u16 {
        T::InitialAdjustmentInterval::get()
    }

    /// Default bonds moving average.
    #[pallet::type_value]
    pub fn DefaultBondsMovingAverage<T: Config>() -> u64 {
        T::InitialBondsMovingAverage::get()
    }

    /// Default bonds penalty.
    #[pallet::type_value]
    pub fn DefaultBondsPenalty<T: Config>() -> u16 {
        T::InitialBondsPenalty::get()
    }

    /// Default value for bonds reset - will not reset bonds
    #[pallet::type_value]
    pub fn DefaultBondsResetOn<T: Config>() -> bool {
        T::InitialBondsResetOn::get()
    }

    /// Default validator prune length.
    #[pallet::type_value]
    pub fn DefaultValidatorPruneLen<T: Config>() -> u64 {
        T::InitialValidatorPruneLen::get()
    }

    /// Default scaling law power.
    #[pallet::type_value]
    pub fn DefaultScalingLawPower<T: Config>() -> u16 {
        T::InitialScalingLawPower::get()
    }

    /// Default target registrations per interval.
    #[pallet::type_value]
    pub fn DefaultTargetRegistrationsPerInterval<T: Config>() -> u16 {
        T::InitialTargetRegistrationsPerInterval::get()
    }

    /// Default adjustment alpha.
    #[pallet::type_value]
    pub fn DefaultAdjustmentAlpha<T: Config>() -> u64 {
        T::InitialAdjustmentAlpha::get()
    }

    /// Default minimum stake for weights.
    #[pallet::type_value]
    pub fn DefaultStakeThreshold<T: Config>() -> u64 {
        0
    }

    /// Default Reveal Period Epochs
    #[pallet::type_value]
    pub fn DefaultRevealPeriodEpochs<T: Config>() -> u64 {
        1
    }

    /// Value definition for vector of u16.
    #[pallet::type_value]
    pub fn EmptyU16Vec<T: Config>() -> Vec<u16> {
        vec![]
    }

    /// Value definition for vector of PerU16.
    #[pallet::type_value]
    pub fn EmptyPerU16Vec<T: Config>() -> Vec<PerU16> {
        vec![]
    }

    /// Value definition for vector of u64.
    #[pallet::type_value]
    pub fn EmptyU64Vec<T: Config>() -> Vec<u64> {
        vec![]
    }

    /// Value definition for vector of bool.
    #[pallet::type_value]
    pub fn EmptyBoolVec<T: Config>() -> Vec<bool> {
        vec![]
    }

    /// Value definition for bonds with type vector of (u16, u16).
    #[pallet::type_value]
    pub fn DefaultBonds<T: Config>() -> Vec<(u16, u16)> {
        vec![]
    }

    /// Value definition for weights with vector of (u16, u16).
    #[pallet::type_value]
    pub fn DefaultWeights<T: Config>() -> Vec<(u16, u16)> {
        vec![]
    }

    /// Default value for key with type T::AccountId derived from trailing zeroes.
    #[pallet::type_value]
    pub fn DefaultKey<T: Config>() -> T::AccountId {
        #[allow(clippy::expect_used)]
        T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
            .expect("trailing zeroes always produce a valid account ID; qed")
    }
    // pub fn DefaultHotkeyEmissionTempo<T: Config>() -> u64 {
    //     T::InitialHotkeyEmissionTempo::get()
    // } (DEPRECATED)

    /// Default per-block epoch cap, seeded from the runtime-configured initial value.
    #[pallet::type_value]
    pub fn DefaultMaxEpochsPerBlock<T: Config>() -> u8 {
        T::InitialMaxEpochsPerBlock::get()
    }

    /// Default value for rate limiting
    #[pallet::type_value]
    pub fn DefaultTxRateLimit<T: Config>() -> u64 {
        T::InitialTxRateLimit::get()
    }

    /// Default value for delegate take rate limiting
    #[pallet::type_value]
    pub fn DefaultTxDelegateTakeRateLimit<T: Config>() -> u64 {
        T::InitialTxDelegateTakeRateLimit::get()
    }

    /// Default value for chidlkey take rate limiting
    #[pallet::type_value]
    pub fn DefaultTxChildKeyTakeRateLimit<T: Config>() -> u64 {
        T::InitialTxChildKeyTakeRateLimit::get()
    }

    /// Default value for last extrinsic block.
    #[pallet::type_value]
    pub fn DefaultLastTxBlock<T: Config>() -> u64 {
        0
    }

    /// Default value for serving rate limit.
    #[pallet::type_value]
    pub fn DefaultServingRateLimit<T: Config>() -> u64 {
        T::InitialServingRateLimit::get()
    }

    /// Default value for weight commit/reveal enabled.
    #[pallet::type_value]
    pub fn DefaultCommitRevealWeightsEnabled<T: Config>() -> bool {
        true
    }

    /// Default value for weight commit/reveal version.
    #[pallet::type_value]
    pub fn DefaultCommitRevealWeightsVersion<T: Config>() -> u16 {
        4
    }

    /// ITEM (switches liquid alpha on)
    #[pallet::type_value]
    pub fn DefaultLiquidAlpha<T: Config>() -> bool {
        false
    }

    /// ITEM (switches liquid alpha on)
    #[pallet::type_value]
    pub fn DefaultYuma3<T: Config>() -> bool {
        false
    }

    /// (alpha_low: 0.7, alpha_high: 0.9)
    #[pallet::type_value]
    pub fn DefaultAlphaValues<T: Config>() -> (u16, u16) {
        (45875, 58982)
    }

    /// Default value for coldkey swap announcement delay.
    #[pallet::type_value]
    pub fn DefaultColdkeySwapAnnouncementDelay<T: Config>() -> BlockNumberFor<T> {
        T::InitialColdkeySwapAnnouncementDelay::get()
    }

    /// Default value for coldkey swap reannouncement delay.
    #[pallet::type_value]
    pub fn DefaultColdkeySwapReannouncementDelay<T: Config>() -> BlockNumberFor<T> {
        T::InitialColdkeySwapReannouncementDelay::get()
    }

    /// Default value for applying pending items (e.g. childkeys).
    #[pallet::type_value]
    pub fn DefaultPendingCooldown<T: Config>() -> u64 {
        prod_or_fast!(7_200, 15)
    }

    /// Default minimum stake.
    #[pallet::type_value]
    pub fn DefaultMinStake<T: Config>() -> TaoBalance {
        T::InitialMinStake::get().into()
    }

    /// Default unicode vector for tau symbol.
    #[pallet::type_value]
    pub fn DefaultUnicodeVecU8<T: Config>() -> Vec<u8> {
        b"\xF0\x9D\x9C\x8F".to_vec() // Unicode for tau (𝜏)
    }

    /// Default value for dissolve network schedule duration
    #[pallet::type_value]
    pub fn DefaultDissolveNetworkScheduleDuration<T: Config>() -> BlockNumberFor<T> {
        T::InitialDissolveNetworkScheduleDuration::get()
    }

    /// Default moving alpha for the moving price.
    #[pallet::type_value]
    pub fn DefaultMovingAlpha<T: Config>() -> I96F32 {
        // Moving average take 30 days to reach 50% of the price
        // and 3.5 months to reach 90%.
        I96F32::saturating_from_num(0.000003)
    }

    /// Default subnet moving price.
    #[pallet::type_value]
    pub fn DefaultMovingPrice<T: Config>() -> I96F32 {
        I96F32::saturating_from_num(0.0)
    }

    /// Default subnet root proportion.
    #[pallet::type_value]
    pub fn DefaultRootProp<T: Config>() -> U96F32 {
        U96F32::saturating_from_num(0.0)
    }

    /// Default subnet root claimable
    #[pallet::type_value]
    pub fn DefaultRootClaimable<T: Config>() -> BTreeMap<NetUid, I96F32> {
        Default::default()
    }

    /// Default value for Share Pool variables
    #[pallet::type_value]
    pub fn DefaultSharePoolZero<T: Config>() -> U64F64 {
        U64F64::saturating_from_num(0)
    }

    /// Default value for minimum activity cutoff
    #[pallet::type_value]
    pub fn DefaultMinActivityCutoff<T: Config>() -> u16 {
        360
    }

    /// Default value for setting subnet owner hotkey rate limit
    #[pallet::type_value]
    pub fn DefaultSetSNOwnerHotkeyRateLimit<T: Config>() -> u64 {
        50400
    }

    /// Default last Alpha map key for iteration
    #[pallet::type_value]
    pub fn DefaultAlphaIterationLastKey<T: Config>() -> Option<Vec<u8>> {
        None
    }

    /// Default number of terminal blocks in a tempo during which admin operations are prohibited
    #[pallet::type_value]
    pub fn DefaultAdminFreezeWindow<T: Config>() -> u16 {
        10
    }

    /// Default number of tempos for owner hyperparameter update rate limit
    #[pallet::type_value]
    pub fn DefaultOwnerHyperparamRateLimit<T: Config>() -> u16 {
        2
    }

    /// Default value for ck burn, 0%.
    #[pallet::type_value]
    pub fn DefaultCKBurn<T: Config>() -> u64 {
        0
    }

    /// Default value for subnet limit.
    #[pallet::type_value]
    pub fn DefaultSubnetLimit<T: Config>() -> u16 {
        128
    }

    /// Default value for MinNonImmuneUids.
    #[pallet::type_value]
    pub fn DefaultMinNonImmuneUids<T: Config>() -> u16 {
        10u16
    }

    /// Default value for AutoParentDelegationEnabled.
    #[pallet::type_value]
    pub fn DefaultAutoParentDelegationEnabled<T: Config>() -> bool {
        true
    }

    #[pallet::storage]
    pub type MinActivityCutoff<T: Config> =
        StorageValue<_, u16, ValueQuery, DefaultMinActivityCutoff<T>>;

    /// Global window (in blocks) at the end of each tempo where admin ops are disallowed
    #[pallet::storage]
    pub type AdminFreezeWindow<T: Config> =
        StorageValue<_, u16, ValueQuery, DefaultAdminFreezeWindow<T>>;

    /// Global number of epochs used to rate limit subnet owner hyperparameter updates
    #[pallet::storage]
    pub type OwnerHyperparamRateLimit<T: Config> =
        StorageValue<_, u16, ValueQuery, DefaultOwnerHyperparamRateLimit<T>>;

    /// Duration of dissolve network schedule before execution
    #[pallet::storage]
    pub type DissolveNetworkScheduleDuration<T: Config> =
        StorageValue<_, BlockNumberFor<T>, ValueQuery, DefaultDissolveNetworkScheduleDuration<T>>;

    /// DMap ( netuid, coldkey ) --> blocknumber | last hotkey swap on network.
    #[pallet::storage]
    pub type LastHotkeySwapOnNetuid<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        u64,
        ValueQuery,
        DefaultZeroU64<T>,
    >;

    /// Ensures unique IDs for StakeJobs storage map
    #[pallet::storage]
    pub type NextStakeJobId<T> = StorageValue<_, u64, ValueQuery, DefaultZeroU64<T>>;

    // Staking Variables
    /// The Subtensor [`TotalIssuance`] represents the total issuance of tokens on the Bittensor network.
    ///
    /// It is comprised of three parts:
    /// * The total amount of issued tokens, tracked in the TotalIssuance of the Balances pallet
    /// * The total amount of tokens staked in the system, tracked in [`TotalStake`]
    /// * The total amount of tokens locked up for subnet reg, tracked in [`TotalSubnetLocked`] attained by iterating over subnet lock.
    ///
    /// Eventually, Bittensor should migrate to using Holds afterwhich time we will not require this
    /// separate accounting.
    /// ITEM --> Global weight
    #[pallet::storage]
    pub type TaoWeight<T> = StorageValue<_, u64, ValueQuery, DefaultTaoWeight<T>>;

    /// ITEM --> CK burn
    #[pallet::storage]
    pub type CKBurn<T> = StorageValue<_, u64, ValueQuery, DefaultCKBurn<T>>;

    /// ITEM ( default_delegate_take )
    #[pallet::storage]
    pub type MaxDelegateTake<T> = StorageValue<_, PerU16, ValueQuery, DefaultDelegateTake<T>>;

    /// ITEM ( min_delegate_take )
    #[pallet::storage]
    pub type MinDelegateTake<T> = StorageValue<_, PerU16, ValueQuery, DefaultMinDelegateTake<T>>;

    /// ITEM ( default_childkey_take )
    #[pallet::storage]
    pub type MaxChildkeyTake<T> = StorageValue<_, PerU16, ValueQuery, DefaultMaxChildKeyTake<T>>;

    /// ITEM ( min_childkey_take )
    #[pallet::storage]
    pub type MinChildkeyTake<T> = StorageValue<_, PerU16, ValueQuery, DefaultMinChildKeyTake<T>>;

    /// MAP ( netuid ) --> take | Returns the subnet-specific minimum childkey take.
    #[pallet::storage]
    pub type MinChildkeyTakePerSubnet<T: Config> =
        StorageMap<_, Identity, NetUid, PerU16, ValueQuery>;

    /// MAP ( hot ) --> cold | Returns the controlling coldkey for a hotkey
    #[pallet::storage]
    pub type Owner<T: Config> =
        StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, ValueQuery, DefaultAccount<T>>;

    /// MAP ( coldkey ) --> flags | Account-level flags. Defaults to zero.
    #[pallet::storage]
    pub type AccountFlags<T: Config> =
        StorageMap<_, Blake2_128Concat, T::AccountId, u128, ValueQuery>;

    /// MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation
    #[pallet::storage]
    pub type Delegates<T: Config> =
        StorageMap<_, Blake2_128Concat, T::AccountId, PerU16, ValueQuery, DefaultDelegateTake<T>>;

    /// DMAP ( hot, netuid ) --> take | Returns the hotkey childkey take for a specific subnet
    #[pallet::storage]
    pub type ChildkeyTake<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId, // First key: hotkey
        Identity,
        NetUid, // Second key: netuid
        PerU16, // Value: take
        ValueQuery,
    >;

    /// DMAP ( netuid, parent ) --> (Vec<(proportion,child)>, cool_down_block)
    #[pallet::storage]
    pub type PendingChildKeys<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        (Vec<(u64, T::AccountId)>, u64),
        ValueQuery,
        DefaultPendingChildkeys<T>,
    >;

    /// DMAP ( parent, netuid ) --> Vec<(proportion,child)>
    #[pallet::storage]
    pub type ChildKeys<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        Vec<(u64, T::AccountId)>,
        ValueQuery,
        DefaultAccountLinkage<T>,
    >;

    /// DMAP ( child, netuid ) --> Vec<(proportion,parent)>
    #[pallet::storage]
    pub type ParentKeys<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        Vec<(u64, T::AccountId)>,
        ValueQuery,
        DefaultAccountLinkage<T>,
    >;

    /// DMAP ( netuid, hotkey ) --> u64 | Last alpha dividend this hotkey got on tempo.
    #[pallet::storage]
    pub type AlphaDividendsPerSubnet<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        AlphaBalance,
        ValueQuery,
        DefaultZeroAlpha<T>,
    >;

    /// DMAP ( netuid, hotkey ) --> u64 | Last root alpha dividend this hotkey got on tempo.
    #[pallet::storage]
    pub type RootAlphaDividendsPerSubnet<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        AlphaBalance,
        ValueQuery,
        DefaultZeroAlpha<T>,
    >;

    // Coinbase
    /// ITEM ( global_block_emission )
    #[deprecated(note = "Use calculate_block_emission() or the block emission RPC instead.")]
    #[pallet::storage]
    pub type BlockEmission<T> = StorageValue<_, u64, ValueQuery, DefaultBlockEmission<T>>;

    /// DMap ( hot, netuid ) --> emission | last hotkey emission on network.
    #[pallet::storage]
    pub type LastHotkeyEmissionOnNetuid<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        AlphaBalance,
        ValueQuery,
        DefaultZeroAlpha<T>,
    >;
    // Staking Counters
    /// The Subtensor [`TotalIssuance`] represents the total issuance of tokens on the Bittensor network.
    ///
    /// It is comprised of three parts:
    /// * The total amount of issued tokens, tracked in the TotalIssuance of the Balances pallet
    /// * The total amount of tokens staked in the system, tracked in [`TotalStake`]
    /// * The total amount of tokens locked up for subnet reg, tracked in [`TotalSubnetLocked`] attained by iterating over subnet lock.
    ///
    /// Eventually, Bittensor should migrate to using Holds afterwhich time we will not require this
    /// separate accounting.
    /// ITEM ( maximum_number_of_networks )
    #[pallet::storage]
    pub type SubnetLimit<T> = StorageValue<_, u16, ValueQuery, DefaultSubnetLimit<T>>;

    /// ITEM ( total_issuance )
    #[pallet::storage]
    pub type TotalIssuance<T> = StorageValue<_, TaoBalance, ValueQuery, DefaultTotalIssuance<T>>;

    /// ITEM ( total_stake )
    #[pallet::storage]
    pub type TotalStake<T> = StorageValue<_, TaoBalance, ValueQuery, DefaultZeroTao<T>>;

    /// ITEM ( moving_alpha ) -- subnet moving alpha.
    #[pallet::storage]
    pub type SubnetMovingAlpha<T> = StorageValue<_, I96F32, ValueQuery, DefaultMovingAlpha<T>>;

    /// MAP ( netuid ) --> moving_price | The subnet moving price.
    #[pallet::storage]
    pub type SubnetMovingPrice<T: Config> =
        StorageMap<_, Identity, NetUid, I96F32, ValueQuery, DefaultMovingPrice<T>>;

    /// MAP ( netuid ) --> root_prop | The subnet root proportion.
    #[pallet::storage]
    pub type RootProp<T: Config> =
        StorageMap<_, Identity, NetUid, U96F32, ValueQuery, DefaultRootProp<T>>;

    /// MAP ( netuid ) --> total_volume | The total amount of TAO bought and sold since the start of the network.
    #[pallet::storage]
    pub type SubnetVolume<T: Config> =
        StorageMap<_, Identity, NetUid, u128, ValueQuery, DefaultZeroU128<T>>;

    /// MAP ( netuid ) --> tao_in_subnet | Returns the amount of TAO in the subnet.
    #[pallet::storage]
    pub type SubnetTAO<T: Config> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultZeroTao<T>>;

    /// MAP ( netuid ) --> alpha_in_emission | Returns the amount of alph in  emission into the pool per block.
    #[pallet::storage]
    pub type SubnetAlphaInEmission<T: Config> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( netuid ) --> subnet_emission_enabled
    ///
    /// When false, subnet pool-side emission is disabled for this subnet:
    /// `alpha_in`, `tao_in`, and `excess_tao` chain buys are all treated as zero.
    /// `alpha_out`, owner cut, root proportion, pending server emission, and pending
    /// validator emission are intentionally left unchanged.
    ///
    /// Defaults to true so existing subnets keep current behavior.
    #[pallet::storage]
    pub type SubnetEmissionEnabled<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultTrue<T>>;

    /// MAP ( netuid ) --> alpha_out_emission | Returns the amount of alpha out emission into the network per block.
    #[pallet::storage]
    pub type SubnetAlphaOutEmission<T: Config> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( netuid ) --> tao_in_emission | Returns the amount of tao emitted into this subent on the last block.
    #[pallet::storage]
    pub type SubnetTaoInEmission<T: Config> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultZeroTao<T>>;

    /// MAP ( netuid ) --> excess_tao | Returns the excess TAO swapped (chain buys) into this subnet on the last block.
    #[pallet::storage]
    pub type SubnetExcessTao<T: Config> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultZeroTao<T>>;

    /// MAP ( netuid ) --> root_sell_tao | Returns the TAO received from root dividend sells on this subnet on the last block.
    #[pallet::storage]
    pub type SubnetRootSellTao<T: Config> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultZeroTao<T>>;

    /// MAP ( netuid ) --> alpha_supply_in_pool | Returns the amount of alpha in the pool.
    #[pallet::storage]
    pub type SubnetAlphaIn<T: Config> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( netuid ) --> alpha_supply_in_subnet | Returns the amount of alpha in the subnet.
    #[pallet::storage]
    pub type SubnetAlphaOut<T: Config> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;
    /// MAP ( netuid ) --> protocol_alpha | Returns the protocol-owned alpha cached for the subnet.
    #[pallet::storage]
    pub type SubnetProtocolAlpha<T: Config> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( cold ) --> Vec<hot> | Maps coldkey to hotkeys that stake to it
    #[pallet::storage]
    pub type StakingHotkeys<T: Config> =
        StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;

    /// MAP ( cold ) --> Vec<hot> | Returns the vector of hotkeys controlled by this coldkey.
    #[pallet::storage]
    pub type OwnedHotkeys<T: Config> =
        StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;

    /// DMAP ( cold, netuid )--> hot | Returns the hotkey a coldkey will autostake to with mining rewards.
    #[pallet::storage]
    pub type AutoStakeDestination<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        T::AccountId,
        OptionQuery,
    >;

    /// DMAP ( hot, netuid )--> Vec<cold> | Returns a list of coldkeys that are autostaking to a hotkey
    #[pallet::storage]
    pub type AutoStakeDestinationColdkeys<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        Vec<T::AccountId>,
        ValueQuery,
    >;

    /// The delay after an announcement before a coldkey swap can be performed.
    #[pallet::storage]
    pub type ColdkeySwapAnnouncementDelay<T: Config> =
        StorageValue<_, BlockNumberFor<T>, ValueQuery, DefaultColdkeySwapAnnouncementDelay<T>>;

    /// The delay after the initial delay has passed before a new announcement can be made.
    #[pallet::storage]
    pub type ColdkeySwapReannouncementDelay<T: Config> =
        StorageValue<_, BlockNumberFor<T>, ValueQuery, DefaultColdkeySwapReannouncementDelay<T>>;

    /// A map of the coldkey swap announcements from a coldkey
    /// to the block number the coldkey swap can be performed.
    #[pallet::storage]
    pub type ColdkeySwapAnnouncements<T: Config> =
        StorageMap<_, Twox64Concat, T::AccountId, (BlockNumberFor<T>, T::Hash), OptionQuery>;

    /// A map of the coldkey swap disputes from a coldkey to the
    /// block number the coldkey swap was disputed.
    #[pallet::storage]
    pub type ColdkeySwapDisputes<T: Config> =
        StorageMap<_, Twox64Concat, T::AccountId, BlockNumberFor<T>, OptionQuery>;

    /// DMAP ( hot, netuid ) --> alpha | Returns the total amount of alpha a hotkey owns.
    #[pallet::storage]
    pub type TotalHotkeyAlpha<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        AlphaBalance,
        ValueQuery,
        DefaultZeroAlpha<T>,
    >;

    /// DMAP ( hot, netuid ) --> alpha | Returns the total amount of alpha a hotkey owned in the last epoch.
    #[pallet::storage]
    pub type TotalHotkeyAlphaLastEpoch<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        AlphaBalance,
        ValueQuery,
        DefaultZeroAlpha<T>,
    >;

    /// DMAP ( hot, netuid ) --> total_alpha_shares | Returns the number of alpha shares for a hotkey on a subnet.
    #[pallet::storage]
    pub type TotalHotkeyShares<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        U64F64,
        ValueQuery,
        DefaultSharePoolZero<T>,
    >;

    /// NMAP ( hot, cold, netuid ) --> alpha | Returns the alpha shares for a hotkey, coldkey, netuid triplet.
    #[pallet::storage]
    pub type Alpha<T: Config> = StorageNMap<
        _,
        (
            NMapKey<Blake2_128Concat, T::AccountId>, // hot
            NMapKey<Blake2_128Concat, T::AccountId>, // cold
            NMapKey<Identity, NetUid>,               // subnet
        ),
        U64F64, // Shares
        ValueQuery,
    >;

    /// DMAP ( hot, netuid ) --> total_alpha_shares | Returns the number of alpha shares for a hotkey on a subnet, stores SafeFloat.
    #[pallet::storage]
    pub type TotalHotkeySharesV2<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId, // hot
        Identity,
        NetUid,    // subnet
        SafeFloat, // Hotkey shares in unlimited precision
        ValueQuery,
    >;

    /// NMAP ( hot, cold, netuid ) --> alpha | Returns the alpha shares for a hotkey, coldkey, netuid triplet, stores SafeFloat.
    #[pallet::storage]
    pub type AlphaV2<T: Config> = StorageNMap<
        _,
        (
            NMapKey<Blake2_128Concat, T::AccountId>, // hot
            NMapKey<Blake2_128Concat, T::AccountId>, // cold
            NMapKey<Identity, NetUid>,               // subnet
        ),
        SafeFloat, // Shares in unlimited precision
        ValueQuery,
    >;

    /// DMAP ( coldkey, netuid, hotkey ) --> LockState | Exponential lock per coldkey per subnet.
    #[pallet::storage]
    pub type Lock<T: Config> = StorageNMap<
        _,
        (
            NMapKey<Blake2_128Concat, T::AccountId>, // coldkey
            NMapKey<Identity, NetUid>,               // subnet
            NMapKey<Blake2_128Concat, T::AccountId>, // hotkey
        ),
        LockState,
        OptionQuery,
    >;

    /// NMAP ( netuid, hotkey, coldkey ) --> () | Reverse index for non-zero locks targeting this hotkey on this subnet.
    #[pallet::storage]
    pub type LockingColdkeys<T: Config> = StorageNMap<
        _,
        (
            NMapKey<Identity, NetUid>,               // subnet
            NMapKey<Blake2_128Concat, T::AccountId>, // hotkey
            NMapKey<Blake2_128Concat, T::AccountId>, // coldkey
        ),
        (),
        OptionQuery,
    >;

    /// DMAP ( netuid, hotkey ) --> LockState | Total lock per hotkey per subnet.
    #[pallet::storage]
    pub type HotkeyLock<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid, // subnet
        Blake2_128Concat,
        T::AccountId, // hotkey
        LockState,    // Total merged lock
        OptionQuery,
    >;

    /// DMAP ( netuid, hotkey ) --> LockState | Total decaying non-owner lock per hotkey per subnet.
    #[pallet::storage]
    pub type DecayingHotkeyLock<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid, // subnet
        Blake2_128Concat,
        T::AccountId, // hotkey
        LockState,    // Total merged decaying lock
        OptionQuery,
    >;

    /// MAP ( netuid ) --> LockState | Total perpetual lock to the owner hotkey for a subnet.
    #[pallet::storage]
    pub type OwnerLock<T: Config> = StorageMap<_, Identity, NetUid, LockState, OptionQuery>;

    /// MAP ( netuid ) --> LockState | Total decaying lock to the owner hotkey for a subnet.
    #[pallet::storage]
    pub type DecayingOwnerLock<T: Config> = StorageMap<_, Identity, NetUid, LockState, OptionQuery>;

    /// DMAP ( coldkey, netuid ) --> false | When present and false, this coldkey's lock is perpetual.
    /// Missing entries mean the lock decays by default.
    #[pallet::storage]
    pub type DecayingLock<T: Config> =
        StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, NetUid, bool, OptionQuery>;

    /// Default value for owner cut auto-locking.
    #[pallet::type_value]
    pub fn DefaultOwnerCutAutoLockEnabled<T: Config>() -> bool {
        false
    }

    /// MAP ( netuid ) --> bool | Whether subnet owner cut should be auto-locked.
    /// Missing entries default to false, so auto-locking is disabled unless explicitly enabled.
    #[pallet::storage]
    pub type OwnerCutAutoLockEnabled<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultOwnerCutAutoLockEnabled<T>>;

    /// Default unlock timescale: 50% lock back in ~90 days.
    #[pallet::type_value]
    pub fn DefaultUnlockRate<T: Config>() -> u64 {
        934_866
    }

    /// Default maturity timescale: 50% conviction in ~90 days.
    #[pallet::type_value]
    pub fn DefaultMaturityRate<T: Config>() -> u64 {
        934_866
    }

    /// ITEM( maturity_rate ) | Decay timescale in blocks for lock conviction.
    #[pallet::storage]
    pub type MaturityRate<T: Config> = StorageValue<_, u64, ValueQuery, DefaultMaturityRate<T>>;

    /// ITEM( unlock_rate ) | Decay timescale in blocks for locked mass.
    #[pallet::storage]
    pub type UnlockRate<T: Config> = StorageValue<_, u64, ValueQuery, DefaultUnlockRate<T>>;

    /// Contains last Alpha storage map key to iterate (check first)
    #[pallet::storage]
    pub type AlphaMapLastKey<T: Config> =
        StorageValue<_, Option<Vec<u8>>, ValueQuery, DefaultAlphaIterationLastKey<T>>;

    /// Contains last AlphaV2 storage map key to iterate (check first)
    #[pallet::storage]
    pub type AlphaV2MapLastKey<T: Config> =
        StorageValue<_, Option<Vec<u8>>, ValueQuery, DefaultAlphaIterationLastKey<T>>;

    /// MAP ( netuid ) --> token_symbol | Returns the token symbol for a subnet.
    #[pallet::storage]
    pub type TokenSymbol<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<u8>, ValueQuery, DefaultUnicodeVecU8<T>>;

    /// MAP ( netuid ) --> subnet_tao_flow | Returns the TAO inflow-outflow balance.
    #[pallet::storage]
    pub type SubnetTaoFlow<T: Config> =
        StorageMap<_, Identity, NetUid, i64, ValueQuery, DefaultZeroI64<T>>;

    /// MAP ( netuid ) --> subnet_ema_tao_flow | Returns the EMA of TAO inflow-outflow balance.
    #[pallet::storage]
    pub type SubnetEmaTaoFlow<T: Config> =
        StorageMap<_, Identity, NetUid, (u64, I64F64), OptionQuery>;

    /// ITEM --> net_tao_flow_enabled | When true, emission shares use net flow (user - protocol). When false, uses gross user flow only.
    #[pallet::type_value]
    pub fn DefaultNetTaoFlowEnabled<T: Config>() -> bool {
        true
    }
    #[pallet::storage]
    pub type NetTaoFlowEnabled<T: Config> =
        StorageValue<_, bool, ValueQuery, DefaultNetTaoFlowEnabled<T>>;

    /// MAP ( netuid ) --> subnet_protocol_flow | Per-block accumulator for protocol cost (emission + chain buys - root sells).
    #[pallet::storage]
    pub type SubnetProtocolFlow<T: Config> =
        StorageMap<_, Identity, NetUid, i64, ValueQuery, DefaultZeroI64<T>>;

    /// MAP ( netuid ) --> subnet_ema_protocol_flow | EMA of protocol cost flow, same smoothing as SubnetEmaTaoFlow.
    #[pallet::storage]
    pub type SubnetEmaProtocolFlow<T: Config> =
        StorageMap<_, Identity, NetUid, (u64, I64F64), OptionQuery>;

    /// Default value for flow cutoff.
    #[pallet::type_value]
    pub fn DefaultFlowCutoff<T: Config>() -> I64F64 {
        I64F64::saturating_from_num(0)
    }
    #[pallet::storage]
    /// ITEM --> TAO Flow Cutoff
    pub type TaoFlowCutoff<T: Config> = StorageValue<_, I64F64, ValueQuery, DefaultFlowCutoff<T>>;
    #[pallet::type_value]
    /// Default value for flow normalization exponent.
    pub fn DefaultFlowNormExponent<T: Config>() -> U64F64 {
        U64F64::saturating_from_num(1)
    }
    #[pallet::storage]
    /// ITEM --> Flow Normalization Exponent (p)
    pub type FlowNormExponent<T: Config> =
        StorageValue<_, U64F64, ValueQuery, DefaultFlowNormExponent<T>>;
    #[pallet::type_value]
    /// Default value for flow EMA smoothing.
    pub fn DefaultFlowEmaSmoothingFactor<T: Config>() -> u64 {
        // Example values:
        //   half-life            factor value        i64 normalized (x 2^63)
        //   216000 (1 month) --> 0.000003209009576 ( 29_597_889_189_277)
        //    50400 (1 week)  --> 0.000013752825678 (126_847_427_788_335)
        29_597_889_189_277
    }
    #[pallet::type_value]
    /// Flow EMA smoothing half-life.
    pub fn FlowHalfLife<T: Config>() -> u64 {
        216_000
    }
    #[pallet::storage]
    /// ITEM --> Flow EMA smoothing factor (flow alpha), u64 normalized
    pub type FlowEmaSmoothingFactor<T: Config> =
        StorageValue<_, u64, ValueQuery, DefaultFlowEmaSmoothingFactor<T>>;

    // Global Parameters
    /// StorageItem Global Used Work.
    #[pallet::storage]
    pub type UsedWork<T: Config> = StorageMap<_, Identity, Vec<u8>, u64, ValueQuery>;

    /// ITEM( global_max_registrations_per_block )
    #[pallet::storage]
    pub type MaxRegistrationsPerBlock<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMaxRegistrationsPerBlock<T>>;

    /// ITEM( total_number_of_existing_networks )
    #[pallet::storage]
    pub type TotalNetworks<T> = StorageValue<_, u16, ValueQuery>;

    /// ITEM( network_immunity_period )
    #[pallet::storage]
    pub type NetworkImmunityPeriod<T> =
        StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod<T>>;

    /// ITEM( start_call_delay )
    #[pallet::storage]
    pub type StartCallDelay<T: Config> = StorageValue<_, u64, ValueQuery, T::InitialStartCallDelay>;

    /// ITEM( min_network_lock_cost )
    #[pallet::storage]
    pub type NetworkMinLockCost<T> =
        StorageValue<_, TaoBalance, ValueQuery, DefaultNetworkMinLockCost<T>>;

    /// ITEM( last_network_lock_cost )
    #[pallet::storage]
    pub type NetworkLastLockCost<T> =
        StorageValue<_, TaoBalance, ValueQuery, DefaultNetworkMinLockCost<T>>;

    /// ITEM( network_lock_reduction_interval )
    #[pallet::storage]
    pub type NetworkLockReductionInterval<T> =
        StorageValue<_, u64, ValueQuery, DefaultNetworkLockReductionInterval<T>>;

    /// ITEM( subnet_owner_cut )
    #[pallet::storage]
    pub type SubnetOwnerCut<T> = StorageValue<_, u16, ValueQuery, DefaultSubnetOwnerCut<T>>;

    /// Default value for subnet owner cut enabled flag.
    #[pallet::type_value]
    pub fn DefaultOwnerCutEnabled<T: Config>() -> bool {
        true
    }

    /// MAP ( netuid ) --> owner_cut_enabled
    #[pallet::storage]
    pub type OwnerCutEnabled<T> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultOwnerCutEnabled<T>>;

    /// ITEM( network_rate_limit )
    #[pallet::storage]
    pub type NetworkRateLimit<T> = StorageValue<_, u64, ValueQuery, DefaultNetworkRateLimit<T>>;

    /// ITEM( nominator_min_required_stake ) --- Factor of DefaultMinStake in per-mill format.
    #[pallet::storage]
    pub type NominatorMinRequiredStake<T> = StorageValue<_, u64, ValueQuery, DefaultZeroU64<T>>;

    /// ITEM( weights_version_key_rate_limit ) --- Rate limit in tempos.
    #[pallet::storage]
    pub type WeightsVersionKeyRateLimit<T> =
        StorageValue<_, u64, ValueQuery, DefaultWeightsVersionKeyRateLimit<T>>;

    // Rate Limiting
    /// MAP ( RateLimitKey ) --> Block number in which the last rate limited operation occured
    #[pallet::storage]
    pub type LastRateLimitedBlock<T: Config> =
        StorageMap<_, Identity, RateLimitKey<T::AccountId>, u64, ValueQuery, DefaultZeroU64<T>>;

    // Subnet Locks
    /// MAP ( netuid ) --> transfer_toggle
    #[pallet::storage]
    pub type TransferToggle<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultTrue<T>>;

    /// MAP ( netuid ) --> total_subnet_locked
    #[pallet::storage]
    pub type SubnetLocked<T: Config> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultZeroTao<T>>;

    /// MAP ( netuid ) --> largest_locked
    #[pallet::storage]
    pub type LargestLocked<T: Config> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultZeroU64<T>>;

    // Tempos
    /// MAP ( netuid ) --> tempo
    #[pallet::storage]
    pub type Tempo<T> = StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultTempo<T>>;

    /// Lower bound for owner-set tempo. Also the fixed cooldown for `sudo_set_tempo`.
    pub const MIN_TEMPO: u16 = 360;
    /// Upper bound for owner-set tempo (≈ 7 days at 12 s/block).
    pub const MAX_TEMPO: u16 = 50_400;
    /// Lower bound for activity-cutoff factor (per-mille). 1_000 = one full tempo.
    pub const MIN_ACTIVITY_CUTOFF_FACTOR_MILLI: u32 = 1_000;
    /// Upper bound for activity-cutoff factor (per-mille). 50_000 = 50 tempos.
    pub const MAX_ACTIVITY_CUTOFF_FACTOR_MILLI: u32 = 50_000;
    /// Default activity-cutoff factor (per-mille). 13_889 ≈ legacy 5000-block cutoff
    /// at default tempo 360 (`13_889 * 360 / 1000 = 5_000`, exact via ceiling rounding).
    pub const INITIAL_ACTIVITY_CUTOFF_FACTOR_MILLI: u32 = 13_889;

    /// Default value for activity-cutoff factor (per-mille).
    #[pallet::type_value]
    pub fn DefaultActivityCutoffFactorMilli<T: Config>() -> u32 {
        INITIAL_ACTIVITY_CUTOFF_FACTOR_MILLI
    }

    /// MAP ( netuid ) --> last epoch attempt block (consumed slot).
    /// Drives normal-cadence scheduling and the admin freeze window.
    /// Advances on every `should_run_epoch == true` slot — including consistency-skipped slots —
    /// and on a successful `sudo_set_tempo` (cycle reset).
    #[pallet::storage]
    pub type LastEpochBlock<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultZeroU64<T>>;

    /// MAP ( netuid ) --> block at which a manually triggered epoch should fire.
    /// `0` means no trigger pending. Cleared after the triggered epoch runs.
    #[pallet::storage]
    pub type PendingEpochAt<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultZeroU64<T>>;

    /// MAP ( netuid ) --> monotonic epoch counter.
    /// Incremented by exactly one each time the subnet's epoch slot is consumed in `run_coinbase`
    #[pallet::storage]
    pub type SubnetEpochIndex<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultZeroU64<T>>;

    /// MAP ( netuid ) --> activity-cutoff factor in per-mille epochs (1/1000 granularity).
    /// Effective cutoff in blocks = `(factor × tempo) / 1000`, clamped to ≥ 1.
    #[pallet::storage]
    pub type ActivityCutoffFactorMilli<T> =
        StorageMap<_, Identity, NetUid, u32, ValueQuery, DefaultActivityCutoffFactorMilli<T>>;

    // Subnet Parameters
    /// MAP ( netuid ) --> block number of first emission
    #[pallet::storage]
    pub type FirstEmissionBlockNumber<T: Config> =
        StorageMap<_, Identity, NetUid, u64, OptionQuery>;

    /// MAP ( netuid ) --> subnet mechanism
    #[pallet::storage]
    pub type SubnetMechanism<T: Config> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultZeroU16<T>>;

    /// MAP ( netuid ) --> subnetwork_n (Number of UIDs in the network).
    #[pallet::storage]
    pub type SubnetworkN<T: Config> = StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultN<T>>;

    /// MAP ( netuid ) --> network_is_added
    #[pallet::storage]
    pub type NetworksAdded<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultNeworksAdded<T>>;

    /// DMAP ( hotkey, netuid ) --> bool
    #[pallet::storage]
    pub type IsNetworkMember<T: Config> = StorageDoubleMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        Identity,
        NetUid,
        bool,
        ValueQuery,
        DefaultIsNetworkMember<T>,
    >;

    /// MAP ( netuid ) --> network_registration_allowed
    #[pallet::storage]
    pub type NetworkRegistrationAllowed<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultRegistrationAllowed<T>>;

    /// MAP ( netuid ) --> network_pow_allowed
    #[pallet::storage]
    pub type NetworkPowRegistrationAllowed<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultRegistrationAllowed<T>>;

    /// MAP ( netuid ) --> block_created
    #[pallet::storage]
    pub type NetworkRegisteredAt<T: Config> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultNetworkRegisteredAt<T>>;

    /// MAP ( netuid ) --> registered_subnet_counter
    ///
    /// Monotonic counter incremented on every successful `do_register_network`
    /// for a given netuid. Consumers that persist per-netuid state keyed by
    /// `(user, netuid)` (e.g. the staking precompile `AllowancesStorage`) can
    /// mix the current counter value into their storage key so that entries
    /// written under a previous registration of the same netuid become
    /// unreachable after the netuid is re-registered, without requiring
    /// unbounded storage iteration on deregistration.
    #[pallet::storage]
    pub type RegisteredSubnetCounter<T: Config> = StorageMap<_, Identity, NetUid, u64, ValueQuery>;

    /// MAP ( netuid ) --> pending_server_emission
    #[pallet::storage]
    pub type PendingServerEmission<T> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( netuid ) --> pending_validator_emission
    #[pallet::storage]
    pub type PendingValidatorEmission<T> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( netuid ) --> pending_root_alpha_emission
    #[pallet::storage]
    pub type PendingRootAlphaDivs<T> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// MAP ( netuid ) --> pending_owner_cut
    #[pallet::storage]
    pub type PendingOwnerCut<T> =
        StorageMap<_, Identity, NetUid, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// Default miner-burned proportion.
    #[pallet::type_value]
    pub fn DefaultMinerBurned<T: Config>() -> U96F32 {
        U96F32::saturating_from_num(0.0)
    }
    /// MAP ( netuid ) --> miner_burned | Proportion (0..1) of this tempo's miner
    /// (incentive) emission that was withheld from miners during emission distribution
    /// because the recipient hotkey is owned by the subnet owner (immune key). Counts
    /// emission that is either recycled or burned, so the value is independent of the
    /// subnet's RecycleOrBurn configuration.
    #[pallet::storage]
    pub type MinerBurned<T> =
        StorageMap<_, Identity, NetUid, U96F32, ValueQuery, DefaultMinerBurned<T>>;

    /// MAP ( netuid ) --> blocks_since_last_step
    #[pallet::storage]
    pub type BlocksSinceLastStep<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultBlocksSinceLastStep<T>>;

    /// MAP ( netuid ) --> last_mechanism_step_block
    #[pallet::storage]
    pub type LastMechansimStepBlock<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultLastMechanismStepBlock<T>>;

    /// MAP ( netuid ) --> subnet_owner
    #[pallet::storage]
    pub type SubnetOwner<T: Config> =
        StorageMap<_, Identity, NetUid, T::AccountId, ValueQuery, DefaultSubnetOwner<T>>;

    /// MAP ( netuid ) --> subnet_owner_hotkey
    #[pallet::storage]
    pub type SubnetOwnerHotkey<T: Config> =
        StorageMap<_, Identity, NetUid, T::AccountId, ValueQuery, DefaultSubnetOwner<T>>;

    /// MAP ( netuid ) --> recycle_or_burn
    #[pallet::storage]
    pub type RecycleOrBurn<T: Config> =
        StorageMap<_, Identity, NetUid, RecycleOrBurnEnum, ValueQuery, DefaultRecycleOrBurn<T>>;

    /// MAP ( netuid ) --> serving_rate_limit
    #[pallet::storage]
    pub type ServingRateLimit<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultServingRateLimit<T>>;

    /// MAP ( netuid ) --> Rho
    #[pallet::storage]
    pub type Rho<T> = StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultRho<T>>;

    /// MAP ( netuid ) --> AlphaSigmoidSteepness
    #[pallet::storage]
    pub type AlphaSigmoidSteepness<T> =
        StorageMap<_, Identity, NetUid, i16, ValueQuery, DefaultAlphaSigmoidSteepness<T>>;

    /// MAP ( netuid ) --> Kappa
    #[pallet::storage]
    pub type Kappa<T> = StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultKappa<T>>;

    /// MAP ( netuid ) --> registrations_this_interval
    #[pallet::storage]
    pub type RegistrationsThisInterval<T: Config> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery>;

    /// MAP ( netuid ) --> pow_registrations_this_interval
    #[pallet::storage]
    pub type POWRegistrationsThisInterval<T: Config> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery>;

    /// MAP ( netuid ) --> burn_registrations_this_interval
    #[pallet::storage]
    pub type BurnRegistrationsThisInterval<T: Config> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery>;

    /// MAP ( netuid ) --> min_allowed_uids
    #[pallet::storage]
    pub type MinAllowedUids<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMinAllowedUids<T>>;

    /// MAP ( netuid ) --> max_allowed_uids
    #[pallet::storage]
    pub type MaxAllowedUids<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMaxAllowedUids<T>>;

    /// MAP ( netuid ) --> immunity_period
    #[pallet::storage]
    pub type ImmunityPeriod<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultImmunityPeriod<T>>;

    /// MAP ( netuid ) --> activity_cutoff
    // #[deprecated(note = "Replaced by `ActivityCutoffFactorMilli` (per-mille of `Tempo`).")]
    #[pallet::storage]
    pub type ActivityCutoff<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultActivityCutoff<T>>;
    #[pallet::type_value]
    /// Default maximum weights limit.
    pub fn DefaultMaxWeightsLimit<T: Config>() -> u16 {
        u16::MAX
    }

    /// MAP ( netuid ) --> max_weight_limit
    #[pallet::storage]
    pub type MaxWeightsLimit<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMaxWeightsLimit<T>>;

    /// MAP ( netuid ) --> weights_version_key
    #[pallet::storage]
    pub type WeightsVersionKey<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultWeightsVersionKey<T>>;

    /// MAP ( netuid ) --> min_allowed_weights
    #[pallet::storage]
    pub type MinAllowedWeights<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMinAllowedWeights<T>>;

    /// MAP ( netuid ) --> max_allowed_validators
    #[pallet::storage]
    pub type MaxAllowedValidators<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMaxAllowedValidators<T>>;

    /// MAP ( netuid ) --> adjustment_interval
    #[pallet::storage]
    pub type AdjustmentInterval<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultAdjustmentInterval<T>>;

    /// MAP ( netuid ) --> bonds_moving_average
    #[pallet::storage]
    pub type BondsMovingAverage<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultBondsMovingAverage<T>>;

    /// MAP ( netuid ) --> bonds_penalty
    #[pallet::storage]
    pub type BondsPenalty<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultBondsPenalty<T>>;

    /// MAP ( netuid ) --> bonds_reset
    #[pallet::storage]
    pub type BondsResetOn<T> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultBondsResetOn<T>>;

    /// MAP ( netuid ) --> weights_set_rate_limit
    #[pallet::storage]
    pub type WeightsSetRateLimit<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultWeightsSetRateLimit<T>>;

    /// MAP ( netuid ) --> validator_prune_len
    #[pallet::storage]
    pub type ValidatorPruneLen<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultValidatorPruneLen<T>>;

    /// MAP ( netuid ) --> scaling_law_power
    #[pallet::storage]
    pub type ScalingLawPower<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultScalingLawPower<T>>;

    /// MAP ( netuid ) --> target_registrations_this_interval
    #[pallet::storage]
    pub type TargetRegistrationsPerInterval<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultTargetRegistrationsPerInterval<T>>;

    /// MAP ( netuid ) --> adjustment_alpha
    #[pallet::storage]
    pub type AdjustmentAlpha<T: Config> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultAdjustmentAlpha<T>>;

    /// MAP ( netuid ) --> commit reveal v2 weights are enabled
    #[pallet::storage]
    pub type CommitRevealWeightsEnabled<T> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultCommitRevealWeightsEnabled<T>>;

    /// MAP ( netuid ) --> Burn
    #[pallet::storage]
    pub type Burn<T> = StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultBurn<T>>;

    /// MAP ( netuid ) --> Difficulty
    #[pallet::storage]
    pub type Difficulty<T> = StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultDifficulty<T>>;

    /// MAP ( netuid ) --> MinBurn
    #[pallet::storage]
    pub type MinBurn<T> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultMinBurn<T>>;

    /// MAP ( netuid ) --> MaxBurn
    #[pallet::storage]
    pub type MaxBurn<T> =
        StorageMap<_, Identity, NetUid, TaoBalance, ValueQuery, DefaultMaxBurn<T>>;

    /// MAP ( netuid ) --> MinDifficulty
    #[pallet::storage]
    pub type MinDifficulty<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultMinDifficulty<T>>;

    /// MAP ( netuid ) --> MaxDifficulty
    #[pallet::storage]
    pub type MaxDifficulty<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultMaxDifficulty<T>>;

    /// MAP ( netuid ) -->  Block at last adjustment.
    #[pallet::storage]
    pub type LastAdjustmentBlock<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultLastAdjustmentBlock<T>>;

    /// MAP ( netuid ) --> Registrations of this Block.
    #[pallet::storage]
    pub type RegistrationsThisBlock<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultRegistrationsThisBlock<T>>;

    /// MAP ( netuid ) --> Halving time of average moving price.
    #[pallet::storage]
    pub type EMAPriceHalvingBlocks<T> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultEMAPriceMovingBlocks<T>>;

    /// MAP ( netuid ) --> global_RAO_recycled_for_registration
    #[pallet::storage]
    pub type RAORecycledForRegistration<T> = StorageMap<
        _,
        Identity,
        NetUid,
        TaoBalance,
        ValueQuery,
        DefaultRAORecycledForRegistration<T>,
    >;

    /// ITEM ( max_epochs_per_block )
    #[pallet::storage]
    pub type MaxEpochsPerBlock<T> = StorageValue<_, u8, ValueQuery, DefaultMaxEpochsPerBlock<T>>;

    /// ITEM ( tx_rate_limit )
    #[pallet::storage]
    pub type TxRateLimit<T> = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit<T>>;

    /// ITEM ( tx_delegate_take_rate_limit )
    #[pallet::storage]
    pub type TxDelegateTakeRateLimit<T> =
        StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit<T>>;

    /// ITEM ( tx_childkey_take_rate_limit )
    #[pallet::storage]
    pub type TxChildkeyTakeRateLimit<T> =
        StorageValue<_, u64, ValueQuery, DefaultTxChildKeyTakeRateLimit<T>>;

    /// MAP ( netuid ) --> Whether or not Liquid Alpha is enabled
    #[pallet::storage]
    pub type LiquidAlphaOn<T> =
        StorageMap<_, Blake2_128Concat, NetUid, bool, ValueQuery, DefaultLiquidAlpha<T>>;

    /// MAP ( netuid ) --> Whether or not Yuma3 is enabled
    #[pallet::storage]
    pub type Yuma3On<T> =
        StorageMap<_, Blake2_128Concat, NetUid, bool, ValueQuery, DefaultYuma3<T>>;

    ///  MAP ( netuid ) --> (alpha_low, alpha_high)
    #[pallet::storage]
    pub type AlphaValues<T> =
        StorageMap<_, Identity, NetUid, (u16, u16), ValueQuery, DefaultAlphaValues<T>>;

    /// MAP ( netuid ) --> If subtoken trading enabled
    #[pallet::storage]
    pub type SubtokenEnabled<T> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultFalse<T>>;

    /// ITEM ( dissolve_cleanup_queue ) Networks dissolved but some storage not removed yet
    #[pallet::storage]
    pub type DissolveCleanupQueue<T> = StorageValue<_, Vec<NetUid>, ValueQuery>;

    /// ITEM ( current_dissolve_cleanup_status ) dissolve status for the network
    #[pallet::storage]
    pub type CurrentDissolveCleanupStatus<T> = StorageValue<_, DissolveCleanupStatus, OptionQuery>;

    /// ITEM ( network_registration_queue ) Network registrations waiting to be executed.
    #[pallet::storage]
    pub type NetworkRegistrationQueue<T> =
        StorageValue<_, Vec<NetworkRegistrationInfo<AccountIdOf<T>>>, ValueQuery>;

    /// MAP ( coldkey ) --> lock_id
    #[pallet::storage]
    pub type NetworkRegistrationLockId<T: Config> = StorageValue<_, u32, ValueQuery>;

    // =======================================
    // ==== VotingPower Storage  ====
    // =======================================

    #[pallet::type_value]
    /// Default VotingPower EMA alpha value (0.1 represented as u64 with 18 decimals)
    /// alpha = 0.1 means slow response, 10% weight to new values per epoch
    pub fn DefaultVotingPowerEmaAlpha<T: Config>() -> u64 {
        0_003_570_000_000_000_000 // 0.00357 * 10^18 = 2 weeks e-folding (time-constant) @ 361
        // blocks per tempo
        // After 2 weeks  -> EMA reaches 63.2% of a step change
        // After ~4 weeks -> 86.5%
        // After ~6 weeks -> 95%
    }

    #[pallet::storage]
    /// DMAP ( netuid, hotkey ) --> voting_power | EMA of stake for voting
    /// This tracks stake EMA updated every epoch when VotingPowerTrackingEnabled is true.
    /// Used by smart contracts to determine validator voting power for subnet governance.
    pub type VotingPower<T: Config> =
        StorageDoubleMap<_, Identity, NetUid, Blake2_128Concat, T::AccountId, u64, ValueQuery>;

    #[pallet::storage]
    /// MAP ( netuid ) --> bool | Whether voting power tracking is enabled for this subnet.
    /// When enabled, VotingPower EMA is updated every epoch. Default is false.
    /// When disabled with disable_at_block set, tracking continues until that block.
    pub type VotingPowerTrackingEnabled<T: Config> =
        StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultFalse<T>>;

    #[pallet::storage]
    /// MAP ( netuid ) --> block_number | Block at which voting power tracking will be disabled.
    /// When set (non-zero), tracking continues until this block, then automatically disables
    /// and clears VotingPower entries for the subnet. Provides a 14-day grace period.
    pub type VotingPowerDisableAtBlock<T: Config> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery>;

    #[pallet::storage]
    /// MAP ( netuid ) --> u64 | EMA alpha value for voting power calculation.
    /// Higher alpha = faster response to stake changes.
    /// Stored as u64 with 18 decimal precision (1.0 = 10^18).
    /// Only settable by sudo/root.
    pub type VotingPowerEmaAlpha<T: Config> =
        StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultVotingPowerEmaAlpha<T>>;

    #[pallet::type_value]
    /// Default value for burn keys limit
    pub fn DefaultImmuneOwnerUidsLimit<T: Config>() -> u16 {
        1
    }

    /// Maximum value for burn keys limit
    #[pallet::type_value]
    pub fn MaxImmuneOwnerUidsLimit<T: Config>() -> u16 {
        10
    }

    /// Minimum value for burn keys limit
    #[pallet::type_value]
    pub fn MinImmuneOwnerUidsLimit<T: Config>() -> u16 {
        1
    }

    /// MAP ( netuid ) --> Burn key limit
    #[pallet::storage]
    pub type ImmuneOwnerUidsLimit<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultImmuneOwnerUidsLimit<T>>;

    // Subnetwork Consensus Storage
    /// DMAP ( netuid ) --> stake_weight | weight for stake used in YC.
    #[pallet::storage]
    pub type StakeWeight<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;

    /// DMAP ( netuid, hotkey ) --> uid
    #[pallet::storage]
    pub type Uids<T: Config> =
        StorageDoubleMap<_, Identity, NetUid, Blake2_128Concat, T::AccountId, u16, OptionQuery>;

    /// DMAP ( netuid, uid ) --> hotkey
    #[pallet::storage]
    pub type Keys<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Identity,
        u16,
        T::AccountId,
        ValueQuery,
        DefaultKey<T>,
    >;

    /// MAP ( netuid ) --> (hotkey, se, ve)
    #[pallet::storage]
    pub type LoadedEmission<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<(T::AccountId, u64, u64)>, OptionQuery>;

    /// MAP ( netuid ) --> active
    #[pallet::storage]
    pub type Active<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<bool>, ValueQuery, EmptyBoolVec<T>>;

    /// MAP ( netuid ) --> consensus
    #[pallet::storage]
    pub type Consensus<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<PerU16>, ValueQuery, EmptyPerU16Vec<T>>;

    /// MAP ( netuid ) --> incentive
    #[pallet::storage]
    pub type Incentive<T: Config> =
        StorageMap<_, Identity, NetUidStorageIndex, Vec<PerU16>, ValueQuery, EmptyPerU16Vec<T>>;

    /// MAP ( netuid ) --> dividends
    #[pallet::storage]
    pub type Dividends<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<PerU16>, ValueQuery, EmptyPerU16Vec<T>>;

    /// MAP ( netuid ) --> emission
    #[pallet::storage]
    pub type Emission<T: Config> = StorageMap<_, Identity, NetUid, Vec<AlphaBalance>, ValueQuery>;

    /// MAP ( netuid ) --> last_update
    #[pallet::storage]
    pub type LastUpdate<T: Config> =
        StorageMap<_, Identity, NetUidStorageIndex, Vec<u64>, ValueQuery, EmptyU64Vec<T>>;

    /// MAP ( netuid ) --> validator_trust
    #[pallet::storage]
    pub type ValidatorTrust<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<PerU16>, ValueQuery, EmptyPerU16Vec<T>>;

    /// MAP ( netuid ) --> validator_permit
    #[pallet::storage]
    pub type ValidatorPermit<T: Config> =
        StorageMap<_, Identity, NetUid, Vec<bool>, ValueQuery, EmptyBoolVec<T>>;

    /// DMAP ( netuid, uid ) --> weights
    #[pallet::storage]
    pub type Weights<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUidStorageIndex,
        Identity,
        u16,
        Vec<(u16, u16)>,
        ValueQuery,
        DefaultWeights<T>,
    >;

    /// DMAP ( netuid, uid ) --> bonds
    #[pallet::storage]
    pub type Bonds<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUidStorageIndex,
        Identity,
        u16,
        Vec<(u16, u16)>,
        ValueQuery,
        DefaultBonds<T>,
    >;

    /// DMAP ( netuid, uid ) --> block_at_registration
    #[pallet::storage]
    pub type BlockAtRegistration<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Identity,
        u16,
        u64,
        ValueQuery,
        DefaultBlockAtRegistration<T>,
    >;

    /// MAP ( netuid, hotkey ) --> axon_info
    #[pallet::storage]
    pub type Axons<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        AxonInfoOf,
        OptionQuery,
    >;

    /// MAP ( netuid, hotkey ) --> certificate
    #[pallet::storage]
    pub type NeuronCertificates<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        NeuronCertificateOf,
        OptionQuery,
    >;

    /// MAP ( netuid, hotkey ) --> prometheus_info
    #[pallet::storage]
    pub type Prometheus<T: Config> = StorageDoubleMap<
        _,
        Identity,
        NetUid,
        Blake2_128Concat,
        T::AccountId,
        PrometheusInfoOf,
        OptionQuery,
    >;

    /// MAP ( coldkey ) --> identity
    #[pallet::storage]
    pub type IdentitiesV2<T: Config> =
        StorageMap<_, Blake2_128Concat, T::AccountId, ChainIdentityOfV2, OptionQuery>;

    /// MAP ( netuid ) --> SubnetIdentityOfV3
    #[pallet::storage]
    pub type SubnetIdentitiesV3<T: Config> =
        StorageMap<_, Blake2_128Concat, NetUid, SubnetIdentityOfV3, OptionQuery>;

    // Axon / Promo Endpoints
    /// NMAP ( hot, netuid, name ) --> last_block | Returns the last block of a transaction for a given key, netuid, and name.
    #[pallet::storage]
    pub type TransactionKeyLastBlock<T: Config> = StorageNMap<
        _,
        (
            NMapKey<Blake2_128Concat, T::AccountId>, // hot
            NMapKey<Identity, NetUid>,               // netuid
            NMapKey<Identity, u16>,                  // extrinsic enum.
        ),
        u64,
        ValueQuery,
    >;

    /// MAP ( key ) --> last_block
    #[deprecated]
    #[pallet::storage]
    pub type LastTxBlock<T: Config> =
        StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock<T>>;

    /// MAP ( key ) --> last_tx_block_childkey_take
    #[deprecated]
    #[pallet::storage]
    pub type LastTxBlockChildKeyTake<T: Config> =
        StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock<T>>;

    /// MAP ( key ) --> last_tx_block_delegate_take
    #[deprecated]
    #[pallet::storage]
    pub type LastTxBlockDelegateTake<T: Config> =
        StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock<T>>;

    /// ITEM( weights_min_stake )
    // FIXME: this storage is used interchangably for alpha/tao
    #[pallet::storage]
    pub type StakeThreshold<T> = StorageValue<_, u64, ValueQuery, DefaultStakeThreshold<T>>;

    /// MAP (netuid, who) --> VecDeque<(hash, commit_epoch, commit_block, _unused)>
    /// Stores a queue of commit-reveal-v2 commits for an account on a given netuid.
    #[pallet::storage]
    pub type WeightCommits<T: Config> = StorageDoubleMap<
        _,
        Twox64Concat,
        NetUidStorageIndex,
        Twox64Concat,
        T::AccountId,
        VecDeque<(H256, u64, u64, u64)>,
        OptionQuery,
    >;

    /// MAP (netuid, epoch) → VecDeque<(who, commit_block, ciphertext, reveal_round)>
    /// Stores a queue of weight commits for an account on a given subnet.
    #[pallet::storage]
    pub type TimelockedWeightCommits<T: Config> = StorageDoubleMap<
        _,
        Twox64Concat,
        NetUidStorageIndex,
        Twox64Concat,
        u64, // epoch key
        VecDeque<(
            T::AccountId,
            u64, // commit_block
            BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>>,
            RoundNumber,
        )>,
        ValueQuery,
    >;

    /// MAP (netuid, epoch) → VecDeque<(who, ciphertext, reveal_round)>
    /// Deprecated: superseded by `CRV3WeightCommitsV2`.
    #[pallet::storage]
    pub type CRV3WeightCommits<T: Config> = StorageDoubleMap<
        _,
        Twox64Concat,
        NetUidStorageIndex,
        Twox64Concat,
        u64, // epoch key
        VecDeque<(
            T::AccountId,
            BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>>,
            RoundNumber,
        )>,
        ValueQuery,
    >;

    /// MAP (netuid, epoch) → VecDeque<(who, commit_block, ciphertext, reveal_round)>
    /// Deprecated: superseded by `TimelockedWeightCommits`.
    #[pallet::storage]
    pub type CRV3WeightCommitsV2<T: Config> = StorageDoubleMap<
        _,
        Twox64Concat,
        NetUidStorageIndex,
        Twox64Concat,
        u64, // epoch key
        VecDeque<(
            T::AccountId,
            u64, // commit_block
            BoundedVec<u8, ConstU32<MAX_CRV3_COMMIT_SIZE_BYTES>>,
            RoundNumber,
        )>,
        ValueQuery,
    >;

    /// Map (netuid) --> Number of epochs allowed for commit reveal periods
    #[pallet::storage]
    pub type RevealPeriodEpochs<T: Config> =
        StorageMap<_, Twox64Concat, NetUid, u64, ValueQuery, DefaultRevealPeriodEpochs<T>>;

    /// Map (coldkey, hotkey) --> u64 the last block at which stake was added/removed.
    #[pallet::storage]
    pub type LastColdkeyHotkeyStakeBlock<T: Config> = StorageDoubleMap<
        _,
        Twox64Concat,
        T::AccountId,
        Twox64Concat,
        T::AccountId,
        u64,
        OptionQuery,
    >;

    #[pallet::storage] // --- MAP(netuid ) --> Root claim threshold
    pub type RootClaimableThreshold<T: Config> =
        StorageMap<_, Blake2_128Concat, NetUid, I96F32, ValueQuery, DefaultMinRootClaimAmount<T>>;

    #[pallet::storage] // --- MAP ( hot ) --> MAP(netuid ) --> claimable_dividends | Root claimable dividends.
    pub type RootClaimable<T: Config> = StorageMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        BTreeMap<NetUid, I96F32>,
        ValueQuery,
        DefaultRootClaimable<T>,
    >;

    // Already claimed root alpha.
    #[pallet::storage]
    pub type RootClaimed<T: Config> = StorageNMap<
        _,
        (
            NMapKey<Identity, NetUid>,               // subnet
            NMapKey<Blake2_128Concat, T::AccountId>, // hot
            NMapKey<Blake2_128Concat, T::AccountId>, // cold
        ),
        u128,
        ValueQuery,
    >;
    #[pallet::storage] // -- MAP ( cold ) --> root_claim_type enum
    pub type RootClaimType<T: Config> = StorageMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        RootClaimTypeEnum,
        ValueQuery,
        DefaultRootClaimType<T>,
    >;
    #[pallet::storage] // --- MAP ( u64 ) --> coldkey | Maps coldkeys that have stake to an index
    pub type StakingColdkeysByIndex<T: Config> =
        StorageMap<_, Identity, u64, T::AccountId, OptionQuery>;

    #[pallet::storage] // --- MAP ( coldkey ) --> index | Maps index that have stake to a coldkey
    pub type StakingColdkeys<T: Config> = StorageMap<_, Identity, T::AccountId, u64, OptionQuery>;

    #[pallet::storage] // --- Value --> num_staking_coldkeys
    pub type NumStakingColdkeys<T: Config> = StorageValue<_, u64, ValueQuery, DefaultZeroU64<T>>;
    #[pallet::storage] // --- Value --> num_root_claim | Number of coldkeys to claim each auto-claim.
    pub type NumRootClaim<T: Config> = StorageValue<_, u64, ValueQuery, DefaultNumRootClaim<T>>;

    // EVM related storage
    /// DMAP (netuid, uid) --> (H160, last_block_where_ownership_was_proven)
    #[pallet::storage]
    pub type AssociatedEvmAddress<T: Config> =
        StorageDoubleMap<_, Twox64Concat, NetUid, Twox64Concat, u16, (H160, u64), OptionQuery>;

    /// DMAP (netuid, H160) --> associated UIDs and last block where ownership was proven.
    #[pallet::storage]
    pub type AssociatedUidsByEvmAddress<T: Config> = StorageDoubleMap<
        _,
        Twox64Concat,
        NetUid,
        Twox64Concat,
        H160,
        BoundedVec<(u16, u64), ConstU32<MAX_ASSOCIATED_UIDS_PER_EVM_ADDRESS>>,
        ValueQuery,
    >;

    // Subnet Leasing
    /// MAP ( lease_id ) --> subnet lease | The subnet lease for a given lease id.
    #[pallet::storage]
    pub type SubnetLeases<T: Config> =
        StorageMap<_, Twox64Concat, LeaseId, SubnetLeaseOf<T>, OptionQuery>;

    /// DMAP ( lease_id, contributor ) --> shares | The shares of a contributor for a given lease.
    #[pallet::storage]
    pub type SubnetLeaseShares<T: Config> =
        StorageDoubleMap<_, Twox64Concat, LeaseId, Identity, T::AccountId, U64F64, ValueQuery>;

    /// MAP ( netuid ) --> lease_id | The lease id for a given netuid.
    #[pallet::storage]
    pub type SubnetUidToLeaseId<T: Config> =
        StorageMap<_, Twox64Concat, NetUid, LeaseId, OptionQuery>;

    /// ITEM ( next_lease_id ) | The next lease id.
    #[pallet::storage]
    pub type NextSubnetLeaseId<T: Config> = StorageValue<_, LeaseId, ValueQuery, ConstU32<0>>;

    /// MAP ( lease_id ) --> accumulated_dividends | The accumulated dividends for a given lease that needs to be distributed.
    #[pallet::storage]
    pub type AccumulatedLeaseDividends<T: Config> =
        StorageMap<_, Twox64Concat, LeaseId, AlphaBalance, ValueQuery, DefaultZeroAlpha<T>>;

    /// ITEM ( CommitRevealWeightsVersion )
    #[pallet::storage]
    pub type CommitRevealWeightsVersion<T> =
        StorageValue<_, u16, ValueQuery, DefaultCommitRevealWeightsVersion<T>>;

    /// ITEM( NetworkRegistrationStartBlock )
    #[pallet::storage]
    pub type NetworkRegistrationStartBlock<T> =
        StorageValue<_, u64, ValueQuery, DefaultNetworkRegistrationStartBlock<T>>;

    /// ITEM( TaoInRefundDeploymentBlock )
    #[pallet::storage]
    pub type TaoInRefundDeploymentBlock<T> =
        StorageValue<_, u64, ValueQuery, DefaultTaoInRefundDeploymentBlock>;

    /// MAP ( netuid ) --> minimum required number of non-immortal & non-immune UIDs
    #[pallet::storage]
    pub type MinNonImmuneUids<T: Config> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultMinNonImmuneUids<T>>;

    // Subnet Mechanisms
    /// ITEM (Default number of sub-subnets)
    #[pallet::type_value]
    pub fn DefaultMechanismCount<T: Config>() -> MechId {
        MechId::from(1)
    }

    /// ITEM (Maximum number of mechanisms)
    #[pallet::type_value]
    pub fn DefaultMaxMechanismCount<T: Config>() -> MechId {
        MechId::from(2)
    }

    /// ITEM( max_mechanism_count )
    #[pallet::storage]
    pub type MaxMechanismCount<T> =
        StorageValue<_, MechId, ValueQuery, DefaultMaxMechanismCount<T>>;

    /// ITEM (Rate limit for mechanism count updates)
    #[pallet::type_value]
    pub fn MechanismCountSetRateLimit<T: Config>() -> u64 {
        prod_or_fast!(7_200, 1)
    }

    /// ITEM (Rate limit for mechanism emission distribution updates)
    #[pallet::type_value]
    pub fn MechanismEmissionRateLimit<T: Config>() -> u64 {
        prod_or_fast!(7_200, 1)
    }

    /// MAP ( netuid ) --> Current number of subnet mechanisms
    #[pallet::storage]
    pub type MechanismCountCurrent<T: Config> =
        StorageMap<_, Twox64Concat, NetUid, MechId, ValueQuery, DefaultMechanismCount<T>>;

    /// MAP ( netuid ) --> Normalized vector of emission split proportion between subnet mechanisms
    #[pallet::storage]
    pub type MechanismEmissionSplit<T: Config> =
        StorageMap<_, Twox64Concat, NetUid, Vec<u16>, OptionQuery>;

    /// MAP ( netuid ) --> BurnHalfLife (blocks)
    #[pallet::storage]
    pub type BurnHalfLife<T> =
        StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultBurnHalfLife<T>>;

    /// MAP ( netuid ) --> BurnIncreaseMult
    #[pallet::storage]
    pub type BurnIncreaseMult<T> =
        StorageMap<_, Identity, NetUid, U64F64, ValueQuery, DefaultBurnIncreaseMult<T>>;

    /// MAP ( hotkey ) --> parent_delegation_enabled
    ///
    /// When `true`, this root validator allows auto parent delegation.
    /// Defaults to `true`; validators can opt out at any time
    /// by calling `set_auto_parent_delegation_enabled(false)`.
    #[pallet::storage]
    pub type AutoParentDelegationEnabled<T: Config> = StorageMap<
        _,
        Blake2_128Concat,
        T::AccountId,
        bool,
        ValueQuery,
        DefaultAutoParentDelegationEnabled<T>, // default = true
    >;

    // Genesis
    /// Storage for migration run status
    #[pallet::storage]
    pub type HasMigrationRun<T: Config> = StorageMap<_, Identity, Vec<u8>, bool, ValueQuery>;

    /// Default value for pending childkey cooldown (settable by root).
    /// Uses the same value as DefaultPendingCooldown for consistency.
    #[pallet::type_value]
    pub fn DefaultPendingChildKeyCooldown<T: Config>() -> u64 {
        DefaultPendingCooldown::<T>::get()
    }

    /// Storage value for pending childkey cooldown, settable by root.
    #[pallet::storage]
    pub type PendingChildKeyCooldown<T: Config> =
        StorageValue<_, u64, ValueQuery, DefaultPendingChildKeyCooldown<T>>;

    #[pallet::genesis_config]
    pub struct GenesisConfig<T: Config> {
        /// Stakes record in genesis.
        pub stakes: Vec<(T::AccountId, Vec<(T::AccountId, (u64, u16))>)>,
        /// The total issued balance in genesis
        pub balances_issuance: TaoBalance,
        /// The delay before a subnet can call start
        pub start_call_delay: Option<u64>,
    }

    impl<T: Config> Default for GenesisConfig<T> {
        fn default() -> Self {
            Self {
                stakes: Default::default(),
                balances_issuance: TaoBalance::ZERO,
                start_call_delay: None,
            }
        }
    }

    // ---- Subtensor helper functions.
    impl<T: Config> Pallet<T> {
        /// Is the caller allowed to set weights
        pub fn check_weights_min_stake(hotkey: &T::AccountId, netuid: NetUid) -> bool {
            // Allow the subnet owner hotkey to set weights regardless of stake.
            if let Some(owner_uid) = Self::get_owner_uid(netuid)
                && Uids::<T>::get(netuid, hotkey) == Some(owner_uid)
            {
                return true;
            }

            // Blacklist weights transactions for low stake peers.
            let (total_stake, _, _) = Self::get_stake_weights_for_hotkey_on_subnet(hotkey, netuid);
            total_stake >= Self::get_stake_threshold()
        }
        /// Helper function to check if register is allowed
        pub fn checked_allowed_register(netuid: NetUid) -> bool {
            if netuid.is_root() {
                return false;
            }
            if !Self::if_subnet_exist(netuid) {
                return false;
            }
            if !Self::get_network_registration_allowed(netuid) {
                return false;
            }
            if Self::get_registrations_this_block(netuid)
                >= Self::get_max_registrations_per_block(netuid)
            {
                return false;
            }
            if Self::get_registrations_this_interval(netuid)
                >= Self::get_target_registrations_per_interval(netuid).saturating_mul(3)
            {
                return false;
            }
            true
        }

        /// Ensure subtoken enalbed
        pub fn ensure_subtoken_enabled(subnet: NetUid) -> Result<(), Error<T>> {
            ensure!(
                SubtokenEnabled::<T>::get(subnet),
                Error::<T>::SubtokenDisabled
            );
            Ok(())
        }
    }
}

use sp_std::vec;

// TODO: unravel this rats nest, for some reason rustc thinks this is unused even though it's
// used not 25 lines below
#[allow(unused)]
use sp_std::vec::Vec;
use subtensor_macros::freeze_struct;

#[derive(Clone)]
pub struct TaoBalanceReserve<T: Config>(PhantomData<T>);

impl<T: Config> TokenReserve<TaoBalance> for TaoBalanceReserve<T> {
    #![deny(clippy::expect_used)]
    fn reserve(netuid: NetUid) -> TaoBalance {
        SubnetTAO::<T>::get(netuid)
    }

    fn increase_provided(netuid: NetUid, tao: TaoBalance) {
        Pallet::<T>::increase_provided_tao_reserve(netuid, tao);
    }

    fn decrease_provided(netuid: NetUid, tao: TaoBalance) {
        Pallet::<T>::decrease_provided_tao_reserve(netuid, tao);
    }
}

#[derive(Clone)]
pub struct AlphaBalanceReserve<T: Config>(PhantomData<T>);

impl<T: Config> TokenReserve<AlphaBalance> for AlphaBalanceReserve<T> {
    #![deny(clippy::expect_used)]
    fn reserve(netuid: NetUid) -> AlphaBalance {
        SubnetAlphaIn::<T>::get(netuid)
    }

    fn increase_provided(netuid: NetUid, alpha: AlphaBalance) {
        Pallet::<T>::increase_provided_alpha_reserve(netuid, alpha);
    }

    fn decrease_provided(netuid: NetUid, alpha: AlphaBalance) {
        Pallet::<T>::decrease_provided_alpha_reserve(netuid, alpha);
    }
}

pub type GetAlphaForTao<T> =
    subtensor_swap_interface::GetAlphaForTao<TaoBalanceReserve<T>, AlphaBalanceReserve<T>>;
pub type GetTaoForAlpha<T> =
    subtensor_swap_interface::GetTaoForAlpha<AlphaBalanceReserve<T>, TaoBalanceReserve<T>>;

impl<T: Config + pallet_balances::Config<Balance = TaoBalance>>
    subtensor_runtime_common::SubnetInfo<T::AccountId> for Pallet<T>
{
    #![deny(clippy::expect_used)]
    fn exists(netuid: NetUid) -> bool {
        Self::if_subnet_exist(netuid)
    }

    fn mechanism(netuid: NetUid) -> u16 {
        SubnetMechanism::<T>::get(netuid)
    }

    fn is_owner(account_id: &T::AccountId, netuid: NetUid) -> bool {
        SubnetOwner::<T>::get(netuid) == *account_id
    }

    fn is_subtoken_enabled(netuid: NetUid) -> bool {
        SubtokenEnabled::<T>::get(netuid)
    }

    fn get_validator_trust(netuid: NetUid) -> Vec<u16> {
        ValidatorTrust::<T>::get(netuid)
            .into_iter()
            .map(PerU16::deconstruct)
            .collect()
    }

    fn get_validator_permit(netuid: NetUid) -> Vec<bool> {
        ValidatorPermit::<T>::get(netuid)
    }

    fn hotkey_of_uid(netuid: NetUid, uid: u16) -> Option<T::AccountId> {
        Keys::<T>::try_get(netuid, uid).ok()
    }
}

impl<T: Config + pallet_balances::Config<Balance = TaoBalance>>
    subtensor_runtime_common::BalanceOps<T::AccountId> for Pallet<T>
{
    #![deny(clippy::expect_used)]
    fn tao_balance(account_id: &T::AccountId) -> TaoBalance {
        pallet_balances::Pallet::<T>::free_balance(account_id).into()
    }

    fn alpha_balance(
        netuid: NetUid,
        coldkey: &T::AccountId,
        hotkey: &T::AccountId,
    ) -> AlphaBalance {
        Self::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid)
    }

    fn increase_stake(
        coldkey: &T::AccountId,
        hotkey: &T::AccountId,
        netuid: NetUid,
        alpha: AlphaBalance,
    ) -> Result<(), DispatchError> {
        ensure!(
            Self::hotkey_account_exists(hotkey),
            Error::<T>::HotKeyAccountNotExists
        );

        // Increse alpha out counter
        SubnetAlphaOut::<T>::mutate(netuid, |total| {
            *total = total.saturating_add(alpha);
        });

        Self::increase_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);

        Ok(())
    }

    fn decrease_stake(
        coldkey: &T::AccountId,
        hotkey: &T::AccountId,
        netuid: NetUid,
        alpha: AlphaBalance,
    ) -> Result<(), DispatchError> {
        ensure!(
            Self::hotkey_account_exists(hotkey),
            Error::<T>::HotKeyAccountNotExists
        );

        ensure!(
            Self::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid) >= alpha,
            Error::<T>::InsufficientAlphaBalance
        );

        // Decrese alpha out counter
        SubnetAlphaOut::<T>::mutate(netuid, |total| {
            *total = total.saturating_sub(alpha);
        });

        Self::decrease_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);

        Ok(())
    }
}

/// Enum that defines types of rate limited operations for
/// storing last block when this operation occured
#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo)]
pub enum RateLimitKey<AccountId> {
    // The setting sn owner hotkey operation is rate limited per netuid
    #[codec(index = 0)]
    SetSNOwnerHotkey(NetUid),
    // Generic rate limit for subnet-owner hyperparameter updates (per netuid)
    #[codec(index = 1)]
    OwnerHyperparamUpdate(NetUid, Hyperparameter),
    // Subnet registration rate limit
    #[codec(index = 2)]
    NetworkLastRegistered,
    // Last tx block limit per account ID
    #[codec(index = 3)]
    LastTxBlock(AccountId),
    // Last tx block child key limit per account ID
    #[codec(index = 4)]
    LastTxBlockChildKeyTake(AccountId),
    // Last tx block delegate key limit per account ID
    #[codec(index = 5)]
    LastTxBlockDelegateTake(AccountId),
    // "Add stake and burn" rate limit
    #[codec(index = 6)]
    AddStakeBurn(NetUid),
}

pub trait ProxyInterface<AccountId> {
    fn add_lease_beneficiary_proxy(beneficiary: &AccountId, lease: &AccountId) -> DispatchResult;
    fn remove_lease_beneficiary_proxy(beneficiary: &AccountId, lease: &AccountId)
    -> DispatchResult;
}

impl<T> ProxyInterface<T> for () {
    fn add_lease_beneficiary_proxy(_: &T, _: &T) -> DispatchResult {
        Ok(())
    }

    fn remove_lease_beneficiary_proxy(_: &T, _: &T) -> DispatchResult {
        Ok(())
    }
}

/// Pallets that hold per-subnet commitments implement this to purge all state for `netuid`.
pub trait CommitmentsInterface {
    fn purge_netuid(netuid: NetUid, weight_meter: &mut WeightMeter) -> bool;
}