git.delta.rocks / unique-network / refs/commits / 903c7da37bfa

difftreelog

test(sub/nesting) children checking + orderliness

Fahrrader2023-05-17parent: #a8ddb93.patch.diff
in: master

6 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -39,12 +39,14 @@
     "testParallelFull": "yarn testParallel && yarn testSequential",
     "testParallel": "yarn _testParallel './src/**/*.test.ts'",
     "testSequential": "yarn _test './src/**/*.seqtest.ts'",
-    "testStructure": "yarn setup && yarn _test ./**/nesting/*.*test.ts",
-    "testEth": "yarn setup && yarn _test './**/eth/**/*.*test.ts'",
-    "testEthNesting": "yarn setup && yarn _test './**/eth/nesting/**/*.*test.ts'",
-    "testEthFractionalizer": "yarn setup && yarn _test './**/eth/fractionalizer/**/*.*test.ts'",
-    "testEthMarketplace": "yarn setup && yarn _test './**/eth/marketplace/**/*.*test.ts'",
-    "testEvent": "yarn setup && yarn _test ./src/check-event/*.*test.ts",
+    "testStructure": "yarn _test ./**/nesting/*.*test.ts",
+    "testEth": "yarn _test './**/eth/**/*.*test.ts'",
+    "testEthNesting": "yarn _test './**/eth/nesting/**/*.*test.ts'",
+    "testEthFractionalizer": "yarn _test './**/eth/fractionalizer/**/*.*test.ts'",
+    "testEthMarketplace": "yarn _test './**/eth/marketplace/**/*.*test.ts'",
+    "testSub": "yarn _test './**/sub/**/*.*test.ts'",
+    "testSubNesting": "yarn _test './**/sub/nesting/**/*.*test.ts'",
+    "testEvent": "yarn _test ./src/check-event/*.*test.ts",
     "testEthPayable": "yarn _test './**/eth/payable.test.ts'",
     "testEvmCoder": "yarn _test './**/eth/evmCoder.test.ts'",
     "testNesting": "yarn _test ./**/nest.test.ts",
modifiedtests/src/sub/nesting/admin.test.tsdiffbeforeafterboth
--- a/tests/src/sub/nesting/admin.test.ts
+++ b/tests/src/sub/nesting/admin.test.ts
@@ -17,7 +17,7 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {expect, itSub, usingPlaygrounds} from '../../util';
 
-describe('Collection admin', () => {
+describe('Nesting by collection admin', () => {
   let alice: IKeyringPair;
   let bob: IKeyringPair;
   let charlie: IKeyringPair;
@@ -84,4 +84,3 @@
     expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());
   });
 });
-
modifiedtests/src/sub/nesting/common.test.tsdiffbeforeafterboth
--- a/tests/src/sub/nesting/common.test.ts
+++ b/tests/src/sub/nesting/common.test.ts
@@ -21,130 +21,143 @@
 let alice: IKeyringPair;
 let bob: IKeyringPair;
 
