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}