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

difftreelog

Merge pull request #442 from UniqueNetwork/doc/nonfungible-pallet

Yaroslav Bolyukin2022-07-21parents: #3750ef0 #4bd95ca.patch.diff
in: master

6 files changed

modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -133,6 +133,8 @@
 	}
 }
 
+/// Implementation of `CommonCollectionOperations` for `NonfungibleHandle`. It wraps Nonfungible Pallete
+/// methods and adds weight info.
 impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {
 	fn create_item(
 		&self,
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -14,6 +14,11 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Nonfungible Pallet EVM API
+//!
+//! Provides ERC-721 standart support implementation and EVM API for unique extensions for Nonfungible Pallet.
+//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.
+
 extern crate alloc;
 use core::{
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
@@ -40,8 +45,15 @@
 	SelfWeightOf, weights::WeightInfo, TokenProperties,
 };
 
+/// @title A contract that allows to set and delete token properties and change token property permissions.
 #[solidity_interface(name = "TokenProperties")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Set permissions for token property.
+	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	/// @param key Property key.
+	/// @param is_mutable Permission to mutate property.
+	/// @param collection_admin Permission to mutate property by collection admin if property is mutable.
+	/// @param token_owner Permission to mutate property by token owner if property is mutable.
 	fn set_token_property_permission(
 		&mut self,
 		caller: caller,
@@ -68,6 +80,11 @@
 		.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// @notice Set token property value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @param value Property value.
 	fn set_property(
 		&mut self,
 		caller: caller,
@@ -96,6 +113,10 @@
 		.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// @notice Delete token property value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
 	fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -111,7 +132,11 @@
 			.map_err(dispatch_to_evm::<T>)
 	}
 
-	/// Throws error if key not found
+	/// @notice Get token property value.
+	/// @dev Throws error if key not found
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @return Property value bytes
 	fn property(&self, token_id: uint256, key: string) -> Result<bytes> {
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		let key = <Vec<u8>>::from(key)
@@ -127,6 +152,11 @@
 
 #[derive(ToLog)]
 pub enum ERC721Events {
+	/// @dev This emits when ownership of any NFT changes by any mechanism.
+	///  This event emits when NFTs are created (`from` == 0) and destroyed
+	///  (`to` == 0). Exception: during contract creation, any number of NFTs
+	///  may be created and assigned without emitting Transfer. At the time of
+	///  any transfer, the approved address for that NFT (if any) is reset to none.
 	Transfer {
 		#[indexed]
 		from: address,
@@ -135,6 +165,10 @@
 		#[indexed]
 		token_id: uint256,
 	},
+	/// @dev This emits when the approved address for an NFT is changed or
+	///  reaffirmed. The zero address indicates there is no approved address.
+	///  When a Transfer event emits, this also indicates that the approved
+	///  address for that NFT (if any) is reset to none.
 	Approval {
 		#[indexed]
 		owner: address,
@@ -143,6 +177,8 @@
 		#[indexed]
 		token_id: uint256,
 	},
+	/// @dev This emits when an operator is enabled or disabled for an owner.
+	///  The operator can manage all NFTs of the owner.
 	#[allow(dead_code)]
 	ApprovalForAll {
 		#[indexed]
@@ -159,19 +195,27 @@
 	MintingFinished {},
 }
 
+/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
 #[solidity_interface(name = "ERC721Metadata")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice A descriptive name for a collection of NFTs in this contract
 	fn name(&self) -> Result<string> {
 		Ok(decode_utf16(self.name.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
 			.collect::<string>())
 	}
 
+	/// @notice An abbreviated name for NFTs in this contract
 	fn symbol(&self) -> Result<string> {
 		Ok(string::from_utf8_lossy(&self.token_prefix).into())
 	}
 
-	/// Returns token's const_metadata
+	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	/// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC
+	///  3986. The URI may point to a JSON file that conforms to the "ERC721
+	///  Metadata JSON Schema".
+	/// @return token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
 	fn token_uri(&self, token_id: uint256) -> Result<string> {
 		let key = token_uri_key();
@@ -192,32 +236,53 @@
 	}
 }
 
+/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
 #[solidity_interface(name = "ERC721Enumerable")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Enumerate valid NFTs
+	/// @param index A counter less than `totalSupply()`
+	/// @return The token identifier for the `index`th NFT,
+	///  (sort order not specified)
 	fn token_by_index(&self, index: uint256) -> Result<uint256> {
 		Ok(index)
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
+	/// @notice Count NFTs tracked by this contract
+	/// @return A count of valid NFTs tracked by this contract, where each one of
+	///  them has an assigned and queryable owner not equal to the zero address
 	fn total_supply(&self) -> Result<uint256> {
 		self.consume_store_reads(1)?;
 		Ok(<Pallet<T>>::total_supply(self).into())
 	}
 }
 
+/// @title ERC-721 Non-Fungible Token Standard
+/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 #[solidity_interface(name = "ERC721", events(ERC721Events))]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Count all NFTs assigned to an owner
+	/// @dev NFTs assigned to the zero address are considered invalid, and this
+	///  function throws for queries about the zero address.
+	/// @param owner An address for whom to query the balance
+	/// @return The number of NFTs owned by `owner`, possibly zero
 	fn balance_of(&self, owner: address) -> Result<uint256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <AccountBalance<T>>::get((self.id, owner));
 		Ok(balance.into())
 	}
+	/// @notice Find the owner of an NFT
+	/// @dev NFTs assigned to zero address are considered invalid, and queries
+	///  about them do throw.
+	/// @param tokenId The identifier for an NFT
+	/// @return The address of the owner of the NFT
 	fn owner_of(&self, token_id: uint256) -> Result<address> {
 		self.consume_store_reads(1)?;
 		let token: TokenId = token_id.try_into()?;
@@ -226,7 +291,7 @@
 			.owner
 			.as_eth())
 	}
-	/// Not implemented
+	/// @dev Not implemented
 	fn safe_transfer_from_with_data(
 		&mut self,
 		_from: address,
@@ -238,7 +303,7 @@
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
-	/// Not implemented
+	/// @dev Not implemented
 	fn safe_transfer_from(
 		&mut self,
 		_from: address,
@@ -250,6 +315,16 @@
 		Err("not implemented".into())
 	}
 
+	/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	///  THEY MAY BE PERMANENTLY LOST
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from The current owner of the NFT
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @param _value Not used for an NFT
 	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
@@ -272,6 +347,12 @@
 		Ok(())
 	}
 
+	/// @notice Set or reaffirm the approved address for an NFT
+	/// @dev The zero address indicates there is no approved address.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param approved The new approved NFT controller
+	/// @param tokenId The NFT to approve
 	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve(
 		&mut self,
@@ -289,7 +370,7 @@
 		Ok(())
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn set_approval_for_all(
 		&mut self,
 		_caller: caller,
@@ -300,21 +381,26 @@
 		Err("not implemented".into())
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn get_approved(&self, _token_id: uint256) -> Result<address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 }
 
+/// @title ERC721 Token that can be irreversibly burned (destroyed).
 #[solidity_interface(name = "ERC721Burnable")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param tokenId The NFT to approve
 	#[weight(<SelfWeightOf<T>>::burn_item())]
 	fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -325,14 +411,18 @@
 	}
 }
 
+/// @title ERC721 minting logic.
 #[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]
 impl<T: Config> NonfungibleHandle<T> {
 	fn minting_finished(&self) -> Result<bool> {
 		Ok(false)
 	}
 
-	/// `token_id` should be obtained with `next_token_id` method,
-	/// unlike standard, you can't specify it manually
+	/// @notice Function to mint token.
+	/// @dev `tokenId` should be obtained with `nextTokenId` method,
+	///  unlike standard, you can't specify it manually
+	/// @param to The new owner
+	/// @param tokenId ID of the minted NFT
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -364,8 +454,12 @@
 		Ok(true)
 	}
 
-	/// `token_id` should be obtained with `next_token_id` method,
-	/// unlike standard, you can't specify it manually
+	/// @notice Function to mint token with the given tokenUri.
+	/// @dev `tokenId` should be obtained with `nextTokenId` method,
+	///  unlike standard, you can't specify it manually
+	/// @param to The new owner
+	/// @param tokenId ID of the minted NFT
+	/// @param tokenUri Token URI that would be stored in the NFT properties
 	#[solidity(rename_selector = "mintWithTokenURI")]
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri(
@@ -420,7 +514,7 @@
 		Ok(true)
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn finish_minting(&mut self, _caller: caller) -> Result<bool> {
 		Err("not implementable".into())
 	}
@@ -449,8 +543,15 @@
 	false
 }
 
+/// @title Unique extensions for ERC721.
 #[solidity_interface(name = "ERC721UniqueExtensions")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Transfer ownership of an NFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @param _value Not used for an NFT
 	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer(
 		&mut self,
@@ -470,6 +571,13 @@
 		Ok(())
 	}
 
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from The current owner of the NFT
+	/// @param tokenId The NFT to transfer
+	/// @param _value Not used for an NFT
 	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from(
 		&mut self,
@@ -490,6 +598,7 @@
 		Ok(())
 	}
 
+	/// @notice Returns next free NFT ID.
 	fn next_token_id(&self) -> Result<uint256> {
 		self.consume_store_reads(1)?;
 		Ok(<TokensMinted<T>>::get(self.id)
@@ -498,6 +607,11 @@
 			.into())
 	}
 
+	/// @notice Function to mint multiple tokens.
+	/// @dev `tokenIds` should be an array of consecutive numbers and first number
+	///  should be obtained with `nextTokenId` method
+	/// @param to The new owner
+	/// @param tokenIds IDs of the minted NFTs
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
 	fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -529,6 +643,11 @@
 		Ok(true)
 	}
 
+	/// @notice Function to mint multiple tokens with the given tokenUris.
+	/// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	///  numbers and first number should be obtained with `nextTokenId` method
+	/// @param to The new owner
+	/// @param tokens array of pairs of token ID and token URI for minted tokens
 	#[solidity(rename_selector = "mintBulkWithTokenURI")]
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]
 	fn mint_bulk_with_token_uri(
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -14,6 +14,80 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Nonfungible Pallet
+//!
+//! The Nonfungible pallet provides functionality for handling nonfungible collections and tokens.
+//!
+//! - [`Config`]
+//! - [`NonfungibleHandle`]
+//! - [`Pallet`]
+//! - [`CommonWeights`]
+//!
+//! ## Overview
+//!
+//! The Nonfungible pallet provides functions for:
+//!
+//! - NFT collection creation and removal
+//! - Minting and burning of NFT tokens
+//! - Retrieving account balances
+//! - Transfering NFT tokens
+//! - Setting and checking allowance for NFT tokens
+//! - Setting properties and permissions for NFT collections and tokens
+//! - Nesting and unnesting tokens
+//!
+//! ### Terminology
+//!
+//! - **NFT token:** Non fungible token.
+//!
+//! - **NFT Collection:** A collection of NFT tokens. All NFT tokens are part of a collection.
+//!   Each collection can define it's own properties, properties for it's tokens and set of permissions.
+//!
+//! - **Balance:** Number of NFT tokens owned by an account
+//!
+//! - **Allowance:** NFT tokens owned by one account that another account is allowed to make operations on
+//!
+//! - **Burning:** The process of “deleting” a token from a collection and from
+//!   an account balance of the owner.
+//!
+//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting
+//!   owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in
+//!   it's child token i.e. parent-child relationship graph shouldn't have cycles.
+//!
+//! - **Properties:** Key-Values pairs. Token properties are attached to a token. Collection properties are
+//!   attached to a collection. Set of permissions could be defined for each property.
+//!
+//! ### Implementations
+//!
+//! The Nonfungible pallet provides implementations for the following traits. If these traits provide
+//! the functionality that you need, then you can avoid coupling with the Nonfungible pallet.
+//!
+//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight
+//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing
+//!   with collections
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Functions
+//!
+//! - `init_collection` - Create NFT collection. NFT collection can be configured to allow or deny access for
+//!   some accounts.
+//! - `destroy_collection` - Destroy exising NFT collection. There should be no tokens in the collection.
+//! - `burn` - Burn NFT token owned by account.
+//! - `transfer` - Transfer NFT token. Transfers should be enabled for NFT collection.
+//!   Nests the NFT token if it is sent to another token.
+//! - `create_item` - Mint NFT token in collection. Sender should have permission to mint tokens.
+//! - `set_allowance` - Set allowance for another account.
+//! - `set_token_property` - Set token property value.
+//! - `delete_token_property` - Remove property from the token.
+//! - `set_collection_properties` - Set collection properties.
+//! - `delete_collection_properties` - Remove properties from the collection.
+//! - `set_property_permission` - Set collection property permission.
+//! - `set_token_property_permissions` - Set token property permissions.
+//!
+//! ## Assumptions
+//!
+//! * To perform operations on tokens sender should be in collection's allow list if collection access mode is `AllowList`.
+
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use erc::ERC721Events;
@@ -102,13 +176,17 @@
 	#[pallet::generate_store(pub(super) trait Store)]
 	pub struct Pallet<T>(_);
 
+	/// Amount of tokens minted for collection.
 	#[pallet::storage]
 	pub type TokensMinted<T: Config> =
 		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
+
+	/// Amount of burnt tokens for collection.
 	#[pallet::storage]
 	pub type TokensBurnt<T: Config> =
 		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
 
+	/// Custom data serialized to bytes for token.
 	#[pallet::storage]
 	pub type TokenData<T: Config> = StorageNMap<
 		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -116,6 +194,7 @@
 		QueryKind = OptionQuery,
 	>;
 
+	/// Key-Value map stored for token.
 	#[pallet::storage]
 	#[pallet::getter(fn token_properties)]
 	pub type TokenProperties<T: Config> = StorageNMap<
@@ -125,6 +204,8 @@
 		OnEmpty = up_data_structs::TokenProperties,
 	>;
 
+	/// Custom data that is serialized to bytes and attached to a token property.
+	/// Currently used to store RMRK data.
 	#[pallet::storage]
 	#[pallet::getter(fn token_aux_property)]
 	pub type TokenAuxProperties<T: Config> = StorageNMap<
@@ -138,7 +219,7 @@
 		QueryKind = OptionQuery,
 	>;
 
-	/// Used to enumerate tokens owned by account
+	/// Used to enumerate tokens owned by account.
 	#[pallet::storage]
 	pub type Owned<T: Config> = StorageNMap<
 		Key = (
@@ -150,7 +231,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Used to enumerate token's children
+	/// Used to enumerate token's children.
 	#[pallet::storage]
 	#[pallet::getter(fn token_children)]
 	pub type TokenChildren<T: Config> = StorageNMap<
@@ -163,6 +244,7 @@
 		QueryKind = ValueQuery,
 	>;
 
+	/// Amount of tokens owned by account.
 	#[pallet::storage]
 	pub type AccountBalance<T: Config> = StorageNMap<
 		Key = (
@@ -173,6 +255,7 @@
 		QueryKind = ValueQuery,
 	>;
 
+	/// Allowance set by an owner for a spender for a token.
 	#[pallet::storage]
 	pub type Allowance<T: Config> = StorageNMap<
 		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -273,13 +356,21 @@
 }
 
 impl<T: Config> Pallet<T> {
+	/// Get number of NFT tokens in collection.
 	pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {
 		<TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)
 	}
+
+	/// Check that NFT token exists.
+	///
+	/// - `token`: Token ID.
 	pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {
 		<TokenData<T>>::contains_key((collection.id, token))
 	}
 
+	/// Set the token property with the scope.
+	///
+	/// - `property`: Contains key-value pair.
 	pub fn set_scoped_token_property(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -294,6 +385,7 @@
 		Ok(())
 	}
 
+	/// Batch operation to set multiple properties with the same scope.
 	pub fn set_scoped_token_properties(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -308,6 +400,9 @@
 		Ok(())
 	}
 
+	/// Add or edit auxiliary data for the property.
+	///
+	/// - `f`: function that adds or edits auxiliary data.
 	pub fn try_mutate_token_aux_property<R, E>(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -318,6 +413,7 @@
 		<TokenAuxProperties<T>>::try_mutate((collection_id, token_id, scope, key), f)
 	}
 
+	/// Remove auxiliary data for the property.
 	pub fn remove_token_aux_property(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -327,6 +423,9 @@
 		<TokenAuxProperties<T>>::remove((collection_id, token_id, scope, key));
 	}
 
+	/// Get all auxiliary data in a given scope.
+	///
+	/// Returns iterator over Property Key - Data pairs.
 	pub fn iterate_token_aux_properties(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -335,6 +434,7 @@
 		<TokenAuxProperties<T>>::iter_prefix((collection_id, token_id, scope))
 	}
 
+	/// Get ID of the last minted token
 	pub fn current_token_id(collection_id: CollectionId) -> TokenId {
 		TokenId(<TokensMinted<T>>::get(collection_id))
 	}
@@ -342,6 +442,11 @@
 
 // unchecked calls skips any permission checks
 impl<T: Config> Pallet<T> {
+	/// Create NFT collection
+	///
+	/// `init_collection` will take non-refundable deposit for collection creation.
+	///
+	/// - `data`: Contains settings for collection limits and permissions.
 	pub fn init_collection(
 		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
@@ -349,6 +454,11 @@
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data, is_external)
 	}
+
+	/// Destroy NFT collection
+	///
+	/// `destroy_collection` will throw error if collection contains any tokens.
+	/// Only owner can destroy collection.
 	pub fn destroy_collection(
 		collection: NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -373,6 +483,15 @@
 		Ok(())
 	}
 
+	/// Burn NFT token
+	///
+	/// `burn` removes `token` from the `collection`, from it's owner and from the parent token
+	/// if the token is nested.
+	/// Only the owner can `burn` the token. The `token` shouldn't have any nested tokens.
+	/// Also removes all corresponding properties and auxiliary properties.
+	///
+	/// - `token`: Token that should be burned
+	/// - `collection`: Collection that contains the token
 	pub fn burn(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -442,6 +561,12 @@
 		Ok(())
 	}
 
+	/// Same as [`burn`] but burns all the tokens that are nested in the token first
+	///
+	/// - `self_budget`: Limit for searching children in depth.
+	/// - `breadth_budget`: Limit of breadth of searching children.
+	///
+	/// [`burn`]: struct.Pallet.html#method.burn
 	#[transactional]
 	pub fn burn_recursively(
 		collection: &NonfungibleHandle<T>,
@@ -481,6 +606,14 @@
 		})
 	}
 
