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