git.delta.rocks / unique-network / refs/commits / 80dcadd1d3b4

difftreelog

Merge pull request #567 from UniqueNetwork/test/playground-migration

ut-akuznetsov2022-09-12parents: #e4516e4 #5401624.patch.diff
in: master
Test/playground migration

5 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -49,6 +49,7 @@
     "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",
     "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts",
     "testRemoveFromAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromAllowList.test.ts",
+    "testAllowLists": "mocha --timeout 9999999 -r ts-node/register ./**/allowLists.test.ts",
     "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",
     "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts",
     "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts",
modifiedtests/src/adminTransferAndBurn.test.tsdiffbeforeafterboth
--- a/tests/src/adminTransferAndBurn.test.ts
+++ b/tests/src/adminTransferAndBurn.test.ts
@@ -17,56 +17,63 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
-import {default as usingApi} from './substrate/substrate-api';
-import {
-  createCollectionExpectSuccess,
-  createItemExpectSuccess,
-  transferExpectFailure,
-  transferFromExpectSuccess,
-  burnItemExpectFailure,
-  burnFromExpectSuccess,
-  setCollectionLimitsExpectSuccess,
-} from './util/helpers';
+import {usingPlaygrounds} from './util/playgrounds';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
 
+let donor: IKeyringPair;
+
+before(async () => {
+  await usingPlaygrounds(async (_, privateKey) => {
+    donor = privateKey('//Alice');
+  });
+});
+
 describe('Integration Test: ownerCanTransfer allows admins to use only transferFrom/burnFrom:', () => {
   let alice: IKeyringPair;
   let bob: IKeyringPair;
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice = privateKeyWrapper('//Alice');
-      bob = privateKeyWrapper('//Bob');
-      charlie = privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor);
     });
   });
 
   it('admin transfers other user\'s token', async () => {
-    await usingApi(async () => {
-      const collectionId = await createCollectionExpectSuccess();
-      await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
-
-      const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Substrate: bob.address});
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
+      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+      const limits = await helper.collection.getEffectiveLimits(collectionId);
+      expect(limits.ownerCanTransfer).to.be.true;
 
-      await transferExpectFailure(collectionId, tokenId, alice, charlie);
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(transferResult()).to.be.rejected;
 
-      await transferFromExpectSuccess(collectionId, tokenId, alice, bob, charlie, 1);
+      await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address});
+      const newTokenOwner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(newTokenOwner.Substrate).to.be.equal(charlie.address);
     });
   });
 
   it('admin burns other user\'s token', async () => {
-    await usingApi(async () => {
-      const collectionId = await createCollectionExpectSuccess();
-      await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'});
+
+      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+      const limits = await helper.collection.getEffectiveLimits(collectionId);
+      expect(limits.ownerCanTransfer).to.be.true;
 
-      const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Substrate: bob.address});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      const burnTxFailed = async () => helper.nft.burnToken(alice, collectionId, tokenId);
 
-      await burnItemExpectFailure(alice, collectionId, tokenId);
+      await expect(burnTxFailed()).to.be.rejected;
 
-      await burnFromExpectSuccess(alice, bob, collectionId, tokenId);
+      await helper.nft.burnToken(bob, collectionId, tokenId);
+      const token = await helper.nft.getToken(collectionId, tokenId);
+      expect(token).to.be.null;
     });
   });
 });
modifiedtests/src/allowLists.test.tsdiffbeforeafterboth
--- a/tests/src/allowLists.test.ts
+++ b/tests/src/allowLists.test.ts
@@ -17,31 +17,19 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
-import usingApi, {submitTransactionExpectFailAsync} from './substrate/substrate-api';
-import {
-  addToAllowListExpectSuccess,
-  createCollectionExpectSuccess,
-  createItemExpectSuccess,
-  destroyCollectionExpectSuccess,
-  enableAllowListExpectSuccess,
-  normalizeAccountId,
-  addCollectionAdminExpectSuccess,
-  addToAllowListExpectFail,
-  removeFromAllowListExpectSuccess,
-  removeFromAllowListExpectFailure,
-  addToAllowListAgainExpectSuccess,
-  transferExpectFailure,
-  approveExpectSuccess,
-  approveExpectFail,
-  transferExpectSuccess,
-  transferFromExpectSuccess,
-  setMintPermissionExpectSuccess,
-  createItemExpectFailure,
-} from './util/helpers';
+import {usingPlaygrounds} from './util/playgrounds';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
 
+let donor: IKeyringPair;
+
+before(async () => {
+  await usingPlaygrounds(async (_, privateKey) => {
+    donor = privateKey('//Alice');
+  });
+});
+
 let alice: IKeyringPair;
 let bob: IKeyringPair;
 let charlie: IKeyringPair;
@@ -49,266 +37,348 @@
 describe('Integration Test ext. Allow list tests', () => {
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice = privateKeyWrapper('//Alice');
-      bob = privateKeyWrapper('//Bob');
-      charlie = privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
   });
 
   it('Owner can add address to allow list', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectSuccess(alice, collectionId, bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      const allowList = await helper.nft.getAllowList(collectionId);
+      expect(allowList).to.be.deep.contains({Substrate: bob.address});
+    });
   });
 
   it('Admin can add address to allow list', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await addToAllowListExpectSuccess(bob, collectionId, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});
+
+      await helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address});
+      const allowList = await helper.nft.getAllowList(collectionId);
+      expect(allowList).to.be.deep.contains({Substrate: charlie.address});
+    });
   });
 
   it('Non-privileged user cannot add address to allow list', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectFail(bob, collectionId, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const addToAllowListTx = async () => helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address});
+      await expect(addToAllowListTx()).to.be.rejected;
+    });
   });
 
   it('Nobody can add address to allow list of non-existing collection', async () => {
     const collectionId = (1<<32) - 1;
-    await addToAllowListExpectFail(alice, collectionId, bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const addToAllowListTx = async () => helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address});
+      await expect(addToAllowListTx()).to.be.rejected;
+    });
   });
 
   it('Nobody can add address to allow list of destroyed collection', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await destroyCollectionExpectSuccess(collectionId, '//Alice');
-    await addToAllowListExpectFail(alice, collectionId, bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.collection.burn(alice, collectionId);
+      const addToAllowListTx = async () => helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      await expect(addToAllowListTx()).to.be.rejected;
+    });
   });
 
   it('If address is already added to allow list, nothing happens', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectSuccess(alice, collectionId, bob.address);
-    await addToAllowListAgainExpectSuccess(alice, collectionId, bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      const allowList = await helper.nft.getAllowList(collectionId);
+      expect(allowList).to.be.deep.contains({Substrate: bob.address});
+    });
   });
 
   it('Owner can remove address from allow list', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectSuccess(alice, collectionId, bob.address);
-    await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(bob));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+
+      await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+
+      const allowList = await helper.nft.getAllowList(collectionId);
+
+      expect(allowList).to.be.not.deep.contains({Substrate: bob.address});
+    });
   });
 
   it('Admin can remove address from allow list', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await removeFromAllowListExpectSuccess(bob, collectionId, normalizeAccountId(charlie));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addAdmin(alice, collectionId, {Substrate: charlie.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      await helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: bob.address});
+
+      const allowList = await helper.nft.getAllowList(collectionId);
+
+      expect(allowList).to.be.not.deep.contains({Substrate: bob.address});
+    });
   });
 
   it('Non-privileged user cannot remove address from allow list', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await removeFromAllowListExpectFailure(bob, collectionId, normalizeAccountId(charlie));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+      const removeTx = async () => helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address});
+      await expect(removeTx()).to.be.rejected;
+      const allowList = await helper.nft.getAllowList(collectionId);
+
+      expect(allowList).to.be.deep.contains({Substrate: charlie.address});
+    });
   });
 
   it('Nobody can remove address from allow list of non-existing collection', async () => {
     const collectionId = (1<<32) - 1;
-    await removeFromAllowListExpectFailure(alice, collectionId, normalizeAccountId(charlie));
+    await usingPlaygrounds(async (helper) => {
+      const removeTx = async () => helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address});
+      await expect(removeTx()).to.be.rejected;
+    });
   });
 
   it('Nobody can remove address from allow list of deleted collection', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await destroyCollectionExpectSuccess(collectionId, '//Alice');
-    await removeFromAllowListExpectFailure(alice, collectionId, normalizeAccountId(charlie));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      await helper.collection.burn(alice, collectionId);
+      const removeTx = async () => helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+
+      await expect(removeTx()).to.be.rejected;
+    });
   });
 
   it('If address is already removed from allow list, nothing happens', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(charlie));
-    await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(charlie));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+      const allowListBefore = await helper.nft.getAllowList(collectionId);
+      expect(allowListBefore).to.be.not.deep.contains({Substrate: bob.address});
+
+      await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address});
+
+      const allowListAfter = await helper.nft.getAllowList(collectionId);
+      expect(allowListAfter).to.be.not.deep.contains({Substrate: bob.address});
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom. Test1', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
 
