git.delta.rocks / unique-network / refs/commits / 074bf74bed72

difftreelog

Merge pull request #726 from UniqueNetwork/feature/setCollectionLimit

Yaroslav Bolyukin2022-11-23parents: #78a9ca0 #2e0d1a6.patch.diff
in: master
feature/setCollectionLimit

22 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5831,7 +5831,7 @@
 
 [[package]]
 name = "pallet-common"
-version = "0.1.10"
+version = "0.1.11"
 dependencies = [
  "ethereum",
  "evm-coder",
modifiedpallets/common/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/common/CHANGELOG.md
+++ b/pallets/common/CHANGELOG.md
@@ -2,10 +2,22 @@
 
 All notable changes to this project will be documented in this file.
 
+<!-- bureaucrate goes here -->
+
+## [0.1.11] - 2022-11-16
+
+### Changed
+
+- Behavior of the `setCollectionLimit` method.
+  Removed method overload: single signature `(string, uint256)`
+  is used for both cases.
+
 ## [0.1.10] - 2022-11-02
+
 ### Changed
- - Use named structure `EthCrossAccount` in eth functions.
 
+- Use named structure `EthCrossAccount` in eth functions.
+
 ## [0.1.9] - 2022-10-13
 
 ## Added
@@ -34,8 +46,6 @@
 ### Added
 
 - New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate).
-
-<!-- bureaucrate goes here -->
 
 ## [v0.1.5] 2022-08-16
 
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-common"
-version = "0.1.10"
+version = "0.1.11"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -303,11 +303,29 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
+	///  	"ownerCanTransfer",
+	/// 	"ownerCanDestroy",
+	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
 	#[solidity(rename_selector = "setCollectionLimit")]
-	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {
+	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint256) -> Result<void> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
+		let value = value
+			.try_into()
+			.map_err(|_| Error::Revert(format!("can't convert value to u32 \"{}\"", value)))?;
+
+		let convert_value_to_bool = || match value {
+			0 => Ok(false),
+			1 => Ok(true),
+			_ => {
+				return Err(Error::Revert(format!(
+					"can't convert value to boolean \"{}\"",
+					value
+				)))
+			}
+		};
+
 		check_is_owner_or_admin(caller, self)?;
 		let mut limits = self.limits.clone();
 
@@ -330,48 +348,16 @@
 			"sponsorApproveTimeout" => {
 				limits.sponsor_approve_timeout = Some(value);
 			}
