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::{
30 imbalance::{
31 ImbalanceAccounting, TryMerge, UnsafeConstructorDestructor, UnsafeManualAccounting,
32 },
33 AssetId, Balance,
34 },
35 },
36};
37use alloc::boxed::Box;
38use core::marker::PhantomData;
39use frame_support_procedural::{DebugNoBound, EqNoBound, PartialEqNoBound};
40use sp_arithmetic::traits::SaturatedConversion;
41use sp_runtime::traits::Zero;
42
43pub trait HandleImbalanceDrop<Balance> {
46 fn handle(amount: Balance);
48}
49
50impl<Balance> HandleImbalanceDrop<Balance> for () {
51 fn handle(_: Balance) {}
52}
53
54#[must_use]
60#[derive(
61 EqNoBound,
62 PartialEqNoBound,
63 DebugNoBound,
64 Encode,
65 Decode,
66 DecodeWithMemTracking,
67 MaxEncodedLen,
68 TypeInfo,
69)]
70#[scale_info(skip_type_params(OnDrop, OppositeOnDrop))]
71pub struct Imbalance<
72 B: Balance,
73 OnDrop: HandleImbalanceDrop<B>,
74 OppositeOnDrop: HandleImbalanceDrop<B>,
75> {
76 amount: B,
77 _phantom: PhantomData<(OnDrop, OppositeOnDrop)>,
78}
79
80impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> Drop
81 for Imbalance<B, OnDrop, OppositeOnDrop>
82{
83 fn drop(&mut self) {
84 if !self.amount.is_zero() {
85 OnDrop::handle(self.amount)
86 }
87 }
88}
89
90impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> TryDrop
91 for Imbalance<B, OnDrop, OppositeOnDrop>
92{
93 fn try_drop(self) -> Result<(), Self> {
95 self.drop_zero()
96 }
97}
98
99impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> Default
100 for Imbalance<B, OnDrop, OppositeOnDrop>
101{
102 fn default() -> Self {
103 Self::zero()
104 }
105}
106
107impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>>
108 Imbalance<B, OnDrop, OppositeOnDrop>
109{
110 pub(crate) fn new(amount: B) -> Self {
111 Self { amount, _phantom: PhantomData }
112 }
113
114 pub(crate) fn forget(imbalance: Self) {
116 core::mem::forget(imbalance);
117 }
118}
119
120impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>>
121 ImbalanceT<B> for Imbalance<B, OnDrop, OppositeOnDrop>
122{
123 type Opposite = Imbalance<B, OppositeOnDrop, OnDrop>;
124
125 fn zero() -> Self {
126 Self { amount: Zero::zero(), _phantom: PhantomData }
127 }
128
129 fn drop_zero(self) -> Result<(), Self> {
130 if self.amount.is_zero() {
131 core::mem::forget(self);
132 Ok(())
133 } else {
134 Err(self)
135 }
136 }
137
138 fn split(self, amount: B) -> (Self, Self) {
139 let first = self.amount.min(amount);
140 let second = self.amount - first;
141 core::mem::forget(self);
142 (Imbalance::new(first), Imbalance::new(second))
143 }
144
145 fn extract(&mut self, amount: B) -> Self {
146 let new = self.amount.min(amount);
147 self.amount = self.amount - new;
148 Imbalance::new(new)
149 }
150
151 fn merge(mut self, other: Self) -> Self {
152 self.amount = self.amount.saturating_add(other.amount);
153 core::mem::forget(other);
154 self
155 }
156 fn subsume(&mut self, other: Self) {
157 self.amount = self.amount.saturating_add(other.amount);
158 core::mem::forget(other);
159 }
160 fn offset(
161 self,
162 other: Imbalance<B, OppositeOnDrop, OnDrop>,
163 ) -> SameOrOther<Self, Imbalance<B, OppositeOnDrop, OnDrop>> {
164 let (a, b) = (self.amount, other.amount);
165 core::mem::forget((self, other));
166
167 if a == b {
168 SameOrOther::None
169 } else if a > b {
170 SameOrOther::Same(Imbalance::new(a - b))
171 } else {
172 SameOrOther::Other(Imbalance::<B, OppositeOnDrop, OnDrop>::new(b - a))
173 }
174 }
175 fn peek(&self) -> B {
176 self.amount
177 }
178}
179
180impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> TryMerge
181 for Imbalance<B, OnDrop, OppositeOnDrop>
182{
183 fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
184 Ok(self.merge(other))
185 }
186}
187
188impl<
189 B: Balance + 'static,
190 OnDrop: HandleImbalanceDrop<B> + 'static,
191 OppositeOnDrop: HandleImbalanceDrop<B> + 'static,
192 > UnsafeConstructorDestructor<u128> for Imbalance<B, OnDrop, OppositeOnDrop>
193{
194 fn unsafe_clone(&self) -> Box<dyn ImbalanceAccounting<u128>> {
195 let clone = Self { amount: self.amount, _phantom: PhantomData::default() };
196 Box::new(clone)
197 }
198 fn forget_imbalance(&mut self) -> u128 {
199 let amount = self.amount.saturated_into();
200 self.amount = 0u128.saturated_into();
201 amount
202 }
203}
204
205impl<
206 B: Balance + 'static,
207 OnDrop: HandleImbalanceDrop<B> + 'static,
208 OppositeOnDrop: HandleImbalanceDrop<B> + 'static,
209 > UnsafeManualAccounting<u128> for Imbalance<B, OnDrop, OppositeOnDrop>
210{
211 fn saturating_subsume(&mut self, mut other: Box<dyn ImbalanceAccounting<u128>>) {
212 let amount = other.forget_imbalance();
213 self.amount = self.amount.saturating_add(amount.saturated_into());
214 }
215}
216
217impl<
218 B: Balance + 'static,
219 OnDrop: HandleImbalanceDrop<B> + 'static,
220 OppositeOnDrop: HandleImbalanceDrop<B> + 'static,
221 > ImbalanceAccounting<u128> for Imbalance<B, OnDrop, OppositeOnDrop>
222{
223 fn amount(&self) -> u128 {
224 self.peek().saturated_into()
225 }
226 fn saturating_take(&mut self, amount: u128) -> Box<dyn ImbalanceAccounting<u128>> {
227 Box::new(self.extract(amount.saturated_into()))
228 }
229}
230
231pub(crate) fn from_fungibles<
238 A: AssetId,
239 B: Balance,
240 OnDropIn: fungibles::HandleImbalanceDrop<A, B>,
241 OppositeIn: fungibles::HandleImbalanceDrop<A, B>,
242 OnDropOut: HandleImbalanceDrop<B>,
243 OppositeOut: HandleImbalanceDrop<B>,
244>(
245 imbalance: fungibles::Imbalance<A, B, OnDropIn, OppositeIn>,
246) -> Imbalance<B, OnDropOut, OppositeOut> {
247 let new = Imbalance::new(imbalance.peek());
248 fungibles::Imbalance::forget(imbalance);
249 new
250}
251
252pub type Debt<AccountId, B> = Imbalance<
254 <B as Inspect<AccountId>>::Balance,
255 <B as Balanced<AccountId>>::OnDropDebt,
257 <B as Balanced<AccountId>>::OnDropCredit,
258>;
259
260pub type Credit<AccountId, B> = Imbalance<
263 <B as Inspect<AccountId>>::Balance,
264 <B as Balanced<AccountId>>::OnDropCredit,
266 <B as Balanced<AccountId>>::OnDropDebt,
267>;