-before(async () => {
-  await usingPlaygrounds(async (helper, privateKey) => {
-    const donor = await privateKey({url: import.meta.url});
-    [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+describe('Common nesting tests', () => {
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+    });
   });
-});
 
-[
-  {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
-  {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
-  {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
-  {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
-].map(testCase => {
-  itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
-    // Only NFT can be target for nesting in
-    const targetNFTCollection = await helper.nft.mintCollection(alice);
-    const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+  [
+    {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
+    {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
+    {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
+    {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
+  ].map(testCase => {
+    itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
+      // Only NFT can be target for nesting in
+      const targetNFTCollection = await helper.nft.mintCollection(alice);
+      const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
 
-    const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
-    // permissions should be set:
-    await targetNFTCollection.setPermissions(alice, {
-      nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
-    });
+      const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
+      // permissions should be set:
+      await targetNFTCollection.setPermissions(alice, {
+        nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+      });
 
-    // 1. Bob can immediately create nested token:
-    const nestedToken1 = testCase.mode === 'nft'
-      ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
-      : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
-    expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
-    expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
+      // 1. Bob can immediately create nested token:
+      const nestedToken1 = testCase.mode === 'nft'
+        ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
+        : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
+      expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+      expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
 
-    // 2. Bob can mint and nest token:
-    const nestedToken2 = await collectionForNesting.mintToken(bob);
-    await nestedToken2.nest(bob, targetTokenBob);
-    expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
-    expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
+      // 2. Bob can mint and nest token:
+      const nestedToken2 = await collectionForNesting.mintToken(bob);
+      await nestedToken2.nest(bob, targetTokenBob);
+      expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+      expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
+    });
   });
-});
 
 
-[
-  {restrictedMode: true},
-  {restrictedMode: false},
-].map(testCase => {
-  itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set  ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
-    // Only NFT allows nesting, permissions should be set:
-    const targetNFTCollection = await helper.nft.mintCollection(alice);
-    const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+  [
+    {restrictedMode: true},
+    {restrictedMode: false},
+  ].map(testCase => {
+    itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set  ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
+      // Only NFT allows nesting, permissions should be set:
+      const targetNFTCollection = await helper.nft.mintCollection(alice);
+      const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
 
-    const collectionForNesting = await helper.ft.mintCollection(bob);
-    // permissions should be set:
-    await targetNFTCollection.setPermissions(alice, {
-      nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
-    });
+      const collectionForNesting = await helper.ft.mintCollection(bob);
+      // permissions should be set:
+      await targetNFTCollection.setPermissions(alice, {
+        nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+      });
 
-    // 1. Alice can immediately create nested tokens:
-    await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
-    expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);
-    expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
+      // 1. Alice can immediately create nested tokens:
+      await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
+      expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);
+      expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
 
-    // 2. Alice can mint and nest token:
-    await collectionForNesting.mint(bob, 100n);
-    await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
-    expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
+      // 2. Alice can mint and nest token:
+      await collectionForNesting.mint(bob, 100n);
+      await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
+      expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
+      expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);
+    });
   });
-});
 
-[
-  {restrictedMode: true},
-  {restrictedMode: false},
-].map(testCase => {
-  itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set  ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
-    // Only NFT allows nesting, permissions should be set:
-    const targetNFTCollection = await helper.nft.mintCollection(alice);
-    const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+  [
+    {restrictedMode: true},
+    {restrictedMode: false},
+  ].map(testCase => {
+    itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set  ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
+      // Only NFT allows nesting, permissions should be set:
+      const targetNFTCollection = await helper.nft.mintCollection(alice);
+      const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+      expect(await targetTokenBob.getChildren()).to.be.empty;
 
-    const collectionForNesting = helper.ft.getCollectionObject(0);
-    // permissions should be set:
-    await targetNFTCollection.setPermissions(alice, {
-      nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+      const collectionForNesting = helper.ft.getCollectionObject(0);
+      // permissions should be set:
+      await targetNFTCollection.setPermissions(alice, {
+        nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+      });
+
+      // Bob can nest Native FT into their NFT:
+      await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
+      expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
+      expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: 0, tokenId: 0}]);
     });
-
-    // Bob can nest Native FT into their NFT:
-    await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
-    expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
   });
-});
 
 
-itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
-  const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-  const tokenA = await collectionToNest.mintToken(alice);
-  const tokenB = await collectionToNest.mintToken(alice);
+  itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
+    const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const tokenA = await collectionToNest.mintToken(alice);
+    const tokenB = await collectionToNest.mintToken(alice);
 
-  // Create a nested token
-  const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-  const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-  const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-  const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
+    // Create a nested token
+    const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
 
-  const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
-  const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
-  const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
-  await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
-  expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
-  expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
-  expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
-  expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
+    const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
+    const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
+    const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
+    await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
+    expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
+    expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
+    expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
+    expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
 
