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