+	/// Batch operation to add, edit or remove properties for the token
+	///
+	/// All affected properties should have mutable permission and sender should have
+	/// permission to edit those properties.
+	///
+	/// - `nesting_budget`: Limit for searching parents in depth to check ownership.
+	/// - `is_token_create`: Indicates that method is called during token initialization.
+	///   Allows to bypass ownership check.
 	#[transactional]
 	fn modify_token_properties(
 		collection: &NonfungibleHandle<T>,
@@ -574,6 +707,11 @@
 		Ok(())
 	}
 
+	/// Batch operation to add or edit properties for the token
+	///
+	/// Same as [`modify_token_properties`] but doesn't allow to remove properties
+	///
+	/// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties
 	pub fn set_token_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -592,6 +730,11 @@
 		)
 	}
 
+	/// Add or edit single property for the token
+	///
+	/// Calls [`set_token_properties`] internally
+	///
+	/// [`set_token_properties`]: struct.Pallet.html#method.set_token_properties
 	pub fn set_token_property(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -611,6 +754,11 @@
 		)
 	}
 
+	/// Batch operation to remove properties from the token
+	///
+	/// Same as [`modify_token_properties`] but doesn't allow to add or edit properties
+	///
+	/// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties
 	pub fn delete_token_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -630,6 +778,11 @@
 		)
 	}
 