-  // Transfer the nested token to another token
-  await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
-  await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
-  await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
-  await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+    expect(await tokenA.getChildren()).to.be.length(4);
+    expect(await tokenB.getChildren()).to.be.length(0);
 
-  expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
-  expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());
+    // Transfer the nested token to another token
+    await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
+    await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+    await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+    await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
 
-  expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);
-  expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);
+    expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
+    expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());
+
+    expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);
+    expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);
+
+    expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
+    expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
 
-  expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
-  expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
+    expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
+    expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
 
-  expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
-  expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
+    // RFT, FT, and native FT
+    expect(await tokenA.getChildren()).to.be.length(3);
+    // NFT, RFT, FT, and native FT
+    expect(await tokenB.getChildren()).to.be.length(4);
+  });
 });
modifiedtests/src/sub/nesting/e2e.test.tsdiffbeforeafterboth
--- a/tests/src/sub/nesting/e2e.test.ts
+++ b/tests/src/sub/nesting/e2e.test.ts
@@ -32,7 +32,7 @@
     const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
     const collectionB = await helper.ft.mintCollection(alice);
     const collectionC = await helper.rft.mintCollection(alice);
-    const collectionD = helper.ft.getCollectionObject(0);
+    const collectionNative = helper.ft.getCollectionObject(0);
 
     const targetToken = await collectionA.mintToken(alice);
     expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation');
@@ -75,12 +75,12 @@
     ]).and.has.length(3);
 
     // Nest native fungible token into another collection
