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

difftreelog

feature(common-pallet): add changeOwner method

Grigoriy Simonov2022-08-23parent: #565dfea.patch.diff
in: master

14 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -431,6 +431,27 @@
 		};
 		Ok(mode.into())
 	}
+
+	/// Changes collection owner
+	///
+	/// @dev Owner can be changed only by current owner
+	/// @param newOwner new owner
+	fn change_owner(&mut self, caller: caller, new_owner: address) -> Result<void> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let new_owner = T::CrossAccountId::from_eth(new_owner);
+		self.change_owner_internal(caller, new_owner)
+	}
+
+impl<T: Config> CollectionHandle<T>
+where
+	T::AccountId: From<[u8; 32]>,
+{
+
+	fn change_owner_internal(&mut self, caller: T::CrossAccountId, new_owner: T::CrossAccountId) -> Result<void> {
+		self.check_is_owner(&caller).map_err(dispatch_to_evm::<T>)?;
+		self.collection.owner = new_owner.as_sub().clone();
+		save(self)
+	}
 }
 
 fn check_is_owner_or_admin<T: Config>(
@@ -440,12 +461,13 @@
 	let caller = T::CrossAccountId::from_eth(caller);
 	collection
 		.check_is_owner_or_admin(&caller)
-		.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+		.map_err(dispatch_to_evm::<T>)?;
 	Ok(caller)
 }
 
 fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {
 	// TODO possibly delete for the lack of transaction
+	collection.consume_store_writes(1)?;
 	collection
 		.check_is_internal()
 		.map_err(dispatch_to_evm::<T>)?;
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -31,7 +31,103 @@
 	);
 }
 
-// Selector: 6cf113cd
+// Selector: 79cc6790
+contract ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		from;
+		amount;
+		dummy = 0;
+		return false;
+	}
+}
+
+// Selector: 942e8b22
+contract ERC20 is Dummy, ERC165, ERC20Events {
+	// Selector: name() 06fdde03
+	function name() public view returns (string memory) {
+		require(false, stub_error);
+		dummy;
+		return "";
+	}
+
+	// Selector: symbol() 95d89b41
+	function symbol() public view returns (string memory) {
+		require(false, stub_error);
+		dummy;
+		return "";
+	}
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+
+	// Selector: decimals() 313ce567
+	function decimals() public view returns (uint8) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+
+	// Selector: balanceOf(address) 70a08231
+	function balanceOf(address owner) public view returns (uint256) {
+		require(false, stub_error);
+		owner;
+		dummy;
+		return 0;
+	}
+
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		to;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: transferFrom(address,address,uint256) 23b872dd
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) public returns (bool) {
+		require(false, stub_error);
+		from;
+		to;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: approve(address,uint256) 095ea7b3
+	function approve(address spender, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		spender;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: allowance(address,address) dd62ed3e
+	function allowance(address owner, address spender)
+		public
+		view
+		returns (uint256)
+	{
+		require(false, stub_error);
+		owner;
+		spender;
+		dummy;
+		return 0;
+	}
+}
+
+// Selector: ca08c92c
 contract Collection is Dummy, ERC165 {
 	// Set collection property.
 	//
@@ -276,105 +372,21 @@
 	//
 	// Selector: uniqueCollectionType() d34b55b8
 	function uniqueCollectionType() public returns (string memory) {
-		require(false, stub_error);
-		dummy = 0;
-		return "";
-	}
-}
-
-// Selector: 79cc6790
-contract ERC20UniqueExtensions is Dummy, ERC165 {
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 amount) public returns (bool) {
 		require(false, stub_error);
-		from;
-		amount;
 		dummy = 0;
-		return false;
-	}
-}
-
-// Selector: 942e8b22
-contract ERC20 is Dummy, ERC165, ERC20Events {
-	// Selector: name() 06fdde03
-	function name() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	// Selector: symbol() 95d89b41
-	function symbol() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
 		return "";
-	}
-
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	// Selector: decimals() 313ce567
-	function decimals() public view returns (uint8) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	// Selector: balanceOf(address) 70a08231
-	function balanceOf(address owner) public view returns (uint256) {
-		require(false, stub_error);
-		owner;
-		dummy;
-		return 0;
 	}
 
-	// Selector: transfer(address,uint256) a9059cbb
-	function transfer(address to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	// Selector: transferFrom(address,address,uint256) 23b872dd
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) public returns (bool) {
-		require(false, stub_error);
-		from;
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	// Selector: approve(address,uint256) 095ea7b3
-	function approve(address spender, uint256 amount) public returns (bool) {
+	// Changes collection owner
+	//
+	// @dev Owner can be changed only by current owner
+	// @param newOwner new owner
+	//
+	// Selector: changeOwner(address) a6f9dae1
+	function changeOwner(address newOwner) public {
 		require(false, stub_error);
-		spender;
-		amount;
+		newOwner;
 		dummy = 0;
-		return false;
-	}
-
-	// Selector: allowance(address,address) dd62ed3e
-	function allowance(address owner, address spender)
-		public
-		view
-		returns (uint256)
-	{
-		require(false, stub_error);
-		owner;
-		spender;
-		dummy;
-		return 0;
 	}
 }
 
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -373,7 +373,49 @@
 	}
 }
 
-// Selector: 6cf113cd
+// Selector: 780e9d63
+contract ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid NFTs
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
+	// Selector: tokenByIndex(uint256) 4f6ccce7
+	function tokenByIndex(uint256 index) public view returns (uint256) {
+		require(false, stub_error);
+		index;
+		dummy;
+		return 0;
+	}
+
+	// @dev Not implemented
+	//
+	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+	function tokenOfOwnerByIndex(address owner, uint256 index)
+		public
+		view
+		returns (uint256)
+	{
+		require(false, stub_error);
+		owner;
+		index;
+		dummy;
+		return 0;
+	}
+
+	// @notice Count NFTs tracked by this contract
+	// @return A count of valid NFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+}
+
+// Selector: ca08c92c
 contract Collection is Dummy, ERC165 {
 	// Set collection property.
 	//
@@ -622,47 +664,17 @@
 		dummy = 0;
 		return "";
 	}
-}
 
