referrerpolicy=no-referrer-when-downgrade

pallet_nfts/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Nfts Module
19//!
20//! A simple, secure module for dealing with non-fungible items.
21//!
22//! ## Related Modules
23//!
24//! * [`System`](../frame_system/index.html)
25//! * [`Support`](../frame_support/index.html)
26
27#![recursion_limit = "256"]
28// Ensure we're `no_std` when compiling for Wasm.
29#![cfg_attr(not(feature = "std"), no_std)]
30
31#[cfg(feature = "runtime-benchmarks")]
32mod benchmarking;
33pub mod migration;
34#[cfg(test)]
35pub mod mock;
36#[cfg(test)]
37mod tests;
38
39mod common_functions;
40/// A library providing the feature set of this pallet. It contains modules with helper methods that
41/// perform storage updates and checks required by this pallet's dispatchables. To use pallet level
42/// features, make sure to set appropriate bitflags for [`Config::Features`] in your runtime
43/// configuration trait.
44mod features;
45mod impl_nonfungibles;
46mod types;
47
48pub mod macros;
49pub mod weights;
50
51extern crate alloc;
52
53use alloc::{boxed::Box, vec, vec::Vec};
54use codec::{Decode, Encode};
55use frame_support::traits::{
56	tokens::Locker, BalanceStatus::Reserved, Currency, EnsureOriginWithArg, Incrementable,
57	ReservableCurrency,
58};
59use frame_system::Config as SystemConfig;
60use sp_runtime::{
61	traits::{BlockNumberProvider, IdentifyAccount, Saturating, StaticLookup, Verify, Zero},
62	RuntimeDebug,
63};
64
65pub use pallet::*;
66pub use types::*;
67pub use weights::WeightInfo;
68
69/// The log target of this pallet.
70pub const LOG_TARGET: &'static str = "runtime::nfts";
71
72/// A type alias for the account ID type used in the dispatchable functions of this pallet.
73type AccountIdLookupOf<T> = <<T as SystemConfig>::Lookup as StaticLookup>::Source;
74
75#[frame_support::pallet]
76pub mod pallet {
77	use super::*;
78	use frame_support::{pallet_prelude::*, traits::ExistenceRequirement};
79	use frame_system::{ensure_signed, pallet_prelude::OriginFor};
80
81	/// The in-code storage version.
82	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
83
84	#[pallet::pallet]
85	#[pallet::storage_version(STORAGE_VERSION)]
86	pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
87
88	#[cfg(feature = "runtime-benchmarks")]
89	pub trait BenchmarkHelper<CollectionId, ItemId, Public, AccountId, Signature> {
90		fn collection(i: u16) -> CollectionId;
91		fn item(i: u16) -> ItemId;
92		fn signer() -> (Public, AccountId);
93		fn sign(signer: &Public, message: &[u8]) -> Signature;
94	}
95	#[cfg(feature = "runtime-benchmarks")]
96	impl<CollectionId, ItemId>
97		BenchmarkHelper<
98			CollectionId,
99			ItemId,
100			sp_runtime::MultiSigner,
101			sp_runtime::AccountId32,
102			sp_runtime::MultiSignature,
103		> for ()
104	where
105		CollectionId: From<u16>,
106		ItemId: From<u16>,
107	{
108		fn collection(i: u16) -> CollectionId {
109			i.into()
110		}
111		fn item(i: u16) -> ItemId {
112			i.into()
113		}
114		fn signer() -> (sp_runtime::MultiSigner, sp_runtime::AccountId32) {
115			let public = sp_io::crypto::sr25519_generate(0.into(), None);
116			let account = sp_runtime::MultiSigner::Sr25519(public).into_account();
117			(public.into(), account)
118		}
119		fn sign(signer: &sp_runtime::MultiSigner, message: &[u8]) -> sp_runtime::MultiSignature {
120			sp_runtime::MultiSignature::Sr25519(
121				sp_io::crypto::sr25519_sign(0.into(), &signer.clone().try_into().unwrap(), message)
122					.unwrap(),
123			)
124		}
125	}
126
127	#[pallet::config]
128	/// The module configuration trait.
129	pub trait Config<I: 'static = ()>: frame_system::Config {
130		/// The overarching event type.
131		#[allow(deprecated)]
132		type RuntimeEvent: From<Event<Self, I>>
133			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
134
135		/// Identifier for the collection of item.
136		///
137		/// SAFETY: The functions in the `Incrementable` trait are fallible. If the functions
138		/// of the implementation both return `None`, the automatic CollectionId generation
139		/// should not be used. So the `create` and `force_create` extrinsics and the
140		/// `create_collection` function will return an `UnknownCollection` Error. Instead use
141		/// the `create_collection_with_id` function. However, if the `Incrementable` trait
142		/// implementation has an incremental order, the `create_collection_with_id` function
143		/// should not be used as it can claim a value in the ID sequence.
144		type CollectionId: Member + Parameter + MaxEncodedLen + Copy + Incrementable;
145
146		/// The type used to identify a unique item within a collection.
147		type ItemId: Member + Parameter + MaxEncodedLen + Copy;
148
149		/// The currency mechanism, used for paying for reserves.
150		type Currency: ReservableCurrency<Self::AccountId>;
151
152		/// The origin which may forcibly create or destroy an item or otherwise alter privileged
153		/// attributes.
154		type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
155
156		/// Standard collection creation is only allowed if the origin attempting it and the
157		/// collection are in this set.
158		type CreateOrigin: EnsureOriginWithArg<
159			Self::RuntimeOrigin,
160			Self::CollectionId,
161			Success = Self::AccountId,
162		>;
163
164		/// Locker trait to enable Locking mechanism downstream.
165		type Locker: Locker<Self::CollectionId, Self::ItemId>;
166
167		/// The basic amount of funds that must be reserved for collection.
168		#[pallet::constant]
169		type CollectionDeposit: Get<DepositBalanceOf<Self, I>>;
170
171		/// The basic amount of funds that must be reserved for an item.
172		#[pallet::constant]
173		type ItemDeposit: Get<DepositBalanceOf<Self, I>>;
174
175		/// The basic amount of funds that must be reserved when adding metadata to your item.
176		#[pallet::constant]
177		type MetadataDepositBase: Get<DepositBalanceOf<Self, I>>;
178
179		/// The basic amount of funds that must be reserved when adding an attribute to an item.
180		#[pallet::constant]
181		type AttributeDepositBase: Get<DepositBalanceOf<Self, I>>;
182
183		/// The additional funds that must be reserved for the number of bytes store in metadata,
184		/// either "normal" metadata or attribute metadata.
185		#[pallet::constant]
186		type DepositPerByte: Get<DepositBalanceOf<Self, I>>;
187
188		/// The maximum length of data stored on-chain.
189		#[pallet::constant]
190		type StringLimit: Get<u32>;
191
192		/// The maximum length of an attribute key.
193		#[pallet::constant]
194		type KeyLimit: Get<u32>;
195
196		/// The maximum length of an attribute value.
197		#[pallet::constant]
198		type ValueLimit: Get<u32>;
199
200		/// The maximum approvals an item could have.
201		#[pallet::constant]
202		type ApprovalsLimit: Get<u32>;
203
204		/// The maximum attributes approvals an item could have.
205		#[pallet::constant]
206		type ItemAttributesApprovalsLimit: Get<u32>;
207
208		/// The max number of tips a user could send.
209		#[pallet::constant]
210		type MaxTips: Get<u32>;
211
212		/// The max duration in blocks for deadlines.
213		#[pallet::constant]
214		type MaxDeadlineDuration: Get<BlockNumberFor<Self, I>>;
215
216		/// The max number of attributes a user could set per call.
217		#[pallet::constant]
218		type MaxAttributesPerCall: Get<u32>;
219
220		/// Disables some of pallet's features.
221		#[pallet::constant]
222		type Features: Get<PalletFeatures>;
223
224		/// Off-Chain signature type.
225		///
226		/// Can verify whether an `Self::OffchainPublic` created a signature.
227		type OffchainSignature: Verify<Signer = Self::OffchainPublic> + Parameter;
228
229		/// Off-Chain public key.
230		///
231		/// Must identify as an on-chain `Self::AccountId`.
232		type OffchainPublic: IdentifyAccount<AccountId = Self::AccountId>;
233
234		#[cfg(feature = "runtime-benchmarks")]
235		/// A set of helper functions for benchmarking.
236		type Helper: BenchmarkHelper<
237			Self::CollectionId,
238			Self::ItemId,
239			Self::OffchainPublic,
240			Self::AccountId,
241			Self::OffchainSignature,
242		>;
243
244		/// Weight information for extrinsics in this pallet.
245		type WeightInfo: WeightInfo;
246
247		/// Provider for the block number. Normally this is the `frame_system` pallet.
248		type BlockNumberProvider: BlockNumberProvider;
249	}
250
251	/// Details of a collection.
252	#[pallet::storage]
253	pub type Collection<T: Config<I>, I: 'static = ()> = StorageMap<
254		_,
255		Blake2_128Concat,
256		T::CollectionId,
257		CollectionDetails<T::AccountId, DepositBalanceOf<T, I>>,
258	>;
259
260	/// The collection, if any, of which an account is willing to take ownership.
261	#[pallet::storage]
262	pub type OwnershipAcceptance<T: Config<I>, I: 'static = ()> =
263		StorageMap<_, Blake2_128Concat, T::AccountId, T::CollectionId>;
264
265	/// The items held by any given account; set out this way so that items owned by a single
266	/// account can be enumerated.
267	#[pallet::storage]
268	pub type Account<T: Config<I>, I: 'static = ()> = StorageNMap<
269		_,
270		(
271			NMapKey<Blake2_128Concat, T::AccountId>, // owner
272			NMapKey<Blake2_128Concat, T::CollectionId>,
273			NMapKey<Blake2_128Concat, T::ItemId>,
274		),
275		(),
276		OptionQuery,
277	>;
278
279	/// The collections owned by any given account; set out this way so that collections owned by
280	/// a single account can be enumerated.
281	#[pallet::storage]
282	pub type CollectionAccount<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
283		_,
284		Blake2_128Concat,
285		T::AccountId,
286		Blake2_128Concat,
287		T::CollectionId,
288		(),
289		OptionQuery,
290	>;
291
292	/// The items in existence and their ownership details.
293	#[pallet::storage]
294	/// Stores collection roles as per account.
295	pub type CollectionRoleOf<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
296		_,
297		Blake2_128Concat,
298		T::CollectionId,
299		Blake2_128Concat,
300		T::AccountId,
301		CollectionRoles,
302		OptionQuery,
303	>;
304
305	/// The items in existence and their ownership details.
306	#[pallet::storage]
307	pub type Item<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
308		_,
309		Blake2_128Concat,
310		T::CollectionId,
311		Blake2_128Concat,
312		T::ItemId,
313		ItemDetails<T::AccountId, ItemDepositOf<T, I>, ApprovalsOf<T, I>>,
314		OptionQuery,
315	>;
316
317	/// Metadata of a collection.
318	#[pallet::storage]
319	pub type CollectionMetadataOf<T: Config<I>, I: 'static = ()> = StorageMap<
320		_,
321		Blake2_128Concat,
322		T::CollectionId,
323		CollectionMetadata<DepositBalanceOf<T, I>, T::StringLimit>,
324		OptionQuery,
325	>;
326
327	/// Metadata of an item.
328	#[pallet::storage]
329	pub type ItemMetadataOf<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
330		_,
331		Blake2_128Concat,
332		T::CollectionId,
333		Blake2_128Concat,
334		T::ItemId,
335		ItemMetadata<ItemMetadataDepositOf<T, I>, T::StringLimit>,
336		OptionQuery,
337	>;
338
339	/// Attributes of a collection.
340	#[pallet::storage]
341	pub type Attribute<T: Config<I>, I: 'static = ()> = StorageNMap<
342		_,
343		(
344			NMapKey<Blake2_128Concat, T::CollectionId>,
345			NMapKey<Blake2_128Concat, Option<T::ItemId>>,
346			NMapKey<Blake2_128Concat, AttributeNamespace<T::AccountId>>,
347			NMapKey<Blake2_128Concat, BoundedVec<u8, T::KeyLimit>>,
348		),
349		(BoundedVec<u8, T::ValueLimit>, AttributeDepositOf<T, I>),
350		OptionQuery,
351	>;
352
353	/// A price of an item.
354	#[pallet::storage]
355	pub type ItemPriceOf<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
356		_,
357		Blake2_128Concat,
358		T::CollectionId,
359		Blake2_128Concat,
360		T::ItemId,
361		(ItemPrice<T, I>, Option<T::AccountId>),
362		OptionQuery,
363	>;
364
365	/// Item attribute approvals.
366	#[pallet::storage]
367	pub type ItemAttributesApprovalsOf<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
368		_,
369		Blake2_128Concat,
370		T::CollectionId,
371		Blake2_128Concat,
372		T::ItemId,
373		ItemAttributesApprovals<T, I>,
374		ValueQuery,
375	>;
376
377	/// Stores the `CollectionId` that is going to be used for the next collection.
378	/// This gets incremented whenever a new collection is created.
379	#[pallet::storage]
380	pub type NextCollectionId<T: Config<I>, I: 'static = ()> =
381		StorageValue<_, T::CollectionId, OptionQuery>;
382
383	/// Handles all the pending swaps.
384	#[pallet::storage]
385	pub type PendingSwapOf<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
386		_,
387		Blake2_128Concat,
388		T::CollectionId,
389		Blake2_128Concat,
390		T::ItemId,
391		PendingSwap<
392			T::CollectionId,
393			T::ItemId,
394			PriceWithDirection<ItemPrice<T, I>>,
395			BlockNumberFor<T, I>,
396		>,
397		OptionQuery,
398	>;
399
400	/// Config of a collection.
401	#[pallet::storage]
402	pub type CollectionConfigOf<T: Config<I>, I: 'static = ()> =
403		StorageMap<_, Blake2_128Concat, T::CollectionId, CollectionConfigFor<T, I>, OptionQuery>;
404
405	/// Config of an item.
406	#[pallet::storage]
407	pub type ItemConfigOf<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
408		_,
409		Blake2_128Concat,
410		T::CollectionId,
411		Blake2_128Concat,
412		T::ItemId,
413		ItemConfig,
414		OptionQuery,
415	>;
416
417	#[pallet::event]
418	#[pallet::generate_deposit(pub(super) fn deposit_event)]
419	pub enum Event<T: Config<I>, I: 'static = ()> {
420		/// A `collection` was created.
421		Created { collection: T::CollectionId, creator: T::AccountId, owner: T::AccountId },
422		/// A `collection` was force-created.
423		ForceCreated { collection: T::CollectionId, owner: T::AccountId },
424		/// A `collection` was destroyed.
425		Destroyed { collection: T::CollectionId },
426		/// An `item` was issued.
427		Issued { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId },
428		/// An `item` was transferred.
429		Transferred {
430			collection: T::CollectionId,
431			item: T::ItemId,
432			from: T::AccountId,
433			to: T::AccountId,
434		},
435		/// An `item` was destroyed.
436		Burned { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId },
437		/// An `item` became non-transferable.
438		ItemTransferLocked { collection: T::CollectionId, item: T::ItemId },
439		/// An `item` became transferable.
440		ItemTransferUnlocked { collection: T::CollectionId, item: T::ItemId },
441		/// `item` metadata or attributes were locked.
442		ItemPropertiesLocked {
443			collection: T::CollectionId,
444			item: T::ItemId,
445			lock_metadata: bool,
446			lock_attributes: bool,
447		},
448		/// Some `collection` was locked.
449		CollectionLocked { collection: T::CollectionId },
450		/// The owner changed.
451		OwnerChanged { collection: T::CollectionId, new_owner: T::AccountId },
452		/// The management team changed.
453		TeamChanged {
454			collection: T::CollectionId,
455			issuer: Option<T::AccountId>,
456			admin: Option<T::AccountId>,
457			freezer: Option<T::AccountId>,
458		},
459		/// An `item` of a `collection` has been approved by the `owner` for transfer by
460		/// a `delegate`.
461		TransferApproved {
462			collection: T::CollectionId,
463			item: T::ItemId,
464			owner: T::AccountId,
465			delegate: T::AccountId,
466			deadline: Option<BlockNumberFor<T, I>>,
467		},
468		/// An approval for a `delegate` account to transfer the `item` of an item
469		/// `collection` was cancelled by its `owner`.
470		ApprovalCancelled {
471			collection: T::CollectionId,
472			item: T::ItemId,
473			owner: T::AccountId,
474			delegate: T::AccountId,
475		},
476		/// All approvals of an item got cancelled.
477		AllApprovalsCancelled { collection: T::CollectionId, item: T::ItemId, owner: T::AccountId },
478		/// A `collection` has had its config changed by the `Force` origin.
479		CollectionConfigChanged { collection: T::CollectionId },
480		/// New metadata has been set for a `collection`.
481		CollectionMetadataSet { collection: T::CollectionId, data: BoundedVec<u8, T::StringLimit> },
482		/// Metadata has been cleared for a `collection`.
483		CollectionMetadataCleared { collection: T::CollectionId },
484		/// New metadata has been set for an item.
485		ItemMetadataSet {
486			collection: T::CollectionId,
487			item: T::ItemId,
488			data: BoundedVec<u8, T::StringLimit>,
489		},
490		/// Metadata has been cleared for an item.
491		ItemMetadataCleared { collection: T::CollectionId, item: T::ItemId },
492		/// The deposit for a set of `item`s within a `collection` has been updated.
493		Redeposited { collection: T::CollectionId, successful_items: Vec<T::ItemId> },
494		/// New attribute metadata has been set for a `collection` or `item`.
495		AttributeSet {
496			collection: T::CollectionId,
497			maybe_item: Option<T::ItemId>,
498			key: BoundedVec<u8, T::KeyLimit>,
499			value: BoundedVec<u8, T::ValueLimit>,
500			namespace: AttributeNamespace<T::AccountId>,
501		},
502		/// Attribute metadata has been cleared for a `collection` or `item`.
503		AttributeCleared {
504			collection: T::CollectionId,
505			maybe_item: Option<T::ItemId>,
506			key: BoundedVec<u8, T::KeyLimit>,
507			namespace: AttributeNamespace<T::AccountId>,
508		},
509		/// A new approval to modify item attributes was added.
510		ItemAttributesApprovalAdded {
511			collection: T::CollectionId,
512			item: T::ItemId,
513			delegate: T::AccountId,
514		},
515		/// A new approval to modify item attributes was removed.
516		ItemAttributesApprovalRemoved {
517			collection: T::CollectionId,
518			item: T::ItemId,
519			delegate: T::AccountId,
520		},
521		/// Ownership acceptance has changed for an account.
522		OwnershipAcceptanceChanged { who: T::AccountId, maybe_collection: Option<T::CollectionId> },
523		/// Max supply has been set for a collection.
524		CollectionMaxSupplySet { collection: T::CollectionId, max_supply: u32 },
525		/// Mint settings for a collection had changed.
526		CollectionMintSettingsUpdated { collection: T::CollectionId },
527		/// Event gets emitted when the `NextCollectionId` gets incremented.
528		NextCollectionIdIncremented { next_id: Option<T::CollectionId> },
529		/// The price was set for the item.
530		ItemPriceSet {
531			collection: T::CollectionId,
532			item: T::ItemId,
533			price: ItemPrice<T, I>,
534			whitelisted_buyer: Option<T::AccountId>,
535		},
536		/// The price for the item was removed.
537		ItemPriceRemoved { collection: T::CollectionId, item: T::ItemId },
538		/// An item was bought.
539		ItemBought {
540			collection: T::CollectionId,
541			item: T::ItemId,
542			price: ItemPrice<T, I>,
543			seller: T::AccountId,
544			buyer: T::AccountId,
545		},
546		/// A tip was sent.
547		TipSent {
548			collection: T::CollectionId,
549			item: T::ItemId,
550			sender: T::AccountId,
551			receiver: T::AccountId,
552			amount: DepositBalanceOf<T, I>,
553		},
554		/// An `item` swap intent was created.
555		SwapCreated {
556			offered_collection: T::CollectionId,
557			offered_item: T::ItemId,
558			desired_collection: T::CollectionId,
559			desired_item: Option<T::ItemId>,
560			price: Option<PriceWithDirection<ItemPrice<T, I>>>,
561			deadline: BlockNumberFor<T, I>,
562		},
563		/// The swap was cancelled.
564		SwapCancelled {
565			offered_collection: T::CollectionId,
566			offered_item: T::ItemId,
567			desired_collection: T::CollectionId,
568			desired_item: Option<T::ItemId>,
569			price: Option<PriceWithDirection<ItemPrice<T, I>>>,
570			deadline: BlockNumberFor<T, I>,
571		},
572		/// The swap has been claimed.
573		SwapClaimed {
574			sent_collection: T::CollectionId,
575			sent_item: T::ItemId,
576			sent_item_owner: T::AccountId,
577			received_collection: T::CollectionId,
578			received_item: T::ItemId,
579			received_item_owner: T::AccountId,
580			price: Option<PriceWithDirection<ItemPrice<T, I>>>,
581			deadline: BlockNumberFor<T, I>,
582		},
583		/// New attributes have been set for an `item` of the `collection`.
584		PreSignedAttributesSet {
585			collection: T::CollectionId,
586			item: T::ItemId,
587			namespace: AttributeNamespace<T::AccountId>,
588		},
589		/// A new attribute in the `Pallet` namespace was set for the `collection` or an `item`
590		/// within that `collection`.
591		PalletAttributeSet {
592			collection: T::CollectionId,
593			item: Option<T::ItemId>,
594			attribute: PalletAttributes<T::CollectionId>,
595			value: BoundedVec<u8, T::ValueLimit>,
596		},
597	}
598
599	#[pallet::error]
600	pub enum Error<T, I = ()> {
601		/// The signing account has no permission to do the operation.
602		NoPermission,
603		/// The given item ID is unknown.
604		UnknownCollection,
605		/// The item ID has already been used for an item.
606		AlreadyExists,
607		/// The approval had a deadline that expired, so the approval isn't valid anymore.
608		ApprovalExpired,
609		/// The owner turned out to be different to what was expected.
610		WrongOwner,
611		/// The witness data given does not match the current state of the chain.
612		BadWitness,
613		/// Collection ID is already taken.
614		CollectionIdInUse,
615		/// Items within that collection are non-transferable.
616		ItemsNonTransferable,
617		/// The provided account is not a delegate.
618		NotDelegate,
619		/// The delegate turned out to be different to what was expected.
620		WrongDelegate,
621		/// No approval exists that would allow the transfer.
622		Unapproved,
623		/// The named owner has not signed ownership acceptance of the collection.
624		Unaccepted,
625		/// The item is locked (non-transferable).
626		ItemLocked,
627		/// Item's attributes are locked.
628		LockedItemAttributes,
629		/// Collection's attributes are locked.
630		LockedCollectionAttributes,
631		/// Item's metadata is locked.
632		LockedItemMetadata,
633		/// Collection's metadata is locked.
634		LockedCollectionMetadata,
635		/// All items have been minted.
636		MaxSupplyReached,
637		/// The max supply is locked and can't be changed.
638		MaxSupplyLocked,
639		/// The provided max supply is less than the number of items a collection already has.
640		MaxSupplyTooSmall,
641		/// The given item ID is unknown.
642		UnknownItem,
643		/// Swap doesn't exist.
644		UnknownSwap,
645		/// The given item has no metadata set.
646		MetadataNotFound,
647		/// The provided attribute can't be found.
648		AttributeNotFound,
649		/// Item is not for sale.
650		NotForSale,
651		/// The provided bid is too low.
652		BidTooLow,
653		/// The item has reached its approval limit.
654		ReachedApprovalLimit,
655		/// The deadline has already expired.
656		DeadlineExpired,
657		/// The duration provided should be less than or equal to `MaxDeadlineDuration`.
658		WrongDuration,
659		/// The method is disabled by system settings.
660		MethodDisabled,
661		/// The provided setting can't be set.
662		WrongSetting,
663		/// Item's config already exists and should be equal to the provided one.
664		InconsistentItemConfig,
665		/// Config for a collection or an item can't be found.
666		NoConfig,
667		/// Some roles were not cleared.
668		RolesNotCleared,
669		/// Mint has not started yet.
670		MintNotStarted,
671		/// Mint has already ended.
672		MintEnded,
673		/// The provided Item was already used for claiming.
674		AlreadyClaimed,
675		/// The provided data is incorrect.
676		IncorrectData,
677		/// The extrinsic was sent by the wrong origin.
678		WrongOrigin,
679		/// The provided signature is incorrect.
680		WrongSignature,
681		/// The provided metadata might be too long.
682		IncorrectMetadata,
683		/// Can't set more attributes per one call.
684		MaxAttributesLimitReached,
685		/// The provided namespace isn't supported in this call.
686		WrongNamespace,
687		/// Can't delete non-empty collections.
688		CollectionNotEmpty,
689		/// The witness data should be provided.
690		WitnessRequired,
691	}
692
693	#[pallet::call]
694	impl<T: Config<I>, I: 'static> Pallet<T, I> {
695		/// Issue a new collection of non-fungible items from a public origin.
696		///
697		/// This new collection has no items initially and its owner is the origin.
698		///
699		/// The origin must be Signed and the sender must have sufficient funds free.
700		///
701		/// `CollectionDeposit` funds of sender are reserved.
702		///
703		/// Parameters:
704		/// - `admin`: The admin of this collection. The admin is the initial address of each
705		/// member of the collection's admin team.
706		///
707		/// Emits `Created` event when successful.
708		///
709		/// Weight: `O(1)`
710		#[pallet::call_index(0)]
711		#[pallet::weight(T::WeightInfo::create())]
712		pub fn create(
713			origin: OriginFor<T>,
714			admin: AccountIdLookupOf<T>,
715			config: CollectionConfigFor<T, I>,
716		) -> DispatchResult {
717			let collection = NextCollectionId::<T, I>::get()
718				.or(T::CollectionId::initial_value())
719				.ok_or(Error::<T, I>::UnknownCollection)?;
720
721			let owner = T::CreateOrigin::ensure_origin(origin, &collection)?;
722			let admin = T::Lookup::lookup(admin)?;
723
724			// DepositRequired can be disabled by calling the force_create() only
725			ensure!(
726				!config.has_disabled_setting(CollectionSetting::DepositRequired),
727				Error::<T, I>::WrongSetting
728			);
729
730			Self::do_create_collection(
731				collection,
732				owner.clone(),
733				admin.clone(),
734				config,
735				T::CollectionDeposit::get(),
736				Event::Created { collection, creator: owner, owner: admin },
737			)?;
738
739			Self::set_next_collection_id(collection);
740			Ok(())
741		}
742
743		/// Issue a new collection of non-fungible items from a privileged origin.
744		///
745		/// This new collection has no items initially.
746		///
747		/// The origin must conform to `ForceOrigin`.
748		///
749		/// Unlike `create`, no funds are reserved.
750		///
751		/// - `owner`: The owner of this collection of items. The owner has full superuser
752		///   permissions over this item, but may later change and configure the permissions using
753		///   `transfer_ownership` and `set_team`.
754		///
755		/// Emits `ForceCreated` event when successful.
756		///
757		/// Weight: `O(1)`
758		#[pallet::call_index(1)]
759		#[pallet::weight(T::WeightInfo::force_create())]
760		pub fn force_create(
761			origin: OriginFor<T>,
762			owner: AccountIdLookupOf<T>,
763			config: CollectionConfigFor<T, I>,
764		) -> DispatchResult {
765			T::ForceOrigin::ensure_origin(origin)?;
766			let owner = T::Lookup::lookup(owner)?;
767
768			let collection = NextCollectionId::<T, I>::get()
769				.or(T::CollectionId::initial_value())
770				.ok_or(Error::<T, I>::UnknownCollection)?;
771
772			Self::do_create_collection(
773				collection,
774				owner.clone(),
775				owner.clone(),
776				config,
777				Zero::zero(),
778				Event::ForceCreated { collection, owner },
779			)?;
780
781			Self::set_next_collection_id(collection);
782			Ok(())
783		}
784
785		/// Destroy a collection of fungible items.
786		///
787		/// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the
788		/// owner of the `collection`.
789		///
790		/// NOTE: The collection must have 0 items to be destroyed.
791		///
792		/// - `collection`: The identifier of the collection to be destroyed.
793		/// - `witness`: Information on the items minted in the collection. This must be
794		/// correct.
795		///
796		/// Emits `Destroyed` event when successful.
797		///
798		/// Weight: `O(m + c + a)` where:
799		/// - `m = witness.item_metadatas`
800		/// - `c = witness.item_configs`
801		/// - `a = witness.attributes`
802		#[pallet::call_index(2)]
803		#[pallet::weight(T::WeightInfo::destroy(
804			witness.item_metadatas,
805			witness.item_configs,
806			witness.attributes,
807 		))]
808		pub fn destroy(
809			origin: OriginFor<T>,
810			collection: T::CollectionId,
811			witness: DestroyWitness,
812		) -> DispatchResultWithPostInfo {
813			let maybe_check_owner = T::ForceOrigin::try_origin(origin)
814				.map(|_| None)
815				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
816			let details = Self::do_destroy_collection(collection, witness, maybe_check_owner)?;
817
818			Ok(Some(T::WeightInfo::destroy(
819				details.item_metadatas,
820				details.item_configs,
821				details.attributes,
822			))
823			.into())
824		}
825
826		/// Mint an item of a particular collection.
827		///
828		/// The origin must be Signed and the sender must comply with the `mint_settings` rules.
829		///
830		/// - `collection`: The collection of the item to be minted.
831		/// - `item`: An identifier of the new item.
832		/// - `mint_to`: Account into which the item will be minted.
833		/// - `witness_data`: When the mint type is `HolderOf(collection_id)`, then the owned
834		///   item_id from that collection needs to be provided within the witness data object. If
835		///   the mint price is set, then it should be additionally confirmed in the `witness_data`.
836		///
837		/// Note: the deposit will be taken from the `origin` and not the `owner` of the `item`.
838		///
839		/// Emits `Issued` event when successful.
840		///
841		/// Weight: `O(1)`
842		#[pallet::call_index(3)]
843		#[pallet::weight(T::WeightInfo::mint())]
844		pub fn mint(
845			origin: OriginFor<T>,
846			collection: T::CollectionId,
847			item: T::ItemId,
848			mint_to: AccountIdLookupOf<T>,
849			witness_data: Option<MintWitness<T::ItemId, DepositBalanceOf<T, I>>>,
850		) -> DispatchResult {
851			let caller = ensure_signed(origin)?;
852			let mint_to = T::Lookup::lookup(mint_to)?;
853			let item_config =
854				ItemConfig { settings: Self::get_default_item_settings(&collection)? };
855
856			Self::do_mint(
857				collection,
858				item,
859				Some(caller.clone()),
860				mint_to.clone(),
861				item_config,
862				|collection_details, collection_config| {
863					let mint_settings = collection_config.mint_settings;
864					let now = T::BlockNumberProvider::current_block_number();
865
866					if let Some(start_block) = mint_settings.start_block {
867						ensure!(start_block <= now, Error::<T, I>::MintNotStarted);
868					}
869					if let Some(end_block) = mint_settings.end_block {
870						ensure!(end_block >= now, Error::<T, I>::MintEnded);
871					}
872
873					match mint_settings.mint_type {
874						MintType::Issuer => {
875							ensure!(
876								Self::has_role(&collection, &caller, CollectionRole::Issuer),
877								Error::<T, I>::NoPermission
878							);
879						},
880						MintType::HolderOf(collection_id) => {
881							let MintWitness { owned_item, .. } =
882								witness_data.clone().ok_or(Error::<T, I>::WitnessRequired)?;
883							let owned_item = owned_item.ok_or(Error::<T, I>::BadWitness)?;
884
885							let owns_item = Account::<T, I>::contains_key((
886								&caller,
887								&collection_id,
888								&owned_item,
889							));
890							ensure!(owns_item, Error::<T, I>::BadWitness);
891
892							let pallet_attribute =
893								PalletAttributes::<T::CollectionId>::UsedToClaim(collection);
894
895							let key = (
896								&collection_id,
897								Some(owned_item),
898								AttributeNamespace::Pallet,
899								&Self::construct_attribute_key(pallet_attribute.encode())?,
900							);
901							let already_claimed = Attribute::<T, I>::contains_key(key.clone());
902							ensure!(!already_claimed, Error::<T, I>::AlreadyClaimed);
903
904							let attribute_value = Self::construct_attribute_value(vec![])?;
905							Attribute::<T, I>::insert(
906								key,
907								(
908									attribute_value.clone(),
909									AttributeDeposit { account: None, amount: Zero::zero() },
910								),
911							);
912							Self::deposit_event(Event::PalletAttributeSet {
913								collection: collection_id,
914								item: Some(owned_item),
915								attribute: pallet_attribute,
916								value: attribute_value,
917							});
918						},
919						_ => {},
920					}
921
922					if let Some(price) = mint_settings.price {
923						let MintWitness { mint_price, .. } =
924							witness_data.clone().ok_or(Error::<T, I>::WitnessRequired)?;
925						let mint_price = mint_price.ok_or(Error::<T, I>::BadWitness)?;
926						ensure!(mint_price >= price, Error::<T, I>::BadWitness);
927						T::Currency::transfer(
928							&caller,
929							&collection_details.owner,
930							price,
931							ExistenceRequirement::KeepAlive,
932						)?;
933					}
934
935					Ok(())
936				},
937			)
938		}
939
940		/// Mint an item of a particular collection from a privileged origin.
941		///
942		/// The origin must conform to `ForceOrigin` or must be `Signed` and the sender must be the
943		/// Issuer of the `collection`.
944		///
945		/// - `collection`: The collection of the item to be minted.
946		/// - `item`: An identifier of the new item.
947		/// - `mint_to`: Account into which the item will be minted.
948		/// - `item_config`: A config of the new item.
949		///
950		/// Emits `Issued` event when successful.
951		///
952		/// Weight: `O(1)`
953		#[pallet::call_index(4)]
954		#[pallet::weight(T::WeightInfo::force_mint())]
955		pub fn force_mint(
956			origin: OriginFor<T>,
957			collection: T::CollectionId,
958			item: T::ItemId,
959			mint_to: AccountIdLookupOf<T>,
960			item_config: ItemConfig,
961		) -> DispatchResult {
962			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
963				.map(|_| None)
964				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
965			let mint_to = T::Lookup::lookup(mint_to)?;
966
967			if let Some(check_origin) = maybe_check_origin {
968				ensure!(
969					Self::has_role(&collection, &check_origin, CollectionRole::Issuer),
970					Error::<T, I>::NoPermission
971				);
972			}
973			Self::do_mint(collection, item, None, mint_to, item_config, |_, _| Ok(()))
974		}
975
976		/// Destroy a single item.
977		///
978		/// The origin must conform to `ForceOrigin` or must be Signed and the signing account must
979		/// be the owner of the `item`.
980		///
981		/// - `collection`: The collection of the item to be burned.
982		/// - `item`: The item to be burned.
983		///
984		/// Emits `Burned`.
985		///
986		/// Weight: `O(1)`
987		#[pallet::call_index(5)]
988		#[pallet::weight(T::WeightInfo::burn())]
989		pub fn burn(
990			origin: OriginFor<T>,
991			collection: T::CollectionId,
992			item: T::ItemId,
993		) -> DispatchResult {
994			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
995				.map(|_| None)
996				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
997
998			Self::do_burn(collection, item, |details| {
999				if let Some(check_origin) = maybe_check_origin {
1000					ensure!(details.owner == check_origin, Error::<T, I>::NoPermission);
1001				}
1002				Ok(())
1003			})
1004		}
1005
1006		/// Move an item from the sender account to another.
1007		///
1008		/// Origin must be Signed and the signing account must be either:
1009		/// - the Owner of the `item`;
1010		/// - the approved delegate for the `item` (in this case, the approval is reset).
1011		///
1012		/// Arguments:
1013		/// - `collection`: The collection of the item to be transferred.
1014		/// - `item`: The item to be transferred.
1015		/// - `dest`: The account to receive ownership of the item.
1016		///
1017		/// Emits `Transferred`.
1018		///
1019		/// Weight: `O(1)`
1020		#[pallet::call_index(6)]
1021		#[pallet::weight(T::WeightInfo::transfer())]
1022		pub fn transfer(
1023			origin: OriginFor<T>,
1024			collection: T::CollectionId,
1025			item: T::ItemId,
1026			dest: AccountIdLookupOf<T>,
1027		) -> DispatchResult {
1028			let origin = ensure_signed(origin)?;
1029			let dest = T::Lookup::lookup(dest)?;
1030
1031			Self::do_transfer(collection, item, dest, |_, details| {
1032				if details.owner != origin {
1033					let deadline =
1034						details.approvals.get(&origin).ok_or(Error::<T, I>::NoPermission)?;
1035					if let Some(d) = deadline {
1036						let block_number = T::BlockNumberProvider::current_block_number();
1037						ensure!(block_number <= *d, Error::<T, I>::ApprovalExpired);
1038					}
1039				}
1040				Ok(())
1041			})
1042		}
1043
1044		/// Re-evaluate the deposits on some items.
1045		///
1046		/// Origin must be Signed and the sender should be the Owner of the `collection`.
1047		///
1048		/// - `collection`: The collection of the items to be reevaluated.
1049		/// - `items`: The items of the collection whose deposits will be reevaluated.
1050		///
1051		/// NOTE: This exists as a best-effort function. Any items which are unknown or
1052		/// in the case that the owner account does not have reservable funds to pay for a
1053		/// deposit increase are ignored. Generally the owner isn't going to call this on items
1054		/// whose existing deposit is less than the refreshed deposit as it would only cost them,
1055		/// so it's of little consequence.
1056		///
1057		/// It will still return an error in the case that the collection is unknown or the signer
1058		/// is not permitted to call it.
1059		///
1060		/// Weight: `O(items.len())`
1061		#[pallet::call_index(7)]
1062		#[pallet::weight(T::WeightInfo::redeposit(items.len() as u32))]
1063		pub fn redeposit(
1064			origin: OriginFor<T>,
1065			collection: T::CollectionId,
1066			items: Vec<T::ItemId>,
1067		) -> DispatchResult {
1068			let origin = ensure_signed(origin)?;
1069
1070			let collection_details =
1071				Collection::<T, I>::get(&collection).ok_or(Error::<T, I>::UnknownCollection)?;
1072			ensure!(collection_details.owner == origin, Error::<T, I>::NoPermission);
1073
1074			let config = Self::get_collection_config(&collection)?;
1075			let deposit = match config.is_setting_enabled(CollectionSetting::DepositRequired) {
1076				true => T::ItemDeposit::get(),
1077				false => Zero::zero(),
1078			};
1079
1080			let mut successful = Vec::with_capacity(items.len());
1081			for item in items.into_iter() {
1082				let mut details = match Item::<T, I>::get(&collection, &item) {
1083					Some(x) => x,
1084					None => continue,
1085				};
1086				let old = details.deposit.amount;
1087				if old > deposit {
1088					T::Currency::unreserve(&details.deposit.account, old - deposit);
1089				} else if deposit > old {
1090					if T::Currency::reserve(&details.deposit.account, deposit - old).is_err() {
1091						// NOTE: No alterations made to collection_details in this iteration so far,
1092						// so this is OK to do.
1093						continue
1094					}
1095				} else {
1096					continue
1097				}
1098				details.deposit.amount = deposit;
1099				Item::<T, I>::insert(&collection, &item, &details);
1100				successful.push(item);
1101			}
1102
1103			Self::deposit_event(Event::<T, I>::Redeposited {
1104				collection,
1105				successful_items: successful,
1106			});
1107
1108			Ok(())
1109		}
1110
1111		/// Disallow further unprivileged transfer of an item.
1112		///
1113		/// Origin must be Signed and the sender should be the Freezer of the `collection`.
1114		///
1115		/// - `collection`: The collection of the item to be changed.
1116		/// - `item`: The item to become non-transferable.
1117		///
1118		/// Emits `ItemTransferLocked`.
1119		///
1120		/// Weight: `O(1)`
1121		#[pallet::call_index(8)]
1122		#[pallet::weight(T::WeightInfo::lock_item_transfer())]
1123		pub fn lock_item_transfer(
1124			origin: OriginFor<T>,
1125			collection: T::CollectionId,
1126			item: T::ItemId,
1127		) -> DispatchResult {
1128			let origin = ensure_signed(origin)?;
1129			Self::do_lock_item_transfer(origin, collection, item)
1130		}
1131
1132		/// Re-allow unprivileged transfer of an item.
1133		///
1134		/// Origin must be Signed and the sender should be the Freezer of the `collection`.
1135		///
1136		/// - `collection`: The collection of the item to be changed.
1137		/// - `item`: The item to become transferable.
1138		///
1139		/// Emits `ItemTransferUnlocked`.
1140		///
1141		/// Weight: `O(1)`
1142		#[pallet::call_index(9)]
1143		#[pallet::weight(T::WeightInfo::unlock_item_transfer())]
1144		pub fn unlock_item_transfer(
1145			origin: OriginFor<T>,
1146			collection: T::CollectionId,
1147			item: T::ItemId,
1148		) -> DispatchResult {
1149			let origin = ensure_signed(origin)?;
1150			Self::do_unlock_item_transfer(origin, collection, item)
1151		}
1152
1153		/// Disallows specified settings for the whole collection.
1154		///
1155		/// Origin must be Signed and the sender should be the Owner of the `collection`.
1156		///
1157		/// - `collection`: The collection to be locked.
1158		/// - `lock_settings`: The settings to be locked.
1159		///
1160		/// Note: it's possible to only lock(set) the setting, but not to unset it.
1161		///
1162		/// Emits `CollectionLocked`.
1163		///
1164		/// Weight: `O(1)`
1165		#[pallet::call_index(10)]
1166		#[pallet::weight(T::WeightInfo::lock_collection())]
1167		pub fn lock_collection(
1168			origin: OriginFor<T>,
1169			collection: T::CollectionId,
1170			lock_settings: CollectionSettings,
1171		) -> DispatchResult {
1172			let origin = ensure_signed(origin)?;
1173			Self::do_lock_collection(origin, collection, lock_settings)
1174		}
1175
1176		/// Change the Owner of a collection.
1177		///
1178		/// Origin must be Signed and the sender should be the Owner of the `collection`.
1179		///
1180		/// - `collection`: The collection whose owner should be changed.
1181		/// - `owner`: The new Owner of this collection. They must have called
1182		///   `set_accept_ownership` with `collection` in order for this operation to succeed.
1183		///
1184		/// Emits `OwnerChanged`.
1185		///
1186		/// Weight: `O(1)`
1187		#[pallet::call_index(11)]
1188		#[pallet::weight(T::WeightInfo::transfer_ownership())]
1189		pub fn transfer_ownership(
1190			origin: OriginFor<T>,
1191			collection: T::CollectionId,
1192			new_owner: AccountIdLookupOf<T>,
1193		) -> DispatchResult {
1194			let origin = ensure_signed(origin)?;
1195			let new_owner = T::Lookup::lookup(new_owner)?;
1196			Self::do_transfer_ownership(origin, collection, new_owner)
1197		}
1198
1199		/// Change the Issuer, Admin and Freezer of a collection.
1200		///
1201		/// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the
1202		/// `collection`.
1203		///
1204		/// Note: by setting the role to `None` only the `ForceOrigin` will be able to change it
1205		/// after to `Some(account)`.
1206		///
1207		/// - `collection`: The collection whose team should be changed.
1208		/// - `issuer`: The new Issuer of this collection.
1209		/// - `admin`: The new Admin of this collection.
1210		/// - `freezer`: The new Freezer of this collection.
1211		///
1212		/// Emits `TeamChanged`.
1213		///
1214		/// Weight: `O(1)`
1215		#[pallet::call_index(12)]
1216		#[pallet::weight(T::WeightInfo::set_team())]
1217		pub fn set_team(
1218			origin: OriginFor<T>,
1219			collection: T::CollectionId,
1220			issuer: Option<AccountIdLookupOf<T>>,
1221			admin: Option<AccountIdLookupOf<T>>,
1222			freezer: Option<AccountIdLookupOf<T>>,
1223		) -> DispatchResult {
1224			let maybe_check_owner = T::ForceOrigin::try_origin(origin)
1225				.map(|_| None)
1226				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1227			let issuer = issuer.map(T::Lookup::lookup).transpose()?;
1228			let admin = admin.map(T::Lookup::lookup).transpose()?;
1229			let freezer = freezer.map(T::Lookup::lookup).transpose()?;
1230			Self::do_set_team(maybe_check_owner, collection, issuer, admin, freezer)
1231		}
1232
1233		/// Change the Owner of a collection.
1234		///
1235		/// Origin must be `ForceOrigin`.
1236		///
1237		/// - `collection`: The identifier of the collection.
1238		/// - `owner`: The new Owner of this collection.
1239		///
1240		/// Emits `OwnerChanged`.
1241		///
1242		/// Weight: `O(1)`
1243		#[pallet::call_index(13)]
1244		#[pallet::weight(T::WeightInfo::force_collection_owner())]
1245		pub fn force_collection_owner(
1246			origin: OriginFor<T>,
1247			collection: T::CollectionId,
1248			owner: AccountIdLookupOf<T>,
1249		) -> DispatchResult {
1250			T::ForceOrigin::ensure_origin(origin)?;
1251			let new_owner = T::Lookup::lookup(owner)?;
1252			Self::do_force_collection_owner(collection, new_owner)
1253		}
1254
1255		/// Change the config of a collection.
1256		///
1257		/// Origin must be `ForceOrigin`.
1258		///
1259		/// - `collection`: The identifier of the collection.
1260		/// - `config`: The new config of this collection.
1261		///
1262		/// Emits `CollectionConfigChanged`.
1263		///
1264		/// Weight: `O(1)`
1265		#[pallet::call_index(14)]
1266		#[pallet::weight(T::WeightInfo::force_collection_config())]
1267		pub fn force_collection_config(
1268			origin: OriginFor<T>,
1269			collection: T::CollectionId,
1270			config: CollectionConfigFor<T, I>,
1271		) -> DispatchResult {
1272			T::ForceOrigin::ensure_origin(origin)?;
1273			Self::do_force_collection_config(collection, config)
1274		}
1275
1276		/// Approve an item to be transferred by a delegated third-party account.
1277		///
1278		/// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the
1279		/// `item`.
1280		///
1281		/// - `collection`: The collection of the item to be approved for delegated transfer.
1282		/// - `item`: The item to be approved for delegated transfer.
1283		/// - `delegate`: The account to delegate permission to transfer the item.
1284		/// - `maybe_deadline`: Optional deadline for the approval. Specified by providing the
1285		/// 	number of blocks after which the approval will expire
1286		///
1287		/// Emits `TransferApproved` on success.
1288		///
1289		/// Weight: `O(1)`
1290		#[pallet::call_index(15)]
1291		#[pallet::weight(T::WeightInfo::approve_transfer())]
1292		pub fn approve_transfer(
1293			origin: OriginFor<T>,
1294			collection: T::CollectionId,
1295			item: T::ItemId,
1296			delegate: AccountIdLookupOf<T>,
1297			maybe_deadline: Option<BlockNumberFor<T, I>>,
1298		) -> DispatchResult {
1299			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1300				.map(|_| None)
1301				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1302			let delegate = T::Lookup::lookup(delegate)?;
1303			Self::do_approve_transfer(
1304				maybe_check_origin,
1305				collection,
1306				item,
1307				delegate,
1308				maybe_deadline,
1309			)
1310		}
1311
1312		/// Cancel one of the transfer approvals for a specific item.
1313		///
1314		/// Origin must be either:
1315		/// - the `Force` origin;
1316		/// - `Signed` with the signer being the Owner of the `item`;
1317		///
1318		/// Arguments:
1319		/// - `collection`: The collection of the item of whose approval will be cancelled.
1320		/// - `item`: The item of the collection of whose approval will be cancelled.
1321		/// - `delegate`: The account that is going to loose their approval.
1322		///
1323		/// Emits `ApprovalCancelled` on success.
1324		///
1325		/// Weight: `O(1)`
1326		#[pallet::call_index(16)]
1327		#[pallet::weight(T::WeightInfo::cancel_approval())]
1328		pub fn cancel_approval(
1329			origin: OriginFor<T>,
1330			collection: T::CollectionId,
1331			item: T::ItemId,
1332			delegate: AccountIdLookupOf<T>,
1333		) -> DispatchResult {
1334			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1335				.map(|_| None)
1336				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1337			let delegate = T::Lookup::lookup(delegate)?;
1338			Self::do_cancel_approval(maybe_check_origin, collection, item, delegate)
1339		}
1340
1341		/// Cancel all the approvals of a specific item.
1342		///
1343		/// Origin must be either:
1344		/// - the `Force` origin;
1345		/// - `Signed` with the signer being the Owner of the `item`;
1346		///
1347		/// Arguments:
1348		/// - `collection`: The collection of the item of whose approvals will be cleared.
1349		/// - `item`: The item of the collection of whose approvals will be cleared.
1350		///
1351		/// Emits `AllApprovalsCancelled` on success.
1352		///
1353		/// Weight: `O(1)`
1354		#[pallet::call_index(17)]
1355		#[pallet::weight(T::WeightInfo::clear_all_transfer_approvals())]
1356		pub fn clear_all_transfer_approvals(
1357			origin: OriginFor<T>,
1358			collection: T::CollectionId,
1359			item: T::ItemId,
1360		) -> DispatchResult {
1361			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1362				.map(|_| None)
1363				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1364			Self::do_clear_all_transfer_approvals(maybe_check_origin, collection, item)
1365		}
1366
1367		/// Disallows changing the metadata or attributes of the item.
1368		///
1369		/// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin
1370		/// of the `collection`.
1371		///
1372		/// - `collection`: The collection if the `item`.
1373		/// - `item`: An item to be locked.
1374		/// - `lock_metadata`: Specifies whether the metadata should be locked.
1375		/// - `lock_attributes`: Specifies whether the attributes in the `CollectionOwner` namespace
1376		///   should be locked.
1377		///
1378		/// Note: `lock_attributes` affects the attributes in the `CollectionOwner` namespace only.
1379		/// When the metadata or attributes are locked, it won't be possible the unlock them.
1380		///
1381		/// Emits `ItemPropertiesLocked`.
1382		///
1383		/// Weight: `O(1)`
1384		#[pallet::call_index(18)]
1385		#[pallet::weight(T::WeightInfo::lock_item_properties())]
1386		pub fn lock_item_properties(
1387			origin: OriginFor<T>,
1388			collection: T::CollectionId,
1389			item: T::ItemId,
1390			lock_metadata: bool,
1391			lock_attributes: bool,
1392		) -> DispatchResult {
1393			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1394				.map(|_| None)
1395				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1396			Self::do_lock_item_properties(
1397				maybe_check_origin,
1398				collection,
1399				item,
1400				lock_metadata,
1401				lock_attributes,
1402			)
1403		}
1404
1405		/// Set an attribute for a collection or item.
1406		///
1407		/// Origin must be Signed and must conform to the namespace ruleset:
1408		/// - `CollectionOwner` namespace could be modified by the `collection` Admin only;
1409		/// - `ItemOwner` namespace could be modified by the `maybe_item` owner only. `maybe_item`
1410		///   should be set in that case;
1411		/// - `Account(AccountId)` namespace could be modified only when the `origin` was given a
1412		///   permission to do so;
1413		///
1414		/// The funds of `origin` are reserved according to the formula:
1415		/// `AttributeDepositBase + DepositPerByte * (key.len + value.len)` taking into
1416		/// account any already reserved funds.
1417		///
1418		/// - `collection`: The identifier of the collection whose item's metadata to set.
1419		/// - `maybe_item`: The identifier of the item whose metadata to set.
1420		/// - `namespace`: Attribute's namespace.
1421		/// - `key`: The key of the attribute.
1422		/// - `value`: The value to which to set the attribute.
1423		///
1424		/// Emits `AttributeSet`.
1425		///
1426		/// Weight: `O(1)`
1427		#[pallet::call_index(19)]
1428		#[pallet::weight(T::WeightInfo::set_attribute())]
1429		pub fn set_attribute(
1430			origin: OriginFor<T>,
1431			collection: T::CollectionId,
1432			maybe_item: Option<T::ItemId>,
1433			namespace: AttributeNamespace<T::AccountId>,
1434			key: BoundedVec<u8, T::KeyLimit>,
1435			value: BoundedVec<u8, T::ValueLimit>,
1436		) -> DispatchResult {
1437			let origin = ensure_signed(origin)?;
1438			let depositor = match namespace {
1439				AttributeNamespace::CollectionOwner =>
1440					Self::collection_owner(collection).ok_or(Error::<T, I>::UnknownCollection)?,
1441				_ => origin.clone(),
1442			};
1443			Self::do_set_attribute(origin, collection, maybe_item, namespace, key, value, depositor)
1444		}
1445
1446		/// Force-set an attribute for a collection or item.
1447		///
1448		/// Origin must be `ForceOrigin`.
1449		///
1450		/// If the attribute already exists and it was set by another account, the deposit
1451		/// will be returned to the previous owner.
1452		///
1453		/// - `set_as`: An optional owner of the attribute.
1454		/// - `collection`: The identifier of the collection whose item's metadata to set.
1455		/// - `maybe_item`: The identifier of the item whose metadata to set.
1456		/// - `namespace`: Attribute's namespace.
1457		/// - `key`: The key of the attribute.
1458		/// - `value`: The value to which to set the attribute.
1459		///
1460		/// Emits `AttributeSet`.
1461		///
1462		/// Weight: `O(1)`
1463		#[pallet::call_index(20)]
1464		#[pallet::weight(T::WeightInfo::force_set_attribute())]
1465		pub fn force_set_attribute(
1466			origin: OriginFor<T>,
1467			set_as: Option<T::AccountId>,
1468			collection: T::CollectionId,
1469			maybe_item: Option<T::ItemId>,
1470			namespace: AttributeNamespace<T::AccountId>,
1471			key: BoundedVec<u8, T::KeyLimit>,
1472			value: BoundedVec<u8, T::ValueLimit>,
1473		) -> DispatchResult {
1474			T::ForceOrigin::ensure_origin(origin)?;
1475			Self::do_force_set_attribute(set_as, collection, maybe_item, namespace, key, value)
1476		}
1477
1478		/// Clear an attribute for a collection or item.
1479		///
1480		/// Origin must be either `ForceOrigin` or Signed and the sender should be the Owner of the
1481		/// attribute.
1482		///
1483		/// Any deposit is freed for the collection's owner.
1484		///
1485		/// - `collection`: The identifier of the collection whose item's metadata to clear.
1486		/// - `maybe_item`: The identifier of the item whose metadata to clear.
1487		/// - `namespace`: Attribute's namespace.
1488		/// - `key`: The key of the attribute.
1489		///
1490		/// Emits `AttributeCleared`.
1491		///
1492		/// Weight: `O(1)`
1493		#[pallet::call_index(21)]
1494		#[pallet::weight(T::WeightInfo::clear_attribute())]
1495		pub fn clear_attribute(
1496			origin: OriginFor<T>,
1497			collection: T::CollectionId,
1498			maybe_item: Option<T::ItemId>,
1499			namespace: AttributeNamespace<T::AccountId>,
1500			key: BoundedVec<u8, T::KeyLimit>,
1501		) -> DispatchResult {
1502			let maybe_check_owner = T::ForceOrigin::try_origin(origin)
1503				.map(|_| None)
1504				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1505			Self::do_clear_attribute(maybe_check_owner, collection, maybe_item, namespace, key)
1506		}
1507
1508		/// Approve item's attributes to be changed by a delegated third-party account.
1509		///
1510		/// Origin must be Signed and must be an owner of the `item`.
1511		///
1512		/// - `collection`: A collection of the item.
1513		/// - `item`: The item that holds attributes.
1514		/// - `delegate`: The account to delegate permission to change attributes of the item.
1515		///
1516		/// Emits `ItemAttributesApprovalAdded` on success.
1517		#[pallet::call_index(22)]
1518		#[pallet::weight(T::WeightInfo::approve_item_attributes())]
1519		pub fn approve_item_attributes(
1520			origin: OriginFor<T>,
1521			collection: T::CollectionId,
1522			item: T::ItemId,
1523			delegate: AccountIdLookupOf<T>,
1524		) -> DispatchResult {
1525			let origin = ensure_signed(origin)?;
1526			let delegate = T::Lookup::lookup(delegate)?;
1527			Self::do_approve_item_attributes(origin, collection, item, delegate)
1528		}
1529
1530		/// Cancel the previously provided approval to change item's attributes.
1531		/// All the previously set attributes by the `delegate` will be removed.
1532		///
1533		/// Origin must be Signed and must be an owner of the `item`.
1534		///
1535		/// - `collection`: Collection that the item is contained within.
1536		/// - `item`: The item that holds attributes.
1537		/// - `delegate`: The previously approved account to remove.
1538		///
1539		/// Emits `ItemAttributesApprovalRemoved` on success.
1540		#[pallet::call_index(23)]
1541		#[pallet::weight(T::WeightInfo::cancel_item_attributes_approval(
1542			witness.account_attributes
1543		))]
1544		pub fn cancel_item_attributes_approval(
1545			origin: OriginFor<T>,
1546			collection: T::CollectionId,
1547			item: T::ItemId,
1548			delegate: AccountIdLookupOf<T>,
1549			witness: CancelAttributesApprovalWitness,
1550		) -> DispatchResult {
1551			let origin = ensure_signed(origin)?;
1552			let delegate = T::Lookup::lookup(delegate)?;
1553			Self::do_cancel_item_attributes_approval(origin, collection, item, delegate, witness)
1554		}
1555
1556		/// Set the metadata for an item.
1557		///
1558		/// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin of the
1559		/// `collection`.
1560		///
1561		/// If the origin is Signed, then funds of signer are reserved according to the formula:
1562		/// `MetadataDepositBase + DepositPerByte * data.len` taking into
1563		/// account any already reserved funds.
1564		///
1565		/// - `collection`: The identifier of the collection whose item's metadata to set.
1566		/// - `item`: The identifier of the item whose metadata to set.
1567		/// - `data`: The general information of this item. Limited in length by `StringLimit`.
1568		///
1569		/// Emits `ItemMetadataSet`.
1570		///
1571		/// Weight: `O(1)`
1572		#[pallet::call_index(24)]
1573		#[pallet::weight(T::WeightInfo::set_metadata())]
1574		pub fn set_metadata(
1575			origin: OriginFor<T>,
1576			collection: T::CollectionId,
1577			item: T::ItemId,
1578			data: BoundedVec<u8, T::StringLimit>,
1579		) -> DispatchResult {
1580			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1581				.map(|_| None)
1582				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1583			Self::do_set_item_metadata(maybe_check_origin, collection, item, data, None)
1584		}
1585
1586		/// Clear the metadata for an item.
1587		///
1588		/// Origin must be either `ForceOrigin` or Signed and the sender should be the Admin of the
1589		/// `collection`.
1590		///
1591		/// Any deposit is freed for the collection's owner.
1592		///
1593		/// - `collection`: The identifier of the collection whose item's metadata to clear.
1594		/// - `item`: The identifier of the item whose metadata to clear.
1595		///
1596		/// Emits `ItemMetadataCleared`.
1597		///
1598		/// Weight: `O(1)`
1599		#[pallet::call_index(25)]
1600		#[pallet::weight(T::WeightInfo::clear_metadata())]
1601		pub fn clear_metadata(
1602			origin: OriginFor<T>,
1603			collection: T::CollectionId,
1604			item: T::ItemId,
1605		) -> DispatchResult {
1606			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1607				.map(|_| None)
1608				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1609			Self::do_clear_item_metadata(maybe_check_origin, collection, item)
1610		}
1611
1612		/// Set the metadata for a collection.
1613		///
1614		/// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Admin of
1615		/// the `collection`.
1616		///
1617		/// If the origin is `Signed`, then funds of signer are reserved according to the formula:
1618		/// `MetadataDepositBase + DepositPerByte * data.len` taking into
1619		/// account any already reserved funds.
1620		///
1621		/// - `collection`: The identifier of the item whose metadata to update.
1622		/// - `data`: The general information of this item. Limited in length by `StringLimit`.
1623		///
1624		/// Emits `CollectionMetadataSet`.
1625		///
1626		/// Weight: `O(1)`
1627		#[pallet::call_index(26)]
1628		#[pallet::weight(T::WeightInfo::set_collection_metadata())]
1629		pub fn set_collection_metadata(
1630			origin: OriginFor<T>,
1631			collection: T::CollectionId,
1632			data: BoundedVec<u8, T::StringLimit>,
1633		) -> DispatchResult {
1634			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1635				.map(|_| None)
1636				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1637			Self::do_set_collection_metadata(maybe_check_origin, collection, data)
1638		}
1639
1640		/// Clear the metadata for a collection.
1641		///
1642		/// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Admin of
1643		/// the `collection`.
1644		///
1645		/// Any deposit is freed for the collection's owner.
1646		///
1647		/// - `collection`: The identifier of the collection whose metadata to clear.
1648		///
1649		/// Emits `CollectionMetadataCleared`.
1650		///
1651		/// Weight: `O(1)`
1652		#[pallet::call_index(27)]
1653		#[pallet::weight(T::WeightInfo::clear_collection_metadata())]
1654		pub fn clear_collection_metadata(
1655			origin: OriginFor<T>,
1656			collection: T::CollectionId,
1657		) -> DispatchResult {
1658			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1659				.map(|_| None)
1660				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1661			Self::do_clear_collection_metadata(maybe_check_origin, collection)
1662		}
1663
1664		/// Set (or reset) the acceptance of ownership for a particular account.
1665		///
1666		/// Origin must be `Signed` and if `maybe_collection` is `Some`, then the signer must have a
1667		/// provider reference.
1668		///
1669		/// - `maybe_collection`: The identifier of the collection whose ownership the signer is
1670		///   willing to accept, or if `None`, an indication that the signer is willing to accept no
1671		///   ownership transferal.
1672		///
1673		/// Emits `OwnershipAcceptanceChanged`.
1674		#[pallet::call_index(28)]
1675		#[pallet::weight(T::WeightInfo::set_accept_ownership())]
1676		pub fn set_accept_ownership(
1677			origin: OriginFor<T>,
1678			maybe_collection: Option<T::CollectionId>,
1679		) -> DispatchResult {
1680			let who = ensure_signed(origin)?;
1681			Self::do_set_accept_ownership(who, maybe_collection)
1682		}
1683
1684		/// Set the maximum number of items a collection could have.
1685		///
1686		/// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Owner of
1687		/// the `collection`.
1688		///
1689		/// - `collection`: The identifier of the collection to change.
1690		/// - `max_supply`: The maximum number of items a collection could have.
1691		///
1692		/// Emits `CollectionMaxSupplySet` event when successful.
1693		#[pallet::call_index(29)]
1694		#[pallet::weight(T::WeightInfo::set_collection_max_supply())]
1695		pub fn set_collection_max_supply(
1696			origin: OriginFor<T>,
1697			collection: T::CollectionId,
1698			max_supply: u32,
1699		) -> DispatchResult {
1700			let maybe_check_owner = T::ForceOrigin::try_origin(origin)
1701				.map(|_| None)
1702				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1703			Self::do_set_collection_max_supply(maybe_check_owner, collection, max_supply)
1704		}
1705
1706		/// Update mint settings.
1707		///
1708		/// Origin must be either `ForceOrigin` or `Signed` and the sender should be the Issuer
1709		/// of the `collection`.
1710		///
1711		/// - `collection`: The identifier of the collection to change.
1712		/// - `mint_settings`: The new mint settings.
1713		///
1714		/// Emits `CollectionMintSettingsUpdated` event when successful.
1715		#[pallet::call_index(30)]
1716		#[pallet::weight(T::WeightInfo::update_mint_settings())]
1717		pub fn update_mint_settings(
1718			origin: OriginFor<T>,
1719			collection: T::CollectionId,
1720			mint_settings: MintSettings<BalanceOf<T, I>, BlockNumberFor<T, I>, T::CollectionId>,
1721		) -> DispatchResult {
1722			let maybe_check_origin = T::ForceOrigin::try_origin(origin)
1723				.map(|_| None)
1724				.or_else(|origin| ensure_signed(origin).map(Some).map_err(DispatchError::from))?;
1725			Self::do_update_mint_settings(maybe_check_origin, collection, mint_settings)
1726		}
1727
1728		/// Set (or reset) the price for an item.
1729		///
1730		/// Origin must be Signed and must be the owner of the `item`.
1731		///
1732		/// - `collection`: The collection of the item.
1733		/// - `item`: The item to set the price for.
1734		/// - `price`: The price for the item. Pass `None`, to reset the price.
1735		/// - `buyer`: Restricts the buy operation to a specific account.
1736		///
1737		/// Emits `ItemPriceSet` on success if the price is not `None`.
1738		/// Emits `ItemPriceRemoved` on success if the price is `None`.
1739		#[pallet::call_index(31)]
1740		#[pallet::weight(T::WeightInfo::set_price())]
1741		pub fn set_price(
1742			origin: OriginFor<T>,
1743			collection: T::CollectionId,
1744			item: T::ItemId,
1745			price: Option<ItemPrice<T, I>>,
1746			whitelisted_buyer: Option<AccountIdLookupOf<T>>,
1747		) -> DispatchResult {
1748			let origin = ensure_signed(origin)?;
1749			let whitelisted_buyer = whitelisted_buyer.map(T::Lookup::lookup).transpose()?;
1750			Self::do_set_price(collection, item, origin, price, whitelisted_buyer)
1751		}
1752
1753		/// Allows to buy an item if it's up for sale.
1754		///
1755		/// Origin must be Signed and must not be the owner of the `item`.
1756		///
1757		/// - `collection`: The collection of the item.
1758		/// - `item`: The item the sender wants to buy.
1759		/// - `bid_price`: The price the sender is willing to pay.
1760		///
1761		/// Emits `ItemBought` on success.
1762		#[pallet::call_index(32)]
1763		#[pallet::weight(T::WeightInfo::buy_item())]
1764		pub fn buy_item(
1765			origin: OriginFor<T>,
1766			collection: T::CollectionId,
1767			item: T::ItemId,
1768			bid_price: ItemPrice<T, I>,
1769		) -> DispatchResult {
1770			let origin = ensure_signed(origin)?;
1771			Self::do_buy_item(collection, item, origin, bid_price)
1772		}
1773
1774		/// Allows to pay the tips.
1775		///
1776		/// Origin must be Signed.
1777		///
1778		/// - `tips`: Tips array.
1779		///
1780		/// Emits `TipSent` on every tip transfer.
1781		#[pallet::call_index(33)]
1782		#[pallet::weight(T::WeightInfo::pay_tips(tips.len() as u32))]
1783		pub fn pay_tips(
1784			origin: OriginFor<T>,
1785			tips: BoundedVec<ItemTipOf<T, I>, T::MaxTips>,
1786		) -> DispatchResult {
1787			let origin = ensure_signed(origin)?;
1788			Self::do_pay_tips(origin, tips)
1789		}
1790
1791		/// Register a new atomic swap, declaring an intention to send an `item` in exchange for
1792		/// `desired_item` from origin to target on the current blockchain.
1793		/// The target can execute the swap during the specified `duration` of blocks (if set).
1794		/// Additionally, the price could be set for the desired `item`.
1795		///
1796		/// Origin must be Signed and must be an owner of the `item`.
1797		///
1798		/// - `collection`: The collection of the item.
1799		/// - `item`: The item an owner wants to give.
1800		/// - `desired_collection`: The collection of the desired item.
1801		/// - `desired_item`: The desired item an owner wants to receive.
1802		/// - `maybe_price`: The price an owner is willing to pay or receive for the desired `item`.
1803		/// - `duration`: A deadline for the swap. Specified by providing the number of blocks
1804		/// 	after which the swap will expire.
1805		///
1806		/// Emits `SwapCreated` on success.
1807		#[pallet::call_index(34)]
1808		#[pallet::weight(T::WeightInfo::create_swap())]
1809		pub fn create_swap(
1810			origin: OriginFor<T>,
1811			offered_collection: T::CollectionId,
1812			offered_item: T::ItemId,
1813			desired_collection: T::CollectionId,
1814			maybe_desired_item: Option<T::ItemId>,
1815			maybe_price: Option<PriceWithDirection<ItemPrice<T, I>>>,
1816			duration: BlockNumberFor<T, I>,
1817		) -> DispatchResult {
1818			let origin = ensure_signed(origin)?;
1819			Self::do_create_swap(
1820				origin,
1821				offered_collection,
1822				offered_item,
1823				desired_collection,
1824				maybe_desired_item,
1825				maybe_price,
1826				duration,
1827			)
1828		}
1829
1830		/// Cancel an atomic swap.
1831		///
1832		/// Origin must be Signed.
1833		/// Origin must be an owner of the `item` if the deadline hasn't expired.
1834		///
1835		/// - `collection`: The collection of the item.
1836		/// - `item`: The item an owner wants to give.
1837		///
1838		/// Emits `SwapCancelled` on success.
1839		#[pallet::call_index(35)]
1840		#[pallet::weight(T::WeightInfo::cancel_swap())]
1841		pub fn cancel_swap(
1842			origin: OriginFor<T>,
1843			offered_collection: T::CollectionId,
1844			offered_item: T::ItemId,
1845		) -> DispatchResult {
1846			let origin = ensure_signed(origin)?;
1847			Self::do_cancel_swap(origin, offered_collection, offered_item)
1848		}
1849
1850		/// Claim an atomic swap.
1851		/// This method executes a pending swap, that was created by a counterpart before.
1852		///
1853		/// Origin must be Signed and must be an owner of the `item`.
1854		///
1855		/// - `send_collection`: The collection of the item to be sent.
1856		/// - `send_item`: The item to be sent.
1857		/// - `receive_collection`: The collection of the item to be received.
1858		/// - `receive_item`: The item to be received.
1859		/// - `witness_price`: A price that was previously agreed on.
1860		///
1861		/// Emits `SwapClaimed` on success.
1862		#[pallet::call_index(36)]
1863		#[pallet::weight(T::WeightInfo::claim_swap())]
1864		pub fn claim_swap(
1865			origin: OriginFor<T>,
1866			send_collection: T::CollectionId,
1867			send_item: T::ItemId,
1868			receive_collection: T::CollectionId,
1869			receive_item: T::ItemId,
1870			witness_price: Option<PriceWithDirection<ItemPrice<T, I>>>,
1871		) -> DispatchResult {
1872			let origin = ensure_signed(origin)?;
1873			Self::do_claim_swap(
1874				origin,
1875				send_collection,
1876				send_item,
1877				receive_collection,
1878				receive_item,
1879				witness_price,
1880			)
1881		}
1882
1883		/// Mint an item by providing the pre-signed approval.
1884		///
1885		/// Origin must be Signed.
1886		///
1887		/// - `mint_data`: The pre-signed approval that consists of the information about the item,
1888		///   its metadata, attributes, who can mint it (`None` for anyone) and until what block
1889		///   number.
1890		/// - `signature`: The signature of the `data` object.
1891		/// - `signer`: The `data` object's signer. Should be an Issuer of the collection.
1892		///
1893		/// Emits `Issued` on success.
1894		/// Emits `AttributeSet` if the attributes were provided.
1895		/// Emits `ItemMetadataSet` if the metadata was not empty.
1896		#[pallet::call_index(37)]
1897		#[pallet::weight(T::WeightInfo::mint_pre_signed(mint_data.attributes.len() as u32))]
1898		pub fn mint_pre_signed(
1899			origin: OriginFor<T>,
1900			mint_data: Box<PreSignedMintOf<T, I>>,
1901			signature: T::OffchainSignature,
1902			signer: T::AccountId,
1903		) -> DispatchResult {
1904			let origin = ensure_signed(origin)?;
1905			Self::validate_signature(&Encode::encode(&mint_data), &signature, &signer)?;
1906			Self::do_mint_pre_signed(origin, *mint_data, signer)
1907		}
1908
1909		/// Set attributes for an item by providing the pre-signed approval.
1910		///
1911		/// Origin must be Signed and must be an owner of the `data.item`.
1912		///
1913		/// - `data`: The pre-signed approval that consists of the information about the item,
1914		///   attributes to update and until what block number.
1915		/// - `signature`: The signature of the `data` object.
1916		/// - `signer`: The `data` object's signer. Should be an Admin of the collection for the
1917		///   `CollectionOwner` namespace.
1918		///
1919		/// Emits `AttributeSet` for each provided attribute.
1920		/// Emits `ItemAttributesApprovalAdded` if the approval wasn't set before.
1921		/// Emits `PreSignedAttributesSet` on success.
1922		#[pallet::call_index(38)]
1923		#[pallet::weight(T::WeightInfo::set_attributes_pre_signed(data.attributes.len() as u32))]
1924		pub fn set_attributes_pre_signed(
1925			origin: OriginFor<T>,
1926			data: PreSignedAttributesOf<T, I>,
1927			signature: T::OffchainSignature,
1928			signer: T::AccountId,
1929		) -> DispatchResult {
1930			let origin = ensure_signed(origin)?;
1931			Self::validate_signature(&Encode::encode(&data), &signature, &signer)?;
1932			Self::do_set_attributes_pre_signed(origin, data, signer)
1933		}
1934	}
1935}
1936
1937sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $);