use cfg_traits::PreConditions;
use frame_support::{
defensive,
traits::{
fungible::{Dust, Inspect, InspectHold, Mutate, MutateHold, Unbalanced},
tokens::{
DepositConsequence, Fortitude, Precision, Preservation, Provenance, Restriction,
WithdrawConsequence,
},
},
};
use super::*;
pub enum FungibleInspectEffects<AccountId, Balance> {
ReducibleBalance(AccountId, Preservation, Fortitude, Balance),
}
pub struct FungibleInspectPassthrough;
impl<AccountId, Balance> PreConditions<FungibleInspectEffects<AccountId, Balance>>
for FungibleInspectPassthrough
{
type Result = Balance;
fn check(t: FungibleInspectEffects<AccountId, Balance>) -> Self::Result {
match t {
FungibleInspectEffects::ReducibleBalance(_, _, _, amount) => amount,
}
}
}
impl<T: Config> Inspect<T::AccountId> for Pallet<T> {
type Balance = T::Balance;
fn total_issuance() -> Self::Balance {
<T::NativeFungible as Inspect<T::AccountId>>::total_issuance()
}
fn minimum_balance() -> Self::Balance {
<T::NativeFungible as Inspect<T::AccountId>>::minimum_balance()
}
fn total_balance(who: &T::AccountId) -> Self::Balance {
<T::NativeFungible as Inspect<T::AccountId>>::total_balance(who)
}
fn balance(who: &T::AccountId) -> Self::Balance {
<T::NativeFungible as Inspect<T::AccountId>>::balance(who)
}
fn reducible_balance(
who: &T::AccountId,
preservation: Preservation,
force: Fortitude,
) -> Self::Balance {
T::PreFungibleInspect::check(FungibleInspectEffects::ReducibleBalance(
who.clone(),
preservation,
force,
<T::NativeFungible as Inspect<T::AccountId>>::reducible_balance(
who,
preservation,
force,
),
))
}
fn can_deposit(
who: &T::AccountId,
amount: Self::Balance,
provenance: Provenance,
) -> DepositConsequence {
<T::NativeFungible as Inspect<T::AccountId>>::can_deposit(who, amount, provenance)
}
fn can_withdraw(
who: &T::AccountId,
amount: Self::Balance,
) -> WithdrawConsequence<Self::Balance> {
<T::NativeFungible as Inspect<T::AccountId>>::can_withdraw(who, amount)
}
}
pub enum FungibleInspectHoldEffects<AccountId, Balance> {
CanHold(AccountId, Balance, bool),
HoldAvailable(AccountId, bool),
}
impl<T: Config> InspectHold<T::AccountId> for Pallet<T> {
type Reason = T::RuntimeHoldReason;
fn total_balance_on_hold(who: &T::AccountId) -> Self::Balance {
<T::NativeFungible as InspectHold<T::AccountId>>::total_balance_on_hold(who)
}
fn reducible_total_balance_on_hold(who: &T::AccountId, force: Fortitude) -> Self::Balance {
<T::NativeFungible as InspectHold<T::AccountId>>::reducible_total_balance_on_hold(
who, force,
)
}
fn balance_on_hold(reason: &Self::Reason, who: &T::AccountId) -> Self::Balance {
<T::NativeFungible as InspectHold<T::AccountId>>::balance_on_hold(reason, who)
}
fn hold_available(reason: &Self::Reason, who: &T::AccountId) -> bool {
T::PreFungibleInspectHold::check(FungibleInspectHoldEffects::HoldAvailable(
who.clone(),
<T::NativeFungible as InspectHold<T::AccountId>>::hold_available(reason, who),
)) && <T::NativeFungible as InspectHold<T::AccountId>>::hold_available(reason, who)
}
fn can_hold(reason: &Self::Reason, who: &T::AccountId, amount: Self::Balance) -> bool {
T::PreFungibleInspectHold::check(FungibleInspectHoldEffects::CanHold(
who.clone(),
amount,
<T::NativeFungible as InspectHold<T::AccountId>>::can_hold(reason, who, amount),
)) && <T::NativeFungible as InspectHold<T::AccountId>>::can_hold(reason, who, amount)
}
}
pub enum FungibleMutateEffects<AccountId, Balance> {
MintInto(AccountId, Balance),
BurnFrom(AccountId, Balance),
}
impl<T: Config> Mutate<T::AccountId> for Pallet<T> {
fn mint_into(
who: &T::AccountId,
amount: Self::Balance,
) -> Result<Self::Balance, DispatchError> {
ensure!(
T::PreFungibleMutate::check(FungibleMutateEffects::MintInto(who.clone(), amount)),
Error::<T>::PreConditionsNotMet
);
<T::NativeFungible as Mutate<T::AccountId>>::mint_into(who, amount)
}
fn burn_from(
who: &T::AccountId,
amount: Self::Balance,
precision: Precision,
force: Fortitude,
) -> Result<Self::Balance, DispatchError> {
ensure!(
T::PreFungibleMutate::check(FungibleMutateEffects::BurnFrom(who.clone(), amount)),
Error::<T>::PreConditionsNotMet
);
<T::NativeFungible as Mutate<T::AccountId>>::burn_from(who, amount, precision, force)
}
fn transfer(
source: &T::AccountId,
dest: &T::AccountId,
amount: Self::Balance,
preservation: Preservation,
) -> Result<Self::Balance, DispatchError> {
ensure!(
T::PreFungibleTransfer::check(FungibleTransferEffects::Transfer(
source.clone(),
dest.clone(),
amount,
preservation,
)),
Error::<T>::PreConditionsNotMet
);
<T::NativeFungible as Mutate<T::AccountId>>::transfer(source, dest, amount, preservation)
}
}
pub enum FungibleMutateHoldEffects<AccountId, Balance> {
Hold(AccountId, Balance),
Release(AccountId, Balance, bool),
TransferHeld(AccountId, AccountId, Balance, bool, bool),
}
impl<T: Config> Unbalanced<T::AccountId> for Pallet<T> {
fn handle_dust(_dust: Dust<T::AccountId, Self>) {
defensive!("DustRemoval disabled");
}
fn write_balance(
who: &T::AccountId,
amount: Self::Balance,
) -> Result<Option<Self::Balance>, DispatchError> {
<T::NativeFungible as Unbalanced<T::AccountId>>::write_balance(who, amount)
}
fn set_total_issuance(amount: Self::Balance) {
<T::NativeFungible as Unbalanced<T::AccountId>>::set_total_issuance(amount)
}
}
impl<T: Config> fungible::hold::Unbalanced<T::AccountId> for Pallet<T> {
fn set_balance_on_hold(
reason: &Self::Reason,
who: &T::AccountId,
amount: Self::Balance,
) -> sp_runtime::DispatchResult {
<T::NativeFungible as fungible::hold::Unbalanced<T::AccountId>>::set_balance_on_hold(
reason, who, amount,
)
}
}
impl<T: Config> MutateHold<T::AccountId> for Pallet<T> {
fn hold(reason: &Self::Reason, who: &T::AccountId, amount: Self::Balance) -> DispatchResult {
ensure!(
T::PreFungibleMutateHold::check(FungibleMutateHoldEffects::Hold(who.clone(), amount)),
Error::<T>::PreConditionsNotMet
);
<T::NativeFungible as MutateHold<T::AccountId>>::hold(reason, who, amount)?;
Ok(())
}
fn release(
reason: &Self::Reason,
who: &T::AccountId,
amount: Self::Balance,
precision: Precision,
) -> Result<Self::Balance, DispatchError> {
ensure!(
T::PreFungibleMutateHold::check(FungibleMutateHoldEffects::Release(
who.clone(),
amount,
precision == Precision::BestEffort,
)),
Error::<T>::PreConditionsNotMet
);
<T::NativeFungible as MutateHold<T::AccountId>>::release(reason, who, amount, precision)
}
fn transfer_on_hold(
reason: &Self::Reason,
source: &T::AccountId,
dest: &T::AccountId,
amount: Self::Balance,
precision: Precision,
mode: Restriction,
force: Fortitude,
) -> Result<Self::Balance, DispatchError> {
ensure!(
T::PreFungibleMutateHold::check(FungibleMutateHoldEffects::TransferHeld(
source.clone(),
dest.clone(),
amount,
precision == Precision::BestEffort,
mode == Restriction::OnHold,
)),
Error::<T>::PreConditionsNotMet
);
<T::NativeFungible as MutateHold<T::AccountId>>::transfer_on_hold(
reason, source, dest, amount, precision, mode, force,
)
}
}
pub enum FungibleTransferEffects<AccountId, Balance> {
Transfer(AccountId, AccountId, Balance, Preservation),
}