git.delta.rocks / unique-network / refs/commits / 3d7ffe75f2a8

difftreelog

fix skip refungible and scheduler tests on qtz/unq

Daniel Shiposha2022-08-09parent: #5eadf5f.patch.diff
in: master

43 files changed

modifiedtests/src/approve.test.tsdiffbeforeafterboth
--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -32,6 +32,8 @@
   getCreatedCollectionCount,
   transferFromExpectSuccess,
   transferFromExpectFail,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -49,34 +51,44 @@
     });
   });
 
-  it('Execute the extrinsic and check approvedList', async () => {
+  it('[nft] Execute the extrinsic and check approvedList', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
-    // nft
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
-    // fungible
+  });
+
+  it('[fungible] Execute the extrinsic and check approvedList', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
-    // reFungible
+  });
+
+  it('[refungible] Execute the extrinsic and check approvedList', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
   });
 
-  it('Remove approval by using 0 amount', async () => {
+  it('[nft] Remove approval by using 0 amount', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
-    // nft
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 1);
     await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 0);
-    // fungible
+  });
+
+  it('[fungible] Remove approval by using 0 amount', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 1);
     await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 0);
-    // reFungible
+  });
+
+  it('[refungible] Remove approval by using 0 amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -117,7 +129,9 @@
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -151,7 +165,9 @@
     await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible');
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -188,7 +204,9 @@
     await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1);
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -250,7 +268,9 @@
     await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, bob, charlie, 1);
   });
 
-  it('ReFungible', async () => {
+  it('ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -285,7 +305,9 @@
     await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, charlie, 11);
   });
 
-  it('ReFungible', async () => {
+  it('ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, charlie, 101);
@@ -325,7 +347,9 @@
     await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'Fungible');
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address);
@@ -422,63 +446,87 @@
     });
   });
 
-  it('Approve for a collection that does not exist', async () => {
+  it('[nft] Approve for a collection that does not exist', async () => {
     await usingApi(async (api: ApiPromise) => {
-      // nft
       const nftCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
-      // fungible
+    });
+  });
+
+  it('[fungible] Approve for a collection that does not exist', async () => {
+    await usingApi(async (api: ApiPromise) => {
       const fungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob);
-      // reFungible
+    });
+  });
+
+  it('[refungible] Approve for a collection that does not exist', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api: ApiPromise) => {
       const reFungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob);
     });
   });
 
-  it('Approve for a collection that was destroyed', async () => {
-    // nft
+  it('[nft] Approve for a collection that was destroyed', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     await destroyCollectionExpectSuccess(nftCollectionId);
     await approveExpectFail(nftCollectionId, 1, alice, bob);
-    // fungible
+  });
+
+  it('Approve for a collection that was destroyed', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await destroyCollectionExpectSuccess(fungibleCollectionId);
     await approveExpectFail(fungibleCollectionId, 0, alice, bob);
-    // reFungible
+  });
+
+  it('[refungible] Approve for a collection that was destroyed', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await destroyCollectionExpectSuccess(reFungibleCollectionId);
     await approveExpectFail(reFungibleCollectionId, 1, alice, bob);
   });
 
-  it('Approve transfer of a token that does not exist', async () => {
-    // nft
+  it('[nft] Approve transfer of a token that does not exist', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     await approveExpectFail(nftCollectionId, 2, alice, bob);
-    // reFungible
+  });
+
+  it('[refungible] Approve transfer of a token that does not exist', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await approveExpectFail(reFungibleCollectionId, 2, alice, bob);
   });
 
-  it('Approve using the address that does not own the approved token', async () => {
+  it('[nft] Approve using the address that does not own the approved token', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
-    // nft
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice);
-    // fungible
+  });
+
+  it('[fungible] Approve using the address that does not own the approved token', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice);
-    // reFungible
+  });
+
+  it('[refungible] Approve using the address that does not own the approved token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, alice);
   });
 
-  it('should fail if approved more ReFungibles than owned', async () => {
+  it('should fail if approved more ReFungibles than owned', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'ReFungible');
     await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 100, 'ReFungible');
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -25,6 +25,8 @@
   getBalance,
   setCollectionLimitsExpectSuccess,
   isTokenExists,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 
 import chai from 'chai';
@@ -80,7 +82,9 @@
     });
   });
 
-  it('Burn item in ReFungible collection', async () => {
+  it('Burn item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
@@ -99,7 +103,9 @@
     });
   });
 
-  it('Burn owned portion of item in ReFungible collection', async () => {
+  it('Burn owned portion of item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
@@ -189,7 +195,9 @@
   });
 
   // TODO: burnFrom
-  it('Burn item in ReFungible collection', async () => {
+  it('Burn item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -33,6 +33,8 @@
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
   UNIQUE,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -124,7 +126,9 @@
     });
   });
 
-  it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {
+  it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
@@ -252,7 +256,9 @@
     });
   });
 
-  it('ReFungible: Sponsoring is rate limited', async () => {
+  it('ReFungible: Sponsoring is rate limited', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -16,7 +16,7 @@
 
 import {expect} from 'chai';
 import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api';
-import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess} from './util/helpers';
+import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess, requirePallets, Pallets} from './util/helpers';
 
 describe('integration test: ext. createCollection():', () => {
   it('Create new NFT collection', async () => {
@@ -34,7 +34,9 @@
   it('Create new Fungible collection', async () => {
     await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
   });
-  it('Create new ReFungible collection', async () => {
+  it('Create new ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
   });
 
modifiedtests/src/createItem.test.tsdiffbeforeafterboth
--- a/tests/src/createItem.test.ts
+++ b/tests/src/createItem.test.ts
@@ -29,6 +29,8 @@
   itApi,
   normalizeAccountId,
   getCreateItemResult,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 
 const expect = chai.expect;
@@ -79,7 +81,9 @@
     }
 
   });
-  it('Create new item in ReFungible collection', async () => {
+  it('Create new item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await createItemExpectSuccess(alice, newCollectionID, createMode);
@@ -96,7 +100,9 @@
     await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
     await createItemExpectSuccess(bob, newCollectionID, createMode);
   });
-  it('Create new item in ReFungible collection with collection admin permissions', async () => {
+  it('Create new item in ReFungible collection with collection admin permissions', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
@@ -175,7 +181,9 @@
     });
   });
 
-  it('Check total pieces of ReFungible token', async () => {
+  it('Check total pieces of ReFungible token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const createMode = 'ReFungible';
       const createCollectionResult = await createCollection(api, alice, {mode: {type: createMode}});
@@ -219,7 +227,9 @@
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
     await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
   });
-  it('Regular user cannot create new item in ReFungible collection', async () => {
+  it('Regular user cannot create new item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
@@ -296,7 +306,9 @@
     });
   });
 
-  it('Check total pieces for invalid Refungible token', async () => {
+  it('Check total pieces for invalid Refungible token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
       const collectionId  = createCollectionResult.collectionId;
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -33,6 +33,9 @@
   createCollectionWithPropsExpectSuccess,
   createMultipleItemsWithPropsExpectSuccess,
   getTokenProperties,
+  requirePallets,
+  Pallets,
+  checkPalletsPresence
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -91,7 +94,9 @@
     });
   });
 
-  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -272,7 +277,9 @@
     });
   });
 
-  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -335,7 +342,9 @@
     });
   });
 
-  it('Regular user cannot create items in active ReFungible collection', async () => {
+  it('Regular user cannot create items in active ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -358,9 +367,8 @@
     });
   });
 
-  it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {
+  it('Create NFTs that has reached the maximum data limit', async function() {
     await usingApi(async (api, privateKeyWrapper) => {
-      // NFT
       const collectionId = await createCollectionWithPropsExpectSuccess({
         propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}],
       });
@@ -372,8 +380,13 @@
       ];
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
+    });
+  });
 
-      // ReFungible
+  it('Create Refungible tokens that has reached the maximum data limit', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async api => {
       const collectionIdReFungible =
         await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       {
@@ -402,8 +415,15 @@
   it('Create tokens with different types', async () => {
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess();
+
+      let types = ['NFT', 'Fungible'];
+
+      if (await checkPalletsPresence([Pallets.ReFungible])) {
+        types.push('ReFungible');
+      }
+
       const createMultipleItemsTx = api.tx.unique
-        .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'Fungible', 'ReFungible']);
+        .createMultipleItems(collectionId, normalizeAccountId(alice.address), types);
       await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/);
       // garbage collection :-D // lol
       await destroyCollectionExpectSuccess(collectionId);
modifiedtests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItemsEx.test.ts
+++ b/tests/src/createMultipleItemsEx.test.ts
@@ -16,7 +16,7 @@
 
 import {expect} from 'chai';
 import usingApi, {executeTransaction} from './substrate/substrate-api';
-import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties} from './util/helpers';
+import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties, requirePallets, Pallets} from './util/helpers';
 
 describe.only('Integration Test: createMultipleItemsEx', () => {
   it('can initialize multiple NFT with different owners', async () => {
@@ -146,7 +146,9 @@
     });
   });
 
-  it('can initialize an RFT with multiple owners', async () => {
+  it('can initialize an RFT with multiple owners', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       const alice = privateKeyWrapper('//Alice');
       const bob = privateKeyWrapper('//Bob');
@@ -178,7 +180,9 @@
     });
   });
 
-  it('can initialize multiple RFTs with the same owner', async () => {
+  it('can initialize multiple RFTs with the same owner', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       const alice = privateKeyWrapper('//Alice');
       const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
@@ -389,7 +393,9 @@
     });
   });
 
-  it('fails when trying to set multiple owners when creating multiple refungibles', async () => {
+  it('fails when trying to set multiple owners when creating multiple refungibles', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
 
     await usingApi(async (api, privateKeyWrapper) => {
modifiedtests/src/destroyCollection.test.tsdiffbeforeafterboth
--- a/tests/src/destroyCollection.test.ts
+++ b/tests/src/destroyCollection.test.ts
@@ -25,6 +25,8 @@
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
   createItemExpectSuccess,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -38,7 +40,9 @@
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await destroyCollectionExpectSuccess(collectionId);
   });
-  it('ReFungible collection can be destroyed', async () => {
+  it('ReFungible collection can be destroyed', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await destroyCollectionExpectSuccess(collectionId);
   });
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -16,7 +16,7 @@
 
 import {evmToAddress} from '@polkadot/util-crypto';
 import {expect} from 'chai';
-import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
+import {getCreatedCollectionCount, getDetailedCollectionInfo, requirePallets, Pallets} from '../util/helpers';
 import {
   evmCollectionHelpers,
   collectionIdToAddress,
@@ -28,6 +28,10 @@
 } from './util/helpers';
 
 describe('Create RFT collection from EVM', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Create collection', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
@@ -146,6 +150,10 @@
 });
 
 describe('(!negative tests!) Create RFT collection from EVM', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
@@ -228,4 +236,4 @@
       .setCollectionLimit('badLimit', 'true')
       .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');
   });
-});
\ No newline at end of file
+});
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -14,12 +14,16 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {createCollectionExpectSuccess, UNIQUE} from '../util/helpers';
+import {createCollectionExpectSuccess, UNIQUE, requirePallets, Pallets} from '../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, tokenIdToAddress} from './util/helpers';
 import reFungibleTokenAbi from './reFungibleTokenAbi.json';
 import {expect} from 'chai';
 
 describe('Refungible: Information getting', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
     const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, caller);
@@ -120,6 +124,10 @@
 });
 
 describe('Refungible: Plain calls', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
@@ -399,6 +407,10 @@
 });
 
 describe('RFT: Fees', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
     const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, caller);
@@ -435,6 +447,10 @@
 });
 
 describe('Common metadata', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
     const collection = await createCollectionExpectSuccess({
       name: 'token name',
@@ -462,4 +478,4 @@
 
     expect(symbol).to.equal('TOK');
   });
-});
\ No newline at end of file
+});
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';
+import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';
 import reFungibleTokenAbi from './reFungibleTokenAbi.json';
 
@@ -24,6 +24,10 @@
 const expect = chai.expect;
 
 describe('Refungible token: Information getting', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
@@ -75,6 +79,10 @@
 
 // FIXME: Need erc721 for ReFubgible.
 describe('Check ERC721 token URI for ReFungible', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
@@ -216,6 +224,10 @@
 });
 
 describe('Refungible: Plain calls', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
@@ -477,6 +489,10 @@
 });
 
 describe('Refungible: Fees', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
@@ -532,6 +548,10 @@
 });
 
 describe('Refungible: Substrate calls', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
modifiedtests/src/eth/scheduling.test.tsdiffbeforeafterboth
--- a/tests/src/eth/scheduling.test.ts
+++ b/tests/src/eth/scheduling.test.ts
@@ -16,9 +16,13 @@
 
 import {expect} from 'chai';
 import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';
-import {scheduleExpectSuccess, waitNewBlocks} from '../util/helpers';
+import {scheduleExpectSuccess, waitNewBlocks, requirePallets, Pallets} from '../util/helpers';
 
 describe('Scheduing EVM smart contracts', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.Scheduler]);
