git.delta.rocks / unique-network / refs/commits / 5223dbed88c4

difftreelog

added `collectionNestingRestrictedCollectionIds()` function in `Collection` interface.

PraetorP2022-12-02parent: #46e50c0.patch.diff
in: master

14 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -493,6 +493,21 @@
 		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)
 	}
 
+	/// Returns nesting for a collection
+	#[solidity(rename_selector = "collectionNestingRestrictedCollectionIds")]
+	fn collection_nesting_restricted_ids(&self) -> Result<(bool, Vec<uint256>)> {
+		let nesting = self.collection.permissions.nesting();
+
+		Ok((
+			nesting.token_owner,
+			nesting
+				.restricted
+				.clone()
+				.map(|b| b.0.into_inner().iter().map(|id| id.0.into()).collect())
+				.unwrap_or_default(),
+		))
+	}
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
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 0xcc1d80ca
+/// @dev the ERC-165 identifier for this interface is 0xeecfdb34
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -254,6 +254,15 @@
 		dummy = 0;
 	}
 
+	/// Returns nesting for a collection
+	/// @dev EVM selector for this function is: 0x22d25bfe,
+	///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	function collectionNestingRestrictedCollectionIds() public view returns (Tuple21 memory) {
+		require(false, stub_error);
+		dummy;
+		return Tuple21(false, new uint256[](0));
+	}
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
@@ -425,6 +434,12 @@
 	uint256 sub;
 }
 
+/// @dev anonymous struct
+struct Tuple21 {
+	bool field_0;
+	uint256[] field_1;
+}
+
 /// @dev Property struct
 struct Property {
 	string key;
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 0xcc1d80ca
+/// @dev the ERC-165 identifier for this interface is 0xeecfdb34
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -355,6 +355,15 @@
 		dummy = 0;
 	}
 
+	/// Returns nesting for a collection
+	/// @dev EVM selector for this function is: 0x22d25bfe,
+	///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	function collectionNestingRestrictedCollectionIds() public view returns (Tuple34 memory) {
+		require(false, stub_error);
+		dummy;
+		return Tuple34(false, new uint256[](0));
+	}
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
@@ -527,6 +536,12 @@
 }
 
 /// @dev anonymous struct
+struct Tuple34 {
+	bool field_0;
+	uint256[] field_1;
+}
+
+/// @dev anonymous struct
 struct Tuple30 {
 	address field_0;
 	uint256 field_1;
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 0xcc1d80ca
+/// @dev the ERC-165 identifier for this interface is 0xeecfdb34
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -355,6 +355,15 @@
 		dummy = 0;
 	}
 
+	/// Returns nesting for a collection
+	/// @dev EVM selector for this function is: 0x22d25bfe,
+	///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	function collectionNestingRestrictedCollectionIds() public view returns (Tuple33 memory) {
+		require(false, stub_error);
+		dummy;
+		return Tuple33(false, new uint256[](0));
+	}
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
@@ -527,6 +536,12 @@
 }
 
 /// @dev anonymous struct
+struct Tuple33 {
+	bool field_0;
+	uint256[] field_1;
+}
+
+/// @dev anonymous struct
 struct Tuple29 {
 	address field_0;
 	uint256 field_1;
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.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
@@ -208,6 +208,27 @@
   },
   {
     "inputs": [],
+    "name": "collectionNestingRestrictedCollectionIds",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "field_0", "type": "bool" },
+          {
+            "internalType": "uint256[]",
+            "name": "field_1",
+            "type": "uint256[]"
+          }
+        ],
+        "internalType": "struct Tuple21",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "collectionOwner",
     "outputs": [
       {
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -238,6 +238,27 @@
   },
   {
     "inputs": [],
+    "name": "collectionNestingRestrictedCollectionIds",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "field_0", "type": "bool" },
+          {
+            "internalType": "uint256[]",
+            "name": "field_1",
+            "type": "uint256[]"
+          }
+        ],
+        "internalType": "struct Tuple34",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "collectionOwner",
     "outputs": [
       {
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -220,6 +220,27 @@
   },
   {
     "inputs": [],
+    "name": "collectionNestingRestrictedCollectionIds",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "field_0", "type": "bool" },
+          {
+            "internalType": "uint256[]",
+            "name": "field_1",
+            "type": "uint256[]"
+          }
+        ],
+        "internalType": "struct Tuple33",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "collectionOwner",
     "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 0xcc1d80ca
