git.delta.rocks / unique-network / refs/commits / 415e2e02d914

difftreelog

tests(nesting+properties): collection and token interfaces + make lower case not default for token addresses + more consts from old helpers included

Fahrrader2022-09-27parent: #b0b1d40.patch.diff
in: master

8 files changed

modifiedtests/src/fungible.test.tsdiffbeforeafterboth
--- a/tests/src/fungible.test.ts
+++ b/tests/src/fungible.test.ts
@@ -15,9 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util/playgrounds';
-
-const U128_MAX = (1n << 128n) - 1n;
+import {itSub, usingPlaygrounds, expect, U128_MAX} from './util/playgrounds';
 
 describe('integration test: Fungible functionality:', () => {
   let alice: IKeyringPair;
modifiedtests/src/nesting/graphs.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/graphs.test.ts
+++ b/tests/src/nesting/graphs.test.ts
@@ -16,7 +16,8 @@
 
 import {IKeyringPair} from '@polkadot/types/types';
 import {expect, itSub, usingPlaygrounds} from '../util/playgrounds';
-import {UniqueHelper, UniqueNFTToken} from '../util/playgrounds/unique';
+import {ITokenNonfungible} from '../util/playgrounds/types';
+import {UniqueHelper} from '../util/playgrounds/unique';
 
 /**
  * ```dot
@@ -25,7 +26,7 @@
  * 8 -> 5
  * ```
  */
-async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<UniqueNFTToken[]> {
+async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<ITokenNonfungible[]> {
   const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
   const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
 
modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -35,7 +35,7 @@
     // Create an immediately nested token
     const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
     
     // Create a token to be nested
     const newToken = await collection.mintToken(alice);
@@ -43,14 +43,14 @@
     // Nest
     await newToken.nest(alice, targetToken);
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Move bundle to different user
     await targetToken.transfer(alice, {Substrate: bob.address});
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Unnest
     await newToken.unnest(bob, targetToken, {Substrate: bob.address});
@@ -65,12 +65,12 @@
 
     // Create a nested token
     const tokenC = await collection.mintToken(alice, tokenA.nestingAccount());
-    expect(await tokenC.getOwner()).to.be.deep.equal(tokenA.nestingAccount());
+    expect(await tokenC.getOwner()).to.be.deep.equal(tokenA.nestingAccountInLowerCase());
     
     // Transfer the nested token to another token
     await expect(tokenC.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount())).to.be.fulfilled;
     expect(await tokenC.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
-    expect(await tokenC.getOwner()).to.be.deep.equal(tokenB.nestingAccount());
+    expect(await tokenC.getOwner()).to.be.deep.equal(tokenB.nestingAccountInLowerCase());
   });
 
   itSub('Checks token children', async ({helper}) => {
@@ -150,13 +150,13 @@
     // Create an immediately nested token
     const nestedToken = await collection.mintToken(bob, targetToken.nestingAccount());
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Create a token to be nested and nest
     const newToken = await collection.mintToken(bob);
     await newToken.nest(bob, targetToken);
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   itSub('Admin (NFT): Admin and Token Owner can operate together', async ({helper}) => {
@@ -167,13 +167,13 @@
     // Create an immediately nested token by an administrator
     const nestedToken = await collection.mintToken(bob, targetToken.nestingAccount());
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Create a token to be nested and nest
     const newToken = await collection.mintToken(alice, {Substrate: charlie.address});
     await newToken.nest(charlie, targetToken);
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   itSub('Admin (NFT): allows an Admin to nest a token (Restricted nesting)', async ({helper}) => {
@@ -187,13 +187,13 @@
     // Create an immediately nested token
     const nestedToken = await collectionB.mintToken(bob, targetToken.nestingAccount());
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Create a token to be nested and nest
     const newToken = await collectionB.mintToken(bob);
     await newToken.nest(bob, targetToken);
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   // ---------- Non-Fungible ----------
@@ -207,13 +207,13 @@
     // Create an immediately nested token
     const nestedToken = await collection.mintToken(charlie, targetToken.nestingAccount());
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Create a token to be nested and nest
     const newToken = await collection.mintToken(charlie);
     await newToken.nest(charlie, targetToken);
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   itSub('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {
@@ -233,13 +233,13 @@
     // Create an immediately nested token
     const nestedToken = await collectionB.mintToken(charlie, targetToken.nestingAccount());
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Create a token to be nested and nest
     const newToken = await collectionB.mintToken(charlie);
     await newToken.nest(charlie, targetToken);
     expect(await newToken.getTopmostOwner()).to.be.deep.equal({Substrate: charlie.address});
-    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   // ---------- Fungible ----------
@@ -424,7 +424,7 @@
 
     expect(await targetToken.getChildren()).to.be.length(1);
     expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   itSub('Admin (NFT): disallows an Admin to nest a token from an unlisted collection (Restricted nesting)', async ({helper}) => {
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -14,19 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-/*import usingApi, {executeTransaction} from '../substrate/substrate-api';
-import {
-  addCollectionAdminExpectSuccess,
-  CollectionMode,
-  createCollectionExpectSuccess,
-  setCollectionPermissionsExpectSuccess,
-  createItemExpectSuccess,
-  getCreateCollectionResult,
-  transferExpectSuccess,
-} from '../util/helpers';*/
 import {IKeyringPair} from '@polkadot/types/types';
 import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../util/playgrounds';
-import {UniqueCollectionBase, UniqueHelper, UniqueNFTCollection, UniqueNFTToken, UniqueRFTCollection, UniqueRFTToken} from '../util/playgrounds/unique';
+import {ICollectionBase, ICollectionNFT, ITokenNonfungible, ICollectionRFT, ITokenRefungible} from '../util/playgrounds/types';
+import {UniqueHelper} from '../util/playgrounds/unique';
 
 // ---------- COLLECTION PROPERTIES
 
@@ -46,7 +37,7 @@
     expect(await collection.getProperties()).to.be.empty;
   });
 
-  async function testSetsPropertiesForCollection(collection: UniqueCollectionBase) {
+  async function testSetsPropertiesForCollection(collection: ICollectionBase) {
     // As owner
     await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;
 
@@ -70,7 +61,7 @@
     await testSetsPropertiesForCollection(await helper.rft.mintCollection(alice));
   });
 
-  async function testCheckValidNames(collection: UniqueCollectionBase) {
+  async function testCheckValidNames(collection: ICollectionBase) {
     // alpha symbols
     await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;
 
@@ -104,7 +95,7 @@
     await testCheckValidNames(await helper.rft.mintCollection(alice));
   });
 
-  async function testChangesProperties(collection: UniqueCollectionBase) {
+  async function testChangesProperties(collection: ICollectionBase) {
     await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;
 
     // Mutate the properties
@@ -125,7 +116,7 @@
     await testChangesProperties(await helper.rft.mintCollection(alice));
   });
 
-  async function testDeleteProperties(collection: UniqueCollectionBase) {
+  async function testDeleteProperties(collection: ICollectionBase) {
     await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
 
     await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled;
@@ -156,7 +147,7 @@
     });
   });
   
-  async function testFailsSetPropertiesIfNotOwnerOrAdmin(collection: UniqueCollectionBase) {  
+  async function testFailsSetPropertiesIfNotOwnerOrAdmin(collection: ICollectionBase) {  
     await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))
       .to.be.rejectedWith(/common\.NoPermission/);
 
@@ -171,7 +162,7 @@
     await testFailsSetPropertiesIfNotOwnerOrAdmin(await helper.rft.mintCollection(alice));
   });
   
-  async function testFailsSetPropertiesThatExeedLimits(collection: UniqueCollectionBase) {
+  async function testFailsSetPropertiesThatExeedLimits(collection: ICollectionBase) {
     const spaceLimit = (await (collection.helper!.api! as any).query.common.collectionProperties(collection.collectionId)).spaceLimit.toNumber();
   
     // Mute the general tx parsing error, too many bytes to process
@@ -200,7 +191,7 @@
     await testFailsSetPropertiesThatExeedLimits(await helper.rft.mintCollection(alice));
   });
   
-  async function testFailsSetMorePropertiesThanAllowed(collection: UniqueCollectionBase) {
+  async function testFailsSetMorePropertiesThanAllowed(collection: ICollectionBase) {
     const propertiesToBeSet = [];
     for (let i = 0; i < 65; i++) {
       propertiesToBeSet.push({
@@ -223,7 +214,7 @@
     await testFailsSetMorePropertiesThanAllowed(await helper.rft.mintCollection(alice));
   });
   
-  async function testFailsSetPropertiesWithInvalidNames(collection: UniqueCollectionBase) {
+  async function testFailsSetPropertiesWithInvalidNames(collection: ICollectionBase) {
     const invalidProperties = [
       [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
       [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
@@ -290,7 +281,7 @@
     expect(propertyRights).to.be.empty;
   });
   
-  async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {  
+  async function testSetsAccessRightsToProperties(collection: ICollectionNFT | ICollectionRFT) {  
     await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}]))
       .to.be.fulfilled;
 
@@ -314,7 +305,7 @@
     await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice));
   });
   
-  async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) {
+  async function testChangesAccessRightsToProperty(collection: ICollectionNFT | ICollectionRFT) {
     await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]))
       .to.be.fulfilled;
 
@@ -347,7 +338,7 @@
     });
   });
 