-    await transferExpectFailure(
-      collectionId,
-      itemId,
-      alice,
-      charlie,
-      1,
-    );
+      const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(transferResult()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom. Test2', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await approveExpectSuccess(collectionId, itemId, alice, charlie.address);
-    await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(alice));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});
 
-    await transferExpectFailure(
-      collectionId,
-      itemId,
-      alice,
-      charlie,
-      1,
-    );
+      const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(transferResult()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom. Test1', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
 
-    await transferExpectFailure(
-      collectionId,
-      itemId,
-      alice,
-      charlie,
-      1,
-    );
+      const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(transferResult()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom. Test2', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await approveExpectSuccess(collectionId, itemId, alice, charlie.address);
-    await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(alice));
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address});
 
-    await transferExpectFailure(
-      collectionId,
-      itemId,
-      alice,
-      charlie,
-      1,
-    );
+      const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(transferResult()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-
-    await usingApi(async (api) => {
-      const tx = api.tx.unique.burnItem(collectionId, itemId, /*normalizeAccountId(Alice.address),*/ 11);
-      const badTransaction = async function () {
-        await submitTransactionExpectFailAsync(alice, tx);
-      };
-      await expect(badTransaction()).to.be.rejected;
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      const burnTx = async () => helper.nft.burnToken(bob, collectionId, tokenId);
+      await expect(burnTx()).to.be.rejected;
     });
   });
 
   it('If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method)', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await approveExpectFail(collectionId, itemId, alice, bob);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      const approveTx = async () => helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transfer.', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await transferExpectSuccess(collectionId, itemId, alice, charlie, 1, 'NFT');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+      await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(charlie.address);
+    });
   });
 
-  it('If Public Access mode is set to AllowList, tokens can be transferred to a alowlisted address with transferFrom.', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await approveExpectSuccess(collectionId, itemId, alice, charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, alice, alice, charlie, 1, 'NFT');
+  it('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transferFrom.', async () => {
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+
+      await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(charlie.address);
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await transferExpectSuccess(collectionId, itemId, alice, charlie, 1, 'NFT');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+
+      await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(charlie.address);
+    });
   });
 
   it('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transferFrom', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await addToAllowListExpectSuccess(alice, collectionId, alice.address);
-    await addToAllowListExpectSuccess(alice, collectionId, charlie.address);
-    await approveExpectSuccess(collectionId, itemId, alice, charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, alice, alice, charlie, 1, 'NFT');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address});
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+
+      await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(charlie.address);
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, false);
-    await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      const token = await helper.nft.getToken(collectionId, tokenId);
+      expect(token).to.be.not.null;
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, false);
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await createItemExpectSuccess(bob, collectionId, 'NFT', bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false});
+      await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+      const {tokenId} = await helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address});
+      const token = await helper.nft.getToken(collectionId, tokenId);
+      expect(token).to.be.not.null;
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow-listed address', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, false);
-    await addToAllowListExpectSuccess(alice, collectionId, bob.address);
-    await createItemExpectFailure(bob, collectionId, 'NFT', bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false});
+      await helper.collection.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      const mintTokenTx = async () => helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address});
+      await expect(mintTokenTx()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, false);
-    await createItemExpectFailure(bob, collectionId, 'NFT', bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false});
+      const mintTokenTx = async () => helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address});
+      await expect(mintTokenTx()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, true);
-    await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(alice.address);
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, true);
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await createItemExpectSuccess(bob, collectionId, 'NFT', bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true});
+      await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});
+      const {tokenId} = await helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(bob.address);
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, true);
-    await createItemExpectFailure(bob, collectionId, 'NFT', bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true});
+      const mintTokenTx = async () => helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address});
+      await expect(mintTokenTx()).to.be.rejected;
+    });
   });
 
   it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await enableAllowListExpectSuccess(alice, collectionId);
-    await setMintPermissionExpectSuccess(alice, collectionId, true);
-    await addToAllowListExpectSuccess(alice, collectionId, bob.address);
-    await createItemExpectSuccess(bob, collectionId, 'NFT', bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true});
+      await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address});
+      const {tokenId} = await helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(bob.address);
+    });
   });
 });
modifiedtests/src/approve.test.tsdiffbeforeafterboth
--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -15,28 +15,26 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {ApiPromise} from '@polkadot/api';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
-import {default as usingApi} from './substrate/substrate-api';
 import {
   approveExpectFail,
   approveExpectSuccess,
   createCollectionExpectSuccess,
   createItemExpectSuccess,
-  destroyCollectionExpectSuccess,
-  setCollectionLimitsExpectSuccess,
-  transferExpectSuccess,
-  addCollectionAdminExpectSuccess,
-  adminApproveFromExpectFail,
-  getCreatedCollectionCount,
-  transferFromExpectSuccess,
-  transferFromExpectFail,
-  requirePallets,
-  Pallets,
 } from './util/helpers';
+import {usingPlaygrounds} from './util/playgrounds';
+
+let donor: IKeyringPair;
+
+before(async () => {
+  await usingPlaygrounds(async (_, privateKey) => {
+    donor = privateKey('//Alice');
+  });
+});
 
 chai.use(chaiAsPromised);
+const expect = chai.expect;
 
 describe('Integration Test approve(spender, collection_id, item_id, amount):', () => {
   let alice: IKeyringPair;
@@ -44,63 +42,89 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
   });
 
   it('[nft] Execute the extrinsic and check approvedList', async () => {
-    const nftCollectionId = await createCollectionExpectSuccess();
-    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amount).to.be.equal(BigInt(1));
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+      await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amount).to.be.equal(BigInt(1));
+    });
   });
 
   it('[nft] Remove approval by using 0 amount', async () => {
-    const nftCollectionId = await createCollectionExpectSuccess();
-    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 1);
-    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 0);
+    await usingPlaygrounds(async (helper) => {
+      const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const collectionId = collection.collectionId;
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
+      await helper.signTransaction(alice, helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0));
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountBefore).to.be.equal(BigInt(1));
+
+      await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+      const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountAfter).to.be.equal(BigInt(0));
+    });
   });
 
   it('[refungible] Remove approval by using 0 amount', async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+      await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountBefore).to.be.equal(BigInt(1));
 
-    const reFungibleCollectionId =
-      await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 1);
-    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 0);
+      await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+      const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountAfter).to.be.equal(BigInt(0));
+    });
   });
 
   it('can`t be called by collection owner on non-owned item when OwnerCanTransfer == false', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
-
-    await adminApproveFromExpectFail(collectionId, itemId, alice, bob.address, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      const approveTokenTx = async () => helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(approveTokenTx()).to.be.rejected;
+    });
   });
 });
 
@@ -110,31 +134,39 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
-  });  
+  });
 
   it('NFT', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
-    await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      await helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.true;
+    });
   });
 
   it('Fungible up to an approved amount', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', bob.address); 
-    await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, bob.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, {Substrate: bob.address});
+      expect(amount).to.be.equal(BigInt(1));
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: bob.address, pieces: 100n});
+      await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);
+      const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, {Substrate: bob.address});
+      expect(amount).to.be.equal(BigInt(100n));
+    });
   });
 });
 
@@ -144,34 +176,45 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
-  });  
+  });
 
   it('NFT', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
-    await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'NFT');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      await helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(alice.address);
+    });
   });
 
   it('Fungible up to an approved amount', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', bob.address); 
-    await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, bob.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+      await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n);
+      const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+      expect(after - before).to.be.equal(BigInt(1));
+    });
   });
 
   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);
-    await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'ReFungible');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: bob.address, pieces: 100n});
+      await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+      await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n);
+      const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+      expect(after - before).to.be.equal(BigInt(1));
+    });
   });
 });
 
@@ -181,37 +224,52 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
-  });  
+  });
 
   it('NFT', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
-    await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'NFT');
-    await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      await helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner.Substrate).to.be.equal(alice.address);
+      const transferTokenFromTx = async () => helper.nft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      await expect(transferTokenFromTx()).to.be.rejected;
+    });
   });
 
   it('Fungible up to an approved amount', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', bob.address); 
-    await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible');
-    await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, bob.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+      await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n);
+      const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+      expect(after - before).to.be.equal(BigInt(1));
+
+      const transferTokenFromTx = async () => helper.ft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n);
+      await expect(transferTokenFromTx()).to.be.rejected;
+    });
   });
 
   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);
-    await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'ReFungible');
-    await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: bob.address, pieces: 100n});
+      await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);
+      const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+      await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 100n);
+      const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+      expect(after - before).to.be.equal(BigInt(100));
+      const transferTokenFromTx = async () => helper.rft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 100n);
+      await expect(transferTokenFromTx()).to.be.rejected;
+    });
   });
 });
 
@@ -222,20 +280,28 @@
   let dave: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
-      dave =  privateKeyWrapper('//Dave');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
     });
