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

difftreelog

misk: Move TokenChanged event into ERC721 contracts

Trubnikov Sergey2023-02-02parent: #3563d09.patch.diff
in: master

16 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -26,7 +26,6 @@
 };
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_std::{vec, vec::Vec};
-use sp_core::U256;
 use up_data_structs::{
 	CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property, SponsoringRateLimit,
 	SponsorshipState,
@@ -62,18 +61,9 @@
 	},
 	/// The collection has been changed.
 	CollectionChanged {
-		/// Collection ID.
-		#[indexed]
-		collection_id: Address,
-	},
-
-	/// The token has been changed.
-	TokenChanged {
 		/// Collection ID.
 		#[indexed]
 		collection_id: Address,
-		/// Token ID.
-		token_id: U256,
 	},
 }
 
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1250,6 +1250,7 @@
 		mut stored_properties: Properties,
 		is_token_owner: impl Fn() -> Result<bool, DispatchError>,
 		set_token_properties: impl FnOnce(Properties),
+		log: evm_coder::ethereum::Log,
 	) -> DispatchResult {
 		let is_collection_admin = collection.is_owner_or_admin(sender);
 		let permissions = Self::property_permissions(collection.id);
@@ -1304,13 +1305,7 @@
 				}
 			}
 
-			<PalletEvm<T>>::deposit_log(
-				CollectionHelpersEvents::TokenChanged {
-					collection_id: eth::collection_id_to_address(collection.id),
-					token_id: token_id.into(),
-				}
-				.to_log(T::ContractAddress::get()),
-			);
+			<PalletEvm<T>>::deposit_log(log.clone());
 		}
 
 		set_token_properties(stored_properties);
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -50,13 +50,26 @@
 	TokenProperties, SelfWeightOf, weights::WeightInfo,
 };
 
+/// Nft events.
+#[derive(ToLog)]
+pub enum ERC721TokenEvent {
+	/// The token has been changed.
+	TokenChanged {
+		/// Collection ID.
+		#[indexed]
+		collection_id: Address,
+		/// Token ID.
+		token_id: U256,
+	},
+}
+
 frontier_contract! {
 	macro_rules! NonfungibleHandle_result {...}
 	impl<T: Config> Contract for NonfungibleHandle<T> {...}
 }
 
 /// @title A contract that allows to set and delete token properties and change token property permissions.
-#[solidity_interface(name = TokenProperties, enum(derive(PreDispatch)), enum_attr(weight))]
+#[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))]
 impl<T: Config> NonfungibleHandle<T> {
 	/// @notice Set permissions for token property.
 	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -112,7 +112,7 @@
 };
 use pallet_structure::{Pallet as PalletStructure, Error as StructureError};
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
-use sp_core::H160;
+use sp_core::{Get, H160};
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
 use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
 use core::ops::Deref;
@@ -622,6 +622,11 @@
 			stored_properties,
 			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/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -17,9 +17,14 @@
 	}
 }
 
+/// @dev inlined interface
+contract ERC721TokenEvent {
+	event TokenChanged(address indexed collectionId, uint256 tokenId);
+}
+
 /// @title A contract that allows to set and delete token properties and change token property permissions.
 /// @dev the ERC-165 identifier for this interface is 0xde0695c2
