git.delta.rocks / unique-network / refs/commits / 515ea8c66cf5

difftreelog

feature: Added `delete_properties` in eth functions. The `delete_property` function is now deprecated.

PraetorP2022-11-11parent: #f715967.patch.diff
in: master

15 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6376,7 +6376,7 @@
 
 [[package]]
 name = "pallet-nonfungible"
-version = "0.1.7"
+version = "0.1.8"
 dependencies = [
  "ethereum",
  "evm-coder",
@@ -6498,7 +6498,7 @@
 
 [[package]]
 name = "pallet-refungible"
-version = "0.2.6"
+version = "0.2.7"
 dependencies = [
  "derivative",
  "ethereum",
modifiedpallets/nonfungible/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/nonfungible/CHANGELOG.md
+++ b/pallets/nonfungible/CHANGELOG.md
@@ -3,10 +3,19 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+
+## [v0.1.8] - 2022-11-11
+
+### Changed
+
+- Added `delete_properties` in eth functions. The `delete_property` function is now deprecated.
+
 ## [v0.1.7] - 2022-11-02
+
 ### Changed
- - Use named structure `EthCrossAccount` in eth functions.
 
+- Use named structure `EthCrossAccount` in eth functions.
+
 ## [v0.1.6] - 2022-20-10
 
 ### Change
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-nonfungible"
-version = "0.1.7"
+version = "0.1.8"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -162,6 +162,7 @@
 	/// @dev Throws error if `msg.sender` has no permission to edit the property.
 	/// @param tokenId ID of the token.
 	/// @param key Property key.
+	#[solidity(hide)]
 	fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -177,6 +178,37 @@
 			.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// @notice Delete token properties value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param keys Properties key.
+	fn delete_properties(
+		&mut self,
+		token_id: uint256,
+		caller: caller,
+		keys: Vec<string>,
+	) -> Result<()> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+		let keys = keys
+			.into_iter()
+			.map(|k| Ok(<Vec<u8>>::from(k).try_into().map_err(|_| "key too long")?))
+			.collect::<Result<Vec<_>>>()?;
+
+		let nesting_budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+		<Pallet<T>>::delete_token_properties(
+			self,
+			&caller,
+			TokenId(token_id),
+			keys.into_iter(),
+			&nesting_budget,
+		)
+		.map_err(dispatch_to_evm::<T>)
+	}
+
 	/// @notice Get token property value.
 	/// @dev Throws error if key not found
 	/// @param tokenId ID of the token.
modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -18,7 +18,7 @@
 }
 
 /// @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 0x55dba919
+/// @dev the ERC-165 identifier for this interface is 0x91a97a68
 contract TokenProperties is Dummy, ERC165 {
 	/// @notice Set permissions for token property.
 	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
@@ -74,16 +74,29 @@
 		dummy = 0;
 	}
 
-	/// @notice Delete token property value.
+	// /// @notice Delete token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x066111d1,
+	// ///  or in textual repr: deleteProperty(uint256,string)
+	// function deleteProperty(uint256 tokenId, string memory key) public {
+	// 	require(false, stub_error);
+	// 	tokenId;
+	// 	key;
+	// 	dummy = 0;
+	// }
+
+	/// @notice Delete token properties value.
 	/// @dev Throws error if `msg.sender` has no permission to edit the property.
 	/// @param tokenId ID of the token.