+/// @dev the ERC-165 identifier for this interface is 0xeecfdb34
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -166,6 +166,11 @@
 	///  or in textual repr: setCollectionNesting(bool,address[])
 	function setCollectionNesting(bool enable, address[] memory collections) external;
 
+	/// Returns nesting for a collection
+	/// @dev EVM selector for this function is: 0x22d25bfe,
+	///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	function collectionNestingRestrictedCollectionIds() external view returns (Tuple20 memory);
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
@@ -278,6 +283,12 @@
 	uint256 sub;
 }
 
+/// @dev anonymous struct
+struct Tuple20 {
+	bool field_0;
+	uint256[] field_1;
+}
+
 /// @dev Property struct
 struct Property {
 	string key;
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 0xcc1d80ca
+/// @dev the ERC-165 identifier for this interface is 0xeecfdb34
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -233,6 +233,11 @@
 	///  or in textual repr: setCollectionNesting(bool,address[])
 	function setCollectionNesting(bool enable, address[] memory collections) external;
 
+	/// Returns nesting for a collection
+	/// @dev EVM selector for this function is: 0x22d25bfe,
+	///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	function collectionNestingRestrictedCollectionIds() external view returns (Tuple31 memory);
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
@@ -346,6 +351,12 @@
 }
 
 /// @dev anonymous struct
+struct Tuple31 {
+	bool field_0;
+	uint256[] field_1;
+}
+
+/// @dev anonymous struct
 struct Tuple27 {
 	address field_0;
 	uint256 field_1;
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 0xcc1d80ca
+/// @dev the ERC-165 identifier for this interface is 0xeecfdb34
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -233,6 +233,11 @@
 	///  or in textual repr: setCollectionNesting(bool,address[])
 	function setCollectionNesting(bool enable, address[] memory collections) external;
 
+	/// Returns nesting for a collection
+	/// @dev EVM selector for this function is: 0x22d25bfe,
+	///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	function collectionNestingRestrictedCollectionIds() external view returns (Tuple30 memory);
+
 	/// Set the collection access method.
 	/// @param mode Access mode
 	/// 	0 for Normal
@@ -346,6 +351,12 @@
 }
 
 /// @dev anonymous struct
