--- /dev/null +++ b/tests/globalSetup.ts @@ -0,0 +1,18 @@ +import {Pallets, usingPlaygrounds} from './src/util/playgrounds/index'; + +export async function mochaGlobalSetup() { + await usingPlaygrounds(async (helper, privateKey) => { + // Set up App Promotion admin + const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]); + if (missingPallets.length === 0) { + const superuser = await privateKey('//Alice'); + const palletAddress = helper.arrange.calculatePalleteAddress('appstake'); + const palletAdmin = await privateKey('//PromotionAdmin'); + const api = helper.getApi(); + await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address}))); + const nominal = helper.balance.getOneTokenNominal(); + await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 1000n * nominal); + await helper.balance.transferToSubstrate(superuser, palletAddress, 1000n * nominal); + } + }); +} --- a/tests/package.json +++ b/tests/package.json @@ -21,7 +21,7 @@ }, "mocha": { "timeout": 9999999, - "require": "ts-node/register" + "require": ["ts-node/register", "./globalSetup.ts"] }, "scripts": { "lint": "eslint --ext .ts,.js src/", --- /dev/null +++ b/tests/src/app-promotion.seqtest.ts @@ -0,0 +1,83 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip} from './util/playgrounds'; +import {expect} from './eth/util/playgrounds'; + +let superuser: IKeyringPair; +let donor: IKeyringPair; +let palletAdmin: IKeyringPair; +let nominal: bigint; +let palletAddress; +let accounts: IKeyringPair[]; + + +describe('App promotion', () => { + before(async function () { + await usingPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]); + superuser = await privateKey('//Alice'); + donor = await privateKey({filename: __filename}); + palletAddress = helper.arrange.calculatePalleteAddress('appstake'); + palletAdmin = await privateKey('//PromotionAdmin'); + const api = helper.getApi(); + await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address}))); + nominal = helper.balance.getOneTokenNominal(); + await helper.balance.transferToSubstrate(donor, palletAdmin.address, 1000n * nominal); + await helper.balance.transferToSubstrate(donor, palletAddress, 1000n * nominal); + accounts = await helper.arrange.createCrowd(100, 1000n, donor); // create accounts-pool to speed up tests + }); + }); + + describe('admin adress', () => { + itSub('can be set by sudo only', async ({helper}) => { + const api = helper.getApi(); + const nonAdmin = accounts.pop()!; + // nonAdmin can not set admin not from himself nor as a sudo + await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected; + await expect(helper.signTransaction(nonAdmin, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected; + }); + + itSub('can be any valid CrossAccountId', async ({helper}) => { + // We are not going to set an eth address as a sponsor, + // but we do want to check, it doesn't break anything; + const api = helper.getApi(); + const account = accounts.pop()!; + const ethAccount = helper.address.substrateToEth(account.address); + // Alice sets Ethereum address as a sudo. Then Substrate address back... + await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled; + await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled; + + // ...It doesn't break anything; + const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); + await expect(helper.signTransaction(account, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; + }); + + itSub('can be reassigned', async ({helper}) => { + const api = helper.getApi(); + const [oldAdmin, newAdmin, collectionOwner] = [accounts.pop()!, accounts.pop()!, accounts.pop()!]; + const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); + + await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: oldAdmin.address})))).to.be.fulfilled; + await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: newAdmin.address})))).to.be.fulfilled; + await expect(helper.signTransaction(oldAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; + + await expect(helper.signTransaction(newAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled; + }); + }); +}); + --- a/tests/src/app-promotion.test.ts +++ b/tests/src/app-promotion.test.ts @@ -16,17 +16,14 @@ import {IKeyringPair} from '@polkadot/types/types'; import {itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip} from './util/playgrounds'; -import {encodeAddress} from '@polkadot/util-crypto'; -import {stringToU8a} from '@polkadot/util'; import {DevUniqueHelper} from './util/playgrounds/unique.dev'; import {itEth, expect, SponsoringMode} from './eth/util/playgrounds'; -let superuser: IKeyringPair; let donor: IKeyringPair; let palletAdmin: IKeyringPair; let nominal: bigint; -const palletAddress = calculatePalleteAddress('appstake'); -let accounts: IKeyringPair[] = []; +let palletAddress: string; +let accounts: IKeyringPair[]; const LOCKING_PERIOD = 20n; // 20 blocks of relay const UNLOCKING_PERIOD = 10n; // 10 blocks of parachain const rewardAvailableInBlock = (stakedInBlock: bigint) => { @@ -38,11 +35,9 @@ before(async function () { await usingPlaygrounds(async (helper, privateKey) => { requirePalletsOrSkip(this, helper, [Pallets.AppPromotion]); - superuser = await privateKey('//Alice'); donor = await privateKey({filename: __filename}); - [palletAdmin] = await helper.arrange.createAccounts([100n], donor); - const api = helper.getApi(); - await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address}))); + palletAddress = helper.arrange.calculatePalleteAddress('appstake'); + palletAdmin = await privateKey('//PromotionAdmin'); nominal = helper.balance.getOneTokenNominal(); await helper.balance.transferToSubstrate(donor, palletAdmin.address, 1000n * nominal); await helper.balance.transferToSubstrate(donor, palletAddress, 1000n * nominal); @@ -223,58 +218,10 @@ expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n); })); - }); - }); - - describe('admin adress', () => { - itSub('can be set by sudo only', async ({helper}) => { - const api = helper.getApi(); - const nonAdmin = accounts.pop()!; - // nonAdmin can not set admin not from himself nor as a sudo - await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected; - await expect(helper.signTransaction(nonAdmin, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected; - - // Alice can - await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled; - }); - - itSub('can be any valid CrossAccountId', async ({helper}) => { - // We are not going to set an eth address as a sponsor, - // but we do want to check, it doesn't break anything; - const api = helper.getApi(); - const account = accounts.pop()!; - const ethAccount = helper.address.substrateToEth(account.address); - // Alice sets Ethereum address as a sudo. Then Substrate address back... - await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled; - await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled; - - // ...It doesn't break anything; - const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); - await expect(helper.signTransaction(account, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; }); - - itSub('can be reassigned', async ({helper}) => { - const api = helper.getApi(); - const [oldAdmin, newAdmin, collectionOwner] = [accounts.pop()!, accounts.pop()!, accounts.pop()!]; - const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); - - await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: oldAdmin.address})))).to.be.fulfilled; - await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: newAdmin.address})))).to.be.fulfilled; - await expect(helper.signTransaction(oldAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; - - await expect(helper.signTransaction(newAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled; - }); }); describe('collection sponsoring', () => { - before(async function () { - await usingPlaygrounds(async (helper) => { - const api = helper.getApi(); - const tx = api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})); - await helper.signTransaction(superuser, tx); - }); - }); - itSub('should actually sponsor transactions', async ({helper}) => { const api = helper.getApi(); const [collectionOwner, tokenSender, receiver] = [accounts.pop()!, accounts.pop()!, accounts.pop()!]; @@ -708,11 +655,6 @@ }); }); }); - -function calculatePalleteAddress(palletId: any) { - const address = stringToU8a(('modl' + palletId).padEnd(32, '\0')); - return encodeAddress(address); -} function calculateIncome(base: bigint, calcPeriod: bigint, iter = 0): bigint { const DAY = 7200n; --- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -1,7 +1,8 @@ // Copyright 2019-2022 Unique Network (Gibraltar) Ltd. // SPDX-License-Identifier: Apache-2.0 -import {mnemonicGenerate} from '@polkadot/util-crypto'; +import {stringToU8a} from '@polkadot/util'; +import {encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto'; import {UniqueHelper} from './unique'; import {ApiPromise, WsProvider} from '@polkadot/api'; import * as defs from '../../interfaces/definitions'; @@ -243,6 +244,11 @@ return balance; } + + calculatePalleteAddress(palletId: any) { + const address = stringToU8a(('modl' + palletId).padEnd(32, '\0')); + return encodeAddress(address); + } } class WaitGroup {