-  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) {
+  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: ICollectionNFT | ICollectionRFT) {
     await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]))
       .to.be.rejectedWith(/common\.NoPermission/);
 
@@ -363,7 +354,7 @@
     await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice));
   });
 
-  async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {  
+  async function testPreventFromAddingTooManyPossibleProperties(collection: ICollectionNFT | ICollectionRFT) {  
     const constitution = [];
     for (let i = 0; i < 65; i++) {
       constitution.push({
@@ -387,7 +378,7 @@
     await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice));
   });
 
-  async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) {
+  async function testPreventAccessRightsModifiedIfConstant(collection: ICollectionNFT | ICollectionRFT) {
     await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
       .to.be.fulfilled;
 
@@ -408,7 +399,7 @@
     await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice));
   });
 
-  async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) {
+  async function testPreventsAddingPropertiesWithInvalidNames(collection: ICollectionNFT | ICollectionRFT) {
     const invalidProperties = [
       [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
       [{key: 'G#4', permission: {tokenOwner: true}}],
@@ -478,7 +469,7 @@
     ];
   });
   
-  async function testReadsYetEmptyProperties(token: UniqueNFTToken | UniqueRFTToken) {
+  async function testReadsYetEmptyProperties(token: ITokenNonfungible | ITokenRefungible) {
     const properties = await token.getProperties();
     expect(properties).to.be.empty;
 
@@ -498,7 +489,7 @@
     await testReadsYetEmptyProperties(token);
   });
 
-  async function testAssignPropertiesAccordingToPermissions(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testAssignPropertiesAccordingToPermissions(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -544,7 +535,7 @@
     await testAssignPropertiesAccordingToPermissions(token, 100n);
   });
 
-  async function testChangesPropertiesAccordingPermission(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testChangesPropertiesAccordingPermission(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -597,7 +588,7 @@
     await testChangesPropertiesAccordingPermission(token, 100n);
   });
 
-  async function testDeletePropertiesAccordingPermission(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testDeletePropertiesAccordingPermission(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -808,7 +799,7 @@
     return (await (mode == 'NFT' ? api.query.nonfungible : api.query.refungible).tokenProperties(collectionId, tokenId)).toJSON().consumedSpace;
   }
 
-  async function prepare(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint): Promise<number> {
+  async function prepare(token: ITokenNonfungible | ITokenRefungible, pieces: bigint): Promise<number> {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -832,7 +823,7 @@
     return originalSpace;
   }
 
-  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     let i = 0;
@@ -867,7 +858,7 @@
     await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, 100n);
   });
 