-// Selector: 780e9d63
-contract ERC721Enumerable is Dummy, ERC165 {
-	// @notice Enumerate valid NFTs
-	// @param index A counter less than `totalSupply()`
-	// @return The token identifier for the `index`th NFT,
-	//  (sort order not specified)
+	// Changes collection owner
 	//
-	// Selector: tokenByIndex(uint256) 4f6ccce7
-	function tokenByIndex(uint256 index) public view returns (uint256) {
-		require(false, stub_error);
-		index;
-		dummy;
-		return 0;
-	}
-
-	// @dev Not implemented
+	// @dev Owner can be changed only by current owner
+	// @param newOwner new owner
 	//
-	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
-	function tokenOfOwnerByIndex(address owner, uint256 index)
-		public
-		view
-		returns (uint256)
-	{
+	// Selector: changeOwner(address) a6f9dae1
+	function changeOwner(address newOwner) public {
 		require(false, stub_error);
-		owner;
-		index;
-		dummy;
-		return 0;
-	}
-
-	// @notice Count NFTs tracked by this contract
-	// @return A count of valid NFTs tracked by this contract, where each one of
-	//  them has an assigned and queryable owner not equal to the zero address
-	//
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
+		newOwner;
+		dummy = 0;
 	}
 }
 
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -371,7 +371,142 @@
 	}
 }
 
-// Selector: 6cf113cd
+// Selector: 780e9d63
+contract ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid RFTs
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
+	// Selector: tokenByIndex(uint256) 4f6ccce7
+	function tokenByIndex(uint256 index) public view returns (uint256) {
+		require(false, stub_error);
+		index;
+		dummy;
+		return 0;
+	}
+
+	// Not implemented
+	//
+	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+	function tokenOfOwnerByIndex(address owner, uint256 index)
+		public
+		view
+		returns (uint256)
+	{
+		require(false, stub_error);
+		owner;
+		index;
+		dummy;
+		return 0;
+	}
+
+	// @notice Count RFTs tracked by this contract
+	// @return A count of valid RFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+}
+
+// Selector: 7c3bef89
+contract ERC721UniqueExtensions is Dummy, ERC165 {
+	// @notice Transfer ownership of an RFT
+	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	//  is the zero address. Throws if `tokenId` is not a valid RFT.
+	//  Throws if RFT pieces have multiple owners.
+	// @param to The new owner
+	// @param tokenId The RFT to transfer
+	// @param _value Not used for an RFT
+	//
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 tokenId) public {
+		require(false, stub_error);
+		to;
+		tokenId;
+		dummy = 0;
+	}
+
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this RFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+	//  Throws if RFT pieces have multiple owners.
+	// @param from The current owner of the RFT
+	// @param tokenId The RFT to transfer
+	// @param _value Not used for an RFT
+	//
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 tokenId) public {
+		require(false, stub_error);
+		from;
+		tokenId;
+		dummy = 0;
+	}
+
+	// @notice Returns next free RFT ID.
+	//
+	// Selector: nextTokenId() 75794a3c
+	function nextTokenId() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+
+	// @notice Function to mint multiple tokens.
+	// @dev `tokenIds` should be an array of consecutive numbers and first number
+	//  should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokenIds IDs of the minted RFTs
+	//
+	// Selector: mintBulk(address,uint256[]) 44a9945e
+	function mintBulk(address to, uint256[] memory tokenIds)
+		public
+		returns (bool)
+	{
+		require(false, stub_error);
+		to;
+		tokenIds;
+		dummy = 0;
+		return false;
+	}
+
+	// @notice Function to mint multiple tokens with the given tokenUris.
+	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	//  numbers and first number should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokens array of pairs of token ID and token URI for minted tokens
+	//
+	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
+	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+		public
+		returns (bool)
+	{
+		require(false, stub_error);
+		to;
+		tokens;
+		dummy = 0;
+		return false;
+	}
+
+	// Returns EVM address for refungible token
+	//
+	// @param token ID of the token
+	//
+	// Selector: tokenContractAddress(uint256) ab76fac6
+	function tokenContractAddress(uint256 token) public view returns (address) {
+		require(false, stub_error);
+		token;
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
+}
+
+// Selector: ca08c92c
 contract Collection is Dummy, ERC165 {
 	// Set collection property.
 	//
@@ -620,140 +755,17 @@
 		dummy = 0;
 		return "";
 	}
-}
 
-// Selector: 780e9d63
-contract ERC721Enumerable is Dummy, ERC165 {
-	// @notice Enumerate valid RFTs
-	// @param index A counter less than `totalSupply()`
-	// @return The token identifier for the `index`th NFT,
-	//  (sort order not specified)
+	// Changes collection owner
 	//
-	// Selector: tokenByIndex(uint256) 4f6ccce7
-	function tokenByIndex(uint256 index) public view returns (uint256) {
-		require(false, stub_error);
-		index;
-		dummy;
-		return 0;
-	}
-
-	// Not implemented
+	// @dev Owner can be changed only by current owner
+	// @param newOwner new owner
 	//
-	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
-	function tokenOfOwnerByIndex(address owner, uint256 index)
-		public
-		view
-		returns (uint256)
-	{
+	// Selector: changeOwner(address) a6f9dae1
+	function changeOwner(address newOwner) public {
 		require(false, stub_error);
-		owner;
-		index;
-		dummy;
-		return 0;
-	}
-
-	// @notice Count RFTs tracked by this contract
-	// @return A count of valid RFTs tracked by this contract, where each one of
-	//  them has an assigned and queryable owner not equal to the zero address
-	//
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-}
-
-// Selector: 7c3bef89
-contract ERC721UniqueExtensions is Dummy, ERC165 {
-	// @notice Transfer ownership of an RFT
-	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	//  is the zero address. Throws if `tokenId` is not a valid RFT.
-	//  Throws if RFT pieces have multiple owners.
-	// @param to The new owner
-	// @param tokenId The RFT to transfer
-	// @param _value Not used for an RFT
-	//
-	// Selector: transfer(address,uint256) a9059cbb
-	function transfer(address to, uint256 tokenId) public {
-		require(false, stub_error);
-		to;
-		tokenId;
-		dummy = 0;
-	}
-
-	// @notice Burns a specific ERC721 token.
-	// @dev Throws unless `msg.sender` is the current owner or an authorized
-	//  operator for this RFT. Throws if `from` is not the current owner. Throws
-	//  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
-	//  Throws if RFT pieces have multiple owners.
-	// @param from The current owner of the RFT
-	// @param tokenId The RFT to transfer
-	// @param _value Not used for an RFT
-	//
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 tokenId) public {
-		require(false, stub_error);
-		from;
-		tokenId;
-		dummy = 0;
-	}
-
-	// @notice Returns next free RFT ID.
-	//
-	// Selector: nextTokenId() 75794a3c
-	function nextTokenId() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	// @notice Function to mint multiple tokens.
-	// @dev `tokenIds` should be an array of consecutive numbers and first number
-	//  should be obtained with `nextTokenId` method
-	// @param to The new owner
-	// @param tokenIds IDs of the minted RFTs
-	//
-	// Selector: mintBulk(address,uint256[]) 44a9945e
-	function mintBulk(address to, uint256[] memory tokenIds)
-		public
-		returns (bool)
-	{
-		require(false, stub_error);
-		to;
-		tokenIds;
-		dummy = 0;
-		return false;
-	}
-
-	// @notice Function to mint multiple tokens with the given tokenUris.
-	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
-	//  numbers and first number should be obtained with `nextTokenId` method
-	// @param to The new owner
-	// @param tokens array of pairs of token ID and token URI for minted tokens
-	//
-	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
-	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
-		public
-		returns (bool)
-	{
-		require(false, stub_error);
-		to;
-		tokens;
+		newOwner;
 		dummy = 0;
-		return false;
-	}
-
-	// Returns EVM address for refungible token
-	//
-	// @param token ID of the token
-	//
-	// Selector: tokenContractAddress(uint256) ab76fac6
-	function tokenContractAddress(uint256 token) public view returns (address) {
-		require(false, stub_error);
-		token;
-		dummy;
-		return 0x0000000000000000000000000000000000000000;
 	}
 }
 
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -22,7 +22,50 @@
 	);
 }
 
