git.delta.rocks / unique-network / refs/commits / 36ef0466a311

difftreelog

Add tests for properties

kryadinskii2022-05-10parent: #2976d69.patch.diff
in: master

6 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -50,6 +50,7 @@
     "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts",
     "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts",
     "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts",
+    "testCreateMultipleItemsEx": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItemsEx.test.ts",
     "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",
     "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",
     "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -17,7 +17,7 @@
 import {expect} from 'chai';
 import privateKey from './substrate/privateKey';
 import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api';
-import {createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo} from './util/helpers';
+import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess} from './util/helpers';
 
 describe('integration test: ext. createCollection():', () => {
   it('Create new NFT collection', async () => {
@@ -38,6 +38,25 @@
   it('Create new ReFungible collection', async () => {
     await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
   });
+
+  it('create new collection with properties #1', async () => {
+    await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, 
+      properties: [{key: 'key1', value: 'val1'}], 
+      propPerm:   [{key: 'key1', tokenOwner: true, mutable: false, collectionAdmin: true}]});
+  });
+
+  it('create new collection with properties #2', async () => {
+    await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, 
+      properties: [{key: 'key1', value: 'val1'}], 
+      propPerm:   [{key: 'key1', tokenOwner: false, mutable: true, collectionAdmin: false}]});
+  });
+
+  it('create new collection with properties #3', async () => {
+    await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, 
+      properties: [{key: 'key1', value: 'val1'}], 
+      propPerm:   [{key: 'key1', tokenOwner: true, mutable: false, collectionAdmin: false}]});
+  });
+
   it('Create new collection with extra fields', async () => {
     await usingApi(async api => {
       const alice = privateKey('//Alice');
@@ -96,4 +115,24 @@
       await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/^common.CollectionTokenLimitExceeded$/);
     });
   });
+
+  it('(!negative test!) create collection with incorrect property limit (64 elements)', async () => {
+    const props = [];
+
+    for (let i = 0; i < 65; i++) {
+      props.push({key: `key${i}`, value: `value${i}`});
+    }
+
+    await createCollectionWithPropsExpectFailure({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, properties: props});
+  });
+
+  it('(!negative test!) create collection with incorrect property limit (40 kb)', async () => {
+    const props = [];
+
+    for (let i = 0; i < 32; i++) {
+      props.push({key: `key${i}`.repeat(80), value: `value${i}`.repeat(80)});
+    }
+
+    await createCollectionWithPropsExpectFailure({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, properties: props});
+  });
 });
modifiedtests/src/createItem.test.tsdiffbeforeafterboth
--- a/tests/src/createItem.test.ts
+++ b/tests/src/createItem.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 {default as usingApi} from './substrate/substrate-api';
+import {default as usingApi, executeTransaction} from './substrate/substrate-api';
 import chai from 'chai';
 import {Keyring} from '@polkadot/api';
 import {IKeyringPair} from '@polkadot/types/types';
@@ -22,6 +22,7 @@
   createCollectionExpectSuccess,
   createItemExpectSuccess,
   addCollectionAdminExpectSuccess,
+  createCollectionWithPropsExpectSuccess,
 } from './util/helpers';
 
 const expect = chai.expect;
@@ -70,6 +71,33 @@
     await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
     await createItemExpectSuccess(bob, newCollectionID, createMode);
   });
+
+  it('Set property Admin', async () => {
+    const createMode = 'NFT';
+    const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, 
+      properties: [{key: 'key1', value: 'val1'}], 
+      propPerm:   [{key: 'key1', mutable: true, collectionAdmin: true, tokenOwner: false}]});
+    
+    await createItemExpectSuccess(alice, newCollectionID, createMode);
+  });
+
+  it('Set property AdminConst', async () => {
+    const createMode = 'NFT';
+    const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, 
+      properties: [{key: 'key1', value: 'val1'}], 
+      propPerm:   [{key: 'key1', mutable: false, collectionAdmin: true, tokenOwner: false}]});
+    
+    await createItemExpectSuccess(alice, newCollectionID, createMode);
+  });
+
+  it('Set property itemOwnerOrAdmin', async () => {
+    const createMode = 'NFT';
+    const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, 
+      properties: [{key: 'key1', value: 'val1'}], 
+      propPerm:   [{key: 'key1', mutable: true, collectionAdmin: true, tokenOwner: true}]});
+    
+    await createItemExpectSuccess(alice, newCollectionID, createMode);
+  });
 });
 
 describe('Negative integration test: ext. createItem():', () => {
@@ -96,4 +124,76 @@
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
   });