-  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     let i = 0;
@@ -902,7 +893,7 @@
     await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, 100n);
   });
 
-  async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     await expect(
@@ -938,7 +929,7 @@
     await testForbidsAddingPropertiesIfPropertyNotDeclared(token, 100n);
   });
 
-  async function testForbidsAddingTooManyProperties(token: UniqueNFTToken | UniqueRFTToken, pieces: bigint) {
+  async function testForbidsAddingTooManyProperties(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     await expect(
@@ -993,7 +984,7 @@
     });
   });
 
-  async function prepare(helper: UniqueHelper): Promise<UniqueRFTToken> {
+  async function prepare(helper: UniqueHelper): Promise<ITokenRefungible> {
     const collection = await helper.rft.mintCollection(alice);
     const token = await collection.mintToken(alice, 100n);
     
modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/unnest.test.ts
+++ b/tests/src/nesting/unnest.test.ts
@@ -105,11 +105,11 @@
 
     // Try to unnest
     await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
 
     // Try to burn
     await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
-    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount());
+    expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccountInLowerCase());
   });
 
   // todo another test for creating excessive depth matryoshka with Ethereum?
modifiedtests/src/util/playgrounds/index.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/index.ts
+++ b/tests/src/util/playgrounds/index.ts
@@ -9,10 +9,16 @@
 import '../../interfaces/augment-api-events';
 import {DevUniqueHelper, SilentLogger, SilentConsole} from './unique.dev';
 
-
 chai.use(chaiAsPromised);
 export const expect = chai.expect;
 