-  });  
+  });
 
   it('If a user B is approved to transfer 10 Fungible tokens from user A, they can transfer 2 tokens to user C, which will result in decreasing approval from 10 to 8. Then user B can transfer 8 tokens to user D.', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', alice.address); 
-    await approveExpectSuccess(collectionId, itemId, alice, bob.address, 10);
-    await transferFromExpectSuccess(collectionId, itemId, bob, alice, charlie, 2, 'Fungible');
-    await transferFromExpectSuccess(collectionId, itemId, bob, alice, dave, 8, 'Fungible');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 10n);
+
+      const charlieBefore = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
+      await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address}, 2n);
+      const charlieAfter = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});
+      expect(charlieAfter - charlieBefore).to.be.equal(BigInt(2));
+
+      const daveBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+      await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: alice.address}, {Substrate: dave.address}, 8n);
+      const daveAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+      expect(daveAfter - daveBefore).to.be.equal(BigInt(8));
+    });
   });
 });
 
@@ -245,38 +311,57 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
   });
 
   it('NFT', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT');
-    await approveExpectSuccess(collectionId, itemId, alice, bob.address, 1);
-    await approveExpectSuccess(collectionId, itemId, alice, bob.address, 0);
-    await transferFromExpectFail(collectionId, itemId, bob, bob, charlie, 1);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;
+      await helper.signTransaction(alice, helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0));
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;
+      const transferTokenFromTx = async () => helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: bob.address});
+      await expect(transferTokenFromTx()).to.be.rejected;
+    });
   });
 
   it('Fungible', 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);
-    await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, bob, charlie, 1);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountBefore).to.be.equal(BigInt(1));
+
+      await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+      const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountAfter).to.be.equal(BigInt(0));
+
+      const transferTokenFromTx = async () => helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}, 1n);
+      await expect(transferTokenFromTx()).to.be.rejected;
+    });
   });
 
   it('ReFungible', async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+      await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address});
+      const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountBefore).to.be.equal(BigInt(1));
 
-    const reFungibleCollectionId =
-      await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 1);
-    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 0);
-    await transferFromExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, bob, charlie, 1);
+      await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n);
+      const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address});
+      expect(amountAfter).to.be.equal(BigInt(0));
+
+      const transferTokenFromTx = async () => helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}, 100n);
+      await expect(transferTokenFromTx()).to.be.rejected;
+    });
   });
 });
 
@@ -286,31 +371,38 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
   });
 
   it('1 for NFT', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
-    await approveExpectFail(collectionId, itemId, bob, charlie, 2);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      const approveTx = async () => helper.signTransaction(bob, helper.api?.tx.unique.approve({Substrate: charlie.address}, collectionId, tokenId, 2));
+      await expect(approveTx()).to.be.rejected;
+      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;
+    });
   });
 
   it('Fungible', async () => {
-    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-    await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, charlie, 11);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      const approveTx = async () => helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 11n);
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+      const approveTx = async () => helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 101n);
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 });
 
@@ -321,41 +413,67 @@
   let dave: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
-      dave =  privateKeyWrapper('//Dave');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
     });
-  });  
+  });
 
   it('NFT', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'NFT');
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'NFT');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});
+
+      await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});
+      const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner1.Substrate).to.be.equal(dave.address);
+
+      await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+      await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});
+      const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);
+      expect(owner2.Substrate).to.be.equal(alice.address);
+    });
   });
 
   it('Fungible up to an approved amount', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', charlie.address); 
-    await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'Fungible');
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'Fungible');
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);
+      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+      await helper.ft.mintTokens(alice, collectionId, charlie.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+
+      const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+      await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);
+      const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});
+      expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(BigInt(1));
+
+      await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});
+
+      const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+      await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);
+      const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});
+      expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(BigInt(1));
+    });
   });
 
   it('ReFungible up to an approved amount', async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});
+
+      const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});
+      await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);
+      const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});
+      expect(daveAfter - daveBefore).to.be.equal(BigInt(1));
 
-    const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address);
-    await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'ReFungible');
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'ReFungible');
+      await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+
+      const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+      await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);
+      const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});
+      expect(aliceAfter - aliceBefore).to.be.equal(BigInt(1));
+    });
   });
 });
 
@@ -366,13 +484,10 @@
   let dave: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
-      dave =  privateKeyWrapper('//Dave');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
     });
-  });  
+  });
 
   it.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async () => {
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
@@ -417,19 +532,19 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
   });
 
   it('can be called by collection admin on non-owned item', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
-
-    await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    await adminApproveFromExpectFail(collectionId, itemId, bob, alice.address, charlie.address);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});
+      const approveTx = async () => helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 });
 
@@ -439,114 +554,139 @@
   let charlie: IKeyringPair;
 
   before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice =  privateKeyWrapper('//Alice');
-      bob =  privateKeyWrapper('//Bob');
-      charlie =  privateKeyWrapper('//Charlie');
+    await usingPlaygrounds(async (helper) => {
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
     });
   });
 
   it('[nft] Approve for a collection that does not exist', async () => {
-    await usingApi(async (api: ApiPromise) => {
-      const nftCollectionCount = await getCreatedCollectionCount(api);
-      await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
+    await usingPlaygrounds(async (helper) => {
+      const collectionId = 1 << 32 - 1;
+      const approveTx = async () => helper.nft.approveToken(bob, collectionId, 1, {Substrate: charlie.address});
+      await expect(approveTx()).to.be.rejected;
     });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const collectionId = 1 << 32 - 1;
+      const approveTx = async () => helper.ft.approveToken(bob, collectionId, 1, {Substrate: charlie.address});
+      await expect(approveTx()).to.be.rejected;
     });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const collectionId = 1 << 32 - 1;
+      const approveTx = async () => helper.rft.approveToken(bob, collectionId, 1, {Substrate: charlie.address});
+      await expect(approveTx()).to.be.rejected;
     });
   });
 
   it('[nft] Approve for a collection that was destroyed', async () => {
-    const nftCollectionId = await createCollectionExpectSuccess();
-    await destroyCollectionExpectSuccess(nftCollectionId);
-    await approveExpectFail(nftCollectionId, 1, alice, bob);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.nft.burn(alice, collectionId);
+      const approveTx = async () => helper.nft.approveToken(alice, collectionId, 1, {Substrate: bob.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
-  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);
+  it('[fungible] Approve for a collection that was destroyed', async () => {
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.ft.burn(alice, collectionId);
+      const approveTx = async () => helper.ft.approveToken(alice, collectionId, 1, {Substrate: bob.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.rft.burn(alice, collectionId);
+      const approveTx = async () => helper.rft.approveToken(alice, collectionId, 1, {Substrate: bob.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   it('[nft] Approve transfer of a token that does not exist', async () => {
-    const nftCollectionId = await createCollectionExpectSuccess();
-    await approveExpectFail(nftCollectionId, 2, alice, bob);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const approveTx = async () => helper.nft.approveToken(alice, collectionId, 2, {Substrate: bob.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const approveTx = async () => helper.rft.approveToken(alice, collectionId, 2, {Substrate: bob.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   it('[nft] Approve using the address that does not own the approved token', async () => {
-    const nftCollectionId = await createCollectionExpectSuccess();
-    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-    await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address});
+      const approveTx = async () => helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+      const approveTx = async () => helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   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);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+      const approveTx = async () => helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   it('should fail if approved more ReFungibles than owned', async function() {
-    await requirePallets(this, [Pallets.ReFungible]);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});
+      await helper.rft.transferToken(alice, collectionId, tokenId, {Substrate: bob.address}, 100n);
+      await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 100n);
 
-    const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'ReFungible');
-    await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 100, 'ReFungible');
-    await approveExpectSuccess(nftCollectionId, newNftTokenId, bob, alice.address, 100);
-    await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice, 101);
+      const approveTx = async () => helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 101n);
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   it('should fail if approved more Fungibles than owned', async () => {
-    const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'Fungible');
-    await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 10, 'Fungible');
-    await approveExpectSuccess(nftCollectionId, newNftTokenId, bob, alice.address, 10);
-    await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice, 11);
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      await helper.ft.mintTokens(alice, collectionId, alice.address, 10n);
+      const tokenId = await helper.ft.getLastTokenId(collectionId);
+
+      await helper.ft.transferToken(alice, collectionId, tokenId, {Substrate: bob.address}, 10n);
+      await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 10n);
+      const approveTx = async () => helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 11n);
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 
   it('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: false});
+    await usingPlaygrounds(async (helper) => {
+      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
+      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address});
+      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});
 
-    await approveExpectFail(collectionId, itemId, alice, charlie);
+      const approveTx = async () => helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address});
+      await expect(approveTx()).to.be.rejected;
+    });
   });
 });
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
475 return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();475 return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();
476 }476 }
477477
478 /**478 /**
479 * Get the number of created collections.479 * Get the number of created collections.
480 * 480 *
481 * @returns number of created collections481 * @returns number of created collections
482 */482 */
483 async getTotalCount(): Promise<number> {483 async getTotalCount(): Promise<number> {
484 return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();484 return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();
485 }485 }
486486
487 /**487 /**
488 * Get information about the collection with additional data, 488 * Get information about the collection with additional data,
489 * including the number of tokens it contains, its administrators, 489 * including the number of tokens it contains, its administrators,
490 * the normalized address of the collection's owner, and decoded name and description.490 * the normalized address of the collection's owner, and decoded name and description.
491 * 491 *
492 * @param collectionId ID of collection492 * @param collectionId ID of collection
493 * @example await getData(2)493 * @example await getData(2)
494 * @returns collection information object494 * @returns collection information object
495 */495 */
496 async getData(collectionId: number): Promise<{496 async getData(collectionId: number): Promise<{
497 id: number;497 id: number;
498 name: string;498 name: string;
523 return collectionData;523 return collectionData;
524 }524 }
525525
526 /**526 /**
527 * Get the addresses of the collection's administrators, optionally normalized.527 * Get the addresses of the collection's administrators, optionally normalized.
528 * 528 *
529 * @param collectionId ID of collection529 * @param collectionId ID of collection
530 * @param normalize whether to normalize the addresses to the default ss58 format530 * @param normalize whether to normalize the addresses to the default ss58 format
531 * @example await getAdmins(1)531 * @example await getAdmins(1)
532 * @returns array of administrators532 * @returns array of administrators
533 */533 */
534 async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {534 async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
535 const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();535 const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();
536536
561 : allowListed;561 : allowListed;
562 }562 }
563563
564 /**564 /**
565 * Get the effective limits of the collection instead of null for default values565 * Get the effective limits of the collection instead of null for default values
566 * 566 *
567 * @param collectionId ID of collection567 * @param collectionId ID of collection
568 * @example await getEffectiveLimits(2)568 * @example await getEffectiveLimits(2)
569 * @returns object of collection limits569 * @returns object of collection limits
570 */570 */
571 async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {571 async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {
572 return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();572 return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();
573 }573 }
574574
575 /**575 /**
576 * Burns the collection if the signer has sufficient permissions and collection is empty.576 * Burns the collection if the signer has sufficient permissions and collection is empty.
577 * 577 *
578 * @param signer keyring of signer578 * @param signer keyring of signer
579 * @param collectionId ID of collection579 * @param collectionId ID of collection
580 * @example await helper.collection.burn(aliceKeyring, 3);580 * @example await helper.collection.burn(aliceKeyring, 3);
581 * @returns ```true``` if extrinsic success, otherwise ```false```581 * @returns ```true``` if extrinsic success, otherwise ```false```
582 */582 */
583 async burn(signer: TSigner, collectionId: number): Promise<boolean> {583 async burn(signer: TSigner, collectionId: number): Promise<boolean> {
584 const result = await this.helper.executeExtrinsic(584 const result = await this.helper.executeExtrinsic(
585 signer,585 signer,
590 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');590 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');
591 }591 }
592592
593 /**593 /**
594 * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.594 * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.
595 * 595 *
596 * @param signer keyring of signer596 * @param signer keyring of signer
597 * @param collectionId ID of collection597 * @param collectionId ID of collection
598 * @param sponsorAddress Sponsor substrate address598 * @param sponsorAddress Sponsor substrate address
599 * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")599 * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
600 * @returns ```true``` if extrinsic success, otherwise ```false```600 * @returns ```true``` if extrinsic success, otherwise ```false```
601 */601 */
602 async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {602 async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {
603 const result = await this.helper.executeExtrinsic(603 const result = await this.helper.executeExtrinsic(
604 signer,604 signer,
609 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet');609 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet');
610 }610 }
611611
612 /**612 /**
613 * Confirms consent to sponsor the collection on behalf of the signer.613 * Confirms consent to sponsor the collection on behalf of the signer.
614 * 614 *
615 * @param signer keyring of signer615 * @param signer keyring of signer
616 * @param collectionId ID of collection616 * @param collectionId ID of collection
617 * @example confirmSponsorship(aliceKeyring, 10)617 * @example confirmSponsorship(aliceKeyring, 10)
618 * @returns ```true``` if extrinsic success, otherwise ```false```618 * @returns ```true``` if extrinsic success, otherwise ```false```
619 */619 */
620 async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {620 async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {
621 const result = await this.helper.executeExtrinsic(621 const result = await this.helper.executeExtrinsic(
622 signer,622 signer,
627 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed');627 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed');
628 }628 }
629629
630 /**630 /**
631 * Removes the sponsor of a collection, regardless if it consented or not.631 * Removes the sponsor of a collection, regardless if it consented or not.
632 * 632 *
633 * @param signer keyring of signer633 * @param signer keyring of signer
634 * @param collectionId ID of collection634 * @param collectionId ID of collection
635 * @example removeSponsor(aliceKeyring, 10)635 * @example removeSponsor(aliceKeyring, 10)
636 * @returns ```true``` if extrinsic success, otherwise ```false```636 * @returns ```true``` if extrinsic success, otherwise ```false```
637 */637 */
638 async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {638 async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {
639 const result = await this.helper.executeExtrinsic(639 const result = await this.helper.executeExtrinsic(
640 signer,640 signer,
645 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved');645 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved');
646 }646 }
647647
648 /**648 /**
649 * Sets the limits of the collection. At least one limit must be specified for a correct call.649 * Sets the limits of the collection. At least one limit must be specified for a correct call.
650 * 650 *
651 * @param signer keyring of signer651 * @param signer keyring of signer
652 * @param collectionId ID of collection652 * @param collectionId ID of collection
653 * @param limits collection limits object653 * @param limits collection limits object
654 * @example654 * @example
655 * await setLimits(655 * await setLimits(
656 * aliceKeyring,656 * aliceKeyring,
657 * 10,657 * 10,
658 * {658 * {
659 * sponsorTransferTimeout: 0,659 * sponsorTransferTimeout: 0,
660 * ownerCanDestroy: false660 * ownerCanDestroy: false
661 * }661 * }
662 * )662 * )
663 * @returns ```true``` if extrinsic success, otherwise ```false```663 * @returns ```true``` if extrinsic success, otherwise ```false```
664 */664 */
665 async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {665 async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {
666 const result = await this.helper.executeExtrinsic(666 const result = await this.helper.executeExtrinsic(
667 signer,667 signer,
672 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet');672 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet');
673 }673 }
674674
675 /**675 /**
676 * Changes the owner of the collection to the new Substrate address.676 * Changes the owner of the collection to the new Substrate address.
677 * 677 *
678 * @param signer keyring of signer678 * @param signer keyring of signer
679 * @param collectionId ID of collection679 * @param collectionId ID of collection
680 * @param ownerAddress substrate address of new owner680 * @param ownerAddress substrate address of new owner
681 * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")681 * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")
682 * @returns ```true``` if extrinsic success, otherwise ```false```682 * @returns ```true``` if extrinsic success, otherwise ```false```
683 */683 */
684 async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {684 async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {
685 const result = await this.helper.executeExtrinsic(685 const result = await this.helper.executeExtrinsic(
686 signer,686 signer,
691 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged');691 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged');
692 }692 }
693693
694 /**694 /**
695 * Adds a collection administrator. 695 * Adds a collection administrator.
696 * 696 *
697 * @param signer keyring of signer697 * @param signer keyring of signer
698 * @param collectionId ID of collection698 * @param collectionId ID of collection
699 * @param adminAddressObj Administrator address (substrate or ethereum)699 * @param adminAddressObj Administrator address (substrate or ethereum)
700 * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})700 * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
701 * @returns ```true``` if extrinsic success, otherwise ```false```701 * @returns ```true``` if extrinsic success, otherwise ```false```
702 */702 */
703 async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {703 async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
704 const result = await this.helper.executeExtrinsic(704 const result = await this.helper.executeExtrinsic(
705 signer,705 signer,
710 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded');710 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded');
711 }711 }
712712
713 /**713 /**
714 * Removes a collection administrator.714 * Removes a collection administrator.
715 * 715 *
716 * @param signer keyring of signer716 * @param signer keyring of signer
717 * @param collectionId ID of collection717 * @param collectionId ID of collection
718 * @param adminAddressObj Administrator address (substrate or ethereum)718 * @param adminAddressObj Administrator address (substrate or ethereum)
719 * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})719 * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})
720 * @returns ```true``` if extrinsic success, otherwise ```false```720 * @returns ```true``` if extrinsic success, otherwise ```false```
721 */721 */
722 async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {722 async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {
723 const result = await this.helper.executeExtrinsic(723 const result = await this.helper.executeExtrinsic(
724 signer,724 signer,
729 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');729 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');
730 }730 }
731731
732 /**732 /**
733 * Adds an address to allow list 733 * Adds an address to allow list
734 * @param signer keyring of signer734 * @param signer keyring of signer
735 * @param collectionId ID of collection735 * @param collectionId ID of collection
736 * @param addressObj address to add to the allow list736 * @param addressObj address to add to the allow list
737 * @returns ```true``` if extrinsic success, otherwise ```false```737 * @returns ```true``` if extrinsic success, otherwise ```false```
738 */738 */
739 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {739 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
740 const result = await this.helper.executeExtrinsic(740 const result = await this.helper.executeExtrinsic(
741 signer,741 signer,
746 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');746 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');
747 }747 }
748748
749 /**749 /**
750 * Removes an address from allow list 750 * Removes an address from allow list
751 * 751 *
752 * @param signer keyring of signer752 * @param signer keyring of signer
753 * @param collectionId ID of collection753 * @param collectionId ID of collection
754 * @param addressObj address to remove from the allow list754 * @param addressObj address to remove from the allow list
755 * @returns ```true``` if extrinsic success, otherwise ```false```755 * @returns ```true``` if extrinsic success, otherwise ```false```
756 */756 */
757 async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {757 async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {
758 const result = await this.helper.executeExtrinsic(758 const result = await this.helper.executeExtrinsic(
759 signer,759 signer,
764 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved');764 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved');
765 }765 }
766766
767 /**767 /**
768 * Sets onchain permissions for selected collection.768 * Sets onchain permissions for selected collection.
769 * 769 *
770 * @param signer keyring of signer770 * @param signer keyring of signer
771 * @param collectionId ID of collection771 * @param collectionId ID of collection
772 * @param permissions collection permissions object772 * @param permissions collection permissions object
773 * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});773 * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});
774 * @returns ```true``` if extrinsic success, otherwise ```false```774 * @returns ```true``` if extrinsic success, otherwise ```false```
775 */775 */
776 async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {776 async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {
777 const result = await this.helper.executeExtrinsic(777 const result = await this.helper.executeExtrinsic(
778 signer,778 signer,
783 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet');783 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet');
784 }784 }
785785
786 /**786 /**
787 * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.787 * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.
788 * 788 *
789 * @param signer keyring of signer789 * @param signer keyring of signer
790 * @param collectionId ID of collection790 * @param collectionId ID of collection
791 * @param permissions nesting permissions object791 * @param permissions nesting permissions object
792 * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});792 * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});
793 * @returns ```true``` if extrinsic success, otherwise ```false```793 * @returns ```true``` if extrinsic success, otherwise ```false```
794 */794 */
795 async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {795 async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {
796 return await this.setPermissions(signer, collectionId, {nesting: permissions});796 return await this.setPermissions(signer, collectionId, {nesting: permissions});
797 }797 }
798798
799 /**799 /**
800 * Disables nesting for selected collection.800 * Disables nesting for selected collection.
801 * 801 *
802 * @param signer keyring of signer802 * @param signer keyring of signer
803 * @param collectionId ID of collection803 * @param collectionId ID of collection
804 * @example disableNesting(aliceKeyring, 10);804 * @example disableNesting(aliceKeyring, 10);
805 * @returns ```true``` if extrinsic success, otherwise ```false```805 * @returns ```true``` if extrinsic success, otherwise ```false```
806 */806 */
807 async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {807 async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {
808 return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});808 return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});
809 }809 }
810810
811 /**811 /**
812 * Sets onchain properties to the collection.812 * Sets onchain properties to the collection.
813 * 813 *
814 * @param signer keyring of signer814 * @param signer keyring of signer
815 * @param collectionId ID of collection815 * @param collectionId ID of collection
816 * @param properties array of property objects816 * @param properties array of property objects
817 * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);817 * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);
818 * @returns ```true``` if extrinsic success, otherwise ```false```818 * @returns ```true``` if extrinsic success, otherwise ```false```
819 */819 */
820 async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {820 async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {
821 const result = await this.helper.executeExtrinsic(821 const result = await this.helper.executeExtrinsic(
822 signer,822 signer,
827 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');827 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');
828 }828 }
829829
830 /**830 /**
831 * Deletes onchain properties from the collection.831 * Deletes onchain properties from the collection.
832 * 832 *
833 * @param signer keyring of signer833 * @param signer keyring of signer
834 * @param collectionId ID of collection834 * @param collectionId ID of collection
835 * @param propertyKeys array of property keys to delete835 * @param propertyKeys array of property keys to delete
836 * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);836 * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);
837 * @returns ```true``` if extrinsic success, otherwise ```false```837 * @returns ```true``` if extrinsic success, otherwise ```false```
838 */838 */
839 async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {839 async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {
840 const result = await this.helper.executeExtrinsic(840 const result = await this.helper.executeExtrinsic(
841 signer,841 signer,
846 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');846 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');
847 }847 }
848848
849 /**849 /**
850 * Changes the owner of the token.850 * Changes the owner of the token.
851 * 851 *
852 * @param signer keyring of signer852 * @param signer keyring of signer
853 * @param collectionId ID of collection853 * @param collectionId ID of collection
854 * @param tokenId ID of token854 * @param tokenId ID of token
855 * @param addressObj address of a new owner855 * @param addressObj address of a new owner
856 * @param amount amount of tokens to be transfered. For NFT must be set to 1n856 * @param amount amount of tokens to be transfered. For NFT must be set to 1n
857 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})857 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
858 * @returns true if the token success, otherwise false858 * @returns true if the token success, otherwise false
859 */859 */
860 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {860 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {
861 const result = await this.helper.executeExtrinsic(861 const result = await this.helper.executeExtrinsic(
862 signer,862 signer,
867 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);867 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);
868 }868 }
869869
870 /**870 /**
871 * 871 *
872 * Change ownership of a token(s) on behalf of the owner. 872 * Change ownership of a token(s) on behalf of the owner.
873 * 873 *
874 * @param signer keyring of signer874 * @param signer keyring of signer
875 * @param collectionId ID of collection875 * @param collectionId ID of collection
876 * @param tokenId ID of token876 * @param tokenId ID of token
877 * @param fromAddressObj address on behalf of which the token will be sent877 * @param fromAddressObj address on behalf of which the token will be sent
878 * @param toAddressObj new token owner878 * @param toAddressObj new token owner
879 * @param amount amount of tokens to be transfered. For NFT must be set to 1n879 * @param amount amount of tokens to be transfered. For NFT must be set to 1n
880 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})880 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})
881 * @returns true if the token success, otherwise false881 * @returns true if the token success, otherwise false
882 */882 */
883 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {883 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {
884 const result = await this.helper.executeExtrinsic(884 const result = await this.helper.executeExtrinsic(
885 signer,885 signer,
889 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);889 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
890 }890 }
891891
892 /**892 /**
893 * 893 *
894 * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.894 * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.
895 * 895 *
896 * @param signer keyring of signer896 * @param signer keyring of signer
897 * @param collectionId ID of collection897 * @param collectionId ID of collection
898 * @param tokenId ID of token898 * @param tokenId ID of token
899 * @param amount amount of tokens to be burned. For NFT must be set to 1n899 * @param amount amount of tokens to be burned. For NFT must be set to 1n
900 * @example burnToken(aliceKeyring, 10, 5);900 * @example burnToken(aliceKeyring, 10, 5);
901 * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null```901 * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null```
902 */902 */
903 async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<{903 async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<{
904 success: boolean,904 success: boolean,
905 token: number | null905 token: number | null
914 return {success: burnedTokens.success, token: burnedTokens.tokens.length > 0 ? burnedTokens.tokens[0] : null};914 return {success: burnedTokens.success, token: burnedTokens.tokens.length > 0 ? burnedTokens.tokens[0] : null};
915 }915 }
916916
917 /**917 /**
918 * Destroys a concrete instance of NFT on behalf of the owner918 * Destroys a concrete instance of NFT on behalf of the owner
919 * 919 *
920 * @param signer keyring of signer920 * @param signer keyring of signer
921 * @param collectionId ID of collection921 * @param collectionId ID of collection
922 * @param fromAddressObj address on behalf of which the token will be burnt922 * @param fromAddressObj address on behalf of which the token will be burnt
923 * @param tokenId ID of token923 * @param tokenId ID of token
924 * @param amount amount of tokens to be burned. For NFT must be set to 1n924 * @param amount amount of tokens to be burned. For NFT must be set to 1n
925 * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})925 * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})
926 * @returns ```true``` if extrinsic success, otherwise ```false```926 * @returns ```true``` if extrinsic success, otherwise ```false```
927 */927 */
928 async burnTokenFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, tokenId: number, amount=1n): Promise<boolean> {928 async burnTokenFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, tokenId: number, amount=1n): Promise<boolean> {
929 const burnResult = await this.helper.executeExtrinsic(929 const burnResult = await this.helper.executeExtrinsic(
930 signer,930 signer,
935 return burnedTokens.success && burnedTokens.tokens.length > 0;935 return burnedTokens.success && burnedTokens.tokens.length > 0;
936 }936 }
937937
938 /**938 /**
939 * Set, change, or remove approved address to transfer the ownership of the NFT.939 * Set, change, or remove approved address to transfer the ownership of the NFT.
940 * 940 *
941 * @param signer keyring of signer941 * @param signer keyring of signer
942 * @param collectionId ID of collection942 * @param collectionId ID of collection
943 * @param tokenId ID of token943 * @param tokenId ID of token
944 * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens944 * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens
945 * @param amount amount of token to be approved. For NFT must be set to 1n945 * @param amount amount of token to be approved. For NFT must be set to 1n
946 * @returns ```true``` if extrinsic success, otherwise ```false```946 * @returns ```true``` if extrinsic success, otherwise ```false```
947 */947 */
948 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {948 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {
949 const approveResult = await this.helper.executeExtrinsic(949 const approveResult = await this.helper.executeExtrinsic(
950 signer, 950 signer,
955 return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');955 return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');
956 }956 }
957957
958 /**958 /**
959 * Get the amount of token pieces approved to transfer or burn. Normally 0.959 * Get the amount of token pieces approved to transfer or burn. Normally 0.
960 * 960 *
961 * @param collectionId ID of collection961 * @param collectionId ID of collection
962 * @param tokenId ID of token962 * @param tokenId ID of token
963 * @param toAccountObj address which is approved to use token pieces963 * @param toAccountObj address which is approved to use token pieces
964 * @param fromAccountObj address which may have allowed the use of its owned tokens964 * @param fromAccountObj address which may have allowed the use of its owned tokens
965 * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})965 * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})
966 * @returns number of approved to transfer pieces966 * @returns number of approved to transfer pieces
967 */967 */
968 async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {968 async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {
969 return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();969 return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();
970 }970 }
971971
972 /**972 /**
973 * Get the last created token ID in a collection973 * Get the last created token ID in a collection
974 * 974 *
975 * @param collectionId ID of collection975 * @param collectionId ID of collection
976 * @example getLastTokenId(10);976 * @example getLastTokenId(10);
977 * @returns id of the last created token977 * @returns id of the last created token
978 */978 */
979 async getLastTokenId(collectionId: number): Promise<number> {979 async getLastTokenId(collectionId: number): Promise<number> {
980 return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();980 return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();
981 }981 }
982982
983 /**983 /**
984 * Check if token exists984 * Check if token exists
985 * 985 *
986 * @param collectionId ID of collection986 * @param collectionId ID of collection
987 * @param tokenId ID of token987 * @param tokenId ID of token
988 * @example isTokenExists(10, 20);988 * @example isTokenExists(10, 20);
989 * @returns true if the token exists, otherwise false989 * @returns true if the token exists, otherwise false
990 */990 */
991 async isTokenExists(collectionId: number, tokenId: number): Promise<boolean> {991 async isTokenExists(collectionId: number, tokenId: number): Promise<boolean> {
992 return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();992 return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();
993 }993 }
994}994}
995995
996class NFTnRFT extends CollectionGroup {996class NFTnRFT extends CollectionGroup {
997 /**997 /**
998 * Get tokens owned by account998 * Get tokens owned by account
999 * 999 *
1000 * @param collectionId ID of collection1000 * @param collectionId ID of collection
1001 * @param addressObj tokens owner1001 * @param addressObj tokens owner
1002 * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1002 * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})
1003 * @returns array of token ids owned by account1003 * @returns array of token ids owned by account
1004 */1004 */
1005 async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1005 async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {
1006 return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1006 return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();
1007 }1007 }
10081008
1009 /**1009 /**
1010 * Get token data1010 * Get token data
1011 * 1011 *
1012 * @param collectionId ID of collection1012 * @param collectionId ID of collection
1013 * @param tokenId ID of token1013 * @param tokenId ID of token
1014 * @param propertyKeys optionally filter the token properties to only these keys1014 * @param propertyKeys optionally filter the token properties to only these keys
1015 * @param blockHashAt optionally query the data at some block with this hash1015 * @param blockHashAt optionally query the data at some block with this hash
1016 * @example getToken(10, 5);1016 * @example getToken(10, 5);
1017 * @returns human readable token data 1017 * @returns human readable token data
1018 */1018 */
1019 async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1019 async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{
1020 properties: IProperty[];1020 properties: IProperty[];
1021 owner: ICrossAccountId;1021 owner: ICrossAccountId;
1043 return tokenData;1043 return tokenData;
1044 }1044 }
10451045
1046 /**1046 /**
1047 * Set permissions to change token properties1047 * Set permissions to change token properties
1048 * 1048 *
1049 * @param signer keyring of signer1049 * @param signer keyring of signer
1050 * @param collectionId ID of collection1050 * @param collectionId ID of collection
1051 * @param permissions permissions to change a property by the collection owner or admin1051 * @param permissions permissions to change a property by the collection owner or admin
1052 * @example setTokenPropertyPermissions(1052 * @example setTokenPropertyPermissions(
1053 * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1053 * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]
1054 * )1054 * )
1055 * @returns true if extrinsic success otherwise false1055 * @returns true if extrinsic success otherwise false
1056 */1056 */
1057 async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1057 async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {
1058 const result = await this.helper.executeExtrinsic(1058 const result = await this.helper.executeExtrinsic(
1059 signer,1059 signer,
1064 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1064 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');
1065 }1065 }
10661066
1067 /**1067 /**
1068 * Set token properties1068 * Set token properties
1069 * 1069 *
1070 * @param signer keyring of signer1070 * @param signer keyring of signer
1071 * @param collectionId ID of collection1071 * @param collectionId ID of collection
1072 * @param tokenId ID of token1072 * @param tokenId ID of token
1073 * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1073 * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection
1074 * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1074 * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])
1075 * @returns ```true``` if extrinsic success, otherwise ```false```1075 * @returns ```true``` if extrinsic success, otherwise ```false```
1076 */1076 */
1077 async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1077 async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {
1078 const result = await this.helper.executeExtrinsic(1078 const result = await this.helper.executeExtrinsic(
1079 signer,1079 signer,
1084 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1084 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');
1085 }1085 }
10861086
1087 /**1087 /**
1088 * Delete the provided properties of a token1088 * Delete the provided properties of a token
1089 * @param signer keyring of signer1089 * @param signer keyring of signer
1090 * @param collectionId ID of collection1090 * @param collectionId ID of collection
1091 * @param tokenId ID of token1091 * @param tokenId ID of token
1092 * @param propertyKeys property keys to be deleted 1092 * @param propertyKeys property keys to be deleted
1093 * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1093 * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])
1094 * @returns ```true``` if extrinsic success, otherwise ```false```1094 * @returns ```true``` if extrinsic success, otherwise ```false```
1095 */1095 */
1096 async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1096 async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {
1097 const result = await this.helper.executeExtrinsic(1097 const result = await this.helper.executeExtrinsic(
1098 signer,1098 signer,
1103 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1103 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');
1104 }1104 }
11051105
1106 /**1106 /**
1107 * Mint new collection1107 * Mint new collection
1108 * 1108 *
1109 * @param signer keyring of signer1109 * @param signer keyring of signer
1110 * @param collectionOptions basic collection options and properties 1110 * @param collectionOptions basic collection options and properties
1111 * @param mode NFT or RFT type of a collection1111 * @param mode NFT or RFT type of a collection
1112 * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1112 * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")
1113 * @returns object of the created collection1113 * @returns object of the created collection
1114 */1114 */
1115 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueCollectionBase> {1115 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueCollectionBase> {
1116 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1116 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
1117 collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1117 collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};
1187 return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1187 return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;
1188 }1188 }
11891189
1190 /**1190 /**
1191 * Changes the owner of the token.1191 * Changes the owner of the token.
1192 * 1192 *
1193 * @param signer keyring of signer1193 * @param signer keyring of signer
1194 * @param collectionId ID of collection1194 * @param collectionId ID of collection
1195 * @param tokenId ID of token1195 * @param tokenId ID of token
1196 * @param addressObj address of a new owner1196 * @param addressObj address of a new owner
1197 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1197 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
1198 * @returns ```true``` if extrinsic success, otherwise ```false```1198 * @returns ```true``` if extrinsic success, otherwise ```false```
1199 */1199 */
1200 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1200 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {
1201 return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1201 return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);
1202 }1202 }
12031203
1204 /**1204 /**
1205 * 1205 *
1206 * Change ownership of a NFT on behalf of the owner. 1206 * Change ownership of a NFT on behalf of the owner.
1207 * 1207 *
1208 * @param signer keyring of signer1208 * @param signer keyring of signer
1209 * @param collectionId ID of collection1209 * @param collectionId ID of collection
1210 * @param tokenId ID of token1210 * @param tokenId ID of token
1211 * @param fromAddressObj address on behalf of which the token will be sent1211 * @param fromAddressObj address on behalf of which the token will be sent
1212 * @param toAddressObj new token owner1212 * @param toAddressObj new token owner
1213 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1213 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})
1214 * @returns ```true``` if extrinsic success, otherwise ```false```1214 * @returns ```true``` if extrinsic success, otherwise ```false```
1215 */1215 */
1216 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1216 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {
1217 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1217 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);
1218 }1218 }
12191219
1220 /**1220 /**
1221 * Recursively find the address that owns the token1221 * Recursively find the address that owns the token
1222 * @param collectionId ID of collection1222 * @param collectionId ID of collection
1223 * @param tokenId ID of token1223 * @param tokenId ID of token
1224 * @param blockHashAt 1224 * @param blockHashAt
1225 * @example getTokenTopmostOwner(10, 5);1225 * @example getTokenTopmostOwner(10, 5);
1226 * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1226 * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}
1227 */1227 */
1228 async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId | null> {1228 async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId | null> {
1229 let owner;1229 let owner;
1230 if (typeof blockHashAt === 'undefined') {1230 if (typeof blockHashAt === 'undefined') {
1240 return owner.Substrate ? {Substrate: this.helper.address.normalizeSubstrate(owner.Substrate)} : owner;1240 return owner.Substrate ? {Substrate: this.helper.address.normalizeSubstrate(owner.Substrate)} : owner;
1241 }1241 }
12421242
1243 /**1243 /**
1244 * Get tokens nested in the provided token1244 * Get tokens nested in the provided token
1245 * @param collectionId ID of collection1245 * @param collectionId ID of collection
1246 * @param tokenId ID of token1246 * @param tokenId ID of token
1247 * @param blockHashAt optionally query the data at the block with this hash1247 * @param blockHashAt optionally query the data at the block with this hash
1248 * @example getTokenChildren(10, 5);1248 * @example getTokenChildren(10, 5);
1249 * @returns tokens whose depth of nesting is <= 5 1249 * @returns tokens whose depth of nesting is <= 5
1250 */1250 */
1251 async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1251 async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {
1252 let children;1252 let children;
1253 if(typeof blockHashAt === 'undefined') {1253 if(typeof blockHashAt === 'undefined') {
1278 return result;1278 return result;
1279 }1279 }
12801280
1281 /**1281 /**
1282 * Remove token from nested state1282 * Remove token from nested state
1283 * @param signer keyring of signer1283 * @param signer keyring of signer
1284 * @param tokenObj token to unnest1284 * @param tokenObj token to unnest
1285 * @param rootTokenObj parent of a token1285 * @param rootTokenObj parent of a token
1286 * @param toAddressObj address of a new token owner 1286 * @param toAddressObj address of a new token owner
1287 * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1287 * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});
1288 * @returns ```true``` if extrinsic success, otherwise ```false```1288 * @returns ```true``` if extrinsic success, otherwise ```false```
1289 */1289 */
1290 async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1290 async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {
1291 const rootTokenAddress = {Ethereum: this.helper.util.getNestingTokenAddress(rootTokenObj.collectionId, rootTokenObj.tokenId)};1291 const rootTokenAddress = {Ethereum: this.helper.util.getNestingTokenAddress(rootTokenObj.collectionId, rootTokenObj.tokenId)};
1292 const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1292 const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);
1296 return result;1296 return result;
1297 }1297 }
12981298
1299 /**1299 /**
1300 * Mint new collection1300 * Mint new collection
1301 * @param signer keyring of signer1301 * @param signer keyring of signer
1302 * @param collectionOptions Collection options1302 * @param collectionOptions Collection options
1303 * @example 1303 * @example
1304 * mintCollection(aliceKeyring, {1304 * mintCollection(aliceKeyring, {
1305 * name: 'New',1305 * name: 'New',
1306 * description: 'New collection',1306 * description: 'New collection',
1307 * tokenPrefix: 'NEW',1307 * tokenPrefix: 'NEW',
1308 * })1308 * })
1309 * @returns object of the created collection1309 * @returns object of the created collection
1310 */1310 */
1311 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions): Promise<UniqueNFTCollection> {1311 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions): Promise<UniqueNFTCollection> {
1312 return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1312 return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;
1313 }1313 }
1334 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1334 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
1335 }1335 }
13361336
1337 /**1337 /**
1338 * Mint multiple NFT tokens1338 * Mint multiple NFT tokens
1339 * @param signer keyring of signer1339 * @param signer keyring of signer
1340 * @param collectionId ID of collection1340 * @param collectionId ID of collection
1341 * @param tokens array of tokens with owner and properties1341 * @param tokens array of tokens with owner and properties
1342 * @example 1342 * @example
1343 * mintMultipleTokens(aliceKeyring, 10, [{1343 * mintMultipleTokens(aliceKeyring, 10, [{
1344 * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1344 * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},
1345 * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1345 * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],
1346 * },{1346 * },{
1347 * owner: {Ethereum: "0x9F0583DbB855d..."},1347 * owner: {Ethereum: "0x9F0583DbB855d..."},
1348 * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1348 * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],
1349 * }]);1349 * }]);
1350 * @returns ```true``` if extrinsic success, otherwise ```false```1350 * @returns ```true``` if extrinsic success, otherwise ```false```
1351 */1351 */
1352 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFTToken[]> {1352 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFTToken[]> {
1353 const creationResult = await this.helper.executeExtrinsic(1353 const creationResult = await this.helper.executeExtrinsic(
1354 signer,1354 signer,
1392 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1392 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
1393 }1393 }
1394
1395 /**
1396 * Destroys a concrete instance of NFT.
1397 * @param signer keyring of signer
1398 * @param collectionId ID of collection
1399 * @param tokenId ID of token
1400 * @example burnToken(aliceKeyring, 10, 5);
1401 * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null```
1402 */
1403 async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number): Promise<{ success: boolean; token: number | null; }> {
1404 return await super.burnToken(signer, collectionId, tokenId, 1n);
1405 }
14061394
1407 /**1395 /**
1408 * Set, change, or remove approved address to transfer the ownership of the NFT.1396 * Set, change, or remove approved address to transfer the ownership of the NFT.
1409 * 1397 *
1410 * @param signer keyring of signer1398 * @param signer keyring of signer
1411 * @param collectionId ID of collection1399 * @param collectionId ID of collection
1412 * @param tokenId ID of token1400 * @param tokenId ID of token
1413 * @param toAddressObj address to approve1401 * @param toAddressObj address to approve
1414 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1402 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})
1415 * @returns ```true``` if extrinsic success, otherwise ```false```1403 * @returns ```true``` if extrinsic success, otherwise ```false```
1416 */1404 */
1417 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1405 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {
1418 return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1406 return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);
1419 }1407 }
1442 return new UniqueRFTToken(tokenId, this.getCollectionObject(collectionId));1430 return new UniqueRFTToken(tokenId, this.getCollectionObject(collectionId));
1443 }1431 }
14441432
1445 /**1433 /**
1446 * Get top 10 token owners with the largest number of pieces 1434 * Get top 10 token owners with the largest number of pieces
1447 * @param collectionId ID of collection1435 * @param collectionId ID of collection
1448 * @param tokenId ID of token1436 * @param tokenId ID of token
1449 * @example getTokenTop10Owners(10, 5);1437 * @example getTokenTop10Owners(10, 5);
1450 * @returns array of top 10 owners1438 * @returns array of top 10 owners
1451 */1439 */
1452 async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<ICrossAccountId[]> {1440 async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<ICrossAccountId[]> {
1453 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(crossAccountIdFromLower);1441 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(crossAccountIdFromLower);
1454 }1442 }
1479 return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1467 return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);
1480 }1468 }
14811469
1482 /**1470 /**
1483 * Change ownership of some pieces of RFT on behalf of the owner. 1471 * Change ownership of some pieces of RFT on behalf of the owner.
1484 * @param signer keyring of signer1472 * @param signer keyring of signer
1485 * @param collectionId ID of collection1473 * @param collectionId ID of collection
1486 * @param tokenId ID of token1474 * @param tokenId ID of token
1487 * @param fromAddressObj address on behalf of which the token will be sent1475 * @param fromAddressObj address on behalf of which the token will be sent
1488 * @param toAddressObj new token owner1476 * @param toAddressObj new token owner
1489 * @param amount number of pieces to be transfered1477 * @param amount number of pieces to be transfered
1490 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1478 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)
1491 * @returns ```true``` if extrinsic success, otherwise ```false```1479 * @returns ```true``` if extrinsic success, otherwise ```false```
1492 */1480 */
1493 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1481 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {
1494 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1482 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);
1495 }1483 }
1582 return await super.burnToken(signer, collectionId, tokenId, amount);1570 return await super.burnToken(signer, collectionId, tokenId, amount);
1583 }1571 }
15841572
1585 /**1573 /**
1586 * Set, change, or remove approved address to transfer the ownership of the RFT.1574 * Set, change, or remove approved address to transfer the ownership of the RFT.
1587 * 1575 *
1588 * @param signer keyring of signer1576 * @param signer keyring of signer
1589 * @param collectionId ID of collection1577 * @param collectionId ID of collection
1590 * @param tokenId ID of token1578 * @param tokenId ID of token
1591 * @param toAddressObj address to approve1579 * @param toAddressObj address to approve
1592 * @param amount number of pieces to be approved1580 * @param amount number of pieces to be approved
1593 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1581 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);
1594 * @returns true if the token success, otherwise false1582 * @returns true if the token success, otherwise false
1595 */1583 */
1596 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1584 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {
1597 return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1585 return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);
1598 }1586 }
1641 return new UniqueFTCollection(collectionId, this.helper);1629 return new UniqueFTCollection(collectionId, this.helper);
1642 }1630 }
16431631
1644 /**1632 /**
1645 * Mint new fungible collection1633 * Mint new fungible collection
1646 * @param signer keyring of signer1634 * @param signer keyring of signer
1647 * @param collectionOptions Collection options1635 * @param collectionOptions Collection options
1648 * @param decimalPoints number of token decimals 1636 * @param decimalPoints number of token decimals
1649 * @example1637 * @example
1650 * mintCollection(aliceKeyring, {1638 * mintCollection(aliceKeyring, {
1651 * name: 'New',1639 * name: 'New',
1652 * description: 'New collection',1640 * description: 'New collection',
1653 * tokenPrefix: 'NEW',1641 * tokenPrefix: 'NEW',
1654 * }, 18)1642 * }, 18)
1655 * @returns newly created fungible collection1643 * @returns newly created fungible collection
1656 */1644 */
1657 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, decimalPoints = 0): Promise<UniqueFTCollection> {1645 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, decimalPoints = 0): Promise<UniqueFTCollection> {
1658 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1646 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
1659 if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');1647 if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');
1669 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1657 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
1670 }1658 }
16711659
1672 /**1660 /**
1673 * Mint tokens1661 * Mint tokens
1674 * @param signer keyring of signer1662 * @param signer keyring of signer
1675 * @param collectionId ID of collection1663 * @param collectionId ID of collection
1676 * @param owner address owner of new tokens1664 * @param owner address owner of new tokens
1677 * @param amount amount of tokens to be meanted1665 * @param amount amount of tokens to be meanted
1678 * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);1666 * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);
1679 * @returns ```true``` if extrinsic success, otherwise ```false``` 1667 * @returns ```true``` if extrinsic success, otherwise ```false```
1680 */1668 */
1681 async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {1669 async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {
1682 const creationResult = await this.helper.executeExtrinsic(1670 const creationResult = await this.helper.executeExtrinsic(
1683 signer,1671 signer,
1691 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');1679 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
1692 }1680 }
16931681
1694 /**1682 /**
1695 * Mint multiple Fungible tokens with one owner1683 * Mint multiple Fungible tokens with one owner
1696 * @param signer keyring of signer1684 * @param signer keyring of signer
1697 * @param collectionId ID of collection1685 * @param collectionId ID of collection
1698 * @param owner tokens owner1686 * @param owner tokens owner
1699 * @param tokens array of tokens with properties and pieces1687 * @param tokens array of tokens with properties and pieces
1700 * @returns ```true``` if extrinsic success, otherwise ```false``` 1688 * @returns ```true``` if extrinsic success, otherwise ```false```
1701 */1689 */
1702 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {1690 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {
1703 const rawTokens = [];1691 const rawTokens = [];
1704 for (const token of tokens) {1692 for (const token of tokens) {
1713 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');1701 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');
1714 }1702 }
17151703
1716 /**1704 /**
1717 * Get the top 10 owners with the largest balance for the Fungible collection 1705 * Get the top 10 owners with the largest balance for the Fungible collection
1718 * @param collectionId ID of collection1706 * @param collectionId ID of collection
1719 * @example getTop10Owners(10);1707 * @example getTop10Owners(10);
1720 * @returns array of ```ICrossAccountId```1708 * @returns array of ```ICrossAccountId```
1721 */1709 */
1722 async getTop10Owners(collectionId: number): Promise<ICrossAccountId[]> {1710 async getTop10Owners(collectionId: number): Promise<ICrossAccountId[]> {
1723 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(crossAccountIdFromLower);1711 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(crossAccountIdFromLower);
1724 }1712 }
1734 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();1722 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();
1735 }1723 }
17361724
1737 /**1725 /**
1738 * Transfer tokens to address1726 * Transfer tokens to address
1739 * @param signer keyring of signer1727 * @param signer keyring of signer
1740 * @param collectionId ID of collection1728 * @param collectionId ID of collection
1741 * @param toAddressObj address recipient1729 * @param toAddressObj address recipient
1742 * @param amount amount of tokens to be sent1730 * @param amount amount of tokens to be sent
1743 * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);1731 * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
1744 * @returns ```true``` if extrinsic success, otherwise ```false``` 1732 * @returns ```true``` if extrinsic success, otherwise ```false```
1745 */1733 */
1746 async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {1734 async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {
1747 return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);1735 return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);
1748 }1736 }
17491737
1750 /**1738 /**
1751 * Transfer some tokens on behalf of the owner.1739 * Transfer some tokens on behalf of the owner.
1752 * @param signer keyring of signer1740 * @param signer keyring of signer
1753 * @param collectionId ID of collection1741 * @param collectionId ID of collection
1754 * @param fromAddressObj address on behalf of which tokens will be sent1742 * @param fromAddressObj address on behalf of which tokens will be sent
1755 * @param toAddressObj address where token to be sent1743 * @param toAddressObj address where token to be sent
1756 * @param amount number of tokens to be sent1744 * @param amount number of tokens to be sent
1757 * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);1745 * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);
1758 * @returns ```true``` if extrinsic success, otherwise ```false``` 1746 * @returns ```true``` if extrinsic success, otherwise ```false```
1759 */1747 */
1760 async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {1748 async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {
1761 return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);1749 return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);
1762 }1750 }
17631751
1764 /**1752 /**
1765 * Destroy some amount of tokens1753 * Destroy some amount of tokens
1766 * @param signer keyring of signer1754 * @param signer keyring of signer
1767 * @param collectionId ID of collection1755 * @param collectionId ID of collection
1768 * @param amount amount of tokens to be destroyed1756 * @param amount amount of tokens to be destroyed
1769 * @example burnTokens(aliceKeyring, 10, 1000n);1757 * @example burnTokens(aliceKeyring, 10, 1000n);
1770 * @returns ```true``` if extrinsic success, otherwise ```false``` 1758 * @returns ```true``` if extrinsic success, otherwise ```false```
1771 */1759 */
1772 async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {1760 async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {
1773 return (await super.burnToken(signer, collectionId, 0, amount)).success;1761 return (await super.burnToken(signer, collectionId, 0, amount)).success;
1774 }1762 }
17751763
1776 /**1764 /**
1777 * Burn some tokens on behalf of the owner.1765 * Burn some tokens on behalf of the owner.
1778 * @param signer keyring of signer1766 * @param signer keyring of signer
1779 * @param collectionId ID of collection1767 * @param collectionId ID of collection
1780 * @param fromAddressObj address on behalf of which tokens will be burnt1768 * @param fromAddressObj address on behalf of which tokens will be burnt
1781 * @param amount amount of tokens to be burnt1769 * @param amount amount of tokens to be burnt
1782 * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);1770 * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);
1783 * @returns ```true``` if extrinsic success, otherwise ```false``` 1771 * @returns ```true``` if extrinsic success, otherwise ```false```
1784 */1772 */
1785 async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1773 async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {
1786 return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, amount);1774 return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, amount);
1787 }1775 }
17881776
1789 /**1777 /**
1790 * Get total collection supply1778 * Get total collection supply
1791 * @param collectionId 1779 * @param collectionId
1792 * @returns 1780 * @returns
1793 */1781 */
1794 async getTotalPieces(collectionId: number): Promise<bigint> {1782 async getTotalPieces(collectionId: number): Promise<bigint> {
1795 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();1783 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();
1796 }1784 }
17971785
1798 /**1786 /**
1799 * Set, change, or remove approved address to transfer tokens.1787 * Set, change, or remove approved address to transfer tokens.
1800 * 1788 *
1801 * @param signer keyring of signer1789 * @param signer keyring of signer
1802 * @param collectionId ID of collection1790 * @param collectionId ID of collection
1803 * @param toAddressObj address to be approved1791 * @param toAddressObj address to be approved
1804 * @param amount amount of tokens to be approved1792 * @param amount amount of tokens to be approved
1805 * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)1793 * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)
1806 * @returns ```true``` if extrinsic success, otherwise ```false``` 1794 * @returns ```true``` if extrinsic success, otherwise ```false```
1807 */1795 */
1808 async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {1796 async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {
1809 return super.approveToken(signer, collectionId, 0, toAddressObj, amount);1797 return super.approveToken(signer, collectionId, 0, toAddressObj, amount);
1810 }1798 }
1898 return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();1886 return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();
1899 }1887 }
19001888
1901 /**1889 /**
1902 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved1890 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved
1903 * @param address substrate address1891 * @param address substrate address
1904 * @returns 1892 * @returns
1905 */1893 */
1906 async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {1894 async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {
1907 const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;1895 const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;
1908 return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};1896 return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};