From 2eb5d08eae89fe1967319f244c7b0c4308cabb81 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Tue, 23 Aug 2022 05:14:28 +0000 Subject: [PATCH] add extension class to playgrounds + add creteAccounts method + move addCollectionAdmin tests to playgrounds --- --- a/tests/src/addCollectionAdmin.test.ts +++ b/tests/src/addCollectionAdmin.test.ts @@ -14,136 +14,122 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {ApiPromise} from '@polkadot/api'; +import {IKeyringPair} from '@polkadot/types/types'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api'; -import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, destroyCollectionExpectSuccess, getAdminList, normalizeAccountId, queryCollectionExpectSuccess} from './util/helpers'; +import {usingPlaygrounds} from './util/playgrounds'; chai.use(chaiAsPromised); const expect = chai.expect; +let donor: IKeyringPair; + +before(async () => { + await usingPlaygrounds(async (_, privateKeyWrapper) => { + donor = privateKeyWrapper('//Alice'); + }); +}); + describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => { it('Add collection admin.', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); + await usingPlaygrounds(async (helper) => { + const [alice, bob] = await helper.arrange.creteAccounts([10n, 10n], donor); + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.equal(alice.address); + const collection = await helper.collection.getData(collectionId); + expect(collection?.normalizedOwner!).to.be.equal(alice.address); - const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address)); - await submitTransactionAsync(alice, changeAdminTx); + await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address}); - const adminListAfterAddAdmin = await getAdminList(api, collectionId); - expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address)); + const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId); + expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address}); }); }); }); describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => { it("Not owner can't add collection admin.", async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//CHARLIE'); + await usingPlaygrounds(async (helper) => { + const [alice, bob, charlie] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor); + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.equal(alice.address); + const collection = await helper.collection.getData(collectionId); + expect(collection?.normalizedOwner).to.be.equal(alice.address); - const adminListAfterAddAdmin = await getAdminList(api, collectionId); - expect(adminListAfterAddAdmin).to.be.not.deep.contains(normalizeAccountId(bob.address)); + const changeAdminTxBob = async () => helper.collection.addAdmin(bob, collectionId, {Substrate: bob.address}); + const changeAdminTxCharlie = async () => helper.collection.addAdmin(bob, collectionId, {Substrate: charlie.address}); + await expect(changeAdminTxCharlie()).to.be.rejected; + await expect(changeAdminTxBob()).to.be.rejected; - const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address)); - await expect(submitTransactionAsync(bob, changeAdminTxCharlie)).to.be.rejected; - - const adminListAfterAddNewAdmin = await getAdminList(api, collectionId); - expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(bob.address)); - expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(charlie.address)); + const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId); + expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: charlie.address}); + expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: bob.address}); }); }); it("Admin can't add collection admin.", async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//CHARLIE'); + await usingPlaygrounds(async (helper) => { + const [alice, bob, charlie] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor); + const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.equal(alice.address); + await collection.addAdmin(alice, {Substrate: bob.address}); - const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address)); - await submitTransactionAsync(alice, changeAdminTx); + const adminListAfterAddAdmin = await collection.getAdmins(); + expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address}); - const adminListAfterAddAdmin = await getAdminList(api, collectionId); - expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address)); + const changeAdminTxCharlie = async () => collection.addAdmin(bob, {Substrate: charlie.address}); + await expect(changeAdminTxCharlie()).to.be.rejected; - const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address)); - await expect(submitTransactionAsync(bob, changeAdminTxCharlie)).to.be.rejected; - - const adminListAfterAddNewAdmin = await getAdminList(api, collectionId); - expect(adminListAfterAddNewAdmin).to.be.deep.contains(normalizeAccountId(bob.address)); - expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(charlie.address)); + const adminListAfterAddNewAdmin = await collection.getAdmins(); + expect(adminListAfterAddNewAdmin).to.be.deep.contains({Substrate: bob.address}); + expect(adminListAfterAddNewAdmin).to.be.not.deep.contains({Substrate: charlie.address}); }); }); it("Can't add collection admin of not existing collection.", async () => { - await usingApi(async (api, privateKeyWrapper) => { + await usingPlaygrounds(async (helper) => { + const [alice, bob] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor); // tslint:disable-next-line: no-bitwise const collectionId = (1 << 32) - 1; - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const changeOwnerTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address)); - await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected; + const addAdminTx = async () => helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address}); + await expect(addAdminTx()).to.be.rejected; // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); + await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); }); }); it("Can't add an admin to a destroyed collection.", async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - await destroyCollectionExpectSuccess(collectionId); - const changeOwnerTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address)); - await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected; + await usingPlaygrounds(async (helper) => { + const [alice, bob] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor); + const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); + + await collection.burn(alice); + const addAdminTx = async () => collection.addAdmin(alice, {Substrate: bob.address}); + await expect(addAdminTx()).to.be.rejected; // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); + await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); }); }); it('Add an admin to a collection that has reached the maximum number of admins limit', async () => { - await usingApi(async (api: ApiPromise, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const accounts = [ - privateKeyWrapper('//AdminTest/1').address, - privateKeyWrapper('//AdminTest/2').address, - privateKeyWrapper('//AdminTest/3').address, - privateKeyWrapper('//AdminTest/4').address, - privateKeyWrapper('//AdminTest/5').address, - privateKeyWrapper('//AdminTest/6').address, - privateKeyWrapper('//AdminTest/7').address, - ]; - const collectionId = await createCollectionExpectSuccess(); + await usingPlaygrounds(async (helper) => { + const [alice, ...accounts] = await helper.arrange.creteAccounts([10n, 0n, 0n, 0n, 0n, 0n, 0n, 0n], donor); + const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); - const chainAdminLimit = (api.consts.common.collectionAdminsLimit as any).toNumber(); + const chainAdminLimit = (helper.api!.consts.common.collectionAdminsLimit as any).toNumber(); expect(chainAdminLimit).to.be.equal(5); for (let i = 0; i < chainAdminLimit; i++) { - await addCollectionAdminExpectSuccess(alice, collectionId, accounts[i]); - const adminListAfterAddAdmin = await getAdminList(api, collectionId); - expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(accounts[i])); + await collection.addAdmin(alice, {Substrate: accounts[i].address}); + const adminListAfterAddAdmin = await collection.getAdmins(); + expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: accounts[i].address}); } - const tx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(accounts[chainAdminLimit])); - await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected; + const addExtraAdminTx = async () => collection.addAdmin(alice, {Substrate: accounts[chainAdminLimit].address}); + await expect(addExtraAdminTx()).to.be.rejected; }); }); }); --- a/tests/src/util/playgrounds/index.ts +++ b/tests/src/util/playgrounds/index.ts @@ -2,15 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import {IKeyringPair} from '@polkadot/types/types'; -import {UniqueHelper} from './unique'; import config from '../../config'; import '../../interfaces/augment-api-events'; -import * as defs from '../../interfaces/definitions'; -import {ApiPromise, WsProvider} from '@polkadot/api'; - +import {DevUniqueHelper} from './unique.dev'; class SilentLogger { - log(msg: any, level: any): void {} + log(msg: any, level: any): void { } level = { ERROR: 'ERROR' as const, WARNING: 'WARNING' as const, @@ -18,45 +15,7 @@ }; } - -class DevUniqueHelper extends UniqueHelper { - async connect(wsEndpoint: string, listeners?: any): Promise { - const wsProvider = new WsProvider(wsEndpoint); - this.api = new ApiPromise({ - provider: wsProvider, - signedExtensions: { - ContractHelpers: { - extrinsic: {}, - payload: {}, - }, - FakeTransactionFinalizer: { - extrinsic: {}, - payload: {}, - }, - }, - rpc: { - unique: defs.unique.rpc, - rmrk: defs.rmrk.rpc, - eth: { - feeHistory: { - description: 'Dummy', - params: [], - type: 'u8', - }, - maxPriorityFeePerGas: { - description: 'Dummy', - params: [], - type: 'u8', - }, - }, - }, - }); - await this.api.isReadyOrError; - this.network = await UniqueHelper.detectNetwork(this.api); - } -} - -export const usingPlaygrounds = async (code: (helper: UniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise) => { +export const usingPlaygrounds = async (code: (helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise) => { // TODO: Remove, this is temporary: Filter unneeded API output // (Jaco promised it will be removed in the next version) const consoleErr = console.error; @@ -83,7 +42,7 @@ const ss58Format = helper.chain.getChainProperties().ss58Format; const privateKey = (seed: string) => helper.util.fromSeed(seed, ss58Format); await code(helper, privateKey); - } + } finally { await helper.disconnect(); console.error = consoleErr; --- /dev/null +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -0,0 +1,90 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +import {mnemonicGenerate} from '@polkadot/util-crypto'; +import {UniqueHelper} from './unique'; +import {IKeyringPair} from '@polkadot/types/types'; +import {ApiPromise, WsProvider} from '@polkadot/api'; +import * as defs from '../../interfaces/definitions'; + + +export class DevUniqueHelper extends UniqueHelper { + /** + * Arrange methods for tests + */ + arrange: UniqueArrange; + + constructor(logger: { log: (msg: any, level: any) => void, level: any }) { + super(logger); + this.arrange = new UniqueArrange(this); + } + + async connect(wsEndpoint: string, listeners?: any): Promise { + const wsProvider = new WsProvider(wsEndpoint); + this.api = new ApiPromise({ + provider: wsProvider, + signedExtensions: { + ContractHelpers: { + extrinsic: {}, + payload: {}, + }, + FakeTransactionFinalizer: { + extrinsic: {}, + payload: {}, + }, + }, + rpc: { + unique: defs.unique.rpc, + rmrk: defs.rmrk.rpc, + eth: { + feeHistory: { + description: 'Dummy', + params: [], + type: 'u8', + }, + maxPriorityFeePerGas: { + description: 'Dummy', + params: [], + type: 'u8', + }, + }, + }, + }); + await this.api.isReadyOrError; + this.network = await UniqueHelper.detectNetwork(this.api); + } +} + +class UniqueArrange { + helper: UniqueHelper; + + constructor(helper: UniqueHelper) { + this.helper = helper; + } + + /** + * Generates accounts with the specified UNQ token balance + * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal. + * @param donor donor account for balances + * @returns array of newly created accounts + * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); + */ + creteAccounts = async (balances: bigint[], donor: IKeyringPair): Promise => { + let nonce = await this.helper.chain.getNonce(donor.address); + const tokenNominal = this.helper.balance.getOneTokenNominal(); + const transactions = []; + const accounts = []; + for (const balance of balances) { + const recepient = this.helper.util.fromSeed(mnemonicGenerate()); + accounts.push(recepient); + if (balance !== 0n) { + const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]); + transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce})); + nonce++; + } + } + + await Promise.all(transactions); + return accounts; + }; +} \ No newline at end of file --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -439,7 +439,7 @@ return this.transactionStatus.FAIL; } - signTransaction(sender: TSigner, transaction: any, label = 'transaction', options = null) { + signTransaction(sender: TSigner, transaction: any, label = 'transaction', options: any = null) { const sign = (callback: any) => { if(options !== null) return transaction.signAndSend(sender, options, callback); return transaction.signAndSend(sender, callback); -- gitstuff