diff --git a/substrate/frame/assets/src/benchmarking.rs b/substrate/frame/assets/src/benchmarking.rs
index 047ede2ce69641de4c2f8bec1936d344abae13f1..a2483650715a2589212709defc92edc43df54bbf 100644
--- a/substrate/frame/assets/src/benchmarking.rs
+++ b/substrate/frame/assets/src/benchmarking.rs
@@ -482,5 +482,74 @@ benchmarks_instance_pallet! {
 		assert_last_event::<T, I>(Event::AssetMinBalanceChanged { asset_id: asset_id.into(), new_min_balance: 50u32.into() }.into());
 	}
 
+	touch {
+		let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::<T, I>(false);
+		let new_account: T::AccountId = account("newaccount", 1, SEED);
+		T::Currency::make_free_balance_be(&new_account, DepositBalanceOf::<T, I>::max_value());
+		assert_ne!(asset_owner, new_account);
+		assert!(!Account::<T, I>::contains_key(asset_id.into(), &new_account));
+	}: _(SystemOrigin::Signed(new_account.clone()), asset_id)
+	verify {
+		assert!(Account::<T, I>::contains_key(asset_id.into(), &new_account));
+	}
+
+	touch_other {
+		let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::<T, I>(false);
+		let new_account: T::AccountId = account("newaccount", 1, SEED);
+		let new_account_lookup = T::Lookup::unlookup(new_account.clone());
+		T::Currency::make_free_balance_be(&asset_owner, DepositBalanceOf::<T, I>::max_value());
+		assert_ne!(asset_owner, new_account);
+		assert!(!Account::<T, I>::contains_key(asset_id.into(), &new_account));
+	}: _(SystemOrigin::Signed(asset_owner.clone()), asset_id, new_account_lookup)
+	verify {
+		assert!(Account::<T, I>::contains_key(asset_id.into(), &new_account));
+	}
+
+	refund {
+		let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::<T, I>(false);
+		let new_account: T::AccountId = account("newaccount", 1, SEED);
+		T::Currency::make_free_balance_be(&new_account, DepositBalanceOf::<T, I>::max_value());
+		assert_ne!(asset_owner, new_account);
+		assert!(Assets::<T, I>::touch(
+			SystemOrigin::Signed(new_account.clone()).into(),
+			asset_id
+		).is_ok());
+		// `touch` should reserve some balance of the caller...
+		assert!(!T::Currency::reserved_balance(&new_account).is_zero());
+		// ...and also create an `Account` entry.
+		assert!(Account::<T, I>::contains_key(asset_id.into(), &new_account));
+	}: _(SystemOrigin::Signed(new_account.clone()), asset_id, true)
+	verify {
+		// `refund`ing should of course repatriate the reserve
+		assert!(T::Currency::reserved_balance(&new_account).is_zero());
+	}
+
+	refund_other {
+		let (asset_id, asset_owner, asset_owner_lookup) = create_default_asset::<T, I>(false);
+		let new_account: T::AccountId = account("newaccount", 1, SEED);
+		let new_account_lookup = T::Lookup::unlookup(new_account.clone());
+		T::Currency::make_free_balance_be(&asset_owner, DepositBalanceOf::<T, I>::max_value());
+		assert_ne!(asset_owner, new_account);
+		assert!(Assets::<T, I>::touch_other(
+			SystemOrigin::Signed(asset_owner.clone()).into(),
+			asset_id,
+			new_account_lookup.clone()
+		).is_ok());
+		// `touch_other` should reserve balance of the freezer
+		assert!(!T::Currency::reserved_balance(&asset_owner).is_zero());
+		assert!(Account::<T, I>::contains_key(asset_id.into(), &new_account));
+	}: _(SystemOrigin::Signed(asset_owner.clone()), asset_id, new_account_lookup.clone())
+	verify {
+		// this should repatriate the reserved balance of the freezer
+		assert!(T::Currency::reserved_balance(&asset_owner).is_zero());
+	}
+
+	block {
+		let (asset_id, caller, caller_lookup) = create_default_minted_asset::<T, I>(true, 100u32.into());
+	}: _(SystemOrigin::Signed(caller.clone()), asset_id, caller_lookup)
+	verify {
+		assert_last_event::<T, I>(Event::Blocked { asset_id: asset_id.into(), who: caller }.into());
+	}
+
 	impl_benchmark_test_suite!(Assets, crate::mock::new_test_ext(), crate::mock::Test)
 }
diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs
index 1e10e0066e85195edf23922d5ddad6f5957ee8c9..d7c5bbe95e9fecd5c4c4f71833ba2f5afc8e449e 100644
--- a/substrate/frame/assets/src/functions.rs
+++ b/substrate/frame/assets/src/functions.rs
@@ -66,11 +66,15 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	pub(super) fn new_account(
 		who: &T::AccountId,
 		d: &mut AssetDetails<T::Balance, T::AccountId, DepositBalanceOf<T, I>>,
-		maybe_deposit: Option<DepositBalanceOf<T, I>>,
-	) -> Result<ExistenceReason<DepositBalanceOf<T, I>>, DispatchError> {
+		maybe_deposit: Option<(&T::AccountId, DepositBalanceOf<T, I>)>,
+	) -> Result<ExistenceReasonOf<T, I>, DispatchError> {
 		let accounts = d.accounts.checked_add(1).ok_or(ArithmeticError::Overflow)?;
-		let reason = if let Some(deposit) = maybe_deposit {
-			ExistenceReason::DepositHeld(deposit)
+		let reason = if let Some((depositor, deposit)) = maybe_deposit {
+			if depositor == who {
+				ExistenceReason::DepositHeld(deposit)
+			} else {
+				ExistenceReason::DepositFrom(depositor.clone(), deposit)
+			}
 		} else if d.is_sufficient {
 			frame_system::Pallet::<T>::inc_sufficients(who);
 			d.sufficients += 1;
@@ -93,18 +97,19 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	pub(super) fn dead_account(
 		who: &T::AccountId,
 		d: &mut AssetDetails<T::Balance, T::AccountId, DepositBalanceOf<T, I>>,
-		reason: &ExistenceReason<DepositBalanceOf<T, I>>,
+		reason: &ExistenceReasonOf<T, I>,
 		force: bool,
 	) -> DeadConsequence {
+		use ExistenceReason::*;
 		match *reason {
-			ExistenceReason::Consumer => frame_system::Pallet::<T>::dec_consumers(who),
-			ExistenceReason::Sufficient => {
+			Consumer => frame_system::Pallet::<T>::dec_consumers(who),
+			Sufficient => {
 				d.sufficients = d.sufficients.saturating_sub(1);
 				frame_system::Pallet::<T>::dec_sufficients(who);
 			},
-			ExistenceReason::DepositRefunded => {},
-			ExistenceReason::DepositHeld(_) if !force => return Keep,
-			ExistenceReason::DepositHeld(_) => {},
+			DepositRefunded => {},
+			DepositHeld(_) | DepositFrom(..) if !force => return Keep,
+			DepositHeld(_) | DepositFrom(..) => {},
 		}
 		d.accounts = d.accounts.saturating_sub(1);
 		Remove
@@ -130,8 +135,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		if increase_supply && details.supply.checked_add(&amount).is_none() {
 			return DepositConsequence::Overflow
 		}
-		if let Some(balance) = Self::maybe_balance(id, who) {
-			if balance.checked_add(&amount).is_none() {
+		if let Some(account) = Account::<T, I>::get(id, who) {
+			if account.status.is_blocked() {
+				return DepositConsequence::Blocked
+			}
+			if account.balance.checked_add(&amount).is_none() {
 				return DepositConsequence::Overflow
 			}
 		} else {
@@ -174,7 +182,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 			Some(a) => a,
 			None => return BalanceLow,
 		};
-		if account.is_frozen {
+		if account.status.is_frozen() {
 			return Frozen
 		}
 		if let Some(rest) = account.balance.checked_sub(&amount) {
@@ -215,7 +223,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
 
 		let account = Account::<T, I>::get(id, who).ok_or(Error::<T, I>::NoAccount)?;
-		ensure!(!account.is_frozen, Error::<T, I>::Frozen);
+		ensure!(!account.status.is_frozen(), Error::<T, I>::Frozen);
 
 		let amount = if let Some(frozen) = T::Freezer::frozen_balance(id, who) {
 			// Frozen balance: account CANNOT be deleted
@@ -302,43 +310,63 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		Ok((credit, maybe_burn))
 	}
 
-	/// Creates a account for `who` to hold asset `id` with a zero balance and takes a deposit.
-	pub(super) fn do_touch(id: T::AssetId, who: T::AccountId) -> DispatchResult {
+	/// Creates an account for `who` to hold asset `id` with a zero balance and takes a deposit.
+	///
+	/// When `check_depositor` is set to true, the depositor must be either the asset's Admin or
+	/// Freezer, otherwise the depositor can be any account.
+	pub(super) fn do_touch(
+		id: T::AssetId,
+		who: T::AccountId,
+		depositor: T::AccountId,
+		check_depositor: bool,
+	) -> DispatchResult {
 		ensure!(!Account::<T, I>::contains_key(id, &who), Error::<T, I>::AlreadyExists);
 		let deposit = T::AssetAccountDeposit::get();
 		let mut details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
 		ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
-		let reason = Self::new_account(&who, &mut details, Some(deposit))?;
-		T::Currency::reserve(&who, deposit)?;
+		ensure!(
+			!check_depositor || &depositor == &details.admin || &depositor == &details.freezer,
+			Error::<T, I>::NoPermission
+		);
+		let reason = Self::new_account(&who, &mut details, Some((&depositor, deposit)))?;
+		T::Currency::reserve(&depositor, deposit)?;
 		Asset::<T, I>::insert(&id, details);
 		Account::<T, I>::insert(
 			id,
 			&who,
 			AssetAccountOf::<T, I> {
 				balance: Zero::zero(),
-				is_frozen: false,
+				status: AccountStatus::Liquid,
 				reason,
 				extra: T::Extra::default(),
 			},
 		);
+		Self::deposit_event(Event::Touched { asset_id: id, who, depositor });
 		Ok(())
 	}
 
-	/// Returns a deposit, destroying an asset-account.
+	/// Returns a deposit or a consumer reference, destroying an asset-account.
+	/// Non-zero balance accounts refunded and destroyed only if `allow_burn` is true.
 	pub(super) fn do_refund(id: T::AssetId, who: T::AccountId, allow_burn: bool) -> DispatchResult {
+		use AssetStatus::*;
+		use ExistenceReason::*;
 		let mut account = Account::<T, I>::get(id, &who).ok_or(Error::<T, I>::NoDeposit)?;
-		let deposit = account.reason.take_deposit().ok_or(Error::<T, I>::NoDeposit)?;
+		ensure!(matches!(account.reason, Consumer | DepositHeld(..)), Error::<T, I>::NoDeposit);
 		let mut details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
-		ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
+		ensure!(matches!(details.status, Live | Frozen), Error::<T, I>::IncorrectStatus);
 		ensure!(account.balance.is_zero() || allow_burn, Error::<T, I>::WouldBurn);
-		ensure!(!account.is_frozen, Error::<T, I>::Frozen);
 
-		T::Currency::unreserve(&who, deposit);
+		if let Some(deposit) = account.reason.take_deposit() {
+			T::Currency::unreserve(&who, deposit);
+		}
 
 		if let Remove = Self::dead_account(&who, &mut details, &account.reason, false) {
 			Account::<T, I>::remove(id, &who);
 		} else {
 			debug_assert!(false, "refund did not result in dead account?!");
+			// deposit may have been refunded, need to update `Account`
+			Account::<T, I>::insert(id, &who, account);
+			return Ok(())
 		}
 		Asset::<T, I>::insert(&id, details);
 		// Executing a hook here is safe, since it is not in a `mutate`.
@@ -346,6 +374,37 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		Ok(())
 	}
 
+	/// Returns a `DepositFrom` of an account only if balance is zero.
+	pub(super) fn do_refund_other(
+		id: T::AssetId,
+		who: &T::AccountId,
+		caller: &T::AccountId,
+	) -> DispatchResult {
+		let mut account = Account::<T, I>::get(id, &who).ok_or(Error::<T, I>::NoDeposit)?;
+		let (depositor, deposit) =
+			account.reason.take_deposit_from().ok_or(Error::<T, I>::NoDeposit)?;
+		let mut details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
+		ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
+		ensure!(!account.status.is_frozen(), Error::<T, I>::Frozen);
+		ensure!(caller == &depositor || caller == &details.admin, Error::<T, I>::NoPermission);
+		ensure!(account.balance.is_zero(), Error::<T, I>::WouldBurn);
+
+		T::Currency::unreserve(&depositor, deposit);
+
+		if let Remove = Self::dead_account(&who, &mut details, &account.reason, false) {
+			Account::<T, I>::remove(id, &who);
+		} else {
+			debug_assert!(false, "refund did not result in dead account?!");
+			// deposit may have been refunded, need to update `Account`
+			Account::<T, I>::insert(id, &who, account);
+			return Ok(())
+		}
+		Asset::<T, I>::insert(&id, details);
+		// Executing a hook here is safe, since it is not in a `mutate`.
+		T::Freezer::died(id, &who);
+		return Ok(())
+	}
+
 	/// Increases the asset `id` balance of `beneficiary` by `amount`.
 	///
 	/// This alters the registered supply of the asset and emits an event.
@@ -408,7 +467,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 						*maybe_account = Some(AssetAccountOf::<T, I> {
 							balance: amount,
 							reason: Self::new_account(beneficiary, details, None)?,
-							is_frozen: false,
+							status: AccountStatus::Liquid,
 							extra: T::Extra::default(),
 						});
 					},
@@ -602,7 +661,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 					maybe_account @ None => {
 						*maybe_account = Some(AssetAccountOf::<T, I> {
 							balance: credit,
-							is_frozen: false,
+							status: AccountStatus::Liquid,
 							reason: Self::new_account(dest, details, None)?,
 							extra: T::Extra::default(),
 						});
diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs
index d32b407e67f6e78f804ba03a2e20157b634e65c1..e6b59bba53836e2fafc248df894c4b82af386141 100644
--- a/substrate/frame/assets/src/lib.rs
+++ b/substrate/frame/assets/src/lib.rs
@@ -82,6 +82,10 @@
 //! * `approve_transfer`: Create or increase an delegated transfer.
 //! * `cancel_approval`: Rescind a previous approval.
 //! * `transfer_approved`: Transfer third-party's assets to another account.
+//! * `touch`: Create an asset account for non-provider assets. Caller must place a deposit.
+//! * `refund`: Return the deposit (if any) of the caller's asset account or a consumer reference
+//!   (if any) of the caller's account.
+//! * `refund_other`: Return the deposit (if any) of a specified asset account.
 //!
 //! ### Permissioned Functions
 //!
@@ -98,12 +102,16 @@
 //! * `burn`: Decreases the asset balance of an account; called by the asset class's Admin.
 //! * `force_transfer`: Transfers between arbitrary accounts; called by the asset class's Admin.
 //! * `freeze`: Disallows further `transfer`s from an account; called by the asset class's Freezer.
-//! * `thaw`: Allows further `transfer`s from an account; called by the asset class's Admin.
+//! * `thaw`: Allows further `transfer`s to and from an account; called by the asset class's Admin.
 //! * `transfer_ownership`: Changes an asset class's Owner; called by the asset class's Owner.
 //! * `set_team`: Changes an asset class's Admin, Freezer and Issuer; called by the asset class's
 //!   Owner.
 //! * `set_metadata`: Set the metadata of an asset class; called by the asset class's Owner.
 //! * `clear_metadata`: Remove the metadata of an asset class; called by the asset class's Owner.
+//! * `touch_other`: Create an asset account for specified account. Caller must place a deposit;
+//!   called by the asset class's Freezer or Admin.
+//! * `block`: Disallows further `transfer`s to and from an account; called by the asset class's
+//!   Freezer.
 //!
 //! Please refer to the [`Call`] enum and its associated variants for documentation on each
 //! function.
@@ -194,7 +202,7 @@ impl<AssetId, AccountId> AssetsCallback<AssetId, AccountId> for () {}
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use frame_support::pallet_prelude::*;
+	use frame_support::{pallet_prelude::*, traits::AccountTouch};
 	use frame_system::pallet_prelude::*;
 
 	/// The current storage version.
@@ -519,6 +527,10 @@ pub mod pallet {
 		AssetStatusChanged { asset_id: T::AssetId },
 		/// The min_balance of an asset has been updated by the asset owner.
 		AssetMinBalanceChanged { asset_id: T::AssetId, new_min_balance: T::Balance },
+		/// Some account `who` was created with a deposit from `depositor`.
+		Touched { asset_id: T::AssetId, who: T::AccountId, depositor: T::AccountId },
+		/// Some account `who` was blocked.
+		Blocked { asset_id: T::AssetId, who: T::AccountId },
 	}
 
 	#[pallet::error]
@@ -911,7 +923,9 @@ pub mod pallet {
 			Self::do_transfer(id, &source, &dest, amount, Some(origin), f).map(|_| ())
 		}
 
-		/// Disallow further unprivileged transfers from an account.
+		/// Disallow further unprivileged transfers of an asset `id` from an account `who`. `who`
+		/// must already exist as an entry in `Account`s of the asset. If you want to freeze an
+		/// account that does not have an entry, use `touch_other` first.
 		///
 		/// Origin must be Signed and the sender should be the Freezer of the asset `id`.
 		///
@@ -939,7 +953,8 @@ pub mod pallet {
 			let who = T::Lookup::lookup(who)?;
 
 			Account::<T, I>::try_mutate(id, &who, |maybe_account| -> DispatchResult {
-				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.is_frozen = true;
+				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.status =
+					AccountStatus::Frozen;
 				Ok(())
 			})?;
 
@@ -947,7 +962,7 @@ pub mod pallet {
 			Ok(())
 		}
 
-		/// Allow unprivileged transfers from an account again.
+		/// Allow unprivileged transfers to and from an account again.
 		///
 		/// Origin must be Signed and the sender should be the Admin of the asset `id`.
 		///
@@ -975,7 +990,8 @@ pub mod pallet {
 			let who = T::Lookup::lookup(who)?;
 
 			Account::<T, I>::try_mutate(id, &who, |maybe_account| -> DispatchResult {
-				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.is_frozen = false;
+				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.status =
+					AccountStatus::Liquid;
 				Ok(())
 			})?;
 
@@ -1471,22 +1487,25 @@ pub mod pallet {
 		///
 		/// Emits `Touched` event when successful.
 		#[pallet::call_index(26)]
-		#[pallet::weight(T::WeightInfo::mint())]
+		#[pallet::weight(T::WeightInfo::touch())]
 		pub fn touch(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
+			let who = ensure_signed(origin)?;
 			let id: T::AssetId = id.into();
-			Self::do_touch(id, ensure_signed(origin)?)
+			Self::do_touch(id, who.clone(), who, false)
 		}
 
-		/// Return the deposit (if any) of an asset account.
+		/// Return the deposit (if any) of an asset account or a consumer reference (if any) of an
+		/// account.
 		///
 		/// The origin must be Signed.
 		///
-		/// - `id`: The identifier of the asset for the account to be created.
+		/// - `id`: The identifier of the asset for which the caller would like the deposit
+		///   refunded.
 		/// - `allow_burn`: If `true` then assets may be destroyed in order to complete the refund.
 		///
 		/// Emits `Refunded` event when successful.
 		#[pallet::call_index(27)]
-		#[pallet::weight(T::WeightInfo::mint())]
+		#[pallet::weight(T::WeightInfo::refund())]
 		pub fn refund(
 			origin: OriginFor<T>,
 			id: T::AssetIdParameter,
@@ -1541,6 +1560,104 @@ pub mod pallet {
 			});
 			Ok(())
 		}
+
+		/// Create an asset account for `who`.
+		///
+		/// A deposit will be taken from the signer account.
+		///
+		/// - `origin`: Must be Signed by `Freezer` or `Admin` of the asset `id`; the signer account
+		///   must have sufficient funds for a deposit to be taken.
+		/// - `id`: The identifier of the asset for the account to be created.
+		/// - `who`: The account to be created.
+		///
+		/// Emits `Touched` event when successful.
+		#[pallet::call_index(29)]
+		#[pallet::weight(T::WeightInfo::touch_other())]
+		pub fn touch_other(
+			origin: OriginFor<T>,
+			id: T::AssetIdParameter,
+			who: AccountIdLookupOf<T>,
+		) -> DispatchResult {
+			let origin = ensure_signed(origin)?;
+			let who = T::Lookup::lookup(who)?;
+			let id: T::AssetId = id.into();
+			Self::do_touch(id, who, origin, true)
+		}
+
+		/// Return the deposit (if any) of a target asset account. Useful if you are the depositor.
+		///
+		/// The origin must be Signed and either the account owner, depositor, or asset `Admin`. In
+		/// order to burn a non-zero balance of the asset, the caller must be the account and should
+		/// use `refund`.
+		///
+		/// - `id`: The identifier of the asset for the account holding a deposit.
+		/// - `who`: The account to refund.
+		///
+		/// Emits `Refunded` event when successful.
+		#[pallet::call_index(30)]
+		#[pallet::weight(T::WeightInfo::refund_other())]
+		pub fn refund_other(
+			origin: OriginFor<T>,
+			id: T::AssetIdParameter,
+			who: AccountIdLookupOf<T>,
+		) -> DispatchResult {
+			let origin = ensure_signed(origin)?;
+			let who = T::Lookup::lookup(who)?;
+			let id: T::AssetId = id.into();
+			Self::do_refund_other(id, &who, &origin)
+		}
+
+		/// Disallow further unprivileged transfers of an asset `id` to and from an account `who`.
+		///
+		/// Origin must be Signed and the sender should be the Freezer of the asset `id`.
+		///
+		/// - `id`: The identifier of the account's asset.
+		/// - `who`: The account to be unblocked.
+		///
+		/// Emits `Blocked`.
+		///
+		/// Weight: `O(1)`
+		#[pallet::call_index(31)]
+		pub fn block(
+			origin: OriginFor<T>,
+			id: T::AssetIdParameter,
+			who: AccountIdLookupOf<T>,
+		) -> DispatchResult {
+			let origin = ensure_signed(origin)?;
+			let id: T::AssetId = id.into();
+
+			let d = Asset::<T, I>::get(id).ok_or(Error::<T, I>::Unknown)?;
+			ensure!(
+				d.status == AssetStatus::Live || d.status == AssetStatus::Frozen,
+				Error::<T, I>::AssetNotLive
+			);
+			ensure!(origin == d.freezer, Error::<T, I>::NoPermission);
+			let who = T::Lookup::lookup(who)?;
+
+			Account::<T, I>::try_mutate(id, &who, |maybe_account| -> DispatchResult {
+				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.status =
+					AccountStatus::Blocked;
+				Ok(())
+			})?;
+
+			Self::deposit_event(Event::<T, I>::Blocked { asset_id: id, who });
+			Ok(())
+		}
+	}
+
+	/// Implements [AccountTouch] trait.
+	/// Note that a depositor can be any account, without any specific privilege.
+	/// This implementation is supposed to be used only for creation of system accounts.
+	impl<T: Config<I>, I: 'static> AccountTouch<T::AssetId, T::AccountId> for Pallet<T, I> {
+		type Balance = DepositBalanceOf<T, I>;
+
+		fn deposit_required() -> Self::Balance {
+			T::AssetAccountDeposit::get()
+		}
+
+		fn touch(asset: T::AssetId, who: T::AccountId, depositor: T::AccountId) -> DispatchResult {
+			Self::do_touch(asset, who, depositor, false)
+		}
 	}
 }
 
diff --git a/substrate/frame/assets/src/migration.rs b/substrate/frame/assets/src/migration.rs
index 71da8823e92efcf0a9225c91831daa615f1ec73e..90400ef5bd1dc20e0a56cb0161072b0f215e4235 100644
--- a/substrate/frame/assets/src/migration.rs
+++ b/substrate/frame/assets/src/migration.rs
@@ -122,7 +122,10 @@ pub mod v1 {
 			);
 
 			Asset::<T>::iter().for_each(|(_id, asset)| {
-				assert!(asset.status == AssetStatus::Live || asset.status == AssetStatus::Frozen, "assets should only be live or frozen. None should be in destroying status, or undefined state")
+				assert!(
+					asset.status == AssetStatus::Live || asset.status == AssetStatus::Frozen,
+					"assets should only be live or frozen. None should be in destroying status, or undefined state"
+				)
 			});
 			Ok(())
 		}
diff --git a/substrate/frame/assets/src/tests.rs b/substrate/frame/assets/src/tests.rs
index 88ba92d0685a9181f5ba7e16850d3c58e4fa5cc2..009d0180f36bc9cf84f3356f38dc65441af18e4a 100644
--- a/substrate/frame/assets/src/tests.rs
+++ b/substrate/frame/assets/src/tests.rs
@@ -34,6 +34,12 @@ fn asset_ids() -> Vec<u32> {
 	s
 }
 
+/// returns tuple of asset's account and sufficient counts
+fn asset_account_counts(asset_id: u32) -> (u32, u32) {
+	let asset = Asset::<Test>::get(asset_id).unwrap();
+	(asset.accounts, asset.sufficients)
+}
+
 #[test]
 fn transfer_should_never_burn() {
 	new_test_ext().execute_with(|| {
@@ -154,9 +160,11 @@ fn refunding_asset_deposit_without_burn_should_work() {
 		assert_eq!(Assets::balance(0, 2), 100);
 		assert_eq!(Assets::balance(0, 1), 0);
 		assert_eq!(Balances::reserved_balance(&1), 10);
+		assert_eq!(asset_account_counts(0), (2, 0));
 		assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, false));
 		assert_eq!(Balances::reserved_balance(&1), 0);
 		assert_eq!(Assets::balance(1, 0), 0);
+		assert_eq!(asset_account_counts(0), (1, 0));
 	});
 }
 
@@ -176,6 +184,99 @@ fn refunding_calls_died_hook() {
 	});
 }
 
+#[test]
+fn refunding_with_sufficient_existence_reason_should_fail() {
+	new_test_ext().execute_with(|| {
+		// create sufficient asset
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		// create an asset account with sufficient existence reason
+		// by transferring some sufficient assets
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		assert_eq!(Assets::balance(0, 1), 50);
+		assert_eq!(Assets::balance(0, 2), 50);
+		assert_eq!(asset_account_counts(0), (2, 2));
+		// fails to refund
+		assert_noop!(Assets::refund(RuntimeOrigin::signed(2), 0, true), Error::<Test>::NoDeposit);
+	});
+}
+
+#[test]
+fn refunding_with_deposit_from_should_fail() {
+	new_test_ext().execute_with(|| {
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1));
+		Balances::make_free_balance_be(&1, 100);
+		// create asset account `2` with deposit from `1`
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 2));
+		assert_eq!(Balances::reserved_balance(&1), 10);
+		// fails to refund
+		assert_noop!(Assets::refund(RuntimeOrigin::signed(2), 0, true), Error::<Test>::NoDeposit);
+		assert!(Account::<Test>::contains_key(0, &2));
+	});
+}
+
+#[test]
+fn refunding_frozen_with_consumer_ref_works() {
+	new_test_ext().execute_with(|| {
+		// 1 will be an admin
+		// 2 will be a frozen account
+		Balances::make_free_balance_be(&1, 100);
+		Balances::make_free_balance_be(&2, 100);
+		// create non-sufficient asset
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(System::consumers(&2), 0);
+		// create asset account `2` with a consumer reference by transferring
+		// non-sufficient funds into
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		assert_eq!(System::consumers(&2), 1);
+		assert_eq!(Assets::balance(0, 1), 50);
+		assert_eq!(Assets::balance(0, 2), 50);
+		assert_eq!(asset_account_counts(0), (2, 0));
+		// freeze asset account `2` and asset `0`
+		assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2));
+		assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0));
+		// refund works
+		assert_ok!(Assets::refund(RuntimeOrigin::signed(2), 0, true));
+		assert!(!Account::<Test>::contains_key(0, &2));
+		assert_eq!(System::consumers(&2), 0);
+		assert_eq!(asset_account_counts(0), (1, 0));
+	});
+}
+
+#[test]
+fn refunding_frozen_with_deposit_works() {
+	new_test_ext().execute_with(|| {
+		// 1 will be an asset admin
+		// 2 will be a frozen account
+		Balances::make_free_balance_be(&1, 100);
+		Balances::make_free_balance_be(&2, 100);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(System::consumers(&2), 0);
+		assert_ok!(Assets::touch(RuntimeOrigin::signed(2), 0));
+		// reserve deposit holds one consumer ref
+		assert_eq!(System::consumers(&2), 1);
+		assert_eq!(Balances::reserved_balance(&2), 10);
+		assert!(Account::<Test>::contains_key(0, &2));
+		// transfer some assets to `2`
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		assert_eq!(System::consumers(&2), 1);
+		assert_eq!(Assets::balance(0, 1), 50);
+		assert_eq!(Assets::balance(0, 2), 50);
+		assert_eq!(asset_account_counts(0), (2, 0));
+		// ensure refundable even if asset account and asset is frozen
+		assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2));
+		assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0));
+		// success
+		assert_ok!(Assets::refund(RuntimeOrigin::signed(2), 0, true));
+		assert!(!Account::<Test>::contains_key(0, &2));
+		assert_eq!(Balances::reserved_balance(&2), 0);
+		assert_eq!(System::consumers(&2), 0);
+		assert_eq!(asset_account_counts(0), (1, 0));
+	});
+}
+
 #[test]
 fn approval_lifecycle_works() {
 	new_test_ext().execute_with(|| {
@@ -637,6 +738,37 @@ fn approve_transfer_frozen_asset_should_not_work() {
 	});
 }
 
+#[test]
+fn transferring_from_blocked_account_should_not_work() {
+	new_test_ext().execute_with(|| {
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(Assets::balance(0, 1), 100);
+		assert_ok!(Assets::block(RuntimeOrigin::signed(1), 0, 1));
+		// behaves as frozen when transferring from blocked
+		assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::<Test>::Frozen);
+		assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 1));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50));
+	});
+}
+
+#[test]
+fn transferring_to_blocked_account_should_not_work() {
+	new_test_ext().execute_with(|| {
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100));
+		assert_eq!(Assets::balance(0, 1), 100);
+		assert_eq!(Assets::balance(0, 2), 100);
+		assert_ok!(Assets::block(RuntimeOrigin::signed(1), 0, 1));
+		assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50), TokenError::Blocked);
+		assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 1));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+	});
+}
+
 #[test]
 fn origin_guards_should_work() {
 	new_test_ext().execute_with(|| {
@@ -719,7 +851,7 @@ fn set_team_should_work() {
 }
 
 #[test]
-fn transferring_to_frozen_account_should_work() {
+fn transferring_from_frozen_account_should_not_work() {
 	new_test_ext().execute_with(|| {
 		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
 		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
@@ -727,11 +859,226 @@ fn transferring_to_frozen_account_should_work() {
 		assert_eq!(Assets::balance(0, 1), 100);
 		assert_eq!(Assets::balance(0, 2), 100);
 		assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2));
+		// can transfer to `2`
 		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		// cannot transfer from `2`
+		assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 25), Error::<Test>::Frozen);
+		assert_eq!(Assets::balance(0, 1), 50);
 		assert_eq!(Assets::balance(0, 2), 150);
 	});
 }
 
+#[test]
+fn touching_and_freezing_account_with_zero_asset_balance_should_work() {
+	new_test_ext().execute_with(|| {
+		// need some deposit for the touch
+		Balances::make_free_balance_be(&2, 100);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(Assets::balance(0, 1), 100);
+		assert_eq!(Assets::balance(0, 2), 0);
+		// cannot freeze an account that doesn't have an `Assets` entry
+		assert_noop!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2), Error::<Test>::NoAccount);
+		assert_ok!(Assets::touch(RuntimeOrigin::signed(2), 0));
+		// now it can be frozen
+		assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2));
+		// can transfer to `2` even though its frozen
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		// cannot transfer from `2`
+		assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 25), Error::<Test>::Frozen);
+		assert_eq!(Assets::balance(0, 1), 50);
+		assert_eq!(Assets::balance(0, 2), 50);
+	});
+}
+
+#[test]
+fn touch_other_works() {
+	new_test_ext().execute_with(|| {
+		// 1 will be admin
+		// 2 will be freezer
+		// 4 will be an account attempting to execute `touch_other`
+		Balances::make_free_balance_be(&1, 100);
+		Balances::make_free_balance_be(&2, 100);
+		Balances::make_free_balance_be(&4, 100);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1));
+		assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 1, 1, 2));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(Assets::balance(0, 1), 100);
+		// account `3` does not exist
+		assert!(!Account::<Test>::contains_key(0, &3));
+		// creation of asset account `3` by account `4` fails
+		assert_noop!(
+			Assets::touch_other(RuntimeOrigin::signed(4), 0, 3),
+			Error::<Test>::NoPermission
+		);
+		// creation of asset account `3` by admin `1` works
+		assert!(!Account::<Test>::contains_key(0, &3));
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 3));
+		assert!(Account::<Test>::contains_key(0, &3));
+		// creation of asset account `4` by freezer `2` works
+		assert!(!Account::<Test>::contains_key(0, &4));
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 4));
+		assert!(Account::<Test>::contains_key(0, &4));
+	});
+}
+
+#[test]
+fn touch_other_and_freeze_works() {
+	new_test_ext().execute_with(|| {
+		Balances::make_free_balance_be(&1, 100);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(Assets::balance(0, 1), 100);
+		// account `2` does not exist
+		assert!(!Account::<Test>::contains_key(0, &2));
+		// create account `2` with touch_other
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 2));
+		assert!(Account::<Test>::contains_key(0, &2));
+		// now it can be frozen
+		assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2));
+		// can transfer to `2` even though its frozen
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		// cannot transfer from `2`
+		assert_noop!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 25), Error::<Test>::Frozen);
+		assert_eq!(Assets::balance(0, 1), 50);
+		assert_eq!(Assets::balance(0, 2), 50);
+	});
+}
+
+#[test]
+fn account_with_deposit_not_destroyed() {
+	new_test_ext().execute_with(|| {
+		// 1 will be the asset admin
+		// 2 will exist without balance but with deposit
+		Balances::make_free_balance_be(&1, 100);
+		Balances::make_free_balance_be(&2, 100);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1));
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100));
+		assert_eq!(Assets::balance(0, 1), 100);
+		assert_eq!(Assets::balance(0, 2), 0);
+		// case 1; account `2` not destroyed with a holder's deposit
+		assert_ok!(Assets::touch(RuntimeOrigin::signed(2), 0));
+		assert_eq!(Balances::reserved_balance(&2), 10);
+		assert!(Account::<Test>::contains_key(0, &2));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50));
+		assert_eq!(Assets::balance(0, 2), 0);
+		assert!(Account::<Test>::contains_key(0, &2));
+
+		// destroy account `2`
+		assert_ok!(Assets::refund(RuntimeOrigin::signed(2), 0, false));
+		assert!(!Account::<Test>::contains_key(0, &2));
+
+		// case 2; account `2` not destroyed with a deposit from `1`
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 2));
+		assert_eq!(Balances::reserved_balance(&1), 10);
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50));
+		assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 50));
+		assert!(Account::<Test>::contains_key(0, &2));
+	});
+}
+
+#[test]
+fn refund_other_should_fails() {
+	new_test_ext().execute_with(|| {
+		// 1 will be the asset admin
+		// 2 will be the asset freezer
+		// 3 will be created with deposit of 2
+		Balances::make_free_balance_be(&1, 100);
+		Balances::make_free_balance_be(&2, 100);
+		Balances::make_free_balance_be(&3, 0);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 1, 1, 2));
+		assert!(!Account::<Test>::contains_key(0, &3));
+
+		// create asset account `3` with a deposit from freezer `2`
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 3));
+		assert_eq!(Balances::reserved_balance(&2), 10);
+
+		// fail case; non-existing asset account `10`
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(2), 0, 10),
+			Error::<Test>::NoDeposit
+		);
+		// fail case; non-existing asset `3`
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(2), 1, 3),
+			Error::<Test>::NoDeposit
+		);
+		// fail case; no `DepositFrom` for asset account `1`
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(2), 0, 1),
+			Error::<Test>::NoDeposit
+		);
+		// fail case; asset `0` is frozen
+		assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(2), 0));
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(2), 0, 3),
+			Error::<Test>::AssetNotLive
+		);
+		assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0));
+		// fail case; asset `1` is being destroyed
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 10, 1, true, 1));
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 10, 3));
+		assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(1), 10));
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(2), 10, 3),
+			Error::<Test>::AssetNotLive
+		);
+		assert_ok!(Assets::destroy_accounts(RuntimeOrigin::signed(1), 10));
+		assert_ok!(Assets::finish_destroy(RuntimeOrigin::signed(1), 10));
+		// fail case; account is frozen
+		assert_ok!(Assets::freeze(RuntimeOrigin::signed(2), 0, 3));
+		assert_noop!(Assets::refund_other(RuntimeOrigin::signed(2), 0, 3), Error::<Test>::Frozen);
+		assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 3));
+		// fail case; not a freezer or an admin
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(4), 0, 3),
+			Error::<Test>::NoPermission
+		);
+		// fail case; would burn
+		assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 3, 100));
+		assert_noop!(
+			Assets::refund_other(RuntimeOrigin::signed(1), 0, 3),
+			Error::<Test>::WouldBurn
+		);
+		assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 3, 100));
+	})
+}
+
+#[test]
+fn refund_other_works() {
+	new_test_ext().execute_with(|| {
+		// 1 will be the asset admin
+		// 2 will be the asset freezer
+		// 3 will be created with deposit of 2
+		Balances::make_free_balance_be(&1, 100);
+		Balances::make_free_balance_be(&2, 100);
+		assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1));
+		assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 1, 1, 2));
+		assert!(!Account::<Test>::contains_key(0, &3));
+		assert_eq!(asset_account_counts(0), (0, 0));
+
+		// success case; freezer is depositor
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(2), 0, 3));
+		assert_eq!(Balances::reserved_balance(&2), 10);
+		assert_eq!(asset_account_counts(0), (1, 0));
+		assert_ok!(Assets::refund_other(RuntimeOrigin::signed(2), 0, 3));
+		assert_eq!(Balances::reserved_balance(&2), 0);
+		assert!(!Account::<Test>::contains_key(0, &3));
+		assert_eq!(asset_account_counts(0), (0, 0));
+
+		// success case; admin is depositor
+		assert_ok!(Assets::touch_other(RuntimeOrigin::signed(1), 0, 3));
+		assert_eq!(Balances::reserved_balance(&1), 10);
+		assert_eq!(asset_account_counts(0), (1, 0));
+		assert_ok!(Assets::refund_other(RuntimeOrigin::signed(1), 0, 3));
+		assert_eq!(Balances::reserved_balance(&1), 0);
+		assert!(!Account::<Test>::contains_key(0, &3));
+		assert_eq!(asset_account_counts(0), (0, 0));
+	})
+}
+
 #[test]
 fn transferring_amount_more_than_available_balance_should_not_work() {
 	new_test_ext().execute_with(|| {
diff --git a/substrate/frame/assets/src/types.rs b/substrate/frame/assets/src/types.rs
index c83e764f4a68ddfafff4475369afac2836f31834..559afccb946c55ed8d7e111206c21da2919b3a00 100644
--- a/substrate/frame/assets/src/types.rs
+++ b/substrate/frame/assets/src/types.rs
@@ -26,8 +26,14 @@ use sp_runtime::{traits::Convert, FixedPointNumber, FixedPointOperand, FixedU128
 
 pub(super) type DepositBalanceOf<T, I = ()> =
 	<<T as Config<I>>::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance;
-pub(super) type AssetAccountOf<T, I> =
-	AssetAccount<<T as Config<I>>::Balance, DepositBalanceOf<T, I>, <T as Config<I>>::Extra>;
+pub(super) type AssetAccountOf<T, I> = AssetAccount<
+	<T as Config<I>>::Balance,
+	DepositBalanceOf<T, I>,
+	<T as Config<I>>::Extra,
+	<T as SystemConfig>::AccountId,
+>;
+pub(super) type ExistenceReasonOf<T, I> =
+	ExistenceReason<DepositBalanceOf<T, I>, <T as SystemConfig>::AccountId>;
 
 /// AssetStatus holds the current state of the asset. It could either be Live and available for use,
 /// or in a Destroying state.
@@ -83,23 +89,35 @@ pub struct Approval<Balance, DepositBalance> {
 
 #[test]
 fn ensure_bool_decodes_to_consumer_or_sufficient() {
-	assert_eq!(false.encode(), ExistenceReason::<()>::Consumer.encode());
-	assert_eq!(true.encode(), ExistenceReason::<()>::Sufficient.encode());
+	assert_eq!(false.encode(), ExistenceReason::<(), ()>::Consumer.encode());
+	assert_eq!(true.encode(), ExistenceReason::<(), ()>::Sufficient.encode());
 }
 
+/// The reason for an account's existence within an asset class.
 #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
-pub enum ExistenceReason<Balance> {
+pub enum ExistenceReason<Balance, AccountId> {
+	/// A consumer reference was used to create this account.
 	#[codec(index = 0)]
 	Consumer,
+	/// The asset class is `sufficient` for account existence.
 	#[codec(index = 1)]
 	Sufficient,
+	/// The account holder has placed a deposit to exist within an asset class.
 	#[codec(index = 2)]
 	DepositHeld(Balance),
+	/// A deposit was placed for this account to exist, but it has been refunded.
 	#[codec(index = 3)]
 	DepositRefunded,
+	/// Some other `AccountId` has placed a deposit to make this account exist.
+	/// An account with such a reason might not be referenced in `system`.
+	#[codec(index = 4)]
+	DepositFrom(AccountId, Balance),
 }
 
-impl<Balance> ExistenceReason<Balance> {
+impl<Balance, AccountId> ExistenceReason<Balance, AccountId>
+where
+	AccountId: Clone,
+{
 	pub(crate) fn take_deposit(&mut self) -> Option<Balance> {
 		if !matches!(self, ExistenceReason::DepositHeld(_)) {
 			return None
@@ -112,16 +130,56 @@ impl<Balance> ExistenceReason<Balance> {
 			None
 		}
 	}
+
+	pub(crate) fn take_deposit_from(&mut self) -> Option<(AccountId, Balance)> {
+		if !matches!(self, ExistenceReason::DepositFrom(..)) {
+			return None
+		}
+		if let ExistenceReason::DepositFrom(depositor, deposit) =
+			sp_std::mem::replace(self, ExistenceReason::DepositRefunded)
+		{
+			Some((depositor, deposit))
+		} else {
+			None
+		}
+	}
 }
 
+#[test]
+fn ensure_bool_decodes_to_liquid_or_frozen() {
+	assert_eq!(false.encode(), AccountStatus::Liquid.encode());
+	assert_eq!(true.encode(), AccountStatus::Frozen.encode());
+}
+
+/// The status of an asset account.
 #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
-pub struct AssetAccount<Balance, DepositBalance, Extra> {
+pub enum AccountStatus {
+	/// Asset account can receive and transfer the assets.
+	Liquid,
+	/// Asset account cannot transfer the assets.
+	Frozen,
+	/// Asset account cannot receive and transfer the assets.
+	Blocked,
+}
+impl AccountStatus {
+	/// Returns `true` if frozen or blocked.
+	pub(crate) fn is_frozen(&self) -> bool {
+		matches!(self, AccountStatus::Frozen | AccountStatus::Blocked)
+	}
+	/// Returns `true` if blocked.
+	pub(crate) fn is_blocked(&self) -> bool {
+		matches!(self, AccountStatus::Blocked)
+	}
+}
+
+#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
+pub struct AssetAccount<Balance, DepositBalance, Extra, AccountId> {
 	/// The balance.
 	pub(super) balance: Balance,
-	/// Whether the account is frozen.
-	pub(super) is_frozen: bool,
+	/// The status of the account.
+	pub(super) status: AccountStatus,
 	/// The reason for the existence of the account.
-	pub(super) reason: ExistenceReason<DepositBalance>,
+	pub(super) reason: ExistenceReason<DepositBalance, AccountId>,
 	/// Additional "sidecar" data, in case some other pallet wants to use this storage item.
 	pub(super) extra: Extra,
 }
diff --git a/substrate/frame/assets/src/weights.rs b/substrate/frame/assets/src/weights.rs
index 4cc90e25f43fad75a6da0fe3003e0399b560db36..76ac585ff41f87131d8146cb6b9aa5e28e86679b 100644
--- a/substrate/frame/assets/src/weights.rs
+++ b/substrate/frame/assets/src/weights.rs
@@ -18,33 +18,35 @@
 //! Autogenerated weights for pallet_assets
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2023-05-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
+//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
 
 // Executed Command:
-// ./target/production/substrate
+// target/production/substrate
 // benchmark
 // pallet
-// --chain=dev
 // --steps=50
 // --repeat=20
-// --pallet=pallet_assets
 // --extrinsic=*
 // --execution=wasm
 // --wasm-execution=compiled
 // --heap-pages=4096
-// --output=./frame/assets/src/weights.rs
+// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json
+// --pallet=pallet_assets
+// --chain=dev
 // --header=./HEADER-APACHE2
+// --output=./frame/assets/src/weights.rs
 // --template=./.maintain/frame-weight-template.hbs
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
 #![allow(unused_imports)]
+#![allow(missing_docs)]
 
 use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
-use sp_std::marker::PhantomData;
+use core::marker::PhantomData;
 
 /// Weight functions needed for pallet_assets.
 pub trait WeightInfo {
@@ -75,6 +77,11 @@ pub trait WeightInfo {
 	fn cancel_approval() -> Weight;
 	fn force_cancel_approval() -> Weight;
 	fn set_min_balance() -> Weight;
+	fn touch() -> Weight;
+	fn touch_other() -> Weight;
+	fn refund() -> Weight;
+	fn refund_other() -> Weight;
+	fn block() -> Weight;
 }
 
 /// Weights for pallet_assets using the Substrate node and recommended hardware.
@@ -88,8 +95,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `293`
 		//  Estimated: `3675`
-		// Minimum execution time: 33_678_000 picoseconds.
-		Weight::from_parts(34_320_000, 3675)
+		// Minimum execution time: 31_668_000 picoseconds.
+		Weight::from_parts(32_079_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -99,8 +106,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `153`
 		//  Estimated: `3675`
-		// Minimum execution time: 15_521_000 picoseconds.
-		Weight::from_parts(16_035_000, 3675)
+		// Minimum execution time: 14_885_000 picoseconds.
+		Weight::from_parts(15_358_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -110,31 +117,31 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 15_921_000 picoseconds.
-		Weight::from_parts(16_153_000, 3675)
+		// Minimum execution time: 15_295_000 picoseconds.
+		Weight::from_parts(15_639_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1001 w:1000)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1000 w:1000)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	/// The range of component `c` is `[0, 1000]`.
 	fn destroy_accounts(c: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0 + c * (208 ±0)`
-		//  Estimated: `3675 + c * (2603 ±0)`
-		// Minimum execution time: 21_242_000 picoseconds.
-		Weight::from_parts(21_532_000, 3675)
-			// Standard Error: 6_449
-			.saturating_add(Weight::from_parts(13_150_845, 0).saturating_mul(c.into()))
+		//  Estimated: `3675 + c * (2609 ±0)`
+		// Minimum execution time: 19_916_000 picoseconds.
+		Weight::from_parts(20_220_000, 3675)
+			// Standard Error: 7_298
+			.saturating_add(Weight::from_parts(12_553_976, 0).saturating_mul(c.into()))
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into())))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 			.saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into())))
-			.saturating_add(Weight::from_parts(0, 2603).saturating_mul(c.into()))
+			.saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into()))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
@@ -145,10 +152,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `522 + a * (86 ±0)`
 		//  Estimated: `3675 + a * (2623 ±0)`
-		// Minimum execution time: 21_604_000 picoseconds.
-		Weight::from_parts(21_881_000, 3675)
-			// Standard Error: 4_225
-			.saturating_add(Weight::from_parts(15_968_205, 0).saturating_mul(a.into()))
+		// Minimum execution time: 20_322_000 picoseconds.
+		Weight::from_parts(20_744_000, 3675)
+			// Standard Error: 12_314
+			.saturating_add(Weight::from_parts(14_767_353, 0).saturating_mul(a.into()))
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into())))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
@@ -163,105 +170,105 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_465_000 picoseconds.
-		Weight::from_parts(16_775_000, 3675)
+		// Minimum execution time: 15_668_000 picoseconds.
+		Weight::from_parts(16_016_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn mint() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 30_709_000 picoseconds.
-		Weight::from_parts(31_159_000, 3675)
+		// Minimum execution time: 28_227_000 picoseconds.
+		Weight::from_parts(28_769_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn burn() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `459`
 		//  Estimated: `3675`
-		// Minimum execution time: 36_944_000 picoseconds.
-		Weight::from_parts(38_166_000, 3675)
+		// Minimum execution time: 34_672_000 picoseconds.
+		Weight::from_parts(34_902_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn transfer() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `498`
-		//  Estimated: `6144`
-		// Minimum execution time: 52_497_000 picoseconds.
-		Weight::from_parts(53_147_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 49_003_000 picoseconds.
+		Weight::from_parts(49_345_000, 6208)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn transfer_keep_alive() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `498`
-		//  Estimated: `6144`
-		// Minimum execution time: 46_203_000 picoseconds.
-		Weight::from_parts(46_853_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 43_429_000 picoseconds.
+		Weight::from_parts(43_936_000, 6208)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn force_transfer() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `498`
-		//  Estimated: `6144`
-		// Minimum execution time: 52_911_000 picoseconds.
-		Weight::from_parts(55_511_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 49_177_000 picoseconds.
+		Weight::from_parts(49_548_000, 6208)
 			.saturating_add(T::DbWeight::get().reads(4_u64))
 			.saturating_add(T::DbWeight::get().writes(4_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:0)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn freeze() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `459`
 		//  Estimated: `3675`
-		// Minimum execution time: 20_308_000 picoseconds.
-		Weight::from_parts(20_524_000, 3675)
+		// Minimum execution time: 19_323_000 picoseconds.
+		Weight::from_parts(19_945_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:0)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn thaw() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `459`
 		//  Estimated: `3675`
-		// Minimum execution time: 20_735_000 picoseconds.
-		Weight::from_parts(21_026_000, 3675)
+		// Minimum execution time: 19_543_000 picoseconds.
+		Weight::from_parts(19_747_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -271,8 +278,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_148_000 picoseconds.
-		Weight::from_parts(16_404_000, 3675)
+		// Minimum execution time: 15_623_000 picoseconds.
+		Weight::from_parts(15_833_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -282,8 +289,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_075_000 picoseconds.
-		Weight::from_parts(16_542_000, 3675)
+		// Minimum execution time: 15_396_000 picoseconds.
+		Weight::from_parts(15_704_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -295,8 +302,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 17_866_000 picoseconds.
-		Weight::from_parts(18_129_000, 3675)
+		// Minimum execution time: 17_205_000 picoseconds.
+		Weight::from_parts(17_546_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -306,8 +313,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_637_000 picoseconds.
-		Weight::from_parts(16_918_000, 3675)
+		// Minimum execution time: 16_049_000 picoseconds.
+		Weight::from_parts(16_317_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -317,14 +324,16 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen)
 	/// The range of component `n` is `[0, 50]`.
 	/// The range of component `s` is `[0, 50]`.
-	fn set_metadata(_n: u32, s: u32, ) -> Weight {
+	fn set_metadata(n: u32, s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 33_304_000 picoseconds.
-		Weight::from_parts(34_764_544, 3675)
-			// Standard Error: 634
-			.saturating_add(Weight::from_parts(4_733, 0).saturating_mul(s.into()))
+		// Minimum execution time: 31_574_000 picoseconds.
+		Weight::from_parts(32_447_787, 3675)
+			// Standard Error: 904
+			.saturating_add(Weight::from_parts(653, 0).saturating_mul(n.into()))
+			// Standard Error: 904
+			.saturating_add(Weight::from_parts(271, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -336,8 +345,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `515`
 		//  Estimated: `3675`
-		// Minimum execution time: 33_640_000 picoseconds.
-		Weight::from_parts(34_100_000, 3675)
+		// Minimum execution time: 31_865_000 picoseconds.
+		Weight::from_parts(32_160_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -351,12 +360,12 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `190`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_549_000 picoseconds.
-		Weight::from_parts(17_337_982, 3675)
-			// Standard Error: 586
-			.saturating_add(Weight::from_parts(4_584, 0).saturating_mul(n.into()))
-			// Standard Error: 586
-			.saturating_add(Weight::from_parts(4_288, 0).saturating_mul(s.into()))
+		// Minimum execution time: 16_203_000 picoseconds.
+		Weight::from_parts(16_432_499, 3675)
+			// Standard Error: 1_563
+			.saturating_add(Weight::from_parts(5_818, 0).saturating_mul(n.into()))
+			// Standard Error: 1_563
+			.saturating_add(Weight::from_parts(9_660, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -368,8 +377,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `515`
 		//  Estimated: `3675`
-		// Minimum execution time: 34_183_000 picoseconds.
-		Weight::from_parts(34_577_000, 3675)
+		// Minimum execution time: 33_443_000 picoseconds.
+		Weight::from_parts(56_533_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -379,8 +388,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 15_505_000 picoseconds.
-		Weight::from_parts(15_784_000, 3675)
+		// Minimum execution time: 20_636_000 picoseconds.
+		Weight::from_parts(23_960_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
@@ -392,8 +401,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 38_762_000 picoseconds.
-		Weight::from_parts(39_138_000, 3675)
+		// Minimum execution time: 35_987_000 picoseconds.
+		Weight::from_parts(36_429_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -402,15 +411,15 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	/// Storage: Assets Approvals (r:1 w:1)
 	/// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn transfer_approved() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `668`
-		//  Estimated: `6144`
-		// Minimum execution time: 73_396_000 picoseconds.
-		Weight::from_parts(73_986_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 68_059_000 picoseconds.
+		Weight::from_parts(69_845_000, 6208)
 			.saturating_add(T::DbWeight::get().reads(5_u64))
 			.saturating_add(T::DbWeight::get().writes(5_u64))
 	}
@@ -422,8 +431,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `555`
 		//  Estimated: `3675`
-		// Minimum execution time: 39_707_000 picoseconds.
-		Weight::from_parts(40_222_000, 3675)
+		// Minimum execution time: 38_066_000 picoseconds.
+		Weight::from_parts(38_450_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -435,8 +444,8 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `555`
 		//  Estimated: `3675`
-		// Minimum execution time: 40_357_000 picoseconds.
-		Weight::from_parts(40_731_000, 3675)
+		// Minimum execution time: 38_500_000 picoseconds.
+		Weight::from_parts(38_953_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
@@ -446,11 +455,80 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_937_000 picoseconds.
-		Weight::from_parts(17_219_000, 3675)
+		// Minimum execution time: 16_268_000 picoseconds.
+		Weight::from_parts(16_764_000, 3675)
 			.saturating_add(T::DbWeight::get().reads(1_u64))
 			.saturating_add(T::DbWeight::get().writes(1_u64))
 	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	/// Storage: System Account (r:1 w:1)
+	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
+	fn touch() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `453`
+		//  Estimated: `3675`
+		// Minimum execution time: 37_468_000 picoseconds.
+		Weight::from_parts(37_957_000, 3675)
+			.saturating_add(T::DbWeight::get().reads(3_u64))
+			.saturating_add(T::DbWeight::get().writes(3_u64))
+	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	fn touch_other() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `351`
+		//  Estimated: `3675`
+		// Minimum execution time: 383_408_000 picoseconds.
+		Weight::from_parts(392_036_000, 3675)
+			.saturating_add(T::DbWeight::get().reads(2))
+			.saturating_add(T::DbWeight::get().writes(2))
+	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	/// Storage: System Account (r:1 w:1)
+	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
+	fn refund() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `579`
+		//  Estimated: `3675`
+		// Minimum execution time: 34_066_000 picoseconds.
+		Weight::from_parts(34_347_000, 3675)
+			.saturating_add(T::DbWeight::get().reads(3_u64))
+			.saturating_add(T::DbWeight::get().writes(3_u64))
+	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	fn refund_other() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `510`
+		//  Estimated: `3675`
+		// Minimum execution time: 32_060_000 picoseconds.
+		Weight::from_parts(32_519_000, 3675)
+			.saturating_add(T::DbWeight::get().reads(2_u64))
+			.saturating_add(T::DbWeight::get().writes(2_u64))
+	}
+	/// Storage: Assets Asset (r:1 w:0)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	fn block() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `459`
+		//  Estimated: `3675`
+		// Minimum execution time: 115_000_000 picoseconds.
+		Weight::from_parts(163_000_000, 3675)
+			.saturating_add(T::DbWeight::get().reads(2_u64))
+			.saturating_add(T::DbWeight::get().writes(1_u64))
+	}
 }
 
 // For backwards compatibility and tests
@@ -463,8 +541,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `293`
 		//  Estimated: `3675`
-		// Minimum execution time: 33_678_000 picoseconds.
-		Weight::from_parts(34_320_000, 3675)
+		// Minimum execution time: 31_668_000 picoseconds.
+		Weight::from_parts(32_079_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -474,8 +552,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `153`
 		//  Estimated: `3675`
-		// Minimum execution time: 15_521_000 picoseconds.
-		Weight::from_parts(16_035_000, 3675)
+		// Minimum execution time: 14_885_000 picoseconds.
+		Weight::from_parts(15_358_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -485,31 +563,31 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 15_921_000 picoseconds.
-		Weight::from_parts(16_153_000, 3675)
+		// Minimum execution time: 15_295_000 picoseconds.
+		Weight::from_parts(15_639_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1001 w:1000)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1000 w:1000)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	/// The range of component `c` is `[0, 1000]`.
 	fn destroy_accounts(c: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `0 + c * (208 ±0)`
-		//  Estimated: `3675 + c * (2603 ±0)`
-		// Minimum execution time: 21_242_000 picoseconds.
-		Weight::from_parts(21_532_000, 3675)
-			// Standard Error: 6_449
-			.saturating_add(Weight::from_parts(13_150_845, 0).saturating_mul(c.into()))
+		//  Estimated: `3675 + c * (2609 ±0)`
+		// Minimum execution time: 19_916_000 picoseconds.
+		Weight::from_parts(20_220_000, 3675)
+			// Standard Error: 7_298
+			.saturating_add(Weight::from_parts(12_553_976, 0).saturating_mul(c.into()))
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into())))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 			.saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into())))
-			.saturating_add(Weight::from_parts(0, 2603).saturating_mul(c.into()))
+			.saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into()))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
@@ -520,10 +598,10 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `522 + a * (86 ±0)`
 		//  Estimated: `3675 + a * (2623 ±0)`
-		// Minimum execution time: 21_604_000 picoseconds.
-		Weight::from_parts(21_881_000, 3675)
-			// Standard Error: 4_225
-			.saturating_add(Weight::from_parts(15_968_205, 0).saturating_mul(a.into()))
+		// Minimum execution time: 20_322_000 picoseconds.
+		Weight::from_parts(20_744_000, 3675)
+			// Standard Error: 12_314
+			.saturating_add(Weight::from_parts(14_767_353, 0).saturating_mul(a.into()))
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into())))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
@@ -538,105 +616,105 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_465_000 picoseconds.
-		Weight::from_parts(16_775_000, 3675)
+		// Minimum execution time: 15_668_000 picoseconds.
+		Weight::from_parts(16_016_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn mint() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 30_709_000 picoseconds.
-		Weight::from_parts(31_159_000, 3675)
+		// Minimum execution time: 28_227_000 picoseconds.
+		Weight::from_parts(28_769_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn burn() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `459`
 		//  Estimated: `3675`
-		// Minimum execution time: 36_944_000 picoseconds.
-		Weight::from_parts(38_166_000, 3675)
+		// Minimum execution time: 34_672_000 picoseconds.
+		Weight::from_parts(34_902_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn transfer() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `498`
-		//  Estimated: `6144`
-		// Minimum execution time: 52_497_000 picoseconds.
-		Weight::from_parts(53_147_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 49_003_000 picoseconds.
+		Weight::from_parts(49_345_000, 6208)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn transfer_keep_alive() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `498`
-		//  Estimated: `6144`
-		// Minimum execution time: 46_203_000 picoseconds.
-		Weight::from_parts(46_853_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 43_429_000 picoseconds.
+		Weight::from_parts(43_936_000, 6208)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:1)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn force_transfer() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `498`
-		//  Estimated: `6144`
-		// Minimum execution time: 52_911_000 picoseconds.
-		Weight::from_parts(55_511_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 49_177_000 picoseconds.
+		Weight::from_parts(49_548_000, 6208)
 			.saturating_add(RocksDbWeight::get().reads(4_u64))
 			.saturating_add(RocksDbWeight::get().writes(4_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:0)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn freeze() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `459`
 		//  Estimated: `3675`
-		// Minimum execution time: 20_308_000 picoseconds.
-		Weight::from_parts(20_524_000, 3675)
+		// Minimum execution time: 19_323_000 picoseconds.
+		Weight::from_parts(19_945_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
 	/// Storage: Assets Asset (r:1 w:0)
 	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:1 w:1)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	fn thaw() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `459`
 		//  Estimated: `3675`
-		// Minimum execution time: 20_735_000 picoseconds.
-		Weight::from_parts(21_026_000, 3675)
+		// Minimum execution time: 19_543_000 picoseconds.
+		Weight::from_parts(19_747_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -646,8 +724,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_148_000 picoseconds.
-		Weight::from_parts(16_404_000, 3675)
+		// Minimum execution time: 15_623_000 picoseconds.
+		Weight::from_parts(15_833_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -657,8 +735,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_075_000 picoseconds.
-		Weight::from_parts(16_542_000, 3675)
+		// Minimum execution time: 15_396_000 picoseconds.
+		Weight::from_parts(15_704_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -670,8 +748,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 17_866_000 picoseconds.
-		Weight::from_parts(18_129_000, 3675)
+		// Minimum execution time: 17_205_000 picoseconds.
+		Weight::from_parts(17_546_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -681,8 +759,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_637_000 picoseconds.
-		Weight::from_parts(16_918_000, 3675)
+		// Minimum execution time: 16_049_000 picoseconds.
+		Weight::from_parts(16_317_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -692,14 +770,16 @@ impl WeightInfo for () {
 	/// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen)
 	/// The range of component `n` is `[0, 50]`.
 	/// The range of component `s` is `[0, 50]`.
-	fn set_metadata(_n: u32, s: u32, ) -> Weight {
+	fn set_metadata(n: u32, s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 33_304_000 picoseconds.
-		Weight::from_parts(34_764_544, 3675)
-			// Standard Error: 634
-			.saturating_add(Weight::from_parts(4_733, 0).saturating_mul(s.into()))
+		// Minimum execution time: 31_574_000 picoseconds.
+		Weight::from_parts(32_447_787, 3675)
+			// Standard Error: 904
+			.saturating_add(Weight::from_parts(653, 0).saturating_mul(n.into()))
+			// Standard Error: 904
+			.saturating_add(Weight::from_parts(271, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -711,8 +791,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `515`
 		//  Estimated: `3675`
-		// Minimum execution time: 33_640_000 picoseconds.
-		Weight::from_parts(34_100_000, 3675)
+		// Minimum execution time: 31_865_000 picoseconds.
+		Weight::from_parts(32_160_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -726,12 +806,12 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `190`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_549_000 picoseconds.
-		Weight::from_parts(17_337_982, 3675)
-			// Standard Error: 586
-			.saturating_add(Weight::from_parts(4_584, 0).saturating_mul(n.into()))
-			// Standard Error: 586
-			.saturating_add(Weight::from_parts(4_288, 0).saturating_mul(s.into()))
+		// Minimum execution time: 16_203_000 picoseconds.
+		Weight::from_parts(16_432_499, 3675)
+			// Standard Error: 1_563
+			.saturating_add(Weight::from_parts(5_818, 0).saturating_mul(n.into()))
+			// Standard Error: 1_563
+			.saturating_add(Weight::from_parts(9_660, 0).saturating_mul(s.into()))
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -743,8 +823,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `515`
 		//  Estimated: `3675`
-		// Minimum execution time: 34_183_000 picoseconds.
-		Weight::from_parts(34_577_000, 3675)
+		// Minimum execution time: 33_443_000 picoseconds.
+		Weight::from_parts(56_533_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -754,8 +834,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 15_505_000 picoseconds.
-		Weight::from_parts(15_784_000, 3675)
+		// Minimum execution time: 20_636_000 picoseconds.
+		Weight::from_parts(23_960_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
@@ -767,8 +847,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `385`
 		//  Estimated: `3675`
-		// Minimum execution time: 38_762_000 picoseconds.
-		Weight::from_parts(39_138_000, 3675)
+		// Minimum execution time: 35_987_000 picoseconds.
+		Weight::from_parts(36_429_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -777,15 +857,15 @@ impl WeightInfo for () {
 	/// Storage: Assets Approvals (r:1 w:1)
 	/// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen)
 	/// Storage: Assets Account (r:2 w:2)
-	/// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
 	/// Storage: System Account (r:1 w:1)
 	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
 	fn transfer_approved() -> Weight {
 		// Proof Size summary in bytes:
 		//  Measured:  `668`
-		//  Estimated: `6144`
-		// Minimum execution time: 73_396_000 picoseconds.
-		Weight::from_parts(73_986_000, 6144)
+		//  Estimated: `6208`
+		// Minimum execution time: 68_059_000 picoseconds.
+		Weight::from_parts(69_845_000, 6208)
 			.saturating_add(RocksDbWeight::get().reads(5_u64))
 			.saturating_add(RocksDbWeight::get().writes(5_u64))
 	}
@@ -797,8 +877,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `555`
 		//  Estimated: `3675`
-		// Minimum execution time: 39_707_000 picoseconds.
-		Weight::from_parts(40_222_000, 3675)
+		// Minimum execution time: 38_066_000 picoseconds.
+		Weight::from_parts(38_450_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -810,8 +890,8 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `555`
 		//  Estimated: `3675`
-		// Minimum execution time: 40_357_000 picoseconds.
-		Weight::from_parts(40_731_000, 3675)
+		// Minimum execution time: 38_500_000 picoseconds.
+		Weight::from_parts(38_953_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
@@ -821,9 +901,78 @@ impl WeightInfo for () {
 		// Proof Size summary in bytes:
 		//  Measured:  `351`
 		//  Estimated: `3675`
-		// Minimum execution time: 16_937_000 picoseconds.
-		Weight::from_parts(17_219_000, 3675)
+		// Minimum execution time: 16_268_000 picoseconds.
+		Weight::from_parts(16_764_000, 3675)
 			.saturating_add(RocksDbWeight::get().reads(1_u64))
 			.saturating_add(RocksDbWeight::get().writes(1_u64))
 	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	/// Storage: System Account (r:1 w:1)
+	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
+	fn touch() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `453`
+		//  Estimated: `3675`
+		// Minimum execution time: 37_468_000 picoseconds.
+		Weight::from_parts(37_957_000, 3675)
+			.saturating_add(RocksDbWeight::get().reads(3_u64))
+			.saturating_add(RocksDbWeight::get().writes(3_u64))
+	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	fn touch_other() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `351`
+		//  Estimated: `3675`
+		// Minimum execution time: 383_408_000 picoseconds.
+		Weight::from_parts(392_036_000, 3675)
+			.saturating_add(RocksDbWeight::get().reads(2))
+			.saturating_add(RocksDbWeight::get().writes(2))
+	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	/// Storage: System Account (r:1 w:1)
+	/// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen)
+	fn refund() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `579`
+		//  Estimated: `3675`
+		// Minimum execution time: 34_066_000 picoseconds.
+		Weight::from_parts(34_347_000, 3675)
+			.saturating_add(RocksDbWeight::get().reads(3_u64))
+			.saturating_add(RocksDbWeight::get().writes(3_u64))
+	}
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	/// Storage: Assets Asset (r:1 w:1)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	fn refund_other() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `510`
+		//  Estimated: `3675`
+		// Minimum execution time: 32_060_000 picoseconds.
+		Weight::from_parts(32_519_000, 3675)
+			.saturating_add(RocksDbWeight::get().reads(2_u64))
+			.saturating_add(RocksDbWeight::get().writes(2_u64))
+	}
+	/// Storage: Assets Asset (r:1 w:0)
+	/// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen)
+	/// Storage: Assets Account (r:1 w:1)
+	/// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen)
+	fn block() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `459`
+		//  Estimated: `3675`
+		// Minimum execution time: 115_000_000 picoseconds.
+		Weight::from_parts(163_000_000, 3675)
+			.saturating_add(RocksDbWeight::get().reads(2_u64))
+			.saturating_add(RocksDbWeight::get().writes(1_u64))
+	}
 }
diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs
index b2e6a6138c1638eed85a5f01ebe5f323050fa414..8d0f8aa88dc5edf77af829bbf0e6f6d3a96f9dfd 100644
--- a/substrate/frame/support/src/traits.rs
+++ b/substrate/frame/support/src/traits.rs
@@ -55,8 +55,8 @@ pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter
 mod misc;
 pub use misc::{
 	defensive_prelude::{self, *},
-	Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16,
-	ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating,
+	AccountTouch, Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128,
+	ConstU16, ConstU32, ConstU64, ConstU8, DefensiveMax, DefensiveMin, DefensiveSaturating,
 	DefensiveTruncateFrom, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee,
 	ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType,
 	Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time,
diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs
index a320b85eac557c6c6615af61abecada67c787554..e21fcfbb24179d10e8950d99e4da360a39eac0f8 100644
--- a/substrate/frame/support/src/traits/misc.rs
+++ b/substrate/frame/support/src/traits/misc.rs
@@ -17,7 +17,7 @@
 
 //! Smaller traits used in FRAME which don't need their own file.
 
-use crate::dispatch::Parameter;
+use crate::dispatch::{DispatchResult, Parameter};
 use codec::{CompactLen, Decode, DecodeLimit, Encode, EncodeLike, Input, MaxEncodedLen};
 use impl_trait_for_tuples::impl_for_tuples;
 use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter};
@@ -1154,6 +1154,19 @@ impl<Hash> PreimageRecipient<Hash> for () {
 	fn unnote_preimage(_: &Hash) {}
 }
 
+/// Trait for creating an asset account with a deposit taken from a designated depositor specified
+/// by the client.
+pub trait AccountTouch<AssetId, AccountId> {
+	/// The type for currency units of the deposit.
+	type Balance;
+
+	/// The deposit amount of a native currency required for creating an asset account.
+	fn deposit_required() -> Self::Balance;
+
+	/// Create an account for `who` of the `asset` with a deposit taken from the `depositor`.
+	fn touch(asset: AssetId, who: AccountId, depositor: AccountId) -> DispatchResult;
+}
+
 #[cfg(test)]
 mod test {
 	use super::*;
diff --git a/substrate/frame/support/src/traits/tokens/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs
index 75aef0e04ea6501f610ab7784f7d14983d0477fd..0ba900e95f9b8f25315b8fa471a014b13ea1adc5 100644
--- a/substrate/frame/support/src/traits/tokens/misc.rs
+++ b/substrate/frame/support/src/traits/tokens/misc.rs
@@ -141,6 +141,8 @@ pub enum DepositConsequence {
 	Overflow,
 	/// Account continued in existence.
 	Success,
+	/// Account cannot receive the assets.
+	Blocked,
 }
 
 impl DepositConsequence {
@@ -152,6 +154,7 @@ impl DepositConsequence {
 			CannotCreate => TokenError::CannotCreate.into(),
 			UnknownAsset => TokenError::UnknownAsset.into(),
 			Overflow => ArithmeticError::Overflow.into(),
+			Blocked => TokenError::Blocked.into(),
 			Success => return Ok(()),
 		})
 	}
diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs
index e30146918a4a95a344c8c30a52beec189ef4372e..13ef157dff19e7336804b9e3f7033370815aee58 100644
--- a/substrate/primitives/runtime/src/lib.rs
+++ b/substrate/primitives/runtime/src/lib.rs
@@ -626,6 +626,8 @@ pub enum TokenError {
 	CannotCreateHold,
 	/// Withdrawal would cause unwanted loss of account.
 	NotExpendable,
+	/// Account cannot receive the assets.
+	Blocked,
 }
 
 impl From<TokenError> for &'static str {
@@ -641,6 +643,7 @@ impl From<TokenError> for &'static str {
 			TokenError::CannotCreateHold =>
 				"Account cannot be created for recording amount on hold",
 			TokenError::NotExpendable => "Account that is desired to remain would die",
+			TokenError::Blocked => "Account cannot receive the assets",
 		}
 	}
 }