referrerpolicy=no-referrer-when-downgrade

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