+  });
+
   itWeb3('Successfully schedules and periodically executes an EVM contract', async ({api, web3, privateKeyWrapper}) => {
     const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const flipper = await deployFlipper(web3, deployer);
@@ -51,4 +55,4 @@
       expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
     }
   });
-});
\ No newline at end of file
+});
modifiedtests/src/limits.test.tsdiffbeforeafterboth
--- a/tests/src/limits.test.ts
+++ b/tests/src/limits.test.ts
@@ -27,6 +27,8 @@
   transferExpectSuccess,
   getFreeBalance,
   waitNewBlocks, burnItemExpectSuccess,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 import {expect} from 'chai';
 
@@ -67,7 +69,9 @@
 describe('Number of tokens per address (ReFungible)', () => {
   let alice: IKeyringPair;
 
-  before(async () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
     });
@@ -367,7 +371,9 @@
   let bob: IKeyringPair;
   let charlie: IKeyringPair;
 
-  before(async () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
       bob = privateKeyWrapper('//Bob');
modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -17,6 +17,8 @@
   transferExpectSuccess,
   transferFromExpectSuccess,
   setCollectionLimitsExpectSuccess,
+  requirePallets,
+  Pallets
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -311,7 +313,9 @@
 
   // ---------- Re-Fungible ----------
 
-  it('ReFungible: allows an Owner to nest/unnest their token', async () => {
+  it('ReFungible: allows an Owner to nest/unnest their token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});
@@ -333,7 +337,9 @@
     });
   });
 
-  it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {
+  it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});
@@ -715,7 +721,9 @@
 
   // ---------- Re-Fungible ----------
 
-  it('ReFungible: disallows to nest token if nesting is disabled', async () => {
+  it('ReFungible: disallows to nest token if nesting is disabled', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});
@@ -745,7 +753,9 @@
     });
   });
 
-  it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {
+  it('ReFungible: disallows a non-Owner to nest someone else\'s token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});
@@ -773,7 +783,9 @@
     });
   });
 
-  it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {
+  it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);
@@ -800,7 +812,9 @@
     });
   });
 