-	/// @param key Property key.
-	/// @dev EVM selector for this function is: 0x066111d1,
-	///  or in textual repr: deleteProperty(uint256,string)
-	function deleteProperty(uint256 tokenId, string memory key) public {
+	/// @param keys Properties key.
+	/// @dev EVM selector for this function is: 0xc472d371,
+	///  or in textual repr: deleteProperties(uint256,string[])
+	function deleteProperties(uint256 tokenId, string[] memory keys) public {
 		require(false, stub_error);
 		tokenId;
-		key;
+		keys;
 		dummy = 0;
 	}
 
modifiedpallets/refungible/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/refungible/CHANGELOG.md
+++ b/pallets/refungible/CHANGELOG.md
@@ -2,10 +2,20 @@
 
 All notable changes to this project will be documented in this file.
 
+<!-- bureaucrate goes here -->
+
+## [v0.2.7] - 2022-11-11
+
+### Changed
+
+- Added `delete_properties` in eth functions. The `delete_property` function is now deprecated.
+
 ## [v0.2.6] - 2022-11-02
+
 ### Changed
- - Use named structure `EthCrossAccount` in eth functions.
 
+- Use named structure `EthCrossAccount` in eth functions.
+
 ## [v0.2.5] - 2022-20-10
 
 ### Change
@@ -17,8 +27,6 @@
 ### Change
 
 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
-
-<!-- bureaucrate goes here -->
 
 ## [v0.2.3] 2022-08-16
 
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-refungible"
-version = "0.2.6"
+version = "0.2.7"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -164,6 +164,7 @@
 	/// @dev Throws error if `msg.sender` has no permission to edit the property.
 	/// @param tokenId ID of the token.
 	/// @param key Property key.
+	#[solidity(hide)]
 	fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -179,6 +180,37 @@
 			.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// @notice Delete token properties value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param keys Properties key.
+	fn delete_properties(
+		&mut self,
+		token_id: uint256,
+		caller: caller,
+		keys: Vec<string>,
+	) -> Result<()> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+		let keys = keys
+			.into_iter()
+			.map(|k| Ok(<Vec<u8>>::from(k).try_into().map_err(|_| "key too long")?))
+			.collect::<Result<Vec<_>>>()?;
+
+		let nesting_budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+		<Pallet<T>>::delete_token_properties(
+			self,
+			&caller,
+			TokenId(token_id),
+			keys.into_iter(),
+			&nesting_budget,
+		)
+		.map_err(dispatch_to_evm::<T>)
+	}
+
 	/// @notice Get token property value.
 	/// @dev Throws error if key not found
 	/// @param tokenId ID of the token.
modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -18,7 +18,7 @@
 }
 
 /// @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 0x55dba919
+/// @dev the ERC-165 identifier for this interface is 0x91a97a68
 contract TokenProperties is Dummy, ERC165 {
 	/// @notice Set permissions for token property.
 	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
@@ -74,16 +74,29 @@
 		dummy = 0;
 	}
 
-	/// @notice Delete token property value.
+	// /// @notice Delete token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x066111d1,
+	// ///  or in textual repr: deleteProperty(uint256,string)
+	// function deleteProperty(uint256 tokenId, string memory key) public {
+	// 	require(false, stub_error);
+	// 	tokenId;
+	// 	key;
+	// 	dummy = 0;
+	// }
+
+	/// @notice Delete token properties value.
 	/// @dev Throws error if `msg.sender` has no permission to edit the property.
 	/// @param tokenId ID of the token.
-	/// @param key Property key.
-	/// @dev EVM selector for this function is: 0x066111d1,
-	///  or in textual repr: deleteProperty(uint256,string)
-	function deleteProperty(uint256 tokenId, string memory key) public {
+	/// @param keys Properties key.
+	/// @dev EVM selector for this function is: 0xc472d371,
+	///  or in textual repr: deleteProperties(uint256,string[])
+	function deleteProperties(uint256 tokenId, string[] memory keys) public {
 		require(false, stub_error);
 		tokenId;
-		key;
+		keys;
 		dummy = 0;
 	}
 
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -13,7 +13,7 @@
 }
 
 /// @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 0x55dba919
+/// @dev the ERC-165 identifier for this interface is 0x91a97a68
 interface TokenProperties is Dummy, ERC165 {
 	/// @notice Set permissions for token property.
 	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
@@ -51,13 +51,21 @@
 	///  or in textual repr: setProperties(uint256,(string,bytes)[])
 	function setProperties(uint256 tokenId, Tuple21[] memory properties) external;
 
-	/// @notice Delete token property value.
+	// /// @notice Delete token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x066111d1,
+	// ///  or in textual repr: deleteProperty(uint256,string)
+	// function deleteProperty(uint256 tokenId, string memory key) external;
+
+	/// @notice Delete token properties value.
 	/// @dev Throws error if `msg.sender` has no permission to edit the property.
 	/// @param tokenId ID of the token.
-	/// @param key Property key.
-	/// @dev EVM selector for this function is: 0x066111d1,
-	///  or in textual repr: deleteProperty(uint256,string)
-	function deleteProperty(uint256 tokenId, string memory key) external;
+	/// @param keys Properties key.
+	/// @dev EVM selector for this function is: 0xc472d371,
+	///  or in textual repr: deleteProperties(uint256,string[])
+	function deleteProperties(uint256 tokenId, string[] memory keys) external;
 
 	/// @notice Get token property value.
 	/// @dev Throws error if key not found
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -13,7 +13,7 @@
 }
 
 /// @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 0x55dba919