+export const U128_MAX = (1n << 128n) - 1n;
+
+const MICROUNIQUE = 1_000_000_000_000n;
+const MILLIUNIQUE = 1_000n * MICROUNIQUE;
+const CENTIUNIQUE = 10n * MILLIUNIQUE;
+export const UNIQUE = 100n * CENTIUNIQUE;
+
 export const usingPlaygrounds = async (code: (helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>, url: string = config.substrateUrl) => {
   const silentConsole = new SilentConsole();
   silentConsole.enable();
modifiedtests/src/util/playgrounds/types.tsdiffbeforeafterboth
before · tests/src/util/playgrounds/types.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034import {IKeyringPair} from '@polkadot/types/types';56export interface IEvent {7  section: string;8  method: string;9  index: [number, number] | string;10  data: any[];11  phase: {applyExtrinsic: number} | 'Initialization',12}1314export interface ITransactionResult {15  status: 'Fail' | 'Success';16  result: {17      events: {18        phase: any, // {ApplyExtrinsic: number} | 'Initialization',19        event: IEvent;20      }[];21  },22  moduleError?: string;23}2425export interface ISubscribeBlockEventsData {26  number: number;27  hash: string;28  timestamp: number; 29  events: IEvent[];30}3132export interface ILogger {33  log: (msg: any, level?: string) => void;34  level: {35    ERROR: 'ERROR';36    WARNING: 'WARNING';37    INFO: 'INFO';38    [key: string]: string;39  }40}4142export interface IUniqueHelperLog {43  executedAt: number;44  executionTime: number;45  type: 'extrinsic' | 'rpc';46  status: 'Fail' | 'Success';47  call: string;48  params: any[];49  moduleError?: string;50  events?: any;51}5253export interface IApiListeners {54  connected?: (...args: any[]) => any;55  disconnected?: (...args: any[]) => any;56  error?: (...args: any[]) => any;57  ready?: (...args: any[]) => any; 58  decorated?: (...args: any[]) => any;59}6061export interface ICrossAccountId {62  Substrate?: TSubstrateAccount;63  Ethereum?: TEthereumAccount;64}6566export interface ICrossAccountIdLower {67  substrate?: TSubstrateAccount;68  ethereum?: TEthereumAccount;69}7071export interface ICollectionLimits {72  accountTokenOwnershipLimit?: number | null;73  sponsoredDataSize?: number | null;74  sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;75  tokenLimit?: number | null;76  sponsorTransferTimeout?: number | null;77  sponsorApproveTimeout?: number | null;78  ownerCanTransfer?: boolean | null;79  ownerCanDestroy?: boolean | null;80  transfersEnabled?: boolean | null;81}8283export interface INestingPermissions {84  tokenOwner?: boolean;85  collectionAdmin?: boolean;86  restricted?: number[] | null;87}8889export interface ICollectionPermissions {90  access?: 'Normal' | 'AllowList';91  mintMode?: boolean;92  nesting?: INestingPermissions;93}9495export interface IProperty {96  key: string;97  value?: string;98}99100export interface ITokenPropertyPermission {101  key: string;102  permission: {103    mutable?: boolean;104    tokenOwner?: boolean;105    collectionAdmin?: boolean;106  }107}108109export interface IToken {110  collectionId: number;111  tokenId: number;112}113114export interface IBlock {115  extrinsics: IExtrinsic[]116  header: {117    parentHash: string,118    number: number,119  };120}121122export interface IExtrinsic {123  isSigned: boolean,124  method: {125    method: string,126    section: string,127    args: any[]128  }129}130131export interface ICollectionCreationOptions {132  name?: string | number[];133  description?: string | number[];134  tokenPrefix?: string | number[];135  mode?: {136    nft?: null;137    refungible?: null;138    fungible?: number;139  }140  permissions?: ICollectionPermissions;141  properties?: IProperty[];142  tokenPropertyPermissions?: ITokenPropertyPermission[];143  limits?: ICollectionLimits;144  pendingSponsor?: TSubstrateAccount;145}146147export interface IChainProperties {148  ss58Format: number;149  tokenDecimals: number[];150  tokenSymbol: string[]151}152153export interface ISubstrateBalance {154  free: bigint,155  reserved: bigint,156  miscFrozen: bigint,157  feeFrozen: bigint158}159160export interface IStakingInfo {161  block: bigint,162  amount: bigint,163}164165export type TSubstrateAccount = string;166export type TEthereumAccount = string;167export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';168export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';169export type TSigner = IKeyringPair; // | 'string'
after · tests/src/util/playgrounds/types.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034import {IKeyringPair} from '@polkadot/types/types';5import {UniqueHelper} from './unique';67export interface IEvent {8  section: string;9  method: string;10  index: [number, number] | string;11  data: any[];12  phase: {applyExtrinsic: number} | 'Initialization',13}1415export interface ITransactionResult {16  status: 'Fail' | 'Success';17  result: {18      events: {19        phase: any, // {ApplyExtrinsic: number} | 'Initialization',20        event: IEvent;21      }[];22  },23  moduleError?: string;24}2526export interface ISubscribeBlockEventsData {27  number: number;28  hash: string;29  timestamp: number; 30  events: IEvent[];31}3233export interface ILogger {34  log: (msg: any, level?: string) => void;35  level: {36    ERROR: 'ERROR';37    WARNING: 'WARNING';38    INFO: 'INFO';39    [key: string]: string;40  }41}4243export interface IUniqueHelperLog {44  executedAt: number;45  executionTime: number;46  type: 'extrinsic' | 'rpc';47  status: 'Fail' | 'Success';48  call: string;49  params: any[];50  moduleError?: string;51  events?: any;52}5354export interface IApiListeners {55  connected?: (...args: any[]) => any;56  disconnected?: (...args: any[]) => any;57  error?: (...args: any[]) => any;58  ready?: (...args: any[]) => any; 59  decorated?: (...args: any[]) => any;60}6162export interface ICrossAccountId {63  Substrate?: TSubstrateAccount;64  Ethereum?: TEthereumAccount;65}6667export interface ICrossAccountIdLower {68  substrate?: TSubstrateAccount;69  ethereum?: TEthereumAccount;70}7172export interface ICollectionLimits {73  accountTokenOwnershipLimit?: number | null;74  sponsoredDataSize?: number | null;75  sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;76  tokenLimit?: number | null;77  sponsorTransferTimeout?: number | null;78  sponsorApproveTimeout?: number | null;79  ownerCanTransfer?: boolean | null;80  ownerCanDestroy?: boolean | null;81  transfersEnabled?: boolean | null;82}8384export interface INestingPermissions {85  tokenOwner?: boolean;86  collectionAdmin?: boolean;87  restricted?: number[] | null;88}8990export interface ICollectionPermissions {91  access?: 'Normal' | 'AllowList';92  mintMode?: boolean;93  nesting?: INestingPermissions;94}9596export interface IProperty {97  key: string;98  value?: string;99}100101export interface ITokenPropertyPermission {102  key: string;103  permission: {104    mutable?: boolean;105    tokenOwner?: boolean;106    collectionAdmin?: boolean;107  }108}109110export interface ITokenAddress {111  collectionId: number;112  tokenId: number;113}114115export interface IBlock {116  extrinsics: IExtrinsic[]117  header: {118    parentHash: string,119    number: number,120  };121}122123export interface IExtrinsic {124  isSigned: boolean,125  method: {126    method: string,127    section: string,128    args: any[]129  }130}131132export interface ICollectionCreationOptions {133  name?: string | number[];134  description?: string | number[];135  tokenPrefix?: string | number[];136  mode?: {137    nft?: null;138    refungible?: null;139    fungible?: number;140  }141  permissions?: ICollectionPermissions;142  properties?: IProperty[];143  tokenPropertyPermissions?: ITokenPropertyPermission[];144  limits?: ICollectionLimits;145  pendingSponsor?: TSubstrateAccount;146}147148export interface IChainProperties {149  ss58Format: number;150  tokenDecimals: number[];151  tokenSymbol: string[]152}153154export interface ISubstrateBalance {155  free: bigint,156  reserved: bigint,157  miscFrozen: bigint,158  feeFrozen: bigint159}160161export interface IStakingInfo {162  block: bigint,163  amount: bigint,164}165166export type TSubstrateAccount = string;167export type TEthereumAccount = string;168export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';169export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';170export type TSigner = IKeyringPair; // | 'string'171172export interface ICollectionBase {173  helper: UniqueHelper;174  collectionId: number;175  getData: () => Promise<{176    id: number;177    name: string;178    description: string;179    tokensCount: number;180    admins: ICrossAccountId[];181    normalizedOwner: TSubstrateAccount;182    raw: any183  } | null>;184  getLastTokenId: () => Promise<number>;185  isTokenExists: (tokenId: number) => Promise<boolean>;186  getAdmins: () => Promise<ICrossAccountId[]>;187  getAllowList: () => Promise<ICrossAccountId[]>;188  getEffectiveLimits: () => Promise<ICollectionLimits>;189  getProperties: (propertyKeys?: string[]) => Promise<IProperty[]>;190  getTokenNextSponsored: (tokenId: number, addressObj: ICrossAccountId) => Promise<number | null>;191  setSponsor: (signer: TSigner, sponsorAddress: TSubstrateAccount) => Promise<boolean>;192  confirmSponsorship: (signer: TSigner) => Promise<boolean>;193  removeSponsor: (signer: TSigner) => Promise<boolean>;194  setLimits: (signer: TSigner, limits: ICollectionLimits) => Promise<boolean>;195  changeOwner: (signer: TSigner, ownerAddress: TSubstrateAccount) => Promise<boolean>;196  addAdmin: (signer: TSigner, adminAddressObj: ICrossAccountId) => Promise<boolean>;197  addToAllowList: (signer: TSigner, addressObj: ICrossAccountId) => Promise<boolean>;198  removeFromAllowList: (signer: TSigner, addressObj: ICrossAccountId) => Promise<boolean>;199  removeAdmin: (signer: TSigner, adminAddressObj: ICrossAccountId) => Promise<boolean>;200  setProperties: (signer: TSigner, properties: IProperty[]) => Promise<boolean>;201  deleteProperties: (signer: TSigner, propertyKeys: string[]) => Promise<boolean>;202  setPermissions: (signer: TSigner, permissions: ICollectionPermissions) => Promise<boolean>;203  enableNesting: (signer: TSigner, permissions: INestingPermissions) => Promise<boolean>;204  disableNesting: (signer: TSigner) => Promise<boolean>;205  burn: (signer: TSigner) => Promise<boolean>;206}207208export interface ICollectionNFT extends ICollectionBase {209  getTokenObject: (tokenId: number) => ITokenNonfungible; // todo:playgrounds210  getTokensByAddress: (addressObj: ICrossAccountId) => Promise<number[]>;211  getToken: (tokenId: number, blockHashAt?: string) => Promise<{212    properties: IProperty[];213    owner: ICrossAccountId;214    normalizedOwner: ICrossAccountId;215  }| null>;216  getTokenOwner: (tokenId: number, blockHashAt?: string) => Promise<ICrossAccountId>;217  getTokenTopmostOwner: (tokenId: number, blockHashAt?: string) => Promise<ICrossAccountId | null>;218  getTokenChildren: (tokenId: number, blockHashAt?: string) => Promise<ITokenAddress[]>; // todo:playgrounds219  getPropertyPermissions: (propertyKeys?: string[]) => Promise<ITokenPropertyPermission[]>;220  getTokenProperties: (tokenId: number, propertyKeys?: string[]) => Promise<IProperty[]>;221  transferToken: (signer: TSigner, tokenId: number, addressObj: ICrossAccountId) => Promise<boolean>;222  transferTokenFrom: (signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) => Promise<boolean>;223  approveToken: (signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) => Promise<boolean>;224  isTokenApproved: (tokenId: number, toAddressObj: ICrossAccountId) => Promise<boolean>;225  mintToken: (signer: TSigner, owner: ICrossAccountId, properties?: IProperty[]) => Promise<ITokenNonfungible>;// todo:playgrounds226  mintMultipleTokens: (signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) => Promise<ITokenNonfungible[]>;// todo:playgrounds227  burnToken: (signer: TSigner, tokenId: number) => Promise<{228    success: boolean,229    token: number | null230  }>;231  burnTokenFrom: (signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) => Promise<boolean>;232  setTokenProperties: (signer: TSigner, tokenId: number, properties: IProperty[]) => Promise<boolean>;233  deleteTokenProperties: (signer: TSigner, tokenId: number, propertyKeys: string[]) => Promise<boolean>;234  setTokenPropertyPermissions: (signer: TSigner, permissions: ITokenPropertyPermission[]) => Promise<boolean>;235  nestToken: (signer: TSigner, tokenId: number, toTokenObj: ITokenAddress) => Promise<boolean>;236  unnestToken: (signer: TSigner, tokenId: number, fromTokenObj: ITokenAddress, toAddressObj: ICrossAccountId) => Promise<boolean>;237}238239export interface ICollectionRFT extends ICollectionBase {240  getTokenObject: (tokenId: number) => ITokenRefungible;241  getToken: (tokenId: number, blockHashAt?: string) => Promise<{242    properties: IProperty[];243    owner: ICrossAccountId;244    normalizedOwner: ICrossAccountId;245  }| null>;246  getTokensByAddress: (addressObj: ICrossAccountId) => Promise<number[]>;247  getTop10TokenOwners: (tokenId: number) => Promise<ICrossAccountId[]>;248  getTokenBalance: (tokenId: number, addressObj: ICrossAccountId) => Promise<bigint>;249  getTokenTotalPieces: (tokenId: number) => Promise<bigint>;250  getTokenApprovedPieces: (tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) => Promise<bigint>;251  getPropertyPermissions: (propertyKeys?: string[] | null) => Promise<ITokenPropertyPermission[]>;252  getTokenProperties: (tokenId: number, propertyKeys?: string[]) => Promise<IProperty[]>;253  transferToken: (signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;254  transferTokenFrom: (signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;255  approveToken: (signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;256  repartitionToken: (signer: TSigner, tokenId: number, amount: bigint) => Promise<boolean>;257  mintToken: (signer: TSigner, pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]) => Promise<ITokenRefungible>;258  mintMultipleTokens: (signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) => Promise<ITokenRefungible[]>; // todo:playgrounds259  burnToken: (signer: TSigner, tokenId: number, amount: bigint) => Promise<{260    success: boolean,261    token: number | null262  }>;263  burnTokenFrom: (signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId,  amount: bigint) => Promise<boolean>;264  setTokenProperties: (signer: TSigner, tokenId: number, properties: IProperty[]) => Promise<boolean>;265  deleteTokenProperties: (signer: TSigner, tokenId: number, propertyKeys: string[]) => Promise<boolean>;266  setTokenPropertyPermissions: (signer: TSigner, permissions: ITokenPropertyPermission[]) => Promise<boolean>;267}268269export interface ICollectionFT extends ICollectionBase {270  getBalance: (addressObj: ICrossAccountId) => Promise<bigint>;271  getTotalPieces: () => Promise<bigint>;272  getApprovedTokens: (fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) => Promise<bigint>;273  getTop10Owners: () => Promise<ICrossAccountId[]>;274  mint: (signer: TSigner, amount: bigint, owner: ICrossAccountId) => Promise<boolean>;275  mintWithOneOwner: (signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId) => Promise<boolean>;276  transfer: (signer: TSigner, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;277  transferFrom: (signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;278  burnTokens: (signer: TSigner, amount: bigint) => Promise<boolean>;279  burnTokensFrom: (signer: TSigner, fromAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;280  approveTokens: (signer: TSigner, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;281}282283export interface ITokenBase extends ITokenAddress {284  collection: ICollectionNFT | ICollectionRFT;285  getNextSponsored: (addressObj: ICrossAccountId) => Promise<number|null>;286  getProperties: (propertyKeys?: string[]) => Promise<IProperty[]>;287  setProperties: (signer: TSigner, properties: IProperty[]) => Promise<boolean>;288  deleteProperties: (signer: TSigner, propertyKeys: string[]) => Promise<boolean>;289  nestingAccount: () => ICrossAccountId;290  nestingAccountInLowerCase: () => ICrossAccountId;291}292293export interface ITokenNonfungible extends ITokenBase {294  collection: ICollectionNFT;295  getData: (blockHashAt?: string) => Promise<{296    properties: IProperty[];297    owner: ICrossAccountId;298    normalizedOwner: ICrossAccountId;299  }| null>;300  getOwner: (blockHashAt?: string) => Promise<ICrossAccountId>;301  getTopmostOwner: (blockHashAt?: string) => Promise<ICrossAccountId | null>;302  getChildren: (blockHashAt?: string) => Promise<ITokenAddress[]>; // todo:playgrounds303  nest: (signer: TSigner, toTokenObj: ITokenAddress) => Promise<boolean>;304  unnest: (signer: TSigner, fromTokenObj: ITokenAddress, toAddressObj: ICrossAccountId) => Promise<boolean>;305  transfer: (signer: TSigner, addressObj: ICrossAccountId) => Promise<boolean>;306  transferFrom: (signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) => Promise<boolean>;307  approve: (signer: TSigner, toAddressObj: ICrossAccountId) => Promise<boolean>;308  isApproved: (toAddressObj: ICrossAccountId) => Promise<boolean>;309  burn: (signer: TSigner) => Promise<{310    success: boolean,311    token: number | null312  }>;313  burnFrom: (signer: TSigner, fromAddressObj: ICrossAccountId) => Promise<boolean>;314}315316export interface ITokenRefungible extends ITokenBase {317  collection: ICollectionRFT;318  getData: (blockHashAt?: string) => Promise<{319    properties: IProperty[];320    owner: ICrossAccountId;321    normalizedOwner: ICrossAccountId;322  }| null>;323  getTop10Owners: () => Promise<ICrossAccountId[]>;324  getBalance: (addressObj: ICrossAccountId) => Promise<bigint>;325  getTotalPieces: () => Promise<bigint>;326  getApprovedPieces: (fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) => Promise<bigint>;327  transfer: (signer: TSigner, addressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;328  transferFrom: (signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;329  approve: (signer: TSigner, toAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;330  repartition: (signer: TSigner, amount: bigint) => Promise<boolean>;331  burn: (signer: TSigner, amount: bigint) => Promise<{332    success: boolean,333    token: number | null334  }>;335  burnFrom: (signer: TSigner, fromAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;336}
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -9,7 +9,7 @@
 import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';
 import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
 import {IKeyringPair} from '@polkadot/types/types';
-import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
+import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISubstrateBalance, ITokenAddress, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks, ICollectionBase, ICollectionNFT, ICollectionRFT, ITokenBase, ITokenNonfungible, ITokenRefungible, ICollectionFT} from './types';
 
 export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
   const address = {} as ICrossAccountId;
@@ -55,11 +55,15 @@
     RPC: 'rpc',
   };
 
-  static getTokenAccount(token: IToken) {
+  static getTokenAccount(token: ITokenAddress): ICrossAccountId {
+    return {Ethereum: this.getTokenAddress(token)};
+  }
+
+  static getTokenAccountInLowerCase(token: ITokenAddress): ICrossAccountId {
     return {Ethereum: this.getTokenAddress(token).toLowerCase()};
   }
 
-  static getTokenAddress(token: IToken) {
+  static getTokenAddress(token: ITokenAddress): string {
     return nesting.tokenIdToAddress(token.collectionId, token.tokenId);
   }
 
@@ -1348,7 +1352,7 @@
    * @example getTokenChildren(10, 5);
    * @returns tokens whose depth of nesting is <= 5
    */
-  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {
+  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ITokenAddress[]> {
     let children;
     if(typeof blockHashAt === 'undefined') {
       children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);
@@ -1369,7 +1373,7 @@
    * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});
    * @returns ```true``` if extrinsic success, otherwise ```false```
    */
-  async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {
+  async nestToken(signer: TSigner, tokenObj: ITokenAddress, rootTokenObj: ITokenAddress): Promise<boolean> {
     const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
     const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);
     if(!result) {
@@ -1387,7 +1391,7 @@
    * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});
    * @returns ```true``` if extrinsic success, otherwise ```false```
    */
-  async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {
+  async unnestToken(signer: TSigner, tokenObj: ITokenAddress, rootTokenObj: ITokenAddress, toAddressObj: ICrossAccountId): Promise<boolean> {
     const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
     const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);
     if(!result) {
@@ -1456,7 +1460,7 @@
       true,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1489,7 +1493,7 @@
       true,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1630,7 +1634,7 @@
       true, // `Unable to mint RFT tokens for ${label}`,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1654,7 +1658,7 @@
       true,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -2219,7 +2223,7 @@
 }
 
 
-export class UniqueCollectionBase {
+class UniqueCollectionBase implements ICollectionBase {
   helper: UniqueHelper;
   collectionId: number;
 
@@ -2256,6 +2260,10 @@
     return await this.helper.collection.getProperties(this.collectionId, propertyKeys);
   }
 
+  async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {
+    return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);
+  }
+
   async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {
     return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);
   }
@@ -2300,10 +2308,6 @@
     return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);
   }
 
-  async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {
-    return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);
-  }
-
   async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {
     return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);
   }
@@ -2322,7 +2326,7 @@
 }
 
 
-export class UniqueNFTCollection extends UniqueCollectionBase {
+class UniqueNFTCollection extends UniqueCollectionBase implements ICollectionNFT {
   getTokenObject(tokenId: number) {
     return new UniqueNFTToken(tokenId, this);
   }
@@ -2399,17 +2403,17 @@
     return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
   }
 
-  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
+  async nestToken(signer: TSigner, tokenId: number, toTokenObj: ITokenAddress) {
     return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
   }
 
-  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: ITokenAddress, toAddressObj: ICrossAccountId) {
     return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
   }
 }
 
 
-export class UniqueRFTCollection extends UniqueCollectionBase {
+class UniqueRFTCollection extends UniqueCollectionBase implements ICollectionRFT {
   getTokenObject(tokenId: number) {
     return new UniqueRFTToken(tokenId, this);
   }
@@ -2434,6 +2438,10 @@
     return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);
   }
 
+  async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+    return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);
+  }
+
   async getPropertyPermissions(propertyKeys: string[] | null = null) {
     return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);
   }
