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