+struct Tuple30 {
+	bool field_0;
+	uint256[] field_1;
+}
+
+/// @dev anonymous struct
 struct Tuple26 {
 	address field_0;
 	uint256 field_1;
modifiedtests/src/eth/nesting/nest.test.tsdiffbeforeafterboth
before · tests/src/eth/nesting/nest.test.ts
1import {IKeyringPair} from '@polkadot/types/types';2import {Contract} from 'web3-eth-contract';34import {itEth, EthUniqueHelper, usingEthPlaygrounds, expect} from '../util';56const createNestingCollection = async (7  helper: EthUniqueHelper,8  owner: string,9): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {10  const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');1112  const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);13  await contract.methods.setCollectionNesting(true).send({from: owner});1415  return {collectionId, collectionAddress, contract};16};171819describe('EVM nesting tests group', () => {20  let donor: IKeyringPair;2122  before(async function() {23    await usingEthPlaygrounds(async (_, privateKey) => {24      donor = await privateKey({filename: __filename});25    });26  });2728  describe('Integration Test: EVM Nesting', () => {29    itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {30      const owner = await helper.eth.createAccountWithBalance(donor);31      const {collectionId, contract} = await createNestingCollection(helper, owner);3233      // Create a token to be nested to34      const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});35      const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;36      const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);3738      // Create a nested token39      const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});40      const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;41      expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);4243      // Create a token to be nested and nest44      const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});45      const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;4647      await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});48      expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);4950      // Unnest token back51      await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});52      expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);53    });5455    itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {56      const owner = await helper.eth.createAccountWithBalance(donor);5758      const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);59      const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);60      await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});6162      // Create a token to nest into63      const mintingtargetNftTokenIdResult = await contractA.methods.mint(owner).send({from: owner});64      const targetNftTokenId = mintingtargetNftTokenIdResult.events.Transfer.returnValues.tokenId;65      const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);6667      // Create a token for nesting in the same collection as the target68      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});69      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;7071      // Create a token for nesting in a different collection72      const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});73      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;7475      // Nest76      await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});77      expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);7879      await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});80      expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);81    });82  });8384  describe('Negative Test: EVM Nesting', () => {85    itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {86      const owner = await helper.eth.createAccountWithBalance(donor);8788      const {collectionId, contract} = await createNestingCollection(helper, owner);89      await contract.methods.setCollectionNesting(false).send({from: owner});9091      // Create a token to nest into92      const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});93      const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;94      const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);9596      // Create a token to nest97      const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});98      const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;99100      // Try to nest101      await expect(contract.methods102        .transfer(targetNftTokenAddress, nftTokenId)103        .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');104    });105106    itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {107      const owner = await helper.eth.createAccountWithBalance(donor);108      const malignant = await helper.eth.createAccountWithBalance(donor);109110      const {collectionId, contract} = await createNestingCollection(helper, owner);111112      // Mint a token113      const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});114      const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;115      const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);116117      // Mint a token belonging to a different account118      const mintingTokenIdResult = await contract.methods.mint(malignant).send({from: owner});119      const tokenId = mintingTokenIdResult.events.Transfer.returnValues.tokenId;120121      // Try to nest one token in another as a non-owner account122      await expect(contract.methods123        .transfer(targetTokenAddress, tokenId)124        .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');125    });126127    itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {128      const owner = await helper.eth.createAccountWithBalance(donor);129      const malignant = await helper.eth.createAccountWithBalance(donor);130131      const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);132      const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);133134      await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});135136      // Create a token in one collection137      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});138      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;139      const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);140141      // Create a token in another collection142      const mintingTokenIdBResult = await contractB.methods.mint(malignant).send({from: owner});143      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;144145      // Try to drag someone else's token into the other collection and nest146      await expect(contractB.methods147        .transfer(nftTokenAddressA, nftTokenIdB)148        .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');149    });150151    itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {152      const owner = await helper.eth.createAccountWithBalance(donor);153154      const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);155      const {contract: contractB} = await createNestingCollection(helper, owner);156157      await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});158159      // Create a token in one collection160      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});161      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;162      const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);163164      // Create a token in another collection165      const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});166      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;167168169      // Try to nest into a token in the other collection, disallowed in the first170      await expect(contractB.methods171        .transfer(nftTokenAddressA, nftTokenIdB)172        .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');173    });174  });175});
after · tests/src/eth/nesting/nest.test.ts
1import {IKeyringPair} from '@polkadot/types/types';2import {Contract} from 'web3-eth-contract';34import {itEth, EthUniqueHelper, usingEthPlaygrounds, expect} from '../util';56const createNestingCollection = async (7  helper: EthUniqueHelper,8  owner: string,9): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {10  const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');1112  const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);13  await contract.methods.setCollectionNesting(true).send({from: owner});1415  return {collectionId, collectionAddress, contract};16};171819describe('EVM nesting tests group', () => {20  let donor: IKeyringPair;2122  before(async function() {23    await usingEthPlaygrounds(async (_, privateKey) => {24      donor = await privateKey({filename: __filename});25    });26  });2728  describe('Integration Test: EVM Nesting', () => {29    itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {30      const owner = await helper.eth.createAccountWithBalance(donor);31      const {collectionId, contract} = await createNestingCollection(helper, owner);3233      // Create a token to be nested to34      const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});35      const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;36      const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);3738      // Create a nested token39      const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner});40      const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId;41      expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);4243      // Create a token to be nested and nest44      const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});45      const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;4647      await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});48      expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);4950      // Unnest token back51      await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});52      expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);53    });54    55    itEth('NFT: collectionNestingRestrictedCollectionIds()', async ({helper}) => {56      const owner = await helper.eth.createAccountWithBalance(donor);57      const {collectionId: unnestedCollsectionId, collectionAddress: unnsetedCollectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');58      const unnestedContract = helper.ethNativeContract.collection(unnsetedCollectionAddress, 'nft', owner);59      expect(await unnestedContract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([false, []]);60      61      const {contract} = await createNestingCollection(helper, owner);62      expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, []]);63      await contract.methods.setCollectionNesting(true, [unnsetedCollectionAddress]).send({from: owner});64      expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, [unnestedCollsectionId.toString()]]);65      66    });67    68    itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {69      const owner = await helper.eth.createAccountWithBalance(donor);7071      const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);72      const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);73      await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});7475      // Create a token to nest into76      const mintingtargetNftTokenIdResult = await contractA.methods.mint(owner).send({from: owner});77      const targetNftTokenId = mintingtargetNftTokenIdResult.events.Transfer.returnValues.tokenId;78      const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);7980      // Create a token for nesting in the same collection as the target81      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});82      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;8384      // Create a token for nesting in a different collection85      const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});86      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;8788      // Nest89      await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});90      expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);9192      await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});93      expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);94    });95  });9697  describe('Negative Test: EVM Nesting', () => {98    itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {99      const owner = await helper.eth.createAccountWithBalance(donor);100101      const {collectionId, contract} = await createNestingCollection(helper, owner);102      await contract.methods.setCollectionNesting(false).send({from: owner});103104      // Create a token to nest into105      const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});106      const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;107      const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);108109      // Create a token to nest110      const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner});111      const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId;112113      // Try to nest114      await expect(contract.methods115        .transfer(targetNftTokenAddress, nftTokenId)116        .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');117    });118119    itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {120      const owner = await helper.eth.createAccountWithBalance(donor);121      const malignant = await helper.eth.createAccountWithBalance(donor);122123      const {collectionId, contract} = await createNestingCollection(helper, owner);124125      // Mint a token126      const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner});127      const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId;128      const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);129130      // Mint a token belonging to a different account131      const mintingTokenIdResult = await contract.methods.mint(malignant).send({from: owner});132      const tokenId = mintingTokenIdResult.events.Transfer.returnValues.tokenId;133134      // Try to nest one token in another as a non-owner account135      await expect(contract.methods136        .transfer(targetTokenAddress, tokenId)137        .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');138    });139140    itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {141      const owner = await helper.eth.createAccountWithBalance(donor);142      const malignant = await helper.eth.createAccountWithBalance(donor);143144      const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);145      const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);146147      await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});148149      // Create a token in one collection150      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});151      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;152      const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);153154      // Create a token in another collection155      const mintingTokenIdBResult = await contractB.methods.mint(malignant).send({from: owner});156      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;157158      // Try to drag someone else's token into the other collection and nest159      await expect(contractB.methods160        .transfer(nftTokenAddressA, nftTokenIdB)161        .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');162    });163164    itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {165      const owner = await helper.eth.createAccountWithBalance(donor);166167      const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);168      const {contract: contractB} = await createNestingCollection(helper, owner);169170      await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});171172      // Create a token in one collection173      const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner});174      const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId;175      const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);176177      // Create a token in another collection178      const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner});179      const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId;180181182      // Try to nest into a token in the other collection, disallowed in the first183      await expect(contractB.methods184        .transfer(nftTokenAddressA, nftTokenIdB)185        .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');186    });187  });188});