referrerpolicy=no-referrer-when-downgrade

frame_support/traits/tokens/
imbalance.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! The imbalance trait type and its associates, which handles keeps everything adding up properly
19//! with unbalanced operations.
20
21use crate::traits::misc::{SameOrOther, TryDrop};
22use core::ops::Div;
23use sp_runtime::traits::Saturating;
24
25mod imbalance_accounting;
26mod on_unbalanced;
27mod signed_imbalance;
28mod split_two_ways;
29
30pub use imbalance_accounting::{
31	ImbalanceAccounting, UnsafeConstructorDestructor, UnsafeManualAccounting,
32};
33pub use on_unbalanced::{MaybeResolveAssetTo, OnUnbalanced, ResolveAssetTo, ResolveTo};
34pub use signed_imbalance::SignedImbalance;
35pub use split_two_ways::SplitTwoWays;
36
37/// A trait for a not-quite Linear Type that tracks an imbalance.
38///
39/// Functions that alter account balances return an object of this trait to
40/// express how much account balances have been altered in aggregate. If
41/// dropped, the currency system will take some default steps to deal with
42/// the imbalance (`balances` module simply reduces or increases its
43/// total issuance). Your module should generally handle it in some way,
44/// good practice is to do so in a configurable manner using an
45/// `OnUnbalanced` type for each situation in which your module needs to
46/// handle an imbalance.
47///
48/// Imbalances can either be Positive (funds were added somewhere without
49/// being subtracted elsewhere - e.g. a reward) or Negative (funds deducted
50/// somewhere without an equal and opposite addition - e.g. a slash or
51/// system fee payment).
52///
53/// Since they are unsigned, the actual type is always Positive or Negative.
54/// The trait makes no distinction except to define the `Opposite` type.
55///
56/// New instances of zero value can be created (`zero`) and destroyed
57/// (`drop_zero`).
58///
59/// Existing instances can be `split` and merged either consuming `self` with
60/// `merge` or mutating `self` with `subsume`. If the target is an `Option`,
61/// then `maybe_merge` and `maybe_subsume` might work better. Instances can
62/// also be `offset` with an `Opposite` that is less than or equal to in value.
63///
64/// You can always retrieve the raw balance value using `peek`.
65#[must_use]
66pub trait Imbalance<Balance>: Sized + TryDrop + Default + TryMerge {
67	/// The oppositely imbalanced type. They come in pairs.
68	type Opposite: Imbalance<Balance>;
69
70	/// The zero imbalance. Can be destroyed with `drop_zero`.
71	fn zero() -> Self;
72
73	/// Drop an instance cleanly. Only works if its `self.value()` is zero.
74	fn drop_zero(self) -> Result<(), Self>;
75
76	/// Consume `self` and return two independent instances; the first
77	/// is guaranteed to be at most `amount` and the second will be the remainder.
78	fn split(self, amount: Balance) -> (Self, Self);
79
80	/// Mutate `self` by extracting a new instance with at most `amount` value, reducing `self`
81	/// accordingly.
82	fn extract(&mut self, amount: Balance) -> Self;
83
84	/// Consume `self` and return two independent instances; the amounts returned will be in
85	/// approximately the same ratio as `first`:`second`.
86	///
87	/// NOTE: This requires up to `first + second` room for a multiply, and `first + second` should
88	/// fit into a `u32`. Overflow will safely saturate in both cases.
89	fn ration(self, first: u32, second: u32) -> (Self, Self)
90	where
91		Balance: From<u32> + Saturating + Div<Output = Balance>,
92	{
93		let total: u32 = first.saturating_add(second);
94		if total == 0 {
95			return (Self::zero(), Self::zero());
96		}
97		let amount1 = self.peek().saturating_mul(first.into()) / total.into();
98		self.split(amount1)
99	}
100
101	/// Consume self and add its two components, defined by the first component's balance,
102	/// element-wise to two pre-existing Imbalances.
103	///
104	/// A convenient replacement for `split` and `merge`.
105	fn split_merge(self, amount: Balance, others: (Self, Self)) -> (Self, Self) {
106		let (a, b) = self.split(amount);
107		(a.merge(others.0), b.merge(others.1))
108	}
109
110	/// Consume self and add its two components, defined by the ratio `first`:`second`,
111	/// element-wise to two pre-existing Imbalances.
112	///
113	/// A convenient replacement for `split` and `merge`.
114	fn ration_merge(self, first: u32, second: u32, others: (Self, Self)) -> (Self, Self)
115	where
116		Balance: From<u32> + Saturating + Div<Output = Balance>,
117	{
118		let (a, b) = self.ration(first, second);
119		(a.merge(others.0), b.merge(others.1))
120	}
121
122	/// Consume self and add its two components, defined by the first component's balance,
123	/// element-wise into two pre-existing Imbalance refs.
124	///
125	/// A convenient replacement for `split` and `subsume`.
126	fn split_merge_into(self, amount: Balance, others: &mut (Self, Self)) {
127		let (a, b) = self.split(amount);
128		others.0.subsume(a);
129		others.1.subsume(b);
130	}
131
132	/// Consume self and add its two components, defined by the ratio `first`:`second`,
133	/// element-wise to two pre-existing Imbalances.
134	///
135	/// A convenient replacement for `split` and `merge`.
136	fn ration_merge_into(self, first: u32, second: u32, others: &mut (Self, Self))
137	where
138		Balance: From<u32> + Saturating + Div<Output = Balance>,
139	{
140		let (a, b) = self.ration(first, second);
141		others.0.subsume(a);
142		others.1.subsume(b);
143	}
144
145	/// Consume `self` and an `other` to return a new instance that combines
146	/// both.
147	fn merge(self, other: Self) -> Self;
148
149	/// Consume self to mutate `other` so that it combines both. Just like `subsume`, only with
150	/// reversed arguments.
151	fn merge_into(self, other: &mut Self) {
152		other.subsume(self)
153	}
154
155	/// Consume `self` and maybe an `other` to return a new instance that combines
156	/// both.
157	fn maybe_merge(self, other: Option<Self>) -> Self {
158		if let Some(o) = other {
159			self.merge(o)
160		} else {
161			self
162		}
163	}
164
165	/// Consume an `other` to mutate `self` into a new instance that combines
166	/// both.
167	fn subsume(&mut self, other: Self);
168
169	/// Maybe consume an `other` to mutate `self` into a new instance that combines
170	/// both.
171	fn maybe_subsume(&mut self, other: Option<Self>) {
172		if let Some(o) = other {
173			self.subsume(o)
174		}
175	}
176
177	/// Consume self and along with an opposite counterpart to return
178	/// a combined result.
179	///
180	/// Returns `Ok` along with a new instance of `Self` if this instance has a
181	/// greater value than the `other`. Otherwise returns `Err` with an instance of
182	/// the `Opposite`. In both cases the value represents the combination of `self`
183	/// and `other`.
184	fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite>;
185
186	/// The raw value of self.
187	fn peek(&self) -> Balance;
188}
189
190/// Try to merge two imbalances.
191pub trait TryMerge: Sized {
192	/// Consume `self` and an `other` to return a new instance that combines both. Errors with
193	/// Err(self, other) if the imbalances cannot be merged (e.g. imbalances of different assets).
194	fn try_merge(self, other: Self) -> Result<Self, (Self, Self)>;
195}
196
197#[cfg(feature = "std")]
198impl<Balance: Default> Imbalance<Balance> for () {
199	type Opposite = ();
200	fn zero() -> Self {
201		()
202	}
203	fn drop_zero(self) -> Result<(), Self> {
204		Ok(())
205	}
206	fn split(self, _: Balance) -> (Self, Self) {
207		((), ())
208	}
209	fn extract(&mut self, _: Balance) -> Self {
210		()
211	}
212	fn ration(self, _: u32, _: u32) -> (Self, Self)
213	where
214		Balance: From<u32> + Saturating + Div<Output = Balance>,
215	{
216		((), ())
217	}
218	fn split_merge(self, _: Balance, _: (Self, Self)) -> (Self, Self) {
219		((), ())
220	}
221	fn ration_merge(self, _: u32, _: u32, _: (Self, Self)) -> (Self, Self)
222	where
223		Balance: From<u32> + Saturating + Div<Output = Balance>,
224	{
225		((), ())
226	}
227	fn split_merge_into(self, _: Balance, _: &mut (Self, Self)) {}
228	fn ration_merge_into(self, _: u32, _: u32, _: &mut (Self, Self))
229	where
230		Balance: From<u32> + Saturating + Div<Output = Balance>,
231	{
232	}
233	fn merge(self, _: Self) -> Self {
234		()
235	}
236	fn merge_into(self, _: &mut Self) {}
237	fn maybe_merge(self, _: Option<Self>) -> Self {
238		()
239	}
240	fn subsume(&mut self, _: Self) {}
241	fn maybe_subsume(&mut self, _: Option<Self>) {
242		()
243	}
244	fn offset(self, _: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
245		SameOrOther::None
246	}
247	fn peek(&self) -> Balance {
248		Default::default()
249	}
250}
251
252#[cfg(feature = "std")]
253impl TryMerge for () {
254	fn try_merge(self, _: Self) -> Result<Self, (Self, Self)> {
255		Ok(())
256	}
257}