1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]1819pub use pallet::*;20use frame_support::pallet_prelude::*;21use frame_system::pallet_prelude::*;2223#[frame_support::pallet]24pub mod pallet {25 use frame_support::{pallet_prelude::*, dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, traits::{UnfilteredDispatchable, IsSubType, OriginTrait}};26 use frame_system::pallet_prelude::*;27 use sp_std::vec::Vec;28 use pallet_unique_scheduler_v2::{TaskName, Pallet as SchedulerPallet};2930 #[pallet::config]31 pub trait Config: frame_system::Config + pallet_unique_scheduler_v2::Config {32 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;3334 35 type RuntimeCall: Parameter36 + Dispatchable<RuntimeOrigin = <Self as frame_system::Config>::RuntimeOrigin, PostInfo = PostDispatchInfo>37 + GetDispatchInfo38 + From<frame_system::Call<Self>>39 + UnfilteredDispatchable<RuntimeOrigin = <Self as frame_system::Config>::RuntimeOrigin>40 + IsSubType<Call<Self>>41 + IsType<<Self as frame_system::Config>::RuntimeCall>;42 }4344 #[pallet::event]45 #[pallet::generate_deposit(pub(super) fn deposit_event)]46 pub enum Event<T: Config> {47 ValueIsSet,48 ShouldRollback,49 BatchCompleted,50 }5152 #[pallet::pallet]53 #[pallet::generate_store(pub(super) trait Store)]54 pub struct Pallet<T>(_);5556 #[pallet::storage]57 #[pallet::getter(fn is_enabled)]58 pub type Enabled<T> = StorageValue<_, bool, ValueQuery>;5960 #[pallet::storage]61 #[pallet::getter(fn test_value)]62 pub type TestValue<T> = StorageValue<_, u32, ValueQuery>;6364 #[pallet::error]65 pub enum Error<T> {66 TestPalletDisabled,67 TriggerRollback,68 }6970 #[pallet::call]71 impl<T: Config> Pallet<T> {72 #[pallet::weight(10_000)]73 pub fn enable(origin: OriginFor<T>) -> DispatchResult {74 ensure_root(origin)?;75 <Enabled<T>>::set(true);7677 Ok(())78 }7980 #[pallet::weight(10_000)]81 pub fn set_test_value(origin: OriginFor<T>, value: u32) -> DispatchResult {82 Self::ensure_origin_and_enabled(origin)?;8384 <TestValue<T>>::put(value);8586 Self::deposit_event(Event::ValueIsSet);8788 Ok(())89 }9091 #[pallet::weight(10_000)]92 pub fn set_test_value_and_rollback(origin: OriginFor<T>, value: u32) -> DispatchResult {93 Self::set_test_value(origin, value)?;9495 Self::deposit_event(Event::ShouldRollback);9697 Err(<Error<T>>::TriggerRollback.into())98 }99100 #[pallet::weight(10_000)]101 pub fn inc_test_value(origin: OriginFor<T>) -> DispatchResult {102 Self::set_test_value(origin, <TestValue<T>>::get() + 1)103 }104105 #[pallet::weight(10_000)]106 pub fn self_canceling_inc(107 origin: OriginFor<T>,108 id: TaskName,109 max_test_value: u32,110 ) -> DispatchResult {111 Self::ensure_origin_and_enabled(origin.clone())?;112 Self::inc_test_value(origin.clone())?;113114 if <TestValue<T>>::get() == max_test_value {115 SchedulerPallet::<T>::cancel_named(origin, id)?;116 }117118 Ok(())119 }120121 #[pallet::weight(100_000_000)]122 pub fn just_take_fee(origin: OriginFor<T>) -> DispatchResult {123 Self::ensure_origin_and_enabled(origin)?;124 Ok(())125 }126127 #[pallet::weight(10_000)]128 pub fn batch_all(129 origin: OriginFor<T>,130 calls: Vec<<T as Config>::RuntimeCall>,131 ) -> DispatchResultWithPostInfo {132 Self::ensure_origin_and_enabled(origin.clone())?;133134 let is_root = ensure_root(origin.clone()).is_ok();135136 for call in calls {137 if is_root {138 call.dispatch_bypass_filter(origin.clone())?;139 } else {140 let mut filtered_origin = origin.clone();141 142 filtered_origin.add_filter(143 move |c: &<T as frame_system::Config>::RuntimeCall| {144 let c = <T as Config>::RuntimeCall::from_ref(c);145 !matches!(c.is_sub_type(), Some(Call::batch_all { .. }))146 },147 );148 call.dispatch(filtered_origin)?;149 }150 }151152 Self::deposit_event(Event::BatchCompleted);153 Ok(None::<Weight>.into())154 }155 }156}157158impl<T: Config> Pallet<T> {159 fn ensure_origin_and_enabled(origin: OriginFor<T>) -> DispatchResult {160 ensure_signed(origin)?;161 <Enabled<T>>::get()162 .then(|| ())163 .ok_or(<Error<T>>::TestPalletDisabled.into())164 }165}