+	/// Remove single property from the token
+	///
+	/// Calls [`delete_token_properties`] internally
+	///
+	/// [`delete_token_properties`]: struct.Pallet.html#method.delete_token_properties
 	pub fn delete_token_property(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -646,6 +799,7 @@
 		)
 	}
 
+	/// Add or edit properties for the collection
 	pub fn set_collection_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -654,6 +808,7 @@
 		<PalletCommon<T>>::set_collection_properties(collection, sender, properties)
 	}
 
+	/// Remove properties from the collection
 	pub fn delete_collection_properties(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -662,6 +817,9 @@
 		<PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)
 	}
 
+	/// Set property permissions for the token.
+	///
+	/// Sender should be the owner or admin of token's collection.
 	pub fn set_token_property_permissions(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -670,6 +828,9 @@
 		<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)
 	}
 
+	/// Set property permissions for the collection.
+	///
+	/// Sender should be the owner or admin of the collection.
 	pub fn set_property_permission(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -678,6 +839,15 @@
 		<PalletCommon<T>>::set_property_permission(collection, sender, permission)
 	}
 
+	/// Transfer NFT token from one account to another.
+	///
+	/// `from` account stops being the owner and `to` account becomes the owner of the token.
+	/// If `to` is token than `to` becomes owner of the token and the token become nested.
+	/// Unnests token from previous parent if it was nested before.
+	/// Removes allowance for the token if there was any.
+	/// Throws if transfers aren't allowed for collection or if receiver reached token ownership limit.
+	///
+	/// - `nesting_budget`: Limit for token nesting depth
 	pub fn transfer(
 		collection: &NonfungibleHandle<T>,
 		from: &T::CrossAccountId,
@@ -769,6 +939,16 @@
 		Ok(())
 	}
 
+	/// Batch operation to mint multiple NFT tokens.
+	///
+	/// The sender should be the owner/admin of the collection or collection should be configured
+	/// to allow public minting.
+	/// Throws if amount of tokens reached it's limit for the collection or if caller reached
+	/// token ownership limit.
+	///
+	/// - `data`: Contains list of token properties and users who will become the owners of the
+	///   corresponging tokens.
+	/// - `nesting_budget`: Limit for token nesting depth
 	pub fn create_multiple_items(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -953,6 +1133,9 @@
 		}
 	}
 
+	/// Set allowance for the spender to `transfer` or `burn` sender's token.
+	///
+	/// - `token`: Token the spender is allowed to `transfer` or `burn`.
 	pub fn set_allowance(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -985,6 +1168,7 @@
 		Ok(())
 	}
 
