frame_support/traits/tokens/fungibles/
imbalance.rs1use super::*;
24use crate::traits::{
25 fungible,
26 misc::{SameOrOther, TryDrop},
27 tokens::{
28 imbalance::{Imbalance as ImbalanceT, TryMerge},
29 AssetId, Balance,
30 },
31};
32use core::marker::PhantomData;
33use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound};
34use sp_runtime::traits::Zero;
35
36pub trait HandleImbalanceDrop<AssetId, Balance> {
39 fn handle(asset: AssetId, amount: Balance);
40}
41
42#[must_use]
48#[derive(EqNoBound, PartialEqNoBound, RuntimeDebugNoBound)]
49pub struct Imbalance<
50 A: AssetId,
51 B: Balance,
52 OnDrop: HandleImbalanceDrop<A, B>,
53 OppositeOnDrop: HandleImbalanceDrop<A, B>,
54> {
55 asset: A,
56 amount: B,
57 _phantom: PhantomData<(OnDrop, OppositeOnDrop)>,
58}
59
60impl<
61 A: AssetId,
62 B: Balance,
63 OnDrop: HandleImbalanceDrop<A, B>,
64 OppositeOnDrop: HandleImbalanceDrop<A, B>,
65 > Drop for Imbalance<A, B, OnDrop, OppositeOnDrop>
66{
67 fn drop(&mut self) {
68 if !self.amount.is_zero() {
69 OnDrop::handle(self.asset.clone(), self.amount)
70 }
71 }
72}
73
74impl<
75 A: AssetId,
76 B: Balance,
77 OnDrop: HandleImbalanceDrop<A, B>,
78 OppositeOnDrop: HandleImbalanceDrop<A, B>,
79 > TryDrop for Imbalance<A, B, OnDrop, OppositeOnDrop>
80{
81 fn try_drop(self) -> Result<(), Self> {
83 self.drop_zero()
84 }
85}
86
87impl<
88 A: AssetId,
89 B: Balance,
90 OnDrop: HandleImbalanceDrop<A, B>,
91 OppositeOnDrop: HandleImbalanceDrop<A, B>,
92 > Imbalance<A, B, OnDrop, OppositeOnDrop>
93{
94 pub fn zero(asset: A) -> Self {
95 Self { asset, amount: Zero::zero(), _phantom: PhantomData }
96 }
97
98 pub(crate) fn new(asset: A, amount: B) -> Self {
99 Self { asset, amount, _phantom: PhantomData }
100 }
101
102 pub(crate) fn forget(imbalance: Self) {
104 core::mem::forget(imbalance);
105 }
106
107 pub fn drop_zero(self) -> Result<(), Self> {
108 if self.amount.is_zero() {
109 core::mem::forget(self);
110 Ok(())
111 } else {
112 Err(self)
113 }
114 }
115
116 pub fn split(self, amount: B) -> (Self, Self) {
117 let first = self.amount.min(amount);
118 let second = self.amount - first;
119 let asset = self.asset.clone();
120 core::mem::forget(self);
121 (Imbalance::new(asset.clone(), first), Imbalance::new(asset, second))
122 }
123
124 pub fn extract(&mut self, amount: B) -> Self {
127 let new = self.amount.min(amount);
128 self.amount = self.amount - new;
129 Imbalance::new(self.asset.clone(), new)
130 }
131
132 pub fn merge(mut self, other: Self) -> Result<Self, (Self, Self)> {
133 if self.asset == other.asset {
134 self.amount = self.amount.saturating_add(other.amount);
135 core::mem::forget(other);
136 Ok(self)
137 } else {
138 Err((self, other))
139 }
140 }
141 pub fn subsume(&mut self, other: Self) -> Result<(), Self> {
142 if self.asset == other.asset {
143 self.amount = self.amount.saturating_add(other.amount);
144 core::mem::forget(other);
145 Ok(())
146 } else {
147 Err(other)
148 }
149 }
150 pub fn offset(
151 self,
152 other: Imbalance<A, B, OppositeOnDrop, OnDrop>,
153 ) -> Result<
154 SameOrOther<Self, Imbalance<A, B, OppositeOnDrop, OnDrop>>,
155 (Self, Imbalance<A, B, OppositeOnDrop, OnDrop>),
156 > {
157 if self.asset == other.asset {
158 let (a, b) = (self.amount, other.amount);
159 let asset = self.asset.clone();
160 core::mem::forget((self, other));
161
162 if a == b {
163 Ok(SameOrOther::None)
164 } else if a > b {
165 Ok(SameOrOther::Same(Imbalance::new(asset, a - b)))
166 } else {
167 Ok(SameOrOther::Other(Imbalance::<A, B, OppositeOnDrop, OnDrop>::new(asset, b - a)))
168 }
169 } else {
170 Err((self, other))
171 }
172 }
173 pub fn peek(&self) -> B {
174 self.amount
175 }
176
177 pub fn asset(&self) -> A {
178 self.asset.clone()
179 }
180}
181
182impl<
183 A: AssetId,
184 B: Balance,
185 OnDrop: HandleImbalanceDrop<A, B>,
186 OppositeOnDrop: HandleImbalanceDrop<A, B>,
187 > TryMerge for Imbalance<A, B, OnDrop, OppositeOnDrop>
188{
189 fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
190 self.merge(other)
191 }
192}
193
194pub(crate) fn from_fungible<
202 A: AssetId,
203 B: Balance,
204 OnDropIn: fungible::HandleImbalanceDrop<B>,
205 OppositeIn: fungible::HandleImbalanceDrop<B>,
206 OnDropOut: HandleImbalanceDrop<A, B>,
207 OppositeOut: HandleImbalanceDrop<A, B>,
208>(
209 imbalance: fungible::Imbalance<B, OnDropIn, OppositeIn>,
210 asset: A,
211) -> Imbalance<A, B, OnDropOut, OppositeOut> {
212 let new = Imbalance::new(asset, imbalance.peek());
213 fungible::Imbalance::forget(imbalance);
214 new
215}
216
217pub(crate) fn from_fungibles<
224 A: AssetId,
225 B: Balance,
226 OnDropIn: HandleImbalanceDrop<A, B>,
227 OppositeIn: HandleImbalanceDrop<A, B>,
228 AssetOut: AssetId,
229 OnDropOut: HandleImbalanceDrop<AssetOut, B>,
230 OppositeOut: HandleImbalanceDrop<AssetOut, B>,
231>(
232 imbalance: Imbalance<A, B, OnDropIn, OppositeIn>,
233 asset: AssetOut,
234) -> Imbalance<AssetOut, B, OnDropOut, OppositeOut> {
235 let new = Imbalance::new(asset, imbalance.peek());
236 Imbalance::forget(imbalance);
237 new
238}
239
240pub type Debt<AccountId, B> = Imbalance<
242 <B as Inspect<AccountId>>::AssetId,
243 <B as Inspect<AccountId>>::Balance,
244 <B as Balanced<AccountId>>::OnDropDebt,
246 <B as Balanced<AccountId>>::OnDropCredit,
247>;
248
249pub type Credit<AccountId, B> = Imbalance<
252 <B as Inspect<AccountId>>::AssetId,
253 <B as Inspect<AccountId>>::Balance,
254 <B as Balanced<AccountId>>::OnDropCredit,
256 <B as Balanced<AccountId>>::OnDropDebt,
257>;