+/// @dev the ERC-165 identifier for this interface is 0x91a97a68
 interface TokenProperties is Dummy, ERC165 {
 	/// @notice Set permissions for token property.
 	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
@@ -51,13 +51,21 @@
 	///  or in textual repr: setProperties(uint256,(string,bytes)[])
 	function setProperties(uint256 tokenId, Tuple20[] memory properties) external;
 
-	/// @notice Delete token property value.
+	// /// @notice Delete token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x066111d1,
+	// ///  or in textual repr: deleteProperty(uint256,string)
+	// function deleteProperty(uint256 tokenId, string memory key) external;
+
+	/// @notice Delete token properties value.
 	/// @dev Throws error if `msg.sender` has no permission to edit the property.
 	/// @param tokenId ID of the token.
-	/// @param key Property key.
-	/// @dev EVM selector for this function is: 0x066111d1,
-	///  or in textual repr: deleteProperty(uint256,string)
-	function deleteProperty(uint256 tokenId, string memory key) external;
+	/// @param keys Properties key.
+	/// @dev EVM selector for this function is: 0xc472d371,
+	///  or in textual repr: deleteProperties(uint256,string[])
+	function deleteProperties(uint256 tokenId, string[] memory keys) external;
 
 	/// @notice Get token property value.
 	/// @dev Throws error if key not found
modifiedtests/src/eth/collectionProperties.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionProperties.test.ts
+++ b/tests/src/eth/collectionProperties.test.ts
@@ -139,7 +139,7 @@
     await contract.methods.setProperty(tokenId1, 'URI', Buffer.from(URI)).send();
     expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI);
 
-    await contract.methods.deleteProperty(tokenId1, 'URI').send();
+    await contract.methods.deleteProperties(tokenId1, ['URI']).send();
     expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX);
 
     const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send();
@@ -147,7 +147,7 @@
 
     expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI);
 
