git.delta.rocks / unique-network / refs/commits / 374e37517d0d

difftreelog

style fix formatting

Yaroslav Bolyukin2023-04-17parent: #b1f2216.patch.diff
in: master

1 file changed

modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
before · pallets/unique/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Unique Pallet18//!19//! A pallet governing Unique transactions.20//!21//! - [`Config`]22//! - [`Call`]23//! - [`Pallet`]24//!25//! ## Overview26//!27//! The Unique pallet's purpose is to be the primary interface between28//! external users and the inner structure of the Unique chains.29//!30//! It also contains an implementation of [`CollectionHelpers`][`eth`],31//! an Ethereum contract dealing with collection operations.32//!33//! ## Interface34//!35//! ### Dispatchables36//!37//! - `create_collection` - Create a collection of tokens. **Deprecated**, use `create_collection_ex`.38//! - `create_collection_ex` - Create a collection of tokens with explicit parameters.39//! - `destroy_collection` - Destroy a collection if no tokens exist within.40//! - `add_to_allow_list` - Add an address to allow list.41//! - `remove_from_allow_list` - Remove an address from allow list.42//! - `change_collection_owner` - Change the owner of the collection.43//! - `add_collection_admin` - Add an admin to a collection.44//! - `remove_collection_admin` - Remove admin of a collection.45//! - `set_collection_sponsor` - Invite a new collection sponsor.46//! - `confirm_sponsorship` - Confirm own sponsorship of a collection, becoming the sponsor.47//! - `remove_collection_sponsor` - Remove a sponsor from a collection.48//! - `create_item` - Create an item within a collection.49//! - `create_multiple_items` - Create multiple items within a collection.50//! - `set_collection_properties` - Add or change collection properties.51//! - `delete_collection_properties` - Delete specified collection properties.52//! - `set_token_properties` - Add or change token properties.53//! - `delete_token_properties` - Delete token properties.54//! - `set_token_property_permissions` - Add or change token property permissions of a collection.55//! - `create_multiple_items_ex` - Create multiple items within a collection with explicitly specified initial parameters.56//! - `set_transfers_enabled_flag` - Completely allow or disallow transfers for a particular collection.57//! - `burn_item` - Destroy an item.58//! - `burn_from` - Destroy an item on behalf of the owner as a non-owner account.59//! - `transfer` - Change ownership of the token.60//! - `transfer_from` - Change ownership of the token on behalf of the owner as a non-owner account.61//! - `approve` - Allow a non-permissioned address to transfer or burn an item.62//! - `set_collection_limits` - Set specific limits of a collection.63//! - `set_collection_permissions` - Set specific permissions of a collection.64//! - `repartition` - Re-partition a refungible token, while owning all of its parts.6566#![recursion_limit = "1024"]67#![cfg_attr(not(feature = "std"), no_std)]68#![allow(69	clippy::too_many_arguments,70	clippy::unnecessary_mut_passed,71	clippy::unused_unit72)]7374extern crate alloc;7576pub use pallet::*;77use frame_support::pallet_prelude::*;78use frame_system::pallet_prelude::*;79pub mod eth;8081#[cfg(feature = "runtime-benchmarks")]82pub mod benchmarking;83pub mod weights;8485#[frame_support::pallet]86pub mod pallet {87	use super::*;8889	use frame_support::{90		dispatch::DispatchResult,91		ensure, fail,92		BoundedVec,93		storage::Key,94	};95	use scale_info::TypeInfo;96	use frame_system::{ensure_signed, ensure_root};97	use sp_std::{vec, vec::Vec};98	use up_data_structs::{99		MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,100		MAX_PROPERTIES_PER_ITEM, MAX_PROPERTY_KEY_LENGTH, MAX_PROPERTY_VALUE_LENGTH,101		MAX_COLLECTION_PROPERTIES_SIZE, COLLECTION_ADMINS_LIMIT, MAX_TOKEN_PROPERTIES_SIZE,102		CreateItemData, CollectionLimits, CollectionPermissions, CollectionId, CollectionMode,103		TokenId, CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,104		PropertyKeyPermission,105	};106	use pallet_evm::account::CrossAccountId;107	use pallet_common::{108		CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_tx,109		dispatch::CollectionDispatch, RefungibleExtensionsWeightInfo,110	};111	use weights::WeightInfo;112113	/// A maximum number of levels of depth in the token nesting tree.114	pub const NESTING_BUDGET: u32 = 5;115116	/// Errors for the common Unique transactions.117	#[pallet::error]118	pub enum Error<T> {119		/// Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].120		CollectionDecimalPointLimitExceeded,121		/// Length of items properties must be greater than 0.122		EmptyArgument,123		/// Repertition is only supported by refungible collection.124		RepartitionCalledOnNonRefungibleCollection,125	}126127	/// Configuration trait of this pallet.128	#[pallet::config]129	pub trait Config: frame_system::Config + pallet_common::Config + Sized + TypeInfo {130		/// Weight information for extrinsics in this pallet.131		type WeightInfo: WeightInfo;132133		/// Weight information for common pallet operations.134		type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;135136		/// Weight info information for extra refungible pallet operations.137		type RefungibleExtensionsWeightInfo: RefungibleExtensionsWeightInfo;138	}139140	#[pallet::pallet]141	pub struct Pallet<T>(_);142143	pub type SelfWeightOf<T> = <T as Config>::WeightInfo;144145	// # Used definitions146	//147	// ## User control levels148	//149	// chain-controlled - key is uncontrolled by user150	//                    i.e autoincrementing index151	//                    can use non-cryptographic hash152	// real - key is controlled by user153	//        but it is hard to generate enough colliding values, i.e owner of signed txs154	//        can use non-cryptographic hash155	// controlled - key is completly controlled by users156	//              i.e maps with mutable keys157	//              should use cryptographic hash158	//159	// ## User control level downgrade reasons160	//161	// ?1 - chain-controlled -> controlled162	//      collections/tokens can be destroyed, resulting in massive holes163	// ?2 - chain-controlled -> controlled164	//      same as ?1, but can be only added, resulting in easier exploitation165	// ?3 - real -> controlled166	//      no confirmation required, so addresses can be easily generated167168	//#region Private members169	/// Used for migrations170	#[pallet::storage]171	pub type ChainVersion<T> = StorageValue<_, u64, ValueQuery>;172	//#endregion173174	//#region Tokens transfer sponosoring rate limit baskets175	/// (Collection id (controlled?2), who created (real))176	/// TODO: Off chain worker should remove from this map when collection gets removed177	#[pallet::storage]178	#[pallet::getter(fn create_item_busket)]179	pub type CreateItemBasket<T: Config> = StorageMap<180		Hasher = Blake2_128Concat,181		Key = (CollectionId, T::AccountId),182		Value = T::BlockNumber,183		QueryKind = OptionQuery,184	>;185	/// Collection id (controlled?2), token id (controlled?2)186	#[pallet::storage]187	#[pallet::getter(fn nft_transfer_basket)]188	pub type NftTransferBasket<T: Config> = StorageDoubleMap<189		Hasher1 = Blake2_128Concat,190		Key1 = CollectionId,191		Hasher2 = Blake2_128Concat,192		Key2 = TokenId,193		Value = T::BlockNumber,194		QueryKind = OptionQuery,195	>;196	/// Collection id (controlled?2), owning user (real)197	#[pallet::storage]198	#[pallet::getter(fn fungible_transfer_basket)]199	pub type FungibleTransferBasket<T: Config> = StorageDoubleMap<200		Hasher1 = Blake2_128Concat,201		Key1 = CollectionId,202		Hasher2 = Twox64Concat,203		Key2 = T::AccountId,204		Value = T::BlockNumber,205		QueryKind = OptionQuery,206	>;207	/// Collection id (controlled?2), token id (controlled?2)208	#[pallet::storage]209	#[pallet::getter(fn refungible_transfer_basket)]210	pub type ReFungibleTransferBasket<T: Config> = StorageNMap<211		Key = (212			Key<Blake2_128Concat, CollectionId>,213			Key<Blake2_128Concat, TokenId>,214			Key<Twox64Concat, T::AccountId>,215		),216		Value = T::BlockNumber,217		QueryKind = OptionQuery,218	>;219	//#endregion220221	/// Last sponsoring of token property setting // todo:doc rephrase this and the following222	#[pallet::storage]223	#[pallet::getter(fn token_property_basket)]224	pub type TokenPropertyBasket<T: Config> = StorageDoubleMap<225		Hasher1 = Blake2_128Concat,226		Key1 = CollectionId,227		Hasher2 = Blake2_128Concat,228		Key2 = TokenId,229		Value = T::BlockNumber,230		QueryKind = OptionQuery,231	>;232233	/// Last sponsoring of NFT approval in a collection234	#[pallet::storage]235	#[pallet::getter(fn nft_approve_basket)]236	pub type NftApproveBasket<T: Config> = StorageDoubleMap<237		Hasher1 = Blake2_128Concat,238		Key1 = CollectionId,239		Hasher2 = Blake2_128Concat,240		Key2 = TokenId,241		Value = T::BlockNumber,242		QueryKind = OptionQuery,243	>;244	/// Last sponsoring of fungible tokens approval in a collection245	#[pallet::storage]246	#[pallet::getter(fn fungible_approve_basket)]247	pub type FungibleApproveBasket<T: Config> = StorageDoubleMap<248		Hasher1 = Blake2_128Concat,249		Key1 = CollectionId,250		Hasher2 = Twox64Concat,251		Key2 = T::AccountId,252		Value = T::BlockNumber,253		QueryKind = OptionQuery,254	>;255	/// Last sponsoring of RFT approval in a collection256	#[pallet::storage]257	#[pallet::getter(fn refungible_approve_basket)]258	pub type RefungibleApproveBasket<T: Config> = StorageNMap<259		Key = (260			Key<Blake2_128Concat, CollectionId>,261			Key<Blake2_128Concat, TokenId>,262			Key<Twox64Concat, T::AccountId>,263		),264		Value = T::BlockNumber,265		QueryKind = OptionQuery,266	>;267268	#[pallet::extra_constants]269	impl<T: Config> Pallet<T> {270		/// A maximum number of levels of depth in the token nesting tree.271		fn nesting_budget() -> u32 {272			NESTING_BUDGET273		}274275		/// Maximal length of a collection name.276		fn max_collection_name_length() -> u32 {277			MAX_COLLECTION_NAME_LENGTH278		}279280		/// Maximal length of a collection description.281		fn max_collection_description_length() -> u32 {282			MAX_COLLECTION_DESCRIPTION_LENGTH283		}284285		/// Maximal length of a token prefix.286		fn max_token_prefix_length() -> u32 {287			MAX_TOKEN_PREFIX_LENGTH288		}289290		/// Maximum admins per collection.291		fn collection_admins_limit() -> u32 {292			COLLECTION_ADMINS_LIMIT293		}294295		/// Maximal length of a property key.296		fn max_property_key_length() -> u32 {297			MAX_PROPERTY_KEY_LENGTH298		}299300		/// Maximal length of a property value.301		fn max_property_value_length() -> u32 {302			MAX_PROPERTY_VALUE_LENGTH303		}304305		/// A maximum number of token properties.306		fn max_properties_per_item() -> u32 {307			MAX_PROPERTIES_PER_ITEM308		}309310		/// Maximum size for all collection properties.311		fn max_collection_properties_size() -> u32 {312			MAX_COLLECTION_PROPERTIES_SIZE313		}314315		/// Maximum size of all token properties.316		fn max_token_properties_size() -> u32 {317			MAX_TOKEN_PROPERTIES_SIZE318		}319320		/// Default NFT collection limit.321		fn nft_default_collection_limits() -> CollectionLimits {322			CollectionLimits::with_default_limits(CollectionMode::NFT)323		}324325		/// Default RFT collection limit.326		fn rft_default_collection_limits() -> CollectionLimits {327			CollectionLimits::with_default_limits(CollectionMode::ReFungible)328		}329330		/// Default FT collection limit.331		fn ft_default_collection_limits() -> CollectionLimits {332			CollectionLimits::with_default_limits(CollectionMode::Fungible(0))333		}334	}335336	/// Type alias to Pallet, to be used by construct_runtime.337	#[pallet::call]338	impl<T: Config> Pallet<T> {339		/// Create a collection of tokens.340		///341		/// Each Token may have multiple properties encoded as an array of bytes342		/// of certain length. The initial owner of the collection is set343		/// to the address that signed the transaction and can be changed later.344		///345		/// Prefer the more advanced [`create_collection_ex`][`Pallet::create_collection_ex`] instead.346		///347		/// # Permissions348		///349		/// * Anyone - becomes the owner of the new collection.350		///351		/// # Arguments352		///353		/// * `collection_name`: Wide-character string with collection name354		/// (limit [`MAX_COLLECTION_NAME_LENGTH`]).355		/// * `collection_description`: Wide-character string with collection description356		/// (limit [`MAX_COLLECTION_DESCRIPTION_LENGTH`]).357		/// * `token_prefix`: Byte string containing the token prefix to mark a collection358		/// to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).359		/// * `mode`: Type of items stored in the collection and type dependent data.360		///361		/// returns collection ID362		///363		/// Deprecated: `create_collection_ex` is more up-to-date and advanced, prefer it instead.364		#[pallet::call_index(0)]365		#[pallet::weight(<SelfWeightOf<T>>::create_collection())]366		pub fn create_collection(367			origin: OriginFor<T>,368			collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,369			collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,370			token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,371			mode: CollectionMode,372		) -> DispatchResult {373			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {374				name: collection_name,375				description: collection_description,376				token_prefix,377				mode,378				..Default::default()379			};380			Self::create_collection_ex(origin, data)381		}382383		/// Create a collection with explicit parameters.384		///385		/// Prefer it to the deprecated [`create_collection`][`Pallet::create_collection`] method.386		///387		/// # Permissions388		///389		/// * Anyone - becomes the owner of the new collection.390		///391		/// # Arguments392		///393		/// * `data`: Explicit data of a collection used for its creation.394		#[pallet::call_index(1)]395		#[pallet::weight(<SelfWeightOf<T>>::create_collection())]396		pub fn create_collection_ex(397			origin: OriginFor<T>,398			data: CreateCollectionData<T::AccountId>,399		) -> DispatchResult {400			let sender = ensure_signed(origin)?;401402			// =========403			let sender = T::CrossAccountId::from_sub(sender);404			let _id =405				T::CollectionDispatch::create(sender.clone(), sender, data, Default::default())?;406407			Ok(())408		}409410		/// Destroy a collection if no tokens exist within.411		///412		/// # Permissions413		///414		/// * Collection owner415		///416		/// # Arguments417		///418		/// * `collection_id`: Collection to destroy.419		#[pallet::call_index(2)]420		#[pallet::weight(<SelfWeightOf<T>>::destroy_collection())]421		pub fn destroy_collection(422			origin: OriginFor<T>,423			collection_id: CollectionId,424		) -> DispatchResult {425			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);426427			Self::destroy_collection_internal(sender, collection_id)428		}429430		/// Add an address to allow list.431		///432		/// # Permissions433		///434		/// * Collection owner435		/// * Collection admin436		///437		/// # Arguments438		///439		/// * `collection_id`: ID of the modified collection.440		/// * `address`: ID of the address to be added to the allowlist.441		#[pallet::call_index(3)]442		#[pallet::weight(<SelfWeightOf<T>>::add_to_allow_list())]443		pub fn add_to_allow_list(444			origin: OriginFor<T>,445			collection_id: CollectionId,446			address: T::CrossAccountId,447		) -> DispatchResult {448			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);449			let collection = <CollectionHandle<T>>::try_get(collection_id)?;450			collection.check_is_internal()?;451452			<PalletCommon<T>>::toggle_allowlist(&collection, &sender, &address, true)?;453454			Ok(())455		}456457		/// Remove an address from allow list.458		///459		/// # Permissions460		///461		/// * Collection owner462		/// * Collection admin463		///464		/// # Arguments465		///466		/// * `collection_id`: ID of the modified collection.467		/// * `address`: ID of the address to be removed from the allowlist.468		#[pallet::call_index(4)]469		#[pallet::weight(<SelfWeightOf<T>>::remove_from_allow_list())]470		pub fn remove_from_allow_list(471			origin: OriginFor<T>,472			collection_id: CollectionId,473			address: T::CrossAccountId,474		) -> DispatchResult {475			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);476			let collection = <CollectionHandle<T>>::try_get(collection_id)?;477			collection.check_is_internal()?;478479			<PalletCommon<T>>::toggle_allowlist(&collection, &sender, &address, false)?;480481			Ok(())482		}483484		/// Change the owner of the collection.485		///486		/// # Permissions487		///488		/// * Collection owner489		///490		/// # Arguments491		///492		/// * `collection_id`: ID of the modified collection.493		/// * `new_owner`: ID of the account that will become the owner.494		#[pallet::call_index(5)]495		#[pallet::weight(<SelfWeightOf<T>>::change_collection_owner())]496		pub fn change_collection_owner(497			origin: OriginFor<T>,498			collection_id: CollectionId,499			new_owner: T::AccountId,500		) -> DispatchResult {501			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);502			let new_owner = T::CrossAccountId::from_sub(new_owner);503			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;504			target_collection.change_owner(sender, new_owner.clone())505		}506507		/// Add an admin to a collection.508		///509		/// NFT Collection can be controlled by multiple admin addresses510		/// (some which can also be servers, for example). Admins can issue511		/// and burn NFTs, as well as add and remove other admins,512		/// but cannot change NFT or Collection ownership.513		///514		/// # Permissions515		///516		/// * Collection owner517		/// * Collection admin518		///519		/// # Arguments520		///521		/// * `collection_id`: ID of the Collection to add an admin for.522		/// * `new_admin`: Address of new admin to add.523		#[pallet::call_index(6)]524		#[pallet::weight(<SelfWeightOf<T>>::add_collection_admin())]525		pub fn add_collection_admin(526			origin: OriginFor<T>,527			collection_id: CollectionId,528			new_admin_id: T::CrossAccountId,529		) -> DispatchResult {530			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);531			let collection = <CollectionHandle<T>>::try_get(collection_id)?;532			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)533		}534535		/// Remove admin of a collection.536		///537		/// An admin address can remove itself. List of admins may become empty,538		/// in which case only Collection Owner will be able to add an Admin.539		///540		/// # Permissions541		///542		/// * Collection owner543		/// * Collection admin544		///545		/// # Arguments546		///547		/// * `collection_id`: ID of the collection to remove the admin for.548		/// * `account_id`: Address of the admin to remove.549		#[pallet::call_index(7)]550		#[pallet::weight(<SelfWeightOf<T>>::remove_collection_admin())]551		pub fn remove_collection_admin(552			origin: OriginFor<T>,553			collection_id: CollectionId,554			account_id: T::CrossAccountId,555		) -> DispatchResult {556			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);557			let collection = <CollectionHandle<T>>::try_get(collection_id)?;558			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)559		}560561		/// Set (invite) a new collection sponsor.562		///563		/// If successful, confirmation from the sponsor-to-be will be pending.564		///565		/// # Permissions566		///567		/// * Collection owner568		/// * Collection admin569		///570		/// # Arguments571		///572		/// * `collection_id`: ID of the modified collection.573		/// * `new_sponsor`: ID of the account of the sponsor-to-be.574		#[pallet::call_index(8)]575		#[pallet::weight(<SelfWeightOf<T>>::set_collection_sponsor())]576		pub fn set_collection_sponsor(577			origin: OriginFor<T>,578			collection_id: CollectionId,579			new_sponsor: T::AccountId,580		) -> DispatchResult {581			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);582			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;583			target_collection.set_sponsor(&sender, new_sponsor.clone())584		}585586		/// Confirm own sponsorship of a collection, becoming the sponsor.587		///588		/// An invitation must be pending, see [`set_collection_sponsor`][`Pallet::set_collection_sponsor`].589		/// Sponsor can pay the fees of a transaction instead of the sender,590		/// but only within specified limits.591		///592		/// # Permissions593		///594		/// * Sponsor-to-be595		///596		/// # Arguments597		///598		/// * `collection_id`: ID of the collection with the pending sponsor.599		#[pallet::call_index(9)]600		#[pallet::weight(<SelfWeightOf<T>>::confirm_sponsorship())]601		pub fn confirm_sponsorship(602			origin: OriginFor<T>,603			collection_id: CollectionId,604		) -> DispatchResult {605			let sender = ensure_signed(origin)?;606			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;607			target_collection.confirm_sponsorship(&sender)608		}609610		/// Remove a collection's a sponsor, making everyone pay for their own transactions.611		///612		/// # Permissions613		///614		/// * Collection owner615		///616		/// # Arguments617		///618		/// * `collection_id`: ID of the collection with the sponsor to remove.619		#[pallet::call_index(10)]620		#[pallet::weight(<SelfWeightOf<T>>::remove_collection_sponsor())]621		pub fn remove_collection_sponsor(622			origin: OriginFor<T>,623			collection_id: CollectionId,624		) -> DispatchResult {625			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);626			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;627			target_collection.remove_sponsor(&sender)628		}629630		/// Mint an item within a collection.631		///632		/// A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].633		///634		/// # Permissions635		///636		/// * Collection owner637		/// * Collection admin638		/// * Anyone if639		///     * Allow List is enabled, and640		///     * Address is added to allow list, and641		///     * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])642		///643		/// # Arguments644		///645		/// * `collection_id`: ID of the collection to which an item would belong.646		/// * `owner`: Address of the initial owner of the item.647		/// * `data`: Token data describing the item to store on chain.648		#[pallet::call_index(11)]649		#[pallet::weight(T::CommonWeightInfo::create_item(&data))]650		pub fn create_item(651			origin: OriginFor<T>,652			collection_id: CollectionId,653			owner: T::CrossAccountId,654			data: CreateItemData,655		) -> DispatchResultWithPostInfo {656			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);657			let budget = budget::Value::new(NESTING_BUDGET);658659			dispatch_tx::<T, _>(collection_id, |d| {660				d.create_item(sender, owner, data, &budget)661			})662		}663664		/// Create multiple items within a collection.665		///666		/// A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].667		///668		/// # Permissions669		///670		/// * Collection owner671		/// * Collection admin672		/// * Anyone if673		///     * Allow List is enabled, and674		///     * Address is added to the allow list, and675		///     * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])676		///677		/// # Arguments678		///679		/// * `collection_id`: ID of the collection to which the tokens would belong.680		/// * `owner`: Address of the initial owner of the tokens.681		/// * `items_data`: Vector of data describing each item to be created.682		#[pallet::call_index(12)]683		#[pallet::weight(T::CommonWeightInfo::create_multiple_items(&items_data))]684		pub fn create_multiple_items(685			origin: OriginFor<T>,686			collection_id: CollectionId,687			owner: T::CrossAccountId,688			items_data: Vec<CreateItemData>,689		) -> DispatchResultWithPostInfo {690			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);691			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);692			let budget = budget::Value::new(NESTING_BUDGET);693694			dispatch_tx::<T, _>(collection_id, |d| {695				d.create_multiple_items(sender, owner, items_data, &budget)696			})697		}698699		/// Add or change collection properties.700		///701		/// # Permissions702		///703		/// * Collection owner704		/// * Collection admin705		///706		/// # Arguments707		///708		/// * `collection_id`: ID of the modified collection.709		/// * `properties`: Vector of key-value pairs stored as the collection's metadata.710		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.711		#[pallet::call_index(13)]712		#[pallet::weight(T::CommonWeightInfo::set_collection_properties(properties.len() as u32))]713		pub fn set_collection_properties(714			origin: OriginFor<T>,715			collection_id: CollectionId,716			properties: Vec<Property>,717		) -> DispatchResultWithPostInfo {718			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);719720			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);721722			dispatch_tx::<T, _>(collection_id, |d| {723				d.set_collection_properties(sender, properties)724			})725		}726727		/// Delete specified collection properties.728		///729		/// # Permissions730		///731		/// * Collection Owner732		/// * Collection Admin733		///734		/// # Arguments735		///736		/// * `collection_id`: ID of the modified collection.737		/// * `property_keys`: Vector of keys of the properties to be deleted.738		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.739		#[pallet::call_index(14)]740		#[pallet::weight(T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32))]741		pub fn delete_collection_properties(742			origin: OriginFor<T>,743			collection_id: CollectionId,744			property_keys: Vec<PropertyKey>,745		) -> DispatchResultWithPostInfo {746			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);747748			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);749750			dispatch_tx::<T, _>(collection_id, |d| {751				d.delete_collection_properties(&sender, property_keys)752			})753		}754755		/// Add or change token properties according to collection's permissions.756		/// Currently properties only work with NFTs.757		///758		/// # Permissions759		///760		/// * Depends on collection's token property permissions and specified property mutability:761		/// 	* Collection owner762		/// 	* Collection admin763		/// 	* Token owner764		///765		/// See [`set_token_property_permissions`][`Pallet::set_token_property_permissions`].766		///767		/// # Arguments768		///769		/// * `collection_id: ID of the collection to which the token belongs.770		/// * `token_id`: ID of the modified token.771		/// * `properties`: Vector of key-value pairs stored as the token's metadata.772		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.773		#[pallet::call_index(15)]774		#[pallet::weight(T::CommonWeightInfo::set_token_properties(properties.len() as u32))]775		pub fn set_token_properties(776			origin: OriginFor<T>,777			collection_id: CollectionId,778			token_id: TokenId,779			properties: Vec<Property>,780		) -> DispatchResultWithPostInfo {781			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);782783			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);784			let budget = budget::Value::new(NESTING_BUDGET);785786			dispatch_tx::<T, _>(collection_id, |d| {787				d.set_token_properties(sender, token_id, properties, &budget)788			})789		}790791		/// Delete specified token properties. Currently properties only work with NFTs.792		///793		/// # Permissions794		///795		/// * Depends on collection's token property permissions and specified property mutability:796		/// 	* Collection owner797		/// 	* Collection admin798		/// 	* Token owner799		///800		/// # Arguments801		///802		/// * `collection_id`: ID of the collection to which the token belongs.803		/// * `token_id`: ID of the modified token.804		/// * `property_keys`: Vector of keys of the properties to be deleted.805		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.806		#[pallet::call_index(16)]807		#[pallet::weight(T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32))]808		pub fn delete_token_properties(809			origin: OriginFor<T>,810			collection_id: CollectionId,811			token_id: TokenId,812			property_keys: Vec<PropertyKey>,813		) -> DispatchResultWithPostInfo {814			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);815816			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);817			let budget = budget::Value::new(NESTING_BUDGET);818819			dispatch_tx::<T, _>(collection_id, |d| {820				d.delete_token_properties(sender, token_id, property_keys, &budget)821			})822		}823824		/// Add or change token property permissions of a collection.825		///826		/// Without a permission for a particular key, a property with that key827		/// cannot be created in a token.828		///829		/// # Permissions830		///831		/// * Collection owner832		/// * Collection admin833		///834		/// # Arguments835		///836		/// * `collection_id`: ID of the modified collection.837		/// * `property_permissions`: Vector of permissions for property keys.838		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.839		#[pallet::call_index(17)]840		#[pallet::weight(T::CommonWeightInfo::set_token_property_permissions(property_permissions.len() as u32))]841		pub fn set_token_property_permissions(842			origin: OriginFor<T>,843			collection_id: CollectionId,844			property_permissions: Vec<PropertyKeyPermission>,845		) -> DispatchResultWithPostInfo {846			ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);847848			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);849850			dispatch_tx::<T, _>(collection_id, |d| {851				d.set_token_property_permissions(&sender, property_permissions)852			})853		}854855		/// Create multiple items within a collection with explicitly specified initial parameters.856		///857		/// # Permissions858		///859		/// * Collection owner860		/// * Collection admin861		/// * Anyone if862		///     * Allow List is enabled, and863		///     * Address is added to allow list, and864		///     * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])865		///866		/// # Arguments867		///868		/// * `collection_id`: ID of the collection to which the tokens would belong.869		/// * `data`: Explicit item creation data.870		#[pallet::call_index(18)]871		#[pallet::weight(T::CommonWeightInfo::create_multiple_items_ex(&data))]872		pub fn create_multiple_items_ex(873			origin: OriginFor<T>,874			collection_id: CollectionId,875			data: CreateItemExData<T::CrossAccountId>,876		) -> DispatchResultWithPostInfo {877			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);878			let budget = budget::Value::new(NESTING_BUDGET);879880			dispatch_tx::<T, _>(collection_id, |d| {881				d.create_multiple_items_ex(sender, data, &budget)882			})883		}884885		/// Completely allow or disallow transfers for a particular collection.886		///887		/// # Permissions888		///889		/// * Collection owner890		///891		/// # Arguments892		///893		/// * `collection_id`: ID of the collection.894		/// * `value`: New value of the flag, are transfers allowed?895		#[pallet::call_index(19)]896		#[pallet::weight(<SelfWeightOf<T>>::set_transfers_enabled_flag())]897		pub fn set_transfers_enabled_flag(898			origin: OriginFor<T>,899			collection_id: CollectionId,900			value: bool,901		) -> DispatchResult {902			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);903			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;904			target_collection.check_is_internal()?;905			target_collection.check_is_owner(&sender)?;906907			// =========908909			target_collection.limits.transfers_enabled = Some(value);910			target_collection.save()911		}912913		/// Destroy an item.914		///915		/// # Permissions916		///917		/// * Collection owner918		/// * Collection admin919		/// * Current item owner920		///921		/// # Arguments922		///923		/// * `collection_id`: ID of the collection to which the item belongs.924		/// * `item_id`: ID of item to burn.925		/// * `value`: Number of pieces of the item to destroy.926		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.927		///     * Fungible Mode: The desired number of pieces to burn.928		///     * Re-Fungible Mode: The desired number of pieces to burn.929		#[pallet::call_index(20)]930		#[pallet::weight(T::CommonWeightInfo::burn_item())]931		pub fn burn_item(932			origin: OriginFor<T>,933			collection_id: CollectionId,934			item_id: TokenId,935			value: u128,936		) -> DispatchResultWithPostInfo {937			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);938939			let post_info =940				dispatch_tx::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;941			if value == 1 {942				<NftTransferBasket<T>>::remove(collection_id, item_id);943				<NftApproveBasket<T>>::remove(collection_id, item_id);944			}945			// Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?946			// <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());947			// <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));948			Ok(post_info)949		}950951		/// Destroy a token on behalf of the owner as a non-owner account.952		///953		/// See also: [`approve`][`Pallet::approve`].954		///955		/// After this method executes, one approval is removed from the total so that956		/// the approved address will not be able to transfer this item again from this owner.957		///958		/// # Permissions959		///960		/// * Collection owner961		/// * Collection admin962		/// * Current token owner963		/// * Address approved by current item owner964		///965		/// # Arguments966		///967		/// * `from`: The owner of the burning item.968		/// * `collection_id`: ID of the collection to which the item belongs.969		/// * `item_id`: ID of item to burn.970		/// * `value`: Number of pieces to burn.971		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.972		///     * Fungible Mode: The desired number of pieces to burn.973		///     * Re-Fungible Mode: The desired number of pieces to burn.974		#[pallet::call_index(21)]975		#[pallet::weight(T::CommonWeightInfo::burn_from())]976		pub fn burn_from(977			origin: OriginFor<T>,978			collection_id: CollectionId,979			from: T::CrossAccountId,980			item_id: TokenId,981			value: u128,982		) -> DispatchResultWithPostInfo {983			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);984			let budget = budget::Value::new(NESTING_BUDGET);985986			dispatch_tx::<T, _>(collection_id, |d| {987				d.burn_from(sender, from, item_id, value, &budget)988			})989		}990991		/// Change ownership of the token.992		///993		/// # Permissions994		///995		/// * Collection owner996		/// * Collection admin997		/// * Current token owner998		///999		/// # Arguments1000		///1001		/// * `recipient`: Address of token recipient.1002		/// * `collection_id`: ID of the collection the item belongs to.1003		/// * `item_id`: ID of the item.1004		///     * Non-Fungible Mode: Required.1005		///     * Fungible Mode: Ignored.1006		///     * Re-Fungible Mode: Required.1007		///1008		/// * `value`: Amount to transfer.1009		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.1010		///     * Fungible Mode: The desired number of pieces to transfer.1011		///     * Re-Fungible Mode: The desired number of pieces to transfer.1012		#[pallet::call_index(22)]1013		#[pallet::weight(T::CommonWeightInfo::transfer())]1014		pub fn transfer(1015			origin: OriginFor<T>,1016			recipient: T::CrossAccountId,1017			collection_id: CollectionId,1018			item_id: TokenId,1019			value: u128,1020		) -> DispatchResultWithPostInfo {1021			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1022			let budget = budget::Value::new(NESTING_BUDGET);10231024			dispatch_tx::<T, _>(collection_id, |d| {1025				d.transfer(sender, recipient, item_id, value, &budget)1026			})1027		}10281029		/// Allow a non-permissioned address to transfer or burn an item.1030		///1031		/// # Permissions1032		///1033		/// * Collection owner1034		/// * Collection admin1035		/// * Current item owner1036		///1037		/// # Arguments1038		///1039		/// * `spender`: Account to be approved to make specific transactions on non-owned tokens.1040		/// * `collection_id`: ID of the collection the item belongs to.1041		/// * `item_id`: ID of the item transactions on which are now approved.1042		/// * `amount`: Number of pieces of the item approved for a transaction (maximum of 1 for NFTs).1043		/// Set to 0 to revoke the approval.1044		#[pallet::call_index(23)]1045		#[pallet::weight(T::CommonWeightInfo::approve())]1046		pub fn approve(1047			origin: OriginFor<T>,1048			spender: T::CrossAccountId,1049			collection_id: CollectionId,1050			item_id: TokenId,1051			amount: u128,1052		) -> DispatchResultWithPostInfo {1053			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);10541055			dispatch_tx::<T, _>(collection_id, |d| {1056				d.approve(sender, spender, item_id, amount)1057			})1058		}10591060		/// Allow a non-permissioned address to transfer or burn an item from owner's eth mirror.1061		///1062		/// # Permissions1063		///1064		/// * Collection owner1065		/// * Collection admin1066		/// * Current item owner1067		///1068		/// # Arguments1069		///1070		/// * `from`: Owner's account eth mirror1071		/// * `to`: Account to be approved to make specific transactions on non-owned tokens.1072		/// * `collection_id`: ID of the collection the item belongs to.1073		/// * `item_id`: ID of the item transactions on which are now approved.1074		/// * `amount`: Number of pieces of the item approved for a transaction (maximum of 1 for NFTs).1075		/// Set to 0 to revoke the approval.1076		#[pallet::call_index(24)]1077		#[pallet::weight(T::CommonWeightInfo::approve_from())]1078		pub fn approve_from(1079			origin: OriginFor<T>,1080			from: T::CrossAccountId,1081			to: T::CrossAccountId,1082			collection_id: CollectionId,1083			item_id: TokenId,1084			amount: u128,1085		) -> DispatchResultWithPostInfo {1086			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);10871088			dispatch_tx::<T, _>(collection_id, |d| {1089				d.approve_from(sender, from, to, item_id, amount)1090			})1091		}10921093		/// Change ownership of an item on behalf of the owner as a non-owner account.1094		///1095		/// See the [`approve`][`Pallet::approve`] method for additional information.1096		///1097		/// After this method executes, one approval is removed from the total so that1098		/// the approved address will not be able to transfer this item again from this owner.1099		///1100		/// # Permissions1101		///1102		/// * Collection owner1103		/// * Collection admin1104		/// * Current item owner1105		/// * Address approved by current item owner1106		///1107		/// # Arguments1108		///1109		/// * `from`: Address that currently owns the token.1110		/// * `recipient`: Address of the new token-owner-to-be.1111		/// * `collection_id`: ID of the collection the item.1112		/// * `item_id`: ID of the item to be transferred.1113		/// * `value`: Amount to transfer.1114		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.1115		///     * Fungible Mode: The desired number of pieces to transfer.1116		///     * Re-Fungible Mode: The desired number of pieces to transfer.1117		#[pallet::call_index(25)]1118		#[pallet::weight(T::CommonWeightInfo::transfer_from())]1119		pub fn transfer_from(1120			origin: OriginFor<T>,1121			from: T::CrossAccountId,1122			recipient: T::CrossAccountId,1123			collection_id: CollectionId,1124			item_id: TokenId,1125			value: u128,1126		) -> DispatchResultWithPostInfo {1127			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1128			let budget = budget::Value::new(NESTING_BUDGET);11291130			dispatch_tx::<T, _>(collection_id, |d| {1131				d.transfer_from(sender, from, recipient, item_id, value, &budget)1132			})1133		}11341135		/// Set specific limits of a collection. Empty, or None fields mean chain default.1136		///1137		/// # Permissions1138		///1139		/// * Collection owner1140		/// * Collection admin1141		///1142		/// # Arguments1143		///1144		/// * `collection_id`: ID of the modified collection.1145		/// * `new_limit`: New limits of the collection. Fields that are not set (None)1146		/// will not overwrite the old ones.1147		#[pallet::call_index(26)]1148		#[pallet::weight(<SelfWeightOf<T>>::set_collection_limits())]1149		pub fn set_collection_limits(1150			origin: OriginFor<T>,1151			collection_id: CollectionId,1152			new_limit: CollectionLimits,1153		) -> DispatchResult {1154			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1155			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1156			<PalletCommon<T>>::update_limits(&sender, &mut target_collection, new_limit)1157		}11581159		/// Set specific permissions of a collection. Empty, or None fields mean chain default.1160		///1161		/// # Permissions1162		///1163		/// * Collection owner1164		/// * Collection admin1165		///1166		/// # Arguments1167		///1168		/// * `collection_id`: ID of the modified collection.1169		/// * `new_permission`: New permissions of the collection. Fields that are not set (None)1170		/// will not overwrite the old ones.1171		#[pallet::call_index(27)]1172		#[pallet::weight(<SelfWeightOf<T>>::set_collection_limits())]1173		pub fn set_collection_permissions(1174			origin: OriginFor<T>,1175			collection_id: CollectionId,1176			new_permission: CollectionPermissions,1177		) -> DispatchResult {1178			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1179			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1180			<PalletCommon<T>>::update_permissions(&sender, &mut target_collection, new_permission)1181		}11821183		/// Re-partition a refungible token, while owning all of its parts/pieces.1184		///1185		/// # Permissions1186		///1187		/// * Token owner (must own every part)1188		///1189		/// # Arguments1190		///1191		/// * `collection_id`: ID of the collection the RFT belongs to.1192		/// * `token_id`: ID of the RFT.1193		/// * `amount`: New number of parts/pieces into which the token shall be partitioned.1194		#[pallet::call_index(28)]1195		#[pallet::weight(T::RefungibleExtensionsWeightInfo::repartition())]1196		pub fn repartition(1197			origin: OriginFor<T>,1198			collection_id: CollectionId,1199			token_id: TokenId,1200			amount: u128,1201		) -> DispatchResultWithPostInfo {1202			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1203			dispatch_tx::<T, _>(collection_id, |d| {1204				if let Some(refungible_extensions) = d.refungible_extensions() {1205					refungible_extensions.repartition(&sender, token_id, amount)1206				} else {1207					fail!(<Error<T>>::RepartitionCalledOnNonRefungibleCollection)1208				}1209			})1210		}12111212		/// Sets or unsets the approval of a given operator.1213		///1214		/// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.1215		///1216		/// # Arguments1217		///1218		/// * `owner`: Token owner1219		/// * `operator`: Operator1220		/// * `approve`: Should operator status be granted or revoked?1221		#[pallet::call_index(29)]1222		#[pallet::weight(T::CommonWeightInfo::set_allowance_for_all())]1223		pub fn set_allowance_for_all(1224			origin: OriginFor<T>,1225			collection_id: CollectionId,1226			operator: T::CrossAccountId,1227			approve: bool,1228		) -> DispatchResultWithPostInfo {1229			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1230			dispatch_tx::<T, _>(collection_id, |d| {1231				d.set_allowance_for_all(sender, operator, approve)1232			})1233		}12341235		/// Repairs a collection if the data was somehow corrupted.1236		///1237		/// # Arguments1238		///1239		/// * `collection_id`: ID of the collection to repair.1240		#[pallet::call_index(30)]1241		#[pallet::weight(<SelfWeightOf<T>>::force_repair_collection())]1242		pub fn force_repair_collection(1243			origin: OriginFor<T>,1244			collection_id: CollectionId,1245		) -> DispatchResult {1246			ensure_root(origin)?;1247			<PalletCommon<T>>::repair_collection(collection_id)1248		}12491250		/// Repairs a token if the data was somehow corrupted.1251		///1252		/// # Arguments1253		///1254		/// * `collection_id`: ID of the collection the item belongs to.1255		/// * `item_id`: ID of the item.1256		#[pallet::call_index(31)]1257		#[pallet::weight(T::CommonWeightInfo::force_repair_item())]1258		pub fn force_repair_item(1259			origin: OriginFor<T>,1260			collection_id: CollectionId,1261			item_id: TokenId,1262		) -> DispatchResultWithPostInfo {1263			ensure_root(origin)?;1264			dispatch_tx::<T, _>(collection_id, |d| d.repair_item(item_id))1265		}1266	}12671268	impl<T: Config> Pallet<T> {1269		/// Force set `sponsor` for `collection`.1270		///1271		/// Differs from [`set_collection_sponsor`][`Pallet::set_collection_sponsor`] in that confirmation1272		/// from the `sponsor` is not required.1273		///1274		/// # Arguments1275		///1276		/// * `sponsor`: ID of the account of the sponsor-to-be.1277		/// * `collection_id`: ID of the modified collection.1278		pub fn force_set_sponsor(1279			sponsor: T::AccountId,1280			collection_id: CollectionId,1281		) -> DispatchResult {1282			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1283			target_collection.force_set_sponsor(sponsor.clone())1284		}12851286		/// Force remove `sponsor` for `collection`.1287		///1288		/// Differs from `remove_sponsor` in that1289		/// it doesn't require consent from the `owner` of the collection.1290		///1291		/// # Arguments1292		///1293		/// * `collection_id`: ID of the modified collection.1294		pub fn force_remove_collection_sponsor(collection_id: CollectionId) -> DispatchResult {1295			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1296			target_collection.force_remove_sponsor()1297		}12981299		#[inline(always)]1300		pub(crate) fn destroy_collection_internal(1301			sender: T::CrossAccountId,1302			collection_id: CollectionId,1303		) -> DispatchResult {1304			let collection = <CollectionHandle<T>>::try_get(collection_id)?;1305			collection.check_is_internal()?;13061307			T::CollectionDispatch::destroy(sender, collection)?;13081309			// TODO: basket cleanup should be moved elsewhere1310			// Maybe runtime dispatch.rs should perform it?13111312			let _ = <NftTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1313			let _ = <FungibleTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1314			let _ = <ReFungibleTransferBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);13151316			let _ = <NftApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1317			let _ = <FungibleApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1318			let _ = <RefungibleApproveBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);13191320			Ok(())1321		}1322	}1323}