From 9cb35ec055edc8edae2c302ff6b61b05fb033405 Mon Sep 17 00:00:00 2001 From: ut-akuznetsov <59873862+ut-akuznetsov@users.noreply.github.com> Date: Thu, 08 Sep 2022 10:10:52 +0000 Subject: [PATCH] Merge pull request #571 from UniqueNetwork/test/intermittent-playgrounds-update Tests (utility in playgrounds): various modifications and additions --- --- 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", --- 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}); --- a/tests/src/util/playgrounds/types.ts +++ b/tests/src/util/playgrounds/types.ts @@ -102,9 +102,9 @@ } export interface ICollectionCreationOptions { - name: string | number[]; - description: string | number[]; - tokenPrefix: string | number[]; + name?: string | number[]; + description?: string | number[]; + tokenPrefix?: string | number[]; mode?: { nft?: null; refungible?: null; --- 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 => { 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++; } --- 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 { - 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 { + 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 { - const normalized = []; + async getAllowList(collectionId: number, normalize = false): Promise { 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 { + 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) { -- gitstuff