-			_ => {
-				return Err(Error::Revert(format!(
-					"unknown integer limit \"{}\"",
-					limit
-				)))
-			}
-		}
-		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
-			.map_err(dispatch_to_evm::<T>)?;
-		save(self)
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
-	/// 	"ownerCanDestroy",
-	/// 	"transfersEnabled"
-	/// @param value Value of the limit.
-	#[solidity(rename_selector = "setCollectionLimit")]
-	fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {
-		self.consume_store_reads_and_writes(1, 1)?;
-
-		check_is_owner_or_admin(caller, self)?;
-		let mut limits = self.limits.clone();
-
-		match limit.as_str() {
 			"ownerCanTransfer" => {
-				limits.owner_can_transfer = Some(value);
+				limits.owner_can_transfer = Some(convert_value_to_bool()?);
 			}
 			"ownerCanDestroy" => {
-				limits.owner_can_destroy = Some(value);
+				limits.owner_can_destroy = Some(convert_value_to_bool()?);
 			}
 			"transfersEnabled" => {
-				limits.transfers_enabled = Some(value);
-			}
-			_ => {
-				return Err(Error::Revert(format!(
-					"unknown boolean limit \"{}\"",
-					limit
-				)))
+				limits.transfers_enabled = Some(convert_value_to_bool()?);
 			}
+			_ => return Err(Error::Revert(format!("unknown limit \"{}\"", limit))),
 		}
 		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
 			.map_err(dispatch_to_evm::<T>)?;
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

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
@@ -18,7 +18,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x324a7f5b
+/// @dev the ERC-165 identifier for this interface is 0x8b91d192
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -167,26 +167,13 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
+	///  	"ownerCanTransfer",
 	/// 	"ownerCanDestroy",
 	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) public {
+	/// @dev EVM selector for this function is: 0x4ad890a8,
+	///  or in textual repr: setCollectionLimit(string,uint256)
+	function setCollectionLimit(string memory limit, uint256 value) public {
 		require(false, stub_error);
 		limit;
 		value;
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
@@ -119,7 +119,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x324a7f5b
+/// @dev the ERC-165 identifier for this interface is 0x8b91d192
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -268,26 +268,13 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
+	///  	"ownerCanTransfer",
 	/// 	"ownerCanDestroy",
 	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) public {
+	/// @dev EVM selector for this function is: 0x4ad890a8,
+	///  or in textual repr: setCollectionLimit(string,uint256)
+	function setCollectionLimit(string memory limit, uint256 value) public {
 		require(false, stub_error);
 		limit;
 		value;
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
@@ -119,7 +119,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x324a7f5b
+/// @dev the ERC-165 identifier for this interface is 0x8b91d192
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -268,26 +268,13 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
+	///  	"ownerCanTransfer",
 	/// 	"ownerCanDestroy",
 	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) public {
+	/// @dev EVM selector for this function is: 0x4ad890a8,
+	///  or in textual repr: setCollectionLimit(string,uint256)
+	function setCollectionLimit(string memory limit, uint256 value) public {
 		require(false, stub_error);
 		limit;
 		value;
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedtests/src/eth/abi/fungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/fungible.json
+++ b/tests/src/eth/abi/fungible.json
@@ -390,17 +390,7 @@
   {
     "inputs": [
       { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "uint32", "name": "value", "type": "uint32" }
-    ],
-    "name": "setCollectionLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "bool", "name": "value", "type": "bool" }
+      { "internalType": "uint256", "name": "value", "type": "uint256" }
     ],
     "name": "setCollectionLimit",
     "outputs": [],
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -505,17 +505,7 @@
   {
     "inputs": [
       { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "uint32", "name": "value", "type": "uint32" }
-    ],
-    "name": "setCollectionLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "bool", "name": "value", "type": "bool" }
+      { "internalType": "uint256", "name": "value", "type": "uint256" }
     ],
     "name": "setCollectionLimit",
     "outputs": [],
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -487,17 +487,7 @@
   {
     "inputs": [
       { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "uint32", "name": "value", "type": "uint32" }
-    ],
-    "name": "setCollectionLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "bool", "name": "value", "type": "bool" }
+      { "internalType": "uint256", "name": "value", "type": "uint256" }
     ],
     "name": "setCollectionLimit",
     "outputs": [],
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -13,7 +13,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x324a7f5b
+/// @dev the ERC-165 identifier for this interface is 0x8b91d192
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -113,21 +113,13 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) external;
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
+	///  	"ownerCanTransfer",
 	/// 	"ownerCanDestroy",
 	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) external;
+	/// @dev EVM selector for this function is: 0x4ad890a8,
+	///  or in textual repr: setCollectionLimit(string,uint256)
+	function setCollectionLimit(string memory limit, uint256 value) external;
 
 	/// Get contract address.
 	/// @dev EVM selector for this function is: 0xf6b4dfb4,
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -80,7 +80,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x324a7f5b
+/// @dev the ERC-165 identifier for this interface is 0x8b91d192
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -180,21 +180,13 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) external;
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
+	///  	"ownerCanTransfer",
 	/// 	"ownerCanDestroy",
 	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) external;
+	/// @dev EVM selector for this function is: 0x4ad890a8,
+	///  or in textual repr: setCollectionLimit(string,uint256)
+	function setCollectionLimit(string memory limit, uint256 value) external;
 
 	/// Get contract address.
 	/// @dev EVM selector for this function is: 0xf6b4dfb4,
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -80,7 +80,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x324a7f5b
+/// @dev the ERC-165 identifier for this interface is 0x8b91d192
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -180,21 +180,13 @@
 	/// 	"tokenLimit",
 	/// 	"sponsorTransferTimeout",
 	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) external;
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
+	///  	"ownerCanTransfer",
 	/// 	"ownerCanDestroy",
 	/// 	"transfersEnabled"
 	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) external;
+	/// @dev EVM selector for this function is: 0x4ad890a8,
+	///  or in textual repr: setCollectionLimit(string,uint256)
+	function setCollectionLimit(string memory limit, uint256 value) external;
 
 	/// Get contract address.
 	/// @dev EVM selector for this function is: 0xf6b4dfb4,
modifiedtests/src/eth/createFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createFTCollection.test.ts
+++ b/tests/src/eth/createFTCollection.test.ts
@@ -85,32 +85,44 @@
       tokenLimit: 1000000,
       sponsorTransferTimeout: 6,
       sponsorApproveTimeout: 6,
+      ownerCanTransfer: 0,
+      ownerCanDestroy: 0,
+      transfersEnabled: 0,
+    };
+    
+    const expectedLimits = {
+      accountTokenOwnershipLimit: 1000,
+      sponsoredDataSize: 1024,
+      sponsoredDataRateLimit: 30,
+      tokenLimit: 1000000,
+      sponsorTransferTimeout: 6,
+      sponsorApproveTimeout: 6,
       ownerCanTransfer: false,
       ownerCanDestroy: false,
       transfersEnabled: false,
     };