-  it('ReFungible: disallows to nest token to an unlisted collection', async () => {
+  it('ReFungible: disallows to nest token to an unlisted collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
before · tests/src/nesting/properties.test.ts
1import {expect} from 'chai';2import usingApi, {executeTransaction} from '../substrate/substrate-api';3import {4  addCollectionAdminExpectSuccess,5  CollectionMode,6  createCollectionExpectSuccess,7  setCollectionPermissionsExpectSuccess,8  createItemExpectSuccess,9  getCreateCollectionResult,10  transferExpectSuccess,11} from '../util/helpers';12import {IKeyringPair} from '@polkadot/types/types';13import {tokenIdToAddress} from '../eth/util/helpers';1415let alice: IKeyringPair;16let bob: IKeyringPair;17let charlie: IKeyringPair;1819describe('Composite Properties Test', () => {20  before(async () => {21    await usingApi(async (api, privateKeyWrapper) => {22      alice = privateKeyWrapper('//Alice');23      bob = privateKeyWrapper('//Bob');24    });25  });2627  async function testMakeSureSuppliesRequired(mode: CollectionMode) {28    await usingApi(async api => {29      const collectionId = await createCollectionExpectSuccess({mode: mode});3031      const collectionOption = await api.rpc.unique.collectionById(collectionId);32      expect(collectionOption.isSome).to.be.true;33      let collection = collectionOption.unwrap();34      expect(collection.tokenPropertyPermissions.toHuman()).to.be.empty;35      expect(collection.properties.toHuman()).to.be.empty;3637      const propertyPermissions = [38        {key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},39        {key: 'skullduggery', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}},40      ];41      await expect(executeTransaction(42        api, 43        alice, 44        api.tx.unique.setTokenPropertyPermissions(collectionId, propertyPermissions), 45      )).to.not.be.rejected;4647      const collectionProperties = [48        {key: 'black_hole', value: 'LIGO'},49        {key: 'electron', value: 'come bond'}, 50      ];51      await expect(executeTransaction(52        api, 53        alice, 54        api.tx.unique.setCollectionProperties(collectionId, collectionProperties), 55      )).to.not.be.rejected;5657      collection = (await api.rpc.unique.collectionById(collectionId)).unwrap();58      expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);59      expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);60    });61  }6263  it('Makes sure collectionById supplies required fields for NFT', async () => {64    await testMakeSureSuppliesRequired({type: 'NFT'});65  });6667  it('Makes sure collectionById supplies required fields for ReFungible', async () => {68    await testMakeSureSuppliesRequired({type: 'ReFungible'});69  });70});7172// ---------- COLLECTION PROPERTIES7374describe('Integration Test: Collection Properties', () => {75  before(async () => {76    await usingApi(async (api, privateKeyWrapper) => {77      alice = privateKeyWrapper('//Alice');78      bob = privateKeyWrapper('//Bob');79    });80  });8182  it('Reads properties from a collection', async () => {83    await usingApi(async api => {84      const collection = await createCollectionExpectSuccess();85      const properties = (await api.query.common.collectionProperties(collection)).toJSON();86      expect(properties.map).to.be.empty;87      expect(properties.consumedSpace).to.equal(0);88    });89  });909192  async function testSetsPropertiesForCollection(mode: string) {93    await usingApi(async api => {94      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));95      const {collectionId} = getCreateCollectionResult(events);9697      // As owner98      await expect(executeTransaction(99        api, 100        bob, 101        api.tx.unique.setCollectionProperties(collectionId, [{key: 'electron', value: 'come bond'}]), 102      )).to.not.be.rejected;103104      await addCollectionAdminExpectSuccess(bob, collectionId, alice.address);105106      // As administrator107      await expect(executeTransaction(108        api, 109        alice, 110        api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 111      )).to.not.be.rejected;112113      const properties = (await api.rpc.unique.collectionProperties(collectionId, ['electron', 'black_hole'])).toHuman();114      expect(properties).to.be.deep.equal([115        {key: 'electron', value: 'come bond'},116        {key: 'black_hole', value: ''},117      ]);118    });119  }120  it('Sets properties for a NFT collection', async () => {121    await testSetsPropertiesForCollection('NFT');122  });123  it('Sets properties for a ReFungible collection', async () => {124    await testSetsPropertiesForCollection('ReFungible');125  });126127  async function testCheckValidNames(mode: string) {128    await usingApi(async api => {129      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));130      const {collectionId} = getCreateCollectionResult(events);131  132      // alpha symbols133      await expect(executeTransaction(134        api, 135        bob, 136        api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 137      )).to.not.be.rejected;138  139      // numeric symbols140      await expect(executeTransaction(141        api, 142        bob, 143        api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 144      )).to.not.be.rejected;145  146      // underscore symbol147      await expect(executeTransaction(148        api, 149        bob, 150        api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 151      )).to.not.be.rejected;152  153      // dash symbol154      await expect(executeTransaction(155        api, 156        bob, 157        api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 158      )).to.not.be.rejected;159  160      // underscore symbol161      await expect(executeTransaction(162        api, 163        bob, 164        api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 165      )).to.not.be.rejected;166  167      const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];168      const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();169      expect(properties).to.be.deep.equal([170        {key: 'alpha', value: ''},171        {key: '123', value: ''},172        {key: 'black_hole', value: ''},173        {key: 'semi-automatic', value: ''},174        {key: 'build.rs', value: ''},175      ]);176    });177  }178  it('Check valid names for NFT collection properties keys', async () => {179    await testCheckValidNames('NFT');180  });181  it('Check valid names for ReFungible collection properties keys', async () => {182    await testCheckValidNames('ReFungible');183  });184185  async function testChangesProperties(mode: CollectionMode) {186    await usingApi(async api => {187      const collection = await createCollectionExpectSuccess({mode: mode});188  189      await expect(executeTransaction(190        api, 191        alice, 192        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 193      )).to.not.be.rejected;194  195      // Mutate the properties196      await expect(executeTransaction(197        api, 198        alice, 199        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 200      )).to.not.be.rejected;201  202      const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();203      expect(properties).to.be.deep.equal([204        {key: 'electron', value: 'bonded'},205        {key: 'black_hole', value: 'LIGO'},206      ]);207    });208  }209  it('Changes properties of a NFT collection', async () => {210    await testChangesProperties({type: 'NFT'});211  });212  it('Changes properties of a ReFungible collection', async () => {213    await testChangesProperties({type: 'ReFungible'});214  });215216  async function testDeleteProperties(mode: CollectionMode) {217    await usingApi(async api => {218      const collection = await createCollectionExpectSuccess({mode: mode});219  220      await expect(executeTransaction(221        api, 222        alice, 223        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 224      )).to.not.be.rejected;225  226      await expect(executeTransaction(227        api, 228        alice, 229        api.tx.unique.deleteCollectionProperties(collection, ['electron']), 230      )).to.not.be.rejected;231  232      const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();233      expect(properties).to.be.deep.equal([234        {key: 'black_hole', value: 'LIGO'},235      ]);236    });  237  }238  it('Deletes properties of a NFT collection', async () => {239    await testDeleteProperties({type: 'NFT'});240  });241  it('Deletes properties of a ReFungible collection', async () => {242    await testDeleteProperties({type: 'ReFungible'});243  });244});245246describe('Negative Integration Test: Collection Properties', () => {247  before(async () => {248    await usingApi(async (api, privateKeyWrapper) => {249      alice = privateKeyWrapper('//Alice');250      bob = privateKeyWrapper('//Bob');251    });252  });253  254  async function testFailsSetPropertiesIfNotOwnerOrAdmin(mode: CollectionMode) {255    await usingApi(async api => {256      const collection = await createCollectionExpectSuccess({mode: mode});257  258      await expect(executeTransaction(259        api, 260        bob, 261        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 262      )).to.be.rejectedWith(/common\.NoPermission/);263  264      const properties = (await api.query.common.collectionProperties(collection)).toJSON();265      expect(properties.map).to.be.empty;266      expect(properties.consumedSpace).to.equal(0);267    });  268  }269  it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {270    await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});271  });272  it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {273    await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});274  });275  276  async function testFailsSetPropertiesThatExeedLimits(mode: CollectionMode) {277    await usingApi(async api => {278      const collection = await createCollectionExpectSuccess({mode: mode});279      const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 280  281      // Mute the general tx parsing error, too many bytes to process282      {283        console.error = () => {};284        await expect(executeTransaction(285          api, 286          alice, 287          api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 288        )).to.be.rejected;289      }290  291      let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();292      expect(properties).to.be.empty;293  294      await expect(executeTransaction(295        api, 296        alice, 297        api.tx.unique.setCollectionProperties(collection, [298          {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, 299          {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 300        ]), 301      )).to.be.rejectedWith(/common\.NoSpaceForProperty/);302  303      properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();304      expect(properties).to.be.empty;305    });  306  }307  it('Fails to set properties that exceed the limits (NFT)', async () => {308    await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});309  });310  it('Fails to set properties that exceed the limits (ReFungible)', async () => {311    await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});312  });313  314  async function testFailsSetMorePropertiesThanAllowed(mode: CollectionMode) {315    await usingApi(async api => {316      const collection = await createCollectionExpectSuccess({mode: mode});317  318      const propertiesToBeSet = [];319      for (let i = 0; i < 65; i++) {320        propertiesToBeSet.push({321          key: 'electron_' + i,322          value: Math.random() > 0.5 ? 'high' : 'low',323        });324      }325  326      await expect(executeTransaction(327        api, 328        alice, 329        api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 330      )).to.be.rejectedWith(/common\.PropertyLimitReached/);331  332      const properties = (await api.query.common.collectionProperties(collection)).toJSON();333      expect(properties.map).to.be.empty;334      expect(properties.consumedSpace).to.equal(0);335    });  336  }337  it('Fails to set more properties than it is allowed (NFT)', async () => {338    await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});339  });340  it('Fails to set more properties than it is allowed (ReFungible)', async () => {341    await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});342  });343  344  async function testFailsSetPropertiesWithInvalidNames(mode: CollectionMode) {345    await usingApi(async api => {346      const collection = await createCollectionExpectSuccess({mode: mode});347  348      const invalidProperties = [349        [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],350        [{key: 'Mr/Sandman', value: 'Bring me a gene'}],351        [{key: 'déjà vu', value: 'hmm...'}],352      ];353  354      for (let i = 0; i < invalidProperties.length; i++) {355        await expect(executeTransaction(356          api, 357          alice, 358          api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 359        ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);360      }361  362      await expect(executeTransaction(363        api, 364        alice, 365        api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 366      ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);367  368      await expect(executeTransaction(369        api, 370        alice, 371        api.tx.unique.setCollectionProperties(collection, [372          {key: 'CRISPR-Cas9', value: 'rewriting nature!'},373        ]), 374      ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;375  376      const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');377  378      const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();379      expect(properties).to.be.deep.equal([380        {key: 'CRISPR-Cas9', value: 'rewriting nature!'},381      ]);382  383      for (let i = 0; i < invalidProperties.length; i++) {384        await expect(executeTransaction(385          api, 386          alice, 387          api.tx.unique.deleteCollectionProperties(collection, invalidProperties[i].map(propertySet => propertySet.key)), 388        ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);389      }390    });391  }392  it('Fails to set properties with invalid names (NFT)', async () => {393    await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});394  });395  it('Fails to set properties with invalid names (ReFungible)', async () => {396    await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});397  });398});399400// ---------- ACCESS RIGHTS401402describe('Integration Test: Access Rights to Token Properties', () => {403  before(async () => {404    await usingApi(async (api, privateKeyWrapper) => {405      alice = privateKeyWrapper('//Alice');406      bob = privateKeyWrapper('//Bob');407    });408  });409  410  it('Reads access rights to properties of a collection', async () => {411    await usingApi(async api => {412      const collection = await createCollectionExpectSuccess();413      const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();414      expect(propertyRights).to.be.empty;415    });416  });417  418  async function testSetsAccessRightsToProperties(mode: CollectionMode) {419    await usingApi(async api => {420      const collection = await createCollectionExpectSuccess({mode: mode});421  422      await expect(executeTransaction(423        api, 424        alice, 425        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 426      )).to.not.be.rejected;427  428      await addCollectionAdminExpectSuccess(alice, collection, bob.address);429  430      await expect(executeTransaction(431        api, 432        alice, 433        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 434      )).to.not.be.rejected;435  436      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();437      expect(propertyRights).to.be.deep.equal([438        {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},439        {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},440      ]);441    });  442  }443  it('Sets access rights to properties of a collection (NFT)', async () => {444    await testSetsAccessRightsToProperties({type: 'NFT'});445  });446  it('Sets access rights to properties of a collection (ReFungible)', async () => {447    await testSetsAccessRightsToProperties({type: 'ReFungible'});448  });449  450  async function testChangesAccessRightsToProperty(mode: CollectionMode) {451    await usingApi(async api => {452      const collection = await createCollectionExpectSuccess({mode: mode});453  454      await expect(executeTransaction(455        api, 456        alice, 457        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 458      )).to.not.be.rejected;459  460      await expect(executeTransaction(461        api, 462        alice, 463        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 464      )).to.not.be.rejected;465  466      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();467      expect(propertyRights).to.be.deep.equal([468        {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},469      ]);470    });471  }472  it('Changes access rights to properties of a NFT collection', async () => {473    await testChangesAccessRightsToProperty({type: 'NFT'});474  });475  it('Changes access rights to properties of a ReFungible collection', async () => {476    await testChangesAccessRightsToProperty({type: 'ReFungible'});477  });478});479480describe('Negative Integration Test: Access Rights to Token Properties', () => {481  before(async () => {482    await usingApi(async (api, privateKeyWrapper) => {483      alice = privateKeyWrapper('//Alice');484      bob = privateKeyWrapper('//Bob');485    });486  });487488  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(mode: CollectionMode) {489    await usingApi(async api => {490      const collection = await createCollectionExpectSuccess({mode: mode});491  492      await expect(executeTransaction(493        api, 494        bob, 495        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 496      )).to.be.rejectedWith(/common\.NoPermission/);497  498      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();499      expect(propertyRights).to.be.empty;500    });501  }502  it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {503    await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});504  });505  it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {506    await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});507  });508509  async function testPreventFromAddingTooManyPossibleProperties(mode: CollectionMode) {510    await usingApi(async api => {511      const collection = await createCollectionExpectSuccess({mode: mode});512  513      const constitution = [];514      for (let i = 0; i < 65; i++) {515        constitution.push({516          key: 'property_' + i,517          permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},518        });519      }520  521      await expect(executeTransaction(522        api, 523        alice, 524        api.tx.unique.setTokenPropertyPermissions(collection, constitution), 525      )).to.be.rejectedWith(/common\.PropertyLimitReached/);526  527      const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();528      expect(propertyRights).to.be.empty;529    });  530  }531  it('Prevents from adding too many possible properties (NFT)', async () => {532    await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});533  });534  it('Prevents from adding too many possible properties (ReFungible)', async () => {535    await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});536  });537538  async function testPreventAccessRightsModifiedIfConstant(mode: CollectionMode) {539    await usingApi(async api => {540      const collection = await createCollectionExpectSuccess({mode: mode});541  542      await expect(executeTransaction(543        api, 544        alice, 545        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 546      )).to.not.be.rejected;547  548      await expect(executeTransaction(549        api, 550        alice, 551        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 552      )).to.be.rejectedWith(/common\.NoPermission/);553  554      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();555      expect(propertyRights).to.deep.equal([556        {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},557      ]);558    });  559  }560  it('Prevents access rights to be modified if constant (NFT)', async () => {561    await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});562  });563  it('Prevents access rights to be modified if constant (ReFungible)', async () => {564    await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});565  });566567  async function testPreventsAddingPropertiesWithInvalidNames(mode: CollectionMode) {568    await usingApi(async api => {569      const collection = await createCollectionExpectSuccess({mode: mode});570  571      const invalidProperties = [572        [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],573        [{key: 'G#4', permission: {tokenOwner: true}}],574        [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],575      ];576  577      for (let i = 0; i < invalidProperties.length; i++) {578        await expect(executeTransaction(579          api, 580          alice, 581          api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 582        ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);583      }584  585      await expect(executeTransaction(586        api, 587        alice, 588        api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 589      ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);590  591      const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string592      await expect(executeTransaction(593        api, 594        alice, 595        api.tx.unique.setTokenPropertyPermissions(collection, [596          {key: correctKey, permission: {collectionAdmin: true}},597        ]), 598      ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;599  600      const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');601  602      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();603      expect(propertyRights).to.be.deep.equal([604        {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},605      ]);606    });607  }608  it('Prevents adding properties with invalid names (NFT)', async () => {609    await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});610  });611  it('Prevents adding properties with invalid names (ReFungible)', async () => {612    await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});613  });614});615616// ---------- TOKEN PROPERTIES617618describe('Integration Test: Token Properties', () => {619  let permissions: {permission: any, signers: IKeyringPair[]}[];620621  before(async () => {622    await usingApi(async (api, privateKeyWrapper) => {623      alice = privateKeyWrapper('//Alice'); // collection owner624      bob = privateKeyWrapper('//Bob'); // collection admin625      charlie = privateKeyWrapper('//Charlie'); // token owner626627      permissions = [628        {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},629        {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},630        {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},631        {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},632        {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},633        {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},634      ];635    });636  });637  638  async function testReadsYetEmptyProperties(mode: CollectionMode) {639    await usingApi(async api => {640      const collection = await createCollectionExpectSuccess({mode: mode});641      const token = await createItemExpectSuccess(alice, collection, mode.type);642  643      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();644      expect(properties.map).to.be.empty;645      expect(properties.consumedSpace).to.be.equal(0);646  647      const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;648      expect(tokenData).to.be.empty;649    });650  }651  it('Reads yet empty properties of a token (NFT)', async () => {652    await testReadsYetEmptyProperties({type: 'NFT'});653  });654  it('Reads yet empty properties of a token (ReFungible)', async () => {655    await testReadsYetEmptyProperties({type: 'ReFungible'});656  });657658  async function testAssignPropertiesAccordingToPermissions(mode: CollectionMode, pieces: number) {659    await usingApi(async api => {660      const collection = await createCollectionExpectSuccess({mode: mode});661      const token = await createItemExpectSuccess(alice, collection, mode.type);662      await addCollectionAdminExpectSuccess(alice, collection, bob.address);663      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);664665      const propertyKeys: string[] = [];666      let i = 0;667      for (const permission of permissions) {668        for (const signer of permission.signers) {669          const key = i + '_' + signer.address;670          propertyKeys.push(key);671672          await expect(executeTransaction(673            api, 674            alice, 675            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 676          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;677678          await expect(executeTransaction(679            api, 680            signer, 681            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 682          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;683        }684685        i++;686      }687688      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];689      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];690      for (let i = 0; i < properties.length; i++) {691        expect(properties[i].value).to.be.equal('Serotonin increase');692        expect(tokensData[i].value).to.be.equal('Serotonin increase');693      }694    });695  }696  it('Assigns properties to a token according to permissions (NFT)', async () => {697    await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);698  });699  it('Assigns properties to a token according to permissions (ReFungible)', async () => {700    await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);701  });702703  async function testChangesPropertiesAccordingPermission(mode: CollectionMode, pieces: number) {704    await usingApi(async api => {705      const collection = await createCollectionExpectSuccess({mode: mode});706      const token = await createItemExpectSuccess(alice, collection, mode.type);707      await addCollectionAdminExpectSuccess(alice, collection, bob.address);708      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);709710      const propertyKeys: string[] = [];711      let i = 0;712      for (const permission of permissions) {713        if (!permission.permission.mutable) continue;714        715        for (const signer of permission.signers) {716          const key = i + '_' + signer.address;717          propertyKeys.push(key);718  719          await expect(executeTransaction(720            api, 721            alice, 722            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 723          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;724  725          await expect(executeTransaction(726            api, 727            signer, 728            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 729          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;730  731          await expect(executeTransaction(732            api, 733            signer, 734            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 735          ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;736        }737  738        i++;739      }740  741      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];742      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];743      for (let i = 0; i < properties.length; i++) {744        expect(properties[i].value).to.be.equal('Serotonin stable');745        expect(tokensData[i].value).to.be.equal('Serotonin stable');746      }747    });748  }749  it('Changes properties of a token according to permissions (NFT)', async () => {750    await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);751  });752  it('Changes properties of a token according to permissions (ReFungible)', async () => {753    await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);754  });755756  async function testDeletePropertiesAccordingPermission(mode: CollectionMode, pieces: number) {757    await usingApi(async api => {758      const collection = await createCollectionExpectSuccess({mode: mode});759      const token = await createItemExpectSuccess(alice, collection, mode.type);760      await addCollectionAdminExpectSuccess(alice, collection, bob.address);761      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);762763      const propertyKeys: string[] = [];764      let i = 0;765  766      for (const permission of permissions) {767        if (!permission.permission.mutable) continue;768        769        for (const signer of permission.signers) {770          const key = i + '_' + signer.address;771          propertyKeys.push(key);772  773          await expect(executeTransaction(774            api, 775            alice, 776            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 777          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;778  779          await expect(executeTransaction(780            api, 781            signer, 782            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 783          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;784  785          await expect(executeTransaction(786            api, 787            signer, 788            api.tx.unique.deleteTokenProperties(collection, token, [key]), 789          ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;790        }791        792        i++;793      }794  795      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];796      expect(properties).to.be.empty;797      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];798      expect(tokensData).to.be.empty;799      expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);800    });801  }802  it('Deletes properties of a token according to permissions (NFT)', async () => {803    await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);804  });805  it('Deletes properties of a token according to permissions (ReFungible)', async () => {806    await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);807  });808809  it('Assigns properties to a nested token according to permissions', async () => {810    await usingApi(async api => {811      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});812      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});813      const token = await createItemExpectSuccess(alice, collection, 'NFT');814      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});815      await addCollectionAdminExpectSuccess(alice, collection, bob.address);816      await transferExpectSuccess(collection, token, alice, charlie);817818      const propertyKeys: string[] = [];819      let i = 0;820      for (const permission of permissions) {821        for (const signer of permission.signers) {822          const key = i + '_' + signer.address;823          propertyKeys.push(key);824825          await expect(executeTransaction(826            api, 827            alice, 828            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 829          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;830831          await expect(executeTransaction(832            api, 833            signer, 834            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin increase'}]), 835          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;836        }837838        i++;839      }840841      const properties = (await api.rpc.unique.tokenProperties(collection, nestedToken, propertyKeys)).toHuman() as any[];842      const tokensData = (await api.rpc.unique.tokenData(collection, nestedToken, propertyKeys)).toHuman().properties as any[];843      for (let i = 0; i < properties.length; i++) {844        expect(properties[i].value).to.be.equal('Serotonin increase');845        expect(tokensData[i].value).to.be.equal('Serotonin increase');846      }847    });848  });849850  it('Changes properties of a nested token according to permissions', async () => {851    await usingApi(async api => {852      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});853      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});854      const token = await createItemExpectSuccess(alice, collection, 'NFT');855      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});856      await addCollectionAdminExpectSuccess(alice, collection, bob.address);857      await transferExpectSuccess(collection, token, alice, charlie);858859      const propertyKeys: string[] = [];860      let i = 0;861      for (const permission of permissions) {862        if (!permission.permission.mutable) continue;863        864        for (const signer of permission.signers) {865          const key = i + '_' + signer.address;866          propertyKeys.push(key);867868          await expect(executeTransaction(869            api, 870            alice, 871            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 872          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;873874          await expect(executeTransaction(875            api, 876            signer, 877            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin increase'}]), 878          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;879880          await expect(executeTransaction(881            api, 882            signer, 883            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin stable'}]), 884          ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;885        }886887        i++;888      }889890      const properties = (await api.rpc.unique.tokenProperties(collection, nestedToken, propertyKeys)).toHuman() as any[];891      const tokensData = (await api.rpc.unique.tokenData(collection, nestedToken, propertyKeys)).toHuman().properties as any[];892      for (let i = 0; i < properties.length; i++) {893        expect(properties[i].value).to.be.equal('Serotonin stable');894        expect(tokensData[i].value).to.be.equal('Serotonin stable');895      }896    });897  });898899  it('Deletes properties of a nested token according to permissions', async () => {900    await usingApi(async api => {901      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});902      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});903      const token = await createItemExpectSuccess(alice, collection, 'NFT');904      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});905      await addCollectionAdminExpectSuccess(alice, collection, bob.address);906      await transferExpectSuccess(collection, token, alice, charlie);907908      const propertyKeys: string[] = [];909      let i = 0;910911      for (const permission of permissions) {912        if (!permission.permission.mutable) continue;913        914        for (const signer of permission.signers) {915          const key = i + '_' + signer.address;916          propertyKeys.push(key);917918          await expect(executeTransaction(919            api, 920            alice, 921            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 922          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;923924          await expect(executeTransaction(925            api, 926            signer, 927            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin increase'}]), 928          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;929930          await expect(executeTransaction(931            api, 932            signer, 933            api.tx.unique.deleteTokenProperties(collection, nestedToken, [key]), 934          ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;935        }936        937        i++;938      }939940      const properties = (await api.rpc.unique.tokenProperties(collection, nestedToken, propertyKeys)).toJSON() as any[];941      expect(properties).to.be.empty;942      const tokensData = (await api.rpc.unique.tokenData(collection, nestedToken, propertyKeys)).toJSON().properties as any[];943      expect(tokensData).to.be.empty;944      expect((await api.query.nonfungible.tokenProperties(collection, nestedToken)).toJSON().consumedSpace).to.be.equal(0);945    });946  });947});948949describe('Negative Integration Test: Token Properties', () => {950  let collection: number;951  let token: number;952  let originalSpace: number;953  let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];954955  before(async () => {956    await usingApi(async (api, privateKeyWrapper) => {957      alice = privateKeyWrapper('//Alice');958      bob = privateKeyWrapper('//Bob');959      charlie = privateKeyWrapper('//Charlie');960      const dave = privateKeyWrapper('//Dave');961962      constitution = [963        {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},964        {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},965        {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},966        {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},967        {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},968        {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},969      ];970    });971  });972973  async function prepare(mode: CollectionMode, pieces: number) {974    collection = await createCollectionExpectSuccess({mode: mode});975    token = await createItemExpectSuccess(alice, collection, mode.type);976    await addCollectionAdminExpectSuccess(alice, collection, bob.address);977    await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);978        979    await usingApi(async api => {980      let i = 0;981      for (const passage of constitution) {982        const signer = passage.signers[0];983        984        await expect(executeTransaction(985          api, 986          alice, 987          api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 988        ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;989  990        await expect(executeTransaction(991          api, 992          signer, 993          api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 994        ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;995  996        i++;997      }998  999      originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;1000    }); 1001  }10021003  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(mode: CollectionMode, pieces: number) {1004    await prepare(mode, pieces);1005  1006    await usingApi(async api => {1007      let i = -1;1008      for (const forbiddance of constitution) {1009        i++;1010        if (!forbiddance.permission.mutable) continue;1011  1012        await expect(executeTransaction(1013          api, 1014          forbiddance.sinner, 1015          api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1016        ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1017  1018        await expect(executeTransaction(1019          api, 1020          forbiddance.sinner, 1021          api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 1022        ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1023      }1024  1025      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1026      expect(properties.consumedSpace).to.be.equal(originalSpace);1027    });1028  }1029  it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {1030    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);1031  });1032  it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async () => {1033    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);1034  });10351036  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(mode: CollectionMode, pieces: number) {1037    await prepare(mode, pieces);1038    1039    await usingApi(async api => {1040      let i = -1;1041      for (const permission of constitution) {1042        i++;1043        if (permission.permission.mutable) continue;1044  1045        await expect(executeTransaction(1046          api, 1047          permission.signers[0], 1048          api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1049        ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1050  1051        await expect(executeTransaction(1052          api, 1053          permission.signers[0], 1054          api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 1055        ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1056      }1057  1058      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1059      expect(properties.consumedSpace).to.be.equal(originalSpace);1060    });  1061  }1062  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {1063    await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);1064  });1065  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async () => {1066    await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);1067  });10681069  async function testForbidsAddingPropertiesIfPropertyNotDeclared(mode: CollectionMode, pieces: number) {1070    await prepare(mode, pieces);10711072    await usingApi(async api => {1073      await expect(executeTransaction(1074        api, 1075        alice, 1076        api.tx.unique.setTokenProperties(collection, token, [{key: 'non-existent', value: 'I exist!'}]), 1077      ), 'on failing to add a previously non-existent property').to.be.rejectedWith(/common\.NoPermission/);1078        1079      await expect(executeTransaction(1080        api, 1081        alice, 1082        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 1083      ), 'on setting a new non-permitted property').to.not.be.rejected;1084  1085      await expect(executeTransaction(1086        api, 1087        alice, 1088        api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 1089      ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);1090  1091      expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;1092      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1093      expect(properties.consumedSpace).to.be.equal(originalSpace);1094    });1095  }1096  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {1097    await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);1098  });1099  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async () => {1100    await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);1101  });11021103  async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {1104    await prepare(mode, pieces);11051106    await usingApi(async api => {1107      await expect(executeTransaction(1108        api, 1109        alice, 1110        api.tx.unique.setTokenPropertyPermissions(collection, [1111          {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, 1112          {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},1113        ]), 1114      ), 'on setting a new non-permitted property').to.not.be.rejected;1115  1116      // Mute the general tx parsing error1117      {1118        console.error = () => {};1119        await expect(executeTransaction(1120          api, 1121          alice, 1122          api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 1123        )).to.be.rejected;1124      }1125  1126      await expect(executeTransaction(1127        api, 1128        alice, 1129        api.tx.unique.setTokenProperties(collection, token, [1130          {key: 'a_holy_book', value: 'word '.repeat(3277)}, 1131          {key: 'young_years', value: 'neverending'.repeat(1490)},1132        ]), 1133      )).to.be.rejectedWith(/common\.NoSpaceForProperty/);1134  1135      expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;1136      const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1137      expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);1138    });1139  }1140  it('Forbids adding too many properties to a token (NFT)', async () => {1141    await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);1142  });1143  it('Forbids adding too many properties to a token (ReFungible)', async () => {1144    await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);1145  });1146});11471148describe('ReFungible token properties permissions tests', () => {1149  let collection: number;1150  let token: number;11511152  before(async () => {1153    await usingApi(async (api, privateKeyWrapper) => {1154      alice = privateKeyWrapper('//Alice');1155      bob = privateKeyWrapper('//Bob');1156      charlie = privateKeyWrapper('//Charlie');1157    });1158  });11591160  beforeEach(async () => {1161    await usingApi(async api => {1162      collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});1163      token = await createItemExpectSuccess(alice, collection, 'ReFungible');1164      await addCollectionAdminExpectSuccess(alice, collection, bob.address);11651166      await expect(executeTransaction(1167        api, 1168        alice, 1169        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1170      )).to.not.be.rejected;1171    });1172  });11731174  it('Forbids add token property with tokenOwher==true but signer have\'t all pieces', async () => {1175    await usingApi(async api => {1176      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1177  1178      await expect(executeTransaction(1179        api, 1180        alice, 1181        api.tx.unique.setTokenProperties(collection, token, [1182          {key: 'key', value: 'word'}, 1183        ]), 1184      )).to.be.rejectedWith(/common\.NoPermission/);1185    });1186  });11871188  it('Forbids mutate token property with tokenOwher==true but signer have\'t all pieces', async () => {1189    await usingApi(async api => {1190      await expect(executeTransaction(1191        api, 1192        alice, 1193        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1194      )).to.not.be.rejected;1195  1196      await expect(executeTransaction(1197        api, 1198        alice, 1199        api.tx.unique.setTokenProperties(collection, token, [1200          {key: 'key', value: 'word'}, 1201        ]), 1202      )).to.be.not.rejected;12031204      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1205  1206      await expect(executeTransaction(1207        api, 1208        alice, 1209        api.tx.unique.setTokenProperties(collection, token, [1210          {key: 'key', value: 'bad word'}, 1211        ]), 1212      )).to.be.rejectedWith(/common\.NoPermission/);1213    });1214  });12151216  it('Forbids delete token property with tokenOwher==true but signer have\'t all pieces', async () => {1217    await usingApi(async api => {1218      await expect(executeTransaction(1219        api, 1220        alice, 1221        api.tx.unique.setTokenProperties(collection, token, [1222          {key: 'key', value: 'word'}, 1223        ]), 1224      )).to.be.not.rejected;12251226      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1227  1228      await expect(executeTransaction(1229        api, 1230        alice, 1231        api.tx.unique.deleteTokenProperties(collection, token, [1232          'key',1233        ]), 1234      )).to.be.rejectedWith(/common\.NoPermission/);1235    });1236  });1237});
after · tests/src/nesting/properties.test.ts
1import {expect} from 'chai';2import usingApi, {executeTransaction} from '../substrate/substrate-api';3import {4  addCollectionAdminExpectSuccess,5  CollectionMode,6  createCollectionExpectSuccess,7  setCollectionPermissionsExpectSuccess,8  createItemExpectSuccess,9  getCreateCollectionResult,10  transferExpectSuccess,11  requirePallets,12  Pallets13} from '../util/helpers';14import {IKeyringPair} from '@polkadot/types/types';15import {tokenIdToAddress} from '../eth/util/helpers';1617let alice: IKeyringPair;18let bob: IKeyringPair;19let charlie: IKeyringPair;2021describe('Composite Properties Test', () => {22  before(async () => {23    await usingApi(async (api, privateKeyWrapper) => {24      alice = privateKeyWrapper('//Alice');25      bob = privateKeyWrapper('//Bob');26    });27  });2829  async function testMakeSureSuppliesRequired(mode: CollectionMode) {30    await usingApi(async api => {31      const collectionId = await createCollectionExpectSuccess({mode: mode});3233      const collectionOption = await api.rpc.unique.collectionById(collectionId);34      expect(collectionOption.isSome).to.be.true;35      let collection = collectionOption.unwrap();36      expect(collection.tokenPropertyPermissions.toHuman()).to.be.empty;37      expect(collection.properties.toHuman()).to.be.empty;3839      const propertyPermissions = [40        {key: 'mindgame', permission: {collectionAdmin: true, mutable: false, tokenOwner: true}},41        {key: 'skullduggery', permission: {collectionAdmin: false, mutable: true, tokenOwner: false}},42      ];43      await expect(executeTransaction(44        api, 45        alice, 46        api.tx.unique.setTokenPropertyPermissions(collectionId, propertyPermissions), 47      )).to.not.be.rejected;4849      const collectionProperties = [50        {key: 'black_hole', value: 'LIGO'},51        {key: 'electron', value: 'come bond'}, 52      ];53      await expect(executeTransaction(54        api, 55        alice, 56        api.tx.unique.setCollectionProperties(collectionId, collectionProperties), 57      )).to.not.be.rejected;5859      collection = (await api.rpc.unique.collectionById(collectionId)).unwrap();60      expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);61      expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);62    });63  }6465  it('Makes sure collectionById supplies required fields for NFT', async () => {66    await testMakeSureSuppliesRequired({type: 'NFT'});67  });6869  it('Makes sure collectionById supplies required fields for ReFungible', async function() {70    await requirePallets(this, [Pallets.ReFungible]);7172    await testMakeSureSuppliesRequired({type: 'ReFungible'});73  });74});7576// ---------- COLLECTION PROPERTIES7778describe('Integration Test: Collection Properties', () => {79  before(async () => {80    await usingApi(async (api, privateKeyWrapper) => {81      alice = privateKeyWrapper('//Alice');82      bob = privateKeyWrapper('//Bob');83    });84  });8586  it('Reads properties from a collection', async () => {87    await usingApi(async api => {88      const collection = await createCollectionExpectSuccess();89      const properties = (await api.query.common.collectionProperties(collection)).toJSON();90      expect(properties.map).to.be.empty;91      expect(properties.consumedSpace).to.equal(0);92    });93  });949596  async function testSetsPropertiesForCollection(mode: string) {97    await usingApi(async api => {98      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));99      const {collectionId} = getCreateCollectionResult(events);100101      // As owner102      await expect(executeTransaction(103        api, 104        bob, 105        api.tx.unique.setCollectionProperties(collectionId, [{key: 'electron', value: 'come bond'}]), 106      )).to.not.be.rejected;107108      await addCollectionAdminExpectSuccess(bob, collectionId, alice.address);109110      // As administrator111      await expect(executeTransaction(112        api, 113        alice, 114        api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 115      )).to.not.be.rejected;116117      const properties = (await api.rpc.unique.collectionProperties(collectionId, ['electron', 'black_hole'])).toHuman();118      expect(properties).to.be.deep.equal([119        {key: 'electron', value: 'come bond'},120        {key: 'black_hole', value: ''},121      ]);122    });123  }124  it('Sets properties for a NFT collection', async () => {125    await testSetsPropertiesForCollection('NFT');126  });127  it('Sets properties for a ReFungible collection', async function() {128    await requirePallets(this, [Pallets.ReFungible]);129130    await testSetsPropertiesForCollection('ReFungible');131  });132133  async function testCheckValidNames(mode: string) {134    await usingApi(async api => {135      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));136      const {collectionId} = getCreateCollectionResult(events);137  138      // alpha symbols139      await expect(executeTransaction(140        api, 141        bob, 142        api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 143      )).to.not.be.rejected;144  145      // numeric symbols146      await expect(executeTransaction(147        api, 148        bob, 149        api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 150      )).to.not.be.rejected;151  152      // underscore symbol153      await expect(executeTransaction(154        api, 155        bob, 156        api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 157      )).to.not.be.rejected;158  159      // dash symbol160      await expect(executeTransaction(161        api, 162        bob, 163        api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 164      )).to.not.be.rejected;165  166      // underscore symbol167      await expect(executeTransaction(168        api, 169        bob, 170        api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 171      )).to.not.be.rejected;172  173      const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];174      const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();175      expect(properties).to.be.deep.equal([176        {key: 'alpha', value: ''},177        {key: '123', value: ''},178        {key: 'black_hole', value: ''},179        {key: 'semi-automatic', value: ''},180        {key: 'build.rs', value: ''},181      ]);182    });183  }184  it('Check valid names for NFT collection properties keys', async () => {185    await testCheckValidNames('NFT');186  });187  it('Check valid names for ReFungible collection properties keys', async function() {188    await requirePallets(this, [Pallets.ReFungible]);189190    await testCheckValidNames('ReFungible');191  });192193  async function testChangesProperties(mode: CollectionMode) {194    await usingApi(async api => {195      const collection = await createCollectionExpectSuccess({mode: mode});196  197      await expect(executeTransaction(198        api, 199        alice, 200        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 201      )).to.not.be.rejected;202  203      // Mutate the properties204      await expect(executeTransaction(205        api, 206        alice, 207        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 208      )).to.not.be.rejected;209  210      const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();211      expect(properties).to.be.deep.equal([212        {key: 'electron', value: 'bonded'},213        {key: 'black_hole', value: 'LIGO'},214      ]);215    });216  }217  it('Changes properties of a NFT collection', async () => {218    await testChangesProperties({type: 'NFT'});219  });220  it('Changes properties of a ReFungible collection', async function() {221    await requirePallets(this, [Pallets.ReFungible]);222223    await testChangesProperties({type: 'ReFungible'});224  });225226  async function testDeleteProperties(mode: CollectionMode) {227    await usingApi(async api => {228      const collection = await createCollectionExpectSuccess({mode: mode});229  230      await expect(executeTransaction(231        api, 232        alice, 233        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 234      )).to.not.be.rejected;235  236      await expect(executeTransaction(237        api, 238        alice, 239        api.tx.unique.deleteCollectionProperties(collection, ['electron']), 240      )).to.not.be.rejected;241  242      const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();243      expect(properties).to.be.deep.equal([244        {key: 'black_hole', value: 'LIGO'},245      ]);246    });  247  }248  it('Deletes properties of a NFT collection', async () => {249    await testDeleteProperties({type: 'NFT'});250  });251  it('Deletes properties of a ReFungible collection', async function() {252    await requirePallets(this, [Pallets.ReFungible]);253254    await testDeleteProperties({type: 'ReFungible'});255  });256});257258describe('Negative Integration Test: Collection Properties', () => {259  before(async () => {260    await usingApi(async (api, privateKeyWrapper) => {261      alice = privateKeyWrapper('//Alice');262      bob = privateKeyWrapper('//Bob');263    });264  });265  266  async function testFailsSetPropertiesIfNotOwnerOrAdmin(mode: CollectionMode) {267    await usingApi(async api => {268      const collection = await createCollectionExpectSuccess({mode: mode});269  270      await expect(executeTransaction(271        api, 272        bob, 273        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 274      )).to.be.rejectedWith(/common\.NoPermission/);275  276      const properties = (await api.query.common.collectionProperties(collection)).toJSON();277      expect(properties.map).to.be.empty;278      expect(properties.consumedSpace).to.equal(0);279    });  280  }281  it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {282    await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});283  });284  it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async function() {285    await requirePallets(this, [Pallets.ReFungible]);286287    await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});288  });289  290  async function testFailsSetPropertiesThatExeedLimits(mode: CollectionMode) {291    await usingApi(async api => {292      const collection = await createCollectionExpectSuccess({mode: mode});293      const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 294  295      // Mute the general tx parsing error, too many bytes to process296      {297        console.error = () => {};298        await expect(executeTransaction(299          api, 300          alice, 301          api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 302        )).to.be.rejected;303      }304  305      let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();306      expect(properties).to.be.empty;307  308      await expect(executeTransaction(309        api, 310        alice, 311        api.tx.unique.setCollectionProperties(collection, [312          {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, 313          {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 314        ]), 315      )).to.be.rejectedWith(/common\.NoSpaceForProperty/);316  317      properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();318      expect(properties).to.be.empty;319    });  320  }321  it('Fails to set properties that exceed the limits (NFT)', async () => {322    await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});323  });324  it('Fails to set properties that exceed the limits (ReFungible)', async function() {325    await requirePallets(this, [Pallets.ReFungible]);326327    await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});328  });329  330  async function testFailsSetMorePropertiesThanAllowed(mode: CollectionMode) {331    await usingApi(async api => {332      const collection = await createCollectionExpectSuccess({mode: mode});333  334      const propertiesToBeSet = [];335      for (let i = 0; i < 65; i++) {336        propertiesToBeSet.push({337          key: 'electron_' + i,338          value: Math.random() > 0.5 ? 'high' : 'low',339        });340      }341  342      await expect(executeTransaction(343        api, 344        alice, 345        api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 346      )).to.be.rejectedWith(/common\.PropertyLimitReached/);347  348      const properties = (await api.query.common.collectionProperties(collection)).toJSON();349      expect(properties.map).to.be.empty;350      expect(properties.consumedSpace).to.equal(0);351    });  352  }353  it('Fails to set more properties than it is allowed (NFT)', async () => {354    await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});355  });356  it('Fails to set more properties than it is allowed (ReFungible)', async function() {357    await requirePallets(this, [Pallets.ReFungible]);358359    await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});360  });361  362  async function testFailsSetPropertiesWithInvalidNames(mode: CollectionMode) {363    await usingApi(async api => {364      const collection = await createCollectionExpectSuccess({mode: mode});365  366      const invalidProperties = [367        [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],368        [{key: 'Mr/Sandman', value: 'Bring me a gene'}],369        [{key: 'déjà vu', value: 'hmm...'}],370      ];371  372      for (let i = 0; i < invalidProperties.length; i++) {373        await expect(executeTransaction(374          api, 375          alice, 376          api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 377        ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);378      }379  380      await expect(executeTransaction(381        api, 382        alice, 383        api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 384      ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);385  386      await expect(executeTransaction(387        api, 388        alice, 389        api.tx.unique.setCollectionProperties(collection, [390          {key: 'CRISPR-Cas9', value: 'rewriting nature!'},391        ]), 392      ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;393  394      const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');395  396      const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();397      expect(properties).to.be.deep.equal([398        {key: 'CRISPR-Cas9', value: 'rewriting nature!'},399      ]);400  401      for (let i = 0; i < invalidProperties.length; i++) {402        await expect(executeTransaction(403          api, 404          alice, 405          api.tx.unique.deleteCollectionProperties(collection, invalidProperties[i].map(propertySet => propertySet.key)), 406        ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);407      }408    });409  }410  it('Fails to set properties with invalid names (NFT)', async () => {411    await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});412  });413  it('Fails to set properties with invalid names (ReFungible)', async function() {414    await requirePallets(this, [Pallets.ReFungible]);415416    await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});417  });418});419420// ---------- ACCESS RIGHTS421422describe('Integration Test: Access Rights to Token Properties', () => {423  before(async () => {424    await usingApi(async (api, privateKeyWrapper) => {425      alice = privateKeyWrapper('//Alice');426      bob = privateKeyWrapper('//Bob');427    });428  });429  430  it('Reads access rights to properties of a collection', async () => {431    await usingApi(async api => {432      const collection = await createCollectionExpectSuccess();433      const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();434      expect(propertyRights).to.be.empty;435    });436  });437  438  async function testSetsAccessRightsToProperties(mode: CollectionMode) {439    await usingApi(async api => {440      const collection = await createCollectionExpectSuccess({mode: mode});441  442      await expect(executeTransaction(443        api, 444        alice, 445        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 446      )).to.not.be.rejected;447  448      await addCollectionAdminExpectSuccess(alice, collection, bob.address);449  450      await expect(executeTransaction(451        api, 452        alice, 453        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 454      )).to.not.be.rejected;455  456      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();457      expect(propertyRights).to.be.deep.equal([458        {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},459        {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},460      ]);461    });  462  }463  it('Sets access rights to properties of a collection (NFT)', async () => {464    await testSetsAccessRightsToProperties({type: 'NFT'});465  });466  it('Sets access rights to properties of a collection (ReFungible)', async function() {467    await requirePallets(this, [Pallets.ReFungible]);468469    await testSetsAccessRightsToProperties({type: 'ReFungible'});470  });471  472  async function testChangesAccessRightsToProperty(mode: CollectionMode) {473    await usingApi(async api => {474      const collection = await createCollectionExpectSuccess({mode: mode});475  476      await expect(executeTransaction(477        api, 478        alice, 479        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 480      )).to.not.be.rejected;481  482      await expect(executeTransaction(483        api, 484        alice, 485        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 486      )).to.not.be.rejected;487  488      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();489      expect(propertyRights).to.be.deep.equal([490        {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},491      ]);492    });493  }494  it('Changes access rights to properties of a NFT collection', async () => {495    await testChangesAccessRightsToProperty({type: 'NFT'});496  });497  it('Changes access rights to properties of a ReFungible collection', async function() {498    await requirePallets(this, [Pallets.ReFungible]);499500    await testChangesAccessRightsToProperty({type: 'ReFungible'});501  });502});503504describe('Negative Integration Test: Access Rights to Token Properties', () => {505  before(async () => {506    await usingApi(async (api, privateKeyWrapper) => {507      alice = privateKeyWrapper('//Alice');508      bob = privateKeyWrapper('//Bob');509    });510  });511512  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(mode: CollectionMode) {513    await usingApi(async api => {514      const collection = await createCollectionExpectSuccess({mode: mode});515  516      await expect(executeTransaction(517        api, 518        bob, 519        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 520      )).to.be.rejectedWith(/common\.NoPermission/);521  522      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();523      expect(propertyRights).to.be.empty;524    });525  }526  it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {527    await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});528  });529  it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async function() {530    await requirePallets(this, [Pallets.ReFungible]);531532    await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});533  });534535  async function testPreventFromAddingTooManyPossibleProperties(mode: CollectionMode) {536    await usingApi(async api => {537      const collection = await createCollectionExpectSuccess({mode: mode});538  539      const constitution = [];540      for (let i = 0; i < 65; i++) {541        constitution.push({542          key: 'property_' + i,543          permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},544        });545      }546  547      await expect(executeTransaction(548        api, 549        alice, 550        api.tx.unique.setTokenPropertyPermissions(collection, constitution), 551      )).to.be.rejectedWith(/common\.PropertyLimitReached/);552  553      const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();554      expect(propertyRights).to.be.empty;555    });  556  }557  it('Prevents from adding too many possible properties (NFT)', async () => {558    await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});559  });560  it('Prevents from adding too many possible properties (ReFungible)', async function() {561    await requirePallets(this, [Pallets.ReFungible]);562563    await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});564  });565566  async function testPreventAccessRightsModifiedIfConstant(mode: CollectionMode) {567    await usingApi(async api => {568      const collection = await createCollectionExpectSuccess({mode: mode});569  570      await expect(executeTransaction(571        api, 572        alice, 573        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 574      )).to.not.be.rejected;575  576      await expect(executeTransaction(577        api, 578        alice, 579        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 580      )).to.be.rejectedWith(/common\.NoPermission/);581  582      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();583      expect(propertyRights).to.deep.equal([584        {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},585      ]);586    });  587  }588  it('Prevents access rights to be modified if constant (NFT)', async () => {589    await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});590  });591  it('Prevents access rights to be modified if constant (ReFungible)', async function() {592    await requirePallets(this, [Pallets.ReFungible]);593594    await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});595  });596597  async function testPreventsAddingPropertiesWithInvalidNames(mode: CollectionMode) {598    await usingApi(async api => {599      const collection = await createCollectionExpectSuccess({mode: mode});600  601      const invalidProperties = [602        [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],603        [{key: 'G#4', permission: {tokenOwner: true}}],604        [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],605      ];606  607      for (let i = 0; i < invalidProperties.length; i++) {608        await expect(executeTransaction(609          api, 610          alice, 611          api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 612        ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);613      }614  615      await expect(executeTransaction(616        api, 617        alice, 618        api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 619      ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);620  621      const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string622      await expect(executeTransaction(623        api, 624        alice, 625        api.tx.unique.setTokenPropertyPermissions(collection, [626          {key: correctKey, permission: {collectionAdmin: true}},627        ]), 628      ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;629  630      const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');631  632      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();633      expect(propertyRights).to.be.deep.equal([634        {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},635      ]);636    });637  }638  it('Prevents adding properties with invalid names (NFT)', async () => {639    await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});640  });641  it('Prevents adding properties with invalid names (ReFungible)', async function() {642    await requirePallets(this, [Pallets.ReFungible]);643644    await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});645  });646});647648// ---------- TOKEN PROPERTIES649650describe('Integration Test: Token Properties', () => {651  let permissions: {permission: any, signers: IKeyringPair[]}[];652653  before(async () => {654    await usingApi(async (api, privateKeyWrapper) => {655      alice = privateKeyWrapper('//Alice'); // collection owner656      bob = privateKeyWrapper('//Bob'); // collection admin657      charlie = privateKeyWrapper('//Charlie'); // token owner658659      permissions = [660        {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},661        {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},662        {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},663        {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},664        {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},665        {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},666      ];667    });668  });669  670  async function testReadsYetEmptyProperties(mode: CollectionMode) {671    await usingApi(async api => {672      const collection = await createCollectionExpectSuccess({mode: mode});673      const token = await createItemExpectSuccess(alice, collection, mode.type);674  675      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();676      expect(properties.map).to.be.empty;677      expect(properties.consumedSpace).to.be.equal(0);678  679      const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;680      expect(tokenData).to.be.empty;681    });682  }683  it('Reads yet empty properties of a token (NFT)', async () => {684    await testReadsYetEmptyProperties({type: 'NFT'});685  });686  it('Reads yet empty properties of a token (ReFungible)', async function() {687    await requirePallets(this, [Pallets.ReFungible]);688689    await testReadsYetEmptyProperties({type: 'ReFungible'});690  });691692  async function testAssignPropertiesAccordingToPermissions(mode: CollectionMode, pieces: number) {693    await usingApi(async api => {694      const collection = await createCollectionExpectSuccess({mode: mode});695      const token = await createItemExpectSuccess(alice, collection, mode.type);696      await addCollectionAdminExpectSuccess(alice, collection, bob.address);697      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);698699      const propertyKeys: string[] = [];700      let i = 0;701      for (const permission of permissions) {702        for (const signer of permission.signers) {703          const key = i + '_' + signer.address;704          propertyKeys.push(key);705706          await expect(executeTransaction(707            api, 708            alice, 709            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 710          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;711712          await expect(executeTransaction(713            api, 714            signer, 715            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 716          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;717        }718719        i++;720      }721722      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];723      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];724      for (let i = 0; i < properties.length; i++) {725        expect(properties[i].value).to.be.equal('Serotonin increase');726        expect(tokensData[i].value).to.be.equal('Serotonin increase');727      }728    });729  }730  it('Assigns properties to a token according to permissions (NFT)', async () => {731    await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);732  });733  it('Assigns properties to a token according to permissions (ReFungible)', async function() {734    await requirePallets(this, [Pallets.ReFungible]);735736    await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);737  });738739  async function testChangesPropertiesAccordingPermission(mode: CollectionMode, pieces: number) {740    await usingApi(async api => {741      const collection = await createCollectionExpectSuccess({mode: mode});742      const token = await createItemExpectSuccess(alice, collection, mode.type);743      await addCollectionAdminExpectSuccess(alice, collection, bob.address);744      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);745746      const propertyKeys: string[] = [];747      let i = 0;748      for (const permission of permissions) {749        if (!permission.permission.mutable) continue;750        751        for (const signer of permission.signers) {752          const key = i + '_' + signer.address;753          propertyKeys.push(key);754  755          await expect(executeTransaction(756            api, 757            alice, 758            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 759          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;760  761          await expect(executeTransaction(762            api, 763            signer, 764            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 765          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;766  767          await expect(executeTransaction(768            api, 769            signer, 770            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 771          ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;772        }773  774        i++;775      }776  777      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];778      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];779      for (let i = 0; i < properties.length; i++) {780        expect(properties[i].value).to.be.equal('Serotonin stable');781        expect(tokensData[i].value).to.be.equal('Serotonin stable');782      }783    });784  }785  it('Changes properties of a token according to permissions (NFT)', async () => {786    await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);787  });788  it('Changes properties of a token according to permissions (ReFungible)', async function() {789    await requirePallets(this, [Pallets.ReFungible]);790791    await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);792  });793794  async function testDeletePropertiesAccordingPermission(mode: CollectionMode, pieces: number) {795    await usingApi(async api => {796      const collection = await createCollectionExpectSuccess({mode: mode});797      const token = await createItemExpectSuccess(alice, collection, mode.type);798      await addCollectionAdminExpectSuccess(alice, collection, bob.address);799      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);800801      const propertyKeys: string[] = [];802      let i = 0;803  804      for (const permission of permissions) {805        if (!permission.permission.mutable) continue;806        807        for (const signer of permission.signers) {808          const key = i + '_' + signer.address;809          propertyKeys.push(key);810  811          await expect(executeTransaction(812            api, 813            alice, 814            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 815          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;816  817          await expect(executeTransaction(818            api, 819            signer, 820            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 821          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;822  823          await expect(executeTransaction(824            api, 825            signer, 826            api.tx.unique.deleteTokenProperties(collection, token, [key]), 827          ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;828        }829        830        i++;831      }832  833      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];834      expect(properties).to.be.empty;835      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];836      expect(tokensData).to.be.empty;837      expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);838    });839  }840  it('Deletes properties of a token according to permissions (NFT)', async () => {841    await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);842  });843  it('Deletes properties of a token according to permissions (ReFungible)', async function() {844    await requirePallets(this, [Pallets.ReFungible]);845846    await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);847  });848849  it('Assigns properties to a nested token according to permissions', async () => {850    await usingApi(async api => {851      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});852      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});853      const token = await createItemExpectSuccess(alice, collection, 'NFT');854      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});855      await addCollectionAdminExpectSuccess(alice, collection, bob.address);856      await transferExpectSuccess(collection, token, alice, charlie);857858      const propertyKeys: string[] = [];859      let i = 0;860      for (const permission of permissions) {861        for (const signer of permission.signers) {862          const key = i + '_' + signer.address;863          propertyKeys.push(key);864865          await expect(executeTransaction(866            api, 867            alice, 868            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 869          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;870871          await expect(executeTransaction(872            api, 873            signer, 874            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin increase'}]), 875          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;876        }877878        i++;879      }880881      const properties = (await api.rpc.unique.tokenProperties(collection, nestedToken, propertyKeys)).toHuman() as any[];882      const tokensData = (await api.rpc.unique.tokenData(collection, nestedToken, propertyKeys)).toHuman().properties as any[];883      for (let i = 0; i < properties.length; i++) {884        expect(properties[i].value).to.be.equal('Serotonin increase');885        expect(tokensData[i].value).to.be.equal('Serotonin increase');886      }887    });888  });889890  it('Changes properties of a nested token according to permissions', async () => {891    await usingApi(async api => {892      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});893      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});894      const token = await createItemExpectSuccess(alice, collection, 'NFT');895      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});896      await addCollectionAdminExpectSuccess(alice, collection, bob.address);897      await transferExpectSuccess(collection, token, alice, charlie);898899      const propertyKeys: string[] = [];900      let i = 0;901      for (const permission of permissions) {902        if (!permission.permission.mutable) continue;903        904        for (const signer of permission.signers) {905          const key = i + '_' + signer.address;906          propertyKeys.push(key);907908          await expect(executeTransaction(909            api, 910            alice, 911            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 912          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;913914          await expect(executeTransaction(915            api, 916            signer, 917            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin increase'}]), 918          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;919920          await expect(executeTransaction(921            api, 922            signer, 923            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin stable'}]), 924          ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;925        }926927        i++;928      }929930      const properties = (await api.rpc.unique.tokenProperties(collection, nestedToken, propertyKeys)).toHuman() as any[];931      const tokensData = (await api.rpc.unique.tokenData(collection, nestedToken, propertyKeys)).toHuman().properties as any[];932      for (let i = 0; i < properties.length; i++) {933        expect(properties[i].value).to.be.equal('Serotonin stable');934        expect(tokensData[i].value).to.be.equal('Serotonin stable');935      }936    });937  });938939  it('Deletes properties of a nested token according to permissions', async () => {940    await usingApi(async api => {941      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});942      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});943      const token = await createItemExpectSuccess(alice, collection, 'NFT');944      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});945      await addCollectionAdminExpectSuccess(alice, collection, bob.address);946      await transferExpectSuccess(collection, token, alice, charlie);947948      const propertyKeys: string[] = [];949      let i = 0;950951      for (const permission of permissions) {952        if (!permission.permission.mutable) continue;953        954        for (const signer of permission.signers) {955          const key = i + '_' + signer.address;956          propertyKeys.push(key);957958          await expect(executeTransaction(959            api, 960            alice, 961            api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 962          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;963964          await expect(executeTransaction(965            api, 966            signer, 967            api.tx.unique.setTokenProperties(collection, nestedToken, [{key: key, value: 'Serotonin increase'}]), 968          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;969970          await expect(executeTransaction(971            api, 972            signer, 973            api.tx.unique.deleteTokenProperties(collection, nestedToken, [key]), 974          ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;975        }976        977        i++;978      }979980      const properties = (await api.rpc.unique.tokenProperties(collection, nestedToken, propertyKeys)).toJSON() as any[];981      expect(properties).to.be.empty;982      const tokensData = (await api.rpc.unique.tokenData(collection, nestedToken, propertyKeys)).toJSON().properties as any[];983      expect(tokensData).to.be.empty;984      expect((await api.query.nonfungible.tokenProperties(collection, nestedToken)).toJSON().consumedSpace).to.be.equal(0);985    });986  });987});988989describe('Negative Integration Test: Token Properties', () => {990  let collection: number;991  let token: number;992  let originalSpace: number;993  let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];994995  before(async () => {996    await usingApi(async (api, privateKeyWrapper) => {997      alice = privateKeyWrapper('//Alice');998      bob = privateKeyWrapper('//Bob');999      charlie = privateKeyWrapper('//Charlie');1000      const dave = privateKeyWrapper('//Dave');10011002      constitution = [1003        {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},1004        {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},1005        {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},1006        {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},1007        {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},1008        {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},1009      ];1010    });1011  });10121013  async function prepare(mode: CollectionMode, pieces: number) {1014    collection = await createCollectionExpectSuccess({mode: mode});1015    token = await createItemExpectSuccess(alice, collection, mode.type);1016    await addCollectionAdminExpectSuccess(alice, collection, bob.address);1017    await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);1018        1019    await usingApi(async api => {1020      let i = 0;1021      for (const passage of constitution) {1022        const signer = passage.signers[0];1023        1024        await expect(executeTransaction(1025          api, 1026          alice, 1027          api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 1028        ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;1029  1030        await expect(executeTransaction(1031          api, 1032          signer, 1033          api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 1034        ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;1035  1036        i++;1037      }1038  1039      originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;1040    }); 1041  }10421043  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(mode: CollectionMode, pieces: number) {1044    await prepare(mode, pieces);1045  1046    await usingApi(async api => {1047      let i = -1;1048      for (const forbiddance of constitution) {1049        i++;1050        if (!forbiddance.permission.mutable) continue;1051  1052        await expect(executeTransaction(1053          api, 1054          forbiddance.sinner, 1055          api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1056        ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1057  1058        await expect(executeTransaction(1059          api, 1060          forbiddance.sinner, 1061          api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 1062        ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1063      }1064  1065      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1066      expect(properties.consumedSpace).to.be.equal(originalSpace);1067    });1068  }1069  it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {1070    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);1071  });1072  it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async function() {1073    await requirePallets(this, [Pallets.ReFungible]);10741075    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);1076  });10771078  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(mode: CollectionMode, pieces: number) {1079    await prepare(mode, pieces);1080    1081    await usingApi(async api => {1082      let i = -1;1083      for (const permission of constitution) {1084        i++;1085        if (permission.permission.mutable) continue;1086  1087        await expect(executeTransaction(1088          api, 1089          permission.signers[0], 1090          api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1091        ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1092  1093        await expect(executeTransaction(1094          api, 1095          permission.signers[0], 1096          api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 1097        ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1098      }1099  1100      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1101      expect(properties.consumedSpace).to.be.equal(originalSpace);1102    });  1103  }1104  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {1105    await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);1106  });1107  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async function() {1108    await requirePallets(this, [Pallets.ReFungible]);11091110    await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);1111  });11121113  async function testForbidsAddingPropertiesIfPropertyNotDeclared(mode: CollectionMode, pieces: number) {1114    await prepare(mode, pieces);11151116    await usingApi(async api => {1117      await expect(executeTransaction(1118        api, 1119        alice, 1120        api.tx.unique.setTokenProperties(collection, token, [{key: 'non-existent', value: 'I exist!'}]), 1121      ), 'on failing to add a previously non-existent property').to.be.rejectedWith(/common\.NoPermission/);1122        1123      await expect(executeTransaction(1124        api, 1125        alice, 1126        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 1127      ), 'on setting a new non-permitted property').to.not.be.rejected;1128  1129      await expect(executeTransaction(1130        api, 1131        alice, 1132        api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 1133      ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);1134  1135      expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;1136      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1137      expect(properties.consumedSpace).to.be.equal(originalSpace);1138    });1139  }1140  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {1141    await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);1142  });1143  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async function() {1144    await requirePallets(this, [Pallets.ReFungible]);11451146    await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);1147  });11481149  async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {1150    await prepare(mode, pieces);11511152    await usingApi(async api => {1153      await expect(executeTransaction(1154        api, 1155        alice, 1156        api.tx.unique.setTokenPropertyPermissions(collection, [1157          {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, 1158          {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},1159        ]), 1160      ), 'on setting a new non-permitted property').to.not.be.rejected;1161  1162      // Mute the general tx parsing error1163      {1164        console.error = () => {};1165        await expect(executeTransaction(1166          api, 1167          alice, 1168          api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 1169        )).to.be.rejected;1170      }1171  1172      await expect(executeTransaction(1173        api, 1174        alice, 1175        api.tx.unique.setTokenProperties(collection, token, [1176          {key: 'a_holy_book', value: 'word '.repeat(3277)}, 1177          {key: 'young_years', value: 'neverending'.repeat(1490)},1178        ]), 1179      )).to.be.rejectedWith(/common\.NoSpaceForProperty/);1180  1181      expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;1182      const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1183      expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);1184    });1185  }1186  it('Forbids adding too many properties to a token (NFT)', async () => {1187    await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);1188  });1189  it('Forbids adding too many properties to a token (ReFungible)', async function() {1190    await requirePallets(this, [Pallets.ReFungible]);11911192    await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);1193  });1194});11951196describe('ReFungible token properties permissions tests', () => {1197  let collection: number;1198  let token: number;11991200  before(async function() {1201    await requirePallets(this, [Pallets.ReFungible]);12021203    await usingApi(async (api, privateKeyWrapper) => {1204      alice = privateKeyWrapper('//Alice');1205      bob = privateKeyWrapper('//Bob');1206      charlie = privateKeyWrapper('//Charlie');1207    });1208  });12091210  beforeEach(async () => {1211    await usingApi(async api => {1212      collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});1213      token = await createItemExpectSuccess(alice, collection, 'ReFungible');1214      await addCollectionAdminExpectSuccess(alice, collection, bob.address);12151216      await expect(executeTransaction(1217        api, 1218        alice, 1219        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1220      )).to.not.be.rejected;1221    });1222  });12231224  it('Forbids add token property with tokenOwher==true but signer have\'t all pieces', async () => {1225    await usingApi(async api => {1226      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1227  1228      await expect(executeTransaction(1229        api, 1230        alice, 1231        api.tx.unique.setTokenProperties(collection, token, [1232          {key: 'key', value: 'word'}, 1233        ]), 1234      )).to.be.rejectedWith(/common\.NoPermission/);1235    });1236  });12371238  it('Forbids mutate token property with tokenOwher==true but signer have\'t all pieces', async () => {1239    await usingApi(async api => {1240      await expect(executeTransaction(1241        api, 1242        alice, 1243        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1244      )).to.not.be.rejected;1245  1246      await expect(executeTransaction(1247        api, 1248        alice, 1249        api.tx.unique.setTokenProperties(collection, token, [1250          {key: 'key', value: 'word'}, 1251        ]), 1252      )).to.be.not.rejected;12531254      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1255  1256      await expect(executeTransaction(1257        api, 1258        alice, 1259        api.tx.unique.setTokenProperties(collection, token, [1260          {key: 'key', value: 'bad word'}, 1261        ]), 1262      )).to.be.rejectedWith(/common\.NoPermission/);1263    });1264  });12651266  it('Forbids delete token property with tokenOwher==true but signer have\'t all pieces', async () => {1267    await usingApi(async api => {1268      await expect(executeTransaction(1269        api, 1270        alice, 1271        api.tx.unique.setTokenProperties(collection, token, [1272          {key: 'key', value: 'word'}, 1273        ]), 1274      )).to.be.not.rejected;12751276      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1277  1278      await expect(executeTransaction(1279        api, 1280        alice, 1281        api.tx.unique.deleteTokenProperties(collection, token, [1282          'key',1283        ]), 1284      )).to.be.rejectedWith(/common\.NoPermission/);1285    });1286  });1287});
modifiedtests/src/nesting/rules-smoke.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/rules-smoke.test.ts
+++ b/tests/src/nesting/rules-smoke.test.ts
@@ -1,7 +1,7 @@
 import {expect} from 'chai';
 import {tokenIdToAddress} from '../eth/util/helpers';
 import usingApi, {executeTransaction} from '../substrate/substrate-api';