-// Selector: 6cf113cd
+// Selector: 79cc6790
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) external returns (bool);
+}
+
+// Selector: 942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+	// Selector: name() 06fdde03
+	function name() external view returns (string memory);
+
+	// Selector: symbol() 95d89b41
+	function symbol() external view returns (string memory);
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() external view returns (uint256);
+
+	// Selector: decimals() 313ce567
+	function decimals() external view returns (uint8);
+
+	// Selector: balanceOf(address) 70a08231
+	function balanceOf(address owner) external view returns (uint256);
+
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 amount) external returns (bool);
+
+	// Selector: transferFrom(address,address,uint256) 23b872dd
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) external returns (bool);
+
+	// Selector: approve(address,uint256) 095ea7b3
+	function approve(address spender, uint256 amount) external returns (bool);
+
+	// Selector: allowance(address,address) dd62ed3e
+	function allowance(address owner, address spender)
+		external
+		view
+		returns (uint256);
+}
+
+// Selector: ca08c92c
 interface Collection is Dummy, ERC165 {
 	// Set collection property.
 	//
@@ -183,49 +226,14 @@
 	//
 	// Selector: uniqueCollectionType() d34b55b8
 	function uniqueCollectionType() external returns (string memory);
-}
 
-// Selector: 79cc6790
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 amount) external returns (bool);
-}
-
-// Selector: 942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
-	// Selector: name() 06fdde03
-	function name() external view returns (string memory);
-
-	// Selector: symbol() 95d89b41
-	function symbol() external view returns (string memory);
-
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() external view returns (uint256);
-
-	// Selector: decimals() 313ce567
-	function decimals() external view returns (uint8);
-
-	// Selector: balanceOf(address) 70a08231
-	function balanceOf(address owner) external view returns (uint256);
-
-	// Selector: transfer(address,uint256) a9059cbb
-	function transfer(address to, uint256 amount) external returns (bool);
-
-	// Selector: transferFrom(address,address,uint256) 23b872dd
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) external returns (bool);
-
-	// Selector: approve(address,uint256) 095ea7b3
-	function approve(address spender, uint256 amount) external returns (bool);
-
-	// Selector: allowance(address,address) dd62ed3e
-	function allowance(address owner, address spender)
-		external
-		view
-		returns (uint256);
+	// Changes collection owner
+	//
+	// @dev Owner can be changed only by current owner
+	// @param newOwner new owner
+	//
+	// Selector: changeOwner(address) a6f9dae1
+	function changeOwner(address newOwner) external;
 }
 
 interface UniqueFungible is
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -250,7 +250,33 @@
 	function finishMinting() external returns (bool);
 }
 
-// Selector: 6cf113cd
+// Selector: 780e9d63
+interface ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid NFTs
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
+	// Selector: tokenByIndex(uint256) 4f6ccce7
+	function tokenByIndex(uint256 index) external view returns (uint256);
+
+	// @dev Not implemented
+	//
+	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+	function tokenOfOwnerByIndex(address owner, uint256 index)
+		external
+		view
+		returns (uint256);
+
+	// @notice Count NFTs tracked by this contract
+	// @return A count of valid NFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() external view returns (uint256);
+}
+
+// Selector: ca08c92c
 interface Collection is Dummy, ERC165 {
 	// Set collection property.
 	//
@@ -411,32 +437,14 @@
 	//
 	// Selector: uniqueCollectionType() d34b55b8
 	function uniqueCollectionType() external returns (string memory);
-}
 
-// Selector: 780e9d63
-interface ERC721Enumerable is Dummy, ERC165 {
-	// @notice Enumerate valid NFTs
-	// @param index A counter less than `totalSupply()`
-	// @return The token identifier for the `index`th NFT,
-	//  (sort order not specified)
+	// Changes collection owner
 	//
-	// Selector: tokenByIndex(uint256) 4f6ccce7
-	function tokenByIndex(uint256 index) external view returns (uint256);
-
-	// @dev Not implemented
+	// @dev Owner can be changed only by current owner
+	// @param newOwner new owner
 	//
-	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
-	function tokenOfOwnerByIndex(address owner, uint256 index)
-		external
-		view
-		returns (uint256);
-
-	// @notice Count NFTs tracked by this contract
-	// @return A count of valid NFTs tracked by this contract, where each one of
-	//  them has an assigned and queryable owner not equal to the zero address
-	//
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() external view returns (uint256);
+	// Selector: changeOwner(address) a6f9dae1
+	function changeOwner(address newOwner) external;
 }
 
 // Selector: d74d154f
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -248,7 +248,96 @@
 	function finishMinting() external returns (bool);
 }
 
