git.delta.rocks / unique-network / refs/commits / 77e366b9e580

difftreelog

tests(nesting): revert majority of last commit + refactor token and collection naming convention

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

6 files changed

modifiedtests/src/fungible.test.tsdiffbeforeafterboth
--- a/tests/src/fungible.test.ts
+++ b/tests/src/fungible.test.ts
@@ -15,7 +15,9 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect, U128_MAX} from './util/playgrounds';
+import {itSub, usingPlaygrounds, expect} from './util/playgrounds';
+
+const U128_MAX = (1n << 128n) - 1n;
 
 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,8 +16,7 @@
 
 import {IKeyringPair} from '@polkadot/types/types';
 import {expect, itSub, usingPlaygrounds} from '../util/playgrounds';
-import {ITokenNonfungible} from '../util/playgrounds/types';
-import {UniqueHelper} from '../util/playgrounds/unique';
+import {UniqueHelper, UniqueNFToken} from '../util/playgrounds/unique';
 
 /**
  * ```dot
@@ -26,7 +25,7 @@
  * 8 -> 5
  * ```
  */
-async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<ITokenNonfungible[]> {
+async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<UniqueNFToken[]> {
   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/properties.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -16,8 +16,7 @@
 
 import {IKeyringPair} from '@polkadot/types/types';
 import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect} from '../util/playgrounds';
-import {ICollectionBase, ICollectionNFT, ITokenNonfungible, ICollectionRFT, ITokenRefungible} from '../util/playgrounds/types';
-import {UniqueHelper} from '../util/playgrounds/unique';
+import {UniqueHelper, UniqueBaseCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../util/playgrounds/unique';
 
 // ---------- COLLECTION PROPERTIES
 
@@ -37,7 +36,7 @@
     expect(await collection.getProperties()).to.be.empty;
   });
 
-  async function testSetsPropertiesForCollection(collection: ICollectionBase) {
+  async function testSetsPropertiesForCollection(collection: UniqueBaseCollection) {
     // As owner
     await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;
 
@@ -61,7 +60,7 @@
     await testSetsPropertiesForCollection(await helper.rft.mintCollection(alice));
   });
 
-  async function testCheckValidNames(collection: ICollectionBase) {
+  async function testCheckValidNames(collection: UniqueBaseCollection) {
     // alpha symbols
     await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;
 
@@ -95,7 +94,7 @@
     await testCheckValidNames(await helper.rft.mintCollection(alice));
   });
 
-  async function testChangesProperties(collection: ICollectionBase) {
+  async function testChangesProperties(collection: UniqueBaseCollection) {
     await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;
 
     // Mutate the properties
@@ -116,7 +115,7 @@
     await testChangesProperties(await helper.rft.mintCollection(alice));
   });
 
-  async function testDeleteProperties(collection: ICollectionBase) {
+  async function testDeleteProperties(collection: UniqueBaseCollection) {
     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;
@@ -147,7 +146,7 @@
     });
   });
   
-  async function testFailsSetPropertiesIfNotOwnerOrAdmin(collection: ICollectionBase) {  
+  async function testFailsSetPropertiesIfNotOwnerOrAdmin(collection: UniqueBaseCollection) {  
     await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))
       .to.be.rejectedWith(/common\.NoPermission/);
 
@@ -162,7 +161,7 @@
     await testFailsSetPropertiesIfNotOwnerOrAdmin(await helper.rft.mintCollection(alice));
   });
   
-  async function testFailsSetPropertiesThatExeedLimits(collection: ICollectionBase) {
+  async function testFailsSetPropertiesThatExeedLimits(collection: UniqueBaseCollection) {
     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
@@ -191,7 +190,7 @@
     await testFailsSetPropertiesThatExeedLimits(await helper.rft.mintCollection(alice));
   });
   
-  async function testFailsSetMorePropertiesThanAllowed(collection: ICollectionBase) {
+  async function testFailsSetMorePropertiesThanAllowed(collection: UniqueBaseCollection) {
     const propertiesToBeSet = [];
     for (let i = 0; i < 65; i++) {
       propertiesToBeSet.push({
@@ -214,7 +213,7 @@
     await testFailsSetMorePropertiesThanAllowed(await helper.rft.mintCollection(alice));
   });
   
-  async function testFailsSetPropertiesWithInvalidNames(collection: ICollectionBase) {
+  async function testFailsSetPropertiesWithInvalidNames(collection: UniqueBaseCollection) {
     const invalidProperties = [
       [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
       [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
@@ -281,7 +280,7 @@
     expect(propertyRights).to.be.empty;
   });
   
-  async function testSetsAccessRightsToProperties(collection: ICollectionNFT | ICollectionRFT) {  
+  async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {  
     await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}]))
       .to.be.fulfilled;
 
@@ -305,7 +304,7 @@
     await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice));
   });
   