-import {createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, CrossAccountId, getCreateCollectionResult} from '../util/helpers';
+import {createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, CrossAccountId, getCreateCollectionResult, requirePallets, Pallets} from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
 describe('nesting check', () => {
@@ -47,7 +47,9 @@
     });
   });
 
-  it('called for refungible', async () => {
+  it('called for refungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {ReFungible: {}})))
modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/unnest.test.ts
+++ b/tests/src/nesting/unnest.test.ts
@@ -10,6 +10,8 @@
   setCollectionPermissionsExpectSuccess,
   transferExpectSuccess,
   transferFromExpectSuccess,
+  requirePallets,
+  Pallets
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -80,7 +82,9 @@
     });
   });
 
-  it('ReFungible: allows the owner to successfully unnest a token', async () => {
+  it('ReFungible: allows the owner to successfully unnest a token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
modifiedtests/src/nextSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/nextSponsoring.test.ts
+++ b/tests/src/nextSponsoring.test.ts
@@ -27,6 +27,8 @@
   transferExpectSuccess,
   normalizeAccountId,
   getNextSponsored,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -89,7 +91,9 @@
     });
   });
 
-  it('ReFungible', async () => {
+  it('ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
 
       const createMode = 'ReFungible';
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -49,8 +49,6 @@
   'inflation',
   'unique',
   'nonfungible',
-  'refungible',
-  'scheduler',
   'charging',
 ];
 
@@ -66,8 +64,16 @@
     await usingApi(async api => {
       const chain = await api.rpc.system.chain();
 
-      if (!chain.eq('UNIQUE')) {
-        requiredPallets.push(...['rmrkcore', 'rmrkequip']);
+      const refungible = 'refungible';
+      const scheduler = 'scheduler';
+      const rmrkPallets = ['rmrkcore', 'rmrkequip'];
+
+      if (chain.eq('OPAL by UNIQUE')) {
+        requiredPallets.push(refungible, scheduler, ...rmrkPallets);
+      } else if (chain.eq('QUARTZ by UNIQUE')) {
+        // Insert Quartz additional pallets here
+      } else if (chain.eq('UNIQUE')) {
+        // Insert Unique additional pallets here
       }
     });
   });
modifiedtests/src/refungible.test.tsdiffbeforeafterboth
--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -38,6 +38,7 @@
   getDestroyItemsResult,
   getModuleNames,
   Pallets,
+  requirePallets
 } from './util/helpers';
 
 import chai from 'chai';
