referrerpolicy=no-referrer-when-downgrade

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