-  async function testChangesAccessRightsToProperty(collection: ICollectionNFT | ICollectionRFT) {
+  async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) {
     await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]))
       .to.be.fulfilled;
 
@@ -338,7 +337,7 @@
     });
   });
 
-  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: ICollectionNFT | ICollectionRFT) {
+  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) {
     await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]))
       .to.be.rejectedWith(/common\.NoPermission/);
 
@@ -354,7 +353,7 @@
     await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice));
   });
 
-  async function testPreventFromAddingTooManyPossibleProperties(collection: ICollectionNFT | ICollectionRFT) {  
+  async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {  
     const constitution = [];
     for (let i = 0; i < 65; i++) {
       constitution.push({
@@ -378,7 +377,7 @@
     await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice));
   });
 
-  async function testPreventAccessRightsModifiedIfConstant(collection: ICollectionNFT | ICollectionRFT) {
+  async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) {
     await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
       .to.be.fulfilled;
 
@@ -399,7 +398,7 @@
     await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice));
   });
 
-  async function testPreventsAddingPropertiesWithInvalidNames(collection: ICollectionNFT | ICollectionRFT) {
+  async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) {
     const invalidProperties = [
       [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
       [{key: 'G#4', permission: {tokenOwner: true}}],
@@ -469,7 +468,7 @@
     ];
   });
   
-  async function testReadsYetEmptyProperties(token: ITokenNonfungible | ITokenRefungible) {
+  async function testReadsYetEmptyProperties(token: UniqueNFToken | UniqueRFToken) {
     const properties = await token.getProperties();
     expect(properties).to.be.empty;
 
@@ -489,7 +488,7 @@
     await testReadsYetEmptyProperties(token);
   });
 
-  async function testAssignPropertiesAccordingToPermissions(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testAssignPropertiesAccordingToPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -535,7 +534,7 @@
     await testAssignPropertiesAccordingToPermissions(token, 100n);
   });
 
-  async function testChangesPropertiesAccordingPermission(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testChangesPropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -588,7 +587,7 @@
     await testChangesPropertiesAccordingPermission(token, 100n);
   });
 
-  async function testDeletePropertiesAccordingPermission(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testDeletePropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -799,7 +798,7 @@
     return (await (mode == 'NFT' ? api.query.nonfungible : api.query.refungible).tokenProperties(collectionId, tokenId)).toJSON().consumedSpace;
   }
 
-  async function prepare(token: ITokenNonfungible | ITokenRefungible, pieces: bigint): Promise<number> {
+  async function prepare(token: UniqueNFToken | UniqueRFToken, pieces: bigint): Promise<number> {
     await token.collection.addAdmin(alice, {Substrate: bob.address});
     await token.transfer(alice, {Substrate: charlie.address}, pieces);
 
@@ -823,7 +822,7 @@
     return originalSpace;
   }
 
-  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     let i = 0;
@@ -858,7 +857,7 @@
     await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, 100n);
   });
 
-  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     let i = 0;
@@ -893,7 +892,7 @@
     await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, 100n);
   });
 
-  async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     await expect(
@@ -929,7 +928,7 @@
     await testForbidsAddingPropertiesIfPropertyNotDeclared(token, 100n);
   });
 
-  async function testForbidsAddingTooManyProperties(token: ITokenNonfungible | ITokenRefungible, pieces: bigint) {
+  async function testForbidsAddingTooManyProperties(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
     const originalSpace = await prepare(token, pieces);
 
     await expect(
@@ -984,7 +983,7 @@
     });
   });
 
