diff --git a/prdoc/pr_2274.prdoc b/prdoc/pr_2274.prdoc new file mode 100644 index 000000000000..8f03f140e471 --- /dev/null +++ b/prdoc/pr_2274.prdoc @@ -0,0 +1,10 @@ +title: "Add `ConsiderationFromLegacy` traits" + +doc: + - audience: Runtime Dev + description: | + Add a trait that allows to create a `Consideration` from an exact balance deposit. This allows + to migrate the legacy currency deposits to the `Consideration` API. + +crates: + - name: "frame-support" diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index ba4a2e5e21a2..d9f9913e564f 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -75,6 +75,45 @@ use crate::{ traits::{Consideration, Footprint}, }; +/// Extension for the `Consideration` trait to migrate legacy `Currency` deposits. +/// +/// Provides a `new_from_exact` method for those types using a `fungible` balance frozen, +/// This method is useful when a new ticket needs to be created with a precise balance, instead of +/// deriving it from a footprint. +pub trait FreezeConsiderationFromLegacy: Consideration +where + A: 'static, + F: 'static + MutateFreeze, +{ + /// Create a ticket for a `new` balance attributable to `who`. This ticket *must* ultimately + /// be consumed through `update` or `drop` once a footprint changes or is removed. + fn new_from_exact(_who: &A, _new: F::Balance) -> Result + where + Self: Sized, + { + Err(DispatchError::Other("Unsupported")) + } +} + +/// Extension for `Consideration` trait. +/// Provides a `new_from_exact` method for those types using a `fungible` balance placed on hold. +/// This method is useful when a new ticket needs to be created with a precise balance, instead of +/// deriving it from a footprint. +pub trait HoldConsiderationFromLegacy: Consideration +where + A: 'static, + F: 'static + MutateHold, +{ + /// Create a ticket for a `new` balance attributable to `who`. This ticket *must* ultimately + /// be consumed through `update` or `drop` once a footprint changes or is removed. + fn new_from_exact(_who: &A, _new: F::Balance) -> Result + where + Self: Sized, + { + Err(DispatchError::Other("Unsupported")) + } +} + /// Consideration method using a `fungible` balance frozen as the cost exacted for the footprint. /// /// The aggregate amount frozen under `R::get()` for any account which has multiple tickets, @@ -120,7 +159,21 @@ impl< } } -/// Consideration method using a `fungible` balance frozen as the cost exacted for the footprint. +impl< + A: 'static, + F: 'static + MutateFreeze, + R: 'static + Get, + D: 'static + Convert, + > FreezeConsiderationFromLegacy for FreezeConsideration +{ + fn new_from_exact(who: &A, new: F::Balance) -> Result { + F::increase_frozen(&R::get(), who, new)?; + Ok(Self(new, PhantomData)) + } +} + +/// Consideration method using a `fungible` balance placed on hold as the cost exacted for the +/// footprint. #[derive( CloneNoBound, EqNoBound, @@ -165,6 +218,19 @@ impl< } } +impl< + A: 'static, + F: 'static + MutateHold, + R: 'static + Get, + D: 'static + Convert, + > HoldConsiderationFromLegacy for HoldConsideration +{ + fn new_from_exact(who: &A, new: F::Balance) -> Result { + F::hold(&R::get(), who, new)?; + Ok(Self(new, PhantomData)) + } +} + /// Basic consideration method using a `fungible` balance frozen as the cost exacted for the /// footprint. /// @@ -204,6 +270,19 @@ impl< } } +impl< + A: 'static, + Fx: 'static + MutateFreeze, + Rx: 'static + Get, + D: 'static + Convert, + > FreezeConsiderationFromLegacy for LoneFreezeConsideration +{ + fn new_from_exact(who: &A, new: Fx::Balance) -> Result { + ensure!(Fx::balance_frozen(&Rx::get(), who).is_zero(), DispatchError::Unavailable); + Fx::set_frozen(&Rx::get(), who, new, Polite).map(|_| Self(PhantomData)) + } +} + /// Basic consideration method using a `fungible` balance placed on hold as the cost exacted for the /// footprint. /// @@ -245,3 +324,16 @@ impl< let _ = F::burn_all_held(&R::get(), who, BestEffort, Force); } } + +impl< + A: 'static, + F: 'static + MutateHold, + R: 'static + Get, + D: 'static + Convert, + > HoldConsiderationFromLegacy for LoneHoldConsideration +{ + fn new_from_exact(who: &A, new: F::Balance) -> Result { + ensure!(F::balance_on_hold(&R::get(), who).is_zero(), DispatchError::Unavailable); + F::set_on_hold(&R::get(), who, new).map(|_| Self(PhantomData)) + } +}