@@ -52,6 +53,8 @@
 
 describe('integration test: Refungible functionality:', async () => {
   before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
       bob = privateKeyWrapper('//Bob');
modifiedtests/src/rmrk/acceptNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/acceptNft.test.ts
+++ b/tests/src/rmrk/acceptNft.test.ts
@@ -14,7 +14,7 @@
   let api: any;
   before(async function() {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
   
   
modifiedtests/src/rmrk/addResource.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/addResource.test.ts
+++ b/tests/src/rmrk/addResource.test.ts
@@ -27,7 +27,7 @@
   let api: any;
   before(async function() {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   it('add resource', async () => {
modifiedtests/src/rmrk/addTheme.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/addTheme.test.ts
+++ b/tests/src/rmrk/addTheme.test.ts
@@ -9,7 +9,7 @@
   let api: any;
   before(async function() {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkEquip]);
+    await requirePallets(this, [Pallets.RmrkEquip]);
   });
 
   const alice = '//Alice';
modifiedtests/src/rmrk/burnNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/burnNft.test.ts
+++ b/tests/src/rmrk/burnNft.test.ts
@@ -17,7 +17,7 @@
   let api: any;
   before(async function() {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
 
modifiedtests/src/rmrk/changeCollectionIssuer.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/changeCollectionIssuer.test.ts
+++ b/tests/src/rmrk/changeCollectionIssuer.test.ts
@@ -13,7 +13,7 @@
   let api: any;
   before(async function() {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
 
modifiedtests/src/rmrk/createBase.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/createBase.test.ts
+++ b/tests/src/rmrk/createBase.test.ts
@@ -6,7 +6,7 @@
   let api: any;
   before(async function() {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore, Pallets.RmrkEquip]);
+    await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
   });
 
   const alice = '//Alice';
modifiedtests/src/rmrk/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/createCollection.test.ts
+++ b/tests/src/rmrk/createCollection.test.ts
@@ -6,7 +6,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
 
modifiedtests/src/rmrk/deleteCollection.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/deleteCollection.test.ts
+++ b/tests/src/rmrk/deleteCollection.test.ts
@@ -7,7 +7,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const Alice = '//Alice';
modifiedtests/src/rmrk/equipNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/equipNft.test.ts
+++ b/tests/src/rmrk/equipNft.test.ts
@@ -126,7 +126,7 @@
   
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore, Pallets.RmrkEquip]);
+    await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
   });
 
   it('equip nft', async () => {
modifiedtests/src/rmrk/getOwnedNfts.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/getOwnedNfts.test.ts
+++ b/tests/src/rmrk/getOwnedNfts.test.ts
@@ -9,7 +9,7 @@
   
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
 
modifiedtests/src/rmrk/lockCollection.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/lockCollection.test.ts
+++ b/tests/src/rmrk/lockCollection.test.ts
@@ -11,7 +11,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   it('lock collection', async () => {
modifiedtests/src/rmrk/mintNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/mintNft.test.ts
+++ b/tests/src/rmrk/mintNft.test.ts
@@ -10,7 +10,7 @@
  
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
 
modifiedtests/src/rmrk/rejectNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/rejectNft.test.ts
+++ b/tests/src/rmrk/rejectNft.test.ts
@@ -14,7 +14,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
 
modifiedtests/src/rmrk/removeResource.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/removeResource.test.ts
+++ b/tests/src/rmrk/removeResource.test.ts
@@ -20,7 +20,7 @@
   before(async function() {
     api = await getApiConnection();
     ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const Alice = '//Alice';
modifiedtests/src/rmrk/rmrkIsolation.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/rmrkIsolation.test.ts
+++ b/tests/src/rmrk/rmrkIsolation.test.ts
@@ -64,7 +64,7 @@
   before(async function() {
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
-      requirePallets(this, api, [Pallets.RmrkCore]);
+      await requirePallets(this, [Pallets.RmrkCore]);
     });
   });
 
modifiedtests/src/rmrk/sendNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/sendNft.test.ts
+++ b/tests/src/rmrk/sendNft.test.ts
@@ -9,7 +9,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const maxNftId = 0xFFFFFFFF;
modifiedtests/src/rmrk/setCollectionProperty.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setCollectionProperty.test.ts
+++ b/tests/src/rmrk/setCollectionProperty.test.ts
@@ -10,7 +10,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   it('set collection property', async () => {
modifiedtests/src/rmrk/setEquippableList.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setEquippableList.test.ts
+++ b/tests/src/rmrk/setEquippableList.test.ts
@@ -7,7 +7,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const alice = '//Alice';
modifiedtests/src/rmrk/setNftProperty.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setNftProperty.test.ts
+++ b/tests/src/rmrk/setNftProperty.test.ts
@@ -8,7 +8,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const alice = '//Alice';
modifiedtests/src/rmrk/setResourcePriorities.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setResourcePriorities.test.ts
+++ b/tests/src/rmrk/setResourcePriorities.test.ts
@@ -7,7 +7,7 @@
   let api: any;
   before(async function () {
     api = await getApiConnection();
-    requirePallets(this, api, [Pallets.RmrkCore]);
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const alice = '//Alice';
modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionSponsor.test.ts
+++ b/tests/src/setCollectionSponsor.test.ts
@@ -23,6 +23,8 @@
   setCollectionSponsorExpectFailure,
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -50,7 +52,9 @@
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
-  it('Set ReFungible collection sponsor', async () => {
+  it('Set ReFungible collection sponsor', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -35,11 +35,14 @@
   getBalance as getTokenBalance,
   transferFromExpectSuccess,
   transferFromExpectFail,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 import {
   subToEth,
   itWeb3, 
 } from './eth/util/helpers';
+import { request } from 'https';
 
 let alice: IKeyringPair;
 let bob: IKeyringPair;
@@ -89,56 +92,61 @@
     });
   });
 
-  it('User can transfer owned token', async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 'NFT');
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob, 1, 'Fungible');
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await transferExpectSuccess(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        alice,
-        bob,
-        100,
-        'ReFungible',
-      );
-    });
+  it('[nft] User can transfer owned token', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+    await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 'NFT');
+  });
+
+  it('[fungible] User can transfer owned token', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob, 1, 'Fungible');
+  });
+
+  it('[refungible] User can transfer owned token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await transferExpectSuccess(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      alice,
+      bob,
+      100,
+      'ReFungible',
+    );
+  });
+
+  it('[nft] Collection admin can transfer owned token', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
+    const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT', bob.address);
+    await transferExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, 1, 'NFT');
+  });
+
+  it('[fungible] Collection admin can transfer owned token', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    await addCollectionAdminExpectSuccess(alice, fungibleCollectionId, bob.address);
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible', bob.address);
+    await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, 1, 'Fungible');
   });
 
