frame_support/traits/tokens/imbalance/on_unbalanced.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//! Trait for handling imbalances.
19
20use core::marker::PhantomData;
21use frame_support::traits::{fungible, fungibles, misc::TryDrop};
22use sp_core::TypedGet;
23
24/// Handler for when some currency "account" decreased in balance for
25/// some reason.
26///
27/// The only reason at present for an increase would be for validator rewards, but
28/// there may be other reasons in the future or for other chains.
29///
30/// Reasons for decreases include:
31///
32/// - Someone got slashed.
33/// - Someone paid for a transaction to be included.
34pub trait OnUnbalanced<Imbalance: TryDrop> {
35 /// Handler for some imbalances. The different imbalances might have different origins or
36 /// meanings, dependent on the context. Will default to simply calling on_unbalanced for all
37 /// of them. Infallible.
38 fn on_unbalanceds(mut amounts: impl Iterator<Item = Imbalance>)
39 where
40 Imbalance: crate::traits::tokens::imbalance::TryMerge,
41 {
42 let mut sum: Option<Imbalance> = None;
43 while let Some(next) = amounts.next() {
44 sum = match sum {
45 Some(sum) => match sum.try_merge(next) {
46 Ok(sum) => Some(sum),
47 Err((sum, next)) => {
48 Self::on_unbalanced(next);
49 Some(sum)
50 },
51 },
52 None => Some(next),
53 }
54 }
55 if let Some(sum) = sum {
56 Self::on_unbalanced(sum)
57 }
58 }
59
60 /// Handler for some imbalance. Infallible.
61 fn on_unbalanced(amount: Imbalance) {
62 amount.try_drop().unwrap_or_else(Self::on_nonzero_unbalanced)
63 }
64
65 /// Actually handle a non-zero imbalance. You probably want to implement this rather than
66 /// `on_unbalanced`.
67 fn on_nonzero_unbalanced(amount: Imbalance) {
68 drop(amount);
69 }
70}
71
72impl<Imbalance: TryDrop> OnUnbalanced<Imbalance> for () {}
73
74/// Resolves received asset credit to account `A`, implementing [`OnUnbalanced`].
75///
76/// Credits that cannot be resolved to account `A` are dropped. This may occur if the account for
77/// address `A` does not exist and the existential deposit requirement is not met.
78pub struct ResolveTo<A, F>(PhantomData<(A, F)>);
79impl<A: TypedGet, F: fungible::Balanced<A::Type>> OnUnbalanced<fungible::Credit<A::Type, F>>
80 for ResolveTo<A, F>
81{
82 fn on_nonzero_unbalanced(credit: fungible::Credit<A::Type, F>) {
83 let _ = F::resolve(&A::get(), credit).map_err(|c| drop(c));
84 }
85}
86
87/// Resolves received asset credit to account `A`, implementing [`OnUnbalanced`].
88///
89/// Credits that cannot be resolved to account `A` are dropped. This may occur if the account for
90/// address `A` does not exist and the existential deposit requirement is not met.
91pub struct ResolveAssetTo<A, F>(PhantomData<(A, F)>);
92impl<A: TypedGet, F: fungibles::Balanced<A::Type>> OnUnbalanced<fungibles::Credit<A::Type, F>>
93 for ResolveAssetTo<A, F>
94{
95 fn on_nonzero_unbalanced(credit: fungibles::Credit<A::Type, F>) {
96 let _ = F::resolve(&A::get(), credit).map_err(|c| drop(c));
97 }
98}