Skip to main content

fc_pallet_black_hole/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3//! # Black Hole Pallet
4//!
5//! This pallet owns an account, which receives transfers from other accounts. Then, periodically
6//! it burns the balance the pallet account owns.
7
8extern crate alloc;
9
10use alloc::boxed::Box;
11use frame::prelude::*;
12use fungible::{Inspect, Mutate};
13
14#[cfg(feature = "runtime-benchmarks")]
15pub mod benchmarking;
16
17#[cfg(test)]
18mod mock;
19#[cfg(test)]
20mod tests;
21
22pub mod weights;
23pub use weights::*;
24
25pub use pallet::*;
26
27#[frame::pallet]
28pub mod pallet {
29    use super::*;
30    use frame::traits::{Block, Header};
31
32    pub(crate) type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
33    pub(crate) type BalanceOf<T> = <<T as Config>::Balances as Inspect<AccountIdOf<T>>>::Balance;
34    pub(crate) type SystemBlockNumberFor<T> =
35        <<<T as frame_system::Config>::Block as Block>::Header as Header>::Number;
36    pub(crate) type BlockNumberFor<T> =
37        <<T as Config>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
38
39    #[pallet::config]
40    pub trait Config: frame_system::Config {
41        // Primitives: Some overarching types that come from the system (or the system depends on).
42
43        /// The overarching runtime event type
44        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
45        /// The Weight info
46        type WeightInfo: WeightInfo;
47
48        // Origins: Types that manage authorization rules to allow or deny some caller origins to
49        // execute a method.
50
51        /// The origin allowed dispatching a call on behalf of the pallet account (a.k.a. the event
52        /// horizon).
53        type EventHorizonDispatchOrigin: EnsureOrigin<Self::RuntimeOrigin>;
54
55        // Dependencies: The external components this pallet depends on.
56
57        /// The native balance system.
58        type Balances: Mutate<Self::AccountId>;
59        /// The provider of the block number.
60        type BlockNumberProvider: BlockNumberProvider;
61
62        // Parameters: A set of constant parameters to configure limits.
63
64        /// An id for this pallet.
65        #[pallet::constant]
66        type PalletId: Get<PalletId>;
67        /// The burn period. After at least the given number of blocks since the last burn elapsed,
68        /// the burn mechanism will take place.
69        #[pallet::constant]
70        type BurnPeriod: Get<BlockNumberFor<Self>>;
71    }
72
73    /// The last time a burn happened (0 if never).
74    #[pallet::storage]
75    pub type LastBurn<T> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
76    /// Counts the accumulated balance that's been burned so far.
77    #[pallet::storage]
78    pub type BlackHoleMass<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;
79
80    #[pallet::pallet]
81    pub struct Pallet<T>(_);
82
83    #[pallet::event]
84    #[pallet::generate_deposit(pub(super) fn deposit_event)]
85    pub enum Event<T: Config> {
86        BalanceBurned,
87    }
88
89    #[pallet::hooks]
90    impl<T: Config> Hooks<SystemBlockNumberFor<T>> for Pallet<T> {
91        fn on_idle(_: SystemBlockNumberFor<T>, remaining_weight: Weight) -> Weight {
92            if remaining_weight.all_lt(T::WeightInfo::burn()) {
93                return Zero::zero();
94            }
95            Self::burn()
96        }
97    }
98
99    #[pallet::call]
100    impl<T: Config> Pallet<T> {
101        #[pallet::call_index(0)]
102        #[pallet::weight({
103            let di = call.get_dispatch_info();
104			let weight = T::WeightInfo::dispatch_as_event_horizon()
105				.saturating_add(T::DbWeight::get().reads_writes(1, 1))
106				.saturating_add(di.call_weight);
107			(weight, di.class)
108        })]
109        pub fn dispatch_as_event_horizon(
110            origin: OriginFor<T>,
111            call: Box<T::RuntimeCall>,
112        ) -> DispatchResult {
113            T::EventHorizonDispatchOrigin::ensure_origin(origin)?;
114            Self::do_initialize();
115
116            call.dispatch(frame_system::RawOrigin::Signed(Self::event_horizon()).into())
117                .map(|_| ())
118                .map_err(|e| e.error)
119        }
120    }
121
122    impl<T: Config> Pallet<T> {
123        pub fn event_horizon() -> T::AccountId {
124            T::PalletId::get().into_account_truncating()
125        }
126
127        #[inline]
128        fn do_initialize() {
129            if !frame_system::Pallet::<T>::account_exists(&Self::event_horizon()) {
130                frame_system::Pallet::<T>::inc_providers(&Self::event_horizon());
131            }
132        }
133
134        pub(crate) fn burn() -> Weight {
135            if LastBurn::<T>::get().le(&T::BlockNumberProvider::current_block_number()
136                .saturating_sub(T::BurnPeriod::get()))
137            {
138                let burn_account = Self::event_horizon();
139                let burn_balance = T::Balances::total_balance(&burn_account);
140
141                // Just burn it.
142                let _ = T::Balances::burn_from(
143                    &burn_account,
144                    burn_balance,
145                    Preservation::Expendable,
146                    Precision::Exact,
147                    Fortitude::Force,
148                );
149
150                BlackHoleMass::<T>::set(BlackHoleMass::<T>::get().saturating_add(burn_balance));
151                LastBurn::<T>::set(T::BlockNumberProvider::current_block_number());
152                Self::deposit_event(Event::<T>::BalanceBurned);
153            }
154
155            T::WeightInfo::burn()
156        }
157    }
158}