-// Selector: 6cf113cd
+// Selector: 780e9d63
+interface ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid RFTs
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
+	// Selector: tokenByIndex(uint256) 4f6ccce7
+	function tokenByIndex(uint256 index) external view returns (uint256);
+
+	// Not implemented
+	//
+	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+	function tokenOfOwnerByIndex(address owner, uint256 index)
+		external
+		view
+		returns (uint256);
+
+	// @notice Count RFTs tracked by this contract
+	// @return A count of valid RFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() external view returns (uint256);
+}
+
+// Selector: 7c3bef89
+interface ERC721UniqueExtensions is Dummy, ERC165 {
+	// @notice Transfer ownership of an RFT
+	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	//  is the zero address. Throws if `tokenId` is not a valid RFT.
+	//  Throws if RFT pieces have multiple owners.
+	// @param to The new owner
+	// @param tokenId The RFT to transfer
+	// @param _value Not used for an RFT
+	//
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 tokenId) external;
+
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this RFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+	//  Throws if RFT pieces have multiple owners.
+	// @param from The current owner of the RFT
+	// @param tokenId The RFT to transfer
+	// @param _value Not used for an RFT
+	//
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 tokenId) external;
+
+	// @notice Returns next free RFT ID.
+	//
+	// Selector: nextTokenId() 75794a3c
+	function nextTokenId() external view returns (uint256);
+
+	// @notice Function to mint multiple tokens.
+	// @dev `tokenIds` should be an array of consecutive numbers and first number
+	//  should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokenIds IDs of the minted RFTs
+	//
+	// Selector: mintBulk(address,uint256[]) 44a9945e
+	function mintBulk(address to, uint256[] memory tokenIds)
+		external
+		returns (bool);
+
+	// @notice Function to mint multiple tokens with the given tokenUris.
+	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	//  numbers and first number should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokens array of pairs of token ID and token URI for minted tokens
+	//
+	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
+	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+		external
+		returns (bool);
+
+	// Returns EVM address for refungible token
+	//
+	// @param token ID of the token
+	//
+	// Selector: tokenContractAddress(uint256) ab76fac6
+	function tokenContractAddress(uint256 token)
+		external
+		view
+		returns (address);
+}
+
+// Selector: ca08c92c
 interface Collection is Dummy, ERC165 {
 	// Set collection property.
 	//
@@ -409,95 +498,14 @@
 	//
 	// Selector: uniqueCollectionType() d34b55b8
 	function uniqueCollectionType() external returns (string memory);
-}
-
-// Selector: 780e9d63
-interface ERC721Enumerable is Dummy, ERC165 {
-	// @notice Enumerate valid RFTs
-	// @param index A counter less than `totalSupply()`
-	// @return The token identifier for the `index`th NFT,
-	//  (sort order not specified)
-	//
-	// Selector: tokenByIndex(uint256) 4f6ccce7
-	function tokenByIndex(uint256 index) external view returns (uint256);
-
-	// Not implemented
-	//
-	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
-	function tokenOfOwnerByIndex(address owner, uint256 index)
-		external
-		view
-		returns (uint256);
-
-	// @notice Count RFTs tracked by this contract
-	// @return A count of valid RFTs tracked by this contract, where each one of
-	//  them has an assigned and queryable owner not equal to the zero address
-	//
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() external view returns (uint256);
-}
 
-// Selector: 7c3bef89
-interface ERC721UniqueExtensions is Dummy, ERC165 {
-	// @notice Transfer ownership of an RFT
-	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	//  is the zero address. Throws if `tokenId` is not a valid RFT.
-	//  Throws if RFT pieces have multiple owners.
-	// @param to The new owner
-	// @param tokenId The RFT to transfer
-	// @param _value Not used for an RFT
-	//
-	// Selector: transfer(address,uint256) a9059cbb
-	function transfer(address to, uint256 tokenId) external;
-
-	// @notice Burns a specific ERC721 token.
-	// @dev Throws unless `msg.sender` is the current owner or an authorized
-	//  operator for this RFT. Throws if `from` is not the current owner. Throws
-	//  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
-	//  Throws if RFT pieces have multiple owners.
-	// @param from The current owner of the RFT
-	// @param tokenId The RFT to transfer
-	// @param _value Not used for an RFT
-	//
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 tokenId) external;
-
-	// @notice Returns next free RFT ID.
-	//
-	// Selector: nextTokenId() 75794a3c
-	function nextTokenId() external view returns (uint256);
-
-	// @notice Function to mint multiple tokens.
-	// @dev `tokenIds` should be an array of consecutive numbers and first number
-	//  should be obtained with `nextTokenId` method
-	// @param to The new owner
-	// @param tokenIds IDs of the minted RFTs
-	//
-	// Selector: mintBulk(address,uint256[]) 44a9945e
-	function mintBulk(address to, uint256[] memory tokenIds)
-		external
-		returns (bool);
-
-	// @notice Function to mint multiple tokens with the given tokenUris.
-	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
-	//  numbers and first number should be obtained with `nextTokenId` method
-	// @param to The new owner
-	// @param tokens array of pairs of token ID and token URI for minted tokens
+	// Changes collection owner
 	//
-	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
-	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
-		external
-		returns (bool);
-
-	// Returns EVM address for refungible token
-	//
-	// @param token ID of the token
+	// @dev Owner can be changed only by current owner
+	// @param newOwner new owner
 	//
-	// Selector: tokenContractAddress(uint256) ab76fac6
-	function tokenContractAddress(uint256 token)
-		external
-		view
-		returns (address);
+	// Selector: changeOwner(address) a6f9dae1
+	function changeOwner(address newOwner) external;
 }
 
 interface UniqueRefungible is
modifiedtests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionAdmin.test.ts
+++ b/tests/src/eth/collectionAdmin.test.ts
@@ -15,6 +15,7 @@
 
 import {expect} from 'chai';
 import privateKey from '../substrate/privateKey';
+import { UNIQUE } from '../util/helpers';
 import {
   createEthAccount,
   createEthAccountWithBalance, 
@@ -22,6 +23,7 @@
   evmCollectionHelpers, 
   getCollectionAddressFromResult, 
   itWeb3,
+  recordEthFee,
 } from './util/helpers';
 
 describe('Add collection admins', () => {
@@ -309,4 +311,51 @@
     expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())
       .to.be.eq(adminSub.address.toLocaleLowerCase());
   });
+});
+
+describe('Change owner tests', () => {
+  itWeb3('Change owner', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const newOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const collectionHelper = evmCollectionHelpers(web3, owner);
+    const result = await collectionHelper.methods
+      .createNonfungibleCollection('A', 'B', 'C')
+      .send();
+    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+  
+    await collectionEvm.methods.changeOwner(newOwner).send();
+  
+    expect(await collectionEvm.methods.verifyOwnerOrAdmin(owner).call()).to.be.false;
+    expect(await collectionEvm.methods.verifyOwnerOrAdmin(newOwner).call()).to.be.true;
+  });
+
+  itWeb3('change owner call fee', async ({web3, api, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const newOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const collectionHelper = evmCollectionHelpers(web3, owner);
+    const result = await collectionHelper.methods
+      .createNonfungibleCollection('A', 'B', 'C')
+      .send();
+    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+
+    const cost = await recordEthFee(api, owner, () => collectionEvm.methods.changeOwner(newOwner).send());
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+    expect(cost > 0);
+  });
+
+  itWeb3('(!negative tests!) call changeOwner by not owner', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const newOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const collectionHelper = evmCollectionHelpers(web3, owner);
+    const result = await collectionHelper.methods
+      .createNonfungibleCollection('A', 'B', 'C')
+      .send();
+    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+  
+    await expect(collectionEvm.methods.changeOwner(newOwner).send({from: newOwner})).to.be.rejected;
+    expect(await collectionEvm.methods.verifyOwnerOrAdmin(newOwner).call()).to.be.false;
+  });
 });
