frame_support/traits/tokens/fungible/
imbalance.rs1use super::{super::Imbalance as ImbalanceT, Balanced, *};
24use crate::{
25 pallet_prelude::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen, TypeInfo},
26 traits::{
27 fungibles,
28 misc::{SameOrOther, TryDrop},
29 tokens::{imbalance::TryMerge, AssetId, Balance},
30 },
31};
32use core::marker::PhantomData;
33use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound};
34use sp_runtime::traits::Zero;
35
36pub trait HandleImbalanceDrop<Balance> {
39 fn handle(amount: Balance);
41}
42
43impl<Balance> HandleImbalanceDrop<Balance> for () {
44 fn handle(_: Balance) {}
45}
46
47#[must_use]
53#[derive(
54 EqNoBound,
55 PartialEqNoBound,
56 RuntimeDebugNoBound,
57 Encode,
58 Decode,
59 DecodeWithMemTracking,
60 MaxEncodedLen,
61 TypeInfo,
62)]
63#[scale_info(skip_type_params(OnDrop, OppositeOnDrop))]
64pub struct Imbalance<
65 B: Balance,
66 OnDrop: HandleImbalanceDrop<B>,
67 OppositeOnDrop: HandleImbalanceDrop<B>,
68> {
69 amount: B,
70 _phantom: PhantomData<(OnDrop, OppositeOnDrop)>,
71}
72
73impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> Drop
74 for Imbalance<B, OnDrop, OppositeOnDrop>
75{
76 fn drop(&mut self) {
77 if !self.amount.is_zero() {
78 OnDrop::handle(self.amount)
79 }
80 }
81}
82
83impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> TryDrop
84 for Imbalance<B, OnDrop, OppositeOnDrop>
85{
86 fn try_drop(self) -> Result<(), Self> {
88 self.drop_zero()
89 }
90}
91
92impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> Default
93 for Imbalance<B, OnDrop, OppositeOnDrop>
94{
95 fn default() -> Self {
96 Self::zero()
97 }
98}
99
100impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>>
101 Imbalance<B, OnDrop, OppositeOnDrop>
102{
103 pub(crate) fn new(amount: B) -> Self {
104 Self { amount, _phantom: PhantomData }
105 }
106
107 pub(crate) fn forget(imbalance: Self) {
109 core::mem::forget(imbalance);
110 }
111}
112
113impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>>
114 ImbalanceT<B> for Imbalance<B, OnDrop, OppositeOnDrop>
115{
116 type Opposite = Imbalance<B, OppositeOnDrop, OnDrop>;
117
118 fn zero() -> Self {
119 Self { amount: Zero::zero(), _phantom: PhantomData }
120 }
121
122 fn drop_zero(self) -> Result<(), Self> {
123 if self.amount.is_zero() {
124 core::mem::forget(self);
125 Ok(())
126 } else {
127 Err(self)
128 }
129 }
130
131 fn split(self, amount: B) -> (Self, Self) {
132 let first = self.amount.min(amount);
133 let second = self.amount - first;
134 core::mem::forget(self);
135 (Imbalance::new(first), Imbalance::new(second))
136 }
137
138 fn extract(&mut self, amount: B) -> Self {
139 let new = self.amount.min(amount);
140 self.amount = self.amount - new;
141 Imbalance::new(new)
142 }
143
144 fn merge(mut self, other: Self) -> Self {
145 self.amount = self.amount.saturating_add(other.amount);
146 core::mem::forget(other);
147 self
148 }
149 fn subsume(&mut self, other: Self) {
150 self.amount = self.amount.saturating_add(other.amount);
151 core::mem::forget(other);
152 }
153 fn offset(
154 self,
155 other: Imbalance<B, OppositeOnDrop, OnDrop>,
156 ) -> SameOrOther<Self, Imbalance<B, OppositeOnDrop, OnDrop>> {
157 let (a, b) = (self.amount, other.amount);
158 core::mem::forget((self, other));
159
160 if a == b {
161 SameOrOther::None
162 } else if a > b {
163 SameOrOther::Same(Imbalance::new(a - b))
164 } else {
165 SameOrOther::Other(Imbalance::<B, OppositeOnDrop, OnDrop>::new(b - a))
166 }
167 }
168 fn peek(&self) -> B {
169 self.amount
170 }
171}
172
173impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> TryMerge
174 for Imbalance<B, OnDrop, OppositeOnDrop>
175{
176 fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
177 Ok(self.merge(other))
178 }
179}
180
181pub(crate) fn from_fungibles<
188 A: AssetId,
189 B: Balance,
190 OnDropIn: fungibles::HandleImbalanceDrop<A, B>,
191 OppositeIn: fungibles::HandleImbalanceDrop<A, B>,
192 OnDropOut: HandleImbalanceDrop<B>,
193 OppositeOut: HandleImbalanceDrop<B>,
194>(
195 imbalance: fungibles::Imbalance<A, B, OnDropIn, OppositeIn>,
196) -> Imbalance<B, OnDropOut, OppositeOut> {
197 let new = Imbalance::new(imbalance.peek());
198 fungibles::Imbalance::forget(imbalance);
199 new
200}
201
202pub type Debt<AccountId, B> = Imbalance<
204 <B as Inspect<AccountId>>::Balance,
205 <B as Balanced<AccountId>>::OnDropDebt,
207 <B as Balanced<AccountId>>::OnDropCredit,
208>;
209
210pub type Credit<AccountId, B> = Imbalance<
213 <B as Inspect<AccountId>>::Balance,
214 <B as Balanced<AccountId>>::OnDropCredit,
216 <B as Balanced<AccountId>>::OnDropDebt,
217>;