#![cfg_attr(not(feature = "std"), no_std)] use sp_runtime::{traits::StaticLookup, DispatchResult}; use sp_std::prelude::*; use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable}; mod extension; #[cfg(test)] mod mock; #[cfg(test)] mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; pub mod weights; pub use weights::WeightInfo; pub use extension::CheckOnlySudoAccount; pub use pallet::*; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; #[frame_support::pallet] pub mod pallet { use super::{DispatchResult, *}; use frame_support::pallet_prelude::*; use frame_system::{pallet_prelude::*, RawOrigin}; pub mod config_preludes { use super::*; use frame_support::derive_impl; pub struct TestDefaultConfig; #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] impl DefaultConfig for TestDefaultConfig { type WeightInfo = (); #[inject_runtime_type] type RuntimeEvent = (); #[inject_runtime_type] type RuntimeCall = (); } } #[pallet::config(with_default)] pub trait Config: frame_system::Config { #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; #[pallet::no_default_bounds] type RuntimeCall: Parameter + UnfilteredDispatchable + GetDispatchInfo; type WeightInfo: WeightInfo; } #[pallet::pallet] pub struct Pallet(_); #[pallet::call] impl Pallet { #[pallet::call_index(0)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( T::WeightInfo::sudo().saturating_add(dispatch_info.weight), dispatch_info.class ) })] pub fn sudo( origin: OriginFor, call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { Self::ensure_sudo(origin)?; let res = call.dispatch_bypass_filter(RawOrigin::Root.into()); Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error), }); Ok(Pays::No.into()) } #[pallet::call_index(1)] #[pallet::weight((*weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor, call: Box<::RuntimeCall>, weight: Weight, ) -> DispatchResultWithPostInfo { Self::ensure_sudo(origin)?; let _ = weight; let res = call.dispatch_bypass_filter(RawOrigin::Root.into()); Self::deposit_event(Event::Sudid { sudo_result: res.map(|_| ()).map_err(|e| e.error), }); Ok(Pays::No.into()) } #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::set_key())] pub fn set_key( origin: OriginFor, new: AccountIdLookupOf, ) -> DispatchResultWithPostInfo { Self::ensure_sudo(origin)?; let new = T::Lookup::lookup(new)?; Self::deposit_event(Event::KeyChanged { old: Key::::get(), new: new.clone(), }); Key::::put(new); Ok(Pays::No.into()) } #[pallet::call_index(3)] #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( T::WeightInfo::sudo_as().saturating_add(dispatch_info.weight), dispatch_info.class, ) })] pub fn sudo_as( origin: OriginFor, who: AccountIdLookupOf, call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { Self::ensure_sudo(origin)?; let who = T::Lookup::lookup(who)?; let res = call.dispatch_bypass_filter(RawOrigin::Signed(who).into()); Self::deposit_event(Event::SudoAsDone { sudo_result: res.map(|_| ()).map_err(|e| e.error), }); Ok(Pays::No.into()) } #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::remove_key())] pub fn remove_key(origin: OriginFor) -> DispatchResultWithPostInfo { Self::ensure_sudo(origin)?; Self::deposit_event(Event::KeyRemoved {}); Key::::kill(); Ok(Pays::No.into()) } } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { Sudid { sudo_result: DispatchResult, }, KeyChanged { old: Option, new: T::AccountId, }, KeyRemoved, SudoAsDone { sudo_result: DispatchResult, }, } #[pallet::error] pub enum Error { RequireSudo, } #[pallet::storage] pub(super) type Key = StorageValue<_, T::AccountId, OptionQuery>; #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { pub key: Option, } #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { Key::::set(self.key.clone()); } } impl Pallet { pub(crate) fn ensure_sudo(origin: OriginFor) -> DispatchResult { let sender = ensure_signed_or_root(origin)?; if let Some(sender) = sender { if Key::::get().map_or(false, |k| k == sender) { Ok(()) } else { Err(Error::::RequireSudo.into()) } } else { Ok(()) } } } }