git.delta.rocks / unique-network / refs/commits / 6cb52a2e4f02

difftreelog

fix after rebase

Trubnikov Sergey2023-02-13parent: #ab7466d.patch.diff
in: master

5 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -86,7 +86,6 @@
 use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
 
-use crate::erc::CollectionHelpersEvents;
 #[cfg(feature = "runtime-benchmarks")]
 pub mod benchmarking;
 pub mod dispatch;
modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -1,751 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-contract Dummy {
-	uint8 dummy;
-	string stub_error = "this contract is implemented in native";
-}
-
-contract ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool) {
-		require(false, stub_error);
-		interfaceID;
-		return true;
-	}
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1
-contract Collection is Dummy, ERC165 {
-	// /// Set collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @param value Propery value.
-	// /// @dev EVM selector for this function is: 0x2f073f66,
-	// ///  or in textual repr: setCollectionProperty(string,bytes)
-	// function setCollectionProperty(string memory key, bytes memory value) public {
-	// 	require(false, stub_error);
-	// 	key;
-	// 	value;
-	// 	dummy = 0;
-	// }
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Property[] memory properties) public {
-		require(false, stub_error);
-		properties;
-		dummy = 0;
-	}
-
-	// /// Delete collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x7b7debce,
-	// ///  or in textual repr: deleteCollectionProperty(string)
-	// function deleteCollectionProperty(string memory key) public {
-	// 	require(false, stub_error);
-	// 	key;
-	// 	dummy = 0;
-	// }
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) public {
-		require(false, stub_error);
-		keys;
-		dummy = 0;
-	}
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) public view returns (bytes memory) {
-		require(false, stub_error);
-		key;
-		dummy;
-		return hex"";
-	}
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) public view returns (Property[] memory) {
-		require(false, stub_error);
-		keys;
-		dummy;
-		return new Property[](0);
-	}
-
-	// /// Set the sponsor of the collection.
-	// ///
-	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	// ///
-	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	// /// @dev EVM selector for this function is: 0x7623402e,
-	// ///  or in textual repr: setCollectionSponsor(address)
-	// function setCollectionSponsor(address sponsor) public {
-	// 	require(false, stub_error);
-	// 	sponsor;
-	// 	dummy = 0;
-	// }
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(CrossAddress memory sponsor) public {
-		require(false, stub_error);
-		sponsor;
-		dummy = 0;
-	}
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() public view returns (bool) {
-		require(false, stub_error);
-		dummy;
-		return false;
-	}
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() public {
-		require(false, stub_error);
-		dummy = 0;
-	}
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() public {
-		require(false, stub_error);
-		dummy = 0;
-	}
-
-	/// Get current sponsor.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	/// @dev EVM selector for this function is: 0x6ec0a9f1,
-	///  or in textual repr: collectionSponsor()
-	function collectionSponsor() public view returns (CrossAddress memory) {
-		require(false, stub_error);
-		dummy;
-		return CrossAddress(0x0000000000000000000000000000000000000000, 0);
-	}
-
-	/// Get current collection limits.
-	///
-	/// @return Array of collection limits
-	/// @dev EVM selector for this function is: 0xf63bc572,
-	///  or in textual repr: collectionLimits()
-	function collectionLimits() public view returns (CollectionLimit[] memory) {
-		require(false, stub_error);
-		dummy;
-		return new CollectionLimit[](0);
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Some limit.
-	/// @dev EVM selector for this function is: 0x2316ee74,
-	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
-	function setCollectionLimit(CollectionLimit memory limit) public {
-		require(false, stub_error);
-		limit;
-		dummy = 0;
-	}
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() public view returns (address) {
-		require(false, stub_error);
-		dummy;
-		return 0x0000000000000000000000000000000000000000;
-	}
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(CrossAddress memory newAdmin) public {
-		require(false, stub_error);
-		newAdmin;
-		dummy = 0;
-	}
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(CrossAddress memory admin) public {
-		require(false, stub_error);
-		admin;
-		dummy = 0;
-	}
-
-	// /// Add collection admin.
-	// /// @param newAdmin Address of the added administrator.
-	// /// @dev EVM selector for this function is: 0x92e462c7,
-	// ///  or in textual repr: addCollectionAdmin(address)
-	// function addCollectionAdmin(address newAdmin) public {
-	// 	require(false, stub_error);
-	// 	newAdmin;
-	// 	dummy = 0;
-	// }
-
-	// /// Remove collection admin.
-	// ///
-	// /// @param admin Address of the removed administrator.
-	// /// @dev EVM selector for this function is: 0xfafd7b42,
-	// ///  or in textual repr: removeCollectionAdmin(address)
-	// function removeCollectionAdmin(address admin) public {
-	// 	require(false, stub_error);
-	// 	admin;
-	// 	dummy = 0;
-	// }
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	/// @dev EVM selector for this function is: 0x112d4586,
-	///  or in textual repr: setCollectionNesting(bool)
-	function setCollectionNesting(bool enable) public {
-		require(false, stub_error);
-		enable;
-		dummy = 0;
-	}
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	/// @param collections Addresses of collections that will be available for nesting.
-	/// @dev EVM selector for this function is: 0x64872396,
-	///  or in textual repr: setCollectionNesting(bool,address[])
-	function setCollectionNesting(bool enable, address[] memory collections) public {
-		require(false, stub_error);
-		enable;
-		collections;
-		dummy = 0;
-	}
-
-	/// Returns nesting for a collection
-	/// @dev EVM selector for this function is: 0x22d25bfe,
-	///  or in textual repr: collectionNestingRestrictedCollectionIds()
-	function collectionNestingRestrictedCollectionIds() public view returns (CollectionNesting memory) {
-		require(false, stub_error);
-		dummy;
-		return CollectionNesting(false, new uint256[](0));
-	}
-
-	/// Returns permissions for a collection
-	/// @dev EVM selector for this function is: 0x5b2eaf4b,
-	///  or in textual repr: collectionNestingPermissions()
-	function collectionNestingPermissions() public view returns (CollectionNestingPermission[] memory) {
-		require(false, stub_error);
-		dummy;
-		return new CollectionNestingPermission[](0);
-	}
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(AccessMode mode) public {
-		require(false, stub_error);
-		mode;
-		dummy = 0;
-	}
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0x91b6df49,
-	///  or in textual repr: allowlistedCross((address,uint256))
-	function allowlistedCross(CrossAddress memory user) public view returns (bool) {
-		require(false, stub_error);
-		user;
-		dummy;
-		return false;
-	}
-
-	// /// Add the user to the allowed list.
-	// ///
-	// /// @param user Address of a trusted user.
-	// /// @dev EVM selector for this function is: 0x67844fe6,
-	// ///  or in textual repr: addToCollectionAllowList(address)
-	// function addToCollectionAllowList(address user) public {
-	// 	require(false, stub_error);
-	// 	user;
-	// 	dummy = 0;
-	// }
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(CrossAddress memory user) public {
-		require(false, stub_error);
-		user;
-		dummy = 0;
-	}
-
-	// /// Remove the user from the allowed list.
-	// ///
-	// /// @param user Address of a removed user.
-	// /// @dev EVM selector for this function is: 0x85c51acb,
-	// ///  or in textual repr: removeFromCollectionAllowList(address)
-	// function removeFromCollectionAllowList(address user) public {
-	// 	require(false, stub_error);
-	// 	user;
-	// 	dummy = 0;
-	// }
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(CrossAddress memory user) public {
-		require(false, stub_error);
-		user;
-		dummy = 0;
-	}
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) public {
-		require(false, stub_error);
-		mode;
-		dummy = 0;
-	}
-
-	// /// Check that account is the owner or admin of the collection
-	// ///
-	// /// @param user account to verify
-	// /// @return "true" if account is the owner or admin
-	// /// @dev EVM selector for this function is: 0x9811b0c7,
-	// ///  or in textual repr: isOwnerOrAdmin(address)
-	// function isOwnerOrAdmin(address user) public view returns (bool) {
-	// 	require(false, stub_error);
-	// 	user;
-	// 	dummy;
-	// 	return false;
-	// }
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(CrossAddress memory user) public view returns (bool) {
-		require(false, stub_error);
-		user;
-		dummy;
-		return false;
-	}
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() public view returns (CrossAddress memory) {
-		require(false, stub_error);
-		dummy;
-		return CrossAddress(0x0000000000000000000000000000000000000000, 0);
-	}
-
-	// /// Changes collection owner to another account
-	// ///
-	// /// @dev Owner can be changed only by current owner
-	// /// @param newOwner new owner account
-	// /// @dev EVM selector for this function is: 0x4f53e226,
-	// ///  or in textual repr: changeCollectionOwner(address)
-	// function changeCollectionOwner(address newOwner) public {
-	// 	require(false, stub_error);
-	// 	newOwner;
-	// 	dummy = 0;
-	// }
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() public view returns (CrossAddress[] memory) {
-		require(false, stub_error);
-		dummy;
-		return new CrossAddress[](0);
-	}
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0x6496c497,
-	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
-	function changeCollectionOwnerCross(CrossAddress memory newOwner) public {
-		require(false, stub_error);
-		newOwner;
-		dummy = 0;
-	}
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
-	/// Access grant for owner and admins. Used as default.
-	Normal,
-	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
-	AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
-	CollectionPermissionField field;
-	bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
-	/// Owner of token can nest tokens under it.
-	TokenOwner,
-	/// Admin of token collection can nest tokens under token.
-	CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
-	bool token_owner;
-	uint256[] ids;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
-	CollectionLimitField field;
-	OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
-	/// Shows the status of accessibility of value
-	bool status;
-	/// Actual value if `status` is true
-	uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
-	/// How many tokens can a user have on one account.
-	AccountTokenOwnership,
-	/// How many bytes of data are available for sponsorship.
-	SponsoredDataSize,
-	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
-	SponsoredDataRateLimit,
-	/// How many tokens can be mined into this collection.
-	TokenLimit,
-	/// Timeouts for transfer sponsoring.
-	SponsorTransferTimeout,
-	/// Timeout for sponsoring an approval in passed blocks.
-	SponsorApproveTimeout,
-	/// Whether the collection owner of the collection can send tokens (which belong to other users).
-	OwnerCanTransfer,
-	/// Can the collection owner burn other people's tokens.
-	OwnerCanDestroy,
-	/// Is it possible to send tokens from this collection between users.
-	TransferEnabled
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
-	string key;
-	bytes value;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x85d7dea6
-contract ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
-	/// @param owner crossAddress The address which owns the funds.
-	/// @param spender crossAddress The address which will spend the funds.
-	/// @return A uint256 specifying the amount of tokens still available for the spender.
-	/// @dev EVM selector for this function is: 0xe0af4bd7,
-	///  or in textual repr: allowanceCross((address,uint256),(address,uint256))
-	function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) public view returns (uint256) {
-		require(false, stub_error);
-		owner;
-		spender;
-		dummy;
-		return 0;
-	}
-
-	/// @notice A description for the collection.
-	/// @dev EVM selector for this function is: 0x7284e416,
-	///  or in textual repr: description()
-	function description() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// @dev EVM selector for this function is: 0x269e6158,
-	///  or in textual repr: mintCross((address,uint256),uint256)
-	function mintCross(CrossAddress memory to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0x0ecd0ab0,
-	///  or in textual repr: approveCross((address,uint256),uint256)
-	function approveCross(CrossAddress memory spender, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		spender;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	// /// Burn tokens from account
-	// /// @dev Function that burns an `amount` of the tokens of a given account,
-	// /// deducting from the sender's allowance for said account.
-	// /// @param from The account whose tokens will be burnt.
-	// /// @param amount The amount that will be burnt.
-	// /// @dev EVM selector for this function is: 0x79cc6790,
-	// ///  or in textual repr: burnFrom(address,uint256)
-	// function burnFrom(address from, uint256 amount) public returns (bool) {
-	// 	require(false, stub_error);
-	// 	from;
-	// 	amount;
-	// 	dummy = 0;
-	// 	return false;
-	// }
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(CrossAddress memory from, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		from;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// Mint tokens for multiple accounts.
-	/// @param amounts array of pairs of account address and amount
-	/// @dev EVM selector for this function is: 0x1acf2d55,
-	///  or in textual repr: mintBulk((address,uint256)[])
-	function mintBulk(AmountForAddress[] memory amounts) public returns (bool) {
-		require(false, stub_error);
-		amounts;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 amount
-	) public returns (bool) {
-		require(false, stub_error);
-		from;
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @notice Returns collection helper contract address
-	/// @dev EVM selector for this function is: 0x1896cce6,
-	///  or in textual repr: collectionHelperAddress()
-	function collectionHelperAddress() public view returns (address) {
-		require(false, stub_error);
-		dummy;
-		return 0x0000000000000000000000000000000000000000;
-	}
-}
-
-struct AmountForAddress {
-	address to;
-	uint256 amount;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x40c10f19
-contract ERC20Mintable is Dummy, ERC165 {
-	/// Mint tokens for `to` account.
-	/// @param to account that will receive minted tokens
-	/// @param amount amount of tokens to mint
-	/// @dev EVM selector for this function is: 0x40c10f19,
-	///  or in textual repr: mint(address,uint256)
-	function mint(address to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-}
-
-/// @dev inlined interface
-contract ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-contract ERC20 is Dummy, ERC165, ERC20Events {
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() public view returns (uint8) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) public view returns (uint256) {
-		require(false, stub_error);
-		owner;
-		dummy;
-		return 0;
-	}
-
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) public returns (bool) {
-		require(false, stub_error);
-		from;
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		spender;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) public view returns (uint256) {
-		require(false, stub_error);
-		owner;
-		spender;
-		dummy;
-		return 0;
-	}
-}
-
-contract UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -623,7 +623,6 @@
 			is_token_owner,
 			|properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
 			erc::ERC721TokenEvent::TokenChanged {
-				collection_id: collection_id_to_address(collection.id),
 				token_id: token_id.into(),
 			}
 			.to_log(T::ContractAddress::get()),
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
before · pallets/refungible/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Refungible Pallet18//!19//! The Refungible pallet provides functionality for handling refungible collections and tokens.20//!21//! - [`Config`]22//! - [`RefungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`](common::CommonWeights)25//!26//! ## Overview27//!28//! The Refungible pallet provides functions for:29//!30//! - RFT collection creation and removal31//! - Minting and burning of RFT tokens32//! - Partition and repartition of RFT tokens33//! - Retrieving number of pieces of RFT token34//! - Retrieving account balances35//! - Transfering RFT token pieces36//! - Burning RFT token pieces37//! - Setting and checking allowance for RFT tokens38//!39//! ### Terminology40//!41//! - **RFT token:** Non fungible token that was partitioned to pieces. If an account owns all42//!   of the RFT token pieces than it owns the RFT token and can repartition it.43//!44//! - **RFT Collection:** A collection of RFT tokens. All RFT tokens are part of a collection.45//!   Each collection has its own settings and set of permissions.46//!47//! - **RFT token piece:** A fungible part of an RFT token.48//!49//! - **Balance:** RFT token pieces owned by an account50//!51//! - **Allowance:** Maximum number of RFT token pieces that one account is allowed to52//!   transfer from the balance of another account53//!54//! - **Burning:** The process of “deleting” a token from a collection or removing token pieces from55//!   an account balance.56//!57//! ### Implementations58//!59//! The Refungible pallet provides implementations for the following traits. If these traits provide60//! the functionality that you need, then you can avoid coupling with the Refungible pallet.61//!62//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight63//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing64//!   with collections65//! - [`RefungibleExtensions`](pallet_common::RefungibleExtensions): Functions specific for refungible66//!   collection67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create RFT collection. RFT collection can be configured to allow or deny access for73//!   some accounts.74//! - `destroy_collection` - Destroy exising RFT collection. There should be no tokens in the collection.75//! - `burn` - Burn some amount of RFT token pieces owned by account. Burns the RFT token if no pieces left.76//! - `transfer` - Transfer some amount of RFT token pieces. Transfers should be enabled for RFT collection.77//!   Nests the RFT token if RFT token pieces are sent to another token.78//! - `create_item` - Mint RFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account to transfer balance from sender's account.80//! - `repartition` - Repartition token to selected number of pieces. Sender should own all existing pieces.81//!82//! ## Assumptions83//!84//! * Total number of pieces for one token shouldn't exceed `up_data_structs::MAX_REFUNGIBLE_PIECES`.85//! * Total number of tokens of all types shouldn't be greater than `up_data_structs::MAX_TOKEN_PREFIX_LENGTH`.86//! * Sender should be in collection's allow list to perform operations on tokens.8788#![cfg_attr(not(feature = "std"), no_std)]8990use crate::erc_token::ERC20Events;91use crate::erc::ERC721Events;9293use core::ops::Deref;94use evm_coder::ToLog;95use frame_support::{ensure, storage::with_transaction, transactional};96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};97use pallet_evm_coder_substrate::WithRecorder;98use pallet_common::{99	CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address,100	Event as CommonEvent, Pallet as PalletCommon,101};102use pallet_structure::Pallet as PalletStructure;103use sp_core::{Get, H160};104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};106use up_data_structs::{107	AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,108	mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,109	PropertyKeyPermission, PropertyScope, PropertyValue, TokenId, TrySetProperty,110	PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,111};112113pub use pallet::*;114#[cfg(feature = "runtime-benchmarks")]115pub mod benchmarking;116pub mod common;117pub mod erc;118pub mod erc_token;119pub mod weights;120121pub type CreateItemData<T> =122	CreateRefungibleExMultipleOwners<<T as pallet_evm::Config>::CrossAccountId>;123pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;124125#[frame_support::pallet]126pub mod pallet {127	use super::*;128	use frame_support::{129		Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key,130		traits::StorageVersion,131	};132	use up_data_structs::{CollectionId, TokenId};133	use super::weights::WeightInfo;134135	#[pallet::error]136	pub enum Error<T> {137		/// Not Refungible item data used to mint in Refungible collection.138		NotRefungibleDataUsedToMintFungibleCollectionToken,139		/// Maximum refungibility exceeded.140		WrongRefungiblePieces,141		/// Refungible token can't be repartitioned by user who isn't owns all pieces.142		RepartitionWhileNotOwningAllPieces,143		/// Refungible token can't nest other tokens.144		RefungibleDisallowsNesting,145		/// Setting item properties is not allowed.146		SettingPropertiesNotAllowed,147	}148149	#[pallet::config]150	pub trait Config:151		frame_system::Config + pallet_common::Config + pallet_structure::Config152	{153		type WeightInfo: WeightInfo;154	}155156	const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);157158	#[pallet::pallet]159	#[pallet::storage_version(STORAGE_VERSION)]160	#[pallet::generate_store(pub(super) trait Store)]161	pub struct Pallet<T>(_);162163	/// Total amount of minted tokens in a collection.164	#[pallet::storage]165	pub type TokensMinted<T: Config> =166		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;167168	/// Amount of tokens burnt in a collection.169	#[pallet::storage]170	pub type TokensBurnt<T: Config> =171		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;172173	/// Amount of pieces a refungible token is split into.174	#[pallet::storage]175	#[pallet::getter(fn token_properties)]176	pub type TokenProperties<T: Config> = StorageNMap<177		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),178		Value = up_data_structs::Properties,179		QueryKind = ValueQuery,180		OnEmpty = up_data_structs::TokenProperties,181	>;182183	/// Total amount of pieces for token184	#[pallet::storage]185	pub type TotalSupply<T: Config> = StorageNMap<186		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),187		Value = u128,188		QueryKind = ValueQuery,189	>;190191	/// Used to enumerate tokens owned by account.192	#[pallet::storage]193	pub type Owned<T: Config> = StorageNMap<194		Key = (195			Key<Twox64Concat, CollectionId>,196			Key<Blake2_128Concat, T::CrossAccountId>,197			Key<Twox64Concat, TokenId>,198		),199		Value = bool,200		QueryKind = ValueQuery,201	>;202203	/// Amount of tokens (not pieces) partially owned by an account within a collection.204	#[pallet::storage]205	pub type AccountBalance<T: Config> = StorageNMap<206		Key = (207			Key<Twox64Concat, CollectionId>,208			// Owner209			Key<Blake2_128Concat, T::CrossAccountId>,210		),211		Value = u32,212		QueryKind = ValueQuery,213	>;214215	/// Amount of token pieces owned by account.216	#[pallet::storage]217	pub type Balance<T: Config> = StorageNMap<218		Key = (219			Key<Twox64Concat, CollectionId>,220			Key<Twox64Concat, TokenId>,221			// Owner222			Key<Blake2_128Concat, T::CrossAccountId>,223		),224		Value = u128,225		QueryKind = ValueQuery,226	>;227228	/// Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.229	#[pallet::storage]230	pub type Allowance<T: Config> = StorageNMap<231		Key = (232			Key<Twox64Concat, CollectionId>,233			Key<Twox64Concat, TokenId>,234			// Owner235			Key<Blake2_128, T::CrossAccountId>,236			// Spender237			Key<Blake2_128Concat, T::CrossAccountId>,238		),239		Value = u128,240		QueryKind = ValueQuery,241	>;242243	/// Spender set by a wallet owner that could perform certain transactions on all tokens in the wallet.244	#[pallet::storage]245	pub type CollectionAllowance<T: Config> = StorageNMap<246		Key = (247			Key<Twox64Concat, CollectionId>,248			Key<Blake2_128Concat, T::CrossAccountId>, // Owner249			Key<Blake2_128Concat, T::CrossAccountId>, // Spender250		),251		Value = bool,252		QueryKind = ValueQuery,253	>;254}255256pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);257impl<T: Config> RefungibleHandle<T> {258	pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {259		Self(inner)260	}261	pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {262		self.0263	}264	pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {265		&mut self.0266	}267}268269impl<T: Config> Deref for RefungibleHandle<T> {270	type Target = pallet_common::CollectionHandle<T>;271272	fn deref(&self) -> &Self::Target {273		&self.0274	}275}276277impl<T: Config> WithRecorder<T> for RefungibleHandle<T> {278	fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {279		self.0.recorder()280	}281	fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {282		self.0.into_recorder()283	}284}285286impl<T: Config> Pallet<T> {287	/// Get number of RFT tokens in collection288	pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {289		<TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)290	}291292	/// Check that RFT token exists293	///294	/// - `token`: Token ID.295	pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {296		<TotalSupply<T>>::contains_key((collection.id, token))297	}298299	pub fn set_scoped_token_property(300		collection_id: CollectionId,301		token_id: TokenId,302		scope: PropertyScope,303		property: Property,304	) -> DispatchResult {305		TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {306			properties.try_scoped_set(scope, property.key, property.value)307		})308		.map_err(<CommonError<T>>::from)?;309310		Ok(())311	}312313	pub fn set_scoped_token_properties(314		collection_id: CollectionId,315		token_id: TokenId,316		scope: PropertyScope,317		properties: impl Iterator<Item = Property>,318	) -> DispatchResult {319		TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {320			stored_properties.try_scoped_set_from_iter(scope, properties)321		})322		.map_err(<CommonError<T>>::from)?;323324		Ok(())325	}326}327328// unchecked calls skips any permission checks329impl<T: Config> Pallet<T> {330	/// Create RFT collection331	///332	/// `init_collection` will take non-refundable deposit for collection creation.333	///334	/// - `data`: Contains settings for collection limits and permissions.335	pub fn init_collection(336		owner: T::CrossAccountId,337		payer: T::CrossAccountId,338		data: CreateCollectionData<T::AccountId>,339		flags: CollectionFlags,340	) -> Result<CollectionId, DispatchError> {341		<PalletCommon<T>>::init_collection(owner, payer, data, flags)342	}343344	/// Destroy RFT collection345	///346	/// `destroy_collection` will throw error if collection contains any tokens.347	/// Only owner can destroy collection.348	pub fn destroy_collection(349		collection: RefungibleHandle<T>,350		sender: &T::CrossAccountId,351	) -> DispatchResult {352		let id = collection.id;353354		if Self::collection_has_tokens(id) {355			return Err(<CommonError<T>>::CantDestroyNotEmptyCollection.into());356		}357358		// =========359360		PalletCommon::destroy_collection(collection.0, sender)?;361362		<TokensMinted<T>>::remove(id);363		<TokensBurnt<T>>::remove(id);364		let _ = <TotalSupply<T>>::clear_prefix((id,), u32::MAX, None);365		let _ = <Balance<T>>::clear_prefix((id,), u32::MAX, None);366		let _ = <Allowance<T>>::clear_prefix((id,), u32::MAX, None);367		let _ = <Owned<T>>::clear_prefix((id,), u32::MAX, None);368		let _ = <AccountBalance<T>>::clear_prefix((id,), u32::MAX, None);369		Ok(())370	}371372	fn collection_has_tokens(collection_id: CollectionId) -> bool {373		<TotalSupply<T>>::iter_prefix((collection_id,))374			.next()375			.is_some()376	}377378	pub fn burn_token_unchecked(379		collection: &RefungibleHandle<T>,380		owner: &T::CrossAccountId,381		token_id: TokenId,382	) -> DispatchResult {383		let burnt = <TokensBurnt<T>>::get(collection.id)384			.checked_add(1)385			.ok_or(ArithmeticError::Overflow)?;386387		<TokensBurnt<T>>::insert(collection.id, burnt);388		<TokenProperties<T>>::remove((collection.id, token_id));389		<TotalSupply<T>>::remove((collection.id, token_id));390		let _ = <Balance<T>>::clear_prefix((collection.id, token_id), u32::MAX, None);391		let _ = <Allowance<T>>::clear_prefix((collection.id, token_id), u32::MAX, None);392		<PalletEvm<T>>::deposit_log(393			ERC721Events::Transfer {394				from: *owner.as_eth(),395				to: H160::default(),396				token_id: token_id.into(),397			}398			.to_log(collection_id_to_address(collection.id)),399		);400		Ok(())401	}402403	/// Burn RFT token pieces404	///405	/// `burn` will decrease total amount of token pieces and amount owned by sender.406	/// `burn` can be called even if there are multiple owners of the RFT token.407	/// If sender wouldn't have any pieces left after `burn` than she will stop being408	/// one of the owners of the token. If there is no account that owns any pieces of409	/// the token than token will be burned too.410	///411	/// - `amount`: Amount of token pieces to burn.412	/// - `token`: Token who's pieces should be burned413	/// - `collection`: Collection that contains the token414	pub fn burn(415		collection: &RefungibleHandle<T>,416		owner: &T::CrossAccountId,417		token: TokenId,418		amount: u128,419	) -> DispatchResult {420		if <Balance<T>>::get((collection.id, token, owner)) == 0 {421			return Err(<CommonError<T>>::TokenValueTooLow.into());422		}423424		let total_supply = <TotalSupply<T>>::get((collection.id, token))425			.checked_sub(amount)426			.ok_or(<CommonError<T>>::TokenValueTooLow)?;427428		// This was probally last owner of this token?429		if total_supply == 0 {430			// Ensure user actually owns this amount431			ensure!(432				<Balance<T>>::get((collection.id, token, owner)) == amount,433				<CommonError<T>>::TokenValueTooLow434			);435			let account_balance = <AccountBalance<T>>::get((collection.id, owner))436				.checked_sub(1)437				// Should not occur438				.ok_or(ArithmeticError::Underflow)?;439440			// =========441442			<Owned<T>>::remove((collection.id, owner, token));443			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);444			<AccountBalance<T>>::insert((collection.id, owner), account_balance);445			Self::burn_token_unchecked(collection, owner, token)?;446			<PalletEvm<T>>::deposit_log(447				ERC20Events::Transfer {448					from: *owner.as_eth(),449					to: H160::default(),450					value: amount.into(),451				}452				.to_log(collection_id_to_address(collection.id)),453			);454			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(455				collection.id,456				token,457				owner.clone(),458				amount,459			));460			return Ok(());461		}462463		let balance = <Balance<T>>::get((collection.id, token, owner))464			.checked_sub(amount)465			.ok_or(<CommonError<T>>::TokenValueTooLow)?;466		let account_balance = if balance == 0 {467			<AccountBalance<T>>::get((collection.id, owner))468				.checked_sub(1)469				// Should not occur470				.ok_or(ArithmeticError::Underflow)?471		} else {472			0473		};474475		// =========476477		if balance == 0 {478			<Owned<T>>::remove((collection.id, owner, token));479			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);480			<Balance<T>>::remove((collection.id, token, owner));481			<AccountBalance<T>>::insert((collection.id, owner), account_balance);482483			if let Ok(user) = Self::token_owner(collection.id, token) {484				<PalletEvm<T>>::deposit_log(485					ERC721Events::Transfer {486						from: erc::ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,487						to: *user.as_eth(),488						token_id: token.into(),489					}490					.to_log(collection_id_to_address(collection.id)),491				);492			}493		} else {494			<Balance<T>>::insert((collection.id, token, owner), balance);495		}496		<TotalSupply<T>>::insert((collection.id, token), total_supply);497498		<PalletEvm<T>>::deposit_log(499			ERC20Events::Transfer {500				from: *owner.as_eth(),501				to: H160::default(),502				value: amount.into(),503			}504			.to_log(T::EvmTokenAddressMapping::token_to_address(505				collection.id,506				token,507			)),508		);509		<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(510			collection.id,511			token,512			owner.clone(),513			amount,514		));515		Ok(())516	}517518	/// A batch operation to add, edit or remove properties for a token.519	/// It sets or removes a token's properties according to520	/// `properties_updates` contents:521	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`522	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.523	///524	/// - `nesting_budget`: Limit for searching parents in-depth to check ownership.525	/// - `is_token_create`: Indicates that method is called during token initialization.526	///   Allows to bypass ownership check.527	///528	/// All affected properties should have `mutable` permission529	/// to be **deleted** or to be **set more than once**,530	/// and the sender should have permission to edit those properties.531	///532	/// This function fires an event for each property change.533	/// In case of an error, all the changes (including the events) will be reverted534	/// since the function is transactional.535	#[transactional]536	fn modify_token_properties(537		collection: &RefungibleHandle<T>,538		sender: &T::CrossAccountId,539		token_id: TokenId,540		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,541		is_token_create: bool,542		nesting_budget: &dyn Budget,543	) -> DispatchResult {544		let is_token_owner = || -> Result<bool, DispatchError> {545			let balance = collection.balance(sender.clone(), token_id);546			let total_pieces: u128 =547				Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);548			if balance != total_pieces {549				return Ok(false);550			}551552			let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(553				sender.clone(),554				collection.id,555				token_id,556				None,557				nesting_budget,558			)?;559560			Ok(is_bundle_owner)561		};562563		let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));564565		<PalletCommon<T>>::modify_token_properties(566			collection,567			sender,568			token_id,569			properties_updates,570			is_token_create,571			stored_properties,572			is_token_owner,573			|properties| <TokenProperties<T>>::set((collection.id, token_id), properties),574			erc::ERC721TokenEvent::TokenChanged {575				collection_id: collection_id_to_address(collection.id),576				token_id: token_id.into(),577			}578			.to_log(T::ContractAddress::get()),579		)580	}581582	pub fn set_token_properties(583		collection: &RefungibleHandle<T>,584		sender: &T::CrossAccountId,585		token_id: TokenId,586		properties: impl Iterator<Item = Property>,587		is_token_create: bool,588		nesting_budget: &dyn Budget,589	) -> DispatchResult {590		Self::modify_token_properties(591			collection,592			sender,593			token_id,594			properties.map(|p| (p.key, Some(p.value))),595			is_token_create,596			nesting_budget,597		)598	}599600	pub fn set_token_property(601		collection: &RefungibleHandle<T>,602		sender: &T::CrossAccountId,603		token_id: TokenId,604		property: Property,605		nesting_budget: &dyn Budget,606	) -> DispatchResult {607		let is_token_create = false;608609		Self::set_token_properties(610			collection,611			sender,612			token_id,613			[property].into_iter(),614			is_token_create,615			nesting_budget,616		)617	}618619	pub fn delete_token_properties(620		collection: &RefungibleHandle<T>,621		sender: &T::CrossAccountId,622		token_id: TokenId,623		property_keys: impl Iterator<Item = PropertyKey>,624		nesting_budget: &dyn Budget,625	) -> DispatchResult {626		let is_token_create = false;627628		Self::modify_token_properties(629			collection,630			sender,631			token_id,632			property_keys.into_iter().map(|key| (key, None)),633			is_token_create,634			nesting_budget,635		)636	}637638	pub fn delete_token_property(639		collection: &RefungibleHandle<T>,640		sender: &T::CrossAccountId,641		token_id: TokenId,642		property_key: PropertyKey,643		nesting_budget: &dyn Budget,644	) -> DispatchResult {645		Self::delete_token_properties(646			collection,647			sender,648			token_id,649			[property_key].into_iter(),650			nesting_budget,651		)652	}653654	/// Transfer RFT token pieces from one account to another.655	///656	/// If the sender is no longer owns any pieces after the `transfer` than she stops being an owner of the token.657	///658	/// - `from`: Owner of token pieces to transfer.659	/// - `to`: Recepient of transfered token pieces.660	/// - `amount`: Amount of token pieces to transfer.661	/// - `token`: Token whos pieces should be transfered662	/// - `collection`: Collection that contains the token663	pub fn transfer(664		collection: &RefungibleHandle<T>,665		from: &T::CrossAccountId,666		to: &T::CrossAccountId,667		token: TokenId,668		amount: u128,669		nesting_budget: &dyn Budget,670	) -> DispatchResult {671		ensure!(672			collection.limits.transfers_enabled(),673			<CommonError<T>>::TransferNotAllowed674		);675676		if collection.permissions.access() == AccessMode::AllowList {677			collection.check_allowlist(from)?;678			collection.check_allowlist(to)?;679		}680		<PalletCommon<T>>::ensure_correct_receiver(to)?;681682		let initial_balance_from = <Balance<T>>::get((collection.id, token, from));683684		if initial_balance_from == 0 {685			return Err(<CommonError<T>>::TokenValueTooLow.into());686		}687688		let updated_balance_from = initial_balance_from689			.checked_sub(amount)690			.ok_or(<CommonError<T>>::TokenValueTooLow)?;691		let mut create_target = false;692		let from_to_differ = from != to;693		let updated_balance_to = if from != to && amount != 0 {694			let old_balance = <Balance<T>>::get((collection.id, token, to));695			if old_balance == 0 {696				create_target = true;697			}698			Some(699				old_balance700					.checked_add(amount)701					.ok_or(ArithmeticError::Overflow)?,702			)703		} else {704			None705		};706707		let account_balance_from = if updated_balance_from == 0 {708			Some(709				<AccountBalance<T>>::get((collection.id, from))710					.checked_sub(1)711					// Should not occur712					.ok_or(ArithmeticError::Underflow)?,713			)714		} else {715			None716		};717		// Account data is created in token, AccountBalance should be increased718		// But only if from != to as we shouldn't check overflow in this case719		let account_balance_to = if create_target && from_to_differ {720			let account_balance_to = <AccountBalance<T>>::get((collection.id, to))721				.checked_add(1)722				.ok_or(ArithmeticError::Overflow)?;723			ensure!(724				account_balance_to < collection.limits.account_token_ownership_limit(),725				<CommonError<T>>::AccountTokenLimitExceeded,726			);727728			Some(account_balance_to)729		} else {730			None731		};732733		// =========734735		if let Some(updated_balance_to) = updated_balance_to {736			// from != to && amount != 0737738			<PalletStructure<T>>::nest_if_sent_to_token(739				from.clone(),740				to,741				collection.id,742				token,743				nesting_budget,744			)?;745746			if updated_balance_from == 0 {747				<Balance<T>>::remove((collection.id, token, from));748				<PalletStructure<T>>::unnest_if_nested(from, collection.id, token);749			} else {750				<Balance<T>>::insert((collection.id, token, from), updated_balance_from);751			}752			<Balance<T>>::insert((collection.id, token, to), updated_balance_to);753			if let Some(account_balance_from) = account_balance_from {754				<AccountBalance<T>>::insert((collection.id, from), account_balance_from);755				<Owned<T>>::remove((collection.id, from, token));756			}757			if let Some(account_balance_to) = account_balance_to {758				<AccountBalance<T>>::insert((collection.id, to), account_balance_to);759				<Owned<T>>::insert((collection.id, to, token), true);760			}761		}762763		<PalletEvm<T>>::deposit_log(764			ERC20Events::Transfer {765				from: *from.as_eth(),766				to: *to.as_eth(),767				value: amount.into(),768			}769			.to_log(T::EvmTokenAddressMapping::token_to_address(770				collection.id,771				token,772			)),773		);774775		<PalletCommon<T>>::deposit_event(CommonEvent::Transfer(776			collection.id,777			token,778			from.clone(),779			to.clone(),780			amount,781		));782783		let total_supply = <TotalSupply<T>>::get((collection.id, token));784785		if amount == total_supply {786			// if token was fully owned by `from` and will be fully owned by `to` after transfer787			<PalletEvm<T>>::deposit_log(788				ERC721Events::Transfer {789					from: *from.as_eth(),790					to: *to.as_eth(),791					token_id: token.into(),792				}793				.to_log(collection_id_to_address(collection.id)),794			);795		} else if let Some(updated_balance_to) = updated_balance_to {796			// if `from` not equals `to`. This condition is needed to avoid sending event797			// when `from` fully owns token and sends part of token pieces to itself.798			if initial_balance_from == total_supply {799				// if token was fully owned by `from` and will be only partially owned by `to`800				// and `from` after transfer801				<PalletEvm<T>>::deposit_log(802					ERC721Events::Transfer {803						from: *from.as_eth(),804						to: erc::ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,805						token_id: token.into(),806					}807					.to_log(collection_id_to_address(collection.id)),808				);809			} else if updated_balance_to == total_supply {810				// if token was partially owned by `from` and will be fully owned by `to` after transfer811				<PalletEvm<T>>::deposit_log(812					ERC721Events::Transfer {813						from: erc::ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,814						to: *to.as_eth(),815						token_id: token.into(),816					}817					.to_log(collection_id_to_address(collection.id)),818				);819			}820		}821822		Ok(())823	}824825	/// Batched operation to create multiple RFT tokens.826	///827	/// Same as `create_item` but creates multiple tokens.828	///829	/// - `data`: Same as 'data` in `create_item` but contains data for multiple tokens.830	pub fn create_multiple_items(831		collection: &RefungibleHandle<T>,832		sender: &T::CrossAccountId,833		data: Vec<CreateItemData<T>>,834		nesting_budget: &dyn Budget,835	) -> DispatchResult {836		if !collection.is_owner_or_admin(sender) {837			ensure!(838				collection.permissions.mint_mode(),839				<CommonError<T>>::PublicMintingNotAllowed840			);841			collection.check_allowlist(sender)?;842843			for item in data.iter() {844				for user in item.users.keys() {845					collection.check_allowlist(user)?;846				}847			}848		}849850		for item in data.iter() {851			for (owner, _) in item.users.iter() {852				<PalletCommon<T>>::ensure_correct_receiver(owner)?;853			}854		}855856		// Total pieces per tokens857		let totals = data858			.iter()859			.map(|data| {860				Ok(data861					.users862					.iter()863					.map(|u| u.1)864					.try_fold(0u128, |acc, v| acc.checked_add(*v))865					.ok_or(ArithmeticError::Overflow)?)866			})867			.collect::<Result<Vec<_>, DispatchError>>()?;868		for total in &totals {869			ensure!(870				*total <= MAX_REFUNGIBLE_PIECES,871				<Error<T>>::WrongRefungiblePieces872			);873		}874875		let first_token_id = <TokensMinted<T>>::get(collection.id);876		let tokens_minted = first_token_id877			.checked_add(data.len() as u32)878			.ok_or(ArithmeticError::Overflow)?;879		ensure!(880			tokens_minted < collection.limits.token_limit(),881			<CommonError<T>>::CollectionTokenLimitExceeded882		);883884		let mut balances = BTreeMap::new();885		for data in &data {886			for owner in data.users.keys() {887				let balance = balances888					.entry(owner)889					.or_insert_with(|| <AccountBalance<T>>::get((collection.id, owner)));890				*balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;891892				ensure!(893					*balance <= collection.limits.account_token_ownership_limit(),894					<CommonError<T>>::AccountTokenLimitExceeded,895				);896			}897		}898899		for (i, token) in data.iter().enumerate() {900			let token_id = TokenId(first_token_id + i as u32 + 1);901			for (to, _) in token.users.iter() {902				<PalletStructure<T>>::check_nesting(903					sender.clone(),904					to,905					collection.id,906					token_id,907					nesting_budget,908				)?;909			}910		}911912		// =========913914		with_transaction(|| {915			for (i, data) in data.iter().enumerate() {916				let token_id = first_token_id + i as u32 + 1;917				<TotalSupply<T>>::insert((collection.id, token_id), totals[i]);918919				for (user, amount) in data.users.iter() {920					if *amount == 0 {921						continue;922					}923					<Balance<T>>::insert((collection.id, token_id, &user), amount);924					<Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);925					<PalletStructure<T>>::nest_if_sent_to_token_unchecked(926						user,927						collection.id,928						TokenId(token_id),929					);930				}931932				if let Err(e) = Self::set_token_properties(933					collection,934					sender,935					TokenId(token_id),936					data.properties.clone().into_iter(),937					true,938					nesting_budget,939				) {940					return TransactionOutcome::Rollback(Err(e));941				}942			}943			TransactionOutcome::Commit(Ok(()))944		})?;945946		<TokensMinted<T>>::insert(collection.id, tokens_minted);947948		for (account, balance) in balances {949			<AccountBalance<T>>::insert((collection.id, account), balance);950		}951952		for (i, token) in data.into_iter().enumerate() {953			let token_id = first_token_id + i as u32 + 1;954955			let receivers = token956				.users957				.into_iter()958				.filter(|(_, amount)| *amount > 0)959				.collect::<Vec<_>>();960961			if let [(user, _)] = receivers.as_slice() {962				// if there is exactly one receiver963				<PalletEvm<T>>::deposit_log(964					ERC721Events::Transfer {965						from: H160::default(),966						to: *user.as_eth(),967						token_id: token_id.into(),968					}969					.to_log(collection_id_to_address(collection.id)),970				);971			} else if let [_, ..] = receivers.as_slice() {972				// if there is more than one receiver973				<PalletEvm<T>>::deposit_log(974					ERC721Events::Transfer {975						from: H160::default(),976						to: erc::ADDRESS_FOR_PARTIALLY_OWNED_TOKENS,977						token_id: token_id.into(),978					}979					.to_log(collection_id_to_address(collection.id)),980				);981			}982983			for (user, amount) in receivers.into_iter() {984				<PalletEvm<T>>::deposit_log(985					ERC20Events::Transfer {986						from: H160::default(),987						to: *user.as_eth(),988						value: amount.into(),989					}990					.to_log(T::EvmTokenAddressMapping::token_to_address(991						collection.id,992						TokenId(token_id),993					)),994				);995				<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(996					collection.id,997					TokenId(token_id),998					user,999					amount,1000				));1001			}1002		}1003		Ok(())1004	}10051006	pub fn set_allowance_unchecked(1007		collection: &RefungibleHandle<T>,1008		sender: &T::CrossAccountId,1009		spender: &T::CrossAccountId,1010		token: TokenId,1011		amount: u128,1012	) {1013		if amount == 0 {1014			<Allowance<T>>::remove((collection.id, token, sender, spender));1015		} else {1016			<Allowance<T>>::insert((collection.id, token, sender, spender), amount);1017		}10181019		<PalletEvm<T>>::deposit_log(1020			ERC20Events::Approval {1021				owner: *sender.as_eth(),1022				spender: *spender.as_eth(),1023				value: amount.into(),1024			}1025			.to_log(T::EvmTokenAddressMapping::token_to_address(1026				collection.id,1027				token,1028			)),1029		);1030		<PalletCommon<T>>::deposit_event(CommonEvent::Approved(1031			collection.id,1032			token,1033			sender.clone(),1034			spender.clone(),1035			amount,1036		))1037	}10381039	/// Set allowance for the spender to `transfer` or `burn` sender's token pieces.1040	///1041	/// - `amount`: Amount of token pieces the spender is allowed to `transfer` or `burn.1042	pub fn set_allowance(1043		collection: &RefungibleHandle<T>,1044		sender: &T::CrossAccountId,1045		spender: &T::CrossAccountId,1046		token: TokenId,1047		amount: u128,1048	) -> DispatchResult {1049		if collection.permissions.access() == AccessMode::AllowList {1050			collection.check_allowlist(sender)?;1051			collection.check_allowlist(spender)?;1052		}10531054		<PalletCommon<T>>::ensure_correct_receiver(spender)?;10551056		if <Balance<T>>::get((collection.id, token, sender)) < amount {1057			ensure!(1058				collection.ignores_owned_amount(sender) && Self::token_exists(collection, token),1059				<CommonError<T>>::CantApproveMoreThanOwned1060			);1061		}10621063		// =========10641065		Self::set_allowance_unchecked(collection, sender, spender, token, amount);1066		Ok(())1067	}10681069	/// Set allowance to spend from sender's eth mirror1070	///1071	/// - `from`: Address of sender's eth mirror.1072	/// - `to`: Adress of spender.1073	/// - `amount`: Amount of token pieces the spender is allowed to `transfer` or `burn.1074	pub fn set_allowance_from(1075		collection: &RefungibleHandle<T>,1076		sender: &T::CrossAccountId,1077		from: &T::CrossAccountId,1078		to: &T::CrossAccountId,1079		token_id: TokenId,1080		amount: u128,1081	) -> DispatchResult {1082		if collection.permissions.access() == AccessMode::AllowList {1083			collection.check_allowlist(sender)?;1084			collection.check_allowlist(from)?;1085			collection.check_allowlist(to)?;1086		}10871088		<PalletCommon<T>>::ensure_correct_receiver(to)?;10891090		ensure!(1091			sender.conv_eq(from),1092			<CommonError<T>>::AddressIsNotEthMirror1093		);10941095		if <Balance<T>>::get((collection.id, token_id, from)) < amount {1096			ensure!(1097				collection.limits.owner_can_transfer()1098					&& (collection.is_owner_or_admin(sender) || collection.is_owner_or_admin(from))1099					&& Self::token_exists(collection, token_id),1100				<CommonError<T>>::CantApproveMoreThanOwned1101			);1102		}11031104		// =========11051106		Self::set_allowance_unchecked(collection, from, to, token_id, amount);1107		Ok(())1108	}11091110	/// Returns allowance, which should be set after transaction1111	fn check_allowed(1112		collection: &RefungibleHandle<T>,1113		spender: &T::CrossAccountId,1114		from: &T::CrossAccountId,1115		token: TokenId,1116		amount: u128,1117		nesting_budget: &dyn Budget,1118	) -> Result<Option<u128>, DispatchError> {1119		if spender.conv_eq(from) {1120			return Ok(None);1121		}1122		if collection.permissions.access() == AccessMode::AllowList {1123			// `from`, `to` checked in [`transfer`]1124			collection.check_allowlist(spender)?;1125		}11261127		if collection.ignores_token_restrictions(spender) {1128			return Ok(Self::compute_allowance_decrease(1129				collection, token, from, &spender, amount,1130			));1131		}11321133		if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1134			// TODO: should collection owner be allowed to perform this transfer?1135			ensure!(1136				<PalletStructure<T>>::check_indirectly_owned(1137					spender.clone(),1138					source.0,1139					source.1,1140					None,1141					nesting_budget1142				)?,1143				<CommonError<T>>::ApprovedValueTooLow,1144			);1145			return Ok(None);1146		}11471148		let allowance = Self::compute_allowance_decrease(collection, token, from, &spender, amount);1149		if allowance.is_some() {1150			return Ok(allowance);1151		}11521153		// Allowance (if any) would be reduced if spender is also wallet operator1154		if <CollectionAllowance<T>>::get((collection.id, from, spender)) {1155			return Ok(allowance);1156		}11571158		Err(<CommonError<T>>::ApprovedValueTooLow.into())1159	}11601161	/// Returns `Some(amount)` if the `spender` have allowance to spend this amount.1162	/// Otherwise, it returns `None`.1163	fn compute_allowance_decrease(1164		collection: &RefungibleHandle<T>,1165		token: TokenId,1166		from: &T::CrossAccountId,1167		spender: &T::CrossAccountId,1168		amount: u128,1169	) -> Option<u128> {1170		<Allowance<T>>::get((collection.id, token, from, spender)).checked_sub(amount)1171	}11721173	/// Transfer RFT token pieces from one account to another.1174	///1175	/// Same as the [`transfer`] but spender doesn't needs to be an owner of the token pieces.1176	/// The owner should set allowance for the spender to transfer pieces.1177	///1178	/// [`transfer`]: struct.Pallet.html#method.transfer1179	pub fn transfer_from(1180		collection: &RefungibleHandle<T>,1181		spender: &T::CrossAccountId,1182		from: &T::CrossAccountId,1183		to: &T::CrossAccountId,1184		token: TokenId,1185		amount: u128,1186		nesting_budget: &dyn Budget,1187	) -> DispatchResult {1188		let allowance =1189			Self::check_allowed(collection, spender, from, token, amount, nesting_budget)?;11901191		// =========11921193		Self::transfer(collection, from, to, token, amount, nesting_budget)?;1194		if let Some(allowance) = allowance {1195			Self::set_allowance_unchecked(collection, from, spender, token, allowance);1196		}1197		Ok(())1198	}11991200	/// Burn RFT token pieces from the account.1201	///1202	/// Same as the [`burn`] but spender doesn't need to be an owner of the token pieces. The owner should1203	/// set allowance for the spender to burn pieces1204	///1205	/// [`burn`]: struct.Pallet.html#method.burn1206	pub fn burn_from(1207		collection: &RefungibleHandle<T>,1208		spender: &T::CrossAccountId,1209		from: &T::CrossAccountId,1210		token: TokenId,1211		amount: u128,1212		nesting_budget: &dyn Budget,1213	) -> DispatchResult {1214		let allowance =1215			Self::check_allowed(collection, spender, from, token, amount, nesting_budget)?;12161217		// =========12181219		Self::burn(collection, from, token, amount)?;1220		if let Some(allowance) = allowance {1221			Self::set_allowance_unchecked(collection, from, spender, token, allowance);1222		}1223		Ok(())1224	}12251226	/// Create RFT token.1227	///1228	/// The sender should be the owner/admin of the collection or collection should be configured1229	/// to allow public minting.1230	///1231	/// - `data`: Contains list of users who will become the owners of the token pieces and amount1232	///   of token pieces they will receive.1233	pub fn create_item(1234		collection: &RefungibleHandle<T>,1235		sender: &T::CrossAccountId,1236		data: CreateItemData<T>,1237		nesting_budget: &dyn Budget,1238	) -> DispatchResult {1239		Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1240	}12411242	/// Repartition RFT token.1243	///1244	/// `repartition` will set token balance of the sender and total amount of token pieces.1245	/// Sender should own all of the token pieces. `repartition' could be done even if some1246	/// token pieces were burned before.1247	///1248	/// - `amount`: Total amount of token pieces that the token will have after `repartition`.1249	pub fn repartition(1250		collection: &RefungibleHandle<T>,1251		owner: &T::CrossAccountId,1252		token: TokenId,1253		amount: u128,1254	) -> DispatchResult {1255		ensure!(1256			amount <= MAX_REFUNGIBLE_PIECES,1257			<Error<T>>::WrongRefungiblePieces1258		);1259		ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1260		// Ensure user owns all pieces1261		let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);1262		let balance = <Balance<T>>::get((collection.id, token, owner));1263		ensure!(1264			total_pieces == balance,1265			<Error<T>>::RepartitionWhileNotOwningAllPieces1266		);12671268		<Balance<T>>::insert((collection.id, token, owner), amount);1269		<TotalSupply<T>>::insert((collection.id, token), amount);12701271		if amount > total_pieces {1272			let mint_amount = amount - total_pieces;1273			<PalletEvm<T>>::deposit_log(1274				ERC20Events::Transfer {1275					from: H160::default(),1276					to: *owner.as_eth(),1277					value: mint_amount.into(),1278				}1279				.to_log(T::EvmTokenAddressMapping::token_to_address(1280					collection.id,1281					token,1282				)),1283			);1284			<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(1285				collection.id,1286				token,1287				owner.clone(),1288				mint_amount,1289			));1290		} else if total_pieces > amount {1291			let burn_amount = total_pieces - amount;1292			<PalletEvm<T>>::deposit_log(1293				ERC20Events::Transfer {1294					from: *owner.as_eth(),1295					to: H160::default(),1296					value: burn_amount.into(),1297				}1298				.to_log(T::EvmTokenAddressMapping::token_to_address(1299					collection.id,1300					token,1301				)),1302			);1303			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(1304				collection.id,1305				token,1306				owner.clone(),1307				burn_amount,1308			));1309		}13101311		Ok(())1312	}13131314	fn token_owner(1315		collection_id: CollectionId,1316		token_id: TokenId,1317	) -> Result<T::CrossAccountId, TokenOwnerError> {1318		let mut owner = None;1319		let mut count = 0;1320		for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {1321			count += 1;1322			if count > 1 {1323				return Err(TokenOwnerError::MultipleOwners);1324			}1325			owner = Some(key);1326		}1327		owner.ok_or(TokenOwnerError::NotFound)1328	}13291330	fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {1331		<TotalSupply<T>>::try_get((collection_id, token_id)).ok()1332	}13331334	pub fn set_collection_properties(1335		collection: &RefungibleHandle<T>,1336		sender: &T::CrossAccountId,1337		properties: Vec<Property>,1338	) -> DispatchResult {1339		<PalletCommon<T>>::set_collection_properties(collection, sender, properties.into_iter())1340	}13411342	pub fn delete_collection_properties(1343		collection: &RefungibleHandle<T>,1344		sender: &T::CrossAccountId,1345		property_keys: Vec<PropertyKey>,1346	) -> DispatchResult {1347		<PalletCommon<T>>::delete_collection_properties(1348			collection,1349			sender,1350			property_keys.into_iter(),1351		)1352	}13531354	pub fn set_token_property_permissions(1355		collection: &RefungibleHandle<T>,1356		sender: &T::CrossAccountId,1357		property_permissions: Vec<PropertyKeyPermission>,1358	) -> DispatchResult {1359		<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1360	}13611362	pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {1363		<PalletCommon<T>>::property_permissions(collection_id)1364	}13651366	pub fn set_scoped_token_property_permissions(1367		collection: &RefungibleHandle<T>,1368		sender: &T::CrossAccountId,1369		scope: PropertyScope,1370		property_permissions: Vec<PropertyKeyPermission>,1371	) -> DispatchResult {1372		<PalletCommon<T>>::set_scoped_token_property_permissions(1373			collection,1374			sender,1375			scope,1376			property_permissions,1377		)1378	}13791380	/// Returns 10 token in no particular order.1381	///1382	/// There is no direct way to get token holders in ascending order,1383	/// since `iter_prefix` returns values in no particular order.1384	/// Therefore, getting the 10 largest holders with a large value of holders1385	/// can lead to impact memory allocation + sorting with  `n * log (n)`.1386	pub fn token_owners(1387		collection_id: CollectionId,1388		token: TokenId,1389	) -> Option<Vec<T::CrossAccountId>> {1390		let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection_id, token))1391			.map(|(owner, _amount)| owner)1392			.take(10)1393			.collect();13941395		if res.is_empty() {1396			None1397		} else {1398			Some(res)1399		}1400	}14011402	/// Sets or unsets the approval of a given operator.1403	///1404	/// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1405	/// - `owner`: Token owner1406	/// - `operator`: Operator1407	/// - `approve`: Should operator status be granted or revoked?1408	pub fn set_allowance_for_all(1409		collection: &RefungibleHandle<T>,1410		owner: &T::CrossAccountId,1411		spender: &T::CrossAccountId,1412		approve: bool,1413	) -> DispatchResult {1414		<PalletCommon<T>>::set_allowance_for_all(1415			collection,1416			owner,1417			spender,1418			approve,1419			|| <CollectionAllowance<T>>::insert((collection.id, owner, spender), approve),1420			ERC721Events::ApprovalForAll {1421				owner: *owner.as_eth(),1422				operator: *spender.as_eth(),1423				approved: approve,1424			}1425			.to_log(collection_id_to_address(collection.id)),1426		)1427	}14281429	/// Tells whether the given `owner` approves the `operator`.1430	pub fn allowance_for_all(1431		collection: &RefungibleHandle<T>,1432		owner: &T::CrossAccountId,1433		spender: &T::CrossAccountId,1434	) -> bool {1435		<CollectionAllowance<T>>::get((collection.id, owner, spender))1436	}14371438	pub fn repair_item(collection: &RefungibleHandle<T>, token: TokenId) -> DispatchResult {1439		<TokenProperties<T>>::mutate((collection.id, token), |properties| {1440			properties.recompute_consumed_space();1441		});14421443		Ok(())1444	}1445}
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -1,485 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1
-interface Collection is Dummy, ERC165 {
-	// /// Set collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @param value Propery value.
-	// /// @dev EVM selector for this function is: 0x2f073f66,
-	// ///  or in textual repr: setCollectionProperty(string,bytes)
-	// function setCollectionProperty(string memory key, bytes memory value) external;
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Property[] memory properties) external;
-
-	// /// Delete collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x7b7debce,
-	// ///  or in textual repr: deleteCollectionProperty(string)
-	// function deleteCollectionProperty(string memory key) external;
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) external;
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) external view returns (bytes memory);
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
-	// /// Set the sponsor of the collection.
-	// ///
-	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	// ///
-	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	// /// @dev EVM selector for this function is: 0x7623402e,
-	// ///  or in textual repr: setCollectionSponsor(address)
-	// function setCollectionSponsor(address sponsor) external;
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() external view returns (bool);
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() external;
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() external;
-
-	/// Get current sponsor.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	/// @dev EVM selector for this function is: 0x6ec0a9f1,
-	///  or in textual repr: collectionSponsor()
-	function collectionSponsor() external view returns (CrossAddress memory);
-
-	/// Get current collection limits.
-	///
-	/// @return Array of collection limits
-	/// @dev EVM selector for this function is: 0xf63bc572,
-	///  or in textual repr: collectionLimits()
-	function collectionLimits() external view returns (CollectionLimit[] memory);
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Some limit.
-	/// @dev EVM selector for this function is: 0x2316ee74,
-	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
-	function setCollectionLimit(CollectionLimit memory limit) external;
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() external view returns (address);
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(CrossAddress memory admin) external;
-
-	// /// Add collection admin.
-	// /// @param newAdmin Address of the added administrator.
-	// /// @dev EVM selector for this function is: 0x92e462c7,
-	// ///  or in textual repr: addCollectionAdmin(address)
-	// function addCollectionAdmin(address newAdmin) external;
-
-	// /// Remove collection admin.
-	// ///
-	// /// @param admin Address of the removed administrator.
-	// /// @dev EVM selector for this function is: 0xfafd7b42,
-	// ///  or in textual repr: removeCollectionAdmin(address)
-	// function removeCollectionAdmin(address admin) external;
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	/// @dev EVM selector for this function is: 0x112d4586,
-	///  or in textual repr: setCollectionNesting(bool)
-	function setCollectionNesting(bool enable) external;
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	/// @param collections Addresses of collections that will be available for nesting.
-	/// @dev EVM selector for this function is: 0x64872396,
-	///  or in textual repr: setCollectionNesting(bool,address[])
-	function setCollectionNesting(bool enable, address[] memory collections) external;
-
-	/// Returns nesting for a collection
-	/// @dev EVM selector for this function is: 0x22d25bfe,
-	///  or in textual repr: collectionNestingRestrictedCollectionIds()
-	function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
-	/// Returns permissions for a collection
-	/// @dev EVM selector for this function is: 0x5b2eaf4b,
-	///  or in textual repr: collectionNestingPermissions()
-	function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(AccessMode mode) external;
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0x91b6df49,
-	///  or in textual repr: allowlistedCross((address,uint256))
-	function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
-	// /// Add the user to the allowed list.
-	// ///
-	// /// @param user Address of a trusted user.
-	// /// @dev EVM selector for this function is: 0x67844fe6,
-	// ///  or in textual repr: addToCollectionAllowList(address)
-	// function addToCollectionAllowList(address user) external;
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(CrossAddress memory user) external;
-
-	// /// Remove the user from the allowed list.
-	// ///
-	// /// @param user Address of a removed user.
-	// /// @dev EVM selector for this function is: 0x85c51acb,
-	// ///  or in textual repr: removeFromCollectionAllowList(address)
-	// function removeFromCollectionAllowList(address user) external;
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) external;
-
-	// /// Check that account is the owner or admin of the collection
-	// ///
-	// /// @param user account to verify
-	// /// @return "true" if account is the owner or admin
-	// /// @dev EVM selector for this function is: 0x9811b0c7,
-	// ///  or in textual repr: isOwnerOrAdmin(address)
-	// function isOwnerOrAdmin(address user) external view returns (bool);
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() external view returns (string memory);
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() external view returns (CrossAddress memory);
-
-	// /// Changes collection owner to another account
-	// ///
-	// /// @dev Owner can be changed only by current owner
-	// /// @param newOwner new owner account
-	// /// @dev EVM selector for this function is: 0x4f53e226,
-	// ///  or in textual repr: changeCollectionOwner(address)
-	// function changeCollectionOwner(address newOwner) external;
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() external view returns (CrossAddress[] memory);
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0x6496c497,
-	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
-	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
-	/// Access grant for owner and admins. Used as default.
-	Normal,
-	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
-	AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
-	CollectionPermissionField field;
-	bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
-	/// Owner of token can nest tokens under it.
-	TokenOwner,
-	/// Admin of token collection can nest tokens under token.
-	CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
-	bool token_owner;
-	uint256[] ids;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
-	CollectionLimitField field;
-	OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
-	/// Shows the status of accessibility of value
-	bool status;
-	/// Actual value if `status` is true
-	uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
-	/// How many tokens can a user have on one account.
-	AccountTokenOwnership,
-	/// How many bytes of data are available for sponsorship.
-	SponsoredDataSize,
-	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
-	SponsoredDataRateLimit,
-	/// How many tokens can be mined into this collection.
-	TokenLimit,
-	/// Timeouts for transfer sponsoring.
-	SponsorTransferTimeout,
-	/// Timeout for sponsoring an approval in passed blocks.
-	SponsorApproveTimeout,
-	/// Whether the collection owner of the collection can send tokens (which belong to other users).
-	OwnerCanTransfer,
-	/// Can the collection owner burn other people's tokens.
-	OwnerCanDestroy,
-	/// Is it possible to send tokens from this collection between users.
-	TransferEnabled
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
-	string key;
-	bytes value;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x85d7dea6
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
-	/// @param owner crossAddress The address which owns the funds.
-	/// @param spender crossAddress The address which will spend the funds.
-	/// @return A uint256 specifying the amount of tokens still available for the spender.
-	/// @dev EVM selector for this function is: 0xe0af4bd7,
-	///  or in textual repr: allowanceCross((address,uint256),(address,uint256))
-	function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
-
-	/// @notice A description for the collection.
-	/// @dev EVM selector for this function is: 0x7284e416,
-	///  or in textual repr: description()
-	function description() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x269e6158,
-	///  or in textual repr: mintCross((address,uint256),uint256)
-	function mintCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x0ecd0ab0,
-	///  or in textual repr: approveCross((address,uint256),uint256)
-	function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
-
-	// /// Burn tokens from account
-	// /// @dev Function that burns an `amount` of the tokens of a given account,
-	// /// deducting from the sender's allowance for said account.
-	// /// @param from The account whose tokens will be burnt.
-	// /// @param amount The amount that will be burnt.
-	// /// @dev EVM selector for this function is: 0x79cc6790,
-	// ///  or in textual repr: burnFrom(address,uint256)
-	// function burnFrom(address from, uint256 amount) external returns (bool);
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
-
-	/// Mint tokens for multiple accounts.
-	/// @param amounts array of pairs of account address and amount
-	/// @dev EVM selector for this function is: 0x1acf2d55,
-	///  or in textual repr: mintBulk((address,uint256)[])
-	function mintBulk(AmountForAddress[] memory amounts) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 amount
-	) external returns (bool);
-
-	/// @notice Returns collection helper contract address
-	/// @dev EVM selector for this function is: 0x1896cce6,
-	///  or in textual repr: collectionHelperAddress()
-	function collectionHelperAddress() external view returns (address);
-}
-
-struct AmountForAddress {
-	address to;
-	uint256 amount;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x40c10f19
-interface ERC20Mintable is Dummy, ERC165 {
-	/// Mint tokens for `to` account.
-	/// @param to account that will receive minted tokens
-	/// @param amount amount of tokens to mint
-	/// @dev EVM selector for this function is: 0x40c10f19,
-	///  or in textual repr: mint(address,uint256)
-	function mint(address to, uint256 amount) external returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() external view returns (uint8);
-
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) external view returns (uint256);
-}
-
-interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}