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