-  async function prepare(helper: UniqueHelper): Promise<ITokenRefungible> {
+  async function prepare(helper: UniqueHelper): Promise<UniqueRFToken> {
     const collection = await helper.rft.mintCollection(alice);
     const token = await collection.mintToken(alice, 100n);
     
modifiedtests/src/util/playgrounds/index.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/index.ts
+++ b/tests/src/util/playgrounds/index.ts
@@ -12,13 +12,6 @@
 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
2// SPDX-License-Identifier: Apache-2.02// SPDX-License-Identifier: Apache-2.0
33
4import {IKeyringPair} from '@polkadot/types/types';4import {IKeyringPair} from '@polkadot/types/types';
5import {UniqueHelper} from './unique';
65
7export interface IEvent {6export interface IEvent {
8 section: string;7 section: string;
107 }106 }
108}107}
109108
110export interface ITokenAddress {109export interface IToken {
111 collectionId: number;110 collectionId: number;
112 tokenId: number;111 tokenId: number;
113}112}
169export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';168export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
170export type TSigner = IKeyringPair; // | 'string'169export type TSigner = IKeyringPair; // | 'string'
171
172export 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: any
183 } | 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}
207
208export interface ICollectionNFT extends ICollectionBase {
209 getTokenObject: (tokenId: number) => ITokenNonfungible; // todo:playgrounds
210 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:playgrounds
219 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:playgrounds
226 mintMultipleTokens: (signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) => Promise<ITokenNonfungible[]>;// todo:playgrounds
227 burnToken: (signer: TSigner, tokenId: number) => Promise<{
228 success: boolean,
229 token: number | null
230 }>;
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}
238
239export 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:playgrounds
259 burnToken: (signer: TSigner, tokenId: number, amount: bigint) => Promise<{
260 success: boolean,
261 token: number | null
262 }>;
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}
268
269export 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}
282
283export 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}
292
293export 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:playgrounds
303 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 | null
312 }>;
313 burnFrom: (signer: TSigner, fromAddressObj: ICrossAccountId) => Promise<boolean>;
314}
315
316export 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 | null
334 }>;
335 burnFrom: (signer: TSigner, fromAddressObj: ICrossAccountId, amount: bigint) => Promise<boolean>;
336}
337170
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, ITokenAddress, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks, ICollectionBase, ICollectionNFT, ICollectionRFT, ITokenBase, ITokenNonfungible, ITokenRefungible, ICollectionFT} from './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';
 
 export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
   const address = {} as ICrossAccountId;
@@ -55,15 +55,15 @@
     RPC: 'rpc',
   };
 
