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