git.delta.rocks / unique-network / refs/commits / eba9da942ea3

difftreelog

test(util-playgrounds) modifications and additions of all stripes

Fahrrader2022-09-08parent: #fc6e541.patch.diff
in: master

5 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -64,6 +64,7 @@
     "testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts",
     "testAdminTransferAndBurn": "mocha --timeout 9999999 -r ts-node/register ./**/adminTransferAndBurn.test.ts",
     "testSetMintPermission": "mocha --timeout 9999999 -r ts-node/register ./**/setMintPermission.test.ts",
+    "testSetPublicAccessMode": "mocha --timeout 9999999 -r ts-node/register ./**/setPublicAccessMode.test.ts",
     "testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.test.ts",
     "testContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/contractSponsoring.test.ts",
     "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",
@@ -71,7 +72,6 @@
     "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",
     "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",
     "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
-    "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",
     "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
     "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",
     "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",
modifiedtests/src/util/playgrounds/index.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/index.ts
+++ b/tests/src/util/playgrounds/index.ts
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import {IKeyringPair} from '@polkadot/types/types';
+import {Context} from 'mocha';
 import config from '../../config';
 import '../../interfaces/augment-api-events';
 import {DevUniqueHelper, SilentLogger, SilentConsole} from './unique.dev';
@@ -24,3 +25,39 @@
     silentConsole.disable();
   }
 };