-    await contract.methods.deleteProperty(tokenId2, 'URI').send();
+    await contract.methods.deleteProperties(tokenId2, ['URI']).send();
     expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI);
 
     await contract.methods.setProperty(tokenId2, 'URISuffix', Buffer.from(SUFFIX)).send();
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
before · tests/src/eth/nonFungibleAbi.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      {95        "components": [96          { "internalType": "address", "name": "eth", "type": "address" },97          { "internalType": "uint256", "name": "sub", "type": "uint256" }98        ],99        "internalType": "struct EthCrossAccount",100        "name": "newAdmin",101        "type": "tuple"102      }103    ],104    "name": "addCollectionAdminCross",105    "outputs": [],106    "stateMutability": "nonpayable",107    "type": "function"108  },109  {110    "inputs": [111      { "internalType": "address", "name": "user", "type": "address" }112    ],113    "name": "addToCollectionAllowList",114    "outputs": [],115    "stateMutability": "nonpayable",116    "type": "function"117  },118  {119    "inputs": [120      {121        "components": [122          { "internalType": "address", "name": "eth", "type": "address" },123          { "internalType": "uint256", "name": "sub", "type": "uint256" }124        ],125        "internalType": "struct EthCrossAccount",126        "name": "user",127        "type": "tuple"128      }129    ],130    "name": "addToCollectionAllowListCross",131    "outputs": [],132    "stateMutability": "nonpayable",133    "type": "function"134  },135  {136    "inputs": [137      { "internalType": "address", "name": "user", "type": "address" }138    ],139    "name": "allowed",140    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],141    "stateMutability": "view",142    "type": "function"143  },144  {145    "inputs": [146      { "internalType": "address", "name": "approved", "type": "address" },147      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }148    ],149    "name": "approve",150    "outputs": [],151    "stateMutability": "nonpayable",152    "type": "function"153  },154  {155    "inputs": [156      {157        "components": [158          { "internalType": "address", "name": "eth", "type": "address" },159          { "internalType": "uint256", "name": "sub", "type": "uint256" }160        ],161        "internalType": "struct EthCrossAccount",162        "name": "approved",163        "type": "tuple"164      },165      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }166    ],167    "name": "approveCross",168    "outputs": [],169    "stateMutability": "nonpayable",170    "type": "function"171  },172  {173    "inputs": [174      { "internalType": "address", "name": "owner", "type": "address" }175    ],176    "name": "balanceOf",177    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],178    "stateMutability": "view",179    "type": "function"180  },181  {182    "inputs": [183      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }184    ],185    "name": "burn",186    "outputs": [],187    "stateMutability": "nonpayable",188    "type": "function"189  },190  {191    "inputs": [192      { "internalType": "address", "name": "from", "type": "address" },193      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }194    ],195    "name": "burnFrom",196    "outputs": [],197    "stateMutability": "nonpayable",198    "type": "function"199  },200  {201    "inputs": [202      {203        "components": [204          { "internalType": "address", "name": "eth", "type": "address" },205          { "internalType": "uint256", "name": "sub", "type": "uint256" }206        ],207        "internalType": "struct EthCrossAccount",208        "name": "from",209        "type": "tuple"210      },211      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }212    ],213    "name": "burnFromCross",214    "outputs": [],215    "stateMutability": "nonpayable",216    "type": "function"217  },218  {219    "inputs": [220      { "internalType": "address", "name": "newOwner", "type": "address" }221    ],222    "name": "changeCollectionOwner",223    "outputs": [],224    "stateMutability": "nonpayable",225    "type": "function"226  },227  {228    "inputs": [],229    "name": "collectionAdmins",230    "outputs": [231      {232        "components": [233          { "internalType": "address", "name": "eth", "type": "address" },234          { "internalType": "uint256", "name": "sub", "type": "uint256" }235        ],236        "internalType": "struct EthCrossAccount[]",237        "name": "",238        "type": "tuple[]"239      }240    ],241    "stateMutability": "view",242    "type": "function"243  },244  {245    "inputs": [],246    "name": "collectionOwner",247    "outputs": [248      {249        "components": [250          { "internalType": "address", "name": "eth", "type": "address" },251          { "internalType": "uint256", "name": "sub", "type": "uint256" }252        ],253        "internalType": "struct EthCrossAccount",254        "name": "",255        "type": "tuple"256      }257    ],258    "stateMutability": "view",259    "type": "function"260  },261  {262    "inputs": [263      { "internalType": "string[]", "name": "keys", "type": "string[]" }264    ],265    "name": "collectionProperties",266    "outputs": [267      {268        "components": [269          { "internalType": "string", "name": "field_0", "type": "string" },270          { "internalType": "bytes", "name": "field_1", "type": "bytes" }271        ],272        "internalType": "struct Tuple21[]",273        "name": "",274        "type": "tuple[]"275      }276    ],277    "stateMutability": "view",278    "type": "function"279  },280  {281    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],282    "name": "collectionProperty",283    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],284    "stateMutability": "view",285    "type": "function"286  },287  {288    "inputs": [],289    "name": "collectionSponsor",290    "outputs": [291      {292        "components": [293          { "internalType": "address", "name": "field_0", "type": "address" },294          { "internalType": "uint256", "name": "field_1", "type": "uint256" }295        ],296        "internalType": "struct Tuple24",297        "name": "",298        "type": "tuple"299      }300    ],301    "stateMutability": "view",302    "type": "function"303  },304  {305    "inputs": [],306    "name": "confirmCollectionSponsorship",307    "outputs": [],308    "stateMutability": "nonpayable",309    "type": "function"310  },311  {312    "inputs": [],313    "name": "contractAddress",314    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],315    "stateMutability": "view",316    "type": "function"317  },318  {319    "inputs": [320      { "internalType": "string[]", "name": "keys", "type": "string[]" }321    ],322    "name": "deleteCollectionProperties",323    "outputs": [],324    "stateMutability": "nonpayable",325    "type": "function"326  },327  {328    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],329    "name": "deleteCollectionProperty",330    "outputs": [],331    "stateMutability": "nonpayable",332    "type": "function"333  },334  {335    "inputs": [336      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },337      { "internalType": "string", "name": "key", "type": "string" }338    ],339    "name": "deleteProperty",340    "outputs": [],341    "stateMutability": "nonpayable",342    "type": "function"343  },344  {345    "inputs": [],346    "name": "finishMinting",347    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],348    "stateMutability": "nonpayable",349    "type": "function"350  },351  {352    "inputs": [353      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }354    ],355    "name": "getApproved",356    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],357    "stateMutability": "view",358    "type": "function"359  },360  {361    "inputs": [],362    "name": "hasCollectionPendingSponsor",363    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],364    "stateMutability": "view",365    "type": "function"366  },367  {368    "inputs": [369      { "internalType": "address", "name": "owner", "type": "address" },370      { "internalType": "address", "name": "operator", "type": "address" }371    ],372    "name": "isApprovedForAll",373    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],374    "stateMutability": "view",375    "type": "function"376  },377  {378    "inputs": [379      { "internalType": "address", "name": "user", "type": "address" }380    ],381    "name": "isOwnerOrAdmin",382    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],383    "stateMutability": "view",384    "type": "function"385  },386  {387    "inputs": [388      {389        "components": [390          { "internalType": "address", "name": "eth", "type": "address" },391          { "internalType": "uint256", "name": "sub", "type": "uint256" }392        ],393        "internalType": "struct EthCrossAccount",394        "name": "user",395        "type": "tuple"396      }397    ],398    "name": "isOwnerOrAdminCross",399    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],400    "stateMutability": "view",401    "type": "function"402  },403  {404    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],405    "name": "mint",406    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],407    "stateMutability": "nonpayable",408    "type": "function"409  },410  {411    "inputs": [412      { "internalType": "address", "name": "to", "type": "address" },413      { "internalType": "string", "name": "tokenUri", "type": "string" }414    ],415    "name": "mintWithTokenURI",416    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],417    "stateMutability": "nonpayable",418    "type": "function"419  },420  {421    "inputs": [],422    "name": "mintingFinished",423    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],424    "stateMutability": "view",425    "type": "function"426  },427  {428    "inputs": [],429    "name": "name",430    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],431    "stateMutability": "view",432    "type": "function"433  },434  {435    "inputs": [],436    "name": "nextTokenId",437    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],438    "stateMutability": "view",439    "type": "function"440  },441  {442    "inputs": [443      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }444    ],445    "name": "ownerOf",446    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],447    "stateMutability": "view",448    "type": "function"449  },450  {451    "inputs": [452      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },453      { "internalType": "string", "name": "key", "type": "string" }454    ],455    "name": "property",456    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],457    "stateMutability": "view",458    "type": "function"459  },460  {461    "inputs": [462      { "internalType": "address", "name": "admin", "type": "address" }463    ],464    "name": "removeCollectionAdmin",465    "outputs": [],466    "stateMutability": "nonpayable",467    "type": "function"468  },469  {470    "inputs": [471      {472        "components": [473          { "internalType": "address", "name": "eth", "type": "address" },474          { "internalType": "uint256", "name": "sub", "type": "uint256" }475        ],476        "internalType": "struct EthCrossAccount",477        "name": "admin",478        "type": "tuple"479      }480    ],481    "name": "removeCollectionAdminCross",482    "outputs": [],483    "stateMutability": "nonpayable",484    "type": "function"485  },486  {487    "inputs": [],488    "name": "removeCollectionSponsor",489    "outputs": [],490    "stateMutability": "nonpayable",491    "type": "function"492  },493  {494    "inputs": [495      { "internalType": "address", "name": "user", "type": "address" }496    ],497    "name": "removeFromCollectionAllowList",498    "outputs": [],499    "stateMutability": "nonpayable",500    "type": "function"501  },502  {503    "inputs": [504      {505        "components": [506          { "internalType": "address", "name": "eth", "type": "address" },507          { "internalType": "uint256", "name": "sub", "type": "uint256" }508        ],509        "internalType": "struct EthCrossAccount",510        "name": "user",511        "type": "tuple"512      }513    ],514    "name": "removeFromCollectionAllowListCross",515    "outputs": [],516    "stateMutability": "nonpayable",517    "type": "function"518  },519  {520    "inputs": [521      { "internalType": "address", "name": "from", "type": "address" },522      { "internalType": "address", "name": "to", "type": "address" },523      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }524    ],525    "name": "safeTransferFrom",526    "outputs": [],527    "stateMutability": "nonpayable",528    "type": "function"529  },530  {531    "inputs": [532      { "internalType": "address", "name": "from", "type": "address" },533      { "internalType": "address", "name": "to", "type": "address" },534      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },535      { "internalType": "bytes", "name": "data", "type": "bytes" }536    ],537    "name": "safeTransferFrom",538    "outputs": [],539    "stateMutability": "nonpayable",540    "type": "function"541  },542  {543    "inputs": [544      { "internalType": "address", "name": "operator", "type": "address" },545      { "internalType": "bool", "name": "approved", "type": "bool" }546    ],547    "name": "setApprovalForAll",548    "outputs": [],549    "stateMutability": "nonpayable",550    "type": "function"551  },552  {553    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],554    "name": "setCollectionAccess",555    "outputs": [],556    "stateMutability": "nonpayable",557    "type": "function"558  },559  {560    "inputs": [561      { "internalType": "string", "name": "limit", "type": "string" },562      { "internalType": "uint32", "name": "value", "type": "uint32" }563    ],564    "name": "setCollectionLimit",565    "outputs": [],566    "stateMutability": "nonpayable",567    "type": "function"568  },569  {570    "inputs": [571      { "internalType": "string", "name": "limit", "type": "string" },572      { "internalType": "bool", "name": "value", "type": "bool" }573    ],574    "name": "setCollectionLimit",575    "outputs": [],576    "stateMutability": "nonpayable",577    "type": "function"578  },579  {580    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],581    "name": "setCollectionMintMode",582    "outputs": [],583    "stateMutability": "nonpayable",584    "type": "function"585  },586  {587    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],588    "name": "setCollectionNesting",589    "outputs": [],590    "stateMutability": "nonpayable",591    "type": "function"592  },593  {594    "inputs": [595      { "internalType": "bool", "name": "enable", "type": "bool" },596      {597        "internalType": "address[]",598        "name": "collections",599        "type": "address[]"600      }601    ],602    "name": "setCollectionNesting",603    "outputs": [],604    "stateMutability": "nonpayable",605    "type": "function"606  },607  {608    "inputs": [609      {610        "components": [611          { "internalType": "string", "name": "field_0", "type": "string" },612          { "internalType": "bytes", "name": "field_1", "type": "bytes" }613        ],614        "internalType": "struct Tuple21[]",615        "name": "properties",616        "type": "tuple[]"617      }618    ],619    "name": "setCollectionProperties",620    "outputs": [],621    "stateMutability": "nonpayable",622    "type": "function"623  },624  {625    "inputs": [626      { "internalType": "string", "name": "key", "type": "string" },627      { "internalType": "bytes", "name": "value", "type": "bytes" }628    ],629    "name": "setCollectionProperty",630    "outputs": [],631    "stateMutability": "nonpayable",632    "type": "function"633  },634  {635    "inputs": [636      { "internalType": "address", "name": "sponsor", "type": "address" }637    ],638    "name": "setCollectionSponsor",639    "outputs": [],640    "stateMutability": "nonpayable",641    "type": "function"642  },643  {644    "inputs": [645      {646        "components": [647          { "internalType": "address", "name": "eth", "type": "address" },648          { "internalType": "uint256", "name": "sub", "type": "uint256" }649        ],650        "internalType": "struct EthCrossAccount",651        "name": "sponsor",652        "type": "tuple"653      }654    ],655    "name": "setCollectionSponsorCross",656    "outputs": [],657    "stateMutability": "nonpayable",658    "type": "function"659  },660  {661    "inputs": [662      {663        "components": [664          { "internalType": "address", "name": "eth", "type": "address" },665          { "internalType": "uint256", "name": "sub", "type": "uint256" }666        ],667        "internalType": "struct EthCrossAccount",668        "name": "newOwner",669        "type": "tuple"670      }671    ],672    "name": "setOwnerCross",673    "outputs": [],674    "stateMutability": "nonpayable",675    "type": "function"676  },677  {678    "inputs": [679      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },680      {681        "components": [682          { "internalType": "string", "name": "field_0", "type": "string" },683          { "internalType": "bytes", "name": "field_1", "type": "bytes" }684        ],685        "internalType": "struct Tuple21[]",686        "name": "properties",687        "type": "tuple[]"688      }689    ],690    "name": "setProperties",691    "outputs": [],692    "stateMutability": "nonpayable",693    "type": "function"694  },695  {696    "inputs": [697      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },698      { "internalType": "string", "name": "key", "type": "string" },699      { "internalType": "bytes", "name": "value", "type": "bytes" }700    ],701    "name": "setProperty",702    "outputs": [],703    "stateMutability": "nonpayable",704    "type": "function"705  },706  {707    "inputs": [708      { "internalType": "string", "name": "key", "type": "string" },709      { "internalType": "bool", "name": "isMutable", "type": "bool" },710      { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },711      { "internalType": "bool", "name": "tokenOwner", "type": "bool" }712    ],713    "name": "setTokenPropertyPermission",714    "outputs": [],715    "stateMutability": "nonpayable",716    "type": "function"717  },718  {719    "inputs": [720      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }721    ],722    "name": "supportsInterface",723    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],724    "stateMutability": "view",725    "type": "function"726  },727  {728    "inputs": [],729    "name": "symbol",730    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],731    "stateMutability": "view",732    "type": "function"733  },734  {735    "inputs": [736      { "internalType": "uint256", "name": "index", "type": "uint256" }737    ],738    "name": "tokenByIndex",739    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],740    "stateMutability": "view",741    "type": "function"742  },743  {744    "inputs": [745      { "internalType": "address", "name": "owner", "type": "address" },746      { "internalType": "uint256", "name": "index", "type": "uint256" }747    ],748    "name": "tokenOfOwnerByIndex",749    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],750    "stateMutability": "view",751    "type": "function"752  },753  {754    "inputs": [755      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }756    ],757    "name": "tokenURI",758    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],759    "stateMutability": "view",760    "type": "function"761  },762  {763    "inputs": [],764    "name": "totalSupply",765    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],766    "stateMutability": "view",767    "type": "function"768  },769  {770    "inputs": [771      { "internalType": "address", "name": "to", "type": "address" },772      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }773    ],774    "name": "transfer",775    "outputs": [],776    "stateMutability": "nonpayable",777    "type": "function"778  },779  {780    "inputs": [781      { "internalType": "address", "name": "from", "type": "address" },782      { "internalType": "address", "name": "to", "type": "address" },783      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }784    ],785    "name": "transferFrom",786    "outputs": [],787    "stateMutability": "nonpayable",788    "type": "function"789  },790  {791    "inputs": [792      {793        "components": [794          { "internalType": "address", "name": "eth", "type": "address" },795          { "internalType": "uint256", "name": "sub", "type": "uint256" }796        ],797        "internalType": "struct EthCrossAccount",798        "name": "from",799        "type": "tuple"800      },801      {802        "components": [803          { "internalType": "address", "name": "eth", "type": "address" },804          { "internalType": "uint256", "name": "sub", "type": "uint256" }805        ],806        "internalType": "struct EthCrossAccount",807        "name": "to",808        "type": "tuple"809      },810      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }811    ],812    "name": "transferFromCross",813    "outputs": [],814    "stateMutability": "nonpayable",815    "type": "function"816  },817  {818    "inputs": [],819    "name": "uniqueCollectionType",820    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],821    "stateMutability": "view",822    "type": "function"823  }824]
modifiedtests/src/eth/reFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/reFungibleAbi.json
+++ b/tests/src/eth/reFungibleAbi.json
@@ -316,9 +316,9 @@
   {
     "inputs": [
       { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" }
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
     ],
-    "name": "deleteProperty",
+    "name": "deleteProperties",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
modifiedtests/src/eth/tokenProperties.test.tsdiffbeforeafterboth
--- a/tests/src/eth/tokenProperties.test.ts
+++ b/tests/src/eth/tokenProperties.test.ts
@@ -138,18 +138,25 @@
           mutable: true,
           collectionAdmin: true,
         },
+      },
+      {
+        key: 'testKey_1',
+        permission: {
+          mutable: true,
+          collectionAdmin: true,
+        },
       }],
     });
     
     const token = await collection.mintToken(alice);
-    await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]);
+    await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}, {key: 'testKey_1', value: 'testValue_1'}]);
 
     await collection.addAdmin(alice, {Ethereum: caller});
 
     const address = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(address, 'nft', caller);
 
-    await contract.methods.deleteProperty(token.tokenId, 'testKey').send({from: caller});
+    await contract.methods.deleteProperties(token.tokenId, ['testKey', 'testKey_1']).send({from: caller});
 
     const result = await token.getProperties(['testKey']);
     expect(result.length).to.equal(0);