-
+   
     const collection = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
-    await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();
-    await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send();
-    await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send();
-    await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send();
+    await collection.methods.setCollectionLimit('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();
+    await collection.methods.setCollectionLimit('sponsoredDataSize', limits.sponsoredDataSize).send();
+    await collection.methods.setCollectionLimit('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();
+    await collection.methods.setCollectionLimit('tokenLimit', limits.tokenLimit).send();
+    await collection.methods.setCollectionLimit('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();
+    await collection.methods.setCollectionLimit('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();
+    await collection.methods.setCollectionLimit('ownerCanTransfer', limits.ownerCanTransfer).send();
+    await collection.methods.setCollectionLimit('ownerCanDestroy', limits.ownerCanDestroy).send();
+    await collection.methods.setCollectionLimit('transfersEnabled', limits.transfersEnabled).send();
     
     const data = (await helper.rft.getData(collectionId))!;
-    expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit);
-    expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize);
-    expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit);
-    expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit);
-    expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout);
-    expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout);
-    expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer);
-    expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy);
-    expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled);
+    expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(expectedLimits.accountTokenOwnershipLimit);
+    expect(data.raw.limits.sponsoredDataSize).to.be.eq(expectedLimits.sponsoredDataSize);
+    expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(expectedLimits.sponsoredDataRateLimit);
+    expect(data.raw.limits.tokenLimit).to.be.eq(expectedLimits.tokenLimit);
+    expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(expectedLimits.sponsorTransferTimeout);
+    expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(expectedLimits.sponsorApproveTimeout);
+    expect(data.raw.limits.ownerCanTransfer).to.be.eq(expectedLimits.ownerCanTransfer);
+    expect(data.raw.limits.ownerCanDestroy).to.be.eq(expectedLimits.ownerCanDestroy);
+    expect(data.raw.limits.transfersEnabled).to.be.eq(expectedLimits.transfersEnabled);
   });
 
   itEth('Collection address exist', async ({helper}) => {
@@ -257,11 +269,28 @@
   });
 
   itEth('(!negative test!) Set limits', async ({helper}) => {
+
+    const invalidLimits = {
+      accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),
+      transfersEnabled: 3,
+    };
+
     const owner = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Limits', DECIMALS, 'absolutely anything', 'ISNI');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
     await expect(collectionEvm.methods
-      .setCollectionLimit('badLimit', 'true')
-      .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');
+      .setCollectionLimit('badLimit', '1')
+      .call()).to.be.rejectedWith('unknown limit "badLimit"');
+    
+    await expect(collectionEvm.methods
+      .setCollectionLimit(Object.keys(invalidLimits)[0], invalidLimits.accountTokenOwnershipLimit)
+      .call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);
+    
+    await expect(collectionEvm.methods
+      .setCollectionLimit(Object.keys(invalidLimits)[1], invalidLimits.transfersEnabled)
+      .call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);
   });
+
+   
+    
 });
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createNFTCollection.test.ts
+++ b/tests/src/eth/createNFTCollection.test.ts
@@ -124,32 +124,44 @@
       tokenLimit: 1000000,
       sponsorTransferTimeout: 6,
       sponsorApproveTimeout: 6,
+      ownerCanTransfer: 0,
+      ownerCanDestroy: 0,
+      transfersEnabled: 0,
+    };
+    
+    const expectedLimits = {
+      accountTokenOwnershipLimit: 1000,
+      sponsoredDataSize: 1024,
+      sponsoredDataRateLimit: 30,
+      tokenLimit: 1000000,
+      sponsorTransferTimeout: 6,
+      sponsorApproveTimeout: 6,
       ownerCanTransfer: false,
       ownerCanDestroy: false,
       transfersEnabled: false,
     };
 
     const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-    await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();