+	/// Checks allowance for the spender to use the token.
 	fn check_allowed(
 		collection: &NonfungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -1027,6 +1211,12 @@
 		Ok(())
 	}
 
+	/// Transfer NFT token from one account to another.
+	///
+	/// Same as the [`transfer`] but spender doesn't needs to be the owner of the token.
+	/// The owner should set allowance for the spender to transfer token.
+	///
+	/// [`transfer`]: struct.Pallet.html#method.transfer
 	pub fn transfer_from(
 		collection: &NonfungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -1043,6 +1233,12 @@
 		Self::transfer(collection, from, to, token, nesting_budget)
 	}
 
+	/// Burn NFT token for `from` account.
+	///
+	/// Same as the [`burn`] but spender doesn't need to be an owner of the token. The owner should
+	/// set allowance for the spender to burn token.
+	///
+	/// [`burn`]: struct.Pallet.html#method.burn
 	pub fn burn_from(
 		collection: &NonfungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -1057,6 +1253,8 @@
 		Self::burn(collection, from, token)
 	}
 
+	/// Check that `from` token could be nested in `under` token.
+	///
 	pub fn check_nesting(
 		handle: &NonfungibleHandle<T>,
 		sender: T::CrossAccountId,
@@ -1126,7 +1324,11 @@
 			.collect()
 	}
 
