Skip to content

Commit

Permalink
Repot frame_support::traits; introduce some new currency stuff (parit…
Browse files Browse the repository at this point in the history
…ytech#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 <[email protected]>
  • Loading branch information
2 people authored and hirschenberger committed Apr 14, 2021
1 parent 7066523 commit f1b13f4
Show file tree
Hide file tree
Showing 34 changed files with 4,741 additions and 2,365 deletions.
105 changes: 86 additions & 19 deletions frame/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,25 @@ use sp_runtime::{
};
use codec::{Encode, Decode, HasCompact};
use frame_support::{ensure, dispatch::{DispatchError, DispatchResult}};
use frame_support::traits::{Currency, ReservableCurrency, BalanceStatus::Reserved, Fungibles};
use frame_support::traits::{Currency, ReservableCurrency, BalanceStatus::Reserved};
use frame_support::traits::tokens::{WithdrawConsequence, DepositConsequence, fungibles};
use frame_system::Config as SystemConfig;

pub use weights::WeightInfo;
pub use pallet::*;

impl<T: Config> Fungibles<<T as SystemConfig>::AccountId> for Pallet<T> {
impl<T: Config> fungibles::Inspect<<T as SystemConfig>::AccountId> for Pallet<T> {
type AssetId = T::AssetId;
type Balance = T::Balance;

fn total_issuance(asset: Self::AssetId) -> Self::Balance {
Asset::<T>::get(asset).map(|x| x.supply).unwrap_or_else(Zero::zero)
}

fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
Asset::<T>::get(asset).map(|x| x.min_balance).unwrap_or_else(Zero::zero)
}

fn balance(
asset: Self::AssetId,
who: &<T as SystemConfig>::AccountId,
Expand All @@ -159,24 +169,45 @@ impl<T: Config> Fungibles<<T as SystemConfig>::AccountId> for Pallet<T> {
asset: Self::AssetId,
who: &<T as SystemConfig>::AccountId,
amount: Self::Balance,
) -> bool {
) -> DepositConsequence {
Pallet::<T>::can_deposit(asset, who, amount)
}

fn can_withdraw(
asset: Self::AssetId,
who: &<T as SystemConfig>::AccountId,
amount: Self::Balance,
) -> WithdrawConsequence<Self::Balance> {
Pallet::<T>::can_withdraw(asset, who, amount)
}
}

impl<T: Config> fungibles::Mutate<<T as SystemConfig>::AccountId> for Pallet<T> {
fn deposit(
asset: Self::AssetId,
who: <T as SystemConfig>::AccountId,
who: &<T as SystemConfig>::AccountId,
amount: Self::Balance,
) -> DispatchResult {
Pallet::<T>::increase_balance(asset, who, amount, None)
Pallet::<T>::increase_balance(asset, who.clone(), amount, None)
}

fn withdraw(
asset: Self::AssetId,
who: <T as SystemConfig>::AccountId,
who: &<T as SystemConfig>::AccountId,
amount: Self::Balance,
) -> DispatchResult {
Pallet::<T>::reduce_balance(asset, who, amount, None)
) -> Result<Self::Balance, DispatchError> {
Pallet::<T>::reduce_balance(asset, who.clone(), amount, None)
}
}

impl<T: Config> fungibles::Transfer<T::AccountId> for Pallet<T> {
fn transfer(
asset: Self::AssetId,
source: &T::AccountId,
dest: &T::AccountId,
amount: T::Balance,
) -> Result<T::Balance, DispatchError> {
<Self as fungibles::Mutate::<T::AccountId>>::transfer(asset, source, dest, amount)
}
}

Expand Down Expand Up @@ -671,7 +702,7 @@ pub mod pallet {
let origin = ensure_signed(origin)?;
let who = T::Lookup::lookup(who)?;

Self::reduce_balance(id, who, amount, Some(origin))
Self::reduce_balance(id, who, amount, Some(origin)).map(|_| ())
}

/// Move some assets from the sender account to another.
Expand Down Expand Up @@ -1380,21 +1411,57 @@ impl<T: Config> Pallet<T> {
d.accounts = d.accounts.saturating_sub(1);
}

fn can_deposit(id: T::AssetId, who: &T::AccountId, amount: T::Balance) -> bool {
fn can_deposit(id: T::AssetId, who: &T::AccountId, amount: T::Balance) -> DepositConsequence {
let details = match Asset::<T>::get(id) {
Some(details) => details,
None => return false,
None => return DepositConsequence::UnknownAsset,
};
if details.supply.checked_add(&amount).is_none() { return false }
if details.supply.checked_add(&amount).is_none() {
return DepositConsequence::Overflow
}
let account = Account::<T>::get(id, who);
if account.balance.checked_add(&amount).is_none() { return false }
if account.balance.checked_add(&amount).is_none() {
return DepositConsequence::Overflow
}
if account.balance.is_zero() {
if amount < details.min_balance { return false }
if !details.is_sufficient && frame_system::Pallet::<T>::providers(who) == 0 { return false }
if details.is_sufficient && details.sufficients.checked_add(1).is_none() { return false }
if amount < details.min_balance {
return DepositConsequence::BelowMinimum
}
if !details.is_sufficient && frame_system::Pallet::<T>::providers(who) == 0 {
return DepositConsequence::CannotCreate
}
if details.is_sufficient && details.sufficients.checked_add(1).is_none() {
return DepositConsequence::Overflow
}
}

true
DepositConsequence::Success
}

fn can_withdraw(
id: T::AssetId,
who: &T::AccountId,
amount: T::Balance,
) -> WithdrawConsequence<T::Balance> {
let details = match Asset::<T>::get(id) {
Some(details) => details,
None => return WithdrawConsequence::UnknownAsset,
};
if details.supply.checked_sub(&amount).is_none() {
return WithdrawConsequence::Underflow
}
let account = Account::<T>::get(id, who);
if let Some(rest) = account.balance.checked_sub(&amount) {
if rest < details.min_balance {
WithdrawConsequence::ReducedToZero(rest)
} else {
// NOTE: this assumes (correctly) that the token won't be a provider. If that ever
// changes, this will need to change.
WithdrawConsequence::Success
}
} else {
WithdrawConsequence::NoFunds
}
}

fn increase_balance(
Expand Down Expand Up @@ -1430,7 +1497,7 @@ impl<T: Config> Pallet<T> {
target: T::AccountId,
amount: T::Balance,
maybe_check_admin: Option<T::AccountId>,
) -> DispatchResult {
) -> Result<T::Balance, DispatchError> {
Asset::<T>::try_mutate(id, |maybe_details| {
let d = maybe_details.as_mut().ok_or(Error::<T>::Unknown)?;
if let Some(check_admin) = maybe_check_admin {
Expand Down Expand Up @@ -1458,7 +1525,7 @@ impl<T: Config> Pallet<T> {
d.supply = d.supply.saturating_sub(burned);

Self::deposit_event(Event::Burned(id, target, burned));
Ok(())
Ok(burned)
})
}

Expand Down
Loading

0 comments on commit f1b13f4

Please sign in to comment.