Repot frame_support::traits; introduce some new currency stuff (#8435)

* Reservable, Transferrable Fungible(s), plus adapters.

* Repot into new dir

* Imbalances for Fungibles

* Repot and balanced fungible.

* Clean up names and bridge-over Imbalanced.

* Repot frame_support::trait. Finally.

* Make build.

* Docs

* Good errors

* Fix tests. Implement fungible::Inspect for Balances.

* Implement additional traits for Balances.

* Revert UI test "fixes"

* Fix UI error

* Fix UI test

* Fixes

* Update lock

* Grumbles

* Grumbles

* Fixes

Co-authored-by: Bastian Köcher <info@kchr.de>
This commit is contained in:
Gavin Wood
2021-03-27 14:37:13 +01:00
committed by GitHub
parent 5d2640240c
commit ff5765eac3
34 changed files with 4748 additions and 2372 deletions
+166 -8
View File
@@ -682,6 +682,78 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
}
}
fn deposit_consequence(
_who: &T::AccountId,
amount: T::Balance,
account: &AccountData<T::Balance>,
) -> DepositConsequence {
if amount.is_zero() { return DepositConsequence::Success }
if TotalIssuance::<T, I>::get().checked_add(&amount).is_none() {
return DepositConsequence::Overflow
}
let new_total_balance = match account.total().checked_add(&amount) {
Some(x) => x,
None => return DepositConsequence::Overflow,
};
if new_total_balance < T::ExistentialDeposit::get() {
return DepositConsequence::BelowMinimum
}
// NOTE: We assume that we are a provider, so don't need to do any checks in the
// case of account creation.
DepositConsequence::Success
}
fn withdraw_consequence(
who: &T::AccountId,
amount: T::Balance,
account: &AccountData<T::Balance>,
) -> WithdrawConsequence<T::Balance> {
if amount.is_zero() { return WithdrawConsequence::Success }
if TotalIssuance::<T, I>::get().checked_sub(&amount).is_none() {
return WithdrawConsequence::Underflow
}
let new_total_balance = match account.total().checked_sub(&amount) {
Some(x) => x,
None => return WithdrawConsequence::NoFunds,
};
// Provider restriction - total account balance cannot be reduced to zero if it cannot
// sustain the loss of a provider reference.
// NOTE: This assumes that the pallet is a provider (which is true). Is this ever changes,
// then this will need to adapt accordingly.
let ed = T::ExistentialDeposit::get();
let success = if new_total_balance < ed {
if frame_system::Pallet::<T>::can_dec_provider(who) {
WithdrawConsequence::ReducedToZero(new_total_balance)
} else {
return WithdrawConsequence::WouldDie
}
} else {
WithdrawConsequence::Success
};
// Enough free funds to have them be reduced.
let new_free_balance = match account.free.checked_sub(&amount) {
Some(b) => b,
None => return WithdrawConsequence::NoFunds,
};
// Eventual free funds must be no less than the frozen balance.
let min_balance = account.frozen(Reasons::All);
if new_free_balance < min_balance {
return WithdrawConsequence::Frozen
}
success
}
/// Mutate an account to some new value, or delete it entirely with `None`. Will enforce
/// `ExistentialDeposit` law, annulling the account as needed.
///
@@ -803,6 +875,75 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
}
}
use frame_support::traits::tokens::{fungible, DepositConsequence, WithdrawConsequence};
impl<T: Config<I>, I: 'static> fungible::Inspect<T::AccountId> for Pallet<T, I> {
type Balance = T::Balance;
fn total_issuance() -> Self::Balance {
TotalIssuance::<T, I>::get()
}
fn minimum_balance() -> Self::Balance {
T::ExistentialDeposit::get()
}
fn balance(who: &T::AccountId) -> Self::Balance {
Self::account(who).total()
}
fn can_deposit(who: &T::AccountId, amount: Self::Balance) -> DepositConsequence {
Self::deposit_consequence(who, amount, &Self::account(who))
}
fn can_withdraw(who: &T::AccountId, amount: Self::Balance) -> WithdrawConsequence<Self::Balance> {
Self::withdraw_consequence(who, amount, &Self::account(who))
}
}
impl<T: Config<I>, I: 'static> fungible::Mutate<T::AccountId> for Pallet<T, I> {
fn deposit(who: &T::AccountId, amount: Self::Balance) -> DispatchResult {
if amount.is_zero() { return Ok(()) }
Self::try_mutate_account(who, |account, _is_new| -> DispatchResult {
Self::deposit_consequence(who, amount, &account).into_result()?;
account.free += amount;
Ok(())
})?;
TotalIssuance::<T, I>::mutate(|t| *t += amount);
Ok(())
}
fn withdraw(who: &T::AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
if amount.is_zero() { return Ok(Self::Balance::zero()); }
let actual = Self::try_mutate_account(who, |account, _is_new| -> Result<T::Balance, DispatchError> {
let extra = Self::withdraw_consequence(who, amount, &account).into_result()?;
let actual = amount + extra;
account.free -= actual;
Ok(actual)
})?;
TotalIssuance::<T, I>::mutate(|t| *t -= actual);
Ok(actual)
}
}
impl<T: Config<I>, I: 'static> fungible::Transfer<T::AccountId> for Pallet<T, I> {
fn transfer(
source: &T::AccountId,
dest: &T::AccountId,
amount: T::Balance,
) -> Result<T::Balance, DispatchError> {
<Self as fungible::Mutate::<T::AccountId>>::transfer(source, dest, amount)
}
}
impl<T: Config<I>, I: 'static> fungible::Unbalanced<T::AccountId> for Pallet<T, I> {
fn set_balance(who: &T::AccountId, amount: Self::Balance) -> DispatchResult {
Self::mutate_account(who, |account| account.free = amount)?;
Ok(())
}
fn set_total_issuance(amount: Self::Balance) {
TotalIssuance::<T, I>::mutate(|t| *t = amount);
}
}
// wrapping these imbalances in a private module is necessary to ensure absolute privacy
// of the inner member.
mod imbalances {
@@ -811,6 +952,7 @@ mod imbalances {
TryDrop, RuntimeDebug,
};
use sp_std::mem;
use frame_support::traits::SameOrOther;
/// Opaque, move-only struct with private fields that serves as a token denoting that
/// funds have been created without any equal and opposite accounting.
@@ -844,6 +986,12 @@ mod imbalances {
}
}
impl<T: Config<I>, I: 'static> Default for PositiveImbalance<T, I> {
fn default() -> Self {
Self::zero()
}
}
impl<T: Config<I>, I: 'static> Imbalance<T::Balance> for PositiveImbalance<T, I> {
type Opposite = NegativeImbalance<T, I>;
@@ -874,14 +1022,16 @@ mod imbalances {
self.0 = self.0.saturating_add(other.0);
mem::forget(other);
}
fn offset(self, other: Self::Opposite) -> result::Result<Self, Self::Opposite> {
fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
let (a, b) = (self.0, other.0);
mem::forget((self, other));
if a >= b {
Ok(Self(a - b))
if a > b {
SameOrOther::Same(Self(a - b))
} else if b > a {
SameOrOther::Other(NegativeImbalance::new(b - a))
} else {
Err(NegativeImbalance::new(b - a))
SameOrOther::None
}
}
fn peek(&self) -> T::Balance {
@@ -895,6 +1045,12 @@ mod imbalances {
}
}
impl<T: Config<I>, I: 'static> Default for NegativeImbalance<T, I> {
fn default() -> Self {
Self::zero()
}
}
impl<T: Config<I>, I: 'static> Imbalance<T::Balance> for NegativeImbalance<T, I> {
type Opposite = PositiveImbalance<T, I>;
@@ -925,14 +1081,16 @@ mod imbalances {
self.0 = self.0.saturating_add(other.0);
mem::forget(other);
}
fn offset(self, other: Self::Opposite) -> result::Result<Self, Self::Opposite> {
fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
let (a, b) = (self.0, other.0);
mem::forget((self, other));
if a >= b {
Ok(Self(a - b))
if a > b {
SameOrOther::Same(Self(a - b))
} else if b > a {
SameOrOther::Other(PositiveImbalance::new(b - a))
} else {
Err(PositiveImbalance::new(b - a))
SameOrOther::None
}
}
fn peek(&self) -> T::Balance {