pallet_assets/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Assets Pallet
19//!
20//! A simple, secure module for dealing with sets of assets implementing
21//! [`fungible`](frame_support::traits::fungible) traits, via [`fungibles`] traits.
22//!
23//! The pallet makes heavy use of concepts such as Holds and Freezes from the
24//! [`frame_support::traits::fungible`] traits, therefore you should read and understand those docs
25//! as a prerequisite to understanding this pallet.
26//!
27//! See the [`frame_tokens`] reference docs for more information about the place of the
28//! Assets pallet in FRAME.
29//!
30//! ## Overview
31//!
32//! The Assets module provides functionality for asset management of fungible asset classes
33//! with a fixed supply, including:
34//!
35//! * Asset Issuance (Minting)
36//! * Asset Transferal
37//! * Asset Freezing
38//! * Asset Destruction (Burning)
39//! * Delegated Asset Transfers ("Approval API")
40//!
41//! To use it in your runtime, you need to implement the assets [`Config`].
42//!
43//! The supported dispatchable functions are documented in the [`Call`] enum.
44//!
45//! ### Terminology
46//!
47//! * **Admin**: An account ID uniquely privileged to be able to unfreeze (thaw) an account and its
48//!   assets, as well as forcibly transfer a particular class of assets between arbitrary accounts
49//!   and reduce the balance of a particular class of assets of arbitrary accounts.
50//! * **Asset issuance/minting**: The creation of a new asset, whose total supply will belong to the
51//!   account designated as the beneficiary of the asset. This is a privileged operation.
52//! * **Asset transfer**: The reduction of the balance of an asset of one account with the
53//!   corresponding increase in the balance of another.
54//! * **Asset destruction**: The process of reducing the balance of an asset of one account. This is
55//!   a privileged operation.
56//! * **Fungible asset**: An asset whose units are interchangeable.
57//! * **Issuer**: An account ID uniquely privileged to be able to mint a particular class of assets.
58//! * **Freezer**: An account ID uniquely privileged to be able to freeze an account from
59//!   transferring a particular class of assets.
60//! * **Freezing**: Removing the possibility of an unpermissioned transfer of an asset from a
61//!   particular account.
62//! * **Non-fungible asset**: An asset for which each unit has unique characteristics.
63//! * **Owner**: An account ID uniquely privileged to be able to destroy a particular asset class,
64//!   or to set the Issuer, Freezer or Admin of that asset class.
65//! * **Approval**: The act of allowing an account the permission to transfer some balance of asset
66//!   from the approving account into some third-party destination account.
67//! * **Sufficiency**: The idea of a minimum-balance of an asset being sufficient to allow the
68//!   account's existence on the system without requiring any other existential-deposit.
69//!
70//! ### Goals
71//!
72//! The assets system in Substrate is designed to make the following possible:
73//!
74//! * Issue new assets in a permissioned or permissionless way, if permissionless, then with a
75//!   deposit required.
76//! * Allow accounts to be delegated the ability to transfer assets without otherwise existing
77//!   on-chain (*approvals*).
78//! * Move assets between accounts.
79//! * Update an asset class's total supply.
80//! * Allow administrative activities by specially privileged accounts including freezing account
81//!   balances and minting/burning assets.
82//!
83//! ## Interface
84//!
85//! ### Permissionless Functions
86//!
87//! * `create`: Creates a new asset class, taking the required deposit.
88//! * `transfer`: Transfer sender's assets to another account.
89//! * `transfer_keep_alive`: Transfer sender's assets to another account, keeping the sender alive.
90//! * `approve_transfer`: Create or increase an delegated transfer.
91//! * `cancel_approval`: Rescind a previous approval.
92//! * `transfer_approved`: Transfer third-party's assets to another account.
93//! * `touch`: Create an asset account for non-provider assets. Caller must place a deposit.
94//! * `refund`: Return the deposit (if any) of the caller's asset account or a consumer reference
95//!   (if any) of the caller's account.
96//! * `refund_other`: Return the deposit (if any) of a specified asset account.
97//!
98//! ### Permissioned Functions
99//!
100//! * `force_create`: Creates a new asset class without taking any deposit.
101//! * `force_set_metadata`: Set the metadata of an asset class.
102//! * `force_clear_metadata`: Remove the metadata of an asset class.
103//! * `force_asset_status`: Alter an asset class's attributes.
104//! * `force_cancel_approval`: Rescind a previous approval.
105//!
106//! ### Privileged Functions
107//!
108//! * `destroy`: Destroys an entire asset class; called by the asset class's Owner.
109//! * `mint`: Increases the asset balance of an account; called by the asset class's Issuer.
110//! * `burn`: Decreases the asset balance of an account; called by the asset class's Admin.
111//! * `force_transfer`: Transfers between arbitrary accounts; called by the asset class's Admin.
112//! * `freeze`: Disallows further `transfer`s from an account; called by the asset class's Freezer.
113//! * `thaw`: Allows further `transfer`s to and from an account; called by the asset class's Admin.
114//! * `transfer_ownership`: Changes an asset class's Owner; called by the asset class's Owner.
115//! * `set_team`: Changes an asset class's Admin, Freezer and Issuer; called by the asset class's
116//!   Owner.
117//! * `set_metadata`: Set the metadata of an asset class; called by the asset class's Owner.
118//! * `clear_metadata`: Remove the metadata of an asset class; called by the asset class's Owner.
119//! * `touch_other`: Create an asset account for specified account. Caller must place a deposit;
120//!   called by the asset class's Freezer or Admin.
121//! * `block`: Disallows further `transfer`s to and from an account; called by the asset class's
122//!   Freezer.
123//!
124//! Please refer to the [`Call`] enum and its associated variants for documentation on each
125//! function.
126//!
127//! ### Public Functions
128//! <!-- Original author of descriptions: @gavofyork -->
129//!
130//! * `balance` - Get the asset `id` balance of `who`.
131//! * `total_supply` - Get the total supply of an asset `id`.
132//!
133//! Please refer to the [`Pallet`] struct for details on publicly available functions.
134//!
135//! ### Callbacks
136//!
137//! Using `CallbackHandle` associated type, user can configure custom callback functions which are
138//! executed when new asset is created or an existing asset is destroyed.
139//!
140//! ## Related Modules
141//!
142//! * [`System`](../frame_system/index.html)
143//! * [`Support`](../frame_support/index.html)
144//!
145//! [`frame_tokens`]: ../polkadot_sdk_docs/reference_docs/frame_tokens/index.html
146
147// This recursion limit is needed because we have too many benchmarks and benchmarking will fail if
148// we add more without this limit.
149#![recursion_limit = "1024"]
150// Ensure we're `no_std` when compiling for Wasm.
151#![cfg_attr(not(feature = "std"), no_std)]
152
153#[cfg(feature = "runtime-benchmarks")]
154pub mod benchmarking;
155pub mod migration;
156#[cfg(test)]
157pub mod mock;
158#[cfg(test)]
159mod tests;
160pub mod weights;
161
162mod extra_mutator;
163pub use extra_mutator::*;
164mod functions;
165mod impl_fungibles;
166mod impl_stored_map;
167mod types;
168pub use types::*;
169
170extern crate alloc;
171
172use scale_info::TypeInfo;
173use sp_runtime::{
174	traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Saturating, StaticLookup, Zero},
175	ArithmeticError, DispatchError, TokenError,
176};
177
178use alloc::vec::Vec;
179use core::marker::PhantomData;
180use frame_support::{
181	dispatch::DispatchResult,
182	ensure,
183	pallet_prelude::DispatchResultWithPostInfo,
184	storage::KeyPrefixIterator,
185	traits::{
186		tokens::{
187			fungibles, DepositConsequence, Fortitude,
188			Preservation::{Expendable, Preserve},
189			WithdrawConsequence,
190		},
191		BalanceStatus::Reserved,
192		Currency, EnsureOriginWithArg, Incrementable, ReservableCurrency, StoredMap,
193	},
194};
195use frame_system::Config as SystemConfig;
196
197pub use pallet::*;
198pub use weights::WeightInfo;
199
200type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
201const LOG_TARGET: &str = "runtime::assets";
202
203/// Trait with callbacks that are executed after successful asset creation or destruction.
204pub trait AssetsCallback<AssetId, AccountId> {
205	/// Indicates that asset with `id` was successfully created by the `owner`
206	fn created(_id: &AssetId, _owner: &AccountId) -> Result<(), ()> {
207		Ok(())
208	}
209
210	/// Indicates that asset with `id` has just been destroyed
211	fn destroyed(_id: &AssetId) -> Result<(), ()> {
212		Ok(())
213	}
214}
215
216#[impl_trait_for_tuples::impl_for_tuples(10)]
217impl<AssetId, AccountId> AssetsCallback<AssetId, AccountId> for Tuple {
218	fn created(id: &AssetId, owner: &AccountId) -> Result<(), ()> {
219		for_tuples!( #( Tuple::created(id, owner)?; )* );
220		Ok(())
221	}
222
223	fn destroyed(id: &AssetId) -> Result<(), ()> {
224		for_tuples!( #( Tuple::destroyed(id)?; )* );
225		Ok(())
226	}
227}
228
229/// Auto-increment the [`NextAssetId`] when an asset is created.
230///
231/// This has not effect if the [`NextAssetId`] value is not present.
232pub struct AutoIncAssetId<T, I = ()>(PhantomData<(T, I)>);
233impl<T: Config<I>, I> AssetsCallback<T::AssetId, T::AccountId> for AutoIncAssetId<T, I>
234where
235	T::AssetId: Incrementable,
236{
237	fn created(_: &T::AssetId, _: &T::AccountId) -> Result<(), ()> {
238		let Some(next_id) = NextAssetId::<T, I>::get() else {
239			// Auto increment for the asset id is not enabled.
240			return Ok(());
241		};
242		let next_id = next_id.increment().ok_or(())?;
243		NextAssetId::<T, I>::put(next_id);
244		Ok(())
245	}
246}
247
248#[frame_support::pallet]
249pub mod pallet {
250	use super::*;
251	use frame_support::{
252		pallet_prelude::*,
253		traits::{AccountTouch, ContainsPair},
254	};
255	use frame_system::pallet_prelude::*;
256
257	/// The in-code storage version.
258	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
259
260	#[pallet::pallet]
261	#[pallet::storage_version(STORAGE_VERSION)]
262	pub struct Pallet<T, I = ()>(_);
263
264	#[cfg(feature = "runtime-benchmarks")]
265	pub trait BenchmarkHelper<AssetIdParameter> {
266		fn create_asset_id_parameter(id: u32) -> AssetIdParameter;
267	}
268	#[cfg(feature = "runtime-benchmarks")]
269	impl<AssetIdParameter: From<u32>> BenchmarkHelper<AssetIdParameter> for () {
270		fn create_asset_id_parameter(id: u32) -> AssetIdParameter {
271			id.into()
272		}
273	}
274
275	/// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
276	pub mod config_preludes {
277		use super::*;
278		use frame_support::{derive_impl, traits::ConstU64};
279		pub struct TestDefaultConfig;
280
281		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
282		impl frame_system::DefaultConfig for TestDefaultConfig {}
283
284		#[frame_support::register_default_impl(TestDefaultConfig)]
285		impl DefaultConfig for TestDefaultConfig {
286			#[inject_runtime_type]
287			type RuntimeEvent = ();
288			type Balance = u64;
289			type RemoveItemsLimit = ConstU32<5>;
290			type AssetId = u32;
291			type AssetIdParameter = u32;
292			type AssetDeposit = ConstU64<1>;
293			type AssetAccountDeposit = ConstU64<10>;
294			type MetadataDepositBase = ConstU64<1>;
295			type MetadataDepositPerByte = ConstU64<1>;
296			type ApprovalDeposit = ConstU64<1>;
297			type StringLimit = ConstU32<50>;
298			type Extra = ();
299			type CallbackHandle = ();
300			type WeightInfo = ();
301			#[cfg(feature = "runtime-benchmarks")]
302			type BenchmarkHelper = ();
303		}
304	}
305
306	#[pallet::config(with_default)]
307	/// The module configuration trait.
308	pub trait Config<I: 'static = ()>: frame_system::Config {
309		/// The overarching event type.
310		#[pallet::no_default_bounds]
311		type RuntimeEvent: From<Event<Self, I>>
312			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
313
314		/// The units in which we record balances.
315		type Balance: Member
316			+ Parameter
317			+ AtLeast32BitUnsigned
318			+ Default
319			+ Copy
320			+ MaybeSerializeDeserialize
321			+ MaxEncodedLen
322			+ TypeInfo;
323
324		/// Max number of items to destroy per `destroy_accounts` and `destroy_approvals` call.
325		///
326		/// Must be configured to result in a weight that makes each call fit in a block.
327		#[pallet::constant]
328		type RemoveItemsLimit: Get<u32>;
329
330		/// Identifier for the class of asset.
331		type AssetId: Member + Parameter + Clone + MaybeSerializeDeserialize + MaxEncodedLen;
332
333		/// Wrapper around `Self::AssetId` to use in dispatchable call signatures. Allows the use
334		/// of compact encoding in instances of the pallet, which will prevent breaking changes
335		/// resulting from the removal of `HasCompact` from `Self::AssetId`.
336		///
337		/// This type includes the `From<Self::AssetId>` bound, since tightly coupled pallets may
338		/// want to convert an `AssetId` into a parameter for calling dispatchable functions
339		/// directly.
340		type AssetIdParameter: Parameter + From<Self::AssetId> + Into<Self::AssetId> + MaxEncodedLen;
341
342		/// The currency mechanism.
343		#[pallet::no_default]
344		type Currency: ReservableCurrency<Self::AccountId>;
345
346		/// Standard asset class creation is only allowed if the origin attempting it and the
347		/// asset class are in this set.
348		#[pallet::no_default]
349		type CreateOrigin: EnsureOriginWithArg<
350			Self::RuntimeOrigin,
351			Self::AssetId,
352			Success = Self::AccountId,
353		>;
354
355		/// The origin which may forcibly create or destroy an asset or otherwise alter privileged
356		/// attributes.
357		#[pallet::no_default]
358		type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
359
360		/// The basic amount of funds that must be reserved for an asset.
361		#[pallet::constant]
362		#[pallet::no_default_bounds]
363		type AssetDeposit: Get<DepositBalanceOf<Self, I>>;
364
365		/// The amount of funds that must be reserved for a non-provider asset account to be
366		/// maintained.
367		#[pallet::constant]
368		#[pallet::no_default_bounds]
369		type AssetAccountDeposit: Get<DepositBalanceOf<Self, I>>;
370
371		/// The basic amount of funds that must be reserved when adding metadata to your asset.
372		#[pallet::constant]
373		#[pallet::no_default_bounds]
374		type MetadataDepositBase: Get<DepositBalanceOf<Self, I>>;
375
376		/// The additional funds that must be reserved for the number of bytes you store in your
377		/// metadata.
378		#[pallet::constant]
379		#[pallet::no_default_bounds]
380		type MetadataDepositPerByte: Get<DepositBalanceOf<Self, I>>;
381
382		/// The amount of funds that must be reserved when creating a new approval.
383		#[pallet::constant]
384		#[pallet::no_default_bounds]
385		type ApprovalDeposit: Get<DepositBalanceOf<Self, I>>;
386
387		/// The maximum length of a name or symbol stored on-chain.
388		#[pallet::constant]
389		type StringLimit: Get<u32>;
390
391		/// A hook to allow a per-asset, per-account minimum balance to be enforced. This must be
392		/// respected in all permissionless operations.
393		#[pallet::no_default]
394		type Freezer: FrozenBalance<Self::AssetId, Self::AccountId, Self::Balance>;
395
396		/// Additional data to be stored with an account's asset balance.
397		type Extra: Member + Parameter + Default + MaxEncodedLen;
398
399		/// Callback methods for asset state change (e.g. asset created or destroyed)
400		///
401		/// Types implementing the [`AssetsCallback`] can be chained when listed together as a
402		/// tuple.
403		/// The [`AutoIncAssetId`] callback, in conjunction with the [`NextAssetId`], can be
404		/// used to set up auto-incrementing asset IDs for this collection.
405		type CallbackHandle: AssetsCallback<Self::AssetId, Self::AccountId>;
406
407		/// Weight information for extrinsics in this pallet.
408		type WeightInfo: WeightInfo;
409
410		/// Helper trait for benchmarks.
411		#[cfg(feature = "runtime-benchmarks")]
412		type BenchmarkHelper: BenchmarkHelper<Self::AssetIdParameter>;
413	}
414
415	#[pallet::storage]
416	/// Details of an asset.
417	pub(super) type Asset<T: Config<I>, I: 'static = ()> = StorageMap<
418		_,
419		Blake2_128Concat,
420		T::AssetId,
421		AssetDetails<T::Balance, T::AccountId, DepositBalanceOf<T, I>>,
422	>;
423
424	#[pallet::storage]
425	/// The holdings of a specific account for a specific asset.
426	pub(super) type Account<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
427		_,
428		Blake2_128Concat,
429		T::AssetId,
430		Blake2_128Concat,
431		T::AccountId,
432		AssetAccountOf<T, I>,
433	>;
434
435	#[pallet::storage]
436	/// Approved balance transfers. First balance is the amount approved for transfer. Second
437	/// is the amount of `T::Currency` reserved for storing this.
438	/// First key is the asset ID, second key is the owner and third key is the delegate.
439	pub(super) type Approvals<T: Config<I>, I: 'static = ()> = StorageNMap<
440		_,
441		(
442			NMapKey<Blake2_128Concat, T::AssetId>,
443			NMapKey<Blake2_128Concat, T::AccountId>, // owner
444			NMapKey<Blake2_128Concat, T::AccountId>, // delegate
445		),
446		Approval<T::Balance, DepositBalanceOf<T, I>>,
447	>;
448
449	#[pallet::storage]
450	/// Metadata of an asset.
451	pub(super) type Metadata<T: Config<I>, I: 'static = ()> = StorageMap<
452		_,
453		Blake2_128Concat,
454		T::AssetId,
455		AssetMetadata<DepositBalanceOf<T, I>, BoundedVec<u8, T::StringLimit>>,
456		ValueQuery,
457	>;
458
459	/// The asset ID enforced for the next asset creation, if any present. Otherwise, this storage
460	/// item has no effect.
461	///
462	/// This can be useful for setting up constraints for IDs of the new assets. For example, by
463	/// providing an initial [`NextAssetId`] and using the [`crate::AutoIncAssetId`] callback, an
464	/// auto-increment model can be applied to all new asset IDs.
465	///
466	/// The initial next asset ID can be set using the [`GenesisConfig`] or the
467	/// [SetNextAssetId](`migration::next_asset_id::SetNextAssetId`) migration.
468	#[pallet::storage]
469	pub type NextAssetId<T: Config<I>, I: 'static = ()> = StorageValue<_, T::AssetId, OptionQuery>;
470
471	#[pallet::genesis_config]
472	#[derive(frame_support::DefaultNoBound)]
473	pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
474		/// Genesis assets: id, owner, is_sufficient, min_balance
475		pub assets: Vec<(T::AssetId, T::AccountId, bool, T::Balance)>,
476		/// Genesis metadata: id, name, symbol, decimals
477		pub metadata: Vec<(T::AssetId, Vec<u8>, Vec<u8>, u8)>,
478		/// Genesis accounts: id, account_id, balance
479		pub accounts: Vec<(T::AssetId, T::AccountId, T::Balance)>,
480		/// Genesis [`NextAssetId`].
481		///
482		/// Refer to the [`NextAssetId`] item for more information.
483		///
484		/// This does not enforce the asset ID for the [assets](`GenesisConfig::assets`) within the
485		/// genesis config. It sets the [`NextAssetId`] after they have been created.
486		pub next_asset_id: Option<T::AssetId>,
487	}
488
489	#[pallet::genesis_build]
490	impl<T: Config<I>, I: 'static> BuildGenesisConfig for GenesisConfig<T, I> {
491		fn build(&self) {
492			for (id, owner, is_sufficient, min_balance) in &self.assets {
493				assert!(!Asset::<T, I>::contains_key(id), "Asset id already in use");
494				assert!(!min_balance.is_zero(), "Min balance should not be zero");
495				Asset::<T, I>::insert(
496					id,
497					AssetDetails {
498						owner: owner.clone(),
499						issuer: owner.clone(),
500						admin: owner.clone(),
501						freezer: owner.clone(),
502						supply: Zero::zero(),
503						deposit: Zero::zero(),
504						min_balance: *min_balance,
505						is_sufficient: *is_sufficient,
506						accounts: 0,
507						sufficients: 0,
508						approvals: 0,
509						status: AssetStatus::Live,
510					},
511				);
512			}
513
514			for (id, name, symbol, decimals) in &self.metadata {
515				assert!(Asset::<T, I>::contains_key(id), "Asset does not exist");
516
517				let bounded_name: BoundedVec<u8, T::StringLimit> =
518					name.clone().try_into().expect("asset name is too long");
519				let bounded_symbol: BoundedVec<u8, T::StringLimit> =
520					symbol.clone().try_into().expect("asset symbol is too long");
521
522				let metadata = AssetMetadata {
523					deposit: Zero::zero(),
524					name: bounded_name,
525					symbol: bounded_symbol,
526					decimals: *decimals,
527					is_frozen: false,
528				};
529				Metadata::<T, I>::insert(id, metadata);
530			}
531
532			for (id, account_id, amount) in &self.accounts {
533				let result = <Pallet<T, I>>::increase_balance(
534					id.clone(),
535					account_id,
536					*amount,
537					|details| -> DispatchResult {
538						debug_assert!(
539							details.supply.checked_add(&amount).is_some(),
540							"checked in prep; qed"
541						);
542						details.supply = details.supply.saturating_add(*amount);
543						Ok(())
544					},
545				);
546				assert!(result.is_ok());
547			}
548
549			if let Some(next_asset_id) = &self.next_asset_id {
550				NextAssetId::<T, I>::put(next_asset_id);
551			}
552		}
553	}
554
555	#[pallet::event]
556	#[pallet::generate_deposit(pub(super) fn deposit_event)]
557	pub enum Event<T: Config<I>, I: 'static = ()> {
558		/// Some asset class was created.
559		Created { asset_id: T::AssetId, creator: T::AccountId, owner: T::AccountId },
560		/// Some assets were issued.
561		Issued { asset_id: T::AssetId, owner: T::AccountId, amount: T::Balance },
562		/// Some assets were transferred.
563		Transferred {
564			asset_id: T::AssetId,
565			from: T::AccountId,
566			to: T::AccountId,
567			amount: T::Balance,
568		},
569		/// Some assets were destroyed.
570		Burned { asset_id: T::AssetId, owner: T::AccountId, balance: T::Balance },
571		/// The management team changed.
572		TeamChanged {
573			asset_id: T::AssetId,
574			issuer: T::AccountId,
575			admin: T::AccountId,
576			freezer: T::AccountId,
577		},
578		/// The owner changed.
579		OwnerChanged { asset_id: T::AssetId, owner: T::AccountId },
580		/// Some account `who` was frozen.
581		Frozen { asset_id: T::AssetId, who: T::AccountId },
582		/// Some account `who` was thawed.
583		Thawed { asset_id: T::AssetId, who: T::AccountId },
584		/// Some asset `asset_id` was frozen.
585		AssetFrozen { asset_id: T::AssetId },
586		/// Some asset `asset_id` was thawed.
587		AssetThawed { asset_id: T::AssetId },
588		/// Accounts were destroyed for given asset.
589		AccountsDestroyed { asset_id: T::AssetId, accounts_destroyed: u32, accounts_remaining: u32 },
590		/// Approvals were destroyed for given asset.
591		ApprovalsDestroyed {
592			asset_id: T::AssetId,
593			approvals_destroyed: u32,
594			approvals_remaining: u32,
595		},
596		/// An asset class is in the process of being destroyed.
597		DestructionStarted { asset_id: T::AssetId },
598		/// An asset class was destroyed.
599		Destroyed { asset_id: T::AssetId },
600		/// Some asset class was force-created.
601		ForceCreated { asset_id: T::AssetId, owner: T::AccountId },
602		/// New metadata has been set for an asset.
603		MetadataSet {
604			asset_id: T::AssetId,
605			name: Vec<u8>,
606			symbol: Vec<u8>,
607			decimals: u8,
608			is_frozen: bool,
609		},
610		/// Metadata has been cleared for an asset.
611		MetadataCleared { asset_id: T::AssetId },
612		/// (Additional) funds have been approved for transfer to a destination account.
613		ApprovedTransfer {
614			asset_id: T::AssetId,
615			source: T::AccountId,
616			delegate: T::AccountId,
617			amount: T::Balance,
618		},
619		/// An approval for account `delegate` was cancelled by `owner`.
620		ApprovalCancelled { asset_id: T::AssetId, owner: T::AccountId, delegate: T::AccountId },
621		/// An `amount` was transferred in its entirety from `owner` to `destination` by
622		/// the approved `delegate`.
623		TransferredApproved {
624			asset_id: T::AssetId,
625			owner: T::AccountId,
626			delegate: T::AccountId,
627			destination: T::AccountId,
628			amount: T::Balance,
629		},
630		/// An asset has had its attributes changed by the `Force` origin.
631		AssetStatusChanged { asset_id: T::AssetId },
632		/// The min_balance of an asset has been updated by the asset owner.
633		AssetMinBalanceChanged { asset_id: T::AssetId, new_min_balance: T::Balance },
634		/// Some account `who` was created with a deposit from `depositor`.
635		Touched { asset_id: T::AssetId, who: T::AccountId, depositor: T::AccountId },
636		/// Some account `who` was blocked.
637		Blocked { asset_id: T::AssetId, who: T::AccountId },
638		/// Some assets were deposited (e.g. for transaction fees).
639		Deposited { asset_id: T::AssetId, who: T::AccountId, amount: T::Balance },
640		/// Some assets were withdrawn from the account (e.g. for transaction fees).
641		Withdrawn { asset_id: T::AssetId, who: T::AccountId, amount: T::Balance },
642	}
643
644	#[pallet::error]
645	pub enum Error<T, I = ()> {
646		/// Account balance must be greater than or equal to the transfer amount.
647		BalanceLow,
648		/// The account to alter does not exist.
649		NoAccount,
650		/// The signing account has no permission to do the operation.
651		NoPermission,
652		/// The given asset ID is unknown.
653		Unknown,
654		/// The origin account is frozen.
655		Frozen,
656		/// The asset ID is already taken.
657		InUse,
658		/// Invalid witness data given.
659		BadWitness,
660		/// Minimum balance should be non-zero.
661		MinBalanceZero,
662		/// Unable to increment the consumer reference counters on the account. Either no provider
663		/// reference exists to allow a non-zero balance of a non-self-sufficient asset, or one
664		/// fewer then the maximum number of consumers has been reached.
665		UnavailableConsumer,
666		/// Invalid metadata given.
667		BadMetadata,
668		/// No approval exists that would allow the transfer.
669		Unapproved,
670		/// The source account would not survive the transfer and it needs to stay alive.
671		WouldDie,
672		/// The asset-account already exists.
673		AlreadyExists,
674		/// The asset-account doesn't have an associated deposit.
675		NoDeposit,
676		/// The operation would result in funds being burned.
677		WouldBurn,
678		/// The asset is a live asset and is actively being used. Usually emit for operations such
679		/// as `start_destroy` which require the asset to be in a destroying state.
680		LiveAsset,
681		/// The asset is not live, and likely being destroyed.
682		AssetNotLive,
683		/// The asset status is not the expected status.
684		IncorrectStatus,
685		/// The asset should be frozen before the given operation.
686		NotFrozen,
687		/// Callback action resulted in error
688		CallbackFailed,
689		/// The asset ID must be equal to the [`NextAssetId`].
690		BadAssetId,
691	}
692
693	#[pallet::call(weight(<T as Config<I>>::WeightInfo))]
694	impl<T: Config<I>, I: 'static> Pallet<T, I> {
695		/// Issue a new class of fungible assets from a public origin.
696		///
697		/// This new asset class has no assets initially and its owner is the origin.
698		///
699		/// The origin must conform to the configured `CreateOrigin` and have sufficient funds free.
700		///
701		/// Funds of sender are reserved by `AssetDeposit`.
702		///
703		/// Parameters:
704		/// - `id`: The identifier of the new asset. This must not be currently in use to identify
705		/// an existing asset. If [`NextAssetId`] is set, then this must be equal to it.
706		/// - `admin`: The admin of this class of assets. The admin is the initial address of each
707		/// member of the asset class's admin team.
708		/// - `min_balance`: The minimum balance of this new asset that any single account must
709		/// have. If an account's balance is reduced below this, then it collapses to zero.
710		///
711		/// Emits `Created` event when successful.
712		///
713		/// Weight: `O(1)`
714		#[pallet::call_index(0)]
715		pub fn create(
716			origin: OriginFor<T>,
717			id: T::AssetIdParameter,
718			admin: AccountIdLookupOf<T>,
719			min_balance: T::Balance,
720		) -> DispatchResult {
721			let id: T::AssetId = id.into();
722			let owner = T::CreateOrigin::ensure_origin(origin, &id)?;
723			let admin = T::Lookup::lookup(admin)?;
724
725			ensure!(!Asset::<T, I>::contains_key(&id), Error::<T, I>::InUse);
726			ensure!(!min_balance.is_zero(), Error::<T, I>::MinBalanceZero);
727
728			if let Some(next_id) = NextAssetId::<T, I>::get() {
729				ensure!(id == next_id, Error::<T, I>::BadAssetId);
730			}
731
732			let deposit = T::AssetDeposit::get();
733			T::Currency::reserve(&owner, deposit)?;
734
735			Asset::<T, I>::insert(
736				id.clone(),
737				AssetDetails {
738					owner: owner.clone(),
739					issuer: admin.clone(),
740					admin: admin.clone(),
741					freezer: admin.clone(),
742					supply: Zero::zero(),
743					deposit,
744					min_balance,
745					is_sufficient: false,
746					accounts: 0,
747					sufficients: 0,
748					approvals: 0,
749					status: AssetStatus::Live,
750				},
751			);
752			ensure!(T::CallbackHandle::created(&id, &owner).is_ok(), Error::<T, I>::CallbackFailed);
753			Self::deposit_event(Event::Created {
754				asset_id: id,
755				creator: owner.clone(),
756				owner: admin,
757			});
758
759			Ok(())
760		}
761
762		/// Issue a new class of fungible assets from a privileged origin.
763		///
764		/// This new asset class has no assets initially.
765		///
766		/// The origin must conform to `ForceOrigin`.
767		///
768		/// Unlike `create`, no funds are reserved.
769		///
770		/// - `id`: The identifier of the new asset. This must not be currently in use to identify
771		/// an existing asset. If [`NextAssetId`] is set, then this must be equal to it.
772		/// - `owner`: The owner of this class of assets. The owner has full superuser permissions
773		/// over this asset, but may later change and configure the permissions using
774		/// `transfer_ownership` and `set_team`.
775		/// - `min_balance`: The minimum balance of this new asset that any single account must
776		/// have. If an account's balance is reduced below this, then it collapses to zero.
777		///
778		/// Emits `ForceCreated` event when successful.
779		///
780		/// Weight: `O(1)`
781		#[pallet::call_index(1)]
782		pub fn force_create(
783			origin: OriginFor<T>,
784			id: T::AssetIdParameter,
785			owner: AccountIdLookupOf<T>,
786			is_sufficient: bool,
787			#[pallet::compact] min_balance: T::Balance,
788		) -> DispatchResult {
789			T::ForceOrigin::ensure_origin(origin)?;
790			let owner = T::Lookup::lookup(owner)?;
791			let id: T::AssetId = id.into();
792			Self::do_force_create(id, owner, is_sufficient, min_balance)
793		}
794
795		/// Start the process of destroying a fungible asset class.
796		///
797		/// `start_destroy` is the first in a series of extrinsics that should be called, to allow
798		/// destruction of an asset class.
799		///
800		/// The origin must conform to `ForceOrigin` or must be `Signed` by the asset's `owner`.
801		///
802		/// - `id`: The identifier of the asset to be destroyed. This must identify an existing
803		///   asset.
804		#[pallet::call_index(2)]
805		pub fn start_destroy(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
806			let maybe_check_owner = match T::ForceOrigin::try_origin(origin) {
807				Ok(_) => None,
808				Err(origin) => Some(ensure_signed(origin)?),
809			};
810			let id: T::AssetId = id.into();
811			Self::do_start_destroy(id, maybe_check_owner)
812		}
813
814		/// Destroy all accounts associated with a given asset.
815		///
816		/// `destroy_accounts` should only be called after `start_destroy` has been called, and the
817		/// asset is in a `Destroying` state.
818		///
819		/// Due to weight restrictions, this function may need to be called multiple times to fully
820		/// destroy all accounts. It will destroy `RemoveItemsLimit` accounts at a time.
821		///
822		/// - `id`: The identifier of the asset to be destroyed. This must identify an existing
823		///   asset.
824		///
825		/// Each call emits the `Event::DestroyedAccounts` event.
826		#[pallet::call_index(3)]
827		#[pallet::weight(T::WeightInfo::destroy_accounts(T::RemoveItemsLimit::get()))]
828		pub fn destroy_accounts(
829			origin: OriginFor<T>,
830			id: T::AssetIdParameter,
831		) -> DispatchResultWithPostInfo {
832			let _ = ensure_signed(origin)?;
833			let id: T::AssetId = id.into();
834			let removed_accounts = Self::do_destroy_accounts(id, T::RemoveItemsLimit::get())?;
835			Ok(Some(T::WeightInfo::destroy_accounts(removed_accounts)).into())
836		}
837
838		/// Destroy all approvals associated with a given asset up to the max (T::RemoveItemsLimit).
839		///
840		/// `destroy_approvals` should only be called after `start_destroy` has been called, and the
841		/// asset is in a `Destroying` state.
842		///
843		/// Due to weight restrictions, this function may need to be called multiple times to fully
844		/// destroy all approvals. It will destroy `RemoveItemsLimit` approvals at a time.
845		///
846		/// - `id`: The identifier of the asset to be destroyed. This must identify an existing
847		///   asset.
848		///
849		/// Each call emits the `Event::DestroyedApprovals` event.
850		#[pallet::call_index(4)]
851		#[pallet::weight(T::WeightInfo::destroy_approvals(T::RemoveItemsLimit::get()))]
852		pub fn destroy_approvals(
853			origin: OriginFor<T>,
854			id: T::AssetIdParameter,
855		) -> DispatchResultWithPostInfo {
856			let _ = ensure_signed(origin)?;
857			let id: T::AssetId = id.into();
858			let removed_approvals = Self::do_destroy_approvals(id, T::RemoveItemsLimit::get())?;
859			Ok(Some(T::WeightInfo::destroy_approvals(removed_approvals)).into())
860		}
861
862		/// Complete destroying asset and unreserve currency.
863		///
864		/// `finish_destroy` should only be called after `start_destroy` has been called, and the
865		/// asset is in a `Destroying` state. All accounts or approvals should be destroyed before
866		/// hand.
867		///
868		/// - `id`: The identifier of the asset to be destroyed. This must identify an existing
869		///   asset.
870		///
871		/// Each successful call emits the `Event::Destroyed` event.
872		#[pallet::call_index(5)]
873		pub fn finish_destroy(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
874			let _ = ensure_signed(origin)?;
875			let id: T::AssetId = id.into();
876			Self::do_finish_destroy(id)
877		}
878
879		/// Mint assets of a particular class.
880		///
881		/// The origin must be Signed and the sender must be the Issuer of the asset `id`.
882		///
883		/// - `id`: The identifier of the asset to have some amount minted.
884		/// - `beneficiary`: The account to be credited with the minted assets.
885		/// - `amount`: The amount of the asset to be minted.
886		///
887		/// Emits `Issued` event when successful.
888		///
889		/// Weight: `O(1)`
890		/// Modes: Pre-existing balance of `beneficiary`; Account pre-existence of `beneficiary`.
891		#[pallet::call_index(6)]
892		pub fn mint(
893			origin: OriginFor<T>,
894			id: T::AssetIdParameter,
895			beneficiary: AccountIdLookupOf<T>,
896			#[pallet::compact] amount: T::Balance,
897		) -> DispatchResult {
898			let origin = ensure_signed(origin)?;
899			let beneficiary = T::Lookup::lookup(beneficiary)?;
900			let id: T::AssetId = id.into();
901			Self::do_mint(id, &beneficiary, amount, Some(origin))?;
902			Ok(())
903		}
904
905		/// Reduce the balance of `who` by as much as possible up to `amount` assets of `id`.
906		///
907		/// Origin must be Signed and the sender should be the Manager of the asset `id`.
908		///
909		/// Bails with `NoAccount` if the `who` is already dead.
910		///
911		/// - `id`: The identifier of the asset to have some amount burned.
912		/// - `who`: The account to be debited from.
913		/// - `amount`: The maximum amount by which `who`'s balance should be reduced.
914		///
915		/// Emits `Burned` with the actual amount burned. If this takes the balance to below the
916		/// minimum for the asset, then the amount burned is increased to take it to zero.
917		///
918		/// Weight: `O(1)`
919		/// Modes: Post-existence of `who`; Pre & post Zombie-status of `who`.
920		#[pallet::call_index(7)]
921		pub fn burn(
922			origin: OriginFor<T>,
923			id: T::AssetIdParameter,
924			who: AccountIdLookupOf<T>,
925			#[pallet::compact] amount: T::Balance,
926		) -> DispatchResult {
927			let origin = ensure_signed(origin)?;
928			let who = T::Lookup::lookup(who)?;
929			let id: T::AssetId = id.into();
930
931			let f = DebitFlags { keep_alive: false, best_effort: true };
932			let _ = Self::do_burn(id, &who, amount, Some(origin), f)?;
933			Ok(())
934		}
935
936		/// Move some assets from the sender account to another.
937		///
938		/// Origin must be Signed.
939		///
940		/// - `id`: The identifier of the asset to have some amount transferred.
941		/// - `target`: The account to be credited.
942		/// - `amount`: The amount by which the sender's balance of assets should be reduced and
943		/// `target`'s balance increased. The amount actually transferred may be slightly greater in
944		/// the case that the transfer would otherwise take the sender balance above zero but below
945		/// the minimum balance. Must be greater than zero.
946		///
947		/// Emits `Transferred` with the actual amount transferred. If this takes the source balance
948		/// to below the minimum for the asset, then the amount transferred is increased to take it
949		/// to zero.
950		///
951		/// Weight: `O(1)`
952		/// Modes: Pre-existence of `target`; Post-existence of sender; Account pre-existence of
953		/// `target`.
954		#[pallet::call_index(8)]
955		pub fn transfer(
956			origin: OriginFor<T>,
957			id: T::AssetIdParameter,
958			target: AccountIdLookupOf<T>,
959			#[pallet::compact] amount: T::Balance,
960		) -> DispatchResult {
961			let origin = ensure_signed(origin)?;
962			let dest = T::Lookup::lookup(target)?;
963			let id: T::AssetId = id.into();
964
965			let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false };
966			Self::do_transfer(id, &origin, &dest, amount, None, f).map(|_| ())
967		}
968
969		/// Move some assets from the sender account to another, keeping the sender account alive.
970		///
971		/// Origin must be Signed.
972		///
973		/// - `id`: The identifier of the asset to have some amount transferred.
974		/// - `target`: The account to be credited.
975		/// - `amount`: The amount by which the sender's balance of assets should be reduced and
976		/// `target`'s balance increased. The amount actually transferred may be slightly greater in
977		/// the case that the transfer would otherwise take the sender balance above zero but below
978		/// the minimum balance. Must be greater than zero.
979		///
980		/// Emits `Transferred` with the actual amount transferred. If this takes the source balance
981		/// to below the minimum for the asset, then the amount transferred is increased to take it
982		/// to zero.
983		///
984		/// Weight: `O(1)`
985		/// Modes: Pre-existence of `target`; Post-existence of sender; Account pre-existence of
986		/// `target`.
987		#[pallet::call_index(9)]
988		pub fn transfer_keep_alive(
989			origin: OriginFor<T>,
990			id: T::AssetIdParameter,
991			target: AccountIdLookupOf<T>,
992			#[pallet::compact] amount: T::Balance,
993		) -> DispatchResult {
994			let source = ensure_signed(origin)?;
995			let dest = T::Lookup::lookup(target)?;
996			let id: T::AssetId = id.into();
997
998			let f = TransferFlags { keep_alive: true, best_effort: false, burn_dust: false };
999			Self::do_transfer(id, &source, &dest, amount, None, f).map(|_| ())
1000		}
1001
1002		/// Move some assets from one account to another.
1003		///
1004		/// Origin must be Signed and the sender should be the Admin of the asset `id`.
1005		///
1006		/// - `id`: The identifier of the asset to have some amount transferred.
1007		/// - `source`: The account to be debited.
1008		/// - `dest`: The account to be credited.
1009		/// - `amount`: The amount by which the `source`'s balance of assets should be reduced and
1010		/// `dest`'s balance increased. The amount actually transferred may be slightly greater in
1011		/// the case that the transfer would otherwise take the `source` balance above zero but
1012		/// below the minimum balance. Must be greater than zero.
1013		///
1014		/// Emits `Transferred` with the actual amount transferred. If this takes the source balance
1015		/// to below the minimum for the asset, then the amount transferred is increased to take it
1016		/// to zero.
1017		///
1018		/// Weight: `O(1)`
1019		/// Modes: Pre-existence of `dest`; Post-existence of `source`; Account pre-existence of
1020		/// `dest`.
1021		#[pallet::call_index(10)]
1022		pub fn force_transfer(
1023			origin: OriginFor<T>,
1024			id: T::AssetIdParameter,
1025			source: AccountIdLookupOf<T>,
1026			dest: AccountIdLookupOf<T>,
1027			#[pallet::compact] amount: T::Balance,
1028		) -> DispatchResult {
1029			let origin = ensure_signed(origin)?;
1030			let source = T::Lookup::lookup(source)?;
1031			let dest = T::Lookup::lookup(dest)?;
1032			let id: T::AssetId = id.into();
1033
1034			let f = TransferFlags { keep_alive: false, best_effort: false, burn_dust: false };
1035			Self::do_transfer(id, &source, &dest, amount, Some(origin), f).map(|_| ())
1036		}
1037
1038		/// Disallow further unprivileged transfers of an asset `id` from an account `who`. `who`
1039		/// must already exist as an entry in `Account`s of the asset. If you want to freeze an
1040		/// account that does not have an entry, use `touch_other` first.
1041		///
1042		/// Origin must be Signed and the sender should be the Freezer of the asset `id`.
1043		///
1044		/// - `id`: The identifier of the asset to be frozen.
1045		/// - `who`: The account to be frozen.
1046		///
1047		/// Emits `Frozen`.
1048		///
1049		/// Weight: `O(1)`
1050		#[pallet::call_index(11)]
1051		pub fn freeze(
1052			origin: OriginFor<T>,
1053			id: T::AssetIdParameter,
1054			who: AccountIdLookupOf<T>,
1055		) -> DispatchResult {
1056			let origin = ensure_signed(origin)?;
1057			let id: T::AssetId = id.into();
1058
1059			let d = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1060			ensure!(
1061				d.status == AssetStatus::Live || d.status == AssetStatus::Frozen,
1062				Error::<T, I>::IncorrectStatus
1063			);
1064			ensure!(origin == d.freezer, Error::<T, I>::NoPermission);
1065			let who = T::Lookup::lookup(who)?;
1066
1067			Account::<T, I>::try_mutate(&id, &who, |maybe_account| -> DispatchResult {
1068				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.status =
1069					AccountStatus::Frozen;
1070				Ok(())
1071			})?;
1072
1073			Self::deposit_event(Event::<T, I>::Frozen { asset_id: id, who });
1074			Ok(())
1075		}
1076
1077		/// Allow unprivileged transfers to and from an account again.
1078		///
1079		/// Origin must be Signed and the sender should be the Admin of the asset `id`.
1080		///
1081		/// - `id`: The identifier of the asset to be frozen.
1082		/// - `who`: The account to be unfrozen.
1083		///
1084		/// Emits `Thawed`.
1085		///
1086		/// Weight: `O(1)`
1087		#[pallet::call_index(12)]
1088		pub fn thaw(
1089			origin: OriginFor<T>,
1090			id: T::AssetIdParameter,
1091			who: AccountIdLookupOf<T>,
1092		) -> DispatchResult {
1093			let origin = ensure_signed(origin)?;
1094			let id: T::AssetId = id.into();
1095
1096			let details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1097			ensure!(
1098				details.status == AssetStatus::Live || details.status == AssetStatus::Frozen,
1099				Error::<T, I>::IncorrectStatus
1100			);
1101			ensure!(origin == details.admin, Error::<T, I>::NoPermission);
1102			let who = T::Lookup::lookup(who)?;
1103
1104			Account::<T, I>::try_mutate(&id, &who, |maybe_account| -> DispatchResult {
1105				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.status =
1106					AccountStatus::Liquid;
1107				Ok(())
1108			})?;
1109
1110			Self::deposit_event(Event::<T, I>::Thawed { asset_id: id, who });
1111			Ok(())
1112		}
1113
1114		/// Disallow further unprivileged transfers for the asset class.
1115		///
1116		/// Origin must be Signed and the sender should be the Freezer of the asset `id`.
1117		///
1118		/// - `id`: The identifier of the asset to be frozen.
1119		///
1120		/// Emits `Frozen`.
1121		///
1122		/// Weight: `O(1)`
1123		#[pallet::call_index(13)]
1124		pub fn freeze_asset(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
1125			let origin = ensure_signed(origin)?;
1126			let id: T::AssetId = id.into();
1127
1128			Asset::<T, I>::try_mutate(id.clone(), |maybe_details| {
1129				let d = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?;
1130				ensure!(d.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
1131				ensure!(origin == d.freezer, Error::<T, I>::NoPermission);
1132
1133				d.status = AssetStatus::Frozen;
1134
1135				Self::deposit_event(Event::<T, I>::AssetFrozen { asset_id: id });
1136				Ok(())
1137			})
1138		}
1139
1140		/// Allow unprivileged transfers for the asset again.
1141		///
1142		/// Origin must be Signed and the sender should be the Admin of the asset `id`.
1143		///
1144		/// - `id`: The identifier of the asset to be thawed.
1145		///
1146		/// Emits `Thawed`.
1147		///
1148		/// Weight: `O(1)`
1149		#[pallet::call_index(14)]
1150		pub fn thaw_asset(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
1151			let origin = ensure_signed(origin)?;
1152			let id: T::AssetId = id.into();
1153
1154			Asset::<T, I>::try_mutate(id.clone(), |maybe_details| {
1155				let d = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?;
1156				ensure!(origin == d.admin, Error::<T, I>::NoPermission);
1157				ensure!(d.status == AssetStatus::Frozen, Error::<T, I>::NotFrozen);
1158
1159				d.status = AssetStatus::Live;
1160
1161				Self::deposit_event(Event::<T, I>::AssetThawed { asset_id: id });
1162				Ok(())
1163			})
1164		}
1165
1166		/// Change the Owner of an asset.
1167		///
1168		/// Origin must be Signed and the sender should be the Owner of the asset `id`.
1169		///
1170		/// - `id`: The identifier of the asset.
1171		/// - `owner`: The new Owner of this asset.
1172		///
1173		/// Emits `OwnerChanged`.
1174		///
1175		/// Weight: `O(1)`
1176		#[pallet::call_index(15)]
1177		pub fn transfer_ownership(
1178			origin: OriginFor<T>,
1179			id: T::AssetIdParameter,
1180			owner: AccountIdLookupOf<T>,
1181		) -> DispatchResult {
1182			let origin = ensure_signed(origin)?;
1183			let owner = T::Lookup::lookup(owner)?;
1184			let id: T::AssetId = id.into();
1185
1186			Asset::<T, I>::try_mutate(id.clone(), |maybe_details| {
1187				let details = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?;
1188				ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
1189				ensure!(origin == details.owner, Error::<T, I>::NoPermission);
1190				if details.owner == owner {
1191					return Ok(())
1192				}
1193
1194				let metadata_deposit = Metadata::<T, I>::get(&id).deposit;
1195				let deposit = details.deposit + metadata_deposit;
1196
1197				// Move the deposit to the new owner.
1198				T::Currency::repatriate_reserved(&details.owner, &owner, deposit, Reserved)?;
1199
1200				details.owner = owner.clone();
1201
1202				Self::deposit_event(Event::OwnerChanged { asset_id: id, owner });
1203				Ok(())
1204			})
1205		}
1206
1207		/// Change the Issuer, Admin and Freezer of an asset.
1208		///
1209		/// Origin must be Signed and the sender should be the Owner of the asset `id`.
1210		///
1211		/// - `id`: The identifier of the asset to be frozen.
1212		/// - `issuer`: The new Issuer of this asset.
1213		/// - `admin`: The new Admin of this asset.
1214		/// - `freezer`: The new Freezer of this asset.
1215		///
1216		/// Emits `TeamChanged`.
1217		///
1218		/// Weight: `O(1)`
1219		#[pallet::call_index(16)]
1220		pub fn set_team(
1221			origin: OriginFor<T>,
1222			id: T::AssetIdParameter,
1223			issuer: AccountIdLookupOf<T>,
1224			admin: AccountIdLookupOf<T>,
1225			freezer: AccountIdLookupOf<T>,
1226		) -> DispatchResult {
1227			let origin = ensure_signed(origin)?;
1228			let issuer = T::Lookup::lookup(issuer)?;
1229			let admin = T::Lookup::lookup(admin)?;
1230			let freezer = T::Lookup::lookup(freezer)?;
1231			let id: T::AssetId = id.into();
1232
1233			Asset::<T, I>::try_mutate(id.clone(), |maybe_details| {
1234				let details = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?;
1235				ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
1236				ensure!(origin == details.owner, Error::<T, I>::NoPermission);
1237
1238				details.issuer = issuer.clone();
1239				details.admin = admin.clone();
1240				details.freezer = freezer.clone();
1241
1242				Self::deposit_event(Event::TeamChanged { asset_id: id, issuer, admin, freezer });
1243				Ok(())
1244			})
1245		}
1246
1247		/// Set the metadata for an asset.
1248		///
1249		/// Origin must be Signed and the sender should be the Owner of the asset `id`.
1250		///
1251		/// Funds of sender are reserved according to the formula:
1252		/// `MetadataDepositBase + MetadataDepositPerByte * (name.len + symbol.len)` taking into
1253		/// account any already reserved funds.
1254		///
1255		/// - `id`: The identifier of the asset to update.
1256		/// - `name`: The user friendly name of this asset. Limited in length by `StringLimit`.
1257		/// - `symbol`: The exchange symbol for this asset. Limited in length by `StringLimit`.
1258		/// - `decimals`: The number of decimals this asset uses to represent one unit.
1259		///
1260		/// Emits `MetadataSet`.
1261		///
1262		/// Weight: `O(1)`
1263		#[pallet::call_index(17)]
1264		#[pallet::weight(T::WeightInfo::set_metadata(name.len() as u32, symbol.len() as u32))]
1265		pub fn set_metadata(
1266			origin: OriginFor<T>,
1267			id: T::AssetIdParameter,
1268			name: Vec<u8>,
1269			symbol: Vec<u8>,
1270			decimals: u8,
1271		) -> DispatchResult {
1272			let origin = ensure_signed(origin)?;
1273			let id: T::AssetId = id.into();
1274			Self::do_set_metadata(id, &origin, name, symbol, decimals)
1275		}
1276
1277		/// Clear the metadata for an asset.
1278		///
1279		/// Origin must be Signed and the sender should be the Owner of the asset `id`.
1280		///
1281		/// Any deposit is freed for the asset owner.
1282		///
1283		/// - `id`: The identifier of the asset to clear.
1284		///
1285		/// Emits `MetadataCleared`.
1286		///
1287		/// Weight: `O(1)`
1288		#[pallet::call_index(18)]
1289		pub fn clear_metadata(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
1290			let origin = ensure_signed(origin)?;
1291			let id: T::AssetId = id.into();
1292
1293			let d = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1294			ensure!(d.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
1295			ensure!(origin == d.owner, Error::<T, I>::NoPermission);
1296
1297			Metadata::<T, I>::try_mutate_exists(id.clone(), |metadata| {
1298				let deposit = metadata.take().ok_or(Error::<T, I>::Unknown)?.deposit;
1299				T::Currency::unreserve(&d.owner, deposit);
1300				Self::deposit_event(Event::MetadataCleared { asset_id: id });
1301				Ok(())
1302			})
1303		}
1304
1305		/// Force the metadata for an asset to some value.
1306		///
1307		/// Origin must be ForceOrigin.
1308		///
1309		/// Any deposit is left alone.
1310		///
1311		/// - `id`: The identifier of the asset to update.
1312		/// - `name`: The user friendly name of this asset. Limited in length by `StringLimit`.
1313		/// - `symbol`: The exchange symbol for this asset. Limited in length by `StringLimit`.
1314		/// - `decimals`: The number of decimals this asset uses to represent one unit.
1315		///
1316		/// Emits `MetadataSet`.
1317		///
1318		/// Weight: `O(N + S)` where N and S are the length of the name and symbol respectively.
1319		#[pallet::call_index(19)]
1320		#[pallet::weight(T::WeightInfo::force_set_metadata(name.len() as u32, symbol.len() as u32))]
1321		pub fn force_set_metadata(
1322			origin: OriginFor<T>,
1323			id: T::AssetIdParameter,
1324			name: Vec<u8>,
1325			symbol: Vec<u8>,
1326			decimals: u8,
1327			is_frozen: bool,
1328		) -> DispatchResult {
1329			T::ForceOrigin::ensure_origin(origin)?;
1330			let id: T::AssetId = id.into();
1331
1332			let bounded_name: BoundedVec<u8, T::StringLimit> =
1333				name.clone().try_into().map_err(|_| Error::<T, I>::BadMetadata)?;
1334
1335			let bounded_symbol: BoundedVec<u8, T::StringLimit> =
1336				symbol.clone().try_into().map_err(|_| Error::<T, I>::BadMetadata)?;
1337
1338			ensure!(Asset::<T, I>::contains_key(&id), Error::<T, I>::Unknown);
1339			Metadata::<T, I>::try_mutate_exists(id.clone(), |metadata| {
1340				let deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit);
1341				*metadata = Some(AssetMetadata {
1342					deposit,
1343					name: bounded_name,
1344					symbol: bounded_symbol,
1345					decimals,
1346					is_frozen,
1347				});
1348
1349				Self::deposit_event(Event::MetadataSet {
1350					asset_id: id,
1351					name,
1352					symbol,
1353					decimals,
1354					is_frozen,
1355				});
1356				Ok(())
1357			})
1358		}
1359
1360		/// Clear the metadata for an asset.
1361		///
1362		/// Origin must be ForceOrigin.
1363		///
1364		/// Any deposit is returned.
1365		///
1366		/// - `id`: The identifier of the asset to clear.
1367		///
1368		/// Emits `MetadataCleared`.
1369		///
1370		/// Weight: `O(1)`
1371		#[pallet::call_index(20)]
1372		pub fn force_clear_metadata(
1373			origin: OriginFor<T>,
1374			id: T::AssetIdParameter,
1375		) -> DispatchResult {
1376			T::ForceOrigin::ensure_origin(origin)?;
1377			let id: T::AssetId = id.into();
1378
1379			let d = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1380			Metadata::<T, I>::try_mutate_exists(id.clone(), |metadata| {
1381				let deposit = metadata.take().ok_or(Error::<T, I>::Unknown)?.deposit;
1382				T::Currency::unreserve(&d.owner, deposit);
1383				Self::deposit_event(Event::MetadataCleared { asset_id: id });
1384				Ok(())
1385			})
1386		}
1387
1388		/// Alter the attributes of a given asset.
1389		///
1390		/// Origin must be `ForceOrigin`.
1391		///
1392		/// - `id`: The identifier of the asset.
1393		/// - `owner`: The new Owner of this asset.
1394		/// - `issuer`: The new Issuer of this asset.
1395		/// - `admin`: The new Admin of this asset.
1396		/// - `freezer`: The new Freezer of this asset.
1397		/// - `min_balance`: The minimum balance of this new asset that any single account must
1398		/// have. If an account's balance is reduced below this, then it collapses to zero.
1399		/// - `is_sufficient`: Whether a non-zero balance of this asset is deposit of sufficient
1400		/// value to account for the state bloat associated with its balance storage. If set to
1401		/// `true`, then non-zero balances may be stored without a `consumer` reference (and thus
1402		/// an ED in the Balances pallet or whatever else is used to control user-account state
1403		/// growth).
1404		/// - `is_frozen`: Whether this asset class is frozen except for permissioned/admin
1405		/// instructions.
1406		///
1407		/// Emits `AssetStatusChanged` with the identity of the asset.
1408		///
1409		/// Weight: `O(1)`
1410		#[pallet::call_index(21)]
1411		pub fn force_asset_status(
1412			origin: OriginFor<T>,
1413			id: T::AssetIdParameter,
1414			owner: AccountIdLookupOf<T>,
1415			issuer: AccountIdLookupOf<T>,
1416			admin: AccountIdLookupOf<T>,
1417			freezer: AccountIdLookupOf<T>,
1418			#[pallet::compact] min_balance: T::Balance,
1419			is_sufficient: bool,
1420			is_frozen: bool,
1421		) -> DispatchResult {
1422			T::ForceOrigin::ensure_origin(origin)?;
1423			let id: T::AssetId = id.into();
1424
1425			Asset::<T, I>::try_mutate(id.clone(), |maybe_asset| {
1426				let mut asset = maybe_asset.take().ok_or(Error::<T, I>::Unknown)?;
1427				ensure!(asset.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive);
1428				asset.owner = T::Lookup::lookup(owner)?;
1429				asset.issuer = T::Lookup::lookup(issuer)?;
1430				asset.admin = T::Lookup::lookup(admin)?;
1431				asset.freezer = T::Lookup::lookup(freezer)?;
1432				asset.min_balance = min_balance;
1433				asset.is_sufficient = is_sufficient;
1434				if is_frozen {
1435					asset.status = AssetStatus::Frozen;
1436				} else {
1437					asset.status = AssetStatus::Live;
1438				}
1439				*maybe_asset = Some(asset);
1440
1441				Self::deposit_event(Event::AssetStatusChanged { asset_id: id });
1442				Ok(())
1443			})
1444		}
1445
1446		/// Approve an amount of asset for transfer by a delegated third-party account.
1447		///
1448		/// Origin must be Signed.
1449		///
1450		/// Ensures that `ApprovalDeposit` worth of `Currency` is reserved from signing account
1451		/// for the purpose of holding the approval. If some non-zero amount of assets is already
1452		/// approved from signing account to `delegate`, then it is topped up or unreserved to
1453		/// meet the right value.
1454		///
1455		/// NOTE: The signing account does not need to own `amount` of assets at the point of
1456		/// making this call.
1457		///
1458		/// - `id`: The identifier of the asset.
1459		/// - `delegate`: The account to delegate permission to transfer asset.
1460		/// - `amount`: The amount of asset that may be transferred by `delegate`. If there is
1461		/// already an approval in place, then this acts additively.
1462		///
1463		/// Emits `ApprovedTransfer` on success.
1464		///
1465		/// Weight: `O(1)`
1466		#[pallet::call_index(22)]
1467		pub fn approve_transfer(
1468			origin: OriginFor<T>,
1469			id: T::AssetIdParameter,
1470			delegate: AccountIdLookupOf<T>,
1471			#[pallet::compact] amount: T::Balance,
1472		) -> DispatchResult {
1473			let owner = ensure_signed(origin)?;
1474			let delegate = T::Lookup::lookup(delegate)?;
1475			let id: T::AssetId = id.into();
1476			Self::do_approve_transfer(id, &owner, &delegate, amount)
1477		}
1478
1479		/// Cancel all of some asset approved for delegated transfer by a third-party account.
1480		///
1481		/// Origin must be Signed and there must be an approval in place between signer and
1482		/// `delegate`.
1483		///
1484		/// Unreserves any deposit previously reserved by `approve_transfer` for the approval.
1485		///
1486		/// - `id`: The identifier of the asset.
1487		/// - `delegate`: The account delegated permission to transfer asset.
1488		///
1489		/// Emits `ApprovalCancelled` on success.
1490		///
1491		/// Weight: `O(1)`
1492		#[pallet::call_index(23)]
1493		pub fn cancel_approval(
1494			origin: OriginFor<T>,
1495			id: T::AssetIdParameter,
1496			delegate: AccountIdLookupOf<T>,
1497		) -> DispatchResult {
1498			let owner = ensure_signed(origin)?;
1499			let delegate = T::Lookup::lookup(delegate)?;
1500			let id: T::AssetId = id.into();
1501			let mut d = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1502			ensure!(d.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
1503
1504			let approval = Approvals::<T, I>::take((id.clone(), &owner, &delegate))
1505				.ok_or(Error::<T, I>::Unknown)?;
1506			T::Currency::unreserve(&owner, approval.deposit);
1507
1508			d.approvals.saturating_dec();
1509			Asset::<T, I>::insert(id.clone(), d);
1510
1511			Self::deposit_event(Event::ApprovalCancelled { asset_id: id, owner, delegate });
1512			Ok(())
1513		}
1514
1515		/// Cancel all of some asset approved for delegated transfer by a third-party account.
1516		///
1517		/// Origin must be either ForceOrigin or Signed origin with the signer being the Admin
1518		/// account of the asset `id`.
1519		///
1520		/// Unreserves any deposit previously reserved by `approve_transfer` for the approval.
1521		///
1522		/// - `id`: The identifier of the asset.
1523		/// - `delegate`: The account delegated permission to transfer asset.
1524		///
1525		/// Emits `ApprovalCancelled` on success.
1526		///
1527		/// Weight: `O(1)`
1528		#[pallet::call_index(24)]
1529		pub fn force_cancel_approval(
1530			origin: OriginFor<T>,
1531			id: T::AssetIdParameter,
1532			owner: AccountIdLookupOf<T>,
1533			delegate: AccountIdLookupOf<T>,
1534		) -> DispatchResult {
1535			let id: T::AssetId = id.into();
1536			let mut d = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1537			ensure!(d.status == AssetStatus::Live, Error::<T, I>::AssetNotLive);
1538			T::ForceOrigin::try_origin(origin)
1539				.map(|_| ())
1540				.or_else(|origin| -> DispatchResult {
1541					let origin = ensure_signed(origin)?;
1542					ensure!(origin == d.admin, Error::<T, I>::NoPermission);
1543					Ok(())
1544				})?;
1545
1546			let owner = T::Lookup::lookup(owner)?;
1547			let delegate = T::Lookup::lookup(delegate)?;
1548
1549			let approval = Approvals::<T, I>::take((id.clone(), &owner, &delegate))
1550				.ok_or(Error::<T, I>::Unknown)?;
1551			T::Currency::unreserve(&owner, approval.deposit);
1552			d.approvals.saturating_dec();
1553			Asset::<T, I>::insert(id.clone(), d);
1554
1555			Self::deposit_event(Event::ApprovalCancelled { asset_id: id, owner, delegate });
1556			Ok(())
1557		}
1558
1559		/// Transfer some asset balance from a previously delegated account to some third-party
1560		/// account.
1561		///
1562		/// Origin must be Signed and there must be an approval in place by the `owner` to the
1563		/// signer.
1564		///
1565		/// If the entire amount approved for transfer is transferred, then any deposit previously
1566		/// reserved by `approve_transfer` is unreserved.
1567		///
1568		/// - `id`: The identifier of the asset.
1569		/// - `owner`: The account which previously approved for a transfer of at least `amount` and
1570		/// from which the asset balance will be withdrawn.
1571		/// - `destination`: The account to which the asset balance of `amount` will be transferred.
1572		/// - `amount`: The amount of assets to transfer.
1573		///
1574		/// Emits `TransferredApproved` on success.
1575		///
1576		/// Weight: `O(1)`
1577		#[pallet::call_index(25)]
1578		pub fn transfer_approved(
1579			origin: OriginFor<T>,
1580			id: T::AssetIdParameter,
1581			owner: AccountIdLookupOf<T>,
1582			destination: AccountIdLookupOf<T>,
1583			#[pallet::compact] amount: T::Balance,
1584		) -> DispatchResult {
1585			let delegate = ensure_signed(origin)?;
1586			let owner = T::Lookup::lookup(owner)?;
1587			let destination = T::Lookup::lookup(destination)?;
1588			let id: T::AssetId = id.into();
1589			Self::do_transfer_approved(id, &owner, &delegate, &destination, amount)
1590		}
1591
1592		/// Create an asset account for non-provider assets.
1593		///
1594		/// A deposit will be taken from the signer account.
1595		///
1596		/// - `origin`: Must be Signed; the signer account must have sufficient funds for a deposit
1597		///   to be taken.
1598		/// - `id`: The identifier of the asset for the account to be created.
1599		///
1600		/// Emits `Touched` event when successful.
1601		#[pallet::call_index(26)]
1602		#[pallet::weight(T::WeightInfo::touch())]
1603		pub fn touch(origin: OriginFor<T>, id: T::AssetIdParameter) -> DispatchResult {
1604			let who = ensure_signed(origin)?;
1605			let id: T::AssetId = id.into();
1606			Self::do_touch(id, who.clone(), who, false)
1607		}
1608
1609		/// Return the deposit (if any) of an asset account or a consumer reference (if any) of an
1610		/// account.
1611		///
1612		/// The origin must be Signed.
1613		///
1614		/// - `id`: The identifier of the asset for which the caller would like the deposit
1615		///   refunded.
1616		/// - `allow_burn`: If `true` then assets may be destroyed in order to complete the refund.
1617		///
1618		/// Emits `Refunded` event when successful.
1619		#[pallet::call_index(27)]
1620		#[pallet::weight(T::WeightInfo::refund())]
1621		pub fn refund(
1622			origin: OriginFor<T>,
1623			id: T::AssetIdParameter,
1624			allow_burn: bool,
1625		) -> DispatchResult {
1626			let id: T::AssetId = id.into();
1627			Self::do_refund(id, ensure_signed(origin)?, allow_burn)
1628		}
1629
1630		/// Sets the minimum balance of an asset.
1631		///
1632		/// Only works if there aren't any accounts that are holding the asset or if
1633		/// the new value of `min_balance` is less than the old one.
1634		///
1635		/// Origin must be Signed and the sender has to be the Owner of the
1636		/// asset `id`.
1637		///
1638		/// - `id`: The identifier of the asset.
1639		/// - `min_balance`: The new value of `min_balance`.
1640		///
1641		/// Emits `AssetMinBalanceChanged` event when successful.
1642		#[pallet::call_index(28)]
1643		pub fn set_min_balance(
1644			origin: OriginFor<T>,
1645			id: T::AssetIdParameter,
1646			min_balance: T::Balance,
1647		) -> DispatchResult {
1648			let origin = ensure_signed(origin)?;
1649			let id: T::AssetId = id.into();
1650
1651			let mut details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1652			ensure!(origin == details.owner, Error::<T, I>::NoPermission);
1653
1654			let old_min_balance = details.min_balance;
1655			// If the asset is marked as sufficient it won't be allowed to
1656			// change the min_balance.
1657			ensure!(!details.is_sufficient, Error::<T, I>::NoPermission);
1658
1659			// Ensure that either the new min_balance is less than old
1660			// min_balance or there aren't any accounts holding the asset.
1661			ensure!(
1662				min_balance < old_min_balance || details.accounts == 0,
1663				Error::<T, I>::NoPermission
1664			);
1665
1666			details.min_balance = min_balance;
1667			Asset::<T, I>::insert(&id, details);
1668
1669			Self::deposit_event(Event::AssetMinBalanceChanged {
1670				asset_id: id,
1671				new_min_balance: min_balance,
1672			});
1673			Ok(())
1674		}
1675
1676		/// Create an asset account for `who`.
1677		///
1678		/// A deposit will be taken from the signer account.
1679		///
1680		/// - `origin`: Must be Signed by `Freezer` or `Admin` of the asset `id`; the signer account
1681		///   must have sufficient funds for a deposit to be taken.
1682		/// - `id`: The identifier of the asset for the account to be created.
1683		/// - `who`: The account to be created.
1684		///
1685		/// Emits `Touched` event when successful.
1686		#[pallet::call_index(29)]
1687		#[pallet::weight(T::WeightInfo::touch_other())]
1688		pub fn touch_other(
1689			origin: OriginFor<T>,
1690			id: T::AssetIdParameter,
1691			who: AccountIdLookupOf<T>,
1692		) -> DispatchResult {
1693			let origin = ensure_signed(origin)?;
1694			let who = T::Lookup::lookup(who)?;
1695			let id: T::AssetId = id.into();
1696			Self::do_touch(id, who, origin, true)
1697		}
1698
1699		/// Return the deposit (if any) of a target asset account. Useful if you are the depositor.
1700		///
1701		/// The origin must be Signed and either the account owner, depositor, or asset `Admin`. In
1702		/// order to burn a non-zero balance of the asset, the caller must be the account and should
1703		/// use `refund`.
1704		///
1705		/// - `id`: The identifier of the asset for the account holding a deposit.
1706		/// - `who`: The account to refund.
1707		///
1708		/// Emits `Refunded` event when successful.
1709		#[pallet::call_index(30)]
1710		#[pallet::weight(T::WeightInfo::refund_other())]
1711		pub fn refund_other(
1712			origin: OriginFor<T>,
1713			id: T::AssetIdParameter,
1714			who: AccountIdLookupOf<T>,
1715		) -> DispatchResult {
1716			let origin = ensure_signed(origin)?;
1717			let who = T::Lookup::lookup(who)?;
1718			let id: T::AssetId = id.into();
1719			Self::do_refund_other(id, &who, Some(origin))
1720		}
1721
1722		/// Disallow further unprivileged transfers of an asset `id` to and from an account `who`.
1723		///
1724		/// Origin must be Signed and the sender should be the Freezer of the asset `id`.
1725		///
1726		/// - `id`: The identifier of the account's asset.
1727		/// - `who`: The account to be unblocked.
1728		///
1729		/// Emits `Blocked`.
1730		///
1731		/// Weight: `O(1)`
1732		#[pallet::call_index(31)]
1733		pub fn block(
1734			origin: OriginFor<T>,
1735			id: T::AssetIdParameter,
1736			who: AccountIdLookupOf<T>,
1737		) -> DispatchResult {
1738			let origin = ensure_signed(origin)?;
1739			let id: T::AssetId = id.into();
1740
1741			let d = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?;
1742			ensure!(
1743				d.status == AssetStatus::Live || d.status == AssetStatus::Frozen,
1744				Error::<T, I>::IncorrectStatus
1745			);
1746			ensure!(origin == d.freezer, Error::<T, I>::NoPermission);
1747			let who = T::Lookup::lookup(who)?;
1748
1749			Account::<T, I>::try_mutate(&id, &who, |maybe_account| -> DispatchResult {
1750				maybe_account.as_mut().ok_or(Error::<T, I>::NoAccount)?.status =
1751					AccountStatus::Blocked;
1752				Ok(())
1753			})?;
1754
1755			Self::deposit_event(Event::<T, I>::Blocked { asset_id: id, who });
1756			Ok(())
1757		}
1758
1759		/// Transfer the entire transferable balance from the caller asset account.
1760		///
1761		/// NOTE: This function only attempts to transfer _transferable_ balances. This means that
1762		/// any held, frozen, or minimum balance (when `keep_alive` is `true`), will not be
1763		/// transferred by this function. To ensure that this function results in a killed account,
1764		/// you might need to prepare the account by removing any reference counters, storage
1765		/// deposits, etc...
1766		///
1767		/// The dispatch origin of this call must be Signed.
1768		///
1769		/// - `id`: The identifier of the asset for the account holding a deposit.
1770		/// - `dest`: The recipient of the transfer.
1771		/// - `keep_alive`: A boolean to determine if the `transfer_all` operation should send all
1772		///   of the funds the asset account has, causing the sender asset account to be killed
1773		///   (false), or transfer everything except at least the minimum balance, which will
1774		///   guarantee to keep the sender asset account alive (true).
1775		#[pallet::call_index(32)]
1776		#[pallet::weight(T::WeightInfo::transfer_all())]
1777		pub fn transfer_all(
1778			origin: OriginFor<T>,
1779			id: T::AssetIdParameter,
1780			dest: AccountIdLookupOf<T>,
1781			keep_alive: bool,
1782		) -> DispatchResult {
1783			let transactor = ensure_signed(origin)?;
1784			let keep_alive = if keep_alive { Preserve } else { Expendable };
1785			let reducible_balance = <Self as fungibles::Inspect<_>>::reducible_balance(
1786				id.clone().into(),
1787				&transactor,
1788				keep_alive,
1789				Fortitude::Polite,
1790			);
1791			let dest = T::Lookup::lookup(dest)?;
1792			<Self as fungibles::Mutate<_>>::transfer(
1793				id.into(),
1794				&transactor,
1795				&dest,
1796				reducible_balance,
1797				keep_alive,
1798			)?;
1799			Ok(())
1800		}
1801	}
1802
1803	/// Implements [`AccountTouch`] trait.
1804	/// Note that a depositor can be any account, without any specific privilege.
1805	/// This implementation is supposed to be used only for creation of system accounts.
1806	impl<T: Config<I>, I: 'static> AccountTouch<T::AssetId, T::AccountId> for Pallet<T, I> {
1807		type Balance = DepositBalanceOf<T, I>;
1808
1809		fn deposit_required(_: T::AssetId) -> Self::Balance {
1810			T::AssetAccountDeposit::get()
1811		}
1812
1813		fn should_touch(asset: T::AssetId, who: &T::AccountId) -> bool {
1814			match Asset::<T, I>::get(&asset) {
1815				// refer to the [`Self::new_account`] function for more details.
1816				Some(info) if info.is_sufficient => false,
1817				Some(_) if frame_system::Pallet::<T>::can_accrue_consumers(who, 2) => false,
1818				Some(_) => !Account::<T, I>::contains_key(asset, who),
1819				_ => true,
1820			}
1821		}
1822
1823		fn touch(
1824			asset: T::AssetId,
1825			who: &T::AccountId,
1826			depositor: &T::AccountId,
1827		) -> DispatchResult {
1828			Self::do_touch(asset, who.clone(), depositor.clone(), false)
1829		}
1830	}
1831
1832	/// Implements [`ContainsPair`] trait for a pair of asset and account IDs.
1833	impl<T: Config<I>, I: 'static> ContainsPair<T::AssetId, T::AccountId> for Pallet<T, I> {
1834		/// Check if an account with the given asset ID and account address exists.
1835		fn contains(asset: &T::AssetId, who: &T::AccountId) -> bool {
1836			Account::<T, I>::contains_key(asset, who)
1837		}
1838	}
1839}
1840
1841sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);