+
+  it('No editing rights', async () => {
+    await usingApi(async api => {
+      const createMode = 'NFT';
+      const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, 
+        propPerm:   [{key: 'key1', mutable: false, collectionAdmin: false, tokenOwner: false}]});
+
+      const token = await createItemExpectSuccess(alice, newCollectionID, 'NFT');
+      await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(newCollectionID, token, [{key: 'key1', value: 'v2'}]), 
+      )).to.be.rejected;
+    });
+  });
+
+  it('User doesnt have editing rights', async () => {
+    await usingApi(async api => {
+      const createMode = 'NFT';
+      const newCollectionID = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'key1', mutable: true, collectionAdmin: false, tokenOwner: false}]});
+      const token = await createItemExpectSuccess(alice, newCollectionID, 'NFT');
+
+      await expect(executeTransaction(
+        api, 
+        bob, 
+        api.tx.unique.setTokenProperties(newCollectionID, token, [{key: 'key1', value: 'v2'}]), 
+      )).to.be.rejected;
+    });
+  });
+
+  it('Adding property without access rights', async () => {
+    await usingApi(async api => {
+      const createMode = 'NFT';
+      const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
+
+      const token = await createItemExpectSuccess(alice, newCollectionID, 'NFT');
+      await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
+      
+      await expect(executeTransaction(
+        api, 
+        bob, 
+        api.tx.unique.setTokenProperties(newCollectionID, token, [{key: 'key1', value: 'v2'}]), 
+      )).to.be.rejected;
+    });
+  });
+
+  it('Adding more than 64 prps', async () => {
+    await usingApi(async api => {
+      const createMode = 'NFT';
+
+      const prps = [];
+
+      for (let i = 0; i < 65; i++) {
+        prps.push({key: `key${i}`, value: `value${i}`});
+      }
+
+      const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
+      
+      await expect(executeTransaction(api, alice, api.tx.unique.setCollectionProperties(newCollectionID, prps))).to.be.rejectedWith(/common\.PropertyLimitReached/);
+    });
+  });
+
+  it('Trying to add bigger property than allowed', async () => {
+    await usingApi(async api => {
+      const createMode = 'NFT';
+      const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
+      
+      await expect(executeTransaction(api, alice, api.tx.unique.setCollectionProperties(newCollectionID, [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]))).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+    });
+  });
 });
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
before · tests/src/createMultipleItems.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {ApiPromise} from '@polkadot/api';18import {IKeyringPair} from '@polkadot/types/types';19import chai from 'chai';20import chaiAsPromised from 'chai-as-promised';21import privateKey from './substrate/privateKey';22import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';23import {24  createCollectionExpectSuccess,25  destroyCollectionExpectSuccess,26  getGenericResult,27  normalizeAccountId,28  setCollectionLimitsExpectSuccess,29  addCollectionAdminExpectSuccess,30  getBalance,31  getTokenOwner,32  getLastTokenId,33  getVariableMetadata,34  getConstMetadata,35  getCreatedCollectionCount,36} from './util/helpers';3738chai.use(chaiAsPromised);39const expect = chai.expect;4041describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => {42  it('Create  0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {43    await usingApi(async (api: ApiPromise) => {44      const collectionId = await createCollectionExpectSuccess();45      const itemsListIndexBefore = await getLastTokenId(api, collectionId);46      expect(itemsListIndexBefore).to.be.equal(0);47      const alice = privateKey('//Alice');48      const args = [{NFT: ['0x31', '0x31']}, {NFT: ['0x32', '0x32']}, {NFT: ['0x33', '0x33']}];49      const createMultipleItemsTx = api.tx.unique50        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);51      await submitTransactionAsync(alice, createMultipleItemsTx);52      const itemsListIndexAfter = await getLastTokenId(api, collectionId);53      expect(itemsListIndexAfter).to.be.equal(3);5455      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));56      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));57      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));5859      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);60      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);61      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);6263      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);64      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);65      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);66    });67  });6869  it('Create  0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {70    await usingApi(async (api: ApiPromise) => {71      const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});72      const itemsListIndexBefore = await getLastTokenId(api, collectionId);73      expect(itemsListIndexBefore).to.be.equal(0);74      const alice = privateKey('//Alice');75      const args = [76        {Fungible: {value: 1}},77        {Fungible: {value: 2}},78        {Fungible: {value: 3}},79      ];80      const createMultipleItemsTx = api.tx.unique81        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);82      await submitTransactionAsync(alice, createMultipleItemsTx);83      const token1Data = await getBalance(api, collectionId, alice.address, 0);8485      expect(token1Data).to.be.equal(6n); // 1 + 2 + 386    });87  });8889  it('Create  0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {90    await usingApi(async (api: ApiPromise) => {91      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});92      const itemsListIndexBefore = await getLastTokenId(api, collectionId);93      expect(itemsListIndexBefore).to.be.equal(0);94      const alice = privateKey('//Alice');95      const args = [96        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},97        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},98        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},99      ];100      const createMultipleItemsTx = api.tx.unique101        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);102      await submitTransactionAsync(alice, createMultipleItemsTx);103      const itemsListIndexAfter = await getLastTokenId(api, collectionId);104      expect(itemsListIndexAfter).to.be.equal(3);105106      expect(await getBalance(api, collectionId, alice.address, 1)).to.be.equal(1n);107      expect(await getBalance(api, collectionId, alice.address, 2)).to.be.equal(1n);108      expect(await getBalance(api, collectionId, alice.address, 3)).to.be.equal(1n);109110      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);111      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);112      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);113114      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);115      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);116      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);117    });118  });119120  it('Can mint amount of items equals to collection limits', async () => {121    await usingApi(async (api) => {122      const alice = privateKey('//Alice');123124      const collectionId = await createCollectionExpectSuccess();125      await setCollectionLimitsExpectSuccess(alice, collectionId, {126        tokenLimit: 2,127      });128      const args = [129        {NFT: ['A', 'A']},130        {NFT: ['B', 'B']},131      ];132      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);133      const events = await submitTransactionAsync(alice, createMultipleItemsTx);134      const result = getGenericResult(events);135      expect(result.success).to.be.true;136    });137  });138});139140describe('Integration Test createMultipleItems(collection_id, owner, items_data) with collection admin permissions:', () => {141142  let alice: IKeyringPair;143  let bob: IKeyringPair;144145  before(async () => {146    await usingApi(async () => {147      alice = privateKey('//Alice');148      bob = privateKey('//Bob');149    });150  });151152  it('Create  0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {153    await usingApi(async (api: ApiPromise) => {154      const collectionId = await createCollectionExpectSuccess();155      const itemsListIndexBefore = await getLastTokenId(api, collectionId);156      expect(itemsListIndexBefore).to.be.equal(0);157      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);158      const args = [{NFT: ['0x31', '0x31']}, {NFT: ['0x32', '0x32']}, {NFT: ['0x33', '0x33']}];159      const createMultipleItemsTx = api.tx.unique160        .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);161      await submitTransactionAsync(bob, createMultipleItemsTx);162      const itemsListIndexAfter = await getLastTokenId(api, collectionId);163      expect(itemsListIndexAfter).to.be.equal(3);164165      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(bob.address));166      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(bob.address));167      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(bob.address));168169      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);170      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);171      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);172173      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);174      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);175      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);176    });177  });178179  it('Create  0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {180    await usingApi(async (api: ApiPromise) => {181      const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});182      const itemsListIndexBefore = await getLastTokenId(api, collectionId);183      expect(itemsListIndexBefore).to.be.equal(0);184      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);185      const args = [186        {Fungible: {value: 1}},187        {Fungible: {value: 2}},188        {Fungible: {value: 3}},189      ];190      const createMultipleItemsTx = api.tx.unique191        .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);192      await submitTransactionAsync(bob, createMultipleItemsTx);193      const token1Data = await getBalance(api, collectionId, bob.address, 0);194195      expect(token1Data).to.be.equal(6n); // 1 + 2 + 3196    });197  });198199  it('Create  0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {200    await usingApi(async (api: ApiPromise) => {201      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});202      const itemsListIndexBefore = await getLastTokenId(api, collectionId);203      expect(itemsListIndexBefore).to.be.equal(0);204      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);205      const args = [206        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},207        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},208        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},209      ];210      const createMultipleItemsTx = api.tx.unique211        .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);212      await submitTransactionAsync(bob, createMultipleItemsTx);213      const itemsListIndexAfter = await getLastTokenId(api, collectionId);214      expect(itemsListIndexAfter).to.be.equal(3);215216      expect(await getBalance(api, collectionId, bob.address, 1)).to.be.equal(1n);217      expect(await getBalance(api, collectionId, bob.address, 2)).to.be.equal(1n);218      expect(await getBalance(api, collectionId, bob.address, 3)).to.be.equal(1n);219220      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);221      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);222      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);223224      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);225      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);226      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);227    });228  });229});230231describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => {232233  let alice: IKeyringPair;234  let bob: IKeyringPair;235236  before(async () => {237    await usingApi(async () => {238      alice = privateKey('//Alice');239      bob = privateKey('//Bob');240    });241  });242243  it('Regular user cannot create items in active NFT collection', async () => {244    await usingApi(async (api: ApiPromise) => {245      const collectionId = await createCollectionExpectSuccess();246      const itemsListIndexBefore = await getLastTokenId(api, collectionId);247      expect(itemsListIndexBefore).to.be.equal(0);248      const args = [{NFT: ['0x31', '0x31']}, {NFT: ['0x32', '0x32']}, {NFT: ['0x33', '0x33']}];249      const createMultipleItemsTx = api.tx.unique250        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);251      await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;252    });253  });254255  it('Regular user cannot create items in active Fungible collection', async () => {256    await usingApi(async (api: ApiPromise) => {257      const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});258      const itemsListIndexBefore = await getLastTokenId(api, collectionId);259      expect(itemsListIndexBefore).to.be.equal(0);260      const args = [261        {Fungible: {value: 1}},262        {Fungible: {value: 2}},263        {Fungible: {value: 3}},264      ];265      const createMultipleItemsTx = api.tx.unique266        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);267      await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;268    });269  });270271  it('Regular user cannot create items in active ReFungible collection', async () => {272    await usingApi(async (api: ApiPromise) => {273      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});274      const itemsListIndexBefore = await getLastTokenId(api, collectionId);275      expect(itemsListIndexBefore).to.be.equal(0);276      const args = [277        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},278        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},279        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},280      ];281      const createMultipleItemsTx = api.tx.unique282        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);283      await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;284    });285  });286287  it('Create token in not existing collection', async () => {288    await usingApi(async (api: ApiPromise) => {289      const collectionId = await getCreatedCollectionCount(api) + 1;290      const createMultipleItemsTx = api.tx.unique291        .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'NFT', 'NFT']);292      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;293    });294  });295296  it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {297    await usingApi(async (api: ApiPromise) => {298      // NFT299      const collectionId = await createCollectionExpectSuccess();300      const alice = privateKey('//Alice');301      const args = [302        {NFT: ['A'.repeat(2049), 'A'.repeat(2049)]},303        {NFT: ['B'.repeat(2049), 'B'.repeat(2049)]},304        {NFT: ['C'.repeat(2049), 'C'.repeat(2049)]},305      ];306      const createMultipleItemsTx = api.tx.unique307        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);308      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;309310      // ReFungible311      const collectionIdReFungible =312        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});313      const argsReFungible = [314        {ReFungible: ['1'.repeat(2049), '1'.repeat(2049), 10]},315        {ReFungible: ['2'.repeat(2049), '2'.repeat(2049), 10]},316        {ReFungible: ['3'.repeat(2049), '3'.repeat(2049), 10]},317      ];318      const createMultipleItemsTxFungible = api.tx.unique319        .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);320      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;321    });322  });323324  it('Create tokens with different types', async () => {325    await usingApi(async (api: ApiPromise) => {326      const collectionId = await createCollectionExpectSuccess();327      const createMultipleItemsTx = api.tx.unique328        .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'Fungible', 'ReFungible']);329      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;330      // garbage collection :-D331      await destroyCollectionExpectSuccess(collectionId);332    });333  });334335  it('Create tokens with different data limits <> maximum data limit', async () => {336    await usingApi(async (api: ApiPromise) => {337      const collectionId = await createCollectionExpectSuccess();338      const args = [339        {NFT: ['A', 'A']},340        {NFT: ['B', 'B'.repeat(2049)]},341        {NFT: ['C'.repeat(2049), 'C']},342      ];343      const createMultipleItemsTx = await api.tx.unique344        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);345      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;346    });347  });348349  it('Fails when minting tokens exceeds collectionLimits amount', async () => {350    await usingApi(async (api) => {351352      const collectionId = await createCollectionExpectSuccess();353      await setCollectionLimitsExpectSuccess(alice, collectionId, {354        tokenLimit: 1,355      });356      const args = [357        {NFT: ['A', 'A']},358        {NFT: ['B', 'B']},359      ];360      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);361      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;362    });363  });364});
after · tests/src/createMultipleItems.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {ApiPromise} from '@polkadot/api';18import {IKeyringPair} from '@polkadot/types/types';19import chai from 'chai';20import chaiAsPromised from 'chai-as-promised';21import privateKey from './substrate/privateKey';22import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync, executeTransaction} from './substrate/substrate-api';23import {24  createCollectionExpectSuccess,25  destroyCollectionExpectSuccess,26  getGenericResult,27  normalizeAccountId,28  setCollectionLimitsExpectSuccess,29  addCollectionAdminExpectSuccess,30  getBalance,31  getTokenOwner,32  getLastTokenId,33  getVariableMetadata,34  getConstMetadata,35  getCreatedCollectionCount,36  createCollectionWithPropsExpectSuccess,37  getCreateItemsResult,38} from './util/helpers';3940chai.use(chaiAsPromised);41const expect = chai.expect;4243describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => {44  it('Create  0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {45    await usingApi(async (api: ApiPromise) => {46      const collectionId = await createCollectionExpectSuccess();47      const itemsListIndexBefore = await getLastTokenId(api, collectionId);48      expect(itemsListIndexBefore).to.be.equal(0);49      const alice = privateKey('//Alice');50      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},51        {Nft: {const_data: '0x32', variable_data: '0x32'}},52        {Nft: {const_data: '0x33', variable_data: '0x33'}}];53      const createMultipleItemsTx = api.tx.unique54        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);55      await submitTransactionAsync(alice, createMultipleItemsTx);56      const itemsListIndexAfter = await getLastTokenId(api, collectionId);57      expect(itemsListIndexAfter).to.be.equal(3);5859      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));60      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));61      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));6263      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);64      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);65      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);6667      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);68      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);69      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);70    });71  });7273  it('Create  0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {74    await usingApi(async (api: ApiPromise) => {75      const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});76      const itemsListIndexBefore = await getLastTokenId(api, collectionId);77      expect(itemsListIndexBefore).to.be.equal(0);78      const alice = privateKey('//Alice');79      const args = [80        {Fungible: {value: 1}},81        {Fungible: {value: 2}},82        {Fungible: {value: 3}},83      ];84      const createMultipleItemsTx = api.tx.unique85        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);86      await submitTransactionAsync(alice, createMultipleItemsTx);87      const token1Data = await getBalance(api, collectionId, alice.address, 0);8889      expect(token1Data).to.be.equal(6n); // 1 + 2 + 390    });91  });9293  it('Create  0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {94    await usingApi(async (api: ApiPromise) => {95      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});96      const itemsListIndexBefore = await getLastTokenId(api, collectionId);97      expect(itemsListIndexBefore).to.be.equal(0);98      const alice = privateKey('//Alice');99      const args = [100        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},101        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},102        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},103      ];104      const createMultipleItemsTx = api.tx.unique105        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);106      await submitTransactionAsync(alice, createMultipleItemsTx);107      const itemsListIndexAfter = await getLastTokenId(api, collectionId);108      expect(itemsListIndexAfter).to.be.equal(3);109110      expect(await getBalance(api, collectionId, alice.address, 1)).to.be.equal(1n);111      expect(await getBalance(api, collectionId, alice.address, 2)).to.be.equal(1n);112      expect(await getBalance(api, collectionId, alice.address, 3)).to.be.equal(1n);113114      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);115      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);116      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);117118      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);119      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);120      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);121    });122  });123124  it('Can mint amount of items equals to collection limits', async () => {125    await usingApi(async (api) => {126      const alice = privateKey('//Alice');127128      const collectionId = await createCollectionExpectSuccess();129      await setCollectionLimitsExpectSuccess(alice, collectionId, {130        tokenLimit: 2,131      });132      const args = [133        {NFT: ['A', 'A']},134        {NFT: ['B', 'B']},135      ];136      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);137      const events = await submitTransactionAsync(alice, createMultipleItemsTx);138      const result = getGenericResult(events);139      expect(result.success).to.be.true;140    });141  });142143  it('Create  0x31, 0x32, 0x33 items in active NFT with property Admin', async () => {144    await usingApi(async (api: ApiPromise) => {145      const collectionId = await createCollectionExpectSuccess();146      const itemsListIndexBefore = await getLastTokenId(api, collectionId);147      expect(itemsListIndexBefore).to.be.equal(0);148      const alice = privateKey('//Alice');149      const bob = privateKey('//Bob');150      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},151        {Nft: {const_data: '0x32', variable_data: '0x32'}},152        {Nft: {const_data: '0x33', variable_data: '0x33'}}];153      const createMultipleItemsTx = api.tx.unique154        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);155      await submitTransactionAsync(alice, createMultipleItemsTx);156      const itemsListIndexAfter = await getLastTokenId(api, collectionId);157      expect(itemsListIndexAfter).to.be.equal(3);158159      await expect(executeTransaction(160        api, 161        alice, 162        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]), 163      )).to.not.be.rejected;164165      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));166      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));167      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));168169      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);170      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);171      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);172173      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);174      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);175      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);176    });177  });178179  it('Create  0x31, 0x32, 0x33 items in active NFT with property AdminConst', async () => {180    await usingApi(async (api: ApiPromise) => {181      const collectionId = await createCollectionExpectSuccess();182      const itemsListIndexBefore = await getLastTokenId(api, collectionId);183      expect(itemsListIndexBefore).to.be.equal(0);184      const alice = privateKey('//Alice');185      const bob = privateKey('//Bob');186      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},187        {Nft: {const_data: '0x32', variable_data: '0x32'}},188        {Nft: {const_data: '0x33', variable_data: '0x33'}}];189      const createMultipleItemsTx = api.tx.unique190        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);191      await submitTransactionAsync(alice, createMultipleItemsTx);192      const itemsListIndexAfter = await getLastTokenId(api, collectionId);193      expect(itemsListIndexAfter).to.be.equal(3);194195      await expect(executeTransaction(196        api, 197        alice, 198        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]), 199      )).to.not.be.rejected;200201      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));202      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));203      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));204205      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);206      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);207      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);208209      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);210      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);211      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);212    });213  });214215  it('Create  0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async () => {216    await usingApi(async (api: ApiPromise) => {217      const collectionId = await createCollectionExpectSuccess();218      const itemsListIndexBefore = await getLastTokenId(api, collectionId);219      expect(itemsListIndexBefore).to.be.equal(0);220      const alice = privateKey('//Alice');221      const bob = privateKey('//Bob');222      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},223        {Nft: {const_data: '0x32', variable_data: '0x32'}},224        {Nft: {const_data: '0x33', variable_data: '0x33'}}];225      const createMultipleItemsTx = api.tx.unique226        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);227      await submitTransactionAsync(alice, createMultipleItemsTx);228      const itemsListIndexAfter = await getLastTokenId(api, collectionId);229      expect(itemsListIndexAfter).to.be.equal(3);230231      await expect(executeTransaction(232        api, 233        alice, 234        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]), 235      )).to.not.be.rejected;236237      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));238      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address));239      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address));240241      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);242      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);243      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);244245      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);246      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);247      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);248    });249  });250});251252describe('Integration Test createMultipleItems(collection_id, owner, items_data) with collection admin permissions:', () => {253254  let alice: IKeyringPair;255  let bob: IKeyringPair;256257  before(async () => {258    await usingApi(async () => {259      alice = privateKey('//Alice');260      bob = privateKey('//Bob');261    });262  });263264  it('Create  0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {265    await usingApi(async (api: ApiPromise) => {266      const collectionId = await createCollectionExpectSuccess();267      const itemsListIndexBefore = await getLastTokenId(api, collectionId);268      expect(itemsListIndexBefore).to.be.equal(0);269      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);270      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},271        {Nft: {const_data: '0x32', variable_data: '0x32'}},272        {Nft: {const_data: '0x33', variable_data: '0x33'}}];273      const createMultipleItemsTx = api.tx.unique274        .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);275      await submitTransactionAsync(bob, createMultipleItemsTx);276      const itemsListIndexAfter = await getLastTokenId(api, collectionId);277      expect(itemsListIndexAfter).to.be.equal(3);278279      expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(bob.address));280      expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(bob.address));281      expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(bob.address));282283      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);284      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);285      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);286287      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);288      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);289      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);290    });291  });292293  it('Create  0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => {294    await usingApi(async (api: ApiPromise) => {295      const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});296      const itemsListIndexBefore = await getLastTokenId(api, collectionId);297      expect(itemsListIndexBefore).to.be.equal(0);298      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);299      const args = [300        {Fungible: {value: 1}},301        {Fungible: {value: 2}},302        {Fungible: {value: 3}},303      ];304      const createMultipleItemsTx = api.tx.unique305        .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);306      await submitTransactionAsync(bob, createMultipleItemsTx);307      const token1Data = await getBalance(api, collectionId, bob.address, 0);308309      expect(token1Data).to.be.equal(6n); // 1 + 2 + 3310    });311  });312313  it('Create  0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {314    await usingApi(async (api: ApiPromise) => {315      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});316      const itemsListIndexBefore = await getLastTokenId(api, collectionId);317      expect(itemsListIndexBefore).to.be.equal(0);318      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);319      const args = [320        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},321        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},322        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},323      ];324      const createMultipleItemsTx = api.tx.unique325        .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);326      await submitTransactionAsync(bob, createMultipleItemsTx);327      const itemsListIndexAfter = await getLastTokenId(api, collectionId);328      expect(itemsListIndexAfter).to.be.equal(3);329330      expect(await getBalance(api, collectionId, bob.address, 1)).to.be.equal(1n);331      expect(await getBalance(api, collectionId, bob.address, 2)).to.be.equal(1n);332      expect(await getBalance(api, collectionId, bob.address, 3)).to.be.equal(1n);333334      expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);335      expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);336      expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);337338      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);339      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);340      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);341    });342  });343});344345describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => {346347  let alice: IKeyringPair;348  let bob: IKeyringPair;349350  before(async () => {351    await usingApi(async () => {352      alice = privateKey('//Alice');353      bob = privateKey('//Bob');354    });355  });356357  it('Regular user cannot create items in active NFT collection', async () => {358    await usingApi(async (api: ApiPromise) => {359      const collectionId = await createCollectionExpectSuccess();360      const itemsListIndexBefore = await getLastTokenId(api, collectionId);361      expect(itemsListIndexBefore).to.be.equal(0);362      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},363        {Nft: {const_data: '0x32', variable_data: '0x32'}},364        {Nft: {const_data: '0x33', variable_data: '0x33'}}];365      const createMultipleItemsTx = api.tx.unique366        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);367      await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;368    });369  });370371  it('Regular user cannot create items in active Fungible collection', async () => {372    await usingApi(async (api: ApiPromise) => {373      const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});374      const itemsListIndexBefore = await getLastTokenId(api, collectionId);375      expect(itemsListIndexBefore).to.be.equal(0);376      const args = [377        {Fungible: {value: 1}},378        {Fungible: {value: 2}},379        {Fungible: {value: 3}},380      ];381      const createMultipleItemsTx = api.tx.unique382        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);383      await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;384    });385  });386387  it('Regular user cannot create items in active ReFungible collection', async () => {388    await usingApi(async (api: ApiPromise) => {389      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});390      const itemsListIndexBefore = await getLastTokenId(api, collectionId);391      expect(itemsListIndexBefore).to.be.equal(0);392      const args = [393        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},394        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},395        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},396      ];397      const createMultipleItemsTx = api.tx.unique398        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);399      await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;400    });401  });402403  it('Create token in not existing collection', async () => {404    await usingApi(async (api: ApiPromise) => {405      const collectionId = await getCreatedCollectionCount(api) + 1;406      const createMultipleItemsTx = api.tx.unique407        .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'NFT', 'NFT']);408      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;409    });410  });411412  it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {413    await usingApi(async (api: ApiPromise) => {414      // NFT415      const collectionId = await createCollectionExpectSuccess();416      const alice = privateKey('//Alice');417      const args = [418        {NFT: ['A'.repeat(2049), 'A'.repeat(2049)]},419        {NFT: ['B'.repeat(2049), 'B'.repeat(2049)]},420        {NFT: ['C'.repeat(2049), 'C'.repeat(2049)]},421      ];422      const createMultipleItemsTx = api.tx.unique423        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);424      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;425426      // ReFungible427      const collectionIdReFungible =428        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});429      const argsReFungible = [430        {ReFungible: ['1'.repeat(2049), '1'.repeat(2049), 10]},431        {ReFungible: ['2'.repeat(2049), '2'.repeat(2049), 10]},432        {ReFungible: ['3'.repeat(2049), '3'.repeat(2049), 10]},433      ];434      const createMultipleItemsTxFungible = api.tx.unique435        .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);436      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;437    });438  });439440  it('Create tokens with different types', async () => {441    await usingApi(async (api: ApiPromise) => {442      const collectionId = await createCollectionExpectSuccess();443      const createMultipleItemsTx = api.tx.unique444        .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'Fungible', 'ReFungible']);445      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;446      // garbage collection :-D447      await destroyCollectionExpectSuccess(collectionId);448    });449  });450451  it('Create tokens with different data limits <> maximum data limit', async () => {452    await usingApi(async (api: ApiPromise) => {453      const collectionId = await createCollectionExpectSuccess();454      const args = [455        {NFT: ['A', 'A']},456        {NFT: ['B', 'B'.repeat(2049)]},457        {NFT: ['C'.repeat(2049), 'C']},458      ];459      const createMultipleItemsTx = await api.tx.unique460        .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);461      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;462    });463  });464465  it('Fails when minting tokens exceeds collectionLimits amount', async () => {466    await usingApi(async (api) => {467468      const collectionId = await createCollectionExpectSuccess();469      await setCollectionLimitsExpectSuccess(alice, collectionId, {470        tokenLimit: 1,471      });472      const args = [473        {NFT: ['A', 'A']},474        {NFT: ['B', 'B']},475      ];476      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);477      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;478    });479  });480481  it('No editing rights', async () => {482    await usingApi(async (api: ApiPromise) => {483      const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],484        propPerm:   [{key: 'key1', mutable: true, collectionAdmin: false, tokenOwner: false}]});485      const itemsListIndexBefore = await getLastTokenId(api, collectionId);486      expect(itemsListIndexBefore).to.be.equal(0);487      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);488      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},489        {Nft: {const_data: '0x32', variable_data: '0x32'}},490        {Nft: {const_data: '0x33', variable_data: '0x33'}}];491      492      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);493494      const events = await submitTransactionAsync(alice, createMultipleItemsTx);495      const result = getCreateItemsResult(events);496497      for (const elem of result) {498        await expect(executeTransaction(499          api, 500          bob, 501          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 502        )).to.be.rejected;503      }504505      // await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;506    });507  });508509  it('User doesnt have editing rights', async () => {510    await usingApi(async (api: ApiPromise) => {511      const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],512        propPerm:   [{key: 'key1', mutable: false, collectionAdmin: false, tokenOwner: false}]});513      const itemsListIndexBefore = await getLastTokenId(api, collectionId);514      expect(itemsListIndexBefore).to.be.equal(0);515      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);516      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},517        {Nft: {const_data: '0x32', variable_data: '0x32'}},518        {Nft: {const_data: '0x33', variable_data: '0x33'}}];519      520      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);521522      const events = await submitTransactionAsync(alice, createMultipleItemsTx);523      const result = getCreateItemsResult(events);524525      for (const elem of result) {526        await expect(executeTransaction(527          api, 528          bob, 529          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 530        )).to.be.rejected;531      }532    });533  });534535  it('Adding property without access rights', async () => {536    await usingApi(async (api: ApiPromise) => {537      const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}]});538      const itemsListIndexBefore = await getLastTokenId(api, collectionId);539      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);540      expect(itemsListIndexBefore).to.be.equal(0);541      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},542        {Nft: {const_data: '0x32', variable_data: '0x32'}},543        {Nft: {const_data: '0x33', variable_data: '0x33'}}];544      545      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);546547      const events = await submitTransactionAsync(alice, createMultipleItemsTx);548      const result = getCreateItemsResult(events);549550      for (const elem of result) {551        await expect(executeTransaction(552          api, 553          bob, 554          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 555        )).to.be.rejected;556      }557    });558  });559560  it('Adding more than 64 prps', async () => {561    await usingApi(async (api: ApiPromise) => {562      const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],563        propPerm:   [{key: 'key1', mutable: true, collectionAdmin: true, tokenOwner: false}]});564      const itemsListIndexBefore = await getLastTokenId(api, collectionId);565      expect(itemsListIndexBefore).to.be.equal(0);566      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);567568      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},569        {Nft: {const_data: '0x32', variable_data: '0x32'}},570        {Nft: {const_data: '0x33', variable_data: '0x33'}}];571      572      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);573      const events = await submitTransactionAsync(alice, createMultipleItemsTx);574575      const result = getCreateItemsResult(events);576      577      const prps = [];578      579      for (let i = 0; i < 65; i++) {580        prps.push({key: `key${i}`, value: `value${i}`});581      }582583      await expect(executeTransaction(api, bob, api.tx.unique.setCollectionProperties(collectionId, prps))).to.be.rejectedWith(/common\.PropertyLimitReached/);584      585      for (const elem of result) {586        await expect(executeTransaction(587          api, 588          bob, 589          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps), 590        )).to.be.rejected;591      }592    });593  });594595  it('Trying to add bigger property than allowed', async () => {596    await usingApi(async (api: ApiPromise) => {597      const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],598        propPerm:   [{key: 'key1', mutable: true, collectionAdmin: false, tokenOwner: false}]});599      const itemsListIndexBefore = await getLastTokenId(api, collectionId);600      expect(itemsListIndexBefore).to.be.equal(0);601      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},602        {Nft: {const_data: '0x32', variable_data: '0x32'}},603        {Nft: {const_data: '0x33', variable_data: '0x33'}}];604      605      const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);606607      const events = await submitTransactionAsync(alice, createMultipleItemsTx);608      const result = getCreateItemsResult(events);609610611      await expect(executeTransaction(api, alice, api.tx.unique.setCollectionProperties(collectionId, [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]))).to.be.rejectedWith(/common\.NoSpaceForProperty/);612613      for (const elem of result) {614        await expect(executeTransaction(615          api, 616          bob, 617          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]), 618        )).to.be.rejected;619      }620    });621  });622});
modifiedtests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItemsEx.test.ts
+++ b/tests/src/createMultipleItemsEx.test.ts
@@ -16,8 +16,8 @@
 
 import {expect} from 'chai';
 import privateKey from './substrate/privateKey';
-import usingApi, {executeTransaction} from './substrate/substrate-api';
-import {createCollectionExpectSuccess} from './util/helpers';
+import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api';
+import {createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, addCollectionAdminExpectSuccess, getCreateItemsResult} from './util/helpers';
 
 describe('createMultipleItemsEx', () => {
   it('can initialize multiple NFT with different owners', async () => {
@@ -51,6 +51,362 @@
     });
   });
 
+  it('createMultipleItemsEx with property Admin', async () => {
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+          constData: '0x0000',
+          variableData: '0x1111',
+        }, {
+          owner: {substrate: bob.address},
+          constData: '0x2222',
+          variableData: '0x3333',
+        }, {
+          owner: {substrate: charlie.address},
+          constData: '0x4444',
+          variableData: '0x5555',
+        },
+      ];
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]), 
+      )).to.not.be.rejected;
+
+      await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
+        NFT: data,
+      }));
+      const tokens = await api.query.nonfungible.tokenData.entries(collection);
+      const json = tokens.map(([, token]) => token.toJSON());
+      expect(json).to.be.deep.equal(data);
+    });
+  });
+
+  it('createMultipleItemsEx with property AdminConst', async () => {
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+          constData: '0x0000',
+          variableData: '0x1111',
+        }, {
+          owner: {substrate: bob.address},
+          constData: '0x2222',
+          variableData: '0x3333',
+        }, {
+          owner: {substrate: charlie.address},
+          constData: '0x4444',
+          variableData: '0x5555',
+        },
+      ];
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]), 
+      )).to.not.be.rejected;
+
+      await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
+        NFT: data,
+      }));
+      
+
+      const tokens = await api.query.nonfungible.tokenData.entries(collection);
+      const json = tokens.map(([, token]) => token.toJSON());
+      expect(json).to.be.deep.equal(data);
+    });
+  });
+
+  it('createMultipleItemsEx with property itemOwnerOrAdmin', async () => {
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+          constData: '0x0000',
+          variableData: '0x1111',
+        }, {
+          owner: {substrate: bob.address},
+          constData: '0x2222',
+          variableData: '0x3333',
+        }, {
+          owner: {substrate: charlie.address},
+          constData: '0x4444',
+          variableData: '0x5555',
+        },
+      ];
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]), 
+      )).to.not.be.rejected;
+
+      await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
+        NFT: data,
+      }));
+      
+
+      const tokens = await api.query.nonfungible.tokenData.entries(collection);
+      const json = tokens.map(([, token]) => token.toJSON());
+      expect(json).to.be.deep.equal(data);
+    });
+  });
+
+  it('No editing rights', async () => {
+    const collection = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],
+      propPerm:   [{key: 'key1', mutable: true, collectionAdmin: false, tokenOwner: false}]});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+        }, {
+          owner: {substrate: bob.address},
+        }, {
+          owner: {substrate: charlie.address},
+        },
+      ];
+
+      const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
+      await executeTransaction(api, alice, tx);
+      
+      const events = await submitTransactionAsync(alice, tx);
+      const result = getCreateItemsResult(events);
+      
+      for (const elem of result) {
+        await expect(executeTransaction(
+          api, 
+          bob, 
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+        )).to.be.rejected;
+      }
+    });
+  });
+
+  it('User doesnt have editing rights', async () => {
+    const collection = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}],
+      propPerm:   [{key: 'key1', mutable: false, collectionAdmin: false, tokenOwner: false}]});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+        }, {
+          owner: {substrate: bob.address},
+        }, {
+          owner: {substrate: charlie.address},
+        },
+      ];
+
+      const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
+      await executeTransaction(api, alice, tx);
+      
+      const events = await submitTransactionAsync(alice, tx);
+      const result = getCreateItemsResult(events);
+      
+      for (const elem of result) {
+        await expect(executeTransaction(
+          api, 
+          bob, 
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+        )).to.be.rejected;
+      }
+    });
+  });
+
+  it('Adding property without access rights', async () => {
+    const collection = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}]});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+        }, {
+          owner: {substrate: bob.address},
+        }, {
+          owner: {substrate: charlie.address},
+        },
+      ];
+
+      const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
+      await executeTransaction(api, alice, tx);
+      
+      const events = await submitTransactionAsync(alice, tx);
+      const result = getCreateItemsResult(events);
+      
+      for (const elem of result) {
+        await expect(executeTransaction(
+          api, 
+          bob, 
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+        )).to.be.rejected;
+      }
+    });
+  });
+
+  it('Adding more than 64 prps', async () => {
+    const collection = await createCollectionWithPropsExpectSuccess();
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+        }, {
+          owner: {substrate: bob.address},
+        }, {
+          owner: {substrate: charlie.address},
+        },
+      ];
+
+      const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
+      await executeTransaction(api, alice, tx);
+      
+      const events = await submitTransactionAsync(alice, tx);
+      const result = getCreateItemsResult(events);
+
+      const prps = [];
+      
+      for (let i = 0; i < 65; i++) {
+        prps.push({key: `key${i}`, value: `value${i}`});
+      }
+
+      await expect(executeTransaction(api, bob, api.tx.unique.setCollectionProperties(collection, prps))).to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+      
+      for (const elem of result) {
+        await expect(executeTransaction(
+          api, 
+          bob, 
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps), 
+        )).to.be.rejected;
+      }
+    });
+  });
+
+  it('Trying to add bigger property than allowed', async () => {
+    const collection = await createCollectionWithPropsExpectSuccess();
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+        }, {
+          owner: {substrate: bob.address},
+        }, {
+          owner: {substrate: charlie.address},
+        },
+      ];
+
+      const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
+      await executeTransaction(api, alice, tx);
+      
+      const events = await submitTransactionAsync(alice, tx);
+      const result = getCreateItemsResult(events);
+
+      const prps = [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}];
+
+      await expect(executeTransaction(api, bob, api.tx.unique.setCollectionProperties(collection, prps))).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+      
+      for (const elem of result) {
+        await expect(executeTransaction(
+          api, 
+          bob, 
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps), 
+        )).to.be.rejected;
+      }
+    });
+  });
+
+  it('can initialize multiple NFT with different owners', async () => {
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+          constData: '0x0000',
+          variableData: '0x1111',
+        }, {
+          owner: {substrate: bob.address},
+          constData: '0x2222',
+          variableData: '0x3333',
+        }, {
+          owner: {substrate: charlie.address},
+          constData: '0x4444',
+          variableData: '0x5555',
+        },
+      ];
+
+      await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
+        NFT: data,
+      }));
+      const tokens = await api.query.nonfungible.tokenData.entries(collection);
+      const json = tokens.map(([, token]) => token.toJSON());
+      expect(json).to.be.deep.equal(data);
+    });
+  });
+
+  it('can initialize multiple NFT with different owners', async () => {
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const alice = privateKey('//Alice');
+    const bob = privateKey('//Bob');
+    const charlie = privateKey('//Charlie');
+    await usingApi(async (api) => {
+      const data = [
+        {
+          owner: {substrate: alice.address},
+          constData: '0x0000',
+          variableData: '0x1111',
+        }, {
+          owner: {substrate: bob.address},
+          constData: '0x2222',
+          variableData: '0x3333',
+        }, {
+          owner: {substrate: charlie.address},
+          constData: '0x4444',
+          variableData: '0x5555',
+        },
+      ];
+
+      await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
+        NFT: data,
+      }));
+      const tokens = await api.query.nonfungible.tokenData.entries(collection);
+      const json = tokens.map(([, token]) => token.toJSON());
+      expect(json).to.be.deep.equal(data);
+    });
+  });
+
   it('fails when trying to set multiple owners when creating multiple refungibles', async () => {
     const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const alice = privateKey('//Alice');
@@ -72,3 +428,4 @@
     });
   });
 });
