use scale_info::TypeInfo;
use sp_core::Get;
use super::{super::misc::BalanceStatus, Currency};
use crate::{
dispatch::DispatchResult,
traits::{ExistenceRequirement, SignedImbalance, WithdrawReasons},
};
use sp_runtime::DispatchError;
pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
fn can_reserve(who: &AccountId, value: Self::Balance) -> bool;
fn slash_reserved(
who: &AccountId,
value: Self::Balance,
) -> (Self::NegativeImbalance, Self::Balance);
fn reserved_balance(who: &AccountId) -> Self::Balance;
fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult;
fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance;
fn repatriate_reserved(
slashed: &AccountId,
beneficiary: &AccountId,
value: Self::Balance,
status: BalanceStatus,
) -> Result<Self::Balance, DispatchError>;
}
#[cfg(feature = "std")]
impl<AccountId> ReservableCurrency<AccountId> for () {
fn can_reserve(_: &AccountId, _: Self::Balance) -> bool {
true
}
fn slash_reserved(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) {
((), 0)
}
fn reserved_balance(_: &AccountId) -> Self::Balance {
0
}
fn reserve(_: &AccountId, _: Self::Balance) -> DispatchResult {
Ok(())
}
fn unreserve(_: &AccountId, _: Self::Balance) -> Self::Balance {
0
}
fn repatriate_reserved(
_: &AccountId,
_: &AccountId,
_: Self::Balance,
_: BalanceStatus,
) -> Result<Self::Balance, DispatchError> {
Ok(0)
}
}
pub trait NamedReservableCurrency<AccountId>: ReservableCurrency<AccountId> {
type ReserveIdentifier: codec::Encode + TypeInfo + 'static;
fn slash_reserved_named(
id: &Self::ReserveIdentifier,
who: &AccountId,
value: Self::Balance,
) -> (Self::NegativeImbalance, Self::Balance);
fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &AccountId) -> Self::Balance;
fn reserve_named(
id: &Self::ReserveIdentifier,
who: &AccountId,
value: Self::Balance,
) -> DispatchResult;
fn unreserve_named(
id: &Self::ReserveIdentifier,
who: &AccountId,
value: Self::Balance,
) -> Self::Balance;
fn repatriate_reserved_named(
id: &Self::ReserveIdentifier,
slashed: &AccountId,
beneficiary: &AccountId,
value: Self::Balance,
status: BalanceStatus,
) -> Result<Self::Balance, DispatchError>;
fn ensure_reserved_named(
id: &Self::ReserveIdentifier,
who: &AccountId,
value: Self::Balance,
) -> DispatchResult {
let current = Self::reserved_balance_named(id, who);
if current > value {
Self::unreserve_named(id, who, current - value);
Ok(())
} else if value > current {
Self::reserve_named(id, who, value - current)
} else {
Ok(())
}
}
fn unreserve_all_named(id: &Self::ReserveIdentifier, who: &AccountId) -> Self::Balance {
let value = Self::reserved_balance_named(id, who);
Self::unreserve_named(id, who, value);
value
}
fn slash_all_reserved_named(
id: &Self::ReserveIdentifier,
who: &AccountId,
) -> Self::NegativeImbalance {
let value = Self::reserved_balance_named(id, who);
Self::slash_reserved_named(id, who, value).0
}
fn repatriate_all_reserved_named(
id: &Self::ReserveIdentifier,
slashed: &AccountId,
beneficiary: &AccountId,
status: BalanceStatus,
) -> DispatchResult {
let value = Self::reserved_balance_named(id, slashed);
Self::repatriate_reserved_named(id, slashed, beneficiary, value, status).map(|_| ())
}
}
pub struct WithName<NamedReservable, Id, AccountId>(
core::marker::PhantomData<(NamedReservable, Id, AccountId)>,
);
impl<
NamedReservable: NamedReservableCurrency<AccountId>,
Id: Get<NamedReservable::ReserveIdentifier>,
AccountId,
> Currency<AccountId> for WithName<NamedReservable, Id, AccountId>
{
type Balance = <NamedReservable as Currency<AccountId>>::Balance;
type PositiveImbalance = <NamedReservable as Currency<AccountId>>::PositiveImbalance;
type NegativeImbalance = <NamedReservable as Currency<AccountId>>::NegativeImbalance;
fn total_balance(who: &AccountId) -> Self::Balance {
NamedReservable::total_balance(who)
}
fn can_slash(who: &AccountId, value: Self::Balance) -> bool {
NamedReservable::can_slash(who, value)
}
fn total_issuance() -> Self::Balance {
NamedReservable::total_issuance()
}
fn minimum_balance() -> Self::Balance {
NamedReservable::minimum_balance()
}
fn burn(amount: Self::Balance) -> Self::PositiveImbalance {
NamedReservable::burn(amount)
}
fn issue(amount: Self::Balance) -> Self::NegativeImbalance {
NamedReservable::issue(amount)
}
fn pair(amount: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) {
NamedReservable::pair(amount)
}
fn free_balance(who: &AccountId) -> Self::Balance {
NamedReservable::free_balance(who)
}
fn ensure_can_withdraw(
who: &AccountId,
amount: Self::Balance,
reasons: WithdrawReasons,
new_balance: Self::Balance,
) -> DispatchResult {
NamedReservable::ensure_can_withdraw(who, amount, reasons, new_balance)
}
fn transfer(
source: &AccountId,
dest: &AccountId,
value: Self::Balance,
existence_requirement: ExistenceRequirement,
) -> DispatchResult {
NamedReservable::transfer(source, dest, value, existence_requirement)
}
fn slash(who: &AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) {
NamedReservable::slash(who, value)
}
fn deposit_into_existing(
who: &AccountId,
value: Self::Balance,
) -> Result<Self::PositiveImbalance, DispatchError> {
NamedReservable::deposit_into_existing(who, value)
}
fn resolve_into_existing(
who: &AccountId,
value: Self::NegativeImbalance,
) -> Result<(), Self::NegativeImbalance> {
NamedReservable::resolve_into_existing(who, value)
}
fn deposit_creating(who: &AccountId, value: Self::Balance) -> Self::PositiveImbalance {
NamedReservable::deposit_creating(who, value)
}
fn resolve_creating(who: &AccountId, value: Self::NegativeImbalance) {
NamedReservable::resolve_creating(who, value)
}
fn withdraw(
who: &AccountId,
value: Self::Balance,
reasons: WithdrawReasons,
liveness: ExistenceRequirement,
) -> Result<Self::NegativeImbalance, DispatchError> {
NamedReservable::withdraw(who, value, reasons, liveness)
}
fn settle(
who: &AccountId,
value: Self::PositiveImbalance,
reasons: WithdrawReasons,
liveness: ExistenceRequirement,
) -> Result<(), Self::PositiveImbalance> {
NamedReservable::settle(who, value, reasons, liveness)
}
fn make_free_balance_be(
who: &AccountId,
balance: Self::Balance,
) -> SignedImbalance<Self::Balance, Self::PositiveImbalance> {
NamedReservable::make_free_balance_be(who, balance)
}
}
impl<
NamedReservable: NamedReservableCurrency<AccountId>,
Id: Get<NamedReservable::ReserveIdentifier>,
AccountId,
> ReservableCurrency<AccountId> for WithName<NamedReservable, Id, AccountId>
{
fn can_reserve(who: &AccountId, value: Self::Balance) -> bool {
NamedReservable::can_reserve(who, value)
}
fn slash_reserved(
who: &AccountId,
value: Self::Balance,
) -> (Self::NegativeImbalance, Self::Balance) {
NamedReservable::slash_reserved_named(&Id::get(), who, value)
}
fn reserved_balance(who: &AccountId) -> Self::Balance {
NamedReservable::reserved_balance_named(&Id::get(), who)
}
fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult {
NamedReservable::reserve_named(&Id::get(), who, value)
}
fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance {
NamedReservable::unreserve_named(&Id::get(), who, value)
}
fn repatriate_reserved(
slashed: &AccountId,
beneficiary: &AccountId,
value: Self::Balance,
status: BalanceStatus,
) -> Result<Self::Balance, DispatchError> {
NamedReservable::repatriate_reserved_named(&Id::get(), slashed, beneficiary, value, status)
}
}