git.delta.rocks / unique-network / refs/commits / ff0ca4cea892

difftreelog

doc: adjust documentation style

Farhad Hakimov2022-07-11parent: #9b4da67.patch.diff
in: master

2 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
before · pallets/common/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#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;2021use core::ops::{Deref, DerefMut};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use sp_std::vec::Vec;24use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};25use evm_coder::ToLog;26use frame_support::{27	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},28	ensure,29	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},30	weights::Pays,31	transactional,32};33use pallet_evm::GasWeightMapping;34use up_data_structs::{35	COLLECTION_NUMBER_LIMIT,36	Collection,37	RpcCollection,38	CollectionId,39	CreateItemData,40	MAX_TOKEN_PREFIX_LENGTH,41	COLLECTION_ADMINS_LIMIT,42	TokenId,43	TokenChild,44	CollectionStats,45	MAX_TOKEN_OWNERSHIP,46	CollectionMode,47	NFT_SPONSOR_TRANSFER_TIMEOUT,48	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,49	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,50	MAX_SPONSOR_TIMEOUT,51	CUSTOM_DATA_LIMIT,52	CollectionLimits,53	CreateCollectionData,54	SponsorshipState,55	CreateItemExData,56	SponsoringRateLimit,57	budget::Budget,58	PhantomType,59	Property,60	Properties,61	PropertiesPermissionMap,62	PropertyKey,63	PropertyValue,64	PropertyPermission,65	PropertiesError,66	PropertyKeyPermission,67	TokenData,68	TrySetProperty,69	PropertyScope,70	// RMRK71	RmrkCollectionInfo,72	RmrkInstanceInfo,73	RmrkResourceInfo,74	RmrkPropertyInfo,75	RmrkBaseInfo,76	RmrkPartType,77	RmrkBoundedTheme,78	RmrkNftChild,79	CollectionPermissions,80	SchemaVersion,81};8283pub use pallet::*;84use sp_core::H160;85use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};86#[cfg(feature = "runtime-benchmarks")]87pub mod benchmarking;88pub mod dispatch;89pub mod erc;90pub mod eth;91pub mod weights;9293pub type SelfWeightOf<T> = <T as Config>::WeightInfo;9495#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]96pub struct CollectionHandle<T: Config> {97	pub id: CollectionId,98	collection: Collection<T::AccountId>,99	pub recorder: SubstrateRecorder<T>,100}101impl<T: Config> WithRecorder<T> for CollectionHandle<T> {102	fn recorder(&self) -> &SubstrateRecorder<T> {103		&self.recorder104	}105	fn into_recorder(self) -> SubstrateRecorder<T> {106		self.recorder107	}108}109impl<T: Config> CollectionHandle<T> {110	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {111		<CollectionById<T>>::get(id).map(|collection| Self {112			id,113			collection,114			recorder: SubstrateRecorder::new(gas_limit),115		})116	}117118	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {119		<CollectionById<T>>::get(id).map(|collection| Self {120			id,121			collection,122			recorder,123		})124	}125126	pub fn new(id: CollectionId) -> Option<Self> {127		Self::new_with_gas_limit(id, u64::MAX)128	}129130	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {131		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)132	}133134	pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {135		self.recorder136			.consume_gas(T::GasWeightMapping::weight_to_gas(137				<T as frame_system::Config>::DbWeight::get()138					.read139					.saturating_mul(reads),140			))141	}142143	pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {144		self.recorder145			.consume_gas(T::GasWeightMapping::weight_to_gas(146				<T as frame_system::Config>::DbWeight::get()147					.write148					.saturating_mul(writes),149			))150	}151	pub fn save(self) -> DispatchResult {152		<CollectionById<T>>::insert(self.id, self.collection);153		Ok(())154	}155156	pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {157		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);158		Ok(())159	}160161	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {162		if self.collection.sponsorship.pending_sponsor() != Some(sender) {163			return Ok(false);164		}165166		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());167		Ok(true)168	}169170	/// Checks that the collection was created with, and must be operated upon through **Unique API**.171	/// Now check only the `external_collection` flag and if it's **true**, then return `CollectionIsExternal` error.172	pub fn check_is_internal(&self) -> DispatchResult {173		if self.external_collection {174			return Err(<Error<T>>::CollectionIsExternal)?;175		}176177		Ok(())178	}179180	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.181	/// Now check only the `external_collection` flag and if it's **false**, then return `CollectionIsInternal` error.182	pub fn check_is_external(&self) -> DispatchResult {183		if !self.external_collection {184			return Err(<Error<T>>::CollectionIsInternal)?;185		}186187		Ok(())188	}189}190191impl<T: Config> Deref for CollectionHandle<T> {192	type Target = Collection<T::AccountId>;193194	fn deref(&self) -> &Self::Target {195		&self.collection196	}197}198199impl<T: Config> DerefMut for CollectionHandle<T> {200	fn deref_mut(&mut self) -> &mut Self::Target {201		&mut self.collection202	}203}204205impl<T: Config> CollectionHandle<T> {206	pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {207		ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);208		Ok(())209	}210	pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {211		*subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))212	}213	pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {214		ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);215		Ok(())216	}217	pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {218		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)219	}220	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {221		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)222	}223	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {224		ensure!(225			<Allowlist<T>>::get((self.id, user)),226			<Error<T>>::AddressNotInAllowlist227		);228		Ok(())229	}230}231232#[frame_support::pallet]233pub mod pallet {234	use super::*;235	use pallet_evm::account;236	use dispatch::CollectionDispatch;237	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};238	use frame_system::pallet_prelude::*;239	use frame_support::traits::Currency;240	use up_data_structs::{TokenId, mapping::TokenAddressMapping};241	use scale_info::TypeInfo;242	use weights::WeightInfo;243244	#[pallet::config]245	pub trait Config:246		frame_system::Config247		+ pallet_evm_coder_substrate::Config248		+ pallet_evm::Config249		+ TypeInfo250		+ account::Config251	{252		type WeightInfo: WeightInfo;253		type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;254255		type Currency: Currency<Self::AccountId>;256257		#[pallet::constant]258		type CollectionCreationPrice: Get<259			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,260		>;261		type CollectionDispatch: CollectionDispatch<Self>;262263		type TreasuryAccountId: Get<Self::AccountId>;264		type ContractAddress: Get<H160>;265266		type EvmTokenAddressMapping: TokenAddressMapping<H160>;267		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;268	}269270	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);271272	#[pallet::pallet]273	#[pallet::storage_version(STORAGE_VERSION)]274	#[pallet::generate_store(pub(super) trait Store)]275	pub struct Pallet<T>(_);276277	#[pallet::extra_constants]278	impl<T: Config> Pallet<T> {279		pub fn collection_admins_limit() -> u32 {280			COLLECTION_ADMINS_LIMIT281		}282	}283284	#[pallet::event]285	#[pallet::generate_deposit(pub fn deposit_event)]286	pub enum Event<T: Config> {287		/// New collection was created288		///289		/// # Arguments290		///291		/// * collection_id: Globally unique identifier of newly created collection.292		///293		/// * mode: [CollectionMode] converted into u8.294		///295		/// * account_id: Collection owner.296		CollectionCreated(CollectionId, u8, T::AccountId),297298		/// New collection was destroyed299		///300		/// # Arguments301		///302		/// * collection_id: Globally unique identifier of collection that has been destroyed.303		CollectionDestroyed(CollectionId),304305		/// New item was created.306		///307		/// # Arguments308		///309		/// * collection_id: ID of the collection where the item was created.310		///311		/// * item_id: ID of the item. Unique within the collection.312		///313		/// * recipient: Owner of the newly created item.314		///315		/// * amount: The amount of tokens that were created (always 1 for NFT).316		ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),317318		/// Collection item was burned.319		///320		/// # Arguments321		///322		/// * collection_id: Identifier of the collection to which the burned NFT belonged.323		///324		/// * item_id: Identifier of burned NFT.325		///326		/// * owner: Which user has destroyed their tokens.327		///328		/// * amount: The amount of tokens that were destroyed (always 1 for NFT).329		ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),330331		/// Item was transferred.332		///333		/// # Arguments334		///335		/// * collection_id: ID of the collection to which the item belongs.336		///337		/// * item_id: ID of the item transferred.338		///339		/// * sender: Original owner of the item.340		///341		/// * recipient: New owner of the item.342		///343		/// * amount: The amount of tokens that were transferred (always 1 for NFT).344		Transfer(345			CollectionId,346			TokenId,347			T::CrossAccountId,348			T::CrossAccountId,349			u128,350		),351352		/// Sponsoring allowance was approved.353		///354		/// # Arguments355		///356		/// * collection_id357		///358		/// * item_id359		///360		/// * sender361		///362		/// * spender363		///364		/// * amount365		Approved(366			CollectionId,367			TokenId,368			T::CrossAccountId,369			T::CrossAccountId,370			u128,371		),372373		/// Collection property was added or edited.374		///375		/// # Arguments376		///377		/// * collection_id: ID of the collection, whose property was just set.378		///379		/// * property_key: Key of the property that was just set.380		CollectionPropertySet(CollectionId, PropertyKey),381382		/// Collection property was deleted.383		///384		/// # Arguments385		///386		/// * collection_id: ID of the collection, whose property was just deleted.387		///388		/// * property_key: Key of the property that was just deleted.389		CollectionPropertyDeleted(CollectionId, PropertyKey),390391		/// Item property was added or edited.392		///393		/// # Arguments394		///395		/// * collection_id: ID of the collection, whose token's property was just set.396		///397		/// * item_id: ID of the item, whose property was just set.398		///399		/// * property_key: Key of the property that was just set.400		TokenPropertySet(CollectionId, TokenId, PropertyKey),401402		/// Item property was deleted.403		///404		/// # Arguments405		///406		/// * collection_id: ID of the collection, whose token's property was just deleted.407		///408		/// * item_id: ID of the item, whose property was just deleted.409		///410		/// * property_key: Key of the property that was just deleted.411		TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),412413		/// Token property permission was added or updated for a collection.414		///415		/// # Arguments416		///417		/// * collection_id: ID of the collection, whose permissions were just set/updated.418		///419		/// * property_key: Key of the property of the set/updated permission.420		PropertyPermissionSet(CollectionId, PropertyKey),421	}422423	#[pallet::error]424	pub enum Error<T> {425		/// This collection does not exist.426		CollectionNotFound,427		/// Sender parameter and item owner must be equal.428		MustBeTokenOwner,429		/// No permission to perform action430		NoPermission,431		/// Destroying only empty collections is allowed432		CantDestroyNotEmptyCollection,433		/// Collection is not in mint mode.434		PublicMintingNotAllowed,435		/// Address is not in allow list.436		AddressNotInAllowlist,437438		/// Collection name can not be longer than 63 char.439		CollectionNameLimitExceeded,440		/// Collection description can not be longer than 255 char.441		CollectionDescriptionLimitExceeded,442		/// Token prefix can not be longer than 15 char.443		CollectionTokenPrefixLimitExceeded,444		/// Total collections bound exceeded.445		TotalCollectionsLimitExceeded,446		/// Exceeded max admin count447		CollectionAdminCountExceeded,448		/// Collection limit bounds per collection exceeded449		CollectionLimitBoundsExceeded,450		/// Tried to enable permissions which are only permitted to be disabled451		OwnerPermissionsCantBeReverted,452		/// Collection settings not allowing items transferring453		TransferNotAllowed,454		/// Account token limit exceeded per collection455		AccountTokenLimitExceeded,456		/// Collection token limit exceeded457		CollectionTokenLimitExceeded,458		/// Metadata flag frozen459		MetadataFlagFrozen,460461		/// Item does not exist462		TokenNotFound,463		/// Item is balance not enough464		TokenValueTooLow,465		/// Requested value is more than the approved466		ApprovedValueTooLow,467		/// Tried to approve more than owned468		CantApproveMoreThanOwned,469470		/// Can't transfer tokens to ethereum zero address471		AddressIsZero,472		/// Target collection doesn't support this operation473		UnsupportedOperation,474475		/// Insufficient funds to perform an action476		NotSufficientFounds,477478		/// User does not satisfy the nesting rule479		UserIsNotAllowedToNest,480		/// Only tokens from specific collections may nest tokens under this one481		SourceCollectionIsNotAllowedToNest,482483		/// Tried to store more data than allowed in collection field484		CollectionFieldSizeExceeded,485486		/// Tried to store more property data than allowed487		NoSpaceForProperty,488489		/// Tried to store more property keys than allowed490		PropertyLimitReached,491492		/// Property key is too long493		PropertyKeyIsTooLong,494495		/// Only ASCII letters, digits, and symbols '_', '-', and '.' are allowed496		InvalidCharacterInPropertyKey,497498		/// Empty property keys are forbidden499		EmptyPropertyKey,500501		/// Tried to access an external collection with an internal API502		CollectionIsExternal,503504		/// Tried to access an internal collection with an external API505		CollectionIsInternal,506	}507508	/// The number of created collections. Essentially contains the last collection ID.509	#[pallet::storage]510	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;511512	/// The number of destroyed collections513	#[pallet::storage]514	pub type DestroyedCollectionCount<T> =515		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;516517	/// Collection info518	#[pallet::storage]519	pub type CollectionById<T> = StorageMap<520		Hasher = Blake2_128Concat,521		Key = CollectionId,522		Value = Collection<<T as frame_system::Config>::AccountId>,523		QueryKind = OptionQuery,524	>;525526	/// Collection properties527	#[pallet::storage]528	#[pallet::getter(fn collection_properties)]529	pub type CollectionProperties<T> = StorageMap<530		Hasher = Blake2_128Concat,531		Key = CollectionId,532		Value = Properties,533		QueryKind = ValueQuery,534		OnEmpty = up_data_structs::CollectionProperties,535	>;536537	/// Token permissions of a collection538	#[pallet::storage]539	#[pallet::getter(fn property_permissions)]540	pub type CollectionPropertyPermissions<T> = StorageMap<541		Hasher = Blake2_128Concat,542		Key = CollectionId,543		Value = PropertiesPermissionMap,544		QueryKind = ValueQuery,545	>;546547	/// Amount of collection admins548	#[pallet::storage]549	pub type AdminAmount<T> = StorageMap<550		Hasher = Blake2_128Concat,551		Key = CollectionId,552		Value = u32,553		QueryKind = ValueQuery,554	>;555556	/// List of collection admins557	#[pallet::storage]558	pub type IsAdmin<T: Config> = StorageNMap<559		Key = (560			Key<Blake2_128Concat, CollectionId>,561			Key<Blake2_128Concat, T::CrossAccountId>,562		),563		Value = bool,564		QueryKind = ValueQuery,565	>;566567	/// Allowlisted collection users568	#[pallet::storage]569	pub type Allowlist<T: Config> = StorageNMap<570		Key = (571			Key<Blake2_128Concat, CollectionId>,572			Key<Blake2_128Concat, T::CrossAccountId>,573		),574		Value = bool,575		QueryKind = ValueQuery,576	>;577578	/// Not used by code, exists only to provide some types to metadata579	#[pallet::storage]580	pub type DummyStorageValue<T: Config> = StorageValue<581		Value = (582			CollectionStats,583			CollectionId,584			TokenId,585			TokenChild,586			PhantomType<(587				TokenData<T::CrossAccountId>,588				RpcCollection<T::AccountId>,589				// RMRK590				RmrkCollectionInfo<T::AccountId>,591				RmrkInstanceInfo<T::AccountId>,592				RmrkResourceInfo,593				RmrkPropertyInfo,594				RmrkBaseInfo<T::AccountId>,595				RmrkPartType,596				RmrkBoundedTheme,597				RmrkNftChild,598			)>,599		),600		QueryKind = OptionQuery,601	>;602603	#[pallet::hooks]604	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {605		fn on_runtime_upgrade() -> Weight {606			if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {607				use up_data_structs::{CollectionVersion1, CollectionVersion2};608				<CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {609					let mut props = Vec::new();610					if !v.offchain_schema.is_empty() {611						props.push(Property {612							key: b"_old_offchainSchema".to_vec().try_into().unwrap(),613							value: v614								.offchain_schema615								.clone()616								.into_inner()617								.try_into()618								.expect("offchain schema too big"),619						});620					}621					if !v.variable_on_chain_schema.is_empty() {622						props.push(Property {623							key: b"_old_variableOnChainSchema".to_vec().try_into().unwrap(),624							value: v625								.variable_on_chain_schema626								.clone()627								.into_inner()628								.try_into()629								.expect("offchain schema too big"),630						});631					}632					if !v.const_on_chain_schema.is_empty() {633						props.push(Property {634							key: b"_old_constOnChainSchema".to_vec().try_into().unwrap(),635							value: v636								.const_on_chain_schema637								.clone()638								.into_inner()639								.try_into()640								.expect("offchain schema too big"),641						});642					}643					props.push(Property {644						key: b"_old_schemaVersion".to_vec().try_into().unwrap(),645						value: match v.schema_version {646							SchemaVersion::ImageURL => b"ImageUrl".as_slice(),647							SchemaVersion::Unique => b"Unique".as_slice(),648						}649						.to_vec()650						.try_into()651						.unwrap(),652					});653					Self::set_scoped_collection_properties(654						id,655						PropertyScope::None,656						props.into_iter(),657					)658					.expect("existing data larger than properties");659					let mut new = CollectionVersion2::from(v.clone());660					new.permissions.access = Some(v.access);661					new.permissions.mint_mode = Some(v.mint_mode);662					Some(new)663				});664			}665666			0667		}668	}669}670671impl<T: Config> Pallet<T> {672	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens673	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {674		ensure!(675			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,676			<Error<T>>::AddressIsZero677		);678		Ok(())679	}680	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {681		<IsAdmin<T>>::iter_prefix((collection,))682			.map(|(a, _)| a)683			.collect()684	}685	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {686		<Allowlist<T>>::iter_prefix((collection,))687			.map(|(a, _)| a)688			.collect()689	}690	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {691		<Allowlist<T>>::get((collection, user))692	}693	pub fn collection_stats() -> CollectionStats {694		let created = <CreatedCollectionCount<T>>::get();695		let destroyed = <DestroyedCollectionCount<T>>::get();696		CollectionStats {697			created: created.0,698			destroyed: destroyed.0,699			alive: created.0 - destroyed.0,700		}701	}702703	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {704		let collection = <CollectionById<T>>::get(collection);705		if collection.is_none() {706			return None;707		}708709		let collection = collection.unwrap();710		let limits = collection.limits;711		let effective_limits = CollectionLimits {712			account_token_ownership_limit: Some(limits.account_token_ownership_limit()),713			sponsored_data_size: Some(limits.sponsored_data_size()),714			sponsored_data_rate_limit: Some(715				limits716					.sponsored_data_rate_limit717					.unwrap_or(SponsoringRateLimit::SponsoringDisabled),718			),719			token_limit: Some(limits.token_limit()),720			sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(721				match collection.mode {722					CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,723					CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,724					CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,725				},726			)),727			sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),728			owner_can_transfer: Some(limits.owner_can_transfer()),729			owner_can_destroy: Some(limits.owner_can_destroy()),730			transfers_enabled: Some(limits.transfers_enabled()),731		};732733		Some(effective_limits)734	}735736	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {737		let Collection {738			name,739			description,740			owner,741			mode,742			token_prefix,743			sponsorship,744			limits,745			permissions,746			external_collection,747		} = <CollectionById<T>>::get(collection)?;748749		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)750			.into_iter()751			.map(|(key, permission)| PropertyKeyPermission { key, permission })752			.collect();753754		let properties = <CollectionProperties<T>>::get(collection)755			.into_iter()756			.map(|(key, value)| Property { key, value })757			.collect();758759		let permissions = CollectionPermissions {760			access: Some(permissions.access()),761			mint_mode: Some(permissions.mint_mode()),762			nesting: Some(permissions.nesting().clone()),763		};764765		Some(RpcCollection {766			name: name.into_inner(),767			description: description.into_inner(),768			owner,769			mode,770			token_prefix: token_prefix.into_inner(),771			sponsorship,772			limits,773			permissions,774			token_property_permissions,775			properties,776			read_only: external_collection,777		})778	}779}780781macro_rules! limit_default {782	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{783		$(784			if let Some($new) = $new.$field {785				let $old = $old.$field($($arg)?);786				let _ = $new;787				let _ = $old;788				$check789			} else {790				$new.$field = $old.$field791			}792		)*793	}};794}795macro_rules! limit_default_clone {796	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{797		$(798			if let Some($new) = $new.$field.clone() {799				let $old = $old.$field($($arg)?);800				let _ = $new;801				let _ = $old;802				$check803			} else {804				$new.$field = $old.$field.clone()805			}806		)*807	}};808}809810impl<T: Config> Pallet<T> {811	pub fn init_collection(812		owner: T::CrossAccountId,813		data: CreateCollectionData<T::AccountId>,814		is_external: bool,815	) -> Result<CollectionId, DispatchError> {816		{817			ensure!(818				data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,819				Error::<T>::CollectionTokenPrefixLimitExceeded820			);821		}822823		let created_count = <CreatedCollectionCount<T>>::get()824			.0825			.checked_add(1)826			.ok_or(ArithmeticError::Overflow)?;827		let destroyed_count = <DestroyedCollectionCount<T>>::get().0;828		let id = CollectionId(created_count);829830		// bound Total number of collections831		ensure!(832			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,833			<Error<T>>::TotalCollectionsLimitExceeded834		);835836		// =========837838		let collection = Collection {839			owner: owner.as_sub().clone(),840			name: data.name,841			mode: data.mode.clone(),842			description: data.description,843			token_prefix: data.token_prefix,844			sponsorship: data845				.pending_sponsor846				.map(SponsorshipState::Unconfirmed)847				.unwrap_or_default(),848			limits: data849				.limits850				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))851				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,852			permissions: data853				.permissions854				.map(|permissions| {855					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)856				})857				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,858			external_collection: is_external,859		};860861		let mut collection_properties = up_data_structs::CollectionProperties::get();862		collection_properties863			.try_set_from_iter(data.properties.into_iter())864			.map_err(<Error<T>>::from)?;865866		CollectionProperties::<T>::insert(id, collection_properties);867868		let mut token_props_permissions = PropertiesPermissionMap::new();869		token_props_permissions870			.try_set_from_iter(data.token_property_permissions.into_iter())871			.map_err(<Error<T>>::from)?;872873		CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);874875		// Take a (non-refundable) deposit of collection creation876		{877			let mut imbalance =878				<<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();879			imbalance.subsume(880				<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(881					&T::TreasuryAccountId::get(),882					T::CollectionCreationPrice::get(),883				),884			);885			<T as Config>::Currency::settle(886				&owner.as_sub(),887				imbalance,888				WithdrawReasons::TRANSFER,889				ExistenceRequirement::KeepAlive,890			)891			.map_err(|_| Error::<T>::NotSufficientFounds)?;892		}893894		<CreatedCollectionCount<T>>::put(created_count);895		<Pallet<T>>::deposit_event(Event::CollectionCreated(896			id,897			data.mode.id(),898			owner.as_sub().clone(),899		));900		<PalletEvm<T>>::deposit_log(901			erc::CollectionHelpersEvents::CollectionCreated {902				owner: *owner.as_eth(),903				collection_id: eth::collection_id_to_address(id),904			}905			.to_log(T::ContractAddress::get()),906		);907		<CollectionById<T>>::insert(id, collection);908		Ok(id)909	}910911	pub fn destroy_collection(912		collection: CollectionHandle<T>,913		sender: &T::CrossAccountId,914	) -> DispatchResult {915		ensure!(916			collection.limits.owner_can_destroy(),917			<Error<T>>::NoPermission,918		);919		collection.check_is_owner(sender)?;920921		let destroyed_collections = <DestroyedCollectionCount<T>>::get()922			.0923			.checked_add(1)924			.ok_or(ArithmeticError::Overflow)?;925926		// =========927928		<DestroyedCollectionCount<T>>::put(destroyed_collections);929		<CollectionById<T>>::remove(collection.id);930		<AdminAmount<T>>::remove(collection.id);931		<IsAdmin<T>>::remove_prefix((collection.id,), None);932		<Allowlist<T>>::remove_prefix((collection.id,), None);933		<CollectionProperties<T>>::remove(collection.id);934935		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));936		Ok(())937	}938939	pub fn set_collection_property(940		collection: &CollectionHandle<T>,941		sender: &T::CrossAccountId,942		property: Property,943	) -> DispatchResult {944		collection.check_is_owner_or_admin(sender)?;945946		CollectionProperties::<T>::try_mutate(collection.id, |properties| {947			let property = property.clone();948			properties.try_set(property.key, property.value)949		})950		.map_err(<Error<T>>::from)?;951952		Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));953954		Ok(())955	}956957	pub fn set_scoped_collection_property(958		collection_id: CollectionId,959		scope: PropertyScope,960		property: Property,961	) -> DispatchResult {962		CollectionProperties::<T>::try_mutate(collection_id, |properties| {963			properties.try_scoped_set(scope, property.key, property.value)964		})965		.map_err(<Error<T>>::from)?;966967		Ok(())968	}969970	pub fn set_scoped_collection_properties(971		collection_id: CollectionId,972		scope: PropertyScope,973		properties: impl Iterator<Item = Property>,974	) -> DispatchResult {975		CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {976			stored_properties.try_scoped_set_from_iter(scope, properties)977		})978		.map_err(<Error<T>>::from)?;979980		Ok(())981	}982983	#[transactional]984	pub fn set_collection_properties(985		collection: &CollectionHandle<T>,986		sender: &T::CrossAccountId,987		properties: Vec<Property>,988	) -> DispatchResult {989		for property in properties {990			Self::set_collection_property(collection, sender, property)?;991		}992993		Ok(())994	}995996	pub fn delete_collection_property(997		collection: &CollectionHandle<T>,998		sender: &T::CrossAccountId,999		property_key: PropertyKey,1000	) -> DispatchResult {1001		collection.check_is_owner_or_admin(sender)?;10021003		CollectionProperties::<T>::try_mutate(collection.id, |properties| {1004			properties.remove(&property_key)1005		})1006		.map_err(<Error<T>>::from)?;10071008		Self::deposit_event(Event::CollectionPropertyDeleted(1009			collection.id,1010			property_key,1011		));10121013		Ok(())1014	}10151016	#[transactional]1017	pub fn delete_collection_properties(1018		collection: &CollectionHandle<T>,1019		sender: &T::CrossAccountId,1020		property_keys: Vec<PropertyKey>,1021	) -> DispatchResult {1022		for key in property_keys {1023			Self::delete_collection_property(collection, sender, key)?;1024		}10251026		Ok(())1027	}10281029	// For migrations1030	pub fn set_property_permission_unchecked(1031		collection: CollectionId,1032		property_permission: PropertyKeyPermission,1033	) -> DispatchResult {1034		<CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1035			permissions.try_set(property_permission.key, property_permission.permission)1036		})1037		.map_err(<Error<T>>::from)?;1038		Ok(())1039	}10401041	pub fn set_property_permission(1042		collection: &CollectionHandle<T>,1043		sender: &T::CrossAccountId,1044		property_permission: PropertyKeyPermission,1045	) -> DispatchResult {1046		collection.check_is_owner_or_admin(sender)?;10471048		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1049		let current_permission = all_permissions.get(&property_permission.key);1050		if matches![1051			current_permission,1052			Some(PropertyPermission { mutable: false, .. })1053		] {1054			return Err(<Error<T>>::NoPermission.into());1055		}10561057		CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1058			let property_permission = property_permission.clone();1059			permissions.try_set(property_permission.key, property_permission.permission)1060		})1061		.map_err(<Error<T>>::from)?;10621063		Self::deposit_event(Event::PropertyPermissionSet(1064			collection.id,1065			property_permission.key,1066		));10671068		Ok(())1069	}10701071	#[transactional]1072	pub fn set_token_property_permissions(1073		collection: &CollectionHandle<T>,1074		sender: &T::CrossAccountId,1075		property_permissions: Vec<PropertyKeyPermission>,1076	) -> DispatchResult {1077		for prop_pemission in property_permissions {1078			Self::set_property_permission(collection, sender, prop_pemission)?;1079		}10801081		Ok(())1082	}10831084	pub fn get_collection_property(1085		collection_id: CollectionId,1086		key: &PropertyKey,1087	) -> Option<PropertyValue> {1088		Self::collection_properties(collection_id).get(key).cloned()1089	}10901091	pub fn bytes_keys_to_property_keys(1092		keys: Vec<Vec<u8>>,1093	) -> Result<Vec<PropertyKey>, DispatchError> {1094		keys.into_iter()1095			.map(|key| -> Result<PropertyKey, DispatchError> {1096				key.try_into()1097					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1098			})1099			.collect::<Result<Vec<PropertyKey>, DispatchError>>()1100	}11011102	pub fn filter_collection_properties(1103		collection_id: CollectionId,1104		keys: Option<Vec<PropertyKey>>,1105	) -> Result<Vec<Property>, DispatchError> {1106		let properties = Self::collection_properties(collection_id);11071108		let properties = keys1109			.map(|keys| {1110				keys.into_iter()1111					.filter_map(|key| {1112						properties.get(&key).map(|value| Property {1113							key,1114							value: value.clone(),1115						})1116					})1117					.collect()1118			})1119			.unwrap_or_else(|| {1120				properties1121					.into_iter()1122					.map(|(key, value)| Property { key, value })1123					.collect()1124			});11251126		Ok(properties)1127	}11281129	pub fn filter_property_permissions(1130		collection_id: CollectionId,1131		keys: Option<Vec<PropertyKey>>,1132	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1133		let permissions = Self::property_permissions(collection_id);11341135		let key_permissions = keys1136			.map(|keys| {1137				keys.into_iter()1138					.filter_map(|key| {1139						permissions1140							.get(&key)1141							.map(|permission| PropertyKeyPermission {1142								key,1143								permission: permission.clone(),1144							})1145					})1146					.collect()1147			})1148			.unwrap_or_else(|| {1149				permissions1150					.into_iter()1151					.map(|(key, permission)| PropertyKeyPermission { key, permission })1152					.collect()1153			});11541155		Ok(key_permissions)1156	}11571158	pub fn toggle_allowlist(1159		collection: &CollectionHandle<T>,1160		sender: &T::CrossAccountId,1161		user: &T::CrossAccountId,1162		allowed: bool,1163	) -> DispatchResult {1164		collection.check_is_owner_or_admin(sender)?;11651166		// =========11671168		if allowed {1169			<Allowlist<T>>::insert((collection.id, user), true);1170		} else {1171			<Allowlist<T>>::remove((collection.id, user));1172		}11731174		Ok(())1175	}11761177	pub fn toggle_admin(1178		collection: &CollectionHandle<T>,1179		sender: &T::CrossAccountId,1180		user: &T::CrossAccountId,1181		admin: bool,1182	) -> DispatchResult {1183		collection.check_is_owner(sender)?;11841185		let was_admin = <IsAdmin<T>>::get((collection.id, user));1186		if was_admin == admin {1187			return Ok(());1188		}1189		let amount = <AdminAmount<T>>::get(collection.id);11901191		if admin {1192			let amount = amount1193				.checked_add(1)1194				.ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1195			ensure!(1196				amount <= Self::collection_admins_limit(),1197				<Error<T>>::CollectionAdminCountExceeded,1198			);11991200			// =========12011202			<AdminAmount<T>>::insert(collection.id, amount);1203			<IsAdmin<T>>::insert((collection.id, user), true);1204		} else {1205			<AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1206			<IsAdmin<T>>::remove((collection.id, user));1207		}12081209		Ok(())1210	}12111212	pub fn clamp_limits(1213		mode: CollectionMode,1214		old_limit: &CollectionLimits,1215		mut new_limit: CollectionLimits,1216	) -> Result<CollectionLimits, DispatchError> {1217		let limits = old_limit;1218		limit_default!(old_limit, new_limit,1219			account_token_ownership_limit => ensure!(1220				new_limit <= MAX_TOKEN_OWNERSHIP,1221				<Error<T>>::CollectionLimitBoundsExceeded,1222			),1223			sponsored_data_size => ensure!(1224				new_limit <= CUSTOM_DATA_LIMIT,1225				<Error<T>>::CollectionLimitBoundsExceeded,1226			),12271228			sponsored_data_rate_limit => {},1229			token_limit => ensure!(1230				old_limit >= new_limit && new_limit > 0,1231				<Error<T>>::CollectionTokenLimitExceeded1232			),12331234			sponsor_transfer_timeout(match mode {1235				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1236				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1237				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1238			}) => ensure!(1239				new_limit <= MAX_SPONSOR_TIMEOUT,1240				<Error<T>>::CollectionLimitBoundsExceeded,1241			),1242			sponsor_approve_timeout => {},1243			owner_can_transfer => ensure!(1244				!limits.owner_can_transfer_instaled() ||1245				old_limit || !new_limit,1246				<Error<T>>::OwnerPermissionsCantBeReverted,1247			),1248			owner_can_destroy => ensure!(1249				old_limit || !new_limit,1250				<Error<T>>::OwnerPermissionsCantBeReverted,1251			),1252			transfers_enabled => {},1253		);1254		Ok(new_limit)1255	}12561257	pub fn clamp_permissions(1258		_mode: CollectionMode,1259		old_limit: &CollectionPermissions,1260		mut new_limit: CollectionPermissions,1261	) -> Result<CollectionPermissions, DispatchError> {1262		limit_default_clone!(old_limit, new_limit,1263			access => {},1264			mint_mode => {},1265			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1266		);1267		Ok(new_limit)1268	}1269}12701271#[macro_export]1272macro_rules! unsupported {1273	() => {1274		Err(<Error<T>>::UnsupportedOperation.into())1275	};1276}12771278/// Worst cases1279pub trait CommonWeightInfo<CrossAccountId> {1280	fn create_item() -> Weight;1281	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1282	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1283	fn burn_item() -> Weight;1284	fn set_collection_properties(amount: u32) -> Weight;1285	fn delete_collection_properties(amount: u32) -> Weight;1286	fn set_token_properties(amount: u32) -> Weight;1287	fn delete_token_properties(amount: u32) -> Weight;1288	fn set_token_property_permissions(amount: u32) -> Weight;1289	fn transfer() -> Weight;1290	fn approve() -> Weight;1291	fn transfer_from() -> Weight;1292	fn burn_from() -> Weight;12931294	/// Differs from burn_item in case of Fungible and Refungible, as it should burn1295	/// whole users's balance1296	///1297	/// This method shouldn't be used directly, as it doesn't count breadth price, use `burn_recursively` instead1298	fn burn_recursively_self_raw() -> Weight;1299	/// Cost of iterating over `amount` children while burning, without counting child burning itself1300	///1301	/// This method shouldn't be used directly, as it doesn't count depth price, use `burn_recursively` instead1302	fn burn_recursively_breadth_raw(amount: u32) -> Weight;13031304	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1305		Self::burn_recursively_self_raw()1306			.saturating_mul(max_selfs.max(1) as u64)1307			.saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1308	}1309}13101311pub trait RefungibleExtensionsWeightInfo {1312	fn repartition() -> Weight;1313}13141315pub trait CommonCollectionOperations<T: Config> {1316	fn create_item(1317		&self,1318		sender: T::CrossAccountId,1319		to: T::CrossAccountId,1320		data: CreateItemData,1321		nesting_budget: &dyn Budget,1322	) -> DispatchResultWithPostInfo;1323	fn create_multiple_items(1324		&self,1325		sender: T::CrossAccountId,1326		to: T::CrossAccountId,1327		data: Vec<CreateItemData>,1328		nesting_budget: &dyn Budget,1329	) -> DispatchResultWithPostInfo;1330	fn create_multiple_items_ex(1331		&self,1332		sender: T::CrossAccountId,1333		data: CreateItemExData<T::CrossAccountId>,1334		nesting_budget: &dyn Budget,1335	) -> DispatchResultWithPostInfo;1336	fn burn_item(1337		&self,1338		sender: T::CrossAccountId,1339		token: TokenId,1340		amount: u128,1341	) -> DispatchResultWithPostInfo;1342	fn burn_item_recursively(1343		&self,1344		sender: T::CrossAccountId,1345		token: TokenId,1346		self_budget: &dyn Budget,1347		breadth_budget: &dyn Budget,1348	) -> DispatchResultWithPostInfo;1349	fn set_collection_properties(1350		&self,1351		sender: T::CrossAccountId,1352		properties: Vec<Property>,1353	) -> DispatchResultWithPostInfo;1354	fn delete_collection_properties(1355		&self,1356		sender: &T::CrossAccountId,1357		property_keys: Vec<PropertyKey>,1358	) -> DispatchResultWithPostInfo;1359	fn set_token_properties(1360		&self,1361		sender: T::CrossAccountId,1362		token_id: TokenId,1363		property: Vec<Property>,1364		nesting_budget: &dyn Budget,1365	) -> DispatchResultWithPostInfo;1366	fn delete_token_properties(1367		&self,1368		sender: T::CrossAccountId,1369		token_id: TokenId,1370		property_keys: Vec<PropertyKey>,1371		nesting_budget: &dyn Budget,1372	) -> DispatchResultWithPostInfo;1373	fn set_token_property_permissions(1374		&self,1375		sender: &T::CrossAccountId,1376		property_permissions: Vec<PropertyKeyPermission>,1377	) -> DispatchResultWithPostInfo;1378	fn transfer(1379		&self,1380		sender: T::CrossAccountId,1381		to: T::CrossAccountId,1382		token: TokenId,1383		amount: u128,1384		nesting_budget: &dyn Budget,1385	) -> DispatchResultWithPostInfo;1386	fn approve(1387		&self,1388		sender: T::CrossAccountId,1389		spender: T::CrossAccountId,1390		token: TokenId,1391		amount: u128,1392	) -> DispatchResultWithPostInfo;1393	fn transfer_from(1394		&self,1395		sender: T::CrossAccountId,1396		from: T::CrossAccountId,1397		to: T::CrossAccountId,1398		token: TokenId,1399		amount: u128,1400		nesting_budget: &dyn Budget,1401	) -> DispatchResultWithPostInfo;1402	fn burn_from(1403		&self,1404		sender: T::CrossAccountId,1405		from: T::CrossAccountId,1406		token: TokenId,1407		amount: u128,1408		nesting_budget: &dyn Budget,1409	) -> DispatchResultWithPostInfo;14101411	fn check_nesting(1412		&self,1413		sender: T::CrossAccountId,1414		from: (CollectionId, TokenId),1415		under: TokenId,1416		nesting_budget: &dyn Budget,1417	) -> DispatchResult;14181419	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));14201421	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));14221423	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1424	fn collection_tokens(&self) -> Vec<TokenId>;1425	fn token_exists(&self, token: TokenId) -> bool;1426	fn last_token_id(&self) -> TokenId;14271428	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1429	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1430	fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1431	/// Amount of unique collection tokens1432	fn total_supply(&self) -> u32;1433	/// Amount of different tokens account has (Applicable to nonfungible/refungible)1434	fn account_balance(&self, account: T::CrossAccountId) -> u32;1435	/// Amount of specific token account have (Applicable to fungible/refungible)1436	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1437	/// Amount of token pieces1438	fn total_pieces(&self, token: TokenId) -> Option<u128>;1439	fn allowance(1440		&self,1441		sender: T::CrossAccountId,1442		spender: T::CrossAccountId,1443		token: TokenId,1444	) -> u128;1445	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1446}14471448pub trait RefungibleExtensions<T>1449where1450	T: Config,1451{1452	fn repartition(1453		&self,1454		owner: &T::CrossAccountId,1455		token: TokenId,1456		amount: u128,1457	) -> DispatchResultWithPostInfo;1458}14591460// Flexible enough for implementing CommonCollectionOperations1461pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1462	let post_info = PostDispatchInfo {1463		actual_weight: Some(weight),1464		pays_fee: Pays::Yes,1465	};1466	match res {1467		Ok(()) => Ok(post_info),1468		Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1469	}1470}14711472impl<T: Config> From<PropertiesError> for Error<T> {1473	fn from(error: PropertiesError) -> Self {1474		match error {1475			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1476			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1477			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1478			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1479			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1480		}1481	}1482}
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -261,12 +261,9 @@
 		/// # Arguments
 		///
 		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.
