From e5c876dd6b59e2b7dbacaa4538cb42c802db3730 Mon Sep 17 00:00:00 2001
From: Liam Aharon <liam.aharon@hotmail.com>
Date: Wed, 30 Aug 2023 13:40:20 +1000
Subject: [PATCH] balanced and unbalanced conformance tests

---
 substrate/frame/balances/src/impl_fungible.rs |    5 +-
 .../src/tests/fungible_conformance_tests.rs   |   81 +-
 .../tokens/fungible/conformance_tests/mod.rs  |    2 +-
 .../fungible/conformance_tests/regular.rs     | 1347 +++++++++++++++++
 .../src/traits/tokens/fungible/item_of.rs     |    2 +-
 .../src/traits/tokens/fungible/regular.rs     |   76 +-
 6 files changed, 1461 insertions(+), 52 deletions(-)
 create mode 100644 substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular.rs

diff --git a/substrate/frame/balances/src/impl_fungible.rs b/substrate/frame/balances/src/impl_fungible.rs
index 03c40bb3a84..01cb64e66eb 100644
--- a/substrate/frame/balances/src/impl_fungible.rs
+++ b/substrate/frame/balances/src/impl_fungible.rs
@@ -174,7 +174,10 @@ impl<T: Config<I>, I: 'static> fungible::Unbalanced<T::AccountId> for Pallet<T,
 	}
 
 	fn deactivate(amount: Self::Balance) {
-		InactiveIssuance::<T, I>::mutate(|b| b.saturating_accrue(amount));
+		InactiveIssuance::<T, I>::mutate(|b| {
+			// InactiveIssuance cannot be greater than TotalIssuance.
+			*b = b.saturating_add(amount).min(TotalIssuance::<T, I>::get());
+		});
 	}
 
 	fn reactivate(amount: Self::Balance) {
diff --git a/substrate/frame/balances/src/tests/fungible_conformance_tests.rs b/substrate/frame/balances/src/tests/fungible_conformance_tests.rs
index 6262aa04dc0..5c0c19a554a 100644
--- a/substrate/frame/balances/src/tests/fungible_conformance_tests.rs
+++ b/substrate/frame/balances/src/tests/fungible_conformance_tests.rs
@@ -19,17 +19,19 @@ use super::*;
 use frame_support::traits::fungible::{conformance_tests, Inspect, Mutate};
 use paste::paste;
 
-macro_rules! run_tests {
-    ($path:path, $ext_deposit:expr, $($name:ident),*) => {
+macro_rules! generate_tests {
+	// Handle a conformance test that requires special testing with and without a dust trap.
+    (dust_trap_variation, $base_path:path, $scope:expr, $trait:ident, $ext_deposit:expr, $($test_name:ident),*) => {
 		$(
 			paste! {
 				#[test]
-				fn [< $name _existential_deposit_ $ext_deposit _dust_trap_on >]() {
+				fn [<$trait _ $scope _ $test_name _existential_deposit_ $ext_deposit _dust_trap_on >]() {
+					// Some random trap account.
 					let trap_account = <Test as frame_system::Config>::AccountId::from(65174286u64);
 					let builder = ExtBuilder::default().existential_deposit($ext_deposit).dust_trap(trap_account);
 					builder.build_and_execute_with(|| {
 						Balances::set_balance(&trap_account, Balances::minimum_balance());
-						$path::$name::<
+						$base_path::$scope::$trait::$test_name::<
 							Balances,
 							<Test as frame_system::Config>::AccountId,
 						>(Some(trap_account));
@@ -37,10 +39,10 @@ macro_rules! run_tests {
 				}
 
 				#[test]
-				fn [< $name _existential_deposit_ $ext_deposit _dust_trap_off >]() {
+				fn [< $trait _ $scope _ $test_name _existential_deposit_ $ext_deposit _dust_trap_off >]() {
 					let builder = ExtBuilder::default().existential_deposit($ext_deposit);
 					builder.build_and_execute_with(|| {
-						$path::$name::<
+						$base_path::$scope::$trait::$test_name::<
 							Balances,
 							<Test as frame_system::Config>::AccountId,
 						>(None);
@@ -49,9 +51,37 @@ macro_rules! run_tests {
 			}
 		)*
 	};
-	($path:path, $ext_deposit:expr) => {
-		run_tests!(
-			$path,
+	// Regular conformance test
+    ($base_path:path, $scope:expr, $trait:ident, $ext_deposit:expr, $($test_name:ident),*) => {
+		$(
+			paste! {
+				#[test]
+				fn [< $trait _ $scope _ $test_name _existential_deposit_ $ext_deposit>]() {
+					let builder = ExtBuilder::default().existential_deposit($ext_deposit);
+					builder.build_and_execute_with(|| {
+						$base_path::$scope::$trait::$test_name::<
+							Balances,
+							<Test as frame_system::Config>::AccountId,
+						>();
+					});
+				}
+			}
+		)*
+	};
+	($base_path:path, $ext_deposit:expr) => {
+		// regular::mutate
+		generate_tests!(
+			dust_trap_variation,
+			$base_path,
+			regular,
+			mutate,
+			$ext_deposit,
+			transfer_expendable_dust
+		);
+		generate_tests!(
+			$base_path,
+			regular,
+			mutate,
 			$ext_deposit,
 			mint_into_success,
 			mint_into_overflow,
@@ -66,7 +96,6 @@ macro_rules! run_tests {
 			shelve_insufficient_funds,
 			transfer_success,
 			transfer_expendable_all,
-			transfer_expendable_dust,
 			transfer_protect_preserve,
 			set_balance_mint_success,
 			set_balance_burn_success,
@@ -79,10 +108,34 @@ macro_rules! run_tests {
 			reducible_balance_expendable,
 			reducible_balance_protect_preserve
 		);
+		// regular::unbalanced
+		generate_tests!(
+			$base_path,
+			regular,
+			unbalanced,
+			$ext_deposit,
+			write_balance,
+			decrease_balance_expendable,
+			decrease_balance_preserve,
+			increase_balance,
+			set_total_issuance,
+			deactivate_and_reactivate
+		);
+		// regular::balanced
+		generate_tests!(
+			$base_path,
+			regular,
+			balanced,
+			$ext_deposit,
+			issue_and_resolve_credit,
+			rescind_and_settle_debt,
+			deposit,
+			withdraw,
+			pair
+		);
 	};
 }
 
-run_tests!(conformance_tests::inspect_mutate, 1);
-run_tests!(conformance_tests::inspect_mutate, 2);
-run_tests!(conformance_tests::inspect_mutate, 5);
-run_tests!(conformance_tests::inspect_mutate, 1000);
+generate_tests!(conformance_tests, 1);
+generate_tests!(conformance_tests, 5);
+generate_tests!(conformance_tests, 1000);
diff --git a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs
index 88ba56a6fed..22942e9a6d7 100644
--- a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs
+++ b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/mod.rs
@@ -1 +1 @@
-pub mod inspect_mutate;
+pub mod regular;
diff --git a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular.rs
new file mode 100644
index 00000000000..4401a6d4260
--- /dev/null
+++ b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular.rs
@@ -0,0 +1,1347 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+pub mod mutate {
+	use crate::traits::{
+		fungible::{Inspect, Mutate},
+		tokens::{
+			DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence,
+		},
+	};
+	use core::fmt::Debug;
+	use sp_arithmetic::traits::AtLeast8BitUnsigned;
+	use sp_runtime::traits::{Bounded, Zero};
+
+	/// Test [`Mutate::mint_into`] for successful token minting.
+	///
+	/// It ensures that account balances and total issuance values are updated correctly after
+	/// minting tokens into two distinct accounts.
+	pub fn mint_into_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account_0 = AccountId::from(0);
+		let account_1 = AccountId::from(1);
+
+		// Test: Mint an amount into each account
+		let amount_0 = T::minimum_balance();
+		let amount_1 = T::minimum_balance() + 5.into();
+		T::mint_into(&account_0, amount_0).unwrap();
+		T::mint_into(&account_1, amount_1).unwrap();
+
+		// Verify: Account balances are updated correctly
+		assert_eq!(T::total_balance(&account_0), amount_0);
+		assert_eq!(T::total_balance(&account_1), amount_1);
+		assert_eq!(T::balance(&account_0), amount_0);
+		assert_eq!(T::balance(&account_1), amount_1);
+
+		// Verify: Total issuance is updated correctly
+		assert_eq!(T::total_issuance(), initial_total_issuance + amount_0 + amount_1);
+		assert_eq!(T::active_issuance(), initial_active_issuance + amount_0 + amount_1);
+	}
+
+	/// Test [`Mutate::mint_into`] for overflow prevention.
+	///
+	/// This test ensures that minting tokens beyond the maximum balance value for an account
+	/// returns an error and does not change the account balance or total issuance values.
+	pub fn mint_into_overflow<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account = AccountId::from(10);
+		let amount = T::Balance::max_value() - 5.into() - initial_total_issuance;
+
+		// Mint just below the maximum balance
+		T::mint_into(&account, amount).unwrap();
+
+		// Verify: Minting beyond the maximum balance value returns an Err
+		T::mint_into(&account, 10.into()).unwrap_err();
+
+		// Verify: The balance did not change
+		assert_eq!(T::total_balance(&account), amount);
+		assert_eq!(T::balance(&account), amount);
+
+		// Verify: The total issuance did not change
+		assert_eq!(T::total_issuance(), initial_total_issuance + amount);
+		assert_eq!(T::active_issuance(), initial_active_issuance + amount);
+	}
+
+	/// Test [`Mutate::mint_into`] for handling balances below the minimum value.
+	///
+	/// This test verifies that minting tokens below the minimum balance for an account
+	/// returns an error and has no impact on the account balance or total issuance values.
+	pub fn mint_into_below_minimum<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Skip if there is no minimum balance
+		if T::minimum_balance() == T::Balance::zero() {
+			return
+		}
+
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account = AccountId::from(10);
+		let amount = T::minimum_balance() - 1.into();
+
+		// Verify: Minting below the minimum balance returns Err
+		T::mint_into(&account, amount).unwrap_err();
+
+		// Verify: noop
+		assert_eq!(T::total_balance(&account), T::Balance::zero());
+		assert_eq!(T::balance(&account), T::Balance::zero());
+		assert_eq!(T::total_issuance(), initial_total_issuance);
+		assert_eq!(T::active_issuance(), initial_active_issuance);
+	}
+
+	/// Test [`Mutate::burn_from`] for successfully burning an exact amount of tokens.
+	///
+	/// This test checks that burning tokens with [`Precision::Exact`] correctly reduces the account
+	/// balance and total issuance values by the burned amount.
+	pub fn burn_from_exact_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+
+		// Setup account
+		let account = AccountId::from(5);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Test: Burn an exact amount from the account
+		let amount_to_burn = T::Balance::from(5);
+		let precision = Precision::Exact;
+		let force = Fortitude::Polite;
+		T::burn_from(&account, amount_to_burn, precision, force).unwrap();
+
+		// Verify: The balance and total issuance should be reduced by the burned amount
+		assert_eq!(T::balance(&account), initial_balance - amount_to_burn);
+		assert_eq!(T::total_balance(&account), initial_balance - amount_to_burn);
+		assert_eq!(T::total_issuance(), initial_total_issuance + initial_balance - amount_to_burn);
+		assert_eq!(
+			T::active_issuance(),
+			initial_active_issuance + initial_balance - amount_to_burn
+		);
+	}
+
+	/// Test [`Mutate::burn_from`] for successfully burning tokens with [`Precision::BestEffort`].
+	///
+	/// This test verifies that the burning tokens with best-effort precision correctly reduces the
+	/// account balance and total issuance values by the reducible balance when attempting to burn
+	/// an amount greater than the reducible balance.
+	pub fn burn_from_best_effort_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+
+		// Setup account
+		let account = AccountId::from(5);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Get reducible balance
+		let force = Fortitude::Polite;
+		let reducible_balance = T::reducible_balance(&account, Preservation::Expendable, force);
+
+		// Test: Burn a best effort amount from the account that is greater than the reducible
+		// balance
+		let amount_to_burn = reducible_balance + 5.into();
+		let precision = Precision::BestEffort;
+		assert!(amount_to_burn > reducible_balance);
+		assert!(amount_to_burn > T::balance(&account));
+		T::burn_from(&account, amount_to_burn, precision, force).unwrap();
+
+		// Verify: The balance and total issuance should be reduced by the reducible_balance
+		assert_eq!(T::balance(&account), initial_balance - reducible_balance);
+		assert_eq!(T::total_balance(&account), initial_balance - reducible_balance);
+		assert_eq!(
+			T::total_issuance(),
+			initial_total_issuance + initial_balance - reducible_balance
+		);
+		assert_eq!(
+			T::active_issuance(),
+			initial_active_issuance + initial_balance - reducible_balance
+		);
+	}
+
+	/// Test [`Mutate::burn_from`] handling of insufficient funds when called with
+	/// [`Precision::Exact`].
+	///
+	/// This test verifies that burning an amount greater than the account's balance with exact
+	/// precision returns an error and does not change the account balance or total issuance values.
+	pub fn burn_from_exact_insufficient_funds<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Set up the initial conditions and parameters for the test
+		let account = AccountId::from(5);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+
+		// Verify: Burn an amount greater than the account's balance with Exact precision returns
+		// Err
+		let amount_to_burn = initial_balance + 10.into();
+		let precision = Precision::Exact;
+		let force = Fortitude::Polite;
+		T::burn_from(&account, amount_to_burn, precision, force).unwrap_err();
+
+		// Verify: The balance and total issuance should remain unchanged
+		assert_eq!(T::balance(&account), initial_balance);
+		assert_eq!(T::total_balance(&account), initial_balance);
+		assert_eq!(T::total_issuance(), initial_total_issuance);
+		assert_eq!(T::active_issuance(), initial_active_issuance);
+	}
+
+	/// Test [`Mutate::restore`] for successful restoration.
+	///
+	/// This test verifies that restoring an amount into each account updates their balances and the
+	/// total issuance values correctly.
+	pub fn restore_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account_0 = AccountId::from(0);
+		let account_1 = AccountId::from(1);
+
+		// Test: Restore an amount into each account
+		let amount_0 = T::minimum_balance();
+		let amount_1 = T::minimum_balance() + 5.into();
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		T::restore(&account_0, amount_0).unwrap();
+		T::restore(&account_1, amount_1).unwrap();
+
+		// Verify: Account balances are updated correctly
+		assert_eq!(T::total_balance(&account_0), amount_0);
+		assert_eq!(T::total_balance(&account_1), amount_1);
+		assert_eq!(T::balance(&account_0), amount_0);
+		assert_eq!(T::balance(&account_1), amount_1);
+
+		// Verify: Total issuance is updated correctly
+		assert_eq!(T::total_issuance(), initial_total_issuance + amount_0 + amount_1);
+		assert_eq!(T::active_issuance(), initial_active_issuance + amount_0 + amount_1);
+	}
+
+	/// Test [`Mutate::restore`] handles balance overflow.
+	///
+	/// This test verifies that restoring an amount beyond the maximum balance returns an error and
+	/// does not change the account balance or total issuance values.
+	pub fn restore_overflow<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account = AccountId::from(10);
+		let amount = T::Balance::max_value() - 5.into() - initial_total_issuance;
+
+		// Restore just below the maximum balance
+		T::restore(&account, amount).unwrap();
+
+		// Verify: Restoring beyond the maximum balance returns an Err
+		T::restore(&account, 10.into()).unwrap_err();
+
+		// Verify: The balance and total issuance did not change
+		assert_eq!(T::total_balance(&account), amount);
+		assert_eq!(T::balance(&account), amount);
+		assert_eq!(T::total_issuance(), initial_total_issuance + amount);
+		assert_eq!(T::active_issuance(), initial_active_issuance + amount);
+	}
+
+	/// Test [`Mutate::restore`] handles restoration below the minimum balance.
+	///
+	/// This test verifies that restoring an amount below the minimum balance returns an error and
+	/// does not change the account balance or total issuance values.
+	pub fn restore_below_minimum<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Skip if there is no minimum balance
+		if T::minimum_balance() == T::Balance::zero() {
+			return
+		}
+
+		let account = AccountId::from(10);
+		let amount = T::minimum_balance() - 1.into();
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+
+		// Verify: Restoring below the minimum balance returns Err
+		T::restore(&account, amount).unwrap_err();
+
+		// Verify: noop
+		assert_eq!(T::total_balance(&account), T::Balance::zero());
+		assert_eq!(T::balance(&account), T::Balance::zero());
+		assert_eq!(T::total_issuance(), initial_total_issuance);
+		assert_eq!(T::active_issuance(), initial_active_issuance);
+	}
+
+	/// Test [`Mutate::shelve`] for successful shelving.
+	///
+	/// This test verifies that shelving an amount from an account reduces the account balance and
+	/// total issuance values by the shelved amount.
+	pub fn shelve_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+
+		// Setup account
+		let account = AccountId::from(5);
+		let initial_balance = T::minimum_balance() + 10.into();
+
+		T::restore(&account, initial_balance).unwrap();
+
+		// Test: Shelve an amount from the account
+		let amount_to_shelve = T::Balance::from(5);
+		T::shelve(&account, amount_to_shelve).unwrap();
+
+		// Verify: The balance and total issuance should be reduced by the shelved amount
+		assert_eq!(T::balance(&account), initial_balance - amount_to_shelve);
+		assert_eq!(T::total_balance(&account), initial_balance - amount_to_shelve);
+		assert_eq!(
+			T::total_issuance(),
+			initial_total_issuance + initial_balance - amount_to_shelve
+		);
+		assert_eq!(
+			T::active_issuance(),
+			initial_active_issuance + initial_balance - amount_to_shelve
+		);
+	}
+
+	/// Test [`Mutate::shelve`] handles insufficient funds correctly.
+	///
+	/// This test verifies that attempting to shelve an amount greater than the account's balance
+	/// returns an error and does not change the account balance or total issuance values.
+	pub fn shelve_insufficient_funds<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+
+		// Set up the initial conditions and parameters for the test
+		let account = AccountId::from(5);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::restore(&account, initial_balance).unwrap();
+
+		// Verify: Shelving greater than the balance with Exact precision returns Err
+		let amount_to_shelve = initial_balance + 10.into();
+		T::shelve(&account, amount_to_shelve).unwrap_err();
+
+		// Verify: The balance and total issuance should remain unchanged
+		assert_eq!(T::balance(&account), initial_balance);
+		assert_eq!(T::total_balance(&account), initial_balance);
+		assert_eq!(T::total_issuance(), initial_total_issuance + initial_balance);
+		assert_eq!(T::active_issuance(), initial_active_issuance + initial_balance);
+	}
+
+	/// Test [`Mutate::transfer`] for a successful transfer.
+	///
+	/// This test verifies that transferring an amount between two accounts with updates the account
+	/// balances and maintains correct total issuance and active issuance values.
+	pub fn transfer_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account_0 = AccountId::from(0);
+		let account_1 = AccountId::from(1);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::set_balance(&account_0, initial_balance);
+		T::set_balance(&account_1, initial_balance);
+
+		// Test: Transfer an amount from account_0 to account_1
+		let transfer_amount = T::Balance::from(3);
+		T::transfer(&account_0, &account_1, transfer_amount, Preservation::Expendable).unwrap();
+
+		// Verify: Account balances are updated correctly
+		assert_eq!(T::total_balance(&account_0), initial_balance - transfer_amount);
+		assert_eq!(T::total_balance(&account_1), initial_balance + transfer_amount);
+		assert_eq!(T::balance(&account_0), initial_balance - transfer_amount);
+		assert_eq!(T::balance(&account_1), initial_balance + transfer_amount);
+
+		// Verify: Total issuance doesn't change
+		assert_eq!(T::total_issuance(), initial_total_issuance + initial_balance * 2.into());
+		assert_eq!(T::active_issuance(), initial_active_issuance + initial_balance * 2.into());
+	}
+
+	/// Test calling [`Mutate::transfer`] with [`Preservation::Expendable`] correctly transfers the
+	/// entire balance.
+	///
+	/// This test verifies that transferring the entire balance from one account to another with
+	/// when preservation is expendable updates the account balances and maintains the total
+	/// issuance and active issuance values.
+	pub fn transfer_expendable_all<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account_0 = AccountId::from(0);
+		let account_1 = AccountId::from(1);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::set_balance(&account_0, initial_balance);
+		T::set_balance(&account_1, initial_balance);
+
+		// Test: Transfer entire balance from account_0 to account_1
+		let preservation = Preservation::Expendable;
+		let transfer_amount = initial_balance;
+		T::transfer(&account_0, &account_1, transfer_amount, preservation).unwrap();
+
+		// Verify: Account balances are updated correctly
+		assert_eq!(T::total_balance(&account_0), T::Balance::zero());
+		assert_eq!(T::total_balance(&account_1), initial_balance * 2.into());
+		assert_eq!(T::balance(&account_0), T::Balance::zero());
+		assert_eq!(T::balance(&account_1), initial_balance * 2.into());
+
+		// Verify: Total issuance doesn't change
+		assert_eq!(T::total_issuance(), initial_total_issuance + initial_balance * 2.into());
+		assert_eq!(T::active_issuance(), initial_active_issuance + initial_balance * 2.into());
+	}
+
+	/// Test calling [`Mutate::transfer`] function with [`Preservation::Expendable`] and an amount
+	/// that results in some dust.
+	///
+	/// This test verifies that dust is handled correctly when an account is reaped, with and
+	/// without a dust trap.
+	///
+	/// # Parameters
+	///
+	/// - dust_trap: An optional account identifier to which dust will be collected. If `None`, dust
+	///   is expected to be removed from the total and active issuance.
+	pub fn transfer_expendable_dust<T, AccountId>(dust_trap: Option<AccountId>)
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		if T::minimum_balance() == T::Balance::zero() {
+			return
+		}
+
+		let account_0 = AccountId::from(10);
+		let account_1 = AccountId::from(20);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::set_balance(&account_0, initial_balance);
+		T::set_balance(&account_1, initial_balance);
+
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let initial_dust_trap_balance = match dust_trap.clone() {
+			Some(dust_trap) => T::total_balance(&dust_trap),
+			None => T::Balance::zero(),
+		};
+
+		// Test: Transfer balance
+		let preservation = Preservation::Expendable;
+		let transfer_amount = T::Balance::from(11);
+		T::transfer(&account_0, &account_1, transfer_amount, preservation).unwrap();
+
+		// Verify: Account balances are updated correctly
+		assert_eq!(T::total_balance(&account_0), T::Balance::zero());
+		assert_eq!(T::total_balance(&account_1), initial_balance + transfer_amount);
+		assert_eq!(T::balance(&account_0), T::Balance::zero());
+		assert_eq!(T::balance(&account_1), initial_balance + transfer_amount);
+
+		match dust_trap {
+			Some(dust_trap) => {
+				// Verify: Total issuance and active issuance don't change
+				assert_eq!(T::total_issuance(), initial_total_issuance);
+				assert_eq!(T::active_issuance(), initial_active_issuance);
+				// Verify: Dust is collected into dust trap
+				assert_eq!(
+					T::total_balance(&dust_trap),
+					initial_dust_trap_balance + T::minimum_balance() - 1.into()
+				);
+				assert_eq!(
+					T::balance(&dust_trap),
+					initial_dust_trap_balance + T::minimum_balance() - 1.into()
+				);
+			},
+			None => {
+				// Verify: Total issuance and active issuance are reduced by the dust amount
+				assert_eq!(
+					T::total_issuance(),
+					initial_total_issuance - T::minimum_balance() + 1.into()
+				);
+				assert_eq!(
+					T::active_issuance(),
+					initial_active_issuance - T::minimum_balance() + 1.into()
+				);
+			},
+		}
+	}
+
+	/// Test [`Mutate::transfer`] with [`Preservation::Protect`] and [`Preservation::Preserve`]
+	/// transferring the entire balance.
+	///
+	/// This test verifies that attempting to transfer the entire balance with returns an error when
+	/// preservation should not allow it, and the account balances, total issuance, and active
+	/// issuance values remain unchanged.
+	pub fn transfer_protect_preserve<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// This test means nothing if there is no minimum balance
+		if T::minimum_balance() == T::Balance::zero() {
+			return
+		}
+
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account_0 = AccountId::from(0);
+		let account_1 = AccountId::from(1);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::set_balance(&account_0, initial_balance);
+		T::set_balance(&account_1, initial_balance);
+
+		// Verify: Transfer Protect entire balance from account_0 to account_1 should Err
+		let preservation = Preservation::Protect;
+		let transfer_amount = initial_balance;
+		T::transfer(&account_0, &account_1, transfer_amount, preservation).unwrap_err();
+
+		// Verify: Noop
+		assert_eq!(T::total_balance(&account_0), initial_balance);
+		assert_eq!(T::total_balance(&account_1), initial_balance);
+		assert_eq!(T::balance(&account_0), initial_balance);
+		assert_eq!(T::balance(&account_1), initial_balance);
+		assert_eq!(T::total_issuance(), initial_total_issuance + initial_balance * 2.into());
+		assert_eq!(T::active_issuance(), initial_active_issuance + initial_balance * 2.into());
+
+		// Verify: Transfer Preserve entire balance from account_0 to account_1 should Err
+		let preservation = Preservation::Preserve;
+		T::transfer(&account_0, &account_1, transfer_amount, preservation).unwrap_err();
+
+		// Verify: Noop
+		assert_eq!(T::total_balance(&account_0), initial_balance);
+		assert_eq!(T::total_balance(&account_1), initial_balance);
+		assert_eq!(T::balance(&account_0), initial_balance);
+		assert_eq!(T::balance(&account_1), initial_balance);
+		assert_eq!(T::total_issuance(), initial_total_issuance + initial_balance * 2.into());
+		assert_eq!(T::active_issuance(), initial_active_issuance + initial_balance * 2.into());
+	}
+
+	/// Test [`Mutate::set_balance`] mints balances correctly.
+	///
+	/// This test verifies that minting a balance using `set_balance` updates the account balance,
+	/// total issuance, and active issuance correctly.
+	pub fn set_balance_mint_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Test: Increase the account balance with set_balance
+		let increase_amount: T::Balance = 5.into();
+		let new = T::set_balance(&account, initial_balance + increase_amount);
+
+		// Verify: set_balance returned the new balance
+		let expected_new = initial_balance + increase_amount;
+		assert_eq!(new, expected_new);
+
+		// Verify: Balance and issuance is updated correctly
+		assert_eq!(T::total_balance(&account), expected_new);
+		assert_eq!(T::balance(&account), expected_new);
+		assert_eq!(T::total_issuance(), initial_total_issuance + expected_new);
+		assert_eq!(T::active_issuance(), initial_active_issuance + expected_new);
+	}
+
+	/// Test [`Mutate::set_balance`] burns balances correctly.
+	///
+	/// This test verifies that burning a balance using `set_balance` updates the account balance,
+	/// total issuance, and active issuance correctly.
+	pub fn set_balance_burn_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let initial_total_issuance = T::total_issuance();
+		let initial_active_issuance = T::active_issuance();
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Test: Increase the account balance with set_balance
+		let burn_amount: T::Balance = 5.into();
+		let new = T::set_balance(&account, initial_balance - burn_amount);
+
+		// Verify: set_balance returned the new balance
+		let expected_new = initial_balance - burn_amount;
+		assert_eq!(new, expected_new);
+
+		// Verify: Balance and issuance is updated correctly
+		assert_eq!(T::total_balance(&account), expected_new);
+		assert_eq!(T::balance(&account), expected_new);
+		assert_eq!(T::total_issuance(), initial_total_issuance + expected_new);
+		assert_eq!(T::active_issuance(), initial_active_issuance + expected_new);
+	}
+
+	/// Test [`Inspect::can_deposit`] works correctly returns [`DepositConsequence::Success`]
+	/// when depositing an amount that should succeed.
+	pub fn can_deposit_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Test: can_deposit a reasonable amount
+		let ret = T::can_deposit(&account, 5.into(), Provenance::Minted);
+
+		// Verify: Returns success
+		assert_eq!(ret, DepositConsequence::Success);
+	}
+
+	/// Test [`Inspect::can_deposit`] returns [`DepositConsequence::BelowMinimum`] when depositing
+	/// below the minimum balance.
+	pub fn can_deposit_below_minimum<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// can_deposit always returns Success for amount 0
+		if T::minimum_balance() < 2.into() {
+			return
+		}
+
+		let account = AccountId::from(10);
+
+		// Test: can_deposit below the minimum
+		let ret = T::can_deposit(&account, T::minimum_balance() - 1.into(), Provenance::Minted);
+
+		// Verify: Returns success
+		assert_eq!(ret, DepositConsequence::BelowMinimum);
+	}
+
+	/// Test [`Inspect::can_deposit`] returns [`DepositConsequence::Overflow`] when
+	/// depositing an amount that would overflow.
+	pub fn can_deposit_overflow<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(10);
+
+		// Test: Try deposit over the max balance
+		let initial_balance = T::Balance::max_value() - 5.into() - T::total_issuance();
+		T::mint_into(&account, initial_balance).unwrap();
+		let ret = T::can_deposit(&account, 10.into(), Provenance::Minted);
+
+		// Verify: Returns success
+		assert_eq!(ret, DepositConsequence::Overflow);
+	}
+
+	/// Test [`Inspect::can_withdraw`] returns [`WithdrawConsequence::Success`] when withdrawing an
+	/// amount that should succeed.
+	pub fn can_withdraw_success<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Test: can_withdraw a reasonable amount
+		let ret = T::can_withdraw(&account, 5.into());
+
+		// Verify: Returns success
+		assert_eq!(ret, WithdrawConsequence::Success);
+	}
+
+	/// Test [`Inspect::can_withdraw`] returns [`WithdrawConsequence::ReducedToZero`] when
+	/// withdrawing an amount that would reduce the account balance below the minimum balance.
+	pub fn can_withdraw_reduced_to_zero<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		if T::minimum_balance() == T::Balance::zero() {
+			return
+		}
+
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Verify: can_withdraw below the minimum balance returns ReducedToZero
+		let ret = T::can_withdraw(&account, 1.into());
+		assert_eq!(ret, WithdrawConsequence::ReducedToZero(T::minimum_balance() - 1.into()));
+	}
+
+	/// Test [`Inspect::can_withdraw`] returns [`WithdrawConsequence::BalanceLow`] when withdrawing
+	/// an amount that would result in an account balance below the current balance.
+	pub fn can_withdraw_balance_low<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		if T::minimum_balance() == T::Balance::zero() {
+			return
+		}
+
+		let account = AccountId::from(10);
+		let other_account = AccountId::from(100);
+		let initial_balance = T::minimum_balance() + 5.into();
+		T::mint_into(&account, initial_balance).unwrap();
+		T::mint_into(&other_account, initial_balance * 2.into()).unwrap();
+
+		// Verify: can_withdraw below the account balance returns BalanceLow
+		let ret = T::can_withdraw(&account, initial_balance + 1.into());
+		assert_eq!(ret, WithdrawConsequence::BalanceLow);
+	}
+
+	/// Test [`Inspect::reducible_balance`] returns the full account balance when called with
+	/// [`Preservation::Expendable`].
+	pub fn reducible_balance_expendable<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Verify: reducible_balance returns the full balance
+		let ret = T::reducible_balance(&account, Preservation::Expendable, Fortitude::Polite);
+		assert_eq!(ret, initial_balance);
+	}
+
+	/// Tests [`Inspect::reducible_balance`] returns [`Inspect::balance`] -
+	/// [`Inspect::minimum_balance`] when called with either [`Preservation::Protect`] or
+	/// [`Preservation::Preserve`].
+	pub fn reducible_balance_protect_preserve<T, AccountId>()
+	where
+		T: Mutate<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(10);
+		let initial_balance = T::minimum_balance() + 10.into();
+		T::mint_into(&account, initial_balance).unwrap();
+
+		// Verify: reducible_balance returns the full balance - min balance
+		let ret = T::reducible_balance(&account, Preservation::Protect, Fortitude::Polite);
+		assert_eq!(ret, initial_balance - T::minimum_balance());
+		let ret = T::reducible_balance(&account, Preservation::Preserve, Fortitude::Polite);
+		assert_eq!(ret, initial_balance - T::minimum_balance());
+	}
+}
+
+pub mod unbalanced {
+	use crate::traits::{
+		fungible::{Inspect, Unbalanced},
+		tokens::{Fortitude, Precision, Preservation},
+	};
+	use core::fmt::Debug;
+	use sp_arithmetic::{traits::AtLeast8BitUnsigned, ArithmeticError};
+	use sp_runtime::{traits::Bounded, TokenError};
+
+	/// Tests [`Unbalanced::write_balance`].
+	///
+	/// We don't need to test the Error case for this function, because the trait makes no
+	/// assumptions about the ways it can fail. That is completely an implementation detail.
+	pub fn write_balance<T, AccountId>()
+	where
+		T: Unbalanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Setup some accounts to test varying initial balances
+		let account_0_ed = AccountId::from(0);
+		let account_1_gt_ed = AccountId::from(1);
+		let account_2_empty = AccountId::from(2);
+		T::increase_balance(&account_0_ed, T::minimum_balance(), Precision::Exact).unwrap();
+		T::increase_balance(&account_1_gt_ed, T::minimum_balance() + 5.into(), Precision::Exact)
+			.unwrap();
+
+		// Test setting the balances of each account by gt the minimum balance succeeds with no
+		// dust.
+		let amount = T::minimum_balance() + 10.into();
+		assert_eq!(T::write_balance(&account_0_ed, amount), Ok(None));
+		assert_eq!(T::write_balance(&account_1_gt_ed, amount), Ok(None));
+		assert_eq!(T::write_balance(&account_2_empty, amount), Ok(None));
+		assert_eq!(T::balance(&account_0_ed), amount);
+		assert_eq!(T::balance(&account_1_gt_ed), amount);
+		assert_eq!(T::balance(&account_2_empty), amount);
+
+		// Test setting the balances of each account to below the minimum balance succeeds with
+		// the expected dust.
+		// If the minimum balance is 1, then the dust is 0, represented as None.
+		// If the minimum balance is >1, then the dust is the remaining balance that will be wiped
+		// as the account is reaped.
+		let amount = T::minimum_balance() - 1.into();
+		if T::minimum_balance() == 1.into() {
+			assert_eq!(T::write_balance(&account_0_ed, amount), Ok(None));
+			assert_eq!(T::write_balance(&account_1_gt_ed, amount), Ok(None));
+			assert_eq!(T::write_balance(&account_2_empty, amount), Ok(None));
+		} else if T::minimum_balance() > 1.into() {
+			assert_eq!(T::write_balance(&account_0_ed, amount), Ok(Some(amount)));
+			assert_eq!(T::write_balance(&account_1_gt_ed, amount), Ok(Some(amount)));
+			assert_eq!(T::write_balance(&account_2_empty, amount), Ok(Some(amount)));
+		}
+	}
+
+	/// Tests [`Unbalanced::decrease_balance`] called with [`Preservation::Expendable`].
+	pub fn decrease_balance_expendable<T, AccountId>()
+	where
+		T: Unbalanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Setup account with some balance
+		let account_0 = AccountId::from(0);
+		let account_0_initial_balance = T::minimum_balance() + 10.into();
+		T::increase_balance(&account_0, account_0_initial_balance, Precision::Exact).unwrap();
+
+		// Decreasing the balance still above the minimum balance should not reap the account.
+		let amount = 1.into();
+		assert_eq!(
+			T::decrease_balance(
+				&account_0,
+				amount,
+				Precision::Exact,
+				Preservation::Expendable,
+				Fortitude::Polite,
+			),
+			Ok(amount),
+		);
+		assert_eq!(T::balance(&account_0), account_0_initial_balance - amount);
+
+		// Decreasing the balance below funds avalibale should fail when Precision::Exact
+		let balance_before = T::balance(&account_0);
+		assert_eq!(
+			T::decrease_balance(
+				&account_0,
+				account_0_initial_balance,
+				Precision::Exact,
+				Preservation::Expendable,
+				Fortitude::Polite,
+			),
+			Err(TokenError::FundsUnavailable.into())
+		);
+		// Balance unchanged
+		assert_eq!(T::balance(&account_0), balance_before);
+
+		// And reap the account when Precision::BestEffort
+		assert_eq!(
+			T::decrease_balance(
+				&account_0,
+				account_0_initial_balance,
+				Precision::BestEffort,
+				Preservation::Expendable,
+				Fortitude::Polite,
+			),
+			Ok(balance_before),
+		);
+		// Account reaped
+		assert_eq!(T::balance(&account_0), 0.into());
+	}
+
+	/// Tests [`Unbalanced::decrease_balance`] called with [`Preservation::Preserve`].
+	pub fn decrease_balance_preserve<T, AccountId>()
+	where
+		T: Unbalanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Setup account with some balance
+		let account_0 = AccountId::from(0);
+		let account_0_initial_balance = T::minimum_balance() + 10.into();
+		T::increase_balance(&account_0, account_0_initial_balance, Precision::Exact).unwrap();
+
+		// Decreasing the balance below the minimum when Precision::Exact should fail.
+		let amount = 11.into();
+		assert_eq!(
+			T::decrease_balance(
+				&account_0,
+				amount,
+				Precision::Exact,
+				Preservation::Preserve,
+				Fortitude::Polite,
+			),
+			Err(TokenError::BelowMinimum.into()),
+		);
+		// Balance should not have changed.
+		assert_eq!(T::balance(&account_0), account_0_initial_balance);
+
+		// Decreasing the balance below the minimum when Precision::BestEffort should reduce to
+		// minimum balance.
+		let amount = 11.into();
+		assert_eq!(
+			T::decrease_balance(
+				&account_0,
+				amount,
+				Precision::BestEffort,
+				Preservation::Preserve,
+				Fortitude::Polite,
+			),
+			Ok(account_0_initial_balance - T::minimum_balance()),
+		);
+		assert_eq!(T::balance(&account_0), T::minimum_balance());
+	}
+
+	/// Tests [`Unbalanced::increase_balance`].
+	pub fn increase_balance<T, AccountId>()
+	where
+		T: Unbalanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account_0 = AccountId::from(0);
+		assert_eq!(T::balance(&account_0), 0.into());
+
+		// Increasing the bal below the ED errors when precision is Exact
+		if T::minimum_balance() > 0.into() {
+			assert_eq!(
+				T::increase_balance(&account_0, T::minimum_balance() - 1.into(), Precision::Exact),
+				Err(TokenError::BelowMinimum.into()),
+			);
+		}
+		assert_eq!(T::balance(&account_0), 0.into());
+
+		// Increasing the bal below the ED leaves the balance at zero when precision is BestEffort
+		if T::minimum_balance() > 0.into() {
+			assert_eq!(
+				T::increase_balance(
+					&account_0,
+					T::minimum_balance() - 1.into(),
+					Precision::BestEffort
+				),
+				Ok(0.into()),
+			);
+		}
+		assert_eq!(T::balance(&account_0), 0.into());
+
+		// Can increase if new bal is >= ED
+		assert_eq!(
+			T::increase_balance(&account_0, T::minimum_balance(), Precision::Exact),
+			Ok(T::minimum_balance()),
+		);
+		assert_eq!(T::balance(&account_0), T::minimum_balance());
+		assert_eq!(T::increase_balance(&account_0, 5.into(), Precision::Exact), Ok(5.into()),);
+		assert_eq!(T::balance(&account_0), T::minimum_balance() + 5.into());
+
+		// Increasing by amount that would overflow fails when precision is Exact
+		assert_eq!(
+			T::increase_balance(&account_0, T::Balance::max_value(), Precision::Exact),
+			Err(ArithmeticError::Overflow.into()),
+		);
+
+		// Increasing by amount that would overflow saturates when precision is BestEffort
+		let balance_before = T::balance(&account_0);
+		assert_eq!(
+			T::increase_balance(&account_0, T::Balance::max_value(), Precision::BestEffort),
+			Ok(T::Balance::max_value() - balance_before),
+		);
+		assert_eq!(T::balance(&account_0), T::Balance::max_value());
+	}
+
+	/// Tests [`Unbalanced::set_total_issuance`].
+	pub fn set_total_issuance<T, AccountId>()
+	where
+		T: Unbalanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		T::set_total_issuance(1.into());
+		assert_eq!(T::total_issuance(), 1.into());
+
+		T::set_total_issuance(0.into());
+		assert_eq!(T::total_issuance(), 0.into());
+
+		T::set_total_issuance(T::minimum_balance());
+		assert_eq!(T::total_issuance(), T::minimum_balance());
+
+		T::set_total_issuance(T::minimum_balance() + 5.into());
+		assert_eq!(T::total_issuance(), T::minimum_balance() + 5.into());
+
+		if T::minimum_balance() > 0.into() {
+			T::set_total_issuance(T::minimum_balance() - 1.into());
+			assert_eq!(T::total_issuance(), T::minimum_balance() - 1.into());
+		}
+	}
+
+	/// Tests [`Unbalanced::deactivate`] and [`Unbalanced::reactivate`].
+	pub fn deactivate_and_reactivate<T, AccountId>()
+	where
+		T: Unbalanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		T::set_total_issuance(10.into());
+		assert_eq!(T::total_issuance(), 10.into());
+		assert_eq!(T::active_issuance(), 10.into());
+
+		T::deactivate(2.into());
+		assert_eq!(T::total_issuance(), 10.into());
+		assert_eq!(T::active_issuance(), 8.into());
+
+		// Saturates at total_issuance
+		T::reactivate(4.into());
+		assert_eq!(T::total_issuance(), 10.into());
+		assert_eq!(T::active_issuance(), 10.into());
+
+		// Decrements correctly after saturating at total_issuance
+		T::deactivate(1.into());
+		assert_eq!(T::total_issuance(), 10.into());
+		assert_eq!(T::active_issuance(), 9.into());
+
+		// Saturates at zero
+		T::deactivate(15.into());
+		assert_eq!(T::total_issuance(), 10.into());
+		assert_eq!(T::active_issuance(), 0.into());
+
+		// Increments correctly after saturating at zero
+		T::reactivate(1.into());
+		assert_eq!(T::total_issuance(), 10.into());
+		assert_eq!(T::active_issuance(), 1.into());
+	}
+}
+
+pub mod balanced {
+	use crate::traits::{
+		fungible::{Balanced, Inspect},
+		tokens::{imbalance::Imbalance as ImbalanceT, Fortitude, Precision, Preservation},
+	};
+	use core::fmt::Debug;
+	use frame_support::traits::tokens::fungible::imbalance::{Credit, Debt};
+	use sp_arithmetic::{traits::AtLeast8BitUnsigned, ArithmeticError};
+	use sp_runtime::{traits::Bounded, TokenError};
+
+	/// Tests issuing and resolving [`Credit`] imbalances with [`Balanced::issue`] and
+	/// [`Balanced::resolve`].
+	pub fn issue_and_resolve_credit<T, AccountId>()
+	where
+		T: Balanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(0);
+		assert_eq!(T::total_issuance(), 0.into());
+		assert_eq!(T::balance(&account), 0.into());
+
+		// Account that doesn't exist yet can't be credited below the minimum balance
+		let credit: Credit<AccountId, T> = T::issue(T::minimum_balance() - 1.into());
+		// issue temporarily increases total issuance
+		assert_eq!(T::total_issuance(), credit.peek());
+		match T::resolve(&account, credit) {
+			Ok(_) => panic!("Balanced::resolve should have failed"),
+			Err(c) => assert_eq!(c.peek(), T::minimum_balance() - 1.into()),
+		};
+		// Credit was unused and dropped from total issuance
+		assert_eq!(T::total_issuance(), 0.into());
+		assert_eq!(T::balance(&account), 0.into());
+
+		// Credit account with minimum balance
+		let credit: Credit<AccountId, T> = T::issue(T::minimum_balance());
+		match T::resolve(&account, credit) {
+			Ok(()) => {},
+			Err(_) => panic!("resolve failed"),
+		};
+		assert_eq!(T::total_issuance(), T::minimum_balance());
+		assert_eq!(T::balance(&account), T::minimum_balance());
+
+		// Now that account has been created, it can be credited with an amount below the minimum
+		// balance.
+		let total_issuance_before = T::total_issuance();
+		let balance_before = T::balance(&account);
+		let amount = T::minimum_balance() - 1.into();
+		let credit: Credit<AccountId, T> = T::issue(amount);
+		match T::resolve(&account, credit) {
+			Ok(()) => {},
+			Err(_) => panic!("resolve failed"),
+		};
+		assert_eq!(T::total_issuance(), total_issuance_before + amount);
+		assert_eq!(T::balance(&account), balance_before + amount);
+
+		// Unhandled issuance is dropped from total issuance
+		// `let _ = ...` immediately drops the issuance, so everything should be unchanged when
+		// logic gets to the assertions.
+		let total_issuance_before = T::total_issuance();
+		let balance_before = T::balance(&account);
+		let _ = T::issue(5.into());
+		assert_eq!(T::total_issuance(), total_issuance_before);
+		assert_eq!(T::balance(&account), balance_before);
+	}
+
+	/// Tests issuing and resolving [`Debt`] imbalances with [`Balanced::rescind`] and
+	/// [`Balanced::settle`].
+	pub fn rescind_and_settle_debt<T, AccountId>()
+	where
+		T: Balanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Credit account with some balance
+		let account = AccountId::from(0);
+		let initial_bal = T::minimum_balance() + 10.into();
+		let credit = T::issue(initial_bal);
+		match T::resolve(&account, credit) {
+			Ok(()) => {},
+			Err(_) => panic!("resolve failed"),
+		};
+		assert_eq!(T::total_issuance(), initial_bal);
+		assert_eq!(T::balance(&account), initial_bal);
+
+		// Rescind some balance
+		let rescind_amount = 2.into();
+		let debt: Debt<AccountId, T> = T::rescind(rescind_amount);
+		assert_eq!(debt.peek(), rescind_amount);
+		match T::settle(&account, debt, Preservation::Expendable) {
+			Ok(c) => {
+				// We settled the full debt and account was not dusted, so there is no left over
+				// credit.
+				assert_eq!(c.peek(), 0.into());
+			},
+			Err(_) => panic!("settle failed"),
+		};
+		assert_eq!(T::total_issuance(), initial_bal - rescind_amount);
+		assert_eq!(T::balance(&account), initial_bal - rescind_amount);
+
+		// Unhandled debt is added from total issuance
+		// `let _ = ...` immediately drops the debt, so everything should be unchanged when
+		// logic gets to the assertions.
+		let _ = T::rescind(T::minimum_balance());
+		assert_eq!(T::total_issuance(), initial_bal - rescind_amount);
+		assert_eq!(T::balance(&account), initial_bal - rescind_amount);
+
+		// Preservation::Preserve will not allow the account to be dusted on settle
+		let balance_before = T::balance(&account);
+		let total_issuance_before = T::total_issuance();
+		let rescind_amount = balance_before - T::minimum_balance() + 1.into();
+		let debt: Debt<AccountId, T> = T::rescind(rescind_amount);
+		assert_eq!(debt.peek(), rescind_amount);
+		// The new debt is temporarily removed from total_issuance
+		assert_eq!(T::total_issuance(), total_issuance_before - debt.peek().into());
+		match T::settle(&account, debt, Preservation::Preserve) {
+			Ok(_) => panic!("Balanced::settle should have failed"),
+			Err(d) => assert_eq!(d.peek(), rescind_amount),
+		};
+		// The debt is added back to total_issuance because it was dropped, leaving the operation a
+		// noop.
+		assert_eq!(T::total_issuance(), total_issuance_before);
+		assert_eq!(T::balance(&account), balance_before);
+
+		// Preservation::Expendable allows the account to be dusted on settle
+		let debt: Debt<AccountId, T> = T::rescind(rescind_amount);
+		match T::settle(&account, debt, Preservation::Expendable) {
+			Ok(c) => {
+				// Dusting happens internally, there is no left over credit.
+				assert_eq!(c.peek(), 0.into());
+			},
+			Err(_) => panic!("settle failed"),
+		};
+		// The account is dusted and debt dropped from total_issuance
+		assert_eq!(T::total_issuance(), 0.into());
+		assert_eq!(T::balance(&account), 0.into());
+	}
+
+	/// Tests [`Balanced::deposit`].
+	pub fn deposit<T, AccountId>()
+	where
+		T: Balanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Cannot deposit < minimum balance into non-existent account
+		let account = AccountId::from(0);
+		let amount = T::minimum_balance() - 1.into();
+		match T::deposit(&account, amount, Precision::Exact) {
+			Ok(_) => panic!("Balanced::deposit should have failed"),
+			Err(e) => assert_eq!(e, TokenError::BelowMinimum.into()),
+		};
+		assert_eq!(T::total_issuance(), 0.into());
+		assert_eq!(T::balance(&account), 0.into());
+
+		// Can deposit minimum balance into non-existent account
+		let amount = T::minimum_balance();
+		match T::deposit(&account, amount, Precision::Exact) {
+			Ok(d) => assert_eq!(d.peek(), amount),
+			Err(_) => panic!("Balanced::deposit failed"),
+		};
+		assert_eq!(T::total_issuance(), amount);
+		assert_eq!(T::balance(&account), amount);
+
+		// Depositing amount that would overflow when Precision::Exact fails and is a noop
+		let amount = T::Balance::max_value();
+		let balance_before = T::balance(&account);
+		let total_issuance_before = T::total_issuance();
+		match T::deposit(&account, amount, Precision::Exact) {
+			Ok(_) => panic!("Balanced::deposit should have failed"),
+			Err(e) => assert_eq!(e, ArithmeticError::Overflow.into()),
+		};
+		assert_eq!(T::total_issuance(), total_issuance_before);
+		assert_eq!(T::balance(&account), balance_before);
+
+		// Depositing amount that would overflow when Precision::BestEffort saturates
+		match T::deposit(&account, amount, Precision::BestEffort) {
+			Ok(d) => assert_eq!(d.peek(), T::Balance::max_value() - balance_before),
+			Err(_) => panic!("Balanced::deposit failed"),
+		};
+		assert_eq!(T::total_issuance(), T::Balance::max_value());
+		assert_eq!(T::balance(&account), T::Balance::max_value());
+	}
+
+	/// Tests [`Balanced::withdraw`].
+	pub fn withdraw<T, AccountId>()
+	where
+		T: Balanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		let account = AccountId::from(0);
+
+		// Init an account with some balance
+		let initial_balance = T::minimum_balance() + 10.into();
+		match T::deposit(&account, initial_balance, Precision::Exact) {
+			Ok(_) => {},
+			Err(_) => panic!("Balanced::deposit failed"),
+		};
+		assert_eq!(T::total_issuance(), initial_balance);
+		assert_eq!(T::balance(&account), initial_balance);
+
+		// Withdrawing an amount smaller than the balance works when Precision::Exact
+		let amount = 1.into();
+		match T::withdraw(
+			&account,
+			amount,
+			Precision::Exact,
+			Preservation::Expendable,
+			Fortitude::Polite,
+		) {
+			Ok(c) => assert_eq!(c.peek(), amount),
+			Err(_) => panic!("withdraw failed"),
+		};
+		assert_eq!(T::total_issuance(), initial_balance - amount);
+		assert_eq!(T::balance(&account), initial_balance - amount);
+
+		// Withdrawing an amount greater than the balance fails when Precision::Exact
+		let balance_before = T::balance(&account);
+		let amount = balance_before + 1.into();
+		match T::withdraw(
+			&account,
+			amount,
+			Precision::Exact,
+			Preservation::Expendable,
+			Fortitude::Polite,
+		) {
+			Ok(_) => panic!("should have failed"),
+			Err(e) => assert_eq!(e, TokenError::FundsUnavailable.into()),
+		};
+		assert_eq!(T::total_issuance(), balance_before);
+		assert_eq!(T::balance(&account), balance_before);
+
+		// Withdrawing an amount greater than the balance works when Precision::BestEffort
+		let balance_before = T::balance(&account);
+		let amount = balance_before + 1.into();
+		match T::withdraw(
+			&account,
+			amount,
+			Precision::BestEffort,
+			Preservation::Expendable,
+			Fortitude::Polite,
+		) {
+			Ok(c) => assert_eq!(c.peek(), balance_before),
+			Err(_) => panic!("withdraw failed"),
+		};
+		assert_eq!(T::total_issuance(), 0.into());
+		assert_eq!(T::balance(&account), 0.into());
+	}
+
+	/// Tests [`Balanced::pair`].
+	pub fn pair<T, AccountId>()
+	where
+		T: Balanced<AccountId>,
+		<T as Inspect<AccountId>>::Balance: AtLeast8BitUnsigned + Debug,
+		AccountId: AtLeast8BitUnsigned,
+	{
+		// Pair zero balance works
+		let (credit, debt) = T::pair(0.into());
+		assert_eq!(debt.peek(), 0.into());
+		assert_eq!(credit.peek(), 0.into());
+
+		// Pair with non-zero balance: the credit and debt cancel each other out
+		let balance = 10.into();
+		let (credit, debt) = T::pair(balance);
+		assert_eq!(credit.peek(), balance);
+		assert_eq!(debt.peek(), balance);
+
+		// Pair with max balance: the credit and debt still cancel each other out
+		let balance = T::Balance::max_value() - 1.into();
+		let (debt, credit) = T::pair(balance);
+		assert_eq!(debt.peek(), balance);
+		assert_eq!(credit.peek(), balance);
+	}
+}
diff --git a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs
index cf2d96ef287..b0b8bbcf7be 100644
--- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs
+++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs
@@ -386,7 +386,7 @@ impl<
 	fn issue(amount: Self::Balance) -> Credit<AccountId, Self> {
 		Imbalance::new(<F as fungibles::Balanced<AccountId>>::issue(A::get(), amount).peek())
 	}
