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))
+ }
+}