frame_support/traits/tokens/fungible/regular.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! `Inspect` and `Mutate` traits for working with regular balances.
19//!
20//! See the [`crate::traits::fungible`] doc for more information about fungible traits.
21
22use crate::{
23 ensure,
24 traits::{
25 tokens::{
26 misc::{
27 Balance, DepositConsequence,
28 Fortitude::{self, Force, Polite},
29 Precision::{self, BestEffort, Exact},
30 Preservation::{self, Expendable},
31 Provenance::{self, Extant},
32 WithdrawConsequence,
33 },
34 Imbalance as ImbalanceT,
35 },
36 SameOrOther, TryDrop,
37 },
38};
39use core::marker::PhantomData;
40use sp_arithmetic::traits::{CheckedAdd, CheckedSub, One};
41use sp_runtime::{traits::Saturating, ArithmeticError, DispatchError, TokenError};
42
43use super::{Credit, Debt, HandleImbalanceDrop, Imbalance};
44
45/// Trait for providing balance-inspection access to a fungible asset.
46pub trait Inspect<AccountId>: Sized {
47 /// Scalar type for representing balance of an account.
48 type Balance: Balance;
49
50 /// The total amount of issuance in the system.
51 fn total_issuance() -> Self::Balance;
52
53 /// The total amount of issuance in the system excluding those which are controlled by the
54 /// system.
55 fn active_issuance() -> Self::Balance {
56 Self::total_issuance()
57 }
58
59 /// The minimum balance any single account may have.
60 fn minimum_balance() -> Self::Balance;
61
62 /// Get the total amount of funds whose ultimate beneficial ownership can be determined as
63 /// `who`.
64 ///
65 /// This may include funds which are wholly inaccessible to `who`, either temporarily or even
66 /// indefinitely.
67 ///
68 /// For the amount of the balance which is currently free to be removed from the account without
69 /// error, use [`Inspect::reducible_balance`].
70 ///
71 /// For the amount of the balance which may eventually be free to be removed from the account,
72 /// use `balance()`.
73 fn total_balance(who: &AccountId) -> Self::Balance;
74
75 /// Get the balance of `who` which does not include funds which are exclusively allocated to
76 /// subsystems of the chain ("on hold" or "reserved").
77 ///
78 /// In general this isn't especially useful outside of tests, and for practical purposes, you'll
79 /// want to use [`Inspect::reducible_balance`].
80 fn balance(who: &AccountId) -> Self::Balance;
81
82 /// Get the maximum amount that `who` can withdraw/transfer successfully based on whether the
83 /// account should be kept alive (`preservation`) or whether we are willing to force the
84 /// reduction and potentially go below user-level restrictions on the minimum amount of the
85 /// account.
86 ///
87 /// Always less than or equal to [`Inspect::balance`].
88 fn reducible_balance(
89 who: &AccountId,
90 preservation: Preservation,
91 force: Fortitude,
92 ) -> Self::Balance;
93
94 /// Returns `true` if the balance of `who` may be increased by `amount`.
95 ///
96 /// - `who`: The account of which the balance should be increased by `amount`.
97 /// - `amount`: How much should the balance be increased?
98 /// - `provenance`: Will `amount` be minted to deposit it into `account` or is it already in the
99 /// system?
100 fn can_deposit(
101 who: &AccountId,
102 amount: Self::Balance,
103 provenance: Provenance,
104 ) -> DepositConsequence;
105
106 /// Returns `Success` if the balance of `who` may be decreased by `amount`, otherwise
107 /// the consequence.
108 fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence<Self::Balance>;
109}
110
111/// Special dust type which can be type-safely converted into a [`Credit`].
112#[must_use]
113pub struct Dust<A, T: Inspect<A>>(pub T::Balance);
114
115impl<A, T: Balanced<A>> Dust<A, T> {
116 /// Convert `Dust` into an instance of `Credit`.
117 pub fn into_credit(self) -> Credit<A, T> {
118 Credit::<A, T>::new(self.0)
119 }
120}
121
122/// A fungible token class where the balance can be set arbitrarily.
123///
124/// **WARNING**
125/// Do not use this directly unless you want trouble, since it allows you to alter account balances
126/// without keeping the issuance up to date. It has no safeguards against accidentally creating
127/// token imbalances in your system leading to accidental inflation or deflation. It's really just
128/// for the underlying datatype to implement so the user gets the much safer [`Balanced`] trait to
129/// use.
130pub trait Unbalanced<AccountId>: Inspect<AccountId> {
131 /// Create some dust and handle it with [`Unbalanced::handle_dust`]. This is an unbalanced
132 /// operation and it must only be used when an account is modified in a raw fashion, outside of
133 /// the entire fungibles API. The `amount` is capped at [`Inspect::minimum_balance()`] - 1`.
134 ///
135 /// This should not be reimplemented.
136 fn handle_raw_dust(amount: Self::Balance) {
137 Self::handle_dust(Dust(amount.min(Self::minimum_balance().saturating_sub(One::one()))))
138 }
139
140 /// Do something with the dust which has been destroyed from the system. [`Dust`] can be
141 /// converted into a [`Credit`] with the [`Balanced`] trait impl.
142 fn handle_dust(dust: Dust<AccountId, Self>);
143
144 /// Forcefully set the balance of `who` to `amount`.
145 ///
146 /// If this call executes successfully, you can `assert_eq!(Self::balance(), amount);`.
147 ///
148 /// For implementations which include one or more balances on hold, then these are *not*
149 /// included in the `amount`.
150 ///
151 /// This function does its best to force the balance change through, but will not break system
152 /// invariants such as any Existential Deposits needed or overflows/underflows.
153 /// If this cannot be done for some reason (e.g. because the account cannot be created, deleted
154 /// or would overflow) then an `Err` is returned.
155 ///
156 /// If `Ok` is returned then its inner, then `Some` is the amount which was discarded as dust
157 /// due to existential deposit requirements. The default implementation of
158 /// [`Unbalanced::decrease_balance`] and [`Unbalanced::increase_balance`] converts this into an
159 /// [`Imbalance`] and then passes it into [`Unbalanced::handle_dust`].
160 fn write_balance(
161 who: &AccountId,
162 amount: Self::Balance,
163 ) -> Result<Option<Self::Balance>, DispatchError>;
164
165 /// Set the total issuance to `amount`.
166 fn set_total_issuance(amount: Self::Balance);
167
168 /// Reduce the balance of `who` by `amount`.
169 ///
170 /// If `precision` is [`Exact`] and it cannot be reduced by that amount for
171 /// some reason, return `Err` and don't reduce it at all. If `precision` is [`BestEffort`], then
172 /// reduce the balance of `who` by the most that is possible, up to `amount`.
173 ///
174 /// In either case, if `Ok` is returned then the inner is the amount by which is was reduced.
175 /// Minimum balance will be respected and thus the returned amount may be up to
176 /// [`Inspect::minimum_balance()`] - 1` greater than `amount` in the case that the reduction
177 /// caused the account to be deleted.
178 fn decrease_balance(
179 who: &AccountId,
180 mut amount: Self::Balance,
181 precision: Precision,
182 preservation: Preservation,
183 force: Fortitude,
184 ) -> Result<Self::Balance, DispatchError> {
185 let old_balance = Self::balance(who);
186 let reducible = Self::reducible_balance(who, preservation, force);
187 match precision {
188 BestEffort => amount = amount.min(reducible),
189 Exact => ensure!(reducible >= amount, TokenError::FundsUnavailable),
190 }
191
192 let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
193 if let Some(dust) = Self::write_balance(who, new_balance)? {
194 Self::handle_dust(Dust(dust));
195 }
196 Ok(old_balance.saturating_sub(new_balance))
197 }
198
199 /// Increase the balance of `who` by `amount`.
200 ///
201 /// If it cannot be increased by that amount for some reason, return `Err` and don't increase
202 /// it at all. If Ok, return the imbalance.
203 /// Minimum balance will be respected and an error will be returned if
204 /// amount < [`Inspect::minimum_balance()`] when the account of `who` is zero.
205 fn increase_balance(
206 who: &AccountId,
207 amount: Self::Balance,
208 precision: Precision,
209 ) -> Result<Self::Balance, DispatchError> {
210 let old_balance = Self::balance(who);
211 let new_balance = if let BestEffort = precision {
212 old_balance.saturating_add(amount)
213 } else {
214 old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?
215 };
216 if new_balance < Self::minimum_balance() {
217 // Attempt to increase from 0 to below minimum -> stays at zero.
218 if let BestEffort = precision {
219 Ok(Default::default())
220 } else {
221 Err(TokenError::BelowMinimum.into())
222 }
223 } else {
224 if new_balance == old_balance {
225 Ok(Default::default())
226 } else {
227 if let Some(dust) = Self::write_balance(who, new_balance)? {
228 Self::handle_dust(Dust(dust));
229 }
230 Ok(new_balance.saturating_sub(old_balance))
231 }
232 }
233 }
234
235 /// Reduce the active issuance by some amount.
236 fn deactivate(_: Self::Balance) {}
237
238 /// Increase the active issuance by some amount, up to the outstanding amount reduced.
239 fn reactivate(_: Self::Balance) {}
240}
241
242/// Trait for providing a basic fungible asset.
243pub trait Mutate<AccountId>: Inspect<AccountId> + Unbalanced<AccountId>
244where
245 AccountId: Eq,
246{
247 /// Increase the balance of `who` by exactly `amount`, minting new tokens. If that isn't
248 /// possible then an `Err` is returned and nothing is changed.
249 fn mint_into(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
250 Self::total_issuance().checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
251 let actual = Self::increase_balance(who, amount, Exact)?;
252 Self::set_total_issuance(Self::total_issuance().saturating_add(actual));
253 Self::done_mint_into(who, amount);
254 Ok(actual)
255 }
256
257 /// Attempt to decrease the balance of `who`, burning the tokens.
258 /// The actual amount burned is derived from the `amount`, `preservation`, `precision` and
259 /// `force`, and might end up being more, less or equal to the `amount` specified.
260 ///
261 /// If the burn isn't possible then an `Err` is returned and nothing is changed.
262 /// If successful, the amount of tokens reduced is returned.
263 fn burn_from(
264 who: &AccountId,
265 amount: Self::Balance,
266 preservation: Preservation,
267 precision: Precision,
268 force: Fortitude,
269 ) -> Result<Self::Balance, DispatchError> {
270 let actual = Self::reducible_balance(who, preservation, force).min(amount);
271 ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable);
272 Self::total_issuance().checked_sub(&actual).ok_or(ArithmeticError::Overflow)?;
273 let actual = Self::decrease_balance(who, actual, BestEffort, preservation, force)?;
274 Self::set_total_issuance(Self::total_issuance().saturating_sub(actual));
275 Self::done_burn_from(who, actual);
276 Ok(actual)
277 }
278
279 /// Attempt to decrease the `asset` balance of `who` by `amount`.
280 ///
281 /// Equivalent to [`Mutate::burn_from`], except with an expectation that within the bounds of
282 /// some universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The
283 /// implementation may be configured such that the total assets suspended may never be less than
284 /// the total assets resumed (which is the invariant for an issuing system), or the reverse
285 /// (which the invariant in a non-issuing system).
286 ///
287 /// Because of this expectation, any metadata associated with the asset is expected to survive
288 /// the suspect-resume cycle.
289 fn shelve(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
290 let actual = Self::reducible_balance(who, Expendable, Polite).min(amount);
291 ensure!(actual == amount, TokenError::FundsUnavailable);
292 Self::total_issuance().checked_sub(&actual).ok_or(ArithmeticError::Overflow)?;
293 let actual = Self::decrease_balance(who, actual, BestEffort, Expendable, Polite)?;
294 Self::set_total_issuance(Self::total_issuance().saturating_sub(actual));
295 Self::done_shelve(who, actual);
296 Ok(actual)
297 }
298
299 /// Attempt to increase the `asset` balance of `who` by `amount`.
300 ///
301 /// Equivalent to [`Mutate::mint_into`], except with an expectation that within the bounds of
302 /// some universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The
303 /// implementation may be configured such that the total assets suspended may never be less than
304 /// the total assets resumed (which is the invariant for an issuing system), or the reverse
305 /// (which the invariant in a non-issuing system).
306 ///
307 /// Because of this expectation, any metadata associated with the asset is expected to survive
308 /// the suspect-resume cycle.
309 fn restore(who: &AccountId, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
310 Self::total_issuance().checked_add(&amount).ok_or(ArithmeticError::Overflow)?;
311 let actual = Self::increase_balance(who, amount, Exact)?;
312 Self::set_total_issuance(Self::total_issuance().saturating_add(actual));
313 Self::done_restore(who, amount);
314 Ok(actual)
315 }
316
317 /// Transfer funds from one account into another.
318 ///
319 /// A transfer where the source and destination account are identical is treated as No-OP after
320 /// checking the preconditions.
321 fn transfer(
322 source: &AccountId,
323 dest: &AccountId,
324 amount: Self::Balance,
325 preservation: Preservation,
326 ) -> Result<Self::Balance, DispatchError> {
327 let _extra = Self::can_withdraw(source, amount).into_result(preservation != Expendable)?;
328 Self::can_deposit(dest, amount, Extant).into_result()?;
329 if source == dest {
330 return Ok(amount)
331 }
332
333 Self::decrease_balance(source, amount, BestEffort, preservation, Polite)?;
334 // This should never fail as we checked `can_deposit` earlier. But we do a best-effort
335 // anyway.
336 let _ = Self::increase_balance(dest, amount, BestEffort);
337 Self::done_transfer(source, dest, amount);
338 Ok(amount)
339 }
340
341 /// Simple infallible function to force an account to have a particular balance, good for use
342 /// in tests and benchmarks but not recommended for production code owing to the lack of
343 /// error reporting.
344 ///
345 /// Returns the new balance.
346 fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance {
347 let b = Self::balance(who);
348 if b > amount {
349 Self::burn_from(who, b - amount, Expendable, BestEffort, Force)
350 .map(|d| b.saturating_sub(d))
351 } else {
352 Self::mint_into(who, amount - b).map(|d| b.saturating_add(d))
353 }
354 .unwrap_or(b)
355 }
356
357 fn done_mint_into(_who: &AccountId, _amount: Self::Balance) {}
358 fn done_burn_from(_who: &AccountId, _amount: Self::Balance) {}
359 fn done_shelve(_who: &AccountId, _amount: Self::Balance) {}
360 fn done_restore(_who: &AccountId, _amount: Self::Balance) {}
361 fn done_transfer(_source: &AccountId, _dest: &AccountId, _amount: Self::Balance) {}
362}
363
364/// Simple handler for an imbalance drop which increases the total issuance of the system by the
365/// imbalance amount. Used for leftover debt.
366pub struct IncreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
367impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::Balance>
368 for IncreaseIssuance<AccountId, U>
369{
370 fn handle(amount: U::Balance) {
371 U::set_total_issuance(U::total_issuance().saturating_add(amount))
372 }
373}
374
375/// Simple handler for an imbalance drop which decreases the total issuance of the system by the
376/// imbalance amount. Used for leftover credit.
377pub struct DecreaseIssuance<AccountId, U>(PhantomData<(AccountId, U)>);
378impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::Balance>
379 for DecreaseIssuance<AccountId, U>
380{
381 fn handle(amount: U::Balance) {
382 U::set_total_issuance(U::total_issuance().saturating_sub(amount))
383 }
384}
385
386/// A fungible token class where any creation and deletion of tokens is semi-explicit and where the
387/// total supply is maintained automatically.
388///
389/// This is auto-implemented when a token class has [`Unbalanced`] implemented.
390pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
391 /// The type for managing what happens when an instance of `Debt` is dropped without being used.
392 type OnDropDebt: HandleImbalanceDrop<Self::Balance>;
393 /// The type for managing what happens when an instance of `Credit` is dropped without being
394 /// used.
395 type OnDropCredit: HandleImbalanceDrop<Self::Balance>;
396
397 /// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will
398 /// typically be used to reduce an account by the same amount with e.g. [`Balanced::settle`].
399 ///
400 /// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example
401 /// in the case of underflow.
402 fn rescind(amount: Self::Balance) -> Debt<AccountId, Self> {
403 let old = Self::total_issuance();
404 let new = old.saturating_sub(amount);
405 Self::set_total_issuance(new);
406 let delta = old - new;
407 Self::done_rescind(delta);
408 Imbalance::<Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(delta)
409 }
410
411 /// Increase the total issuance by `amount` and return the according imbalance. The imbalance
412 /// will typically be used to increase an account by the same amount with e.g.
413 /// [`Balanced::resolve`].
414 ///
415 /// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example
416 /// in the case of overflow.
417 fn issue(amount: Self::Balance) -> Credit<AccountId, Self> {
418 let old = Self::total_issuance();
419 let new = old.saturating_add(amount);
420 Self::set_total_issuance(new);
421 let delta = new - old;
422 Self::done_issue(delta);
423 Imbalance::<Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(delta)
424 }
425
426 /// Produce a pair of imbalances that cancel each other out exactly.
427 ///
428 /// This is just the same as burning and issuing the same amount and has no effect on the
429 /// total issuance.
430 ///
431 /// This could fail when we cannot issue and redeem the entire `amount`, for example in the
432 /// case where the amount would cause overflow or underflow in [`Balanced::issue`] or
433 /// [`Balanced::rescind`].
434 fn pair(
435 amount: Self::Balance,
436 ) -> Result<(Debt<AccountId, Self>, Credit<AccountId, Self>), DispatchError> {
437 let issued = Self::issue(amount);
438 let rescinded = Self::rescind(amount);
439 // Need to check amount in case by some edge case both issued and rescinded are below
440 // `amount` by the exact same value
441 if issued.peek() != rescinded.peek() || issued.peek() != amount {
442 // Issued and rescinded will be dropped automatically
443 Err("Failed to issue and rescind equal amounts".into())
444 } else {
445 Ok((rescinded, issued))
446 }
447 }
448
449 /// Mints `value` into the account of `who`, creating it as needed.
450 ///
451 /// If `precision` is `BestEffort` and `value` in full could not be minted (e.g. due to
452 /// overflow), then the maximum is minted, up to `value`. If `precision` is [`Exact`], then
453 /// exactly `value` must be minted into the account of `who` or the operation will fail with an
454 /// `Err` and nothing will change.
455 ///
456 /// If the operation is successful, this will return `Ok` with a [`Debt`] of the total value
457 /// added to the account.
458 fn deposit(
459 who: &AccountId,
460 value: Self::Balance,
461 precision: Precision,
462 ) -> Result<Debt<AccountId, Self>, DispatchError> {
463 let increase = Self::increase_balance(who, value, precision)?;
464 Self::done_deposit(who, increase);
465 Ok(Imbalance::<Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(increase))
466 }
467
468 /// Removes `value` balance from `who` account if possible.
469 ///
470 /// If `precision` is [`BestEffort`] and `value` in full could not be removed (e.g. due to
471 /// underflow), then the maximum is removed, up to `value`. If `precision` is [`Exact`], then
472 /// exactly `value` must be removed from the account of `who` or the operation will fail with an
473 /// `Err` and nothing will change.
474 ///
475 /// If the removal is needed but not possible, then it returns `Err` and nothing is changed.
476 /// If the account needed to be deleted, then slightly more than `value` may be removed from the
477 /// account owning since up to (but not including) minimum balance may also need to be removed.
478 ///
479 /// If the operation is successful, this will return `Ok` with a [`Credit`] of the total value
480 /// removed from the account.
481 fn withdraw(
482 who: &AccountId,
483 value: Self::Balance,
484 precision: Precision,
485 preservation: Preservation,
486 force: Fortitude,
487 ) -> Result<Credit<AccountId, Self>, DispatchError> {
488 let decrease = Self::decrease_balance(who, value, precision, preservation, force)?;
489 Self::done_withdraw(who, decrease);
490 Ok(Imbalance::<Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(decrease))
491 }
492
493 /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit`
494 /// cannot be countered, then nothing is changed and the original `credit` is returned in an
495 /// `Err`.
496 ///
497 /// Please note: If `credit.peek()` is less than [`Inspect::minimum_balance()`], then `who` must
498 /// already exist for this to succeed.
499 fn resolve(
500 who: &AccountId,
501 credit: Credit<AccountId, Self>,
502 ) -> Result<(), Credit<AccountId, Self>> {
503 let v = credit.peek();
504 let debt = match Self::deposit(who, v, Exact) {
505 Err(_) => return Err(credit),
506 Ok(d) => d,
507 };
508 let result = credit.offset(debt).try_drop();
509 debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed");
510 Ok(())
511 }
512
513 /// The balance of `who` is decreased in order to counter `debt`. If the whole of `debt`
514 /// cannot be countered, then nothing is changed and the original `debt` is returned in an
515 /// `Err`.
516 fn settle(
517 who: &AccountId,
518 debt: Debt<AccountId, Self>,
519 preservation: Preservation,
520 ) -> Result<Credit<AccountId, Self>, Debt<AccountId, Self>> {
521 let amount = debt.peek();
522 let credit = match Self::withdraw(who, amount, Exact, preservation, Polite) {
523 Err(_) => return Err(debt),
524 Ok(c) => c,
525 };
526
527 match credit.offset(debt) {
528 SameOrOther::None => Ok(Credit::<AccountId, Self>::zero()),
529 SameOrOther::Same(dust) => Ok(dust),
530 SameOrOther::Other(rest) => {
531 debug_assert!(false, "ok withdraw return must be at least debt value; qed");
532 Err(rest)
533 },
534 }
535 }
536
537 fn done_rescind(_amount: Self::Balance) {}
538 fn done_issue(_amount: Self::Balance) {}
539 fn done_deposit(_who: &AccountId, _amount: Self::Balance) {}
540 fn done_withdraw(_who: &AccountId, _amount: Self::Balance) {}
541}
542
543/// Dummy implementation of [`Inspect`]
544#[cfg(feature = "std")]
545impl<AccountId> Inspect<AccountId> for () {
546 type Balance = u32;
547 fn total_issuance() -> Self::Balance {
548 0
549 }
550 fn minimum_balance() -> Self::Balance {
551 0
552 }
553 fn total_balance(_: &AccountId) -> Self::Balance {
554 0
555 }
556 fn balance(_: &AccountId) -> Self::Balance {
557 0
558 }
559 fn reducible_balance(_: &AccountId, _: Preservation, _: Fortitude) -> Self::Balance {
560 0
561 }
562 fn can_deposit(_: &AccountId, _: Self::Balance, _: Provenance) -> DepositConsequence {
563 DepositConsequence::Success
564 }
565 fn can_withdraw(_: &AccountId, _: Self::Balance) -> WithdrawConsequence<Self::Balance> {
566 WithdrawConsequence::Success
567 }
568}
569
570/// Dummy implementation of [`Unbalanced`]
571#[cfg(feature = "std")]
572impl<AccountId> Unbalanced<AccountId> for () {
573 fn handle_dust(_: Dust<AccountId, Self>) {}
574 fn write_balance(
575 _: &AccountId,
576 _: Self::Balance,
577 ) -> Result<Option<Self::Balance>, DispatchError> {
578 Ok(None)
579 }
580 fn set_total_issuance(_: Self::Balance) {}
581}
582
583/// Dummy implementation of [`Mutate`]
584#[cfg(feature = "std")]
585impl<AccountId: Eq> Mutate<AccountId> for () {}