@@ -2452,10 +2460,6 @@
 
   async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {
     return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);
-  }
-
-  async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
-    return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);
   }
 
   async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {
@@ -2492,23 +2496,31 @@
 }
 
 
-export class UniqueFTCollection extends UniqueCollectionBase {
-  async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {
-    return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);
+class UniqueFTCollection extends UniqueCollectionBase implements ICollectionFT {
+  async getBalance(addressObj: ICrossAccountId) {
+    return await this.helper.ft.getBalance(this.collectionId, addressObj);
   }
 
-  async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {
-    return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);
+  async getTotalPieces() {
+    return await this.helper.ft.getTotalPieces(this.collectionId);
   }
 
-  async getBalance(addressObj: ICrossAccountId) {
-    return await this.helper.ft.getBalance(this.collectionId, addressObj);
+  async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
+    return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);
   }
 
   async getTop10Owners() {
     return await this.helper.ft.getTop10Owners(this.collectionId);
   }
 
+  async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {
+    return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);
+  }
+
+  async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {
+    return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);
+  }
+
   async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {
     return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);
   }
@@ -2523,23 +2535,15 @@
 
   async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {
     return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);
-  }
-
-  async getTotalPieces() {
-    return await this.helper.ft.getTotalPieces(this.collectionId);
   }
 
   async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {
     return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);
   }