-  static getTokenAccount(token: ITokenAddress): ICrossAccountId {
+  static getTokenAccount(token: IToken): ICrossAccountId {
     return {Ethereum: this.getTokenAddress(token)};
   }
 
-  static getTokenAccountInLowerCase(token: ITokenAddress): ICrossAccountId {
+  static getTokenAccountInLowerCase(token: IToken): ICrossAccountId {
     return {Ethereum: this.getTokenAddress(token).toLowerCase()};
   }
 
-  static getTokenAddress(token: ITokenAddress): string {
+  static getTokenAddress(token: IToken): string {
     return nesting.tokenIdToAddress(token.collectionId, token.tokenId);
   }
 
@@ -1218,7 +1218,7 @@
    * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")
    * @returns object of the created collection
    */
-  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueCollectionBase> {
+  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {
     collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object
     collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};
     for (const key of ['name', 'description', 'tokenPrefix']) {
@@ -1260,8 +1260,8 @@
    * @example getTokenObject(10, 5);
    * @returns instance of UniqueNFTToken
    */
-  getTokenObject(collectionId: number, tokenId: number): UniqueNFTToken {
-    return new UniqueNFTToken(tokenId, this.getCollectionObject(collectionId));
+  getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {
+    return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));
   }
 
   /**
@@ -1352,7 +1352,7 @@
    * @example getTokenChildren(10, 5);
    * @returns tokens whose depth of nesting is <= 5
    */
-  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ITokenAddress[]> {
+  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {
     let children;
     if(typeof blockHashAt === 'undefined') {
       children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);
@@ -1373,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: ITokenAddress, rootTokenObj: ITokenAddress): Promise<boolean> {
+  async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {
     const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);
     const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);
     if(!result) {
@@ -1391,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: ITokenAddress, rootTokenObj: ITokenAddress, toAddressObj: ICrossAccountId): Promise<boolean> {
+  async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, 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) {
@@ -1422,7 +1422,7 @@
    * @param data token data
    * @returns created token object
    */
-  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFTToken> {
+  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {
     const creationResult = await this.helper.executeExtrinsic(
       signer,
       'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
@@ -1453,14 +1453,14 @@
    * }]);
    * @returns ```true``` if extrinsic success, otherwise ```false```
    */
-  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFTToken[]> {
+  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {
     const creationResult = await this.helper.executeExtrinsic(
       signer,
       'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],
       true,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1481,7 +1481,7 @@
    * }]);
    * @returns array of newly created tokens
    */
-  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFTToken[]> {
+  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {
     const rawTokens = [];
     for (const token of tokens) {
       const raw = {NFT: {properties: token.properties}};
@@ -1493,7 +1493,7 @@
       true,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1530,8 +1530,8 @@
    * @example getTokenObject(10, 5);
    * @returns instance of UniqueNFTToken
    */
-  getTokenObject(collectionId: number, tokenId: number): UniqueRFTToken {
-    return new UniqueRFTToken(tokenId, this.getCollectionObject(collectionId));
+  getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {
+    return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));
   }
 
   /**
@@ -1609,7 +1609,7 @@
    * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});
    * @returns created token object
    */
-  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFTToken> {
+  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {
     const creationResult = await this.helper.executeExtrinsic(
       signer,
       'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {
@@ -1626,7 +1626,7 @@
     return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);
   }
 
-  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFTToken[]> {
+  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {
     throw Error('Not implemented');
     const creationResult = await this.helper.executeExtrinsic(
       signer,
@@ -1634,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: ITokenAddress) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1646,7 +1646,7 @@
    * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);
    * @returns array of newly created RFT tokens
    */
-  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFTToken[]> {
+  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {
     const rawTokens = [];
     for (const token of tokens) {
       const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};
@@ -1658,7 +1658,7 @@
       true,
     );
     const collection = this.getCollectionObject(collectionId);
-    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: ITokenAddress) => collection.getTokenObject(x.tokenId));
+    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));
   }
 
   /**
@@ -1985,7 +1985,7 @@
 
 class BalanceGroup extends HelperGroup {
   /**
-   * Representation of the native token in the smallest unit
+   * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).
    * @example getOneTokenNominal()
    * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.
    */
@@ -2223,7 +2223,7 @@
 }
 
 
-class UniqueCollectionBase implements ICollectionBase {
+export class UniqueBaseCollection {
   helper: UniqueHelper;
   collectionId: number;
 
@@ -2326,9 +2326,9 @@
 }
 
 
-class UniqueNFTCollection extends UniqueCollectionBase implements ICollectionNFT {
+export class UniqueNFTCollection extends UniqueBaseCollection {
   getTokenObject(tokenId: number) {
-    return new UniqueNFTToken(tokenId, this);
+    return new UniqueNFToken(tokenId, this);
   }
 
   async getTokensByAddress(addressObj: ICrossAccountId) {
@@ -2403,19 +2403,19 @@
     return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);
   }
 
-  async nestToken(signer: TSigner, tokenId: number, toTokenObj: ITokenAddress) {
+  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {
     return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);
   }
 
-  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: ITokenAddress, toAddressObj: ICrossAccountId) {
+  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
     return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);
   }
 }
 
 
-class UniqueRFTCollection extends UniqueCollectionBase implements ICollectionRFT {
+export class UniqueRFTCollection extends UniqueBaseCollection {
   getTokenObject(tokenId: number) {
-    return new UniqueRFTToken(tokenId, this);
+    return new UniqueRFToken(tokenId, this);
   }
 
   async getToken(tokenId: number, blockHashAt?: string) {
@@ -2496,7 +2496,7 @@
 }
 
 
-class UniqueFTCollection extends UniqueCollectionBase implements ICollectionFT {
+export class UniqueFTCollection extends UniqueBaseCollection {
   async getBalance(addressObj: ICrossAccountId) {
     return await this.helper.ft.getBalance(this.collectionId, addressObj);
   }
@@ -2543,7 +2543,7 @@
 }
 
 
-class UniqueTokenBase implements ITokenBase {
+export class UniqueBaseToken {
   collection: UniqueNFTCollection | UniqueRFTCollection;
   collectionId: number;
   tokenId: number;
@@ -2580,7 +2580,7 @@
 }
 
 
-class UniqueNFTToken extends UniqueTokenBase implements ITokenNonfungible {
+export class UniqueNFToken extends UniqueBaseToken {
   collection: UniqueNFTCollection;
 
   constructor(tokenId: number, collection: UniqueNFTCollection) {
@@ -2604,11 +2604,11 @@
     return await this.collection.getTokenChildren(this.tokenId, blockHashAt);
   }
 
-  async nest(signer: TSigner, toTokenObj: ITokenAddress) {
+  async nest(signer: TSigner, toTokenObj: IToken) {
     return await this.collection.nestToken(signer, this.tokenId, toTokenObj);
   }
 
-  async unnest(signer: TSigner, fromTokenObj: ITokenAddress, toAddressObj: ICrossAccountId) {
+  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {
     return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);
   }
 
@@ -2637,7 +2637,7 @@
   }
 }
 
-class UniqueRFTToken extends UniqueTokenBase implements ITokenRefungible {
+export class UniqueRFToken extends UniqueBaseToken {
   collection: UniqueRFTCollection;
 
   constructor(tokenId: number, collection: UniqueRFTCollection) {