use super::{
misc::{Balance, DepositConsequence, WithdrawConsequence},
*,
};
use crate::{
dispatch::{DispatchError, DispatchResult},
traits::misc::Get,
};
use sp_runtime::traits::Saturating;
mod balanced;
mod imbalance;
pub use balanced::{Balanced, Unbalanced};
pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance};
pub trait Inspect<AccountId> {
type Balance: Balance;
fn total_issuance() -> Self::Balance;
fn active_issuance() -> Self::Balance {
Self::total_issuance()
}
fn minimum_balance() -> Self::Balance;
fn balance(who: &AccountId) -> Self::Balance;
fn reducible_balance(who: &AccountId, keep_alive: bool) -> Self::Balance;
fn can_deposit(who: &AccountId, amount: Self::Balance, mint: bool) -> DepositConsequence;
fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence<Self::Balance>;
}
pub trait Mutate<AccountId>: Inspect<AccountId> {
fn mint_into(who: &AccountId, amount: Self::Balance) -> DispatchResult;
fn burn_from(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError>;
fn slash(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
Self::burn_from(who, Self::reducible_balance(who, false).min(amount))
}
fn teleport(
source: &AccountId,
dest: &AccountId,
amount: Self::Balance,
) -> Result<Self::Balance, DispatchError> {
let extra = Self::can_withdraw(&source, amount).into_result()?;
Self::can_deposit(dest, amount.saturating_add(extra), false).into_result()?;
let actual = Self::burn_from(source, amount)?;
debug_assert!(
actual == amount.saturating_add(extra),
"can_withdraw must agree with withdraw; qed"
);
match Self::mint_into(dest, actual) {
Ok(_) => Ok(actual),
Err(err) => {
debug_assert!(false, "can_deposit returned true previously; qed");
let revert = Self::mint_into(source, actual);
debug_assert!(revert.is_ok(), "withdrew funds previously; qed");
Err(err)
},
}
}
}
pub trait Transfer<AccountId>: Inspect<AccountId> {
fn transfer(
source: &AccountId,
dest: &AccountId,
amount: Self::Balance,
keep_alive: bool,
) -> Result<Self::Balance, DispatchError>;
fn deactivate(_: Self::Balance) {}
fn reactivate(_: Self::Balance) {}
}
pub trait InspectHold<AccountId>: Inspect<AccountId> {
fn balance_on_hold(who: &AccountId) -> Self::Balance;
fn can_hold(who: &AccountId, amount: Self::Balance) -> bool;
}
pub trait MutateHold<AccountId>: InspectHold<AccountId> + Transfer<AccountId> {
fn hold(who: &AccountId, amount: Self::Balance) -> DispatchResult;
fn release(
who: &AccountId,
amount: Self::Balance,
best_effort: bool,
) -> Result<Self::Balance, DispatchError>;
fn transfer_held(
source: &AccountId,
dest: &AccountId,
amount: Self::Balance,
best_effort: bool,
on_held: bool,
) -> Result<Self::Balance, DispatchError>;
}
pub trait BalancedHold<AccountId>: Balanced<AccountId> + MutateHold<AccountId> {
fn slash_held(
who: &AccountId,
amount: Self::Balance,
) -> (CreditOf<AccountId, Self>, Self::Balance);
}
impl<AccountId, T: Balanced<AccountId> + MutateHold<AccountId>> BalancedHold<AccountId> for T {
fn slash_held(
who: &AccountId,
amount: Self::Balance,
) -> (CreditOf<AccountId, Self>, Self::Balance) {
let actual = match Self::release(who, amount, true) {
Ok(x) => x,
Err(_) => return (Imbalance::default(), amount),
};
<Self as fungible::Balanced<AccountId>>::slash(who, actual)
}
}
pub struct ItemOf<
F: fungibles::Inspect<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
>(sp_std::marker::PhantomData<(F, A, AccountId)>);
impl<
F: fungibles::Inspect<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
> Inspect<AccountId> for ItemOf<F, A, AccountId>
{
type Balance = <F as fungibles::Inspect<AccountId>>::Balance;
fn total_issuance() -> Self::Balance {
<F as fungibles::Inspect<AccountId>>::total_issuance(A::get())
}
fn active_issuance() -> Self::Balance {
<F as fungibles::Inspect<AccountId>>::active_issuance(A::get())
}
fn minimum_balance() -> Self::Balance {
<F as fungibles::Inspect<AccountId>>::minimum_balance(A::get())
}
fn balance(who: &AccountId) -> Self::Balance {
<F as fungibles::Inspect<AccountId>>::balance(A::get(), who)
}
fn reducible_balance(who: &AccountId, keep_alive: bool) -> Self::Balance {
<F as fungibles::Inspect<AccountId>>::reducible_balance(A::get(), who, keep_alive)
}
fn can_deposit(who: &AccountId, amount: Self::Balance, mint: bool) -> DepositConsequence {
<F as fungibles::Inspect<AccountId>>::can_deposit(A::get(), who, amount, mint)
}
fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence<Self::Balance> {
<F as fungibles::Inspect<AccountId>>::can_withdraw(A::get(), who, amount)
}
}
impl<
F: fungibles::Mutate<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
> Mutate<AccountId> for ItemOf<F, A, AccountId>
{
fn mint_into(who: &AccountId, amount: Self::Balance) -> DispatchResult {
<F as fungibles::Mutate<AccountId>>::mint_into(A::get(), who, amount)
}
fn burn_from(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
<F as fungibles::Mutate<AccountId>>::burn_from(A::get(), who, amount)
}
}
impl<
F: fungibles::Transfer<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
> Transfer<AccountId> for ItemOf<F, A, AccountId>
{
fn transfer(
source: &AccountId,
dest: &AccountId,
amount: Self::Balance,
keep_alive: bool,
) -> Result<Self::Balance, DispatchError> {
<F as fungibles::Transfer<AccountId>>::transfer(A::get(), source, dest, amount, keep_alive)
}
fn deactivate(amount: Self::Balance) {
<F as fungibles::Transfer<AccountId>>::deactivate(A::get(), amount)
}
fn reactivate(amount: Self::Balance) {
<F as fungibles::Transfer<AccountId>>::reactivate(A::get(), amount)
}
}
impl<
F: fungibles::InspectHold<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
> InspectHold<AccountId> for ItemOf<F, A, AccountId>
{
fn balance_on_hold(who: &AccountId) -> Self::Balance {
<F as fungibles::InspectHold<AccountId>>::balance_on_hold(A::get(), who)
}
fn can_hold(who: &AccountId, amount: Self::Balance) -> bool {
<F as fungibles::InspectHold<AccountId>>::can_hold(A::get(), who, amount)
}
}
impl<
F: fungibles::MutateHold<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
> MutateHold<AccountId> for ItemOf<F, A, AccountId>
{
fn hold(who: &AccountId, amount: Self::Balance) -> DispatchResult {
<F as fungibles::MutateHold<AccountId>>::hold(A::get(), who, amount)
}
fn release(
who: &AccountId,
amount: Self::Balance,
best_effort: bool,
) -> Result<Self::Balance, DispatchError> {
<F as fungibles::MutateHold<AccountId>>::release(A::get(), who, amount, best_effort)
}
fn transfer_held(
source: &AccountId,
dest: &AccountId,
amount: Self::Balance,
best_effort: bool,
on_hold: bool,
) -> Result<Self::Balance, DispatchError> {
<F as fungibles::MutateHold<AccountId>>::transfer_held(
A::get(),
source,
dest,
amount,
best_effort,
on_hold,
)
}
}
impl<
F: fungibles::Unbalanced<AccountId>,
A: Get<<F as fungibles::Inspect<AccountId>>::AssetId>,
AccountId,
> Unbalanced<AccountId> for ItemOf<F, A, AccountId>
{
fn set_balance(who: &AccountId, amount: Self::Balance) -> DispatchResult {
<F as fungibles::Unbalanced<AccountId>>::set_balance(A::get(), who, amount)
}
fn set_total_issuance(amount: Self::Balance) -> () {
<F as fungibles::Unbalanced<AccountId>>::set_total_issuance(A::get(), amount)
}
fn decrease_balance(
who: &AccountId,
amount: Self::Balance,
) -> Result<Self::Balance, DispatchError> {
<F as fungibles::Unbalanced<AccountId>>::decrease_balance(A::get(), who, amount)
}
fn decrease_balance_at_most(who: &AccountId, amount: Self::Balance) -> Self::Balance {
<F as fungibles::Unbalanced<AccountId>>::decrease_balance_at_most(A::get(), who, amount)
}
fn increase_balance(
who: &AccountId,
amount: Self::Balance,
) -> Result<Self::Balance, DispatchError> {
<F as fungibles::Unbalanced<AccountId>>::increase_balance(A::get(), who, amount)
}
fn increase_balance_at_most(who: &AccountId, amount: Self::Balance) -> Self::Balance {
<F as fungibles::Unbalanced<AccountId>>::increase_balance_at_most(A::get(), who, amount)
}
}