-		///
-		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.
-		///
-		/// * token_prefix: UTF-8 string with token prefix.
-		///
-		/// * mode: [CollectionMode] collection type and type dependent data.
+		/// * collection_description - UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.
+		/// * token_prefix - UTF-8 string with token prefix.
+		/// * mode - [CollectionMode] collection type and type dependent data.
 		// returns collection ID
 		#[weight = <SelfWeightOf<T>>::create_collection()]
 		#[transactional]
@@ -316,7 +313,7 @@
 		///
 		/// # Arguments
 		///
-		/// * collection_id: collection to destroy.
+		/// * collection_id - collection to destroy.
 		#[weight = <SelfWeightOf<T>>::destroy_collection()]
 		#[transactional]
 		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {
@@ -349,7 +346,6 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
 		/// * address.
 		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]
 		#[transactional]
@@ -384,7 +380,6 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
 		/// * address.
 		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]
 		#[transactional]
@@ -418,7 +413,6 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
 		/// * new_owner.
 		#[weight = <SelfWeightOf<T>>::change_collection_owner()]
 		#[transactional]
@@ -448,10 +442,9 @@
 		/// * Collection Admin
 		///
 		/// # Arguments
-		///
-		/// * collection_id: ID of the Collection to add admin for.
 		///
-		/// * new_admin: Address of new admin to add.
+		/// * collection_id - ID of the Collection to add admin for.
+		/// * new_admin - Address of new admin to add.
 		#[weight = <SelfWeightOf<T>>::add_collection_admin()]
 		#[transactional]
 		pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin: T::CrossAccountId) -> DispatchResult {
@@ -476,9 +469,8 @@
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the Collection to remove admin for.
-		///
-		/// * account_id: Address of admin to remove.
+		/// * collection_id - ID of the Collection to remove admin for.
+		/// * account_id - Address of admin to remove.
 		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]
 		#[transactional]
 		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {
@@ -504,7 +496,6 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
 		/// * new_sponsor.
 		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]
 		#[transactional]