-  it('Collection admin can transfer owned token', async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
-      const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT', bob.address);
-      await transferExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, 1, 'NFT');
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      await addCollectionAdminExpectSuccess(alice, fungibleCollectionId, bob.address);
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible', bob.address);
-      await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, 1, 'Fungible');
-      // reFungible
-      const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      await addCollectionAdminExpectSuccess(alice, reFungibleCollectionId, bob.address);
-      const newReFungibleTokenId = await createItemExpectSuccess(bob, reFungibleCollectionId, 'ReFungible', bob.address);
-      await transferExpectSuccess(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        100,
-        'ReFungible',
-      );
-    });
+  it('[refungible] Collection admin can transfer owned token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    await addCollectionAdminExpectSuccess(alice, reFungibleCollectionId, bob.address);
+    const newReFungibleTokenId = await createItemExpectSuccess(bob, reFungibleCollectionId, 'ReFungible', bob.address);
+    await transferExpectSuccess(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      100,
+      'ReFungible',
+    );
   });
 });
 
@@ -150,33 +158,49 @@
       charlie = privateKeyWrapper('//Charlie');
     });
   });
-  it('Transfer with not existed collection_id', async () => {
+
+  it('[nft] Transfer with not existed collection_id', async () => {
     await usingApi(async (api) => {
-      // nft
       const nftCollectionCount = await getCreatedCollectionCount(api);
       await transferExpectFailure(nftCollectionCount + 1, 1, alice, bob, 1);
-      // fungible
+    });
+  });
+
+  it('[fungible] Transfer with not existed collection_id', async () => {
+    await usingApi(async (api) => {
       const fungibleCollectionCount = await getCreatedCollectionCount(api);
       await transferExpectFailure(fungibleCollectionCount + 1, 0, alice, bob, 1);
-      // reFungible
+    });
+  });
+
+  it('[refungible] Transfer with not existed collection_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api) => {
       const reFungibleCollectionCount = await getCreatedCollectionCount(api);
       await transferExpectFailure(reFungibleCollectionCount + 1, 1, alice, bob, 1);
     });
   });