\ No newline at end of file
modifiedtests/src/eth/fungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/fungibleAbi.json
+++ b/tests/src/eth/fungibleAbi.json
@@ -116,6 +116,15 @@
     "type": "function"
   },
   {
+    "inputs": [
+      { "internalType": "address", "name": "newOwner", "type": "address" }
+    ],
+    "name": "changeOwner",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
     "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
     "name": "collectionProperty",
     "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -146,6 +146,15 @@
     "type": "function"
   },
   {
+    "inputs": [
+      { "internalType": "address", "name": "newOwner", "type": "address" }
+    ],
+    "name": "changeOwner",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
     "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
     "name": "collectionProperty",
     "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
modifiedtests/src/eth/reFungibleAbi.jsondiffbeforeafterboth
before · tests/src/eth/reFungibleAbi.json
1[2  {3    "anonymous": false,4    "inputs": [5      {6        "indexed": true,7        "internalType": "address",8        "name": "owner",9        "type": "address"10      },11      {12        "indexed": true,13        "internalType": "address",14        "name": "approved",15        "type": "address"16      },17      {18        "indexed": true,19        "internalType": "uint256",20        "name": "tokenId",21        "type": "uint256"22      }23    ],24    "name": "Approval",25    "type": "event"26  },27  {28    "anonymous": false,29    "inputs": [30      {31        "indexed": true,32        "internalType": "address",33        "name": "owner",34        "type": "address"35      },36      {37        "indexed": true,38        "internalType": "address",39        "name": "operator",40        "type": "address"41      },42      {43        "indexed": false,44        "internalType": "bool",45        "name": "approved",46        "type": "bool"47      }48    ],49    "name": "ApprovalForAll",50    "type": "event"51  },52  {53    "anonymous": false,54    "inputs": [],55    "name": "MintingFinished",56    "type": "event"57  },58  {59    "anonymous": false,60    "inputs": [61      {62        "indexed": true,63        "internalType": "address",64        "name": "from",65        "type": "address"66      },67      {68        "indexed": true,69        "internalType": "address",70        "name": "to",71        "type": "address"72      },73      {74        "indexed": true,75        "internalType": "uint256",76        "name": "tokenId",77        "type": "uint256"78      }79    ],80    "name": "Transfer",81    "type": "event"82  },83  {84    "inputs": [85      { "internalType": "address", "name": "newAdmin", "type": "address" }86    ],87    "name": "addCollectionAdmin",88    "outputs": [],89    "stateMutability": "nonpayable",90    "type": "function"91  },92  {93    "inputs": [94      { "internalType": "uint256", "name": "newAdmin", "type": "uint256" }95    ],96    "name": "addCollectionAdminSubstrate",97    "outputs": [],98    "stateMutability": "nonpayable",99    "type": "function"100  },101  {102    "inputs": [103      { "internalType": "address", "name": "user", "type": "address" }104    ],105    "name": "addToCollectionAllowList",106    "outputs": [],107    "stateMutability": "nonpayable",108    "type": "function"109  },110  {111    "inputs": [112      { "internalType": "address", "name": "approved", "type": "address" },113      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }114    ],115    "name": "approve",116    "outputs": [],117    "stateMutability": "nonpayable",118    "type": "function"119  },120  {121    "inputs": [122      { "internalType": "address", "name": "owner", "type": "address" }123    ],124    "name": "balanceOf",125    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],126    "stateMutability": "view",127    "type": "function"128  },129  {130    "inputs": [131      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }132    ],133    "name": "burn",134    "outputs": [],135    "stateMutability": "nonpayable",136    "type": "function"137  },138  {139    "inputs": [140      { "internalType": "address", "name": "from", "type": "address" },141      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }142    ],143    "name": "burnFrom",144    "outputs": [],145    "stateMutability": "nonpayable",146    "type": "function"147  },148  {149    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],150    "name": "collectionProperty",151    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],152    "stateMutability": "view",153    "type": "function"154  },155  {156    "inputs": [],157    "name": "confirmCollectionSponsorship",158    "outputs": [],159    "stateMutability": "nonpayable",160    "type": "function"161  },162  {163    "inputs": [],164    "name": "contractAddress",165    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],166    "stateMutability": "view",167    "type": "function"168  },169  {170    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],171    "name": "deleteCollectionProperty",172    "outputs": [],173    "stateMutability": "nonpayable",174    "type": "function"175  },176  {177    "inputs": [178      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },179      { "internalType": "string", "name": "key", "type": "string" }180    ],181    "name": "deleteProperty",182    "outputs": [],183    "stateMutability": "nonpayable",184    "type": "function"185  },186  {187    "inputs": [],188    "name": "finishMinting",189    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],190    "stateMutability": "nonpayable",191    "type": "function"192  },193  {194    "inputs": [195      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }196    ],197    "name": "getApproved",198    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],199    "stateMutability": "view",200    "type": "function"201  },202  {203    "inputs": [204      { "internalType": "address", "name": "owner", "type": "address" },205      { "internalType": "address", "name": "operator", "type": "address" }206    ],207    "name": "isApprovedForAll",208    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],209    "stateMutability": "view",210    "type": "function"211  },212  {213    "inputs": [214      { "internalType": "address", "name": "to", "type": "address" },215      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }216    ],217    "name": "mint",218    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],219    "stateMutability": "nonpayable",220    "type": "function"221  },222  {223    "inputs": [224      { "internalType": "address", "name": "to", "type": "address" },225      { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }226    ],227    "name": "mintBulk",228    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],229    "stateMutability": "nonpayable",230    "type": "function"231  },232  {233    "inputs": [234      { "internalType": "address", "name": "to", "type": "address" },235      {236        "components": [237          { "internalType": "uint256", "name": "field_0", "type": "uint256" },238          { "internalType": "string", "name": "field_1", "type": "string" }239        ],240        "internalType": "struct Tuple0[]",241        "name": "tokens",242        "type": "tuple[]"243      }244    ],245    "name": "mintBulkWithTokenURI",246    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],247    "stateMutability": "nonpayable",248    "type": "function"249  },250  {251    "inputs": [252      { "internalType": "address", "name": "to", "type": "address" },253      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },254      { "internalType": "string", "name": "tokenUri", "type": "string" }255    ],256    "name": "mintWithTokenURI",257    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],258    "stateMutability": "nonpayable",259    "type": "function"260  },261  {262    "inputs": [],263    "name": "mintingFinished",264    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],265    "stateMutability": "view",266    "type": "function"267  },268  {269    "inputs": [],270    "name": "name",271    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],272    "stateMutability": "view",273    "type": "function"274  },275  {276    "inputs": [],277    "name": "nextTokenId",278    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],279    "stateMutability": "view",280    "type": "function"281  },282  {283    "inputs": [284      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }285    ],286    "name": "ownerOf",287    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],288    "stateMutability": "view",289    "type": "function"290  },291  {292    "inputs": [293      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },294      { "internalType": "string", "name": "key", "type": "string" }295    ],296    "name": "property",297    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],298    "stateMutability": "view",299    "type": "function"300  },301  {302    "inputs": [303      { "internalType": "address", "name": "admin", "type": "address" }304    ],305    "name": "removeCollectionAdmin",306    "outputs": [],307    "stateMutability": "nonpayable",308    "type": "function"309  },310  {311    "inputs": [312      { "internalType": "uint256", "name": "admin", "type": "uint256" }313    ],314    "name": "removeCollectionAdminSubstrate",315    "outputs": [],316    "stateMutability": "nonpayable",317    "type": "function"318  },319  {320    "inputs": [321      { "internalType": "address", "name": "user", "type": "address" }322    ],323    "name": "removeFromCollectionAllowList",324    "outputs": [],325    "stateMutability": "nonpayable",326    "type": "function"327  },328  {329    "inputs": [330      { "internalType": "address", "name": "from", "type": "address" },331      { "internalType": "address", "name": "to", "type": "address" },332      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }333    ],334    "name": "safeTransferFrom",335    "outputs": [],336    "stateMutability": "nonpayable",337    "type": "function"338  },339  {340    "inputs": [341      { "internalType": "address", "name": "from", "type": "address" },342      { "internalType": "address", "name": "to", "type": "address" },343      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },344      { "internalType": "bytes", "name": "data", "type": "bytes" }345    ],346    "name": "safeTransferFromWithData",347    "outputs": [],348    "stateMutability": "nonpayable",349    "type": "function"350  },351  {352    "inputs": [353      { "internalType": "address", "name": "operator", "type": "address" },354      { "internalType": "bool", "name": "approved", "type": "bool" }355    ],356    "name": "setApprovalForAll",357    "outputs": [],358    "stateMutability": "nonpayable",359    "type": "function"360  },361  {362    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],363    "name": "setCollectionAccess",364    "outputs": [],365    "stateMutability": "nonpayable",366    "type": "function"367  },368  {369    "inputs": [370      { "internalType": "string", "name": "limit", "type": "string" },371      { "internalType": "uint32", "name": "value", "type": "uint32" }372    ],373    "name": "setCollectionLimit",374    "outputs": [],375    "stateMutability": "nonpayable",376    "type": "function"377  },378  {379    "inputs": [380      { "internalType": "string", "name": "limit", "type": "string" },381      { "internalType": "bool", "name": "value", "type": "bool" }382    ],383    "name": "setCollectionLimit",384    "outputs": [],385    "stateMutability": "nonpayable",386    "type": "function"387  },388  {389    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],390    "name": "setCollectionMintMode",391    "outputs": [],392    "stateMutability": "nonpayable",393    "type": "function"394  },395  {396    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],397    "name": "setCollectionNesting",398    "outputs": [],399    "stateMutability": "nonpayable",400    "type": "function"401  },402  {403    "inputs": [404      { "internalType": "bool", "name": "enable", "type": "bool" },405      {406        "internalType": "address[]",407        "name": "collections",408        "type": "address[]"409      }410    ],411    "name": "setCollectionNesting",412    "outputs": [],413    "stateMutability": "nonpayable",414    "type": "function"415  },416  {417    "inputs": [418      { "internalType": "string", "name": "key", "type": "string" },419      { "internalType": "bytes", "name": "value", "type": "bytes" }420    ],421    "name": "setCollectionProperty",422    "outputs": [],423    "stateMutability": "nonpayable",424    "type": "function"425  },426  {427    "inputs": [428      { "internalType": "address", "name": "sponsor", "type": "address" }429    ],430    "name": "setCollectionSponsor",431    "outputs": [],432    "stateMutability": "nonpayable",433    "type": "function"434  },435  {436    "inputs": [437      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },438      { "internalType": "string", "name": "key", "type": "string" },439      { "internalType": "bytes", "name": "value", "type": "bytes" }440    ],441    "name": "setProperty",442    "outputs": [],443    "stateMutability": "nonpayable",444    "type": "function"445  },446  {447    "inputs": [448      { "internalType": "string", "name": "key", "type": "string" },449      { "internalType": "bool", "name": "isMutable", "type": "bool" },450      { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },451      { "internalType": "bool", "name": "tokenOwner", "type": "bool" }452    ],453    "name": "setTokenPropertyPermission",454    "outputs": [],455    "stateMutability": "nonpayable",456    "type": "function"457  },458  {459    "inputs": [460      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }461    ],462    "name": "supportsInterface",463    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],464    "stateMutability": "view",465    "type": "function"466  },467  {468    "inputs": [],469    "name": "symbol",470    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],471    "stateMutability": "view",472    "type": "function"473  },474  {475    "inputs": [476      { "internalType": "uint256", "name": "index", "type": "uint256" }477    ],478    "name": "tokenByIndex",479    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],480    "stateMutability": "view",481    "type": "function"482  },483  {484    "inputs": [485      { "internalType": "uint256", "name": "token", "type": "uint256" }486    ],487    "name": "tokenContractAddress",488    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],489    "stateMutability": "view",490    "type": "function"491  },492  {493    "inputs": [494      { "internalType": "address", "name": "owner", "type": "address" },495      { "internalType": "uint256", "name": "index", "type": "uint256" }496    ],497    "name": "tokenOfOwnerByIndex",498    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],499    "stateMutability": "view",500    "type": "function"501  },502  {503    "inputs": [504      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }505    ],506    "name": "tokenURI",507    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],508    "stateMutability": "view",509    "type": "function"510  },511  {512    "inputs": [],513    "name": "totalSupply",514    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],515    "stateMutability": "view",516    "type": "function"517  },518  {519    "inputs": [520      { "internalType": "address", "name": "to", "type": "address" },521      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }522    ],523    "name": "transfer",524    "outputs": [],525    "stateMutability": "nonpayable",526    "type": "function"527  },528  {529    "inputs": [530      { "internalType": "address", "name": "from", "type": "address" },531      { "internalType": "address", "name": "to", "type": "address" },532      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }533    ],534    "name": "transferFrom",535    "outputs": [],536    "stateMutability": "nonpayable",537    "type": "function"538  },539  {540    "inputs": [],541    "name": "uniqueCollectionType",542    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],543    "stateMutability": "nonpayable",544    "type": "function"545  },546  {547    "inputs": [548      { "internalType": "address", "name": "user", "type": "address" }549    ],550    "name": "verifyOwnerOrAdmin",551    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],552    "stateMutability": "view",553    "type": "function"554  }555]
after · tests/src/eth/reFungibleAbi.json
1[2  {3    "anonymous": false,4    "inputs": [5      {6        "indexed": true,7        "internalType": "address",8        "name": "owner",9        "type": "address"10      },11      {12        "indexed": true,13        "internalType": "address",14        "name": "approved",15        "type": "address"16      },17      {18        "indexed": true,19        "internalType": "uint256",20        "name": "tokenId",21        "type": "uint256"22      }23    ],24    "name": "Approval",25    "type": "event"26  },27  {28    "anonymous": false,29    "inputs": [30      {31        "indexed": true,32        "internalType": "address",33        "name": "owner",34        "type": "address"35      },36      {37        "indexed": true,38        "internalType": "address",39        "name": "operator",40        "type": "address"41      },42      {43        "indexed": false,44        "internalType": "bool",45        "name": "approved",46        "type": "bool"47      }48    ],49    "name": "ApprovalForAll",50    "type": "event"51  },52  {53    "anonymous": false,54    "inputs": [],55    "name": "MintingFinished",56    "type": "event"57  },58  {59    "anonymous": false,60    "inputs": [61      {62        "indexed": true,63        "internalType": "address",64        "name": "from",65        "type": "address"66      },67      {68        "indexed": true,69        "internalType": "address",70        "name": "to",71        "type": "address"72      },73      {74        "indexed": true,75        "internalType": "uint256",76        "name": "tokenId",77        "type": "uint256"78      }79    ],80    "name": "Transfer",81    "type": "event"82  },83  {84    "inputs": [85      { "internalType": "address", "name": "newAdmin", "type": "address" }86    ],87    "name": "addCollectionAdmin",88    "outputs": [],89    "stateMutability": "nonpayable",90    "type": "function"91  },92  {93    "inputs": [94      { "internalType": "uint256", "name": "newAdmin", "type": "uint256" }95    ],96    "name": "addCollectionAdminSubstrate",97    "outputs": [],98    "stateMutability": "nonpayable",99    "type": "function"100  },101  {102    "inputs": [103      { "internalType": "address", "name": "user", "type": "address" }104    ],105    "name": "addToCollectionAllowList",106    "outputs": [],107    "stateMutability": "nonpayable",108    "type": "function"109  },110  {111    "inputs": [112      { "internalType": "address", "name": "approved", "type": "address" },113      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }114    ],115    "name": "approve",116    "outputs": [],117    "stateMutability": "nonpayable",118    "type": "function"119  },120  {121    "inputs": [122      { "internalType": "address", "name": "owner", "type": "address" }123    ],124    "name": "balanceOf",125    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],126    "stateMutability": "view",127    "type": "function"128  },129  {130    "inputs": [131      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }132    ],133    "name": "burn",134    "outputs": [],135    "stateMutability": "nonpayable",136    "type": "function"137  },138  {139    "inputs": [140      { "internalType": "address", "name": "from", "type": "address" },141      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }142    ],143    "name": "burnFrom",144    "outputs": [],145    "stateMutability": "nonpayable",146    "type": "function"147  },148  {149    "inputs": [150      { "internalType": "address", "name": "newOwner", "type": "address" }151    ],152    "name": "changeOwner",153    "outputs": [],154    "stateMutability": "nonpayable",155    "type": "function"156  },157  {158    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],159    "name": "collectionProperty",160    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],161    "stateMutability": "view",162    "type": "function"163  },164  {165    "inputs": [],166    "name": "confirmCollectionSponsorship",167    "outputs": [],168    "stateMutability": "nonpayable",169    "type": "function"170  },171  {172    "inputs": [],173    "name": "contractAddress",174    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],175    "stateMutability": "view",176    "type": "function"177  },178  {179    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],180    "name": "deleteCollectionProperty",181    "outputs": [],182    "stateMutability": "nonpayable",183    "type": "function"184  },185  {186    "inputs": [187      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },188      { "internalType": "string", "name": "key", "type": "string" }189    ],190    "name": "deleteProperty",191    "outputs": [],192    "stateMutability": "nonpayable",193    "type": "function"194  },195  {196    "inputs": [],197    "name": "finishMinting",198    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],199    "stateMutability": "nonpayable",200    "type": "function"201  },202  {203    "inputs": [204      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }205    ],206    "name": "getApproved",207    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],208    "stateMutability": "view",209    "type": "function"210  },211  {212    "inputs": [213      { "internalType": "address", "name": "owner", "type": "address" },214      { "internalType": "address", "name": "operator", "type": "address" }215    ],216    "name": "isApprovedForAll",217    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],218    "stateMutability": "view",219    "type": "function"220  },221  {222    "inputs": [223      { "internalType": "address", "name": "to", "type": "address" },224      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }225    ],226    "name": "mint",227    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],228    "stateMutability": "nonpayable",229    "type": "function"230  },231  {232    "inputs": [233      { "internalType": "address", "name": "to", "type": "address" },234      { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }235    ],236    "name": "mintBulk",237    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],238    "stateMutability": "nonpayable",239    "type": "function"240  },241  {242    "inputs": [243      { "internalType": "address", "name": "to", "type": "address" },244      {245        "components": [246          { "internalType": "uint256", "name": "field_0", "type": "uint256" },247          { "internalType": "string", "name": "field_1", "type": "string" }248        ],249        "internalType": "struct Tuple0[]",250        "name": "tokens",251        "type": "tuple[]"252      }253    ],254    "name": "mintBulkWithTokenURI",255    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],256    "stateMutability": "nonpayable",257    "type": "function"258  },259  {260    "inputs": [261      { "internalType": "address", "name": "to", "type": "address" },262      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },263      { "internalType": "string", "name": "tokenUri", "type": "string" }264    ],265    "name": "mintWithTokenURI",266    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],267    "stateMutability": "nonpayable",268    "type": "function"269  },270  {271    "inputs": [],272    "name": "mintingFinished",273    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],274    "stateMutability": "view",275    "type": "function"276  },277  {278    "inputs": [],279    "name": "name",280    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],281    "stateMutability": "view",282    "type": "function"283  },284  {285    "inputs": [],286    "name": "nextTokenId",287    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],288    "stateMutability": "view",289    "type": "function"290  },291  {292    "inputs": [293      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }294    ],295    "name": "ownerOf",296    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],297    "stateMutability": "view",298    "type": "function"299  },300  {301    "inputs": [302      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },303      { "internalType": "string", "name": "key", "type": "string" }304    ],305    "name": "property",306    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],307    "stateMutability": "view",308    "type": "function"309  },310  {311    "inputs": [312      { "internalType": "address", "name": "admin", "type": "address" }313    ],314    "name": "removeCollectionAdmin",315    "outputs": [],316    "stateMutability": "nonpayable",317    "type": "function"318  },319  {320    "inputs": [321      { "internalType": "uint256", "name": "admin", "type": "uint256" }322    ],323    "name": "removeCollectionAdminSubstrate",324    "outputs": [],325    "stateMutability": "nonpayable",326    "type": "function"327  },328  {329    "inputs": [330      { "internalType": "address", "name": "user", "type": "address" }331    ],332    "name": "removeFromCollectionAllowList",333    "outputs": [],334    "stateMutability": "nonpayable",335    "type": "function"336  },337  {338    "inputs": [339      { "internalType": "address", "name": "from", "type": "address" },340      { "internalType": "address", "name": "to", "type": "address" },341      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }342    ],343    "name": "safeTransferFrom",344    "outputs": [],345    "stateMutability": "nonpayable",346    "type": "function"347  },348  {349    "inputs": [350      { "internalType": "address", "name": "from", "type": "address" },351      { "internalType": "address", "name": "to", "type": "address" },352      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },353      { "internalType": "bytes", "name": "data", "type": "bytes" }354    ],355    "name": "safeTransferFromWithData",356    "outputs": [],357    "stateMutability": "nonpayable",358    "type": "function"359  },360  {361    "inputs": [362      { "internalType": "address", "name": "operator", "type": "address" },363      { "internalType": "bool", "name": "approved", "type": "bool" }364    ],365    "name": "setApprovalForAll",366    "outputs": [],367    "stateMutability": "nonpayable",368    "type": "function"369  },370  {371    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],372    "name": "setCollectionAccess",373    "outputs": [],374    "stateMutability": "nonpayable",375    "type": "function"376  },377  {378    "inputs": [379      { "internalType": "string", "name": "limit", "type": "string" },380      { "internalType": "uint32", "name": "value", "type": "uint32" }381    ],382    "name": "setCollectionLimit",383    "outputs": [],384    "stateMutability": "nonpayable",385    "type": "function"386  },387  {388    "inputs": [389      { "internalType": "string", "name": "limit", "type": "string" },390      { "internalType": "bool", "name": "value", "type": "bool" }391    ],392    "name": "setCollectionLimit",393    "outputs": [],394    "stateMutability": "nonpayable",395    "type": "function"396  },397  {398    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],399    "name": "setCollectionMintMode",400    "outputs": [],401    "stateMutability": "nonpayable",402    "type": "function"403  },404  {405    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],406    "name": "setCollectionNesting",407    "outputs": [],408    "stateMutability": "nonpayable",409    "type": "function"410  },411  {412    "inputs": [413      { "internalType": "bool", "name": "enable", "type": "bool" },414      {415        "internalType": "address[]",416        "name": "collections",417        "type": "address[]"418      }419    ],420    "name": "setCollectionNesting",421    "outputs": [],422    "stateMutability": "nonpayable",423    "type": "function"424  },425  {426    "inputs": [427      { "internalType": "string", "name": "key", "type": "string" },428      { "internalType": "bytes", "name": "value", "type": "bytes" }429    ],430    "name": "setCollectionProperty",431    "outputs": [],432    "stateMutability": "nonpayable",433    "type": "function"434  },435  {436    "inputs": [437      { "internalType": "address", "name": "sponsor", "type": "address" }438    ],439    "name": "setCollectionSponsor",440    "outputs": [],441    "stateMutability": "nonpayable",442    "type": "function"443  },444  {445    "inputs": [446      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },447      { "internalType": "string", "name": "key", "type": "string" },448      { "internalType": "bytes", "name": "value", "type": "bytes" }449    ],450    "name": "setProperty",451    "outputs": [],452    "stateMutability": "nonpayable",453    "type": "function"454  },455  {456    "inputs": [457      { "internalType": "string", "name": "key", "type": "string" },458      { "internalType": "bool", "name": "isMutable", "type": "bool" },459      { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },460      { "internalType": "bool", "name": "tokenOwner", "type": "bool" }461    ],462    "name": "setTokenPropertyPermission",463    "outputs": [],464    "stateMutability": "nonpayable",465    "type": "function"466  },467  {468    "inputs": [469      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }470    ],471    "name": "supportsInterface",472    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],473    "stateMutability": "view",474    "type": "function"475  },476  {477    "inputs": [],478    "name": "symbol",479    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],480    "stateMutability": "view",481    "type": "function"482  },483  {484    "inputs": [485      { "internalType": "uint256", "name": "index", "type": "uint256" }486    ],487    "name": "tokenByIndex",488    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],489    "stateMutability": "view",490    "type": "function"491  },492  {493    "inputs": [494      { "internalType": "uint256", "name": "token", "type": "uint256" }495    ],496    "name": "tokenContractAddress",497    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],498    "stateMutability": "view",499    "type": "function"500  },501  {502    "inputs": [503      { "internalType": "address", "name": "owner", "type": "address" },504      { "internalType": "uint256", "name": "index", "type": "uint256" }505    ],506    "name": "tokenOfOwnerByIndex",507    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],508    "stateMutability": "view",509    "type": "function"510  },511  {512    "inputs": [513      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }514    ],515    "name": "tokenURI",516    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],517    "stateMutability": "view",518    "type": "function"519  },520  {521    "inputs": [],522    "name": "totalSupply",523    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],524    "stateMutability": "view",525    "type": "function"526  },527  {528    "inputs": [529      { "internalType": "address", "name": "to", "type": "address" },530      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }531    ],532    "name": "transfer",533    "outputs": [],534    "stateMutability": "nonpayable",535    "type": "function"536  },537  {538    "inputs": [539      { "internalType": "address", "name": "from", "type": "address" },540      { "internalType": "address", "name": "to", "type": "address" },541      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }542    ],543    "name": "transferFrom",544    "outputs": [],545    "stateMutability": "nonpayable",546    "type": "function"547  },548  {549    "inputs": [],550    "name": "uniqueCollectionType",551    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],552    "stateMutability": "nonpayable",553    "type": "function"554  },555  {556    "inputs": [557      { "internalType": "address", "name": "user", "type": "address" }558    ],559    "name": "verifyOwnerOrAdmin",560    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],561    "stateMutability": "view",562    "type": "function"563  }564]