+'';
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -201,6 +201,37 @@
   return result;
 }
 
+export function getCreateItemsResult(events: EventRecord[]): CreateItemResult[] {
+  let success = false;
+  let collectionId = 0;
+  let itemId = 0;
+  let recipient;
+
+  const results : CreateItemResult[]  = [];
+
+  events.forEach(({event: {data, method, section}}) => {
+    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);
+    if (method == 'ExtrinsicSuccess') {
+      success = true;
+    } else if ((section == 'common') && (method == 'ItemCreated')) {
+      collectionId = parseInt(data[0].toString(), 10);
+      itemId = parseInt(data[1].toString(), 10);
+      recipient = normalizeAccountId(data[2].toJSON() as any);
+
+      const itemRes: CreateItemResult = {
+        success,
+        collectionId,
+        itemId,
+        recipient,
+      };
+
+      results.push(itemRes);
+    }
+  });
+
+  return results;
+}
+
 export function getCreateItemResult(events: EventRecord[]): CreateItemResult {
   let success = false;
   let collectionId = 0;
@@ -263,12 +294,26 @@
 
 type CollectionMode = Nft | Fungible | ReFungible;
 
+export type Property = {
+  key: any,
+  value: any,
+};
+
+type PropertyPermission = {
+  key: any,
+  mutable: boolean;
+  collectionAdmin: boolean;
+  tokenOwner: boolean;
+}
+
 export type CreateCollectionParams = {
   mode: CollectionMode,
   name: string,
   description: string,
   tokenPrefix: string,
   schemaVersion: string,
+  properties?: Array<Property>,
+  propPerm?: Array<PropertyPermission>
 };
 
 const defaultCreateCollectionParams: CreateCollectionParams = {
@@ -333,6 +378,86 @@
   return collectionId;
 }
 
+export async function createCollectionWithPropsExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {
+  const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
+
+  let collectionId = 0;
+  await usingApi(async (api) => {
+    // Get number of collections before the transaction
+    const collectionCountBefore = await getCreatedCollectionCount(api);
+
+    // Run the CreateCollection transaction
+    const alicePrivateKey = privateKey('//Alice');
+
+    let modeprm = {};
+    if (mode.type === 'NFT') {
+      modeprm = {nft: null};
+    } else if (mode.type === 'Fungible') {
+      modeprm = {fungible: mode.decimalPoints};
+    } else if (mode.type === 'ReFungible') {
+      modeprm = {refungible: null};
+    }
+
+    const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});
+    const events = await submitTransactionAsync(alicePrivateKey, tx);
+    const result = getCreateCollectionResult(events);
+
+    // Get number of collections after the transaction
+    const collectionCountAfter = await getCreatedCollectionCount(api);
+
+    // Get the collection
+    const collection = await queryCollectionExpectSuccess(api, result.collectionId);
+
+    // What to expect
+    // tslint:disable-next-line:no-unused-expression
+    expect(result.success).to.be.true;
+    expect(result.collectionId).to.be.equal(collectionCountAfter);
+    // tslint:disable-next-line:no-unused-expression
+    expect(collection).to.be.not.null;
+    expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');
+    expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicesPublicKey));
+    expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);
+    expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);
+    expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);
+
+
+    collectionId = result.collectionId;
+  });
+
+  return collectionId;
+}
+
+export async function createCollectionWithPropsExpectFailure(params: Partial<CreateCollectionParams> = {}) {
+  const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
+
+  const collectionId = 0;
+  await usingApi(async (api) => {
+    // Get number of collections before the transaction
+    const collectionCountBefore = await getCreatedCollectionCount(api);
+
+    // Run the CreateCollection transaction
+    const alicePrivateKey = privateKey('//Alice');
+
+    let modeprm = {};
+    if (mode.type === 'NFT') {
+      modeprm = {nft: null};
+    } else if (mode.type === 'Fungible') {
+      modeprm = {fungible: mode.decimalPoints};
+    } else if (mode.type === 'ReFungible') {
+      modeprm = {refungible: null};
+    }
+
+    const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});
+    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
+
+
+    // Get number of collections after the transaction
+    const collectionCountAfter = await getCreatedCollectionCount(api);
+
+    expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');
+  });
+}
+
 export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {
   const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};