git.delta.rocks / unique-network / refs/commits / 0660dd124ff7

difftreelog

fix code style

Igor Kozyrev2022-02-17parent: #c091cef.patch.diff
in: master

4 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -13,9 +13,8 @@
 use pallet_evm::GasWeightMapping;
 use up_data_structs::{
 	COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,
-	MAX_TOKEN_PREFIX_LENGTH,
-	COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, Pays, PostDispatchInfo, TokenId, Weight,
-	WithdrawReasons, CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode,
+	MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, Pays, PostDispatchInfo,
+	TokenId, Weight, WithdrawReasons, CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode,
 	NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
 	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT, CUSTOM_DATA_LIMIT, CollectionLimits,
 	CustomDataLimit, CreateCollectionData, SponsorshipState,
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -3,8 +3,7 @@
 use erc::ERC721Events;
 use frame_support::{BoundedVec, ensure};
 use up_data_structs::{
-	AccessMode, Collection, CollectionId, CustomDataLimit, TokenId,
-	CreateCollectionData,
+	AccessMode, Collection, CollectionId, CustomDataLimit, TokenId, CreateCollectionData,
 };
 use pallet_common::{
 	Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -2,8 +2,8 @@
 
 use frame_support::{ensure, BoundedVec};
 use up_data_structs::{
-	AccessMode, Collection, CollectionId, CustomDataLimit,
-	MAX_REFUNGIBLE_PIECES, TokenId, CreateCollectionData,
+	AccessMode, Collection, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,
+	CreateCollectionData,
 };
 use pallet_common::{
 	Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
before · pallets/unique/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]7#![cfg_attr(not(feature = "std"), no_std)]8#![allow(9	clippy::too_many_arguments,10	clippy::unnecessary_mut_passed,11	clippy::unused_unit12)]1314extern crate alloc;1516pub use serde::{Serialize, Deserialize};1718pub use frame_support::{19	construct_runtime, decl_module, decl_storage, decl_error, decl_event,20	dispatch::DispatchResult,21	ensure, fail, parameter_types,22	traits::{23		ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness,24		IsSubType, WithdrawReasons,25	},26	weights::{27		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},28		DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,29		WeightToFeePolynomial, DispatchClass,30	},31	StorageValue, transactional,32	pallet_prelude::{DispatchResultWithPostInfo, ConstU32},33	BoundedVec,34};35use scale_info::TypeInfo;36use frame_system::{self as system, ensure_signed};37use sp_runtime::{sp_std::prelude::Vec};38use up_data_structs::{39	MAX_DECIMAL_POINTS,40	VARIABLE_ON_CHAIN_SCHEMA_LIMIT, CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,41	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH,42	MAX_TOKEN_PREFIX_LENGTH, AccessMode, Collection, CreateItemData, CollectionLimits,43	CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState, MetaUpdatePermission,44	CreateCollectionData, CustomDataLimit,45};46use pallet_common::{47	account::CrossAccountId, CollectionHandle, Pallet as PalletCommon, Error as CommonError,48	CommonWeightInfo,49};50use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle};51use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};52use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};5354#[cfg(test)]55mod mock;5657#[cfg(test)]58mod tests;5960mod eth;61mod sponsorship;62pub use sponsorship::UniqueSponsorshipHandler;63pub use eth::sponsoring::UniqueEthSponsorshipHandler;6465pub use eth::UniqueErcSupport;6667pub mod common;68use common::CommonWeights;69pub mod dispatch;70use dispatch::dispatch_call;7172#[cfg(feature = "runtime-benchmarks")]73mod benchmarking;74pub mod weights;75use weights::WeightInfo;7677decl_error! {78	/// Error for non-fungible-token module.79	pub enum Error for Module<T: Config> {80		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.81		CollectionDecimalPointLimitExceeded,82		/// This address is not set as sponsor, use setCollectionSponsor first.83		ConfirmUnsetSponsorFail,84		/// Length of items properties must be greater than 0.85		EmptyArgument,86	}87}8889pub trait Config:90	system::Config91	+ pallet_evm_coder_substrate::Config92	+ pallet_common::Config93	+ pallet_nonfungible::Config94	+ pallet_refungible::Config95	+ pallet_fungible::Config96	+ Sized97	+ TypeInfo98{99	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;100101	/// Weight information for extrinsics in this pallet.102	type WeightInfo: WeightInfo;103}104105decl_event! {106	pub enum Event<T>107	where108		<T as frame_system::Config>::AccountId,109		<T as pallet_common::Config>::CrossAccountId,110	{111		/// Collection sponsor was removed112		///113		/// # Arguments114		///115		/// * collection_id: Globally unique collection identifier.116		CollectionSponsorRemoved(CollectionId),117118		/// Collection admin was added119		///120		/// # Arguments121		///122		/// * collection_id: Globally unique collection identifier.123		///124		/// * admin:  Admin address.125		CollectionAdminAdded(CollectionId, CrossAccountId),126127		/// Collection owned was change128		///129		/// # Arguments130		///131		/// * collection_id: Globally unique collection identifier.132		///133		/// * owner:  New owner address.134		CollectionOwnedChanged(CollectionId, AccountId),135136		/// Collection sponsor was set137		///138		/// # Arguments139		///140		/// * collection_id: Globally unique collection identifier.141		///142		/// * owner:  New sponsor address.143		CollectionSponsorSet(CollectionId, AccountId),144145		/// const on chain schema was set146		///147		/// # Arguments148		///149		/// * collection_id: Globally unique collection identifier.150		ConstOnChainSchemaSet(CollectionId),151152		/// New sponsor was confirm153		///154		/// # Arguments155		///156		/// * collection_id: Globally unique collection identifier.157		///158		/// * sponsor:  New sponsor address.159		SponsorshipConfirmed(CollectionId, AccountId),160161		/// Collection admin was removed162		///163		/// # Arguments164		///165		/// * collection_id: Globally unique collection identifier.166		///167		/// * admin:  Admin address.168		CollectionAdminRemoved(CollectionId, CrossAccountId),169170		/// Address was remove from allow list171		///172		/// # Arguments173		///174		/// * collection_id: Globally unique collection identifier.175		///176		/// * user:  Address.177		AllowListAddressRemoved(CollectionId, CrossAccountId),178179		/// Address was add to allow list180		///181		/// # Arguments182		///183		/// * collection_id: Globally unique collection identifier.184		///185		/// * user:  Address.186		AllowListAddressAdded(CollectionId, CrossAccountId),187188		/// Collection limits was set189		///190		/// # Arguments191		///192		/// * collection_id: Globally unique collection identifier.193		CollectionLimitSet(CollectionId),194195		/// Mint permission	was set196		///197		/// # Arguments198		///199		/// * collection_id: Globally unique collection identifier.200		MintPermissionSet(CollectionId),201202		/// Offchain schema was set203		///204		/// # Arguments205		///206		/// * collection_id: Globally unique collection identifier.207		OffchainSchemaSet(CollectionId),208209		/// Public access mode was set210		///211		/// # Arguments212		///213		/// * collection_id: Globally unique collection identifier.214		///215		/// * mode: New access state.216		PublicAccessModeSet(CollectionId, AccessMode),217218		/// Schema version was set219		///220		/// # Arguments221		///222		/// * collection_id: Globally unique collection identifier.223		SchemaVersionSet(CollectionId),224225		/// Variable on chain schema was set226		///227		/// # Arguments228		///229		/// * collection_id: Globally unique collection identifier.230		VariableOnChainSchemaSet(CollectionId),231	}232}233234type SelfWeightOf<T> = <T as Config>::WeightInfo;235236// # Used definitions237//238// ## User control levels239//240// chain-controlled - key is uncontrolled by user241//                    i.e autoincrementing index242//                    can use non-cryptographic hash243// real - key is controlled by user244//        but it is hard to generate enough colliding values, i.e owner of signed txs245//        can use non-cryptographic hash246// controlled - key is completly controlled by users247//              i.e maps with mutable keys248//              should use cryptographic hash249//250// ## User control level downgrade reasons251//252// ?1 - chain-controlled -> controlled253//      collections/tokens can be destroyed, resulting in massive holes254// ?2 - chain-controlled -> controlled255//      same as ?1, but can be only added, resulting in easier exploitation256// ?3 - real -> controlled257//      no confirmation required, so addresses can be easily generated258decl_storage! {259	trait Store for Module<T: Config> as Unique {260261		//#region Private members262		/// Used for migrations263		ChainVersion: u64;264		//#endregion265266		//#region Tokens transfer rate limit baskets267		/// (Collection id (controlled?2), who created (real))268		/// TODO: Off chain worker should remove from this map when collection gets removed269		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;270		/// Collection id (controlled?2), token id (controlled?2)271		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;272		/// Collection id (controlled?2), owning user (real)273		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;274		/// Collection id (controlled?2), token id (controlled?2)275		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;276		//#endregion277278		/// Variable metadata sponsoring279		/// Collection id (controlled?2), token id (controlled?2)280		pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;281		/// Approval sponsoring282		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;283		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;284		pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;285	}286}287288decl_module! {289	pub struct Module<T: Config> for enum Call290	where291		origin: T::Origin292	{293		type Error = Error<T>;294295		fn deposit_event() = default;296297		fn on_initialize(_now: T::BlockNumber) -> Weight {298			0299		}300301		/// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.302		///303		/// # Permissions304		///305		/// * Anyone.306		///307		/// # Arguments308		///309		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.310		///311		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.312		///313		/// * token_prefix: UTF-8 string with token prefix.314		///315		/// * mode: [CollectionMode] collection type and type dependent data.316		// returns collection ID317		#[weight = <SelfWeightOf<T>>::create_collection()]318		#[transactional]319		#[deprecated]320		pub fn create_collection(origin,321								 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,322								 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,323								 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,324								 mode: CollectionMode) -> DispatchResult  {325			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {326				name: collection_name,327				description: collection_description,328				token_prefix,329				mode,330				..Default::default()331			};332			Self::create_collection_ex(origin, data)333		}334335		/// This method creates a collection336		///337		/// Prefer it to deprecated [`created_collection`] method338		#[weight = <SelfWeightOf<T>>::create_collection()]339		#[transactional]340		pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {341			let owner = ensure_signed(origin)?;342343			let _id = match data.mode {344				CollectionMode::NFT => {<PalletNonfungible<T>>::init_collection(owner, data)?},345				CollectionMode::Fungible(decimal_points) => {346					// check params347					ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);348					<PalletFungible<T>>::init_collection(owner, data)?349				}350				CollectionMode::ReFungible => {351					<PalletRefungible<T>>::init_collection(owner, data)?352				}353			};354355			Ok(())356		}357358		/// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.359		///360		/// # Permissions361		///362		/// * Collection Owner.363		///364		/// # Arguments365		///366		/// * collection_id: collection to destroy.367		#[weight = <SelfWeightOf<T>>::destroy_collection()]368		#[transactional]369		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {370			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);371372			let collection = <CollectionHandle<T>>::try_get(collection_id)?;373			collection.check_is_owner(&sender)?;374375			// =========376377			match collection.mode {378				CollectionMode::ReFungible => PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?,379				CollectionMode::Fungible(_) => PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?,380				CollectionMode::NFT => PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?,381			}382383			<NftTransferBasket<T>>::remove_prefix(collection_id, None);384			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);385			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);386387			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);388			<NftApproveBasket<T>>::remove_prefix(collection_id, None);389			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);390			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);391392			Ok(())393		}394395		/// Add an address to allow list.396		///397		/// # Permissions398		///399		/// * Collection Owner400		/// * Collection Admin401		///402		/// # Arguments403		///404		/// * collection_id.405		///406		/// * address.407		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]408		#[transactional]409		pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{410411			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);412			let collection = <CollectionHandle<T>>::try_get(collection_id)?;413414			<PalletCommon<T>>::toggle_allowlist(415				&collection,416				&sender,417				&address,418				true,419			)?;420421			Self::deposit_event(Event::<T>::AllowListAddressAdded(422				collection_id,423				address424			));425426			Ok(())427		}428429		/// Remove an address from allow list.430		///431		/// # Permissions432		///433		/// * Collection Owner434		/// * Collection Admin435		///436		/// # Arguments437		///438		/// * collection_id.439		///440		/// * address.441		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]442		#[transactional]443		pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{444445			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);446			let collection = <CollectionHandle<T>>::try_get(collection_id)?;447448			<PalletCommon<T>>::toggle_allowlist(449				&collection,450				&sender,451				&address,452				false,453			)?;454455			<Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(456				collection_id,457				address458			));459460			Ok(())461		}462463		/// Toggle between normal and allow list access for the methods with access for `Anyone`.464		///465		/// # Permissions466		///467		/// * Collection Owner.468		///469		/// # Arguments470		///471		/// * collection_id.472		///473		/// * mode: [AccessMode]474		#[weight = <SelfWeightOf<T>>::set_public_access_mode()]475		#[transactional]476		pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult477		{478			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);479480			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;481			target_collection.check_is_owner(&sender)?;482483			target_collection.access = mode.clone();484485			<Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(486				collection_id,487				mode488			));489490			target_collection.save()491		}492493		/// Allows Anyone to create tokens if:494		/// * Allow List is enabled, and495		/// * Address is added to allow list, and496		/// * This method was called with True parameter497		///498		/// # Permissions499		/// * Collection Owner500		///501		/// # Arguments502		///503		/// * collection_id.504		///505		/// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.506		#[weight = <SelfWeightOf<T>>::set_mint_permission()]507		#[transactional]508		pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult509		{510			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);511512			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;513			target_collection.check_is_owner(&sender)?;514515			target_collection.mint_mode = mint_permission;516517			<Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(518				collection_id519			));520521			target_collection.save()522		}523524		/// Change the owner of the collection.525		///526		/// # Permissions527		///528		/// * Collection Owner.529		///530		/// # Arguments531		///532		/// * collection_id.533		///534		/// * new_owner.535		#[weight = <SelfWeightOf<T>>::change_collection_owner()]536		#[transactional]537		pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {538539			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);540541			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;542			target_collection.check_is_owner(&sender)?;543544			target_collection.owner = new_owner.clone();545			<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(546				collection_id,547				new_owner548			));549550			target_collection.save()551		}552553		/// Adds an admin of the Collection.554		/// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.555		///556		/// # Permissions557		///558		/// * Collection Owner.559		/// * Collection Admin.560		///561		/// # Arguments562		///563		/// * collection_id: ID of the Collection to add admin for.564		///565		/// * new_admin_id: Address of new admin to add.566		#[weight = <SelfWeightOf<T>>::add_collection_admin()]567		#[transactional]568		pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {569			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);570			let collection = <CollectionHandle<T>>::try_get(collection_id)?;571572			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(573				collection_id,574				new_admin_id.clone()575			));576577			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)578		}579580		/// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.581		///582		/// # Permissions583		///584		/// * Collection Owner.585		/// * Collection Admin.586		///587		/// # Arguments588		///589		/// * collection_id: ID of the Collection to remove admin for.590		///591		/// * account_id: Address of admin to remove.592		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]593		#[transactional]594		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {595			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);596			let collection = <CollectionHandle<T>>::try_get(collection_id)?;597598			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(599				collection_id,600				account_id.clone()601			));602603			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)604		}605606		/// # Permissions607		///608		/// * Collection Owner609		///610		/// # Arguments611		///612		/// * collection_id.613		///614		/// * new_sponsor.615		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]616		#[transactional]617		pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {618			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);619620			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;621			target_collection.check_is_owner(&sender)?;622623			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());624625			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(626				collection_id,627				new_sponsor628			));629630			target_collection.save()631		}632633		/// # Permissions634		///635		/// * Sponsor.636		///637		/// # Arguments638		///639		/// * collection_id.640		#[weight = <SelfWeightOf<T>>::confirm_sponsorship()]641		#[transactional]642		pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {643			let sender = ensure_signed(origin)?;644645			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;646			ensure!(647				target_collection.sponsorship.pending_sponsor() == Some(&sender),648				Error::<T>::ConfirmUnsetSponsorFail649			);650651			target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());652653			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(654				collection_id,655				sender656			));657658			target_collection.save()659		}660661		/// Switch back to pay-per-own-transaction model.662		///663		/// # Permissions664		///665		/// * Collection owner.666		///667		/// # Arguments668		///669		/// * collection_id.670		#[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]671		#[transactional]672		pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {673			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);674675			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;676			target_collection.check_is_owner(&sender)?;677678			target_collection.sponsorship = SponsorshipState::Disabled;679680			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(681				collection_id682			));683			target_collection.save()684		}685686		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.687		///688		/// # Permissions689		///690		/// * Collection Owner.691		/// * Collection Admin.692		/// * Anyone if693		///     * Allow List is enabled, and694		///     * Address is added to allow list, and695		///     * MintPermission is enabled (see SetMintPermission method)696		///697		/// # Arguments698		///699		/// * collection_id: ID of the collection.700		///701		/// * owner: Address, initial owner of the NFT.702		///703		/// * data: Token data to store on chain.704		#[weight = <CommonWeights<T>>::create_item()]705		#[transactional]706		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {707			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);708709			dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data))710		}711712		/// This method creates multiple items in a collection created with CreateCollection method.713		///714		/// # Permissions715		///716		/// * Collection Owner.717		/// * Collection Admin.718		/// * Anyone if719		///     * Allow List is enabled, and720		///     * Address is added to allow list, and721		///     * MintPermission is enabled (see SetMintPermission method)722		///723		/// # Arguments724		///725		/// * collection_id: ID of the collection.726		///727		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].728		///729		/// * owner: Address, initial owner of the NFT.730		#[weight = <CommonWeights<T>>::create_multiple_items(items_data.len() as u32)]731		#[transactional]732		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {733			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);734			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);735736			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data))737		}738739		// TODO! transaction weight740741		/// Set transfers_enabled value for particular collection742		///743		/// # Permissions744		///745		/// * Collection Owner.746		///747		/// # Arguments748		///749		/// * collection_id: ID of the collection.750		///751		/// * value: New flag value.752		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]753		#[transactional]754		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {755			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);756			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;757			target_collection.check_is_owner(&sender)?;758759			// =========760761			target_collection.limits.transfers_enabled = Some(value);762			target_collection.save()763		}764765		/// Destroys a concrete instance of NFT.766		///767		/// # Permissions768		///769		/// * Collection Owner.770		/// * Collection Admin.771		/// * Current NFT Owner.772		///773		/// # Arguments774		///775		/// * collection_id: ID of the collection.776		///777		/// * item_id: ID of NFT to burn.778		#[weight = <CommonWeights<T>>::burn_item()]779		#[transactional]780		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {781			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);782783			let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;784			if value == 1 {785				<NftTransferBasket<T>>::remove(collection_id, item_id);786				<NftApproveBasket<T>>::remove(collection_id, item_id);787			}788			// Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?789			// <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());790			// <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));791			Ok(post_info)792		}793794		/// Destroys a concrete instance of NFT on behalf of the owner795		/// See also: [`approve`]796		///797		/// # Permissions798		///799		/// * Collection Owner.800		/// * Collection Admin.801		/// * Current NFT Owner.802		///803		/// # Arguments804		///805		/// * collection_id: ID of the collection.806		///807		/// * item_id: ID of NFT to burn.808		///809		/// * from: owner of item810		#[weight = <CommonWeights<T>>::burn_from()]811		#[transactional]812		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {813			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);814815			dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))816		}817818		/// Change ownership of the token.819		///820		/// # Permissions821		///822		/// * Collection Owner823		/// * Collection Admin824		/// * Current NFT owner825		///826		/// # Arguments827		///828		/// * recipient: Address of token recipient.829		///830		/// * collection_id.831		///832		/// * item_id: ID of the item833		///     * Non-Fungible Mode: Required.834		///     * Fungible Mode: Ignored.835		///     * Re-Fungible Mode: Required.836		///837		/// * value: Amount to transfer.838		///     * Non-Fungible Mode: Ignored839		///     * Fungible Mode: Must specify transferred amount840		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)841		#[weight = <CommonWeights<T>>::transfer()]842		#[transactional]843		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {844			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);845846			dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value))847		}848849		/// Set, change, or remove approved address to transfer the ownership of the NFT.850		///851		/// # Permissions852		///853		/// * Collection Owner854		/// * Collection Admin855		/// * Current NFT owner856		///857		/// # Arguments858		///859		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).860		///861		/// * collection_id.862		///863		/// * item_id: ID of the item.864		#[weight = <CommonWeights<T>>::approve()]865		#[transactional]866		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {867			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);868869			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))870		}871872		/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.873		///874		/// # Permissions875		/// * Collection Owner876		/// * Collection Admin877		/// * Current NFT owner878		/// * Address approved by current NFT owner879		///880		/// # Arguments881		///882		/// * from: Address that owns token.883		///884		/// * recipient: Address of token recipient.885		///886		/// * collection_id.887		///888		/// * item_id: ID of the item.889		///890		/// * value: Amount to transfer.891		#[weight = <CommonWeights<T>>::transfer_from()]892		#[transactional]893		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {894			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);895896			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value))897		}898899		/// Set off-chain data schema.900		///901		/// # Permissions902		///903		/// * Collection Owner904		/// * Collection Admin905		///906		/// # Arguments907		///908		/// * collection_id.909		///910		/// * schema: String representing the offchain data schema.911		#[weight = <CommonWeights<T>>::set_variable_metadata(data.len() as u32)]912		#[transactional]913		pub fn set_variable_meta_data (914			origin,915			collection_id: CollectionId,916			item_id: TokenId,917			data: BoundedVec<u8, CustomDataLimit>,918		) -> DispatchResultWithPostInfo {919			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);920921			dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))922		}923924		/// Set meta_update_permission value for particular collection925		///926		/// # Permissions927		///928		/// * Collection Owner.929		///930		/// # Arguments931		///932		/// * collection_id: ID of the collection.933		///934		/// * value: New flag value.935		#[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]936		#[transactional]937		pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {938			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);939			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;940941			ensure!(942				target_collection.meta_update_permission != MetaUpdatePermission::None,943				<CommonError<T>>::MetadataFlagFrozen,944			);945			target_collection.check_is_owner(&sender)?;946947			target_collection.meta_update_permission = value;948949			target_collection.save()950		}951952		/// Set schema standard953		/// ImageURL954		/// Unique955		///956		/// # Permissions957		///958		/// * Collection Owner959		/// * Collection Admin960		///961		/// # Arguments962		///963		/// * collection_id.964		///965		/// * schema: SchemaVersion: enum966		#[weight = <SelfWeightOf<T>>::set_schema_version()]967		#[transactional]968		pub fn set_schema_version(969			origin,970			collection_id: CollectionId,971			version: SchemaVersion972		) -> DispatchResult {973			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);974			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;975			target_collection.check_is_owner_or_admin(&sender)?;976			target_collection.schema_version = version;977978			<Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(979				collection_id980			));981982			target_collection.save()983		}984985		/// Set off-chain data schema.986		///987		/// # Permissions988		///989		/// * Collection Owner990		/// * Collection Admin991		///992		/// # Arguments993		///994		/// * collection_id.995		///996		/// * schema: String representing the offchain data schema.997		#[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]998		#[transactional]999		pub fn set_offchain_schema(1000			origin,1001			collection_id: CollectionId,1002			schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,1003		) -> DispatchResult {1004			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1005			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1006			target_collection.check_is_owner_or_admin(&sender)?;10071008			target_collection.offchain_schema = schema;10091010			<Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1011				collection_id1012			));10131014			target_collection.save()1015		}10161017		/// Set const on-chain data schema.1018		///1019		/// # Permissions1020		///1021		/// * Collection Owner1022		/// * Collection Admin1023		///1024		/// # Arguments1025		///1026		/// * collection_id.1027		///1028		/// * schema: String representing the const on-chain data schema.1029		#[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1030		#[transactional]1031		pub fn set_const_on_chain_schema (1032			origin,1033			collection_id: CollectionId,1034			schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1035		) -> DispatchResult {1036			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1037			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1038			target_collection.check_is_owner_or_admin(&sender)?;10391040			target_collection.const_on_chain_schema = schema;10411042			<Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1043				collection_id1044			));10451046			target_collection.save()1047		}10481049		/// Set variable on-chain data schema.1050		///1051		/// # Permissions1052		///1053		/// * Collection Owner1054		/// * Collection Admin1055		///1056		/// # Arguments1057		///1058		/// * collection_id.1059		///1060		/// * schema: String representing the variable on-chain data schema.1061		#[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1062		#[transactional]1063		pub fn set_variable_on_chain_schema (1064			origin,1065			collection_id: CollectionId,1066			schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>1067		) -> DispatchResult {1068			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1069			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1070			target_collection.check_is_owner_or_admin(&sender)?;10711072			target_collection.variable_on_chain_schema = schema;10731074			<Pallet<T>>::deposit_event(Event::<T>::VariableOnChainSchemaSet(1075				collection_id1076			));10771078			target_collection.save()1079		}10801081		#[weight = <SelfWeightOf<T>>::set_collection_limits()]1082		#[transactional]1083		pub fn set_collection_limits(1084			origin,1085			collection_id: CollectionId,1086			new_limit: CollectionLimits,1087		) -> DispatchResult {1088			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1089			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1090			target_collection.check_is_owner(&sender)?;1091			let old_limit = &target_collection.limits;10921093			target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10941095			<Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1096				collection_id1097			));10981099			target_collection.save()1100		}1101	}1102}
after · pallets/unique/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]7#![cfg_attr(not(feature = "std"), no_std)]8#![allow(9	clippy::too_many_arguments,10	clippy::unnecessary_mut_passed,11	clippy::unused_unit12)]1314extern crate alloc;1516pub use serde::{Serialize, Deserialize};1718pub use frame_support::{19	construct_runtime, decl_module, decl_storage, decl_error, decl_event,20	dispatch::DispatchResult,21	ensure, fail, parameter_types,22	traits::{23		ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness,24		IsSubType, WithdrawReasons,25	},26	weights::{27		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},28		DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,29		WeightToFeePolynomial, DispatchClass,30	},31	StorageValue, transactional,32	pallet_prelude::{DispatchResultWithPostInfo, ConstU32},33	BoundedVec,34};35use scale_info::TypeInfo;36use frame_system::{self as system, ensure_signed};37use sp_runtime::{sp_std::prelude::Vec};38use up_data_structs::{39	MAX_DECIMAL_POINTS, VARIABLE_ON_CHAIN_SCHEMA_LIMIT, CONST_ON_CHAIN_SCHEMA_LIMIT,40	OFFCHAIN_SCHEMA_LIMIT, MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH,41	MAX_TOKEN_PREFIX_LENGTH, AccessMode, Collection, CreateItemData, CollectionLimits,42	CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState, MetaUpdatePermission,43	CreateCollectionData, CustomDataLimit,44};45use pallet_common::{46	account::CrossAccountId, CollectionHandle, Pallet as PalletCommon, Error as CommonError,47	CommonWeightInfo,48};49use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle};50use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};51use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};5253#[cfg(test)]54mod mock;5556#[cfg(test)]57mod tests;5859mod eth;60mod sponsorship;61pub use sponsorship::UniqueSponsorshipHandler;62pub use eth::sponsoring::UniqueEthSponsorshipHandler;6364pub use eth::UniqueErcSupport;6566pub mod common;67use common::CommonWeights;68pub mod dispatch;69use dispatch::dispatch_call;7071#[cfg(feature = "runtime-benchmarks")]72mod benchmarking;73pub mod weights;74use weights::WeightInfo;7576decl_error! {77	/// Error for non-fungible-token module.78	pub enum Error for Module<T: Config> {79		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.80		CollectionDecimalPointLimitExceeded,81		/// This address is not set as sponsor, use setCollectionSponsor first.82		ConfirmUnsetSponsorFail,83		/// Length of items properties must be greater than 0.84		EmptyArgument,85	}86}8788pub trait Config:89	system::Config90	+ pallet_evm_coder_substrate::Config91	+ pallet_common::Config92	+ pallet_nonfungible::Config93	+ pallet_refungible::Config94	+ pallet_fungible::Config95	+ Sized96	+ TypeInfo97{98	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;99100	/// Weight information for extrinsics in this pallet.101	type WeightInfo: WeightInfo;102}103104decl_event! {105	pub enum Event<T>106	where107		<T as frame_system::Config>::AccountId,108		<T as pallet_common::Config>::CrossAccountId,109	{110		/// Collection sponsor was removed111		///112		/// # Arguments113		///114		/// * collection_id: Globally unique collection identifier.115		CollectionSponsorRemoved(CollectionId),116117		/// Collection admin was added118		///119		/// # Arguments120		///121		/// * collection_id: Globally unique collection identifier.122		///123		/// * admin:  Admin address.124		CollectionAdminAdded(CollectionId, CrossAccountId),125126		/// Collection owned was change127		///128		/// # Arguments129		///130		/// * collection_id: Globally unique collection identifier.131		///132		/// * owner:  New owner address.133		CollectionOwnedChanged(CollectionId, AccountId),134135		/// Collection sponsor was set136		///137		/// # Arguments138		///139		/// * collection_id: Globally unique collection identifier.140		///141		/// * owner:  New sponsor address.142		CollectionSponsorSet(CollectionId, AccountId),143144		/// const on chain schema was set145		///146		/// # Arguments147		///148		/// * collection_id: Globally unique collection identifier.149		ConstOnChainSchemaSet(CollectionId),150151		/// New sponsor was confirm152		///153		/// # Arguments154		///155		/// * collection_id: Globally unique collection identifier.156		///157		/// * sponsor:  New sponsor address.158		SponsorshipConfirmed(CollectionId, AccountId),159160		/// Collection admin was removed161		///162		/// # Arguments163		///164		/// * collection_id: Globally unique collection identifier.165		///166		/// * admin:  Admin address.167		CollectionAdminRemoved(CollectionId, CrossAccountId),168169		/// Address was remove from allow list170		///171		/// # Arguments172		///173		/// * collection_id: Globally unique collection identifier.174		///175		/// * user:  Address.176		AllowListAddressRemoved(CollectionId, CrossAccountId),177178		/// Address was add to allow list179		///180		/// # Arguments181		///182		/// * collection_id: Globally unique collection identifier.183		///184		/// * user:  Address.185		AllowListAddressAdded(CollectionId, CrossAccountId),186187		/// Collection limits was set188		///189		/// # Arguments190		///191		/// * collection_id: Globally unique collection identifier.192		CollectionLimitSet(CollectionId),193194		/// Mint permission	was set195		///196		/// # Arguments197		///198		/// * collection_id: Globally unique collection identifier.199		MintPermissionSet(CollectionId),200201		/// Offchain schema was set202		///203		/// # Arguments204		///205		/// * collection_id: Globally unique collection identifier.206		OffchainSchemaSet(CollectionId),207208		/// Public access mode was set209		///210		/// # Arguments211		///212		/// * collection_id: Globally unique collection identifier.213		///214		/// * mode: New access state.215		PublicAccessModeSet(CollectionId, AccessMode),216217		/// Schema version was set218		///219		/// # Arguments220		///221		/// * collection_id: Globally unique collection identifier.222		SchemaVersionSet(CollectionId),223224		/// Variable on chain schema was set225		///226		/// # Arguments227		///228		/// * collection_id: Globally unique collection identifier.229		VariableOnChainSchemaSet(CollectionId),230	}231}232233type SelfWeightOf<T> = <T as Config>::WeightInfo;234235// # Used definitions236//237// ## User control levels238//239// chain-controlled - key is uncontrolled by user240//                    i.e autoincrementing index241//                    can use non-cryptographic hash242// real - key is controlled by user243//        but it is hard to generate enough colliding values, i.e owner of signed txs244//        can use non-cryptographic hash245// controlled - key is completly controlled by users246//              i.e maps with mutable keys247//              should use cryptographic hash248//249// ## User control level downgrade reasons250//251// ?1 - chain-controlled -> controlled252//      collections/tokens can be destroyed, resulting in massive holes253// ?2 - chain-controlled -> controlled254//      same as ?1, but can be only added, resulting in easier exploitation255// ?3 - real -> controlled256//      no confirmation required, so addresses can be easily generated257decl_storage! {258	trait Store for Module<T: Config> as Unique {259260		//#region Private members261		/// Used for migrations262		ChainVersion: u64;263		//#endregion264265		//#region Tokens transfer rate limit baskets266		/// (Collection id (controlled?2), who created (real))267		/// TODO: Off chain worker should remove from this map when collection gets removed268		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;269		/// Collection id (controlled?2), token id (controlled?2)270		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;271		/// Collection id (controlled?2), owning user (real)272		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;273		/// Collection id (controlled?2), token id (controlled?2)274		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;275		//#endregion276277		/// Variable metadata sponsoring278		/// Collection id (controlled?2), token id (controlled?2)279		pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;280		/// Approval sponsoring281		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;282		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;283		pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;284	}285}286287decl_module! {288	pub struct Module<T: Config> for enum Call289	where290		origin: T::Origin291	{292		type Error = Error<T>;293294		fn deposit_event() = default;295296		fn on_initialize(_now: T::BlockNumber) -> Weight {297			0298		}299300		/// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.301		///302		/// # Permissions303		///304		/// * Anyone.305		///306		/// # Arguments307		///308		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.309		///310		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.311		///312		/// * token_prefix: UTF-8 string with token prefix.313		///314		/// * mode: [CollectionMode] collection type and type dependent data.315		// returns collection ID316		#[weight = <SelfWeightOf<T>>::create_collection()]317		#[transactional]318		#[deprecated]319		pub fn create_collection(origin,320								 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,321								 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,322								 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,323								 mode: CollectionMode) -> DispatchResult  {324			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {325				name: collection_name,326				description: collection_description,327				token_prefix,328				mode,329				..Default::default()330			};331			Self::create_collection_ex(origin, data)332		}333334		/// This method creates a collection335		///336		/// Prefer it to deprecated [`created_collection`] method337		#[weight = <SelfWeightOf<T>>::create_collection()]338		#[transactional]339		pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {340			let owner = ensure_signed(origin)?;341342			let _id = match data.mode {343				CollectionMode::NFT => {<PalletNonfungible<T>>::init_collection(owner, data)?},344				CollectionMode::Fungible(decimal_points) => {345					// check params346					ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);347					<PalletFungible<T>>::init_collection(owner, data)?348				}349				CollectionMode::ReFungible => {350					<PalletRefungible<T>>::init_collection(owner, data)?351				}352			};353354			Ok(())355		}356357		/// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.358		///359		/// # Permissions360		///361		/// * Collection Owner.362		///363		/// # Arguments364		///365		/// * collection_id: collection to destroy.366		#[weight = <SelfWeightOf<T>>::destroy_collection()]367		#[transactional]368		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {369			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);370371			let collection = <CollectionHandle<T>>::try_get(collection_id)?;372			collection.check_is_owner(&sender)?;373374			// =========375376			match collection.mode {377				CollectionMode::ReFungible => PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?,378				CollectionMode::Fungible(_) => PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?,379				CollectionMode::NFT => PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?,380			}381382			<NftTransferBasket<T>>::remove_prefix(collection_id, None);383			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);384			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);385386			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);387			<NftApproveBasket<T>>::remove_prefix(collection_id, None);388			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);389			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);390391			Ok(())392		}393394		/// Add an address to allow list.395		///396		/// # Permissions397		///398		/// * Collection Owner399		/// * Collection Admin400		///401		/// # Arguments402		///403		/// * collection_id.404		///405		/// * address.406		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]407		#[transactional]408		pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{409410			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);411			let collection = <CollectionHandle<T>>::try_get(collection_id)?;412413			<PalletCommon<T>>::toggle_allowlist(414				&collection,415				&sender,416				&address,417				true,418			)?;419420			Self::deposit_event(Event::<T>::AllowListAddressAdded(421				collection_id,422				address423			));424425			Ok(())426		}427428		/// Remove an address from allow list.429		///430		/// # Permissions431		///432		/// * Collection Owner433		/// * Collection Admin434		///435		/// # Arguments436		///437		/// * collection_id.438		///439		/// * address.440		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]441		#[transactional]442		pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{443444			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);445			let collection = <CollectionHandle<T>>::try_get(collection_id)?;446447			<PalletCommon<T>>::toggle_allowlist(448				&collection,449				&sender,450				&address,451				false,452			)?;453454			<Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(455				collection_id,456				address457			));458459			Ok(())460		}461462		/// Toggle between normal and allow list access for the methods with access for `Anyone`.463		///464		/// # Permissions465		///466		/// * Collection Owner.467		///468		/// # Arguments469		///470		/// * collection_id.471		///472		/// * mode: [AccessMode]473		#[weight = <SelfWeightOf<T>>::set_public_access_mode()]474		#[transactional]475		pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult476		{477			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);478479			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;480			target_collection.check_is_owner(&sender)?;481482			target_collection.access = mode.clone();483484			<Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(485				collection_id,486				mode487			));488489			target_collection.save()490		}491492		/// Allows Anyone to create tokens if:493		/// * Allow List is enabled, and494		/// * Address is added to allow list, and495		/// * This method was called with True parameter496		///497		/// # Permissions498		/// * Collection Owner499		///500		/// # Arguments501		///502		/// * collection_id.503		///504		/// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.505		#[weight = <SelfWeightOf<T>>::set_mint_permission()]506		#[transactional]507		pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult508		{509			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);510511			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;512			target_collection.check_is_owner(&sender)?;513514			target_collection.mint_mode = mint_permission;515516			<Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(517				collection_id518			));519520			target_collection.save()521		}522523		/// Change the owner of the collection.524		///525		/// # Permissions526		///527		/// * Collection Owner.528		///529		/// # Arguments530		///531		/// * collection_id.532		///533		/// * new_owner.534		#[weight = <SelfWeightOf<T>>::change_collection_owner()]535		#[transactional]536		pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {537538			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);539540			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;541			target_collection.check_is_owner(&sender)?;542543			target_collection.owner = new_owner.clone();544			<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(545				collection_id,546				new_owner547			));548549			target_collection.save()550		}551552		/// Adds an admin of the Collection.553		/// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.554		///555		/// # Permissions556		///557		/// * Collection Owner.558		/// * Collection Admin.559		///560		/// # Arguments561		///562		/// * collection_id: ID of the Collection to add admin for.563		///564		/// * new_admin_id: Address of new admin to add.565		#[weight = <SelfWeightOf<T>>::add_collection_admin()]566		#[transactional]567		pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {568			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);569			let collection = <CollectionHandle<T>>::try_get(collection_id)?;570571			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(572				collection_id,573				new_admin_id.clone()574			));575576			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)577		}578579		/// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.580		///581		/// # Permissions582		///583		/// * Collection Owner.584		/// * Collection Admin.585		///586		/// # Arguments587		///588		/// * collection_id: ID of the Collection to remove admin for.589		///590		/// * account_id: Address of admin to remove.591		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]592		#[transactional]593		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {594			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);595			let collection = <CollectionHandle<T>>::try_get(collection_id)?;596597			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(598				collection_id,599				account_id.clone()600			));601602			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)603		}604605		/// # Permissions606		///607		/// * Collection Owner608		///609		/// # Arguments610		///611		/// * collection_id.612		///613		/// * new_sponsor.614		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]615		#[transactional]616		pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {617			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);618619			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;620			target_collection.check_is_owner(&sender)?;621622			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());623624			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(625				collection_id,626				new_sponsor627			));628629			target_collection.save()630		}631632		/// # Permissions633		///634		/// * Sponsor.635		///636		/// # Arguments637		///638		/// * collection_id.639		#[weight = <SelfWeightOf<T>>::confirm_sponsorship()]640		#[transactional]641		pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {642			let sender = ensure_signed(origin)?;643644			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;645			ensure!(646				target_collection.sponsorship.pending_sponsor() == Some(&sender),647				Error::<T>::ConfirmUnsetSponsorFail648			);649650			target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());651652			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(653				collection_id,654				sender655			));656657			target_collection.save()658		}659660		/// Switch back to pay-per-own-transaction model.661		///662		/// # Permissions663		///664		/// * Collection owner.665		///666		/// # Arguments667		///668		/// * collection_id.669		#[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]670		#[transactional]671		pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {672			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);673674			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;675			target_collection.check_is_owner(&sender)?;676677			target_collection.sponsorship = SponsorshipState::Disabled;678679			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(680				collection_id681			));682			target_collection.save()683		}684685		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.686		///687		/// # Permissions688		///689		/// * Collection Owner.690		/// * Collection Admin.691		/// * Anyone if692		///     * Allow List is enabled, and693		///     * Address is added to allow list, and694		///     * MintPermission is enabled (see SetMintPermission method)695		///696		/// # Arguments697		///698		/// * collection_id: ID of the collection.699		///700		/// * owner: Address, initial owner of the NFT.701		///702		/// * data: Token data to store on chain.703		#[weight = <CommonWeights<T>>::create_item()]704		#[transactional]705		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {706			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);707708			dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data))709		}710711		/// This method creates multiple items in a collection created with CreateCollection method.712		///713		/// # Permissions714		///715		/// * Collection Owner.716		/// * Collection Admin.717		/// * Anyone if718		///     * Allow List is enabled, and719		///     * Address is added to allow list, and720		///     * MintPermission is enabled (see SetMintPermission method)721		///722		/// # Arguments723		///724		/// * collection_id: ID of the collection.725		///726		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].727		///728		/// * owner: Address, initial owner of the NFT.729		#[weight = <CommonWeights<T>>::create_multiple_items(items_data.len() as u32)]730		#[transactional]731		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {732			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);733			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);734735			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data))736		}737738		// TODO! transaction weight739740		/// Set transfers_enabled value for particular collection741		///742		/// # Permissions743		///744		/// * Collection Owner.745		///746		/// # Arguments747		///748		/// * collection_id: ID of the collection.749		///750		/// * value: New flag value.751		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]752		#[transactional]753		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {754			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);755			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;756			target_collection.check_is_owner(&sender)?;757758			// =========759760			target_collection.limits.transfers_enabled = Some(value);761			target_collection.save()762		}763764		/// Destroys a concrete instance of NFT.765		///766		/// # Permissions767		///768		/// * Collection Owner.769		/// * Collection Admin.770		/// * Current NFT Owner.771		///772		/// # Arguments773		///774		/// * collection_id: ID of the collection.775		///776		/// * item_id: ID of NFT to burn.777		#[weight = <CommonWeights<T>>::burn_item()]778		#[transactional]779		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {780			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);781782			let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;783			if value == 1 {784				<NftTransferBasket<T>>::remove(collection_id, item_id);785				<NftApproveBasket<T>>::remove(collection_id, item_id);786			}787			// Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?788			// <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());789			// <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));790			Ok(post_info)791		}792793		/// Destroys a concrete instance of NFT on behalf of the owner794		/// See also: [`approve`]795		///796		/// # Permissions797		///798		/// * Collection Owner.799		/// * Collection Admin.800		/// * Current NFT Owner.801		///802		/// # Arguments803		///804		/// * collection_id: ID of the collection.805		///806		/// * item_id: ID of NFT to burn.807		///808		/// * from: owner of item809		#[weight = <CommonWeights<T>>::burn_from()]810		#[transactional]811		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {812			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);813814			dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))815		}816817		/// Change ownership of the token.818		///819		/// # Permissions820		///821		/// * Collection Owner822		/// * Collection Admin823		/// * Current NFT owner824		///825		/// # Arguments826		///827		/// * recipient: Address of token recipient.828		///829		/// * collection_id.830		///831		/// * item_id: ID of the item832		///     * Non-Fungible Mode: Required.833		///     * Fungible Mode: Ignored.834		///     * Re-Fungible Mode: Required.835		///836		/// * value: Amount to transfer.837		///     * Non-Fungible Mode: Ignored838		///     * Fungible Mode: Must specify transferred amount839		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)840		#[weight = <CommonWeights<T>>::transfer()]841		#[transactional]842		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {843			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);844845			dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value))846		}847848		/// Set, change, or remove approved address to transfer the ownership of the NFT.849		///850		/// # Permissions851		///852		/// * Collection Owner853		/// * Collection Admin854		/// * Current NFT owner855		///856		/// # Arguments857		///858		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).859		///860		/// * collection_id.861		///862		/// * item_id: ID of the item.863		#[weight = <CommonWeights<T>>::approve()]864		#[transactional]865		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {866			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);867868			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))869		}870871		/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.872		///873		/// # Permissions874		/// * Collection Owner875		/// * Collection Admin876		/// * Current NFT owner877		/// * Address approved by current NFT owner878		///879		/// # Arguments880		///881		/// * from: Address that owns token.882		///883		/// * recipient: Address of token recipient.884		///885		/// * collection_id.886		///887		/// * item_id: ID of the item.888		///889		/// * value: Amount to transfer.890		#[weight = <CommonWeights<T>>::transfer_from()]891		#[transactional]892		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {893			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);894895			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value))896		}897898		/// Set off-chain data schema.899		///900		/// # Permissions901		///902		/// * Collection Owner903		/// * Collection Admin904		///905		/// # Arguments906		///907		/// * collection_id.908		///909		/// * schema: String representing the offchain data schema.910		#[weight = <CommonWeights<T>>::set_variable_metadata(data.len() as u32)]911		#[transactional]912		pub fn set_variable_meta_data (913			origin,914			collection_id: CollectionId,915			item_id: TokenId,916			data: BoundedVec<u8, CustomDataLimit>,917		) -> DispatchResultWithPostInfo {918			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);919920			dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))921		}922923		/// Set meta_update_permission value for particular collection924		///925		/// # Permissions926		///927		/// * Collection Owner.928		///929		/// # Arguments930		///931		/// * collection_id: ID of the collection.932		///933		/// * value: New flag value.934		#[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]935		#[transactional]936		pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {937			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);938			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;939940			ensure!(941				target_collection.meta_update_permission != MetaUpdatePermission::None,942				<CommonError<T>>::MetadataFlagFrozen,943			);944			target_collection.check_is_owner(&sender)?;945946			target_collection.meta_update_permission = value;947948			target_collection.save()949		}950951		/// Set schema standard952		/// ImageURL953		/// Unique954		///955		/// # Permissions956		///957		/// * Collection Owner958		/// * Collection Admin959		///960		/// # Arguments961		///962		/// * collection_id.963		///964		/// * schema: SchemaVersion: enum965		#[weight = <SelfWeightOf<T>>::set_schema_version()]966		#[transactional]967		pub fn set_schema_version(968			origin,969			collection_id: CollectionId,970			version: SchemaVersion971		) -> DispatchResult {972			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);973			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;974			target_collection.check_is_owner_or_admin(&sender)?;975			target_collection.schema_version = version;976977			<Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(978				collection_id979			));980981			target_collection.save()982		}983984		/// Set off-chain data schema.985		///986		/// # Permissions987		///988		/// * Collection Owner989		/// * Collection Admin990		///991		/// # Arguments992		///993		/// * collection_id.994		///995		/// * schema: String representing the offchain data schema.996		#[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]997		#[transactional]998		pub fn set_offchain_schema(999			origin,1000			collection_id: CollectionId,1001			schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,1002		) -> DispatchResult {1003			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1004			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1005			target_collection.check_is_owner_or_admin(&sender)?;10061007			target_collection.offchain_schema = schema;10081009			<Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1010				collection_id1011			));10121013			target_collection.save()1014		}10151016		/// Set const on-chain data schema.1017		///1018		/// # Permissions1019		///1020		/// * Collection Owner1021		/// * Collection Admin1022		///1023		/// # Arguments1024		///1025		/// * collection_id.1026		///1027		/// * schema: String representing the const on-chain data schema.1028		#[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1029		#[transactional]1030		pub fn set_const_on_chain_schema (1031			origin,1032			collection_id: CollectionId,1033			schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1034		) -> DispatchResult {1035			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1036			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1037			target_collection.check_is_owner_or_admin(&sender)?;10381039			target_collection.const_on_chain_schema = schema;10401041			<Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1042				collection_id1043			));10441045			target_collection.save()1046		}10471048		/// Set variable on-chain data schema.1049		///1050		/// # Permissions1051		///1052		/// * Collection Owner1053		/// * Collection Admin1054		///1055		/// # Arguments1056		///1057		/// * collection_id.1058		///1059		/// * schema: String representing the variable on-chain data schema.1060		#[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1061		#[transactional]1062		pub fn set_variable_on_chain_schema (1063			origin,1064			collection_id: CollectionId,1065			schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>1066		) -> DispatchResult {1067			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1068			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1069			target_collection.check_is_owner_or_admin(&sender)?;10701071			target_collection.variable_on_chain_schema = schema;10721073			<Pallet<T>>::deposit_event(Event::<T>::VariableOnChainSchemaSet(1074				collection_id1075			));10761077			target_collection.save()1078		}10791080		#[weight = <SelfWeightOf<T>>::set_collection_limits()]1081		#[transactional]1082		pub fn set_collection_limits(1083			origin,1084			collection_id: CollectionId,1085			new_limit: CollectionLimits,1086		) -> DispatchResult {1087			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1088			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1089			target_collection.check_is_owner(&sender)?;1090			let old_limit = &target_collection.limits;10911092			target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10931094			<Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1095				collection_id1096			));10971098			target_collection.save()1099		}1100	}1101}