diff --git a/substrate/frame/support/src/traits/tokens/fungible/as_fungibles.rs b/substrate/frame/support/src/traits/tokens/fungible/as_fungibles.rs new file mode 100644 index 0000000000000..66234a7176088 --- /dev/null +++ b/substrate/frame/support/src/traits/tokens/fungible/as_fungibles.rs @@ -0,0 +1,379 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Adapter to use `fungible:*` implementations as `fungibles::*`. + +use super::{imbalance::from_fungibles, *}; +use crate::traits::tokens::{ + fungible, fungibles, fungibles::imbalance::from_fungible, DepositConsequence, Fortitude, + Precision, Preservation, Provenance, Restriction, WithdrawConsequence, +}; +use sp_runtime::{DispatchError, DispatchResult}; + +/// Redirects `fungibles` function to the `fungible` equivalent without the AssetId argument. +macro_rules! redirect { + ( $( + fn $fn_name:ident ( + $( + $arg_name:ident : $arg_ty:ty + ),* $(,)? + ) $(-> $fn_out:ty)?; + )+) => { + $( + fn $fn_name((): Self::AssetId, $($arg_name:$arg_ty),*) $(-> $fn_out)? { + F::$fn_name($($arg_name),*) + } + )+ + }; +} + +pub struct ConvertHandleImbalanceDrop(PhantomData); + +impl> fungibles::HandleImbalanceDrop<(), B> + for ConvertHandleImbalanceDrop +{ + fn handle((): (), amount: B) { + H::handle(amount) + } +} + +/// A wrapper to use a `fungible` as a `fungibles` with a single asset represented by `()`. +pub struct AsFungibles(PhantomData<(F, AccountId)>); + +impl> fungibles::Inspect + for AsFungibles +{ + type AssetId = (); + type Balance = F::Balance; + + redirect!( + fn total_issuance() -> Self::Balance; + fn minimum_balance() -> Self::Balance; + fn total_balance(who: &AccountId) -> Self::Balance; + fn balance(who: &AccountId) -> Self::Balance; + fn reducible_balance( + who: &AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance; + fn can_deposit( + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence; + fn can_withdraw( + who: &AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence; + fn active_issuance() -> Self::Balance; + ); + + fn asset_exists((): Self::AssetId) -> bool { + true + } +} + +impl> fungibles::Unbalanced + for AsFungibles +{ + redirect!( + fn write_balance( + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError>; + fn set_total_issuance(amount: Self::Balance); + fn handle_raw_dust(amount: Self::Balance); + fn decrease_balance( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result; + fn increase_balance( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result; + fn deactivate(amount: Self::Balance); + fn reactivate(amount: Self::Balance); + ); + + fn handle_dust(fungibles::Dust((), dust): fungibles::Dust) { + F::handle_dust(fungible::Dust(dust)) + } +} + +impl> fungibles::Mutate + for AsFungibles +{ + redirect!( + fn mint_into( + who: &AccountId, + amount: Self::Balance, + ) -> Result; + fn burn_from( + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result; + fn shelve(who: &AccountId, amount: Self::Balance) -> Result; + fn restore(who: &AccountId, amount: Self::Balance) -> Result; + fn transfer( + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result; + fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance; + fn done_mint_into(who: &AccountId, amount: Self::Balance); + fn done_burn_from(who: &AccountId, amount: Self::Balance); + fn done_shelve(who: &AccountId, amount: Self::Balance); + fn done_restore(who: &AccountId, amount: Self::Balance); + fn done_transfer(source: &AccountId, dest: &AccountId, amount: Self::Balance); + ); +} + +impl> fungibles::Balanced + for AsFungibles +{ + type OnDropDebt = ConvertHandleImbalanceDrop; + type OnDropCredit = ConvertHandleImbalanceDrop; + + fn rescind((): Self::AssetId, amount: Self::Balance) -> fungibles::Debt { + let dept = F::rescind(amount); + from_fungible(dept, ()) + } + + fn issue((): Self::AssetId, amount: Self::Balance) -> fungibles::Credit { + let credit = F::issue(amount); + from_fungible(credit, ()) + } + + fn pair( + (): Self::AssetId, + amount: Self::Balance, + ) -> (fungibles::Debt, fungibles::Credit) { + let (dept, credit) = F::pair(amount); + (from_fungible(dept, ()), from_fungible(credit, ())) + } + + fn deposit( + (): Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + ) -> Result, DispatchError> { + F::deposit(who, value, precision).map(|dept| from_fungible(dept, ())) + } + + fn withdraw( + (): Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result, DispatchError> { + F::withdraw(who, value, precision, preservation, force) + .map(|credit| from_fungible(credit, ())) + } + + fn resolve( + who: &AccountId, + credit: fungibles::Credit, + ) -> Result<(), fungibles::Credit> { + F::resolve(who, from_fungibles(credit)).map_err(|credit| from_fungible(credit, ())) + } + + fn settle( + who: &AccountId, + debt: fungibles::Debt, + preservation: Preservation, + ) -> Result, fungibles::Debt> { + F::settle(who, from_fungibles(debt), preservation) + .map(|credit| from_fungible(credit, ())) + .map_err(|dept| from_fungible(dept, ())) + } + + redirect!( + fn done_rescind(amount: Self::Balance); + fn done_issue(amount: Self::Balance); + fn done_deposit(who: &AccountId, amount: Self::Balance); + fn done_withdraw(who: &AccountId, amount: Self::Balance); + ); +} + +impl> fungibles::hold::Inspect + for AsFungibles +{ + type Reason = F::Reason; + + redirect!( + fn total_balance_on_hold(who: &AccountId) -> Self::Balance; + fn balance_on_hold(reason: &Self::Reason, who: &AccountId) -> Self::Balance; + fn reducible_total_balance_on_hold(who: &AccountId, force: Fortitude) -> Self::Balance; + fn hold_available(reason: &Self::Reason, who: &AccountId) -> bool; + fn ensure_can_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + fn can_hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> bool; + ); +} + +impl> fungibles::hold::Unbalanced + for AsFungibles +{ + redirect!( + fn set_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult; + fn decrease_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result; + fn increase_balance_on_hold( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result; + ); +} + +impl> fungibles::hold::Mutate + for AsFungibles +{ + redirect!( + fn hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance) -> DispatchResult; + fn release( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result; + fn burn_held( + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result; + fn burn_all_held( + reason: &Self::Reason, + who: &AccountId, + precision: Precision, + force: Fortitude, + ) -> Result; + fn transfer_on_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + mode: Restriction, + force: Fortitude, + ) -> Result; + fn transfer_and_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + expendability: Preservation, + force: Fortitude, + ) -> Result; + fn done_hold(reason: &Self::Reason, who: &AccountId, amount: Self::Balance); + fn done_release(reason: &Self::Reason, who: &AccountId, amount: Self::Balance); + fn done_burn_held(reason: &Self::Reason, who: &AccountId, amount: Self::Balance); + fn done_transfer_on_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + ); + fn done_transfer_and_hold( + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + transferred: Self::Balance, + ); + ); +} + +impl> fungibles::hold::Balanced + for AsFungibles +{ + fn slash( + (): Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> (fungibles::Credit, Self::Balance) { + let (credit, balance) = F::slash(reason, who, amount); + (from_fungible(credit, ()), balance) + } + + redirect!( + fn done_slash(reason: &Self::Reason, who: &AccountId, amount: Self::Balance); + ); +} + +impl> fungibles::freeze::Inspect + for AsFungibles +{ + type Id = F::Id; + + redirect!( + fn balance_frozen(id: &Self::Id, who: &AccountId) -> Self::Balance; + fn can_freeze(id: &Self::Id, who: &AccountId) -> bool; + fn balance_freezable(who: &AccountId) -> Self::Balance; + ); +} + +impl> fungibles::freeze::Mutate + for AsFungibles +{ + redirect!( + fn set_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult; + fn extend_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult; + fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult; + fn set_frozen( + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + fortitude: Fortitude, + ) -> DispatchResult; + fn ensure_frozen( + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + fortitude: Fortitude, + ) -> DispatchResult; + fn decrease_frozen(id: &Self::Id, who: &AccountId, amount: Self::Balance) + -> DispatchResult; + fn increase_frozen(id: &Self::Id, who: &AccountId, amount: Self::Balance) + -> DispatchResult; + ); +} diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 0e25102197007..388a6d4635750 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -158,9 +158,9 @@ impl, OppositeOnDrop: HandleImbalance /// Converts a `fungibles` `imbalance` instance to an instance of a `fungible` imbalance type. /// /// This function facilitates imbalance conversions within the implementations of -/// [`frame_support::traits::fungibles::UnionOf`], [`frame_support::traits::fungible::UnionOf`], and -/// [`frame_support::traits::fungible::ItemOf`] adapters. It is intended only for internal use -/// within the current crate. +/// [`frame_support::traits::fungibles::UnionOf`], [`frame_support::traits::fungible::UnionOf`], +/// [`frame_support::traits::fungible::AsFungibles`] and [`frame_support::traits::fungible::ItemOf`] +/// adapters. It is intended only for internal use within the current crate. pub(crate) fn from_fungibles< A: AssetId, B: Balance, diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index ba4a2e5e21a2c..fc688e7631520 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -38,6 +38,7 @@ //! funds must be removed from an account before it is known precisely what should be done with //! them. +mod as_fungibles; pub mod conformance_tests; pub mod freeze; pub mod hold; @@ -55,6 +56,7 @@ use super::{ Fortitude::{Force, Polite}, Precision::BestEffort, }; +pub use as_fungibles::AsFungibles; pub use freeze::{Inspect as InspectFreeze, Mutate as MutateFreeze}; pub use hold::{ Balanced as BalancedHold, Inspect as InspectHold, Mutate as MutateHold, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 54c1e900b6e36..32cd7d64774d8 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -178,9 +178,9 @@ impl< /// a specified `asset`. /// /// This function facilitates imbalance conversions within the implementations of -/// [`frame_support::traits::fungibles::UnionOf`], [`frame_support::traits::fungible::UnionOf`], and -/// [`frame_support::traits::fungible::ItemOf`] adapters. It is intended only for internal use -/// within the current crate. +/// [`frame_support::traits::fungibles::UnionOf`], [`frame_support::traits::fungible::UnionOf`], +/// [`frame_support::traits::fungible::AsFungibles`] and [`frame_support::traits::fungible::ItemOf`] +/// adapters. It is intended only for internal use within the current crate. pub(crate) fn from_fungible< A: AssetId, B: Balance,