-  it('Transfer with deleted collection_id', async () => {
-    // nft
+
+  it('[nft] Transfer with deleted collection_id', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId);
     await destroyCollectionExpectSuccess(nftCollectionId);
     await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with deleted collection_id', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
     await destroyCollectionExpectSuccess(fungibleCollectionId);
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, alice, bob, 1);
-    // reFungible
+  });
+
+  it('[refungible] Transfer with deleted collection_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -190,16 +214,21 @@
       1,
     );
   });
-  it('Transfer with not existed item_id', async () => {
-    // nft
+
+  it('[nft] Transfer with not existed item_id', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     await transferExpectFailure(nftCollectionId, 2, alice, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with not existed item_id', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await transferExpectFailure(fungibleCollectionId, 2, alice, bob, 1);
-    // reFungible
-    const reFungibleCollectionId = await
-    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+  });
+
+  it('[refungible] Transfer with not existed item_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await transferExpectFailure(
       reFungibleCollectionId,
       2,
@@ -208,18 +237,24 @@
       1,
     );
   });
-  it('Transfer with deleted item_id', async () => {
-    // nft
+
+  it('[nft] Transfer with deleted item_id', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId, 1);
     await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with deleted item_id', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, alice, bob, 1);
-    // reFungible
+  });
+
+  it('[refungible] Transfer with deleted item_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -232,18 +267,23 @@
       1,
     );
   });