@@ -529,7 +520,7 @@
 		///
 		/// # Permissions
 		///
-		/// * The sponsor to-be
+		/// * Sponsor-to-be
 		///
 		/// # Arguments
 		///
@@ -593,11 +584,9 @@
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * owner: Address, initial owner of the NFT.
-		///
-		/// * data: Token data to store on chain.
+		/// * collection_id - ID of the collection.
+		/// * owner - Address, initial owner of the NFT.
+		/// * data - Token data to store on chain.
 		#[weight = T::CommonWeightInfo::create_item()]
 		#[transactional]
 		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {
@@ -620,11 +609,9 @@
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].
-		///
-		/// * owner: Address, initial owner of the NFT.
+		/// * collection_id - ID of the collection.
+		/// * owner - Address, initial owner of the NFT.
+		/// * items_data - Array items properties. Each property is an array of bytes itself, see [`create_item`].
 		#[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]
 		#[transactional]
 		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {
@@ -645,8 +632,7 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
-		/// * properties: a vector of key-value pairs stored as the collection's metadata. Keys support Latin letters, '-', '_', and '.' as symbols.
+		/// * properties - Vector of key-value pairs stored as the collection's metadata. Keys support Latin letters, '-', '_', and '.' as symbols.
 		#[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]
 		#[transactional]
 		pub fn set_collection_properties(
@@ -671,8 +657,7 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
-		/// * property_keys: a vector of keys of the properties to be deleted.
+		/// * property_keys - Vector of keys of the properties to be deleted.
 		#[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]
 		#[transactional]
 		pub fn delete_collection_properties(
@@ -699,10 +684,8 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
 		/// * token_id.
-		///
-		/// * properties: a vector of key-value pairs stored as the token's metadata. Keys support Latin letters, '-', '_', and '.' as symbols.
+		/// * properties - Vector of key-value pairs stored as the token's metadata. Keys support Latin letters, `-`, `_`, and `.` as symbols.
 		#[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]
 		#[transactional]
 		pub fn set_token_properties(
@@ -731,10 +714,8 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
 		/// * token_id.
-		///
-		/// * property_keys: a vector of keys of the properties to be deleted.
+		/// * property_keys - Vector of keys of the properties to be deleted.
 		#[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]
 		#[transactional]
 		pub fn delete_token_properties(
@@ -761,8 +742,7 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
-		/// * property_permissions: a vector of permissions for property keys. Keys support Latin letters, '-', '_', and '.' as symbols.
+		/// * property_permissions - Vector of permissions for property keys. Keys support Latin letters, `-`, `_`, and `.` as symbols.
 		#[weight = T::CommonWeightInfo::set_token_property_permissions(property_permissions.len() as u32)]
 		#[transactional]
 		pub fn set_token_property_permissions(
@@ -789,10 +769,9 @@
 		///     * MintPermission is enabled (see SetMintPermission method)
 		///
 		/// # Arguments
-		///
-		/// * collection_id: ID of the collection.
 		///
-		/// * data: explicit item creation data.
+		/// * collection_id - ID of the collection.
+		/// * data - Explicit item creation data.
 		#[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]
 		#[transactional]
 		pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {
@@ -810,9 +789,8 @@
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * value: New flag value.
+		/// * collection_id - ID of the collection.
+		/// * value - New flag value.
 		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]
 		#[transactional]
 		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {
@@ -837,9 +815,8 @@
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * item_id: ID of NFT to burn.
+		/// * collection_id - ID of the collection.
+		/// * item_id - ID of NFT to burn.
 		#[weight = T::CommonWeightInfo::burn_item()]
 		#[transactional]
 		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
@@ -866,12 +843,10 @@
 		/// * Current NFT Owner.
 		///
 		/// # Arguments
-		///
-		/// * collection_id: ID of the collection.
 		///
-		/// * item_id: ID of NFT to burn.
-		///
-		/// * from: owner of item
+		/// * collection_id - ID of the collection.
+		/// * item_id - ID of NFT to burn.
+		/// * from - The owner of the item from whom it is taken away.
 		#[weight = T::CommonWeightInfo::burn_from()]
 		#[transactional]
 		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
@@ -891,16 +866,16 @@
 		///
 		/// # Arguments
 		///
-		/// * recipient: Address of token recipient.
+		/// * recipient - Address of token recipient.
 		///
 		/// * collection_id.
 		///
-		/// * item_id: ID of the item
+		/// * item_id - ID of the item
 		///     * Non-Fungible Mode: Required.
 		///     * Fungible Mode: Ignored.
 		///     * Re-Fungible Mode: Required.
 		///
-		/// * value: Amount to transfer.
+		/// * value - Amount to transfer.
 		///     * Non-Fungible Mode: Ignored
 		///     * Fungible Mode: Must specify transferred amount
 		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)
@@ -923,11 +898,9 @@
 		///
 		/// # Arguments
 		///
-		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).
-		///
+		/// * approved - Address that is approved to transfer this NFT or zero (if needed to remove approval).
 		/// * collection_id.
-		///
-		/// * item_id: ID of the item.
+		/// * item_id - ID of the item.
 		#[weight = T::CommonWeightInfo::approve()]
 		#[transactional]
 		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {
@@ -947,15 +920,11 @@
 		///
 		/// # Arguments
 		///
-		/// * from: Address that owns token.
-		///
-		/// * recipient: Address of token recipient.
-		///
+		/// * from - Address that currently owns the token.
+		/// * recipient - Address of the new token-owner-to-be.
 		/// * collection_id.
-		///
-		/// * item_id: ID of the item.
-		///
-		/// * value: Amount to transfer.
+		/// * item_id - ID of the item to be transferred.
+		/// * value - Amount to transfer.
 		#[weight = T::CommonWeightInfo::transfer_from()]
 		#[transactional]
 		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {
@@ -966,7 +935,7 @@
 		}
 
 		/// Set specific limits of a collection. Empty, or None fields mean chain default.
-		///.
+		///
 		/// # Permissions
 		///
 		/// * Collection Owner
@@ -975,8 +944,7 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
-		/// * new_limit: The new limits of the collection. They will overwrite the current ones.
+		/// * new_limit - New limits of the collection. They will overwrite the current ones.
 		#[weight = <SelfWeightOf<T>>::set_collection_limits()]
 		#[transactional]
 		pub fn set_collection_limits(
@@ -1009,8 +977,7 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
-		/// * new_permission: The new permissions of the collection. They will overwrite the current ones.
+		/// * new_permission - New permissions of the collection. They will overwrite the current ones.
 		#[weight = <SelfWeightOf<T>>::set_collection_limits()]
 		#[transactional]
 		pub fn set_collection_permissions(
@@ -1042,16 +1009,14 @@
 		/// # Arguments
 		///
 		/// * collection_id.
-		///
-		/// * token: the ID of the RFT.
-		///
-		/// * amount: The new number of parts into which the token shall be partitioned.
+		/// * token_id - ID of the RFT.
+		/// * amount - New number of parts into which the token shall be partitioned.
 		#[weight = T::RefungibleExtensionsWeightInfo::repartition()]
 		#[transactional]
 		pub fn repartition(
 			origin,
 			collection_id: CollectionId,
-			token: TokenId,
+			token_id: TokenId,
 			amount: u128,
 		) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);