-contract TokenProperties is Dummy, ERC165 {
+contract TokenProperties is Dummy, ERC165, ERC721TokenEvent {
 	// /// @notice Set permissions for token property.
 	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
 	// /// @param key Property key.
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -59,8 +59,21 @@
 
 pub const ADDRESS_FOR_PARTIALLY_OWNED_TOKENS: H160 = H160::repeat_byte(0xff);
 
+/// Rft events.
+#[derive(ToLog)]
+pub enum ERC721TokenEvent {
+	/// The token has been changed.
+	TokenChanged {
+		/// Collection ID.
+		#[indexed]
+		collection_id: Address,
+		/// Token ID.
+		token_id: U256,
+	},
+}
+
 /// @title A contract that allows to set and delete token properties and change token property permissions.
-#[solidity_interface(name = TokenProperties, enum(derive(PreDispatch)), enum_attr(weight))]
+#[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))]
 impl<T: Config> RefungibleHandle<T> {
 	/// @notice Set permissions for token property.
 	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -100,7 +100,7 @@
 	Event as CommonEvent, Pallet as PalletCommon,
 };
 use pallet_structure::Pallet as PalletStructure;
-use sp_core::H160;
+use sp_core::{Get, H160};
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
 use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
 use up_data_structs::{
@@ -571,6 +571,11 @@
 			stored_properties,
 			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/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -17,9 +17,14 @@
 	}
 }
 
+/// @dev inlined interface
+contract ERC721TokenEvent {
+	event TokenChanged(address indexed collectionId, uint256 tokenId);
+}
+
 /// @title A contract that allows to set and delete token properties and change token property permissions.
 /// @dev the ERC-165 identifier for this interface is 0xde0695c2
-contract TokenProperties is Dummy, ERC165 {
+contract TokenProperties is Dummy, ERC165, ERC721TokenEvent {
 	// /// @notice Set permissions for token property.
 	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
 	// /// @param key Property key.
modifiedpallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth
before · pallets/unique/src/eth/stubs/CollectionHelpers.sol
1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56/// @dev common stubs holder7contract Dummy {8	uint8 dummy;9	string stub_error = "this contract is implemented in native";10}1112contract ERC165 is Dummy {13	function supportsInterface(bytes4 interfaceID) external view returns (bool) {14		require(false, stub_error);15		interfaceID;16		return true;17	}18}1920/// @dev inlined interface21contract CollectionHelpersEvents {22	event CollectionCreated(address indexed owner, address indexed collectionId);23	event CollectionDestroyed(address indexed collectionId);24	event CollectionChanged(address indexed collectionId);25	event TokenChanged(address indexed collectionId, uint256 tokenId);26}2728/// @title Contract, which allows users to operate with collections29/// @dev the ERC-165 identifier for this interface is 0xe65011aa30contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {31	/// Create an NFT collection32	/// @param name Name of the collection33	/// @param description Informative description of the collection34	/// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications35	/// @return address Address of the newly created collection36	/// @dev EVM selector for this function is: 0x844af658,37	///  or in textual repr: createNFTCollection(string,string,string)38	function createNFTCollection(39		string memory name,40		string memory description,41		string memory tokenPrefix42	) public payable returns (address) {43		require(false, stub_error);44		name;45		description;46		tokenPrefix;47		dummy = 0;48		return 0x0000000000000000000000000000000000000000;49	}5051	// /// Create an NFT collection52	// /// @param name Name of the collection53	// /// @param description Informative description of the collection54	// /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications55	// /// @return address Address of the newly created collection56	// /// @dev EVM selector for this function is: 0xe34a6844,57	// ///  or in textual repr: createNonfungibleCollection(string,string,string)58	// function createNonfungibleCollection(string memory name, string memory description, string memory tokenPrefix) public payable returns (address) {59	// 	require(false, stub_error);60	// 	name;61	// 	description;62	// 	tokenPrefix;63	// 	dummy = 0;64	// 	return 0x0000000000000000000000000000000000000000;65	// }6667	/// @dev EVM selector for this function is: 0xab173450,68	///  or in textual repr: createRFTCollection(string,string,string)69	function createRFTCollection(70		string memory name,71		string memory description,72		string memory tokenPrefix73	) public payable returns (address) {74		require(false, stub_error);75		name;76		description;77		tokenPrefix;78		dummy = 0;79		return 0x0000000000000000000000000000000000000000;80	}8182	/// @dev EVM selector for this function is: 0x7335b79f,83	///  or in textual repr: createFTCollection(string,uint8,string,string)84	function createFTCollection(85		string memory name,86		uint8 decimals,87		string memory description,88		string memory tokenPrefix89	) public payable returns (address) {90		require(false, stub_error);91		name;92		decimals;93		description;94		tokenPrefix;95		dummy = 0;96		return 0x0000000000000000000000000000000000000000;97	}9899	/// @dev EVM selector for this function is: 0x85624258,100	///  or in textual repr: makeCollectionERC721MetadataCompatible(address,string)101	function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) public {102		require(false, stub_error);103		collection;104		baseUri;105		dummy = 0;106	}107108	/// @dev EVM selector for this function is: 0x564e321f,109	///  or in textual repr: destroyCollection(address)110	function destroyCollection(address collectionAddress) public {111		require(false, stub_error);112		collectionAddress;113		dummy = 0;114	}115116	/// Check if a collection exists117	/// @param collectionAddress Address of the collection in question118	/// @return bool Does the collection exist?119	/// @dev EVM selector for this function is: 0xc3de1494,120	///  or in textual repr: isCollectionExist(address)121	function isCollectionExist(address collectionAddress) public view returns (bool) {122		require(false, stub_error);123		collectionAddress;124		dummy;125		return false;126	}127128	/// @dev EVM selector for this function is: 0xd23a7ab1,129	///  or in textual repr: collectionCreationFee()130	function collectionCreationFee() public view returns (uint256) {131		require(false, stub_error);132		dummy;133		return 0;134	}135136	/// Returns address of a collection.137	/// @param collectionId  - CollectionId  of the collection138	/// @return eth mirror address of the collection139	/// @dev EVM selector for this function is: 0x2e716683,140	///  or in textual repr: collectionAddress(uint32)141	function collectionAddress(uint32 collectionId) public view returns (address) {142		require(false, stub_error);143		collectionId;144		dummy;145		return 0x0000000000000000000000000000000000000000;146	}147148	/// Returns collectionId of a collection.149	/// @param collectionAddress  - Eth address of the collection150	/// @return collectionId of the collection151	/// @dev EVM selector for this function is: 0xb5cb7498,152	///  or in textual repr: collectionId(address)153	function collectionId(address collectionAddress) public view returns (uint32) {154		require(false, stub_error);155		collectionAddress;156		dummy;157		return 0;158	}159}
after · pallets/unique/src/eth/stubs/CollectionHelpers.sol
1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56/// @dev common stubs holder7contract Dummy {8	uint8 dummy;9	string stub_error = "this contract is implemented in native";10}1112contract ERC165 is Dummy {13	function supportsInterface(bytes4 interfaceID) external view returns (bool) {14		require(false, stub_error);15		interfaceID;16		return true;17	}18}1920/// @dev inlined interface21contract CollectionHelpersEvents {22	event CollectionCreated(address indexed owner, address indexed collectionId);23	event CollectionDestroyed(address indexed collectionId);24	event CollectionChanged(address indexed collectionId);25}2627/// @title Contract, which allows users to operate with collections28/// @dev the ERC-165 identifier for this interface is 0xe65011aa29contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {30	/// Create an NFT collection31	/// @param name Name of the collection32	/// @param description Informative description of the collection33	/// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications34	/// @return address Address of the newly created collection35	/// @dev EVM selector for this function is: 0x844af658,36	///  or in textual repr: createNFTCollection(string,string,string)37	function createNFTCollection(38		string memory name,39		string memory description,40		string memory tokenPrefix41	) public payable returns (address) {42		require(false, stub_error);43		name;44		description;45		tokenPrefix;46		dummy = 0;47		return 0x0000000000000000000000000000000000000000;48	}4950	// /// Create an NFT collection51	// /// @param name Name of the collection52	// /// @param description Informative description of the collection53	// /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications54	// /// @return address Address of the newly created collection55	// /// @dev EVM selector for this function is: 0xe34a6844,56	// ///  or in textual repr: createNonfungibleCollection(string,string,string)57	// function createNonfungibleCollection(string memory name, string memory description, string memory tokenPrefix) public payable returns (address) {58	// 	require(false, stub_error);59	// 	name;60	// 	description;61	// 	tokenPrefix;62	// 	dummy = 0;63	// 	return 0x0000000000000000000000000000000000000000;64	// }6566	/// @dev EVM selector for this function is: 0xab173450,67	///  or in textual repr: createRFTCollection(string,string,string)68	function createRFTCollection(69		string memory name,70		string memory description,71		string memory tokenPrefix72	) public payable returns (address) {73		require(false, stub_error);74		name;75		description;76		tokenPrefix;77		dummy = 0;78		return 0x0000000000000000000000000000000000000000;79	}8081	/// @dev EVM selector for this function is: 0x7335b79f,82	///  or in textual repr: createFTCollection(string,uint8,string,string)83	function createFTCollection(84		string memory name,85		uint8 decimals,86		string memory description,87		string memory tokenPrefix88	) public payable returns (address) {89		require(false, stub_error);90		name;91		decimals;92		description;93		tokenPrefix;94		dummy = 0;95		return 0x0000000000000000000000000000000000000000;96	}9798	/// @dev EVM selector for this function is: 0x85624258,99	///  or in textual repr: makeCollectionERC721MetadataCompatible(address,string)100	function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) public {101		require(false, stub_error);102		collection;103		baseUri;104		dummy = 0;105	}106107	/// @dev EVM selector for this function is: 0x564e321f,108	///  or in textual repr: destroyCollection(address)109	function destroyCollection(address collectionAddress) public {110		require(false, stub_error);111		collectionAddress;112		dummy = 0;113	}114115	/// Check if a collection exists116	/// @param collectionAddress Address of the collection in question117	/// @return bool Does the collection exist?118	/// @dev EVM selector for this function is: 0xc3de1494,119	///  or in textual repr: isCollectionExist(address)120	function isCollectionExist(address collectionAddress) public view returns (bool) {121		require(false, stub_error);122		collectionAddress;123		dummy;124		return false;125	}126127	/// @dev EVM selector for this function is: 0xd23a7ab1,128	///  or in textual repr: collectionCreationFee()129	function collectionCreationFee() public view returns (uint256) {130		require(false, stub_error);131		dummy;132		return 0;133	}134135	/// Returns address of a collection.136	/// @param collectionId  - CollectionId  of the collection137	/// @return eth mirror address of the collection138	/// @dev EVM selector for this function is: 0x2e716683,139	///  or in textual repr: collectionAddress(uint32)140	function collectionAddress(uint32 collectionId) public view returns (address) {141		require(false, stub_error);142		collectionId;143		dummy;144		return 0x0000000000000000000000000000000000000000;145	}146147	/// Returns collectionId of a collection.148	/// @param collectionAddress  - Eth address of the collection149	/// @return collectionId of the collection150	/// @dev EVM selector for this function is: 0xb5cb7498,151	///  or in textual repr: collectionId(address)152	function collectionId(address collectionAddress) public view returns (uint32) {153		require(false, stub_error);154		collectionAddress;155		dummy;156		return 0;157	}158}
modifiedtests/src/eth/abi/collectionHelpers.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/collectionHelpers.json
+++ b/tests/src/eth/abi/collectionHelpers.json
@@ -45,25 +45,6 @@
     "type": "event"
   },
   {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "collectionId",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "TokenChanged",
-    "type": "event"
-  },
-  {
     "inputs": [
       { "internalType": "uint32", "name": "collectionId", "type": "uint32" }
     ],
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -55,6 +55,25 @@
       {
         "indexed": true,
         "internalType": "address",
+        "name": "collectionId",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "TokenChanged",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
         "name": "from",
         "type": "address"
       },
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -55,6 +55,25 @@
       {
         "indexed": true,
         "internalType": "address",
+        "name": "collectionId",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "TokenChanged",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
         "name": "from",
         "type": "address"
       },
modifiedtests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/CollectionHelpers.sol
+++ b/tests/src/eth/api/CollectionHelpers.sol
@@ -17,7 +17,6 @@
 	event CollectionCreated(address indexed owner, address indexed collectionId);
 	event CollectionDestroyed(address indexed collectionId);
 	event CollectionChanged(address indexed collectionId);
-	event TokenChanged(address indexed collectionId, uint256 tokenId);
 }
 
 /// @title Contract, which allows users to operate with collections
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -12,9 +12,14 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
+/// @dev inlined interface
+interface ERC721TokenEvent {
+	event TokenChanged(address indexed collectionId, uint256 tokenId);
+}
+
 /// @title A contract that allows to set and delete token properties and change token property permissions.
 /// @dev the ERC-165 identifier for this interface is 0xde0695c2
-interface TokenProperties is Dummy, ERC165 {
+interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
 	// /// @notice Set permissions for token property.
 	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
 	// /// @param key Property key.
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -12,9 +12,14 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
+/// @dev inlined interface
+interface ERC721TokenEvent {
+	event TokenChanged(address indexed collectionId, uint256 tokenId);
+}
+
 /// @title A contract that allows to set and delete token properties and change token property permissions.
 /// @dev the ERC-165 identifier for this interface is 0xde0695c2
-interface TokenProperties is Dummy, ERC165 {
+interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
 	// /// @notice Set permissions for token property.
 	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
 	// /// @param key Property key.
modifiedtests/src/eth/events.test.tsdiffbeforeafterboth
--- a/tests/src/eth/events.test.ts
+++ b/tests/src/eth/events.test.ts
@@ -29,8 +29,10 @@
   });
 });
 
