use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; use frame_support::traits::{Contains, GetCallIndex, GetCallName, PalletInfoAccess}; use scale_info::TypeInfo; use sp_runtime::Vec; use subtensor_macros::freeze_struct; /// Shared proxy filter model exposed by the runtime API. /// /// Runtime filtering remains the source of truth. This metadata is the client-facing /// allowlist view of the same rules. /// Stable proxy type identifiers used on-chain and by RPC clients. #[derive( Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, DecodeWithMemTracking, Debug, MaxEncodedLen, TypeInfo, )] pub enum ProxyType { Any, Owner, NonCritical, NonTransfer, Senate, NonFungible, // Nothing involving moving TAO Triumvirate, Governance, Staking, Registration, Transfer, SmallTransfer, RootWeights, // Deprecated ChildKeys, SudoUncheckedSetCode, SwapHotkey, SubnetLeaseBeneficiary, RootClaim, } impl TryFrom for ProxyType { type Error = (); fn try_from(value: u8) -> Result { match value { 0 => Ok(Self::Any), 1 => Ok(Self::Owner), 2 => Ok(Self::NonCritical), 3 => Ok(Self::NonTransfer), 4 => Ok(Self::Senate), 5 => Ok(Self::NonFungible), 6 => Ok(Self::Triumvirate), 7 => Ok(Self::Governance), 8 => Ok(Self::Staking), 9 => Ok(Self::Registration), 10 => Ok(Self::Transfer), 11 => Ok(Self::SmallTransfer), 12 => Ok(Self::RootWeights), 13 => Ok(Self::ChildKeys), 14 => Ok(Self::SudoUncheckedSetCode), 15 => Ok(Self::SwapHotkey), 16 => Ok(Self::SubnetLeaseBeneficiary), 17 => Ok(Self::RootClaim), _ => Err(()), } } } impl From for u8 { fn from(proxy_type: ProxyType) -> Self { match proxy_type { ProxyType::Any => 0, ProxyType::Owner => 1, ProxyType::NonCritical => 2, ProxyType::NonTransfer => 3, ProxyType::Senate => 4, ProxyType::NonFungible => 5, ProxyType::Triumvirate => 6, ProxyType::Governance => 7, ProxyType::Staking => 8, ProxyType::Registration => 9, ProxyType::Transfer => 10, ProxyType::SmallTransfer => 11, ProxyType::RootWeights => 12, ProxyType::ChildKeys => 13, ProxyType::SudoUncheckedSetCode => 14, ProxyType::SwapHotkey => 15, ProxyType::SubnetLeaseBeneficiary => 16, ProxyType::RootClaim => 17, } } } impl ProxyType { pub fn is_deprecated(&self) -> bool { matches!( self, Self::Triumvirate | Self::Senate | Self::Governance | Self::RootWeights ) } } impl Default for ProxyType { fn default() -> Self { Self::Any } } /// Extra constraint attached to an allowed call. #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo)] pub enum CallConstraint { /// The named numeric parameter must be lower than `limit`. ParamLessThan { param_name: Vec, limit: u128 }, /// The named boxed call parameter must target this pallet/call pair. NestedCallMustBe { param_name: Vec, pallet_name: Vec, call_name: Vec, }, } /// Runtime call identity exposed in proxy filter metadata. #[freeze_struct("85f86877d3d9b870")] #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo)] pub struct CallInfo { /// Runtime pallet name. pub pallet_name: Vec, /// Runtime pallet index. pub pallet_index: u8, /// Pallet call name. pub call_name: Vec, /// Pallet call index. pub call_index: u8, /// Optional value or nested-call constraint. pub constraint: Option, } pub fn call_info_by_name( name: &str, ) -> CallInfo { let names = C::get_call_names(); let indices = C::get_call_indices(); let pos = names .iter() .position(|n| *n == name) .unwrap_or_else(|| panic!("Call '{}' not found in pallet '{}'", name, P::name())); CallInfo { pallet_name: P::name().as_bytes().to_vec(), pallet_index: P::index() as u8, call_name: name.as_bytes().to_vec(), call_index: indices .get(pos) .copied() .unwrap_or_else(|| panic!("Call '{}' index out of bounds in '{}'", name, P::name())), constraint: None, } } /// Metadata view for a call filter group. /// /// Implementations should be generated from the same rules as the executable /// filter so clients and runtime behavior cannot drift. pub trait CallFilterMetadata { fn call_infos() -> Vec; } /// A reusable filter group: executable predicate plus metadata for clients. pub trait CallFilterGroup: Contains + CallFilterMetadata {} impl CallFilterGroup for T where T: Contains + CallFilterMetadata {} impl CallFilterMetadata for () { fn call_infos() -> Vec { Vec::new() } } #[impl_trait_for_tuples::impl_for_tuples(1, 32)] impl CallFilterMetadata for Tuple { fn call_infos() -> Vec { let mut infos = Vec::new(); for_tuples!( #( infos.extend(Tuple::call_infos()); )* ); infos } } /// Public metadata model for a proxy filter. #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo)] pub enum FilterMode { /// All runtime calls are allowed. AllowAll, /// Only listed calls are allowed. An empty list means deny all. Allow(Vec), } /// Runtime API response for one proxy type. #[freeze_struct("288413f4da5ab4ee")] #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo)] pub struct ProxyFilterInfo { pub proxy_type: u8, pub name: Vec, pub deprecated: bool, pub filter_mode: FilterMode, } #[freeze_struct("b0cce66ed9b2451b")] #[derive(Clone, PartialEq, Eq, Encode, Decode, Debug, TypeInfo)] pub struct ProxyTypeInfo { pub name: Vec, pub index: u8, pub deprecated: bool, }