-    await collectionD.transfer(alice, targetToken.nestingAccount(), 2n);
+    await collectionNative.transfer(alice, targetToken.nestingAccount(), 2n);
     expect(await targetToken.getChildren()).to.have.deep.members([
       {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
       {tokenId: 0, collectionId: collectionB.collectionId},
       {tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
-      {tokenId: 0, collectionId: collectionD.collectionId},
+      {tokenId: 0, collectionId: collectionNative.collectionId},
     ]).and.has.length(4);
 
     // Burn all nested pieces
@@ -88,7 +88,7 @@
     expect(await targetToken.getChildren()).to.have.deep.members([
       {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
       {tokenId: 0, collectionId: collectionB.collectionId},
-      {tokenId: 0, collectionId: collectionD.collectionId},
+      {tokenId: 0, collectionId: collectionNative.collectionId},
     ])
       .and.has.length(3);
 
@@ -97,7 +97,7 @@
     expect(await targetToken.getChildren()).to.be.have.deep.members([
       {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
       {tokenId: 0, collectionId: collectionB.collectionId},
-      {tokenId: 0, collectionId: collectionD.collectionId},
+      {tokenId: 0, collectionId: collectionNative.collectionId},
     ]).and.has.length(3);
     // Nested token also has children now:
     expect(await tokenA.getChildren()).to.have.deep.members([
@@ -108,7 +108,7 @@
     await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
     expect(await targetToken.getChildren()).to.have.deep.members([
       {tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
-      {tokenId: 0, collectionId: collectionD.collectionId},
+      {tokenId: 0, collectionId: collectionNative.collectionId},
     ]).and.has.length(2);
     expect(await tokenA.getChildren()).to.have.deep.members([
       {tokenId: 0, collectionId: collectionB.collectionId},
modifiedtests/src/sub/nesting/nesting.negative.test.tsdiffbeforeafterboth
before · tests/src/sub/nesting/nesting.negative.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.89// 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 {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../../util/playgrounds/unique';20import {itEth} from '../../eth/util';2122let alice: IKeyringPair;23let bob: IKeyringPair;24let charlie: IKeyringPair;2526before(async () => {27  await usingPlaygrounds(async (helper, privateKey) => {28    const donor = await privateKey({url: import.meta.url});29    [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);30  });31});3233[34  {mode: 'nft' as const, requiredPallets: []},35  {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},36].map(testCase => {37  itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {38    // Create default collection, permissions are not set:39    const aliceNFTCollection = await helper.nft.mintCollection(alice);40    const targetToken = await aliceNFTCollection.mintToken(alice);4142    const collectionForNesting = await helper[testCase.mode].mintCollection(alice);4344    // 1. Alice cannot create immediately nested tokens:45    const nestingTx = testCase.mode === 'nft'46      ? (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())47      : (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());48    await expect(nestingTx).to.be.rejectedWith('common.UserIsNotAllowedToNest');4950    // 2. Alice cannot mint and nest token:51    const nestedToken2 = await collectionForNesting.mintToken(alice);52    await expect(nestedToken2.nest(alice, targetToken)).to.be.rejectedWith('common.UserIsNotAllowedToNest');53  });54});5556[57  {mode: 'ft'},58  {mode: 'nativeFt'},59].map(testCase => {60  itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled`, async ({helper}) => {61  // Create default collection, permissions are not set:62    const aliceNFTCollection = await helper.nft.mintCollection(alice);63    const targetToken = await aliceNFTCollection.mintToken(alice);6465    const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);6667    // Alice cannot create immediately nested tokens:68    await expect(testCase.mode === 'ft'69      ? collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())70      : collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');7172    // Alice can't mint and nest tokens:73    if (testCase.mode === 'ft') {74      await collectionForNesting.mint(alice, 100n);75    }76    await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');77  });78});7980[81  {mode: 'nft' as const},82  {mode: 'rft' as const},83  {mode: 'ft' as const},84  {mode: 'native ft' as const},85].map(testCase => {86  itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens`, async ({helper}) => {87    const targetCollection = await helper.nft.mintCollection(alice, {permissions:88      {nesting: {tokenOwner: true, collectionAdmin: true}},89    });90    const targetToken = await targetCollection.mintToken(alice);9192    const nestedCollectionBob = await (93      testCase.mode === 'native ft'94        ? helper.ft.getCollectionObject(0)95        : helper[testCase.mode].mintCollection(bob)96    );9798    let nestedTokenBob: UniqueNFToken | UniqueRFToken;99    switch (testCase.mode) {100      case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;101      case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;102      case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;103      case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;104    }105106    // Bob non-owner of targetToken and non admin of targetCollection, so107    // 1. cannot mint nested token:108    switch (testCase.mode) {109      case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;110      case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;111      case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;112      case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;113    }114115    // 2. cannot nest existing token:116    switch (testCase.mode) {117      case 'nft':118      case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;119      case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;120      case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;121    }122  });123});124125[126  {mode: 'nft' as const, nesting: {tokenOwner: true,  collectionAdmin: false}},127  {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},128].map(testCase => {129  itSub(`${testCase.nesting.tokenOwner ? 'Admin' : 'Token owner'} cannot nest when only ${testCase.nesting.tokenOwner ? 'tokenOwner' : 'collectionAdmin'} is allowed`, async ({helper}) => {130    // Create collection with tokenOwner or create collection with collectionAdmin permission:131    const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});132    const targetTokenCharlie = await targetCollection.mintToken(alice, {Substrate: charlie.address});133    await targetCollection.addAdmin(alice, {Substrate: bob.address});134135    const nestedCollectionCharlie = await helper[testCase.mode].mintCollection(charlie);136    const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);137    // if nesting permissions restricted for token owner – minter is bob (admin),138    // if collectionAdmin – charlie (owner)139    testCase.nesting.tokenOwner140      ? await expect(nestedCollectionBob.mintToken(bob, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)141      : await expect(nestedCollectionCharlie.mintToken(charlie, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);142  });143});144145itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {146  const collection = await helper.nft.mintCollection(alice);147  // To avoid UserIsNotAllowedToNest error148  await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});149150  // The list of non-existing tokens:151  const tokenFromNonExistingCollection = helper.nft.getTokenObject(9999999, 1);152  const tokenBurnt = await collection.mintToken(alice);153  await tokenBurnt.burn(alice);154  const tokenNotMintedYet = helper.nft.getTokenObject(collection.collectionId, 2);155156  // The list of collections to nest tokens from:157  const nftCollectionForNesting = await helper.nft.mintCollection(alice);158  const rftCollectionForNesting = await helper.rft.mintCollection(alice);159  const ftCollectionForNesting = await helper.ft.mintCollection(alice);160  const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);161162  const testCases = [163    {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},164    {token: tokenBurnt, error: 'TokenNotFound'},165    {token: tokenNotMintedYet, error: 'TokenNotFound'},166  ];167168  for(const testCase of testCases) {169    // 1. Alice cannot create nested token to non-existing token170    await expect(nftCollectionForNesting.mintToken(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);171    await expect(rftCollectionForNesting.mintToken(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);172    await expect(ftCollectionForNesting.mint(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);173174    // 2. Alice cannot mint and nest token:175    const nft = await nftCollectionForNesting.mintToken(alice);176    const rft = await rftCollectionForNesting.mintToken(alice, 100n);177    const _ft = await ftCollectionForNesting.mint(alice, 100n);178    await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);179    await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);180    await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);181    await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);182  }183});184185itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {186  const existingCollection = await helper.nft.mintCollection(alice);187  const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);188  const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);189190  const nftCollectionForNesting = await helper.nft.mintCollection(alice);191192  // 1. Alice cannot create nested token to collection address193  await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');194  await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');195196  // 2. Alice cannot mint and nest token to collection address:197  const nft = await nftCollectionForNesting.mintToken(alice);198  await expect(nft.transfer(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');199  await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');200});201202itEth.ifWithPallets('Cannot nest in RFT or FT', [Pallets.ReFungible], async ({helper}) => {203  // Create default collection, permissions are not set:204  const rftCollection = await helper.rft.mintCollection(alice);205  const ftCollection = await helper.ft.mintCollection(alice);206  const nativeFtCollection = helper.ft.getCollectionObject(0);207208  const rftToken = await rftCollection.mintToken(alice);209  const _ftToken = await ftCollection.mint(alice, 100n);210211  const collectionForNesting = await helper.nft.mintCollection(alice);212213  // 1. Alice cannot create immediately nested tokens:214  await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');215  await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');216  await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');217218  // 2. Alice cannot mint and nest token:219  const nestedToken2 = await collectionForNesting.mintToken(alice);220  await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');221  await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');222  await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');223});224225itSub('Cannot nest in restricted collection if collection is not in the list', async ({helper}) => {226  const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);227  const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);228  const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);229  const notAllowedCollectionFT = await helper.ft.mintCollection(alice);230  const notAllowedCollectionNativeFT = helper.ft.getCollectionObject(0);231232  // Collection restricted to allowedCollectionId233  const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:234    {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},235  });236  // Create collection with restricted nesting -- even self is not allowed237  const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:238    {nesting: {tokenOwner: true, restricted: []}},239  });240241  const targetTokenA = await restrictedCollectionA.mintToken(alice);242  const targetTokenB = await restrictedCollectionB.mintToken(alice);243244  // 1. Cannot mint in own collection after allowlisting the accounts:245  await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);246  await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);247248  // 2. Cannot mint from notAllowedCollection:249  await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);250  await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);251  await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);252  await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);253  await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);254  await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);255  await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);256  await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);257});258259itSub('Cannot create nesting chains greater than 5', async ({helper}) => {260  const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});261  let token = await collection.mintToken(alice);262263  const maxNestingLevel = 5;264265  // Create a nested-token matryoshka266  for (let i = 0; i < maxNestingLevel; i++) {267    token = await collection.mintToken(alice, token.nestingAccount());268  }269270  // The nesting depth is limited by `maxNestingLevel`271  // 1. Cannot mint:272  await expect(collection.mintToken(alice, token.nestingAccount()))273    .to.be.rejectedWith(/structure\.DepthLimit/);274  // 2. Cannot transfer:275  const anotherToken = await collection.mintToken(alice);276  await expect(anotherToken.transfer(alice, token.nestingAccount()))277    .to.be.rejectedWith(/structure\.DepthLimit/);278  // 3. Cannot nest FT pieces:279  const ftCollection = await helper.ft.mintCollection(alice);280  await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))281    .to.be.rejectedWith(/structure\.DepthLimit/);282283  expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});284  expect(await token.getChildren()).to.has.length(0);285});
after · tests/src/sub/nesting/nesting.negative.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.89// 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 {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../../util/playgrounds/unique';20import {itEth} from '../../eth/util';2122let alice: IKeyringPair;23let bob: IKeyringPair;24let charlie: IKeyringPair;2526describe('Negative Test: Nesting', () => {27  before(async () => {28    await usingPlaygrounds(async (helper, privateKey) => {29      const donor = await privateKey({url: import.meta.url});30      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);31    });32  });3334  [35    {mode: 'nft' as const, requiredPallets: []},36    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},37  ].map(testCase => {38    itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {39      // Create default collection, permissions are not set:40      const aliceNFTCollection = await helper.nft.mintCollection(alice);41      const targetToken = await aliceNFTCollection.mintToken(alice);4243      const collectionForNesting = await helper[testCase.mode].mintCollection(alice);4445      // 1. Alice cannot create immediately nested tokens:46      const nestingTx = testCase.mode === 'nft'47        ? (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())48        : (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());49      await expect(nestingTx).to.be.rejectedWith('common.UserIsNotAllowedToNest');5051      // 2. Alice cannot mint and nest token:52      const nestedToken2 = await collectionForNesting.mintToken(alice);53      await expect(nestedToken2.nest(alice, targetToken)).to.be.rejectedWith('common.UserIsNotAllowedToNest');54    });55  });5657  [58    {mode: 'ft'},59    {mode: 'nativeFt'},60  ].map(testCase => {61    itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled`, async ({helper}) => {62    // Create default collection, permissions are not set:63      const aliceNFTCollection = await helper.nft.mintCollection(alice);64      const targetToken = await aliceNFTCollection.mintToken(alice);6566      const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);6768      // Alice cannot create immediately nested tokens:69      await expect(testCase.mode === 'ft'70        ? collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())71        : collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');7273      // Alice can't mint and nest tokens:74      if (testCase.mode === 'ft') {75        await collectionForNesting.mint(alice, 100n);76      }77      await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');78    });79  });8081  [82    {mode: 'nft' as const},83    {mode: 'rft' as const},84    {mode: 'ft' as const},85    {mode: 'native ft' as const},86  ].map(testCase => {87    itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens`, async ({helper}) => {88      const targetCollection = await helper.nft.mintCollection(alice, {permissions:89        {nesting: {tokenOwner: true, collectionAdmin: true}},90      });91      const targetToken = await targetCollection.mintToken(alice);9293      const nestedCollectionBob = await (94        testCase.mode === 'native ft'95          ? helper.ft.getCollectionObject(0)96          : helper[testCase.mode].mintCollection(bob)97      );9899      let nestedTokenBob: UniqueNFToken | UniqueRFToken;100      switch (testCase.mode) {101        case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;102        case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;103        case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;104        case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;105      }106107      // Bob non-owner of targetToken and non admin of targetCollection, so108      // 1. cannot mint nested token:109      switch (testCase.mode) {110        case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;111        case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;112        case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;113        case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;114      }115116      // 2. cannot nest existing token:117      switch (testCase.mode) {118        case 'nft':119        case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;120        case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;121        case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;122      }123    });124  });125126  [127    {mode: 'nft' as const, nesting: {tokenOwner: true,  collectionAdmin: false}},128    {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},129  ].map(testCase => {130    itSub(`${testCase.nesting.tokenOwner ? 'Admin' : 'Token owner'} cannot nest when only ${testCase.nesting.tokenOwner ? 'tokenOwner' : 'collectionAdmin'} is allowed`, async ({helper}) => {131      // Create collection with tokenOwner or create collection with collectionAdmin permission:132      const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});133      const targetTokenCharlie = await targetCollection.mintToken(alice, {Substrate: charlie.address});134      await targetCollection.addAdmin(alice, {Substrate: bob.address});135136      const nestedCollectionCharlie = await helper[testCase.mode].mintCollection(charlie);137      const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);138      // if nesting permissions restricted for token owner – minter is bob (admin),139      // if collectionAdmin – charlie (owner)140      testCase.nesting.tokenOwner141        ? await expect(nestedCollectionBob.mintToken(bob, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)142        : await expect(nestedCollectionCharlie.mintToken(charlie, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);143    });144  });145146  itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {147    const collection = await helper.nft.mintCollection(alice);148    // To avoid UserIsNotAllowedToNest error149    await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});150151    // The list of non-existing tokens:152    const tokenFromNonExistingCollection = helper.nft.getTokenObject(9999999, 1);153    const tokenBurnt = await collection.mintToken(alice);154    await tokenBurnt.burn(alice);155    const tokenNotMintedYet = helper.nft.getTokenObject(collection.collectionId, 2);156157    // The list of collections to nest tokens from:158    const nftCollectionForNesting = await helper.nft.mintCollection(alice);159    const rftCollectionForNesting = await helper.rft.mintCollection(alice);160    const ftCollectionForNesting = await helper.ft.mintCollection(alice);161    const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);162163    const testCases = [164      {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},165      {token: tokenBurnt, error: 'TokenNotFound'},166      {token: tokenNotMintedYet, error: 'TokenNotFound'},167    ];168169    for(const testCase of testCases) {170      // 1. Alice cannot create nested token to non-existing token171      await expect(nftCollectionForNesting.mintToken(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);172      await expect(rftCollectionForNesting.mintToken(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);173      await expect(ftCollectionForNesting.mint(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);174175      // 2. Alice cannot mint and nest token:176      const nft = await nftCollectionForNesting.mintToken(alice);177      const rft = await rftCollectionForNesting.mintToken(alice, 100n);178      const _ft = await ftCollectionForNesting.mint(alice, 100n);179      await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);180      await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);181      await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);182      await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);183    }184  });185186  itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {187    const existingCollection = await helper.nft.mintCollection(alice);188    const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);189    const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);190191    const nftCollectionForNesting = await helper.nft.mintCollection(alice);192193    // 1. Alice cannot create nested token to collection address194    await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');195    await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');196197    // 2. Alice cannot mint and nest token to collection address:198    const nft = await nftCollectionForNesting.mintToken(alice);199    await expect(nft.transfer(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');200    await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');201  });202203  itEth.ifWithPallets('Cannot nest in RFT or FT', [Pallets.ReFungible], async ({helper}) => {204    // Create default collection, permissions are not set:205    const rftCollection = await helper.rft.mintCollection(alice);206    const ftCollection = await helper.ft.mintCollection(alice);207    const nativeFtCollection = helper.ft.getCollectionObject(0);208209    const rftToken = await rftCollection.mintToken(alice);210    const _ftToken = await ftCollection.mint(alice, 100n);211212    const collectionForNesting = await helper.nft.mintCollection(alice);213214    // 1. Alice cannot create immediately nested tokens:215    await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');216    await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');217    await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');218219    // 2. Alice cannot mint and nest token:220    const nestedToken2 = await collectionForNesting.mintToken(alice);221    await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');222    await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');223    await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');224  });225226  itSub('Cannot nest in restricted collection if collection is not in the list', async ({helper}) => {227    const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);228    const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);229    const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);230    const notAllowedCollectionFT = await helper.ft.mintCollection(alice);231    const notAllowedCollectionNativeFT = helper.ft.getCollectionObject(0);232233    // Collection restricted to allowedCollectionId234    const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:235      {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},236    });237    // Create collection with restricted nesting -- even self is not allowed238    const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:239      {nesting: {tokenOwner: true, restricted: []}},240    });241242    const targetTokenA = await restrictedCollectionA.mintToken(alice);243    const targetTokenB = await restrictedCollectionB.mintToken(alice);244245    // 1. Cannot mint in own collection after allowlisting the accounts:246    await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);247    await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);248249    // 2. Cannot mint from notAllowedCollection:250    await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);251    await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);252    await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);253    await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);254    await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);255    await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);256    await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);257    await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);258  });259260  itSub('Cannot create nesting chains greater than 5', async ({helper}) => {261    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});262    let token = await collection.mintToken(alice);263264    const maxNestingLevel = 5;265266    // Create a nested-token matryoshka267    for (let i = 0; i < maxNestingLevel; i++) {268      token = await collection.mintToken(alice, token.nestingAccount());269    }270271    // The nesting depth is limited by `maxNestingLevel`272    // 1. Cannot mint:273    await expect(collection.mintToken(alice, token.nestingAccount()))274      .to.be.rejectedWith(/structure\.DepthLimit/);275    // 2. Cannot transfer:276    const anotherToken = await collection.mintToken(alice);277    await expect(anotherToken.transfer(alice, token.nestingAccount()))278      .to.be.rejectedWith(/structure\.DepthLimit/);279    // 3. Cannot nest FT pieces:280    const ftCollection = await helper.ft.mintCollection(alice);281    await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))282      .to.be.rejectedWith(/structure\.DepthLimit/);283284    expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});285    expect(await token.getChildren()).to.has.length(0);286  });287});
modifiedtests/src/sub/nesting/refungible.test.tsdiffbeforeafterboth
--- a/tests/src/sub/nesting/refungible.test.ts
+++ b/tests/src/sub/nesting/refungible.test.ts
@@ -17,44 +17,45 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';
 
-// ReFungible specific nesting tests
-let alice: IKeyringPair;
+describe('ReFungible-specific nesting tests', () => {
+  let alice: IKeyringPair;
 
-before(async () => {
-  await usingPlaygrounds(async (helper, privateKey) => {
-    const donor = await privateKey({url: import.meta.url});
-    [alice] = await helper.arrange.createAccounts([200n], donor);
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([200n], donor);
+    });
   });
-});
 
-itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {
-  const collectionNFT = await helper.nft.mintCollection(alice, {
-    permissions: {
-      nesting: {
-        tokenOwner: true,
+  itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {
+    const collectionNFT = await helper.nft.mintCollection(alice, {
+      permissions: {
+        nesting: {
+          tokenOwner: true,
+        },
       },
-    },
-  });
-  const collectionRFT = await helper.rft.mintCollection(alice);
+    });
+    const collectionRFT = await helper.rft.mintCollection(alice);
 
-  const nft = await collectionNFT.mintToken(alice, {Substrate: alice.address});
-  const rft = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
+    const nft = await collectionNFT.mintToken(alice, {Substrate: alice.address});
+    const rft = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
 
-  expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+    expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
 
-  await rft.transfer(alice, nft.nestingAccount(), 40n);
+    await rft.transfer(alice, nft.nestingAccount(), 40n);
 
-  expect(await rft.getTopmostOwner()).deep.equal(null);
+    expect(await rft.getTopmostOwner()).deep.equal(null);
 
-  await rft.transfer(alice, nft.nestingAccount(), 60n);
+    await rft.transfer(alice, nft.nestingAccount(), 60n);
 
-  expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+    expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
 
-  await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 30n);
+    await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 30n);
 
-  expect(await rft.getTopmostOwner()).deep.equal(null);
+    expect(await rft.getTopmostOwner()).deep.equal(null);
 
-  await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 70n);
+    await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 70n);
 
-  expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+    expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+  });
 });