-function clearEvents(ethEvents: NormalizedEvent[], subEvents: IEvent[]) {
-  ethEvents.splice(0);
+function clearEvents(ethEvents: NormalizedEvent[] | null, subEvents: IEvent[]) {
+  if (ethEvents !== null) {
+    ethEvents.splice(0);
+  }
   subEvents.splice(0);
 }
 
@@ -374,7 +376,6 @@
   const owner = await helper.eth.createAccountWithBalance(donor);
   const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');
   const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);
-  const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner);
   const result = await collection.methods.mint(owner).send({from: owner});
   const tokenId = result.events.Transfer.returnValues.tokenId;
   await collection.methods.setTokenPropertyPermissions([
@@ -384,38 +385,31 @@
       [TokenPermissionField.CollectionAdmin, true]],
     ],
   ]).send({from: owner});
-
 
-  const ethEvents: any = [];
-  collectionHelper.events.allEvents((_: any, event: any) => {
-    ethEvents.push(event);
-  });
   const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]);
   {
-    await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});
+    const result = await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});
     await helper.wait.newBlocks(1);
-    expect(ethEvents).to.containSubset([
-      {
-        event: 'TokenChanged',
-        returnValues: {
-          collectionId: collectionAddress,
-        },
+    expect(result.events.TokenChanged).to.be.like({
+      event: 'TokenChanged',
+      returnValues: {
+        collectionId: collectionAddress,
+        tokenId: tokenId,
       },
-    ]);
+    });
     expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]);
-    clearEvents(ethEvents, subEvents);
+    clearEvents(null, subEvents);
   }
   {
-    await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});
+    const result = await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});
     await helper.wait.newBlocks(1);
-    expect(ethEvents).to.containSubset([
-      {
-        event: 'TokenChanged',
-        returnValues: {
-          collectionId: collectionAddress,
-        },
+    expect(result.events.TokenChanged).to.be.like({
+      event: 'TokenChanged',
+      returnValues: {
+        collectionId: collectionAddress,
+        tokenId: tokenId,
       },
-    ]);
+    });
     expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]);
   }
   unsubscribe();