frame_support/traits/tokens/currency/
reservable.rs1use scale_info::TypeInfo;
21use sp_core::Get;
22
23use super::{super::misc::BalanceStatus, Currency};
24use crate::{
25 dispatch::DispatchResult,
26 traits::{ExistenceRequirement, SignedImbalance, WithdrawReasons},
27};
28use sp_runtime::DispatchError;
29
30pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
32 fn can_reserve(who: &AccountId, value: Self::Balance) -> bool;
35
36 fn slash_reserved(
42 who: &AccountId,
43 value: Self::Balance,
44 ) -> (Self::NegativeImbalance, Self::Balance);
45
46 fn reserved_balance(who: &AccountId) -> Self::Balance;
55
56 fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult;
61
62 fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance;
68
69 fn repatriate_reserved(
77 slashed: &AccountId,
78 beneficiary: &AccountId,
79 value: Self::Balance,
80 status: BalanceStatus,
81 ) -> Result<Self::Balance, DispatchError>;
82}
83
84#[cfg(feature = "std")]
85impl<AccountId> ReservableCurrency<AccountId> for () {
86 fn can_reserve(_: &AccountId, _: Self::Balance) -> bool {
87 true
88 }
89 fn slash_reserved(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) {
90 ((), 0)
91 }
92 fn reserved_balance(_: &AccountId) -> Self::Balance {
93 0
94 }
95 fn reserve(_: &AccountId, _: Self::Balance) -> DispatchResult {
96 Ok(())
97 }
98 fn unreserve(_: &AccountId, _: Self::Balance) -> Self::Balance {
99 0
100 }
101 fn repatriate_reserved(
102 _: &AccountId,
103 _: &AccountId,
104 _: Self::Balance,
105 _: BalanceStatus,
106 ) -> Result<Self::Balance, DispatchError> {
107 Ok(0)
108 }
109}
110
111pub trait NamedReservableCurrency<AccountId>: ReservableCurrency<AccountId> {
112 type ReserveIdentifier: codec::Encode + TypeInfo + 'static;
115
116 fn slash_reserved_named(
121 id: &Self::ReserveIdentifier,
122 who: &AccountId,
123 value: Self::Balance,
124 ) -> (Self::NegativeImbalance, Self::Balance);
125
126 fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &AccountId) -> Self::Balance;
138
139 fn reserve_named(
144 id: &Self::ReserveIdentifier,
145 who: &AccountId,
146 value: Self::Balance,
147 ) -> DispatchResult;
148
149 fn unreserve_named(
160 id: &Self::ReserveIdentifier,
161 who: &AccountId,
162 value: Self::Balance,
163 ) -> Self::Balance;
164
165 fn repatriate_reserved_named(
173 id: &Self::ReserveIdentifier,
174 slashed: &AccountId,
175 beneficiary: &AccountId,
176 value: Self::Balance,
177 status: BalanceStatus,
178 ) -> Result<Self::Balance, DispatchError>;
179
180 fn ensure_reserved_named(
185 id: &Self::ReserveIdentifier,
186 who: &AccountId,
187 value: Self::Balance,
188 ) -> DispatchResult {
189 let current = Self::reserved_balance_named(id, who);
190 if current > value {
191 Self::unreserve_named(id, who, current - value);
193 Ok(())
194 } else if value > current {
195 Self::reserve_named(id, who, value - current)
197 } else {
198 Ok(())
200 }
201 }
202
203 fn unreserve_all_named(id: &Self::ReserveIdentifier, who: &AccountId) -> Self::Balance {
207 let value = Self::reserved_balance_named(id, who);
208 Self::unreserve_named(id, who, value);
209 value
210 }
211
212 fn slash_all_reserved_named(
216 id: &Self::ReserveIdentifier,
217 who: &AccountId,
218 ) -> Self::NegativeImbalance {
219 let value = Self::reserved_balance_named(id, who);
220 Self::slash_reserved_named(id, who, value).0
221 }
222
223 fn repatriate_all_reserved_named(
230 id: &Self::ReserveIdentifier,
231 slashed: &AccountId,
232 beneficiary: &AccountId,
233 status: BalanceStatus,
234 ) -> DispatchResult {
235 let value = Self::reserved_balance_named(id, slashed);
236 Self::repatriate_reserved_named(id, slashed, beneficiary, value, status).map(|_| ())
237 }
238}
239
240pub struct WithName<NamedReservable, Id, AccountId>(
245 core::marker::PhantomData<(NamedReservable, Id, AccountId)>,
246);
247impl<
248 NamedReservable: NamedReservableCurrency<AccountId>,
249 Id: Get<NamedReservable::ReserveIdentifier>,
250 AccountId,
251 > Currency<AccountId> for WithName<NamedReservable, Id, AccountId>
252{
253 type Balance = <NamedReservable as Currency<AccountId>>::Balance;
254 type PositiveImbalance = <NamedReservable as Currency<AccountId>>::PositiveImbalance;
255 type NegativeImbalance = <NamedReservable as Currency<AccountId>>::NegativeImbalance;
256
257 fn total_balance(who: &AccountId) -> Self::Balance {
258 NamedReservable::total_balance(who)
259 }
260 fn can_slash(who: &AccountId, value: Self::Balance) -> bool {
261 NamedReservable::can_slash(who, value)
262 }
263 fn total_issuance() -> Self::Balance {
264 NamedReservable::total_issuance()
265 }
266 fn minimum_balance() -> Self::Balance {
267 NamedReservable::minimum_balance()
268 }
269 fn burn(amount: Self::Balance) -> Self::PositiveImbalance {
270 NamedReservable::burn(amount)
271 }
272 fn issue(amount: Self::Balance) -> Self::NegativeImbalance {
273 NamedReservable::issue(amount)
274 }
275 fn pair(amount: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) {
276 NamedReservable::pair(amount)
277 }
278 fn free_balance(who: &AccountId) -> Self::Balance {
279 NamedReservable::free_balance(who)
280 }
281 fn ensure_can_withdraw(
282 who: &AccountId,
283 amount: Self::Balance,
284 reasons: WithdrawReasons,
285 new_balance: Self::Balance,
286 ) -> DispatchResult {
287 NamedReservable::ensure_can_withdraw(who, amount, reasons, new_balance)
288 }
289
290 fn transfer(
291 source: &AccountId,
292 dest: &AccountId,
293 value: Self::Balance,
294 existence_requirement: ExistenceRequirement,
295 ) -> DispatchResult {
296 NamedReservable::transfer(source, dest, value, existence_requirement)
297 }
298 fn slash(who: &AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) {
299 NamedReservable::slash(who, value)
300 }
301 fn deposit_into_existing(
302 who: &AccountId,
303 value: Self::Balance,
304 ) -> Result<Self::PositiveImbalance, DispatchError> {
305 NamedReservable::deposit_into_existing(who, value)
306 }
307 fn resolve_into_existing(
308 who: &AccountId,
309 value: Self::NegativeImbalance,
310 ) -> Result<(), Self::NegativeImbalance> {
311 NamedReservable::resolve_into_existing(who, value)
312 }
313 fn deposit_creating(who: &AccountId, value: Self::Balance) -> Self::PositiveImbalance {
314 NamedReservable::deposit_creating(who, value)
315 }
316 fn resolve_creating(who: &AccountId, value: Self::NegativeImbalance) {
317 NamedReservable::resolve_creating(who, value)
318 }
319 fn withdraw(
320 who: &AccountId,
321 value: Self::Balance,
322 reasons: WithdrawReasons,
323 liveness: ExistenceRequirement,
324 ) -> Result<Self::NegativeImbalance, DispatchError> {
325 NamedReservable::withdraw(who, value, reasons, liveness)
326 }
327 fn settle(
328 who: &AccountId,
329 value: Self::PositiveImbalance,
330 reasons: WithdrawReasons,
331 liveness: ExistenceRequirement,
332 ) -> Result<(), Self::PositiveImbalance> {
333 NamedReservable::settle(who, value, reasons, liveness)
334 }
335 fn make_free_balance_be(
336 who: &AccountId,
337 balance: Self::Balance,
338 ) -> SignedImbalance<Self::Balance, Self::PositiveImbalance> {
339 NamedReservable::make_free_balance_be(who, balance)
340 }
341}
342impl<
343 NamedReservable: NamedReservableCurrency<AccountId>,
344 Id: Get<NamedReservable::ReserveIdentifier>,
345 AccountId,
346 > ReservableCurrency<AccountId> for WithName<NamedReservable, Id, AccountId>
347{
348 fn can_reserve(who: &AccountId, value: Self::Balance) -> bool {
349 NamedReservable::can_reserve(who, value)
350 }
351
352 fn slash_reserved(
353 who: &AccountId,
354 value: Self::Balance,
355 ) -> (Self::NegativeImbalance, Self::Balance) {
356 NamedReservable::slash_reserved_named(&Id::get(), who, value)
357 }
358
359 fn reserved_balance(who: &AccountId) -> Self::Balance {
360 NamedReservable::reserved_balance_named(&Id::get(), who)
361 }
362
363 fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult {
364 NamedReservable::reserve_named(&Id::get(), who, value)
365 }
366
367 fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance {
368 NamedReservable::unreserve_named(&Id::get(), who, value)
369 }
370
371 fn repatriate_reserved(
372 slashed: &AccountId,
373 beneficiary: &AccountId,
374 value: Self::Balance,
375 status: BalanceStatus,
376 ) -> Result<Self::Balance, DispatchError> {
377 NamedReservable::repatriate_reserved_named(&Id::get(), slashed, beneficiary, value, status)
378 }
379}