-
-  async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {
-    return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);
-  }
 }
 
 
-export class UniqueTokenBase implements IToken {
+class UniqueTokenBase implements ITokenBase {
   collection: UniqueNFTCollection | UniqueRFTCollection;
   collectionId: number;
   tokenId: number;
@@ -2569,10 +2573,14 @@
   nestingAccount() {
     return this.collection.helper.util.getTokenAccount(this);
   }
+
+  nestingAccountInLowerCase() {
+    return this.collection.helper.util.getTokenAccountInLowerCase(this);
+  }
 }
 
 
-export class UniqueNFTToken extends UniqueTokenBase {
+class UniqueNFTToken extends UniqueTokenBase implements ITokenNonfungible {
   collection: UniqueNFTCollection;
 
   constructor(tokenId: number, collection: UniqueNFTCollection) {
@@ -2596,11 +2604,11 @@
     return await this.collection.getTokenChildren(this.tokenId, blockHashAt);
   }
 
-  async nest(signer: TSigner, toTokenObj: IToken) {
+  async nest(signer: TSigner, toTokenObj: ITokenAddress) {
     return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
   }
 
-  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
+  async unnest(signer: TSigner, fromTokenObj: ITokenAddress, toAddressObj: ICrossAccountId) {
     return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
   }
 
@@ -2629,7 +2637,7 @@
   }
 }
 
-export class UniqueRFTToken extends UniqueTokenBase {
+class UniqueRFTToken extends UniqueTokenBase implements ITokenRefungible {
   collection: UniqueRFTCollection;
 
   constructor(tokenId: number, collection: UniqueRFTCollection) {
@@ -2653,6 +2661,10 @@
     return await this.collection.getTokenTotalPieces(this.tokenId);
   }
 
+  async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {
+    return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);
+  }
+
   async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {
     return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);
   }
@@ -2663,10 +2675,6 @@
 
   async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {
     return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);
-  }
-
-  async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {
-    return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);
   }
 
   async repartition(signer: TSigner, amount: bigint) {