-    await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();
-    await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send();
-    await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send();
-    await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send();
+    await collection.methods.setCollectionLimit('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();
+    await collection.methods.setCollectionLimit('sponsoredDataSize', limits.sponsoredDataSize).send();
+    await collection.methods.setCollectionLimit('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();
+    await collection.methods.setCollectionLimit('tokenLimit', limits.tokenLimit).send();
+    await collection.methods.setCollectionLimit('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();
+    await collection.methods.setCollectionLimit('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();
+    await collection.methods.setCollectionLimit('ownerCanTransfer', limits.ownerCanTransfer).send();
+    await collection.methods.setCollectionLimit('ownerCanDestroy', limits.ownerCanDestroy).send();
+    await collection.methods.setCollectionLimit('transfersEnabled', limits.transfersEnabled).send();
 
-    const data = (await helper.nft.getData(collectionId))!;
-    expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit);
-    expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize);
-    expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit);
-    expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit);
-    expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout);
-    expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout);
-    expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer);
-    expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy);
-    expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled);
+    const data = (await helper.rft.getData(collectionId))!;
+    expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(expectedLimits.accountTokenOwnershipLimit);
+    expect(data.raw.limits.sponsoredDataSize).to.be.eq(expectedLimits.sponsoredDataSize);
+    expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(expectedLimits.sponsoredDataRateLimit);
+    expect(data.raw.limits.tokenLimit).to.be.eq(expectedLimits.tokenLimit);
+    expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(expectedLimits.sponsorTransferTimeout);
+    expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(expectedLimits.sponsorApproveTimeout);
+    expect(data.raw.limits.ownerCanTransfer).to.be.eq(expectedLimits.ownerCanTransfer);
+    expect(data.raw.limits.ownerCanDestroy).to.be.eq(expectedLimits.ownerCanDestroy);
+    expect(data.raw.limits.transfersEnabled).to.be.eq(expectedLimits.transfersEnabled);
   });
 
   itEth('Collection address exist', async ({helper}) => {
@@ -270,12 +282,22 @@
   });
 
   itEth('(!negative test!) Set limits', async ({helper}) => {
+    const invalidLimits = {
+      accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),
+      transfersEnabled: 3,
+    };
+
     const owner = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+    
+    await expect(collectionEvm.methods
+      .setCollectionLimit(Object.keys(invalidLimits)[0], invalidLimits.accountTokenOwnershipLimit)
+      .call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);
+    
     await expect(collectionEvm.methods
-      .setCollectionLimit('badLimit', 'true')
-      .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');
+      .setCollectionLimit(Object.keys(invalidLimits)[1], invalidLimits.transfersEnabled)
+      .call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);
   });
 
   itEth('destroyCollection', async ({helper}) => {
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
before · tests/src/eth/createRFTCollection.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.8//9// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {evmToAddress} from '@polkadot/util-crypto';18import {IKeyringPair} from '@polkadot/types/types';19import {Pallets, requirePalletsOrSkip} from '../util';20import {expect, itEth, usingEthPlaygrounds} from './util';212223describe('Create RFT collection from EVM', () => {24  let donor: IKeyringPair;2526  before(async function() {27    await usingEthPlaygrounds(async (helper, privateKey) => {28      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);29      donor = await privateKey({filename: __filename});30    });31  });3233  itEth('Create collection', async ({helper}) => {34    const owner = await helper.eth.createAccountWithBalance(donor);35    36    const name = 'CollectionEVM';37    const description = 'Some description';38    const prefix = 'token prefix';39  40    const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix);41    const data = (await helper.rft.getData(collectionId))!;42    const collection = helper.rft.getCollectionObject(collectionId);4344    expect(data.name).to.be.eq(name);45    expect(data.description).to.be.eq(description);46    expect(data.raw.tokenPrefix).to.be.eq(prefix);47    expect(data.raw.mode).to.be.eq('ReFungible');4849    const options = await collection.getOptions();5051    expect(options.tokenPropertyPermissions).to.be.empty;52  });5354  5556  itEth('Create collection with properties', async ({helper}) => {57    const owner = await helper.eth.createAccountWithBalance(donor);5859    const name = 'CollectionEVM';60    const description = 'Some description';61    const prefix = 'token prefix';62    const baseUri = 'BaseURI';6364    const {collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);6566    const collection = helper.rft.getCollectionObject(collectionId);67    const data = (await collection.getData())!;68    69    expect(data.name).to.be.eq(name);70    expect(data.description).to.be.eq(description);71    expect(data.raw.tokenPrefix).to.be.eq(prefix);72    expect(data.raw.mode).to.be.eq('ReFungible');7374    const options = await collection.getOptions();75    expect(options.tokenPropertyPermissions).to.be.deep.equal([76      {77        key: 'URI',78        permission: {mutable: true, collectionAdmin: true, tokenOwner: false},79      },80      {81        key: 'URISuffix',82        permission: {mutable: true, collectionAdmin: true, tokenOwner: false},83      },84    ]);85  });86  87  // this test will occasionally fail when in async environment.88  itEth.skip('Check collection address exist', async ({helper}) => {89    const owner = await helper.eth.createAccountWithBalance(donor);9091    const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;92    const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);93    const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);9495    expect(await collectionHelpers.methods96      .isCollectionExist(expectedCollectionAddress)97      .call()).to.be.false;9899    await collectionHelpers.methods100      .createRFTCollection('A', 'A', 'A')101      .send({value: Number(2n * helper.balance.getOneTokenNominal())});102    103    expect(await collectionHelpers.methods104      .isCollectionExist(expectedCollectionAddress)105      .call()).to.be.true;106  });107  108  // Soft-deprecated109  itEth('[eth] Set sponsorship', async ({helper}) => {110    const owner = await helper.eth.createAccountWithBalance(donor);111    const sponsor = await helper.eth.createAccountWithBalance(donor);112    const ss58Format = helper.chain.getChainProperties().ss58Format;113    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');114115    const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);116    await collection.methods.setCollectionSponsor(sponsor).send();117118    let data = (await helper.rft.getData(collectionId))!;119    expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));120121    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');122123    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);124    await sponsorCollection.methods.confirmCollectionSponsorship().send();125126    data = (await helper.rft.getData(collectionId))!;127    expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));128  });129130  itEth('[cross] Set sponsorship', async ({helper}) => {131    const owner = await helper.eth.createAccountWithBalance(donor);132    const sponsor = await helper.eth.createAccountWithBalance(donor);133    const ss58Format = helper.chain.getChainProperties().ss58Format;134    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');135136    const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);137    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);138    await collection.methods.setCollectionSponsorCross(sponsorCross).send();139140    let data = (await helper.rft.getData(collectionId))!;141    expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));142143    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');144145    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);146    await sponsorCollection.methods.confirmCollectionSponsorship().send();147148    data = (await helper.rft.getData(collectionId))!;149    expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));150  });151152  itEth('Set limits', async ({helper}) => {153    const owner = await helper.eth.createAccountWithBalance(donor);154    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'INSI');155    const limits = {156      accountTokenOwnershipLimit: 1000,157      sponsoredDataSize: 1024,158      sponsoredDataRateLimit: 30,159      tokenLimit: 1000000,160      sponsorTransferTimeout: 6,161      sponsorApproveTimeout: 6,162      ownerCanTransfer: false,163      ownerCanDestroy: false,164      transfersEnabled: false,165    };166167    const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);168    await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();169    await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send();170    await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();171    await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send();172    await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();173    await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();174    await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send();175    await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send();176    await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send();177    178    const data = (await helper.rft.getData(collectionId))!;179    expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit);180    expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize);181    expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit);182    expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit);183    expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout);184    expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout);185    expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer);186    expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy);187    expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled);188  });189190  itEth('Collection address exist', async ({helper}) => {191    const owner = await helper.eth.createAccountWithBalance(donor);192    const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';193    expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)194      .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())195      .to.be.false;196    197    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT');198    expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)199      .methods.isCollectionExist(collectionAddress).call())200      .to.be.true;201  });202});203204describe('(!negative tests!) Create RFT collection from EVM', () => {205  let donor: IKeyringPair;206  let nominal: bigint;207208  before(async function() {209    await usingEthPlaygrounds(async (helper, privateKey) => {210      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);211      donor = await privateKey({filename: __filename});212      nominal = helper.balance.getOneTokenNominal();213    });214  });215216  itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {217    const owner = await helper.eth.createAccountWithBalance(donor);218    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);219    {220      const MAX_NAME_LENGTH = 64;221      const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);222      const description = 'A';223      const tokenPrefix = 'A';224225      await expect(collectionHelper.methods226        .createRFTCollection(collectionName, description, tokenPrefix)227        .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);228    }229    {230      const MAX_DESCRIPTION_LENGTH = 256;231      const collectionName = 'A';232      const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);233      const tokenPrefix = 'A';234      await expect(collectionHelper.methods235        .createRFTCollection(collectionName, description, tokenPrefix)236        .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);237    }238    {239      const MAX_TOKEN_PREFIX_LENGTH = 16;240      const collectionName = 'A';241      const description = 'A';242      const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);243      await expect(collectionHelper.methods244        .createRFTCollection(collectionName, description, tokenPrefix)245        .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);246    }247  });248  249  itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {250    const owner = await helper.eth.createAccountWithBalance(donor);251    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);252    await expect(collectionHelper.methods253      .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')254      .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');255  });256257  // Soft-deprecated258  itEth('(!negative test!) [eth] Check owner', async ({helper}) => {259    const owner = await helper.eth.createAccountWithBalance(donor);260    const peasant = helper.eth.createAccount();261    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');262    const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true);263    const EXPECTED_ERROR = 'NoPermission';264    {265      const sponsor = await helper.eth.createAccountWithBalance(donor);266      await expect(peasantCollection.methods267        .setCollectionSponsor(sponsor)268        .call()).to.be.rejectedWith(EXPECTED_ERROR);269      270      const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);271      await expect(sponsorCollection.methods272        .confirmCollectionSponsorship()273        .call()).to.be.rejectedWith('caller is not set as sponsor');274    }275    {276      await expect(peasantCollection.methods277        .setCollectionLimit('account_token_ownership_limit', '1000')278        .call()).to.be.rejectedWith(EXPECTED_ERROR);279    }280  });281282  itEth('(!negative test!) [cross] Check owner', async ({helper}) => {283    const owner = await helper.eth.createAccountWithBalance(donor);284    const peasant = helper.eth.createAccount();285    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');286    const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant);287    const EXPECTED_ERROR = 'NoPermission';288    {289      const sponsor = await helper.eth.createAccountWithBalance(donor);290      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);291      await expect(peasantCollection.methods292        .setCollectionSponsorCross(sponsorCross)293        .call()).to.be.rejectedWith(EXPECTED_ERROR);294      295      const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);296      await expect(sponsorCollection.methods297        .confirmCollectionSponsorship()298        .call()).to.be.rejectedWith('caller is not set as sponsor');299    }300    {301      await expect(peasantCollection.methods302        .setCollectionLimit('account_token_ownership_limit', '1000')303        .call()).to.be.rejectedWith(EXPECTED_ERROR);304    }305  });306307  itEth('(!negative test!) Set limits', async ({helper}) => {308    const owner = await helper.eth.createAccountWithBalance(donor);309    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'ISNI');310    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);311    await expect(collectionEvm.methods312      .setCollectionLimit('badLimit', 'true')313      .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');314  });315  316  itEth('destroyCollection', async ({helper}) => {317    const owner = await helper.eth.createAccountWithBalance(donor);318    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');319    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);320    321    await expect(collectionHelper.methods322      .destroyCollection(collectionAddress)323      .send({from: owner})).to.be.fulfilled;324    325    expect(await collectionHelper.methods326      .isCollectionExist(collectionAddress)327      .call()).to.be.false;  328  });329});
after · tests/src/eth/createRFTCollection.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.8//9// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {evmToAddress} from '@polkadot/util-crypto';18import {IKeyringPair} from '@polkadot/types/types';19import {Pallets, requirePalletsOrSkip} from '../util';20import {expect, itEth, usingEthPlaygrounds} from './util';212223describe('Create RFT collection from EVM', () => {24  let donor: IKeyringPair;2526  before(async function() {27    await usingEthPlaygrounds(async (helper, privateKey) => {28      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);29      donor = await privateKey({filename: __filename});30    });31  });3233  itEth('Create collection', async ({helper}) => {34    const owner = await helper.eth.createAccountWithBalance(donor);35    36    const name = 'CollectionEVM';37    const description = 'Some description';38    const prefix = 'token prefix';39  40    const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix);41    const data = (await helper.rft.getData(collectionId))!;42    const collection = helper.rft.getCollectionObject(collectionId);4344    expect(data.name).to.be.eq(name);45    expect(data.description).to.be.eq(description);46    expect(data.raw.tokenPrefix).to.be.eq(prefix);47    expect(data.raw.mode).to.be.eq('ReFungible');4849    const options = await collection.getOptions();5051    expect(options.tokenPropertyPermissions).to.be.empty;52  });5354  5556  itEth('Create collection with properties', async ({helper}) => {57    const owner = await helper.eth.createAccountWithBalance(donor);5859    const name = 'CollectionEVM';60    const description = 'Some description';61    const prefix = 'token prefix';62    const baseUri = 'BaseURI';6364    const {collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri);6566    const collection = helper.rft.getCollectionObject(collectionId);67    const data = (await collection.getData())!;68    69    expect(data.name).to.be.eq(name);70    expect(data.description).to.be.eq(description);71    expect(data.raw.tokenPrefix).to.be.eq(prefix);72    expect(data.raw.mode).to.be.eq('ReFungible');7374    const options = await collection.getOptions();75    expect(options.tokenPropertyPermissions).to.be.deep.equal([76      {77        key: 'URI',78        permission: {mutable: true, collectionAdmin: true, tokenOwner: false},79      },80      {81        key: 'URISuffix',82        permission: {mutable: true, collectionAdmin: true, tokenOwner: false},83      },84    ]);85  });86  87  // this test will occasionally fail when in async environment.88  itEth.skip('Check collection address exist', async ({helper}) => {89    const owner = await helper.eth.createAccountWithBalance(donor);9091    const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;92    const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);93    const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);9495    expect(await collectionHelpers.methods96      .isCollectionExist(expectedCollectionAddress)97      .call()).to.be.false;9899    await collectionHelpers.methods100      .createRFTCollection('A', 'A', 'A')101      .send({value: Number(2n * helper.balance.getOneTokenNominal())});102    103    expect(await collectionHelpers.methods104      .isCollectionExist(expectedCollectionAddress)105      .call()).to.be.true;106  });107  108  // Soft-deprecated109  itEth('[eth] Set sponsorship', async ({helper}) => {110    const owner = await helper.eth.createAccountWithBalance(donor);111    const sponsor = await helper.eth.createAccountWithBalance(donor);112    const ss58Format = helper.chain.getChainProperties().ss58Format;113    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');114115    const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);116    await collection.methods.setCollectionSponsor(sponsor).send();117118    let data = (await helper.rft.getData(collectionId))!;119    expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));120121    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');122123    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);124    await sponsorCollection.methods.confirmCollectionSponsorship().send();125126    data = (await helper.rft.getData(collectionId))!;127    expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));128  });129130  itEth('[cross] Set sponsorship', async ({helper}) => {131    const owner = await helper.eth.createAccountWithBalance(donor);132    const sponsor = await helper.eth.createAccountWithBalance(donor);133    const ss58Format = helper.chain.getChainProperties().ss58Format;134    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY');135136    const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);137    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);138    await collection.methods.setCollectionSponsorCross(sponsorCross).send();139140    let data = (await helper.rft.getData(collectionId))!;141    expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));142143    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');144145    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);146    await sponsorCollection.methods.confirmCollectionSponsorship().send();147148    data = (await helper.rft.getData(collectionId))!;149    expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));150  });151152  itEth('Set limits', async ({helper}) => {153    const owner = await helper.eth.createAccountWithBalance(donor);154    const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'INSI');155    const limits = {156      accountTokenOwnershipLimit: 1000,157      sponsoredDataSize: 1024,158      sponsoredDataRateLimit: 30,159      tokenLimit: 1000000,160      sponsorTransferTimeout: 6,161      sponsorApproveTimeout: 6,162      ownerCanTransfer: 0,163      ownerCanDestroy: 0,164      transfersEnabled: 0,165    };166    167    const expectedLimits = {168      accountTokenOwnershipLimit: 1000,169      sponsoredDataSize: 1024,170      sponsoredDataRateLimit: 30,171      tokenLimit: 1000000,172      sponsorTransferTimeout: 6,173      sponsorApproveTimeout: 6,174      ownerCanTransfer: false,175      ownerCanDestroy: false,176      transfersEnabled: false,177    };178    179    const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);180    await collection.methods.setCollectionLimit('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();181    await collection.methods.setCollectionLimit('sponsoredDataSize', limits.sponsoredDataSize).send();182    await collection.methods.setCollectionLimit('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();183    await collection.methods.setCollectionLimit('tokenLimit', limits.tokenLimit).send();184    await collection.methods.setCollectionLimit('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();185    await collection.methods.setCollectionLimit('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();186    await collection.methods.setCollectionLimit('ownerCanTransfer', limits.ownerCanTransfer).send();187    await collection.methods.setCollectionLimit('ownerCanDestroy', limits.ownerCanDestroy).send();188    await collection.methods.setCollectionLimit('transfersEnabled', limits.transfersEnabled).send();189    190    const data = (await helper.rft.getData(collectionId))!;191    expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(expectedLimits.accountTokenOwnershipLimit);192    expect(data.raw.limits.sponsoredDataSize).to.be.eq(expectedLimits.sponsoredDataSize);193    expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(expectedLimits.sponsoredDataRateLimit);194    expect(data.raw.limits.tokenLimit).to.be.eq(expectedLimits.tokenLimit);195    expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(expectedLimits.sponsorTransferTimeout);196    expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(expectedLimits.sponsorApproveTimeout);197    expect(data.raw.limits.ownerCanTransfer).to.be.eq(expectedLimits.ownerCanTransfer);198    expect(data.raw.limits.ownerCanDestroy).to.be.eq(expectedLimits.ownerCanDestroy);199    expect(data.raw.limits.transfersEnabled).to.be.eq(expectedLimits.transfersEnabled);200  });201202  itEth('Collection address exist', async ({helper}) => {203    const owner = await helper.eth.createAccountWithBalance(donor);204    const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';205    expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)206      .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())207      .to.be.false;208    209    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT');210    expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)211      .methods.isCollectionExist(collectionAddress).call())212      .to.be.true;213  });214});215216describe('(!negative tests!) Create RFT collection from EVM', () => {217  let donor: IKeyringPair;218  let nominal: bigint;219220  before(async function() {221    await usingEthPlaygrounds(async (helper, privateKey) => {222      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);223      donor = await privateKey({filename: __filename});224      nominal = helper.balance.getOneTokenNominal();225    });226  });227228  itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {229    const owner = await helper.eth.createAccountWithBalance(donor);230    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);231    {232      const MAX_NAME_LENGTH = 64;233      const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);234      const description = 'A';235      const tokenPrefix = 'A';236237      await expect(collectionHelper.methods238        .createRFTCollection(collectionName, description, tokenPrefix)239        .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);240    }241    {242      const MAX_DESCRIPTION_LENGTH = 256;243      const collectionName = 'A';244      const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);245      const tokenPrefix = 'A';246      await expect(collectionHelper.methods247        .createRFTCollection(collectionName, description, tokenPrefix)248        .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);249    }250    {251      const MAX_TOKEN_PREFIX_LENGTH = 16;252      const collectionName = 'A';253      const description = 'A';254      const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);255      await expect(collectionHelper.methods256        .createRFTCollection(collectionName, description, tokenPrefix)257        .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);258    }259  });260  261  itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {262    const owner = await helper.eth.createAccountWithBalance(donor);263    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);264    await expect(collectionHelper.methods265      .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW')266      .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');267  });268269  // Soft-deprecated270  itEth('(!negative test!) [eth] Check owner', async ({helper}) => {271    const owner = await helper.eth.createAccountWithBalance(donor);272    const peasant = helper.eth.createAccount();273    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');274    const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true);275    const EXPECTED_ERROR = 'NoPermission';276    {277      const sponsor = await helper.eth.createAccountWithBalance(donor);278      await expect(peasantCollection.methods279        .setCollectionSponsor(sponsor)280        .call()).to.be.rejectedWith(EXPECTED_ERROR);281      282      const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);283      await expect(sponsorCollection.methods284        .confirmCollectionSponsorship()285        .call()).to.be.rejectedWith('caller is not set as sponsor');286    }287    {288      await expect(peasantCollection.methods289        .setCollectionLimit('account_token_ownership_limit', '1000')290        .call()).to.be.rejectedWith(EXPECTED_ERROR);291    }292  });293294  itEth('(!negative test!) [cross] Check owner', async ({helper}) => {295    const owner = await helper.eth.createAccountWithBalance(donor);296    const peasant = helper.eth.createAccount();297    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE');298    const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant);299    const EXPECTED_ERROR = 'NoPermission';300    {301      const sponsor = await helper.eth.createAccountWithBalance(donor);302      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);303      await expect(peasantCollection.methods304        .setCollectionSponsorCross(sponsorCross)305        .call()).to.be.rejectedWith(EXPECTED_ERROR);306      307      const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);308      await expect(sponsorCollection.methods309        .confirmCollectionSponsorship()310        .call()).to.be.rejectedWith('caller is not set as sponsor');311    }312    {313      await expect(peasantCollection.methods314        .setCollectionLimit('account_token_ownership_limit', '1000')315        .call()).to.be.rejectedWith(EXPECTED_ERROR);316    }317  });318319  itEth('(!negative test!) Set limits', async ({helper}) => {320    const invalidLimits = {321      accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER),322      transfersEnabled: 3,323    };324325    const owner = await helper.eth.createAccountWithBalance(donor);326    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'ISNI');327    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);328    329    await expect(collectionEvm.methods330      .setCollectionLimit(Object.keys(invalidLimits)[0], invalidLimits.accountTokenOwnershipLimit)331      .call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`);332    333    await expect(collectionEvm.methods334      .setCollectionLimit(Object.keys(invalidLimits)[1], invalidLimits.transfersEnabled)335      .call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`);336  });337  338  itEth('destroyCollection', async ({helper}) => {339    const owner = await helper.eth.createAccountWithBalance(donor);340    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');341    const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);342    343    await expect(collectionHelper.methods344      .destroyCollection(collectionAddress)345      .send({from: owner})).to.be.fulfilled;346    347    expect(await collectionHelper.methods348      .isCollectionExist(collectionAddress)349      .call()).to.be.false;  350  });351});