#![doc = docify::embed!("src/tests.rs", sudo_basics)]
#![doc = docify::embed!("src/tests.rs", set_key_basics)]
#![doc = docify::embed!("src/tests.rs", sudo_as_emits_events_correctly)]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use alloc::boxed::Box;
use pezsp_runtime::{traits::StaticLookup, DispatchResult};
use pezframe_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 pezpallet::*;
type AccountIdLookupOf<T> = <<T as pezframe_system::Config>::Lookup as StaticLookup>::Source;
#[pezframe_support::pezpallet]
pub mod pezpallet {
use super::{DispatchResult, *};
use pezframe_support::pezpallet_prelude::*;
use pezframe_system::{pezpallet_prelude::*, RawOrigin};
pub mod config_preludes {
use super::*;
use pezframe_support::derive_impl;
pub struct TestDefaultConfig;
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
impl pezframe_system::DefaultConfig for TestDefaultConfig {}
#[pezframe_support::register_default_impl(TestDefaultConfig)]
impl DefaultConfig for TestDefaultConfig {
type WeightInfo = ();
#[inject_runtime_type]
type RuntimeEvent = ();
#[inject_runtime_type]
type RuntimeCall = ();
}
}
#[pezpallet::config(with_default)]
pub trait Config: pezframe_system::Config {
#[pezpallet::no_default_bounds]
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self>>
+ IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
#[pezpallet::no_default_bounds]
type RuntimeCall: Parameter
+ UnfilteredDispatchable<RuntimeOrigin = Self::RuntimeOrigin>
+ GetDispatchInfo;
type WeightInfo: WeightInfo;
}
#[pezpallet::pezpallet]
pub struct Pezpallet<T>(_);
#[pezpallet::call]
impl<T: Config> Pezpallet<T> {
#[pezpallet::call_index(0)]
#[pezpallet::weight({
let dispatch_info = call.get_dispatch_info();
(
T::WeightInfo::sudo().saturating_add(dispatch_info.call_weight),
dispatch_info.class
)
})]
pub fn sudo(
origin: OriginFor<T>,
call: Box<<T as Config>::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())
}
#[pezpallet::call_index(1)]
#[pezpallet::weight((*weight, call.get_dispatch_info().class))]
pub fn sudo_unchecked_weight(
origin: OriginFor<T>,
call: Box<<T as Config>::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())
}
#[pezpallet::call_index(2)]
#[pezpallet::weight(T::WeightInfo::set_key())]
pub fn set_key(
origin: OriginFor<T>,
new: AccountIdLookupOf<T>,
) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
let new = T::Lookup::lookup(new)?;
Self::deposit_event(Event::KeyChanged { old: Key::<T>::get(), new: new.clone() });
Key::<T>::put(new);
Ok(Pays::No.into())
}
#[pezpallet::call_index(3)]
#[pezpallet::weight({
let dispatch_info = call.get_dispatch_info();
(
T::WeightInfo::sudo_as().saturating_add(dispatch_info.call_weight),
dispatch_info.class,
)
})]
pub fn sudo_as(
origin: OriginFor<T>,
who: AccountIdLookupOf<T>,
call: Box<<T as Config>::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())
}
#[pezpallet::call_index(4)]
#[pezpallet::weight(T::WeightInfo::remove_key())]
pub fn remove_key(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
Self::ensure_sudo(origin)?;
Self::deposit_event(Event::KeyRemoved {});
Key::<T>::kill();
Ok(Pays::No.into())
}
}
#[pezpallet::event]
#[pezpallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
Sudid {
sudo_result: DispatchResult,
},
KeyChanged {
old: Option<T::AccountId>,
new: T::AccountId,
},
KeyRemoved,
SudoAsDone {
sudo_result: DispatchResult,
},
}
#[pezpallet::error]
pub enum Error<T> {
RequireSudo,
}
#[pezpallet::storage]
pub type Key<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;
#[pezpallet::genesis_config]
#[derive(pezframe_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
pub key: Option<T::AccountId>,
}
#[pezpallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Key::<T>::set(self.key.clone());
}
}
impl<T: Config> Pezpallet<T> {
pub(crate) fn ensure_sudo(origin: OriginFor<T>) -> DispatchResult {
let sender = ensure_signed_or_root(origin)?;
if let Some(sender) = sender {
if Key::<T>::get().map_or(false, |k| k == sender) {
Ok(())
} else {
Err(Error::<T>::RequireSudo.into())
}
} else {
Ok(())
}
}
}
}