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}