-	/// Delegated to `create_multiple_items`
+	/// Mint single NFT token.
+	///
+	/// Delegated to [`create_multiple_items`]
+	///
+	/// [`create_multiple_items`]: struct.Pallet.html#method.create_multiple_items
 	pub fn create_item(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
before · pallets/nonfungible/src/stubs/UniqueNFT.sol
1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8	uint256 field_0;9	string field_1;10}1112// Common stubs holder13contract Dummy {14	uint8 dummy;15	string stub_error = "this contract is implemented in native";16}1718contract ERC165 is Dummy {19	function supportsInterface(bytes4 interfaceID)20		external21		view22		returns (bool)23	{24		require(false, stub_error);25		interfaceID;26		return true;27	}28}2930// Inline31contract ERC721Events {32	event Transfer(33		address indexed from,34		address indexed to,35		uint256 indexed tokenId36	);37	event Approval(38		address indexed owner,39		address indexed approved,40		uint256 indexed tokenId41	);42	event ApprovalForAll(43		address indexed owner,44		address indexed operator,45		bool approved46	);47}4849// Inline50contract ERC721MintableEvents {51	event MintingFinished();52}5354// Selector: 4136937755contract TokenProperties is Dummy, ERC165 {56	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa57	function setTokenPropertyPermission(58		string memory key,59		bool isMutable,60		bool collectionAdmin,61		bool tokenOwner62	) public {63		require(false, stub_error);64		key;65		isMutable;66		collectionAdmin;67		tokenOwner;68		dummy = 0;69	}7071	// Selector: setProperty(uint256,string,bytes) 1752d67b72	function setProperty(73		uint256 tokenId,74		string memory key,75		bytes memory value76	) public {77		require(false, stub_error);78		tokenId;79		key;80		value;81		dummy = 0;82	}8384	// Selector: deleteProperty(uint256,string) 066111d185	function deleteProperty(uint256 tokenId, string memory key) public {86		require(false, stub_error);87		tokenId;88		key;89		dummy = 0;90	}9192	// Throws error if key not found93	//94	// Selector: property(uint256,string) 7228c32795	function property(uint256 tokenId, string memory key)96		public97		view98		returns (bytes memory)99	{100		require(false, stub_error);101		tokenId;102		key;103		dummy;104		return hex"";105	}106}107108// Selector: 42966c68109contract ERC721Burnable is Dummy, ERC165 {110	// Selector: burn(uint256) 42966c68111	function burn(uint256 tokenId) public {112		require(false, stub_error);113		tokenId;114		dummy = 0;115	}116}117118// Selector: 58800161119contract ERC721 is Dummy, ERC165, ERC721Events {120	// Selector: balanceOf(address) 70a08231121	function balanceOf(address owner) public view returns (uint256) {122		require(false, stub_error);123		owner;124		dummy;125		return 0;126	}127128	// Selector: ownerOf(uint256) 6352211e129	function ownerOf(uint256 tokenId) public view returns (address) {130		require(false, stub_error);131		tokenId;132		dummy;133		return 0x0000000000000000000000000000000000000000;134	}135136	// Not implemented137	//138	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672139	function safeTransferFromWithData(140		address from,141		address to,142		uint256 tokenId,143		bytes memory data144	) public {145		require(false, stub_error);146		from;147		to;148		tokenId;149		data;150		dummy = 0;151	}152153	// Not implemented154	//155	// Selector: safeTransferFrom(address,address,uint256) 42842e0e156	function safeTransferFrom(157		address from,158		address to,159		uint256 tokenId160	) public {161		require(false, stub_error);162		from;163		to;164		tokenId;165		dummy = 0;166	}167168	// Selector: transferFrom(address,address,uint256) 23b872dd169	function transferFrom(170		address from,171		address to,172		uint256 tokenId173	) public {174		require(false, stub_error);175		from;176		to;177		tokenId;178		dummy = 0;179	}180181	// Selector: approve(address,uint256) 095ea7b3182	function approve(address approved, uint256 tokenId) public {183		require(false, stub_error);184		approved;185		tokenId;186		dummy = 0;187	}188189	// Not implemented190	//191	// Selector: setApprovalForAll(address,bool) a22cb465192	function setApprovalForAll(address operator, bool approved) public {193		require(false, stub_error);194		operator;195		approved;196		dummy = 0;197	}198199	// Not implemented200	//201	// Selector: getApproved(uint256) 081812fc202	function getApproved(uint256 tokenId) public view returns (address) {203		require(false, stub_error);204		tokenId;205		dummy;206		return 0x0000000000000000000000000000000000000000;207	}208209	// Not implemented210	//211	// Selector: isApprovedForAll(address,address) e985e9c5212	function isApprovedForAll(address owner, address operator)213		public214		view215		returns (address)216	{217		require(false, stub_error);218		owner;219		operator;220		dummy;221		return 0x0000000000000000000000000000000000000000;222	}223}224225// Selector: 5b5e139f226contract ERC721Metadata is Dummy, ERC165 {227	// Selector: name() 06fdde03228	function name() public view returns (string memory) {229		require(false, stub_error);230		dummy;231		return "";232	}233234	// Selector: symbol() 95d89b41235	function symbol() public view returns (string memory) {236		require(false, stub_error);237		dummy;238		return "";239	}240241	// Returns token's const_metadata242	//243	// Selector: tokenURI(uint256) c87b56dd244	function tokenURI(uint256 tokenId) public view returns (string memory) {245		require(false, stub_error);246		tokenId;247		dummy;248		return "";249	}250}251252// Selector: 68ccfe89253contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {254	// Selector: mintingFinished() 05d2035b255	function mintingFinished() public view returns (bool) {256		require(false, stub_error);257		dummy;258		return false;259	}260261	// `token_id` should be obtained with `next_token_id` method,262	// unlike standard, you can't specify it manually263	//264	// Selector: mint(address,uint256) 40c10f19265	function mint(address to, uint256 tokenId) public returns (bool) {266		require(false, stub_error);267		to;268		tokenId;269		dummy = 0;270		return false;271	}272273	// `token_id` should be obtained with `next_token_id` method,274	// unlike standard, you can't specify it manually275	//276	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f277	function mintWithTokenURI(278		address to,279		uint256 tokenId,280		string memory tokenUri281	) public returns (bool) {282		require(false, stub_error);283		to;284		tokenId;285		tokenUri;286		dummy = 0;287		return false;288	}289290	// Not implemented291	//292	// Selector: finishMinting() 7d64bcb4293	function finishMinting() public returns (bool) {294		require(false, stub_error);295		dummy = 0;296		return false;297	}298}299300// Selector: 780e9d63301contract ERC721Enumerable is Dummy, ERC165 {302	// Selector: tokenByIndex(uint256) 4f6ccce7303	function tokenByIndex(uint256 index) public view returns (uint256) {304		require(false, stub_error);305		index;306		dummy;307		return 0;308	}309310	// Not implemented311	//312	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59313	function tokenOfOwnerByIndex(address owner, uint256 index)314		public315		view316		returns (uint256)317	{318		require(false, stub_error);319		owner;320		index;321		dummy;322		return 0;323	}324325	// Selector: totalSupply() 18160ddd326	function totalSupply() public view returns (uint256) {327		require(false, stub_error);328		dummy;329		return 0;330	}331}332333// Selector: 7d9262e6334contract Collection is Dummy, ERC165 {335	// Selector: setCollectionProperty(string,bytes) 2f073f66336	function setCollectionProperty(string memory key, bytes memory value)337		public338	{339		require(false, stub_error);340		key;341		value;342		dummy = 0;343	}344345	// Selector: deleteCollectionProperty(string) 7b7debce346	function deleteCollectionProperty(string memory key) public {347		require(false, stub_error);348		key;349		dummy = 0;350	}351352	// Throws error if key not found353	//354	// Selector: collectionProperty(string) cf24fd6d355	function collectionProperty(string memory key)356		public357		view358		returns (bytes memory)359	{360		require(false, stub_error);361		key;362		dummy;363		return hex"";364	}365366	// Selector: setCollectionSponsor(address) 7623402e367	function setCollectionSponsor(address sponsor) public {368		require(false, stub_error);369		sponsor;370		dummy = 0;371	}372373	// Selector: confirmCollectionSponsorship() 3c50e97a374	function confirmCollectionSponsorship() public {375		require(false, stub_error);376		dummy = 0;377	}378379	// Selector: setCollectionLimit(string,uint32) 6a3841db380	function setCollectionLimit(string memory limit, uint32 value) public {381		require(false, stub_error);382		limit;383		value;384		dummy = 0;385	}386387	// Selector: setCollectionLimit(string,bool) 993b7fba388	function setCollectionLimit(string memory limit, bool value) public {389		require(false, stub_error);390		limit;391		value;392		dummy = 0;393	}394395	// Selector: contractAddress() f6b4dfb4396	function contractAddress() public view returns (address) {397		require(false, stub_error);398		dummy;399		return 0x0000000000000000000000000000000000000000;400	}401402	// Selector: addCollectionAdminSubstrate(uint256) 5730062b403	function addCollectionAdminSubstrate(uint256 newAdmin) public view {404		require(false, stub_error);405		newAdmin;406		dummy;407	}408409	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9410	function removeCollectionAdminSubstrate(uint256 newAdmin) public view {411		require(false, stub_error);412		newAdmin;413		dummy;414	}415416	// Selector: addCollectionAdmin(address) 92e462c7417	function addCollectionAdmin(address newAdmin) public view {418		require(false, stub_error);419		newAdmin;420		dummy;421	}422423	// Selector: removeCollectionAdmin(address) fafd7b42424	function removeCollectionAdmin(address admin) public view {425		require(false, stub_error);426		admin;427		dummy;428	}429430	// Selector: setCollectionNesting(bool) 112d4586431	function setCollectionNesting(bool enable) public {432		require(false, stub_error);433		enable;434		dummy = 0;435	}436437	// Selector: setCollectionNesting(bool,address[]) 64872396438	function setCollectionNesting(bool enable, address[] memory collections)439		public440	{441		require(false, stub_error);442		enable;443		collections;444		dummy = 0;445	}446447	// Selector: setCollectionAccess(uint8) 41835d4c448	function setCollectionAccess(uint8 mode) public {449		require(false, stub_error);450		mode;451		dummy = 0;452	}453454	// Selector: addToCollectionAllowList(address) 67844fe6455	function addToCollectionAllowList(address user) public view {456		require(false, stub_error);457		user;458		dummy;459	}460461	// Selector: removeFromCollectionAllowList(address) 85c51acb462	function removeFromCollectionAllowList(address user) public view {463		require(false, stub_error);464		user;465		dummy;466	}467468	// Selector: setCollectionMintMode(bool) 00018e84469	function setCollectionMintMode(bool mode) public {470		require(false, stub_error);471		mode;472		dummy = 0;473	}474}475476// Selector: d74d154f477contract ERC721UniqueExtensions is Dummy, ERC165 {478	// Selector: transfer(address,uint256) a9059cbb479	function transfer(address to, uint256 tokenId) public {480		require(false, stub_error);481		to;482		tokenId;483		dummy = 0;484	}485486	// Selector: burnFrom(address,uint256) 79cc6790487	function burnFrom(address from, uint256 tokenId) public {488		require(false, stub_error);489		from;490		tokenId;491		dummy = 0;492	}493494	// Selector: nextTokenId() 75794a3c495	function nextTokenId() public view returns (uint256) {496		require(false, stub_error);497		dummy;498		return 0;499	}500501	// Selector: mintBulk(address,uint256[]) 44a9945e502	function mintBulk(address to, uint256[] memory tokenIds)503		public504		returns (bool)505	{506		require(false, stub_error);507		to;508		tokenIds;509		dummy = 0;510		return false;511	}512513	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006514	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)515		public516		returns (bool)517	{518		require(false, stub_error);519		to;520		tokens;521		dummy = 0;522		return false;523	}524}525526contract UniqueNFT is527	Dummy,528	ERC165,529	ERC721,530	ERC721Metadata,531	ERC721Enumerable,532	ERC721UniqueExtensions,533	ERC721Mintable,534	ERC721Burnable,535	Collection,536	TokenProperties537{}
after · pallets/nonfungible/src/stubs/UniqueNFT.sol
1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8	uint256 field_0;9	string field_1;10}1112// Common stubs holder13contract Dummy {14	uint8 dummy;15	string stub_error = "this contract is implemented in native";16}1718contract ERC165 is Dummy {19	function supportsInterface(bytes4 interfaceID)20		external21		view22		returns (bool)23	{24		require(false, stub_error);25		interfaceID;26		return true;27	}28}2930// Inline31contract ERC721Events {32	event Transfer(33		address indexed from,34		address indexed to,35		uint256 indexed tokenId36	);37	event Approval(38		address indexed owner,39		address indexed approved,40		uint256 indexed tokenId41	);42	event ApprovalForAll(43		address indexed owner,44		address indexed operator,45		bool approved46	);47}4849// Inline50contract ERC721MintableEvents {51	event MintingFinished();52}5354// Selector: 4136937755contract TokenProperties is Dummy, ERC165 {56	// @notice Set permissions for token property.57	// @dev Throws error if `msg.sender` is not admin or owner of the collection.58	// @param key Property key.59	// @param is_mutable Permission to mutate property.60	// @param collection_admin Permission to mutate property by collection admin if property is mutable.61	// @param token_owner Permission to mutate property by token owner if property is mutable.62	//63	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa64	function setTokenPropertyPermission(65		string memory key,66		bool isMutable,67		bool collectionAdmin,68		bool tokenOwner69	) public {70		require(false, stub_error);71		key;72		isMutable;73		collectionAdmin;74		tokenOwner;75		dummy = 0;76	}7778	// @notice Set token property value.79	// @dev Throws error if `msg.sender` has no permission to edit the property.80	// @param token_id ID of the token.81	// @param key Property key.82	// @param value Property value.83	//84	// Selector: setProperty(uint256,string,bytes) 1752d67b85	function setProperty(86		uint256 tokenId,87		string memory key,88		bytes memory value89	) public {90		require(false, stub_error);91		tokenId;92		key;93		value;94		dummy = 0;95	}9697	// @notice Delete token property value.98	// @dev Throws error if `msg.sender` has no permission to edit the property.99	// @param token_id ID of the token.100	// @param key Property key.101	//102	// Selector: deleteProperty(uint256,string) 066111d1103	function deleteProperty(uint256 tokenId, string memory key) public {104		require(false, stub_error);105		tokenId;106		key;107		dummy = 0;108	}109110	// @notice Get token property value.111	// @dev Throws error if key not found112	// @param token_id ID of the token.113	// @param key Property key.114	//115	// Selector: property(uint256,string) 7228c327116	function property(uint256 tokenId, string memory key)117		public118		view119		returns (bytes memory)120	{121		require(false, stub_error);122		tokenId;123		key;124		dummy;125		return hex"";126	}127}128129// Selector: 42966c68130contract ERC721Burnable is Dummy, ERC165 {131	// @notice Burns a specific ERC721 token.132	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized133	//  operator of the current owner.134	// @param tokenId The NFT to approve135	//136	// Selector: burn(uint256) 42966c68137	function burn(uint256 tokenId) public {138		require(false, stub_error);139		tokenId;140		dummy = 0;141	}142}143144// Selector: 58800161145contract ERC721 is Dummy, ERC165, ERC721Events {146	// @notice Count all NFTs assigned to an owner147	// @dev NFTs assigned to the zero address are considered invalid, and this148	//  function throws for queries about the zero address.149	// @param _owner An address for whom to query the balance150	// @return The number of NFTs owned by `_owner`, possibly zero151	//152	// Selector: balanceOf(address) 70a08231153	function balanceOf(address owner) public view returns (uint256) {154		require(false, stub_error);155		owner;156		dummy;157		return 0;158	}159160	// @notice Find the owner of an NFT161	// @dev NFTs assigned to zero address are considered invalid, and queries162	//  about them do throw.163	// @param _tokenId The identifier for an NFT164	// @return The address of the owner of the NFT165	//166	// Selector: ownerOf(uint256) 6352211e167	function ownerOf(uint256 tokenId) public view returns (address) {168		require(false, stub_error);169		tokenId;170		dummy;171		return 0x0000000000000000000000000000000000000000;172	}173174	// @dev Not implemented175	//176	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672177	function safeTransferFromWithData(178		address from,179		address to,180		uint256 tokenId,181		bytes memory data182	) public {183		require(false, stub_error);184		from;185		to;186		tokenId;187		data;188		dummy = 0;189	}190191	// @dev Not implemented192	//193	// Selector: safeTransferFrom(address,address,uint256) 42842e0e194	function safeTransferFrom(195		address from,196		address to,197		uint256 tokenId198	) public {199		require(false, stub_error);200		from;201		to;202		tokenId;203		dummy = 0;204	}205206	// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE207	//  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE208	//  THEY MAY BE PERMANENTLY LOST209	// @dev Throws unless `msg.sender` is the current owner or an authorized210	//  operator for this NFT. Throws if `from` is not the current owner. Throws211	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.212	// @param from The current owner of the NFT213	// @param to The new owner214	// @param tokenId The NFT to transfer215	// @param _value Not used for an NFT216	//217	// Selector: transferFrom(address,address,uint256) 23b872dd218	function transferFrom(219		address from,220		address to,221		uint256 tokenId222	) public {223		require(false, stub_error);224		from;225		to;226		tokenId;227		dummy = 0;228	}229230	// @notice Set or reaffirm the approved address for an NFT231	// @dev The zero address indicates there is no approved address.232	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized233	//  operator of the current owner.234	// @param approved The new approved NFT controller235	// @param tokenId The NFT to approve236	//237	// Selector: approve(address,uint256) 095ea7b3238	function approve(address approved, uint256 tokenId) public {239		require(false, stub_error);240		approved;241		tokenId;242		dummy = 0;243	}244245	// @dev Not implemented246	//247	// Selector: setApprovalForAll(address,bool) a22cb465248	function setApprovalForAll(address operator, bool approved) public {249		require(false, stub_error);250		operator;251		approved;252		dummy = 0;253	}254255	// @dev Not implemented256	//257	// Selector: getApproved(uint256) 081812fc258	function getApproved(uint256 tokenId) public view returns (address) {259		require(false, stub_error);260		tokenId;261		dummy;262		return 0x0000000000000000000000000000000000000000;263	}264265	// @dev Not implemented266	//267	// Selector: isApprovedForAll(address,address) e985e9c5268	function isApprovedForAll(address owner, address operator)269		public270		view271		returns (address)272	{273		require(false, stub_error);274		owner;275		operator;276		dummy;277		return 0x0000000000000000000000000000000000000000;278	}279}280281// Selector: 5b5e139f282contract ERC721Metadata is Dummy, ERC165 {283	// @notice A descriptive name for a collection of NFTs in this contract284	//285	// Selector: name() 06fdde03286	function name() public view returns (string memory) {287		require(false, stub_error);288		dummy;289		return "";290	}291292	// @notice An abbreviated name for NFTs in this contract293	//294	// Selector: symbol() 95d89b41295	function symbol() public view returns (string memory) {296		require(false, stub_error);297		dummy;298		return "";299	}300301	// @notice A distinct Uniform Resource Identifier (URI) for a given asset.302	// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC303	//  3986. The URI may point to a JSON file that conforms to the "ERC721304	//  Metadata JSON Schema".305	// @return token's const_metadata306	//307	// Selector: tokenURI(uint256) c87b56dd308	function tokenURI(uint256 tokenId) public view returns (string memory) {309		require(false, stub_error);310		tokenId;311		dummy;312		return "";313	}314}315316// Selector: 68ccfe89317contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {318	// Selector: mintingFinished() 05d2035b319	function mintingFinished() public view returns (bool) {320		require(false, stub_error);321		dummy;322		return false;323	}324325	// @notice Function to mint token.326	// @dev `tokenId` should be obtained with `nextTokenId` method,327	//  unlike standard, you can't specify it manually328	// @param to The new owner329	// @param tokenId ID of the minted NFT330	//331	// Selector: mint(address,uint256) 40c10f19332	function mint(address to, uint256 tokenId) public returns (bool) {333		require(false, stub_error);334		to;335		tokenId;336		dummy = 0;337		return false;338	}339340	// @notice Function to mint token with the given tokenUri.341	// @dev `tokenId` should be obtained with `nextTokenId` method,342	//  unlike standard, you can't specify it manually343	// @param to The new owner344	// @param tokenId ID of the minted NFT345	// @param tokenUri Token URI that would be stored in the NFT properties346	//347	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f348	function mintWithTokenURI(349		address to,350		uint256 tokenId,351		string memory tokenUri352	) public returns (bool) {353		require(false, stub_error);354		to;355		tokenId;356		tokenUri;357		dummy = 0;358		return false;359	}360361	// @dev Not implemented362	//363	// Selector: finishMinting() 7d64bcb4364	function finishMinting() public returns (bool) {365		require(false, stub_error);366		dummy = 0;367		return false;368	}369}370371// Selector: 780e9d63372contract ERC721Enumerable is Dummy, ERC165 {373	// @notice Enumerate valid NFTs374	// @dev Throws if `index` >= `totalSupply()`.375	// @param index A counter less than `totalSupply()`376	// @return The token identifier for the `index`th NFT,377	//  (sort order not specified)378	//379	// Selector: tokenByIndex(uint256) 4f6ccce7380	function tokenByIndex(uint256 index) public view returns (uint256) {381		require(false, stub_error);382		index;383		dummy;384		return 0;385	}386387	// @dev Not implemented388	//389	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59390	function tokenOfOwnerByIndex(address owner, uint256 index)391		public392		view393		returns (uint256)394	{395		require(false, stub_error);396		owner;397		index;398		dummy;399		return 0;400	}401402	// @notice Count NFTs tracked by this contract403	// @return A count of valid NFTs tracked by this contract, where each one of404	//  them has an assigned and queryable owner not equal to the zero address405	//406	// Selector: totalSupply() 18160ddd407	function totalSupply() public view returns (uint256) {408		require(false, stub_error);409		dummy;410		return 0;411	}412}413414// Selector: 7d9262e6415contract Collection is Dummy, ERC165 {416	// Selector: setCollectionProperty(string,bytes) 2f073f66417	function setCollectionProperty(string memory key, bytes memory value)418		public419	{420		require(false, stub_error);421		key;422		value;423		dummy = 0;424	}425426	// Selector: deleteCollectionProperty(string) 7b7debce427	function deleteCollectionProperty(string memory key) public {428		require(false, stub_error);429		key;430		dummy = 0;431	}432433	// Throws error if key not found434	//435	// Selector: collectionProperty(string) cf24fd6d436	function collectionProperty(string memory key)437		public438		view439		returns (bytes memory)440	{441		require(false, stub_error);442		key;443		dummy;444		return hex"";445	}446447	// Selector: setCollectionSponsor(address) 7623402e448	function setCollectionSponsor(address sponsor) public {449		require(false, stub_error);450		sponsor;451		dummy = 0;452	}453454	// Selector: confirmCollectionSponsorship() 3c50e97a455	function confirmCollectionSponsorship() public {456		require(false, stub_error);457		dummy = 0;458	}459460	// Selector: setCollectionLimit(string,uint32) 6a3841db461	function setCollectionLimit(string memory limit, uint32 value) public {462		require(false, stub_error);463		limit;464		value;465		dummy = 0;466	}467468	// Selector: setCollectionLimit(string,bool) 993b7fba469	function setCollectionLimit(string memory limit, bool value) public {470		require(false, stub_error);471		limit;472		value;473		dummy = 0;474	}475476	// Selector: contractAddress() f6b4dfb4477	function contractAddress() public view returns (address) {478		require(false, stub_error);479		dummy;480		return 0x0000000000000000000000000000000000000000;481	}482483	// Selector: addCollectionAdminSubstrate(uint256) 5730062b484	function addCollectionAdminSubstrate(uint256 newAdmin) public view {485		require(false, stub_error);486		newAdmin;487		dummy;488	}489490	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9491	function removeCollectionAdminSubstrate(uint256 newAdmin) public view {492		require(false, stub_error);493		newAdmin;494		dummy;495	}496497	// Selector: addCollectionAdmin(address) 92e462c7498	function addCollectionAdmin(address newAdmin) public view {499		require(false, stub_error);500		newAdmin;501		dummy;502	}503504	// Selector: removeCollectionAdmin(address) fafd7b42505	function removeCollectionAdmin(address admin) public view {506		require(false, stub_error);507		admin;508		dummy;509	}510511	// Selector: setCollectionNesting(bool) 112d4586512	function setCollectionNesting(bool enable) public {513		require(false, stub_error);514		enable;515		dummy = 0;516	}517518	// Selector: setCollectionNesting(bool,address[]) 64872396519	function setCollectionNesting(bool enable, address[] memory collections)520		public521	{522		require(false, stub_error);523		enable;524		collections;525		dummy = 0;526	}527528	// Selector: setCollectionAccess(uint8) 41835d4c529	function setCollectionAccess(uint8 mode) public {530		require(false, stub_error);531		mode;532		dummy = 0;533	}534535	// Selector: addToCollectionAllowList(address) 67844fe6536	function addToCollectionAllowList(address user) public view {537		require(false, stub_error);538		user;539		dummy;540	}541542	// Selector: removeFromCollectionAllowList(address) 85c51acb543	function removeFromCollectionAllowList(address user) public view {544		require(false, stub_error);545		user;546		dummy;547	}548549	// Selector: setCollectionMintMode(bool) 00018e84550	function setCollectionMintMode(bool mode) public {551		require(false, stub_error);552		mode;553		dummy = 0;554	}555}556557// Selector: d74d154f558contract ERC721UniqueExtensions is Dummy, ERC165 {559	// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE560	//  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE561	//  THEY MAY BE PERMANENTLY LOST562	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`563	//  is the zero address. Throws if `tokenId` is not a valid NFT.564	// @param to The new owner565	// @param tokenId The NFT to transfer566	// @param _value Not used for an NFT567	//568	// Selector: transfer(address,uint256) a9059cbb569	function transfer(address to, uint256 tokenId) public {570		require(false, stub_error);571		to;572		tokenId;573		dummy = 0;574	}575576	// @notice Burns a specific ERC721 token.577	// @dev Throws unless `msg.sender` is the current owner or an authorized578	//  operator for this NFT. Throws if `from` is not the current owner. Throws579	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.580	// @param from The current owner of the NFT581	// @param tokenId The NFT to transfer582	// @param _value Not used for an NFT583	//584	// Selector: burnFrom(address,uint256) 79cc6790585	function burnFrom(address from, uint256 tokenId) public {586		require(false, stub_error);587		from;588		tokenId;589		dummy = 0;590	}591592	// @notice Returns next free NFT ID.593	//594	// Selector: nextTokenId() 75794a3c595	function nextTokenId() public view returns (uint256) {596		require(false, stub_error);597		dummy;598		return 0;599	}600601	// @notice Function to mint multiple tokens.602	// @dev `tokenIds` should be an array of consecutive numbers and first number603	//  should be obtained with `nextTokenId` method604	// @param to The new owner605	// @param tokenIds IDs of the minted NFTs606	//607	// Selector: mintBulk(address,uint256[]) 44a9945e608	function mintBulk(address to, uint256[] memory tokenIds)609		public610		returns (bool)611	{612		require(false, stub_error);613		to;614		tokenIds;615		dummy = 0;616		return false;617	}618619	// @notice Function to mint multiple tokens with the given tokenUris.620	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive621	//  numbers and first number should be obtained with `nextTokenId` method622	// @param to The new owner623	// @param tokens array of pairs of token ID and token URI for minted tokens624	//625	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006626	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)627		public628		returns (bool)629	{630		require(false, stub_error);631		to;632		tokens;633		dummy = 0;634		return false;635	}636}637638contract UniqueNFT is639	Dummy,640	ERC165,641	ERC721,642	ERC721Metadata,643	ERC721Enumerable,644	ERC721UniqueExtensions,645	ERC721Mintable,646	ERC721Burnable,647	Collection,648	TokenProperties649{}
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -44,6 +44,13 @@
 
 // Selector: 41369377
 interface TokenProperties is Dummy, ERC165 {
+	// @notice Set permissions for token property.
+	// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	// @param key Property key.
+	// @param is_mutable Permission to mutate property.
+	// @param collection_admin Permission to mutate property by collection admin if property is mutable.
+	// @param token_owner Permission to mutate property by token owner if property is mutable.
+	//
 	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
 	function setTokenPropertyPermission(
 		string memory key,
@@ -52,6 +59,12 @@
 		bool tokenOwner
 	) external;
 
+	// @notice Set token property value.
+	// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// @param token_id ID of the token.
+	// @param key Property key.
+	// @param value Property value.
+	//
 	// Selector: setProperty(uint256,string,bytes) 1752d67b
 	function setProperty(
 		uint256 tokenId,
@@ -59,10 +72,18 @@
 		bytes memory value
 	) external;
 
+	// @notice Delete token property value.
+	// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// @param token_id ID of the token.
+	// @param key Property key.
+	//
 	// Selector: deleteProperty(uint256,string) 066111d1
 	function deleteProperty(uint256 tokenId, string memory key) external;
 
-	// Throws error if key not found
+	// @notice Get token property value.
+	// @dev Throws error if key not found
+	// @param token_id ID of the token.
+	// @param key Property key.
 	//
 	// Selector: property(uint256,string) 7228c327
 	function property(uint256 tokenId, string memory key)
@@ -73,19 +94,36 @@
 
 // Selector: 42966c68
 interface ERC721Burnable is Dummy, ERC165 {
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	//  operator of the current owner.
+	// @param tokenId The NFT to approve
+	//
 	// Selector: burn(uint256) 42966c68
 	function burn(uint256 tokenId) external;
 }
 
 // Selector: 58800161
 interface ERC721 is Dummy, ERC165, ERC721Events {
+	// @notice Count all NFTs assigned to an owner
+	// @dev NFTs assigned to the zero address are considered invalid, and this
+	//  function throws for queries about the zero address.
+	// @param _owner An address for whom to query the balance
+	// @return The number of NFTs owned by `_owner`, possibly zero
+	//
 	// Selector: balanceOf(address) 70a08231
 	function balanceOf(address owner) external view returns (uint256);
 
+	// @notice Find the owner of an NFT
+	// @dev NFTs assigned to zero address are considered invalid, and queries
+	//  about them do throw.
+	// @param _tokenId The identifier for an NFT
+	// @return The address of the owner of the NFT
+	//
 	// Selector: ownerOf(uint256) 6352211e
 	function ownerOf(uint256 tokenId) external view returns (address);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
 	function safeTransferFromWithData(
@@ -95,7 +133,7 @@
 		bytes memory data
 	) external;
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: safeTransferFrom(address,address,uint256) 42842e0e
 	function safeTransferFrom(
@@ -104,6 +142,17 @@
 		uint256 tokenId
 	) external;
 
+	// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	//  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	//  THEY MAY BE PERMANENTLY LOST
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this NFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param from The current owner of the NFT
+	// @param to The new owner
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: transferFrom(address,address,uint256) 23b872dd
 	function transferFrom(
 		address from,
@@ -111,20 +160,27 @@
 		uint256 tokenId
 	) external;
 
+	// @notice Set or reaffirm the approved address for an NFT
+	// @dev The zero address indicates there is no approved address.
+	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	//  operator of the current owner.
+	// @param approved The new approved NFT controller
+	// @param tokenId The NFT to approve
+	//
 	// Selector: approve(address,uint256) 095ea7b3
 	function approve(address approved, uint256 tokenId) external;
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: setApprovalForAll(address,bool) a22cb465
 	function setApprovalForAll(address operator, bool approved) external;
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: getApproved(uint256) 081812fc
 	function getApproved(uint256 tokenId) external view returns (address);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: isApprovedForAll(address,address) e985e9c5
 	function isApprovedForAll(address owner, address operator)
@@ -135,13 +191,21 @@
 
 // Selector: 5b5e139f
 interface ERC721Metadata is Dummy, ERC165 {
+	// @notice A descriptive name for a collection of NFTs in this contract
+	//
 	// Selector: name() 06fdde03
 	function name() external view returns (string memory);
 
+	// @notice An abbreviated name for NFTs in this contract
+	//
 	// Selector: symbol() 95d89b41
 	function symbol() external view returns (string memory);
 
-	// Returns token's const_metadata
+	// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC
+	//  3986. The URI may point to a JSON file that conforms to the "ERC721
+	//  Metadata JSON Schema".
+	// @return token's const_metadata
 	//
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) external view returns (string memory);
@@ -152,14 +216,21 @@
 	// Selector: mintingFinished() 05d2035b
 	function mintingFinished() external view returns (bool);
 
-	// `token_id` should be obtained with `next_token_id` method,
-	// unlike standard, you can't specify it manually
+	// @notice Function to mint token.
+	// @dev `tokenId` should be obtained with `nextTokenId` method,
+	//  unlike standard, you can't specify it manually
+	// @param to The new owner
+	// @param tokenId ID of the minted NFT
 	//
 	// Selector: mint(address,uint256) 40c10f19
 	function mint(address to, uint256 tokenId) external returns (bool);
 
-	// `token_id` should be obtained with `next_token_id` method,
-	// unlike standard, you can't specify it manually
+	// @notice Function to mint token with the given tokenUri.
+	// @dev `tokenId` should be obtained with `nextTokenId` method,
+	//  unlike standard, you can't specify it manually
+	// @param to The new owner
+	// @param tokenId ID of the minted NFT
+	// @param tokenUri Token URI that would be stored in the NFT properties
 	//
 	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
 	function mintWithTokenURI(
@@ -168,7 +239,7 @@
 		string memory tokenUri
 	) external returns (bool);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: finishMinting() 7d64bcb4
 	function finishMinting() external returns (bool);
@@ -176,10 +247,16 @@
 
 // Selector: 780e9d63
 interface ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid NFTs
+	// @dev Throws if `index` >= `totalSupply()`.
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
 	// Selector: tokenByIndex(uint256) 4f6ccce7
 	function tokenByIndex(uint256 index) external view returns (uint256);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
 	function tokenOfOwnerByIndex(address owner, uint256 index)
@@ -187,6 +264,10 @@
 		view
 		returns (uint256);
 
+	// @notice Count NFTs tracked by this contract
+	// @return A count of valid NFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
 	// Selector: totalSupply() 18160ddd
 	function totalSupply() external view returns (uint256);
 }
@@ -257,20 +338,51 @@
 
 // Selector: d74d154f
 interface ERC721UniqueExtensions is Dummy, ERC165 {
+	// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	//  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	//  THEY MAY BE PERMANENTLY LOST
+	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	//  is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param to The new owner
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) external;
 
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this NFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param from The current owner of the NFT
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: burnFrom(address,uint256) 79cc6790
 	function burnFrom(address from, uint256 tokenId) external;
 
+	// @notice Returns next free NFT ID.
+	//
 	// Selector: nextTokenId() 75794a3c
 	function nextTokenId() external view returns (uint256);
 
+	// @notice Function to mint multiple tokens.
+	// @dev `tokenIds` should be an array of consecutive numbers and first number
+	//  should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokenIds IDs of the minted NFTs
+	//
 	// Selector: mintBulk(address,uint256[]) 44a9945e
 	function mintBulk(address to, uint256[] memory tokenIds)
 		external
 		returns (bool);
 
+	// @notice Function to mint multiple tokens with the given tokenUris.
+	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	//  numbers and first number should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokens array of pairs of token ID and token URI for minted tokens
+	//
 	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
 	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
 		external