-  it('Transfer with recipient that is not owner', async () => {
-    // nft
+
+  it('[nft] Transfer with recipient that is not owner', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await transferExpectFailure(nftCollectionId, newNftTokenId, charlie, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with recipient that is not owner', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, charlie, bob, 1);
-    // reFungible
-    const reFungibleCollectionId = await
-    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+  });
+
+  it('[refungible] Transfer with recipient that is not owner', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await transferExpectFailure(
       reFungibleCollectionId,
@@ -276,7 +316,9 @@
     });
   });
 
-  it('RFT', async () => {
+  it('RFT', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -31,6 +31,8 @@
   burnItemExpectSuccess,
   setCollectionLimitsExpectSuccess,
   getCreatedCollectionCount,
+  requirePallets,
+  Pallets
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -49,36 +51,36 @@
     });
   });
 
-  it('Execute the extrinsic and check nftItemList - owner of token', async () => {
-    await usingApi(async () => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+  it('[nft] Execute the extrinsic and check nftItemList - owner of token', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
 
-      await transferFromExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, charlie, 1, 'NFT');
+    await transferFromExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, charlie, 1, 'NFT');
+  });
 
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
-      await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1, 'Fungible');
+  it('[fungible] Execute the extrinsic and check nftItemList - owner of token', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
+    await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1, 'Fungible');
+  });
 
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 100);
-      await transferFromExpectSuccess(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        charlie,
-        100,
-        'ReFungible',
-      );
-    });
+  it('[refungible] Execute the extrinsic and check nftItemList - owner of token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 100);
+    await transferFromExpectSuccess(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      charlie,
+      100,
+      'ReFungible',
+    );
   });
 
   it('Should reduce allowance if value is big', async () => {
@@ -119,20 +121,28 @@
     });
   });
 
-  it('transferFrom for a collection that does not exist', async () => {
+  it('[nft] transferFrom for a collection that does not exist', async () => {
     await usingApi(async (api: ApiPromise) => {
-      // nft
       const nftCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
 
       await transferFromExpectFail(nftCollectionCount + 1, 1, bob, alice, charlie, 1);
+    });
+  });
 
-      // fungible
+  it('[fungible] transferFrom for a collection that does not exist', async () => {
+    await usingApi(async (api: ApiPromise) => {
       const fungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob);
 
       await transferFromExpectFail(fungibleCollectionCount + 1, 0, bob, alice, charlie, 1);
-      // reFungible
+    });
+  });
+
+  it('[refungible] transferFrom for a collection that does not exist', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api: ApiPromise) => {
       const reFungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob);
 
@@ -158,67 +168,70 @@
     });
   }); */
 
-  it('transferFrom for not approved address', async () => {
-    await usingApi(async () => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+  it('[nft] transferFrom for not approved address', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
 
-      await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 1);
+    await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 1);
+  });
 
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1);
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await transferFromExpectFail(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        charlie,
-        1,
-      );
-    });
+  it('[fungible] transferFrom for not approved address', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1);
+  });
+
+  it('[refungible] transferFrom for not approved address', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await
+    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await transferFromExpectFail(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      charlie,
+      1,
+    );
+  });
+
+  it('[nft] transferFrom incorrect token count', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+
+    await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 2);
   });
 
-  it('transferFrom incorrect token count', async () => {
-    await usingApi(async () => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+  it('[fungible] transferFrom incorrect token count', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
+    await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 2);
+  });
 
-      await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 2);
+  it('[refungible] transferFrom incorrect token count', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
 
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
-      await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 2);
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
-      await transferFromExpectFail(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        charlie,
-        2,
-      );
-    });
+    const reFungibleCollectionId = await
+    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
+    await transferFromExpectFail(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      charlie,
+      2,
+    );
   });
 
-  it('execute transferFrom from account that is not owner of collection', async () => {
+  it('[nft] execute transferFrom from account that is not owner of collection', async () => {
     await usingApi(async (api, privateKeyWrapper) => {
       const dave = privateKeyWrapper('//Dave');
-      // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
       try {
@@ -230,8 +243,13 @@
       }
 
       // await transferFromExpectFail(nftCollectionId, newNftTokenId, Dave, Alice, Charlie, 1);
+    });
+  });
 
-      // fungible
+  it('[fungible] execute transferFrom from account that is not owner of collection', async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      const dave = privateKeyWrapper('//Dave');
+
       const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
       const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
       try {
@@ -241,7 +259,14 @@
         // tslint:disable-next-line:no-unused-expression
         expect(e).to.be.exist;
       }
-      // reFungible
+    });
+  });
+
+  it('[refungible] execute transferFrom from account that is not owner of collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api, privateKeyWrapper) => {
+      const dave = privateKeyWrapper('//Dave');
       const reFungibleCollectionId = await
       createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -276,7 +301,9 @@
 
     });
   });
-  it('transferFrom burnt token before approve ReFungible', async () => {
+  it('transferFrom burnt token before approve ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async () => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await setCollectionLimitsExpectSuccess(alice, reFungibleCollectionId, {ownerCanTransfer: true});
@@ -308,7 +335,9 @@
 
     });
   });
-  it('transferFrom burnt token after approve ReFungible', async () => {
+  it('transferFrom burnt token after approve ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async () => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');