-	fn pair(amount: Self::Balance) -> (Debt<AccountId, Self>, Credit<AccountId, Self>) {
+	fn pair(amount: Self::Balance) -> (Credit<AccountId, Self>, Debt<AccountId, Self>) {
 		let (a, b) = <F as fungibles::Balanced<AccountId>>::pair(A::get(), amount);
 		(Imbalance::new(a.peek()), Imbalance::new(b.peek()))
 	}
diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs
index 2838bed540a..1b3e971de46 100644
--- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs
+++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs
@@ -65,7 +65,7 @@ pub trait Inspect<AccountId>: Sized {
 	/// indefinitely.
 	///
 	/// For the amount of the balance which is currently free to be removed from the account without
-	/// error, use `reducible_balance`.
+	/// error, use [`Inspect::reducible_balance`].
 	///
 	/// For the amount of the balance which may eventually be free to be removed from the account,
 	/// use `balance()`.
@@ -75,7 +75,7 @@ pub trait Inspect<AccountId>: Sized {
 	/// subsystems of the chain ("on hold" or "reserved").
 	///
 	/// In general this isn't especially useful outside of tests, and for practical purposes, you'll
-	/// want to use `reducible_balance()`.
+	/// want to use [`Inspect::reducible_balance`].
 	fn balance(who: &AccountId) -> Self::Balance;
 
 	/// Get the maximum amount that `who` can withdraw/transfer successfully based on whether the
@@ -83,7 +83,7 @@ pub trait Inspect<AccountId>: Sized {
 	/// reduction and potentially go below user-level restrictions on the minimum amount of the
 	/// account.
 	///
-	/// Always less than or equal to `balance()`.
+	/// Always less than or equal to [`Inspect::balance`].
 	fn reducible_balance(
 		who: &AccountId,
 		preservation: Preservation,
@@ -107,7 +107,7 @@ pub trait Inspect<AccountId>: Sized {
 	fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence<Self::Balance>;
 }
 
-/// Special dust type which can be type-safely converted into a `Credit`.
+/// Special dust type which can be type-safely converted into a [`Credit`].
 #[must_use]
 pub struct Dust<A, T: Inspect<A>>(pub T::Balance);
 
@@ -124,20 +124,20 @@ impl<A, T: Balanced<A>> Dust<A, T> {
 /// Do not use this directly unless you want trouble, since it allows you to alter account balances
 /// without keeping the issuance up to date. It has no safeguards against accidentally creating
 /// token imbalances in your system leading to accidental inflation or deflation. It's really just
-/// for the underlying datatype to implement so the user gets the much safer `Balanced` trait to
+/// for the underlying datatype to implement so the user gets the much safer [`Balanced`] trait to
 /// use.
 pub trait Unbalanced<AccountId>: Inspect<AccountId> {
-	/// Create some dust and handle it with `Self::handle_dust`. This is an unbalanced operation
-	/// and it must only be used when an account is modified in a raw fashion, outside of the entire
-	/// fungibles API. The `amount` is capped at `Self::minimum_balance() - 1`.
+	/// Create some dust and handle it with [`Unbalanced::handle_dust`]. This is an unbalanced
+	/// operation and it must only be used when an account is modified in a raw fashion, outside of
+	/// the entire fungibles API. The `amount` is capped at [`Inspect::minimum_balance()`] - 1`.
 	///
 	/// This should not be reimplemented.
 	fn handle_raw_dust(amount: Self::Balance) {
 		Self::handle_dust(Dust(amount.min(Self::minimum_balance().saturating_sub(One::one()))))
 	}
 
-	/// Do something with the dust which has been destroyed from the system. `Dust` can be converted
-	/// into a `Credit` with the `Balanced` trait impl.
+	/// Do something with the dust which has been destroyed from the system. [`Dust`] can be
+	/// converted into a [`Credit`] with the [`Balanced`] trait impl.
 	fn handle_dust(dust: Dust<AccountId, Self>);
 
 	/// Forcefully set the balance of `who` to `amount`.
@@ -152,9 +152,10 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
 	/// If this cannot be done for some reason (e.g. because the account cannot be created, deleted
 	/// or would overflow) then an `Err` is returned.
 	///
-	/// If `Ok` is returned then its inner, if `Some` is the amount which was discarded as dust due
-	/// to existential deposit requirements. The default implementation of `decrease_balance` and
-	/// `increase_balance` converts this into an `Imbalance` and then passes it into `handle_dust`.
+	/// If `Ok` is returned then its inner, then `Some` is the amount which was discarded as dust
+	/// due to existential deposit requirements. The default implementation of
+	/// [`Unbalanced::decrease_balance`] and [`Unbalanced::increase_balance`] converts this into an
+	/// [`Imbalance`] and then passes it into [`Unbalanced::handle_dust`].
 	fn write_balance(
 		who: &AccountId,
 		amount: Self::Balance,
@@ -165,14 +166,14 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
 
 	/// Reduce the balance of `who` by `amount`.
 	///
-	/// If `precision` is `Exact` and it cannot be reduced by that amount for
-	/// some reason, return `Err` and don't reduce it at all. If `precision` is `BestEffort`, then
+	/// If `precision` is [`Exact`] and it cannot be reduced by that amount for
+	/// some reason, return `Err` and don't reduce it at all. If `precision` is [`BestEffort`], then
 	/// reduce the balance of `who` by the most that is possible, up to `amount`.
 	///
 	/// In either case, if `Ok` is returned then the inner is the amount by which is was reduced.
 	/// Minimum balance will be respected and thus the returned amount may be up to
-	/// `Self::minimum_balance() - 1` greater than `amount` in the case that the reduction caused
-	/// the account to be deleted.
+	/// [`Inspect::minimum_balance()`] - 1` greater than `amount` in the case that the reduction
+	/// caused the account to be deleted.
 	fn decrease_balance(
 		who: &AccountId,
 		mut amount: Self::Balance,
@@ -182,9 +183,14 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
 	) -> Result<Self::Balance, DispatchError> {
 		let old_balance = Self::balance(who);
 		let free = Self::reducible_balance(who, preservation, force);
-		if let BestEffort = precision {
+		if precision == BestEffort {
 			amount = amount.min(free);
 		}
+
+		// Under no circumsances should the account go below free when preservation is Preserve.
+		if amount > free && preservation == Preservation::Preserve {
+			return Err(TokenError::BelowMinimum.into())
+		}
 		let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
 		if let Some(dust) = Self::write_balance(who, new_balance)? {
 			Self::handle_dust(Dust(dust));
@@ -197,7 +203,7 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
 	/// If it cannot be increased by that amount for some reason, return `Err` and don't increase
 	/// it at all. If Ok, return the imbalance.
 	/// Minimum balance will be respected and an error will be returned if
-	/// `amount < Self::minimum_balance()` when the account of `who` is zero.
+	/// amount < [`Inspect::minimum_balance()`] when the account of `who` is zero.
 	fn increase_balance(
 		who: &AccountId,
 		amount: Self::Balance,
@@ -267,8 +273,8 @@ pub trait Mutate<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 
 	/// Attempt to decrease the `asset` balance of `who` by `amount`.
 	///
-	/// Equivalent to `burn_from`, except with an expectation that within the bounds of some
-	/// universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The
+	/// Equivalent to [`Mutate::burn_from`], except with an expectation that within the bounds of
+	/// some universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The
 	/// implementation may be configured such that the total assets suspended may never be less than
 	/// the total assets resumed (which is the invariant for an issuing system), or the reverse
 	/// (which the invariant in a non-issuing system).
@@ -287,8 +293,8 @@ pub trait Mutate<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 
 	/// Attempt to increase the `asset` balance of `who` by `amount`.
 	///
-	/// Equivalent to `mint_into`, except with an expectation that within the bounds of some
-	/// universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The
+	/// Equivalent to [`Mutate::mint_into`], except with an expectation that within the bounds of
+	/// some universal issuance, the total assets `suspend`ed and `resume`d will be equivalent. The
 	/// implementation may be configured such that the total assets suspended may never be less than
 	/// the total assets resumed (which is the invariant for an issuing system), or the reverse
 	/// (which the invariant in a non-issuing system).
@@ -367,7 +373,7 @@ impl<AccountId, U: Unbalanced<AccountId>> HandleImbalanceDrop<U::Balance>
 /// A fungible token class where any creation and deletion of tokens is semi-explicit and where the
 /// total supply is maintained automatically.
 ///
-/// This is auto-implemented when a token class has `Unbalanced` implemented.
+/// This is auto-implemented when a token class has [`Unbalanced`] implemented.
 pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 	/// The type for managing what happens when an instance of `Debt` is dropped without being used.
 	type OnDropDebt: HandleImbalanceDrop<Self::Balance>;
@@ -376,7 +382,7 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 	type OnDropCredit: HandleImbalanceDrop<Self::Balance>;
 
 	/// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will
-	/// typically be used to reduce an account by the same amount with e.g. `settle`.
+	/// typically be used to reduce an account by the same amount with e.g. [`Balanced::settle`].
 	///
 	/// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example
 	/// in the case of underflow.
@@ -391,7 +397,7 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 
 	/// Increase the total issuance by `amount` and return the according imbalance. The imbalance
 	/// will typically be used to increase an account by the same amount with e.g.
-	/// `resolve_into_existing` or `resolve_creating`.
+	/// [`Balanced::resolve`].
 	///
 	/// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example
 	/// in the case of overflow.
@@ -408,18 +414,18 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 	///
 	/// This is just the same as burning and issuing the same amount and has no effect on the
 	/// total issuance.
-	fn pair(amount: Self::Balance) -> (Debt<AccountId, Self>, Credit<AccountId, Self>) {
-		(Self::rescind(amount), Self::issue(amount))
+	fn pair(amount: Self::Balance) -> (Credit<AccountId, Self>, Debt<AccountId, Self>) {
+		(Self::issue(amount), Self::rescind(amount))
 	}
 
 	/// Mints `value` into the account of `who`, creating it as needed.
 	///
 	/// If `precision` is `BestEffort` and `value` in full could not be minted (e.g. due to
-	/// overflow), then the maximum is minted, up to `value`. If `precision` is `Exact`, then
+	/// overflow), then the maximum is minted, up to `value`. If `precision` is [`Exact`], then
 	/// exactly `value` must be minted into the account of `who` or the operation will fail with an
 	/// `Err` and nothing will change.
 	///
-	/// If the operation is successful, this will return `Ok` with a `Debt` of the total value
+	/// If the operation is successful, this will return `Ok` with a [`Debt`] of the total value
 	/// added to the account.
 	fn deposit(
 		who: &AccountId,
@@ -433,8 +439,8 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 
 	/// Removes `value` balance from `who` account if possible.
 	///
-	/// If `precision` is `BestEffort` and `value` in full could not be removed (e.g. due to
-	/// underflow), then the maximum is removed, up to `value`. If `precision` is `Exact`, then
+	/// If `precision` is [`BestEffort`] and `value` in full could not be removed (e.g. due to
+	/// underflow), then the maximum is removed, up to `value`. If `precision` is [`Exact`], then
 	/// exactly `value` must be removed from the account of `who` or the operation will fail with an
 	/// `Err` and nothing will change.
 	///
@@ -442,7 +448,7 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 	/// If the account needed to be deleted, then slightly more than `value` may be removed from the
 	/// account owning since up to (but not including) minimum balance may also need to be removed.
 	///
-	/// If the operation is successful, this will return `Ok` with a `Credit` of the total value
+	/// If the operation is successful, this will return `Ok` with a [`Credit`] of the total value
 	/// removed from the account.
 	fn withdraw(
 		who: &AccountId,
@@ -460,7 +466,7 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 	/// cannot be countered, then nothing is changed and the original `credit` is returned in an
 	/// `Err`.
 	///
-	/// Please note: If `credit.peek()` is less than `Self::minimum_balance()`, then `who` must
+	/// Please note: If `credit.peek()` is less than [`Inspect::minimum_balance()`], then `who` must
 	/// already exist for this to succeed.
 	fn resolve(
 		who: &AccountId,
@@ -487,7 +493,7 @@ pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
 		let amount = debt.peek();
 		let credit = match Self::withdraw(who, amount, Exact, preservation, Polite) {
 			Err(_) => return Err(debt),
-			Ok(d) => d,
+			Ok(c) => c,
 		};
 
 		match credit.offset(debt) {
-- 
GitLab