+
+export enum Pallets {
+  Inflation = 'inflation',
+  RmrkCore = 'rmrkcore',
+  RmrkEquip = 'rmrkequip',
+  ReFungible = 'refungible',
+  Fungible = 'fungible',
+  NFT = 'nonfungible',
+  Scheduler = 'scheduler',
+}
+
+export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) {
+  const missingPallets = helper.fetchMissingPalletNames(requiredPallets);
+    
+  if (missingPallets.length > 0) {
+    const skipMsg = `\tSkipping test '${test.test?.title}'.\n\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
+    console.warn('\x1b[38:5:208m%s\x1b[0m', skipMsg);
+    test.skip();
+  }
+}
+
+export async function itSub(name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+  (opts.only ? it.only : 
+    opts.skip ? it.skip : it)(name, async function () {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      if (opts.requiredPallets) {
+        requirePalletsOrSkip(this, helper, opts.requiredPallets);
+      }
+      
+      await cb({helper, privateKey});
+    });
+  });
+}
+itSub.only = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itSub(name, cb, {only: true});
+itSub.skip = (name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itSub(name, cb, {skip: true});
+itSub.ifWithPallets = (name: string, required: string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itSub(name, cb, {requiredPallets: required});
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 IChainEvent {7  data: any;8  method: string;9  section: string;10}1112export interface ITransactionResult {13    status: 'Fail' | 'Success';14    result: {15        events: {16          event: IChainEvent17        }[];18    },19    moduleError?: string;20}2122export interface ILogger {23  log: (msg: any, level?: string) => void;24  level: {25    ERROR: 'ERROR';26    WARNING: 'WARNING';27    INFO: 'INFO';28    [key: string]: string;29  }30}3132export interface IUniqueHelperLog {33  executedAt: number;34  executionTime: number;35  type: 'extrinsic' | 'rpc';36  status: 'Fail' | 'Success';37  call: string;38  params: any[];39  moduleError?: string;40  events?: any;41}4243export interface IApiListeners {44  connected?: (...args: any[]) => any;45  disconnected?: (...args: any[]) => any;46  error?: (...args: any[]) => any;47  ready?: (...args: any[]) => any; 48  decorated?: (...args: any[]) => any;49}5051export interface ICrossAccountId {52  Substrate?: TSubstrateAccount;53  Ethereum?: TEthereumAccount;54}5556export interface ICrossAccountIdLower {57  substrate?: TSubstrateAccount;58  ethereum?: TEthereumAccount;59}6061export interface ICollectionLimits {62  accountTokenOwnershipLimit?: number | null;63  sponsoredDataSize?: number | null;64  sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;65  tokenLimit?: number | null;66  sponsorTransferTimeout?: number | null;67  sponsorApproveTimeout?: number | null;68  ownerCanTransfer?: boolean | null;69  ownerCanDestroy?: boolean | null;70  transfersEnabled?: boolean | null;71}7273export interface INestingPermissions {74  tokenOwner?: boolean;75  collectionAdmin?: boolean;76  restricted?: number[] | null;77}7879export interface ICollectionPermissions {80  access?: 'Normal' | 'AllowList';81  mintMode?: boolean;82  nesting?: INestingPermissions;83}8485export interface IProperty {86  key: string;87  value: string;88}8990export interface ITokenPropertyPermission {91  key: string;92  permission: {93    mutable: boolean;94    tokenOwner: boolean;95    collectionAdmin: boolean;96  }97}9899export interface IToken {100  collectionId: number;101  tokenId: number;102}103104export interface ICollectionCreationOptions {105  name: string | number[];106  description: string | number[];107  tokenPrefix: string | number[];108  mode?: {109    nft?: null;110    refungible?: null;111    fungible?: number;112  }113  permissions?: ICollectionPermissions;114  properties?: IProperty[];115  tokenPropertyPermissions?: ITokenPropertyPermission[];116  limits?: ICollectionLimits;117  pendingSponsor?: TSubstrateAccount;118}119120export interface IChainProperties {121  ss58Format: number;122  tokenDecimals: number[];123  tokenSymbol: string[]124}125126export type TSubstrateAccount = string;127export type TEthereumAccount = string;128export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';129export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';130export type TSigner = IKeyringPair; // | 'string'
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -118,14 +118,15 @@
    */
   createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {
     let nonce = await this.helper.chain.getNonce(donor.address);
+    const ss58Format = this.helper.chain.getChainProperties().ss58Format;
     const tokenNominal = this.helper.balance.getOneTokenNominal();
     const transactions = [];
     const accounts: IKeyringPair[] = [];
     for (const balance of balances) {
-      const recepient = this.helper.util.fromSeed(mnemonicGenerate());
-      accounts.push(recepient);
+      const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
+      accounts.push(recipient);
       if (balance !== 0n) {
-        const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);
+        const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, balance * tokenNominal]);
         transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));
         nonce++;
       }
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -11,13 +11,12 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {IApiListeners, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
 
-const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
+export const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
   const address = {} as ICrossAccountId;
   if(lowerAddress.substrate) address.Substrate = lowerAddress.substrate;
   if(lowerAddress.ethereum) address.Ethereum = lowerAddress.ethereum;
   return address;
 };
-
 
 const nesting = {
   toChecksumAddress(address: string): string {
@@ -440,6 +439,16 @@
     if(typeof signer === 'string') return signer;
     return signer.address;
   }
+
+  fetchAllPalletNames(): string[] {
+    if(this.api === null) throw Error('API not initialized');
+    return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());
+  }
+  
+  fetchMissingPalletNames(requiredPallets: string[]): string[] {
+    const palletNames = this.fetchAllPalletNames();
+    return requiredPallets.filter(p => !palletNames.includes(p));
+  }
 }
 
 
@@ -476,7 +485,9 @@
   }
 
   /**
-   * Get information about the collection with additional data, including the number of tokens it contains, its administrators, the normalized address of the collection's owner, and decoded name and description.
+   * Get information about the collection with additional data, 
+   * including the number of tokens it contains, its administrators, 
+   * the normalized address of the collection's owner, and decoded name and description.
    * 
    * @param collectionId ID of collection
    * @example await getData(2)
@@ -504,42 +515,50 @@
       collectionData[key] = this.helper.util.vec2str(humanCollection[key]);
     }
 
-    collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode)) ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId) : 0;
+    collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode)) 
+      ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId) 
+      : 0;
     collectionData.admins = await this.getAdmins(collectionId);
 
     return collectionData;
   }
 
   /**
-   * Get the normalized addresses of the collection's administrators.
+   * Get the addresses of the collection's administrators, optionally normalized.
    * 
    * @param collectionId ID of collection
+   * @param normalize whether to normalize the addresses to the default ss58 format
    * @example await getAdmins(1)
    * @returns array of administrators
    */
-  async getAdmins(collectionId: number): Promise<ICrossAccountId[]> {
-    const normalized = [];
-    for(const admin of (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman()) {
-      if(admin.Substrate) normalized.push({Substrate: this.helper.address.normalizeSubstrate(admin.Substrate)});
-      else normalized.push(admin);
-    }
-    return normalized;
+  async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
+    const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();
+
+    return normalize
+      ? admins.map((address: any) => {
+        return address.Substrate
+          ? {Substrate: this.helper.address.normalizeSubstrate(address.Substrate)}
+          : address;
+      }) 
+      : admins;
   }
 
   /**
-   * Get the normalized addresses added to the collection allow-list.
+   * Get the addresses added to the collection allow-list, optionally normalized.
    * @param collectionId ID of collection
+   * @param normalize whether to normalize the addresses to the default ss58 format
    * @example await getAllowList(1)
    * @returns array of allow-listed addresses
    */
-  async getAllowList(collectionId: number): Promise<ICrossAccountId[]> {
-    const normalized = [];
+  async getAllowList(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {
     const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();
-    for (const address of allowListed) {
-      if (address.Substrate) normalized.push({Substrate: this.helper.address.normalizeSubstrate(address.Substrate)});
-      else normalized.push(address);
-    }
-    return normalized;
+    return normalize
+      ? allowListed.map((address: any) => {
+        return address.Substrate
+          ? {Substrate: this.helper.address.normalizeSubstrate(address.Substrate)}
+          : address;
+      }) 
+      : allowListed;
   }
 
   /**
@@ -572,7 +591,7 @@
   }
 
   /**
-   * Sets the sponsor for the collection (Requires the Substrate address).
+   * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.
    * 
    * @param signer keyring of signer
    * @param collectionId ID of collection
@@ -609,6 +628,24 @@
   }
 
   /**
+   * Removes the sponsor of a collection, regardless if it consented or not.
+   * 
+   * @param signer keyring of signer
+   * @param collectionId ID of collection
+   * @example removeSponsor(aliceKeyring, 10)
+   * @returns ```true``` if extrinsic success, otherwise ```false```
+   */
+  async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {
+    const result = await this.helper.executeExtrinsic(
+      signer,
+      'api.tx.unique.removeCollectionSponsor', [collectionId],
+      true,
+    );
+
+    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved');
+  }
+
+  /**
    * Sets the limits of the collection. At least one limit must be specified for a correct call.
    * 
    * @param signer keyring of signer
@@ -2004,6 +2041,10 @@
     return await this.helper.collection.confirmSponsorship(signer, this.collectionId);
   }
 
+  async removeSponsor(signer: TSigner) {
+    return await this.helper.collection.removeSponsor(signer, this.collectionId);
+  }
+
   async setLimits(signer: TSigner, limits: ICollectionLimits) {
     return await this.helper.collection.setLimits(signer, this.collectionId, limits);
   }
@@ -2016,8 +2057,8 @@
     return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);
   }
 
-  async enableAllowList(signer: TSigner, value = true/*: 'Normal' | 'AllowList' = 'AllowList'*/) {
-    return await this.setPermissions(signer, value ? {access: 'AllowList', mintMode: true} : {access: 'Normal'});
+  async enableCertainPermissions(signer: TSigner, accessMode: 'AllowList' | 'Normal' | undefined = 'AllowList', mintMode: boolean | undefined = true) {
+    return await this.setPermissions(signer, {access: accessMode, mintMode: mintMode});
   }
 
   async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {