#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
pub(crate) mod mock;
#[cfg(test)]
mod tests;
extern crate alloc;
use frame_support::{
defensive,
pallet_prelude::*,
traits::{
fungible::{Balanced, Credit, Inspect, Mutate},
Imbalance, OnUnbalanced,
},
PalletId,
};
pub use pallet::*;
const LOG_TARGET: &str = "runtime::dap";
pub type BalanceOf<T> =
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::{sp_runtime::traits::AccountIdConversion, traits::StorageVersion};
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type Currency: Inspect<Self::AccountId>
+ Mutate<Self::AccountId>
+ Balanced<Self::AccountId>;
#[pallet::constant]
type PalletId: Get<PalletId>;
}
impl<T: Config> Pallet<T> {
pub fn buffer_account() -> T::AccountId {
T::PalletId::get().into_account_truncating()
}
pub fn create_buffer_account() {
let buffer = Self::buffer_account();
let ed = T::Currency::minimum_balance();
if frame_system::Pallet::<T>::providers(&buffer) > 0 &&
T::Currency::balance(&buffer) >= ed
{
log::debug!(
target: LOG_TARGET,
"DAP buffer account already initialized: {buffer:?}"
);
return;
}
frame_system::Pallet::<T>::inc_providers(&buffer);
log::info!(
target: LOG_TARGET,
"Attempting to mint ED ({ed:?}) into DAP buffer: {buffer:?}"
);
match T::Currency::mint_into(&buffer, ed) {
Ok(_) => {
log::info!(
target: LOG_TARGET,
"🏦 Created DAP buffer account: {buffer:?}"
);
},
Err(e) => {
log::error!(
target: LOG_TARGET,
"🚨 Failed to mint ED into DAP buffer: {e:?}"
);
},
}
}
}
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
#[serde(skip)]
_phantom: core::marker::PhantomData<T>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Pallet::<T>::create_buffer_account();
}
}
}
pub mod migrations {
use super::*;
pub mod v1 {
use super::*;
mod inner {
use super::*;
use frame_support::traits::UncheckedOnRuntimeUpgrade;
pub struct InitBufferAccountInner<T>(core::marker::PhantomData<T>);
impl<T: Config> UncheckedOnRuntimeUpgrade for InitBufferAccountInner<T> {
fn on_runtime_upgrade() -> Weight {
Pallet::<T>::create_buffer_account();
T::DbWeight::get().reads_writes(3, 3)
}
}
}
pub type InitBufferAccount<T> = frame_support::migrations::VersionedMigration<
0,
1,
inner::InitBufferAccountInner<T>,
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;
}
}
pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
impl<T: Config> OnUnbalanced<CreditOf<T>> for Pallet<T> {
fn on_nonzero_unbalanced(amount: CreditOf<T>) {
let buffer = Self::buffer_account();
let numeric_amount = amount.peek();
let _ = T::Currency::resolve(&buffer, amount)
.inspect_err(|_| {
defensive!("🚨 Failed to deposit slash to DAP buffer - funds burned, it should never happen!");
})
.inspect(|_| {
log::debug!(
target: LOG_TARGET,
"💸 Deposited slash of {numeric_amount:?} to DAP buffer"
);
});
}
}