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