difftreelog
Tests: unstakeAll after each test
in: master
2 files changed
tests/src/sub/appPromotion/appPromotion.test.tsdiffbeforeafterboth--- a/tests/src/sub/appPromotion/appPromotion.test.ts
+++ b/tests/src/sub/appPromotion/appPromotion.test.ts
@@ -26,6 +26,13 @@
let nominal: bigint;
let palletAddress: string;
let accounts: IKeyringPair[];
+let usedAccounts: IKeyringPair[] = [];
+
+function getAccount(accountsNumber: number) {
+ const accs = accounts.splice(0, accountsNumber);
+ usedAccounts.push(...accs);
+ return accs;
+}
// App promotion periods:
// LOCKING_PERIOD = 12 blocks of relay
// UNLOCKING_PERIOD = 6 blocks of parachain
@@ -39,15 +46,29 @@
palletAdmin = await privateKey('//PromotionAdmin');
nominal = helper.balance.getOneTokenNominal();
- const accountBalances = new Array(100);
- accountBalances.fill(1000n);
+ const accountBalances = new Array(200).fill(1000n);
accounts = await helper.arrange.createAccounts(accountBalances, donor); // create accounts-pool to speed up tests
});
});
+ afterEach(async () => {
+ await usingPlaygrounds(async (helper) => {
+ let unstakeTxs = [];
+ for (const account of usedAccounts) {
+ if (unstakeTxs.length === 3) {
+ await Promise.all(unstakeTxs);
+ unstakeTxs = [];
+ }
+ unstakeTxs.push(helper.staking.unstakeAll(account));
+ }
+ await Promise.all(unstakeTxs);
+ usedAccounts = [];
+ });
+ });
+
describe('stake extrinsic', () => {
itSub('should "lock" staking balance, add it to "staked" map, and increase "totalStaked" amount', async ({helper}) => {
- const [staker, recepient] = [accounts.pop()!, accounts.pop()!];
+ const [staker, recepient] = getAccount(2);
const totalStakedBefore = await helper.staking.getTotalStaked();
// Minimum stake amount is 100:
@@ -114,7 +135,7 @@
});
itSub('should allow to stake() if balance is locked with different id', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
// staker has tokens locked with vesting id:
await helper.balance.vestedTransfer(donor, staker.address, {start: 0n, period: 1n, periodCount: 1n, perPeriod: 200n * nominal});
@@ -147,7 +168,7 @@
});
itSub('should not allow to stake(), if stake amount is more than total free balance minus locked by staking', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
// Can't stake full balance because Alice needs to pay some fee
await expect(helper.staking.stake(staker, 1000n * nominal)).to.be.rejected; // With('Arithmetic')
@@ -159,7 +180,7 @@
});
itSub('for different accounts in one block is possible', async ({helper}) => {
- const crowd = [accounts.pop()!, accounts.pop()!, accounts.pop()!, accounts.pop()!];
+ const crowd = getAccount(4);
const crowdStartsToStake = crowd.map(user => helper.staking.stake(user, 100n * nominal));
await expect(Promise.all(crowdStartsToStake)).to.be.fulfilled;
@@ -175,7 +196,7 @@
{method: 'unstakePartial' as const},
].map(testCase => {
itSub(`[${testCase.method}] should move tokens to "pendingUnstake" and subtract it from totalStaked`, async ({helper}) => {
- const [staker, recepient] = [accounts.pop()!, accounts.pop()!];
+ const [staker, recepient] = getAccount(2);
const totalStakedBefore = await helper.staking.getTotalStaked();
const STAKE_AMOUNT = 900n * nominal;
@@ -201,7 +222,7 @@
{method: 'unstakePartial' as const},
].map(testCase => {
itSub(`[${testCase.method}] should unlock balance after unlocking period ends and remove it from "pendingUnstake"`, async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
testCase.method === 'unstakeAll'
? await helper.staking.unstakeAll(staker)
@@ -224,7 +245,7 @@
{method: 'unstakePartial' as const},
].map(testCase => {
itSub(`[${testCase.method}] should successfully unstake multiple stakes`, async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.stake(staker, 200n * nominal);
await helper.staking.stake(staker, 300n * nominal);
@@ -264,7 +285,7 @@
{method: 'unstakePartial' as const},
].map(testCase => {
itSub(`[${testCase.method}] should not have any effects if no active stakes`, async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
// unstake has no effect if no stakes at all
testCase.method === 'unstakeAll'
@@ -298,7 +319,7 @@
{method: 'unstakePartial' as const},
].map(testCase => {
itSub(`[${testCase.method}] should create different pending-unlock for each unlocking stake`, async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
testCase.method === 'unstakeAll'
? await helper.staking.unstakeAll(staker)
@@ -321,7 +342,7 @@
{method: 'unstakePartial' as const},
].map(testCase => {
itSub(`[${testCase.method}] should be possible for 3 accounts in one block`, async ({helper}) => {
- const stakers = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
+ const stakers = getAccount(3);
await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
await Promise.all(stakers.map(staker => {
@@ -339,7 +360,7 @@
itSub('should not be possible for more than 3 accounts in one block', async ({helper}) => {
if (!await helper.arrange.isDevNode()) {
- const stakers = await helper.arrange.createAccounts([200n,200n,200n,200n,200n,200n,200n,200n,200n,200n], donor);
+ const stakers = getAccount(10);
await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
const unstakingResults = await Promise.allSettled(stakers.map((staker, i) => {
@@ -354,7 +375,7 @@
});
itSub('Cannot partially unstake more than staked', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
// Staker stakes 300:
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.stake(staker, 200n * nominal);
@@ -374,7 +395,7 @@
});
itSub('Can partially unstake arbitrary amount', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.stake(staker, 200n * nominal);
@@ -408,7 +429,7 @@
});
itSub('can mix different type of unstakes', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.stake(staker, 200n * nominal);
@@ -433,7 +454,7 @@
describe('collection sponsoring', () => {
itSub('should actually sponsor transactions', async ({helper}) => {
const api = helper.getApi();
- const [collectionOwner, tokenSender, receiver] = [accounts.pop()!, accounts.pop()!, accounts.pop()!];
+ const [collectionOwner, tokenSender, receiver] = getAccount(3);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'Name', description: 'Description', tokenPrefix: 'Prefix', limits: {sponsorTransferTimeout: 0}});
const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address});
await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId));
@@ -450,7 +471,7 @@
itSub('can not be set by non admin', async ({helper}) => {
const api = helper.getApi();
- const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];
+ const [collectionOwner, nonAdmin] = getAccount(2);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
@@ -460,7 +481,7 @@
itSub('should set pallet address as confirmed admin', async ({helper}) => {
const api = helper.getApi();
- const [collectionOwner, oldSponsor] = [accounts.pop()!, accounts.pop()!];
+ const [collectionOwner, oldSponsor] = getAccount(2);
// Can set sponsoring for collection without sponsor
const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});
@@ -482,7 +503,7 @@
itSub('can be overwritten by collection owner', async ({helper}) => {
const api = helper.getApi();
- const [collectionOwner, newSponsor] = [accounts.pop()!, accounts.pop()!];
+ const [collectionOwner, newSponsor] = getAccount(2);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
const collectionId = collection.collectionId;
@@ -501,7 +522,7 @@
itSub('should not overwrite collection limits set by the owner earlier', async ({helper}) => {
const api = helper.getApi();
const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};
- const collectionWithLimits = await helper.nft.mintCollection(accounts.pop()!, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
+ const collectionWithLimits = await helper.nft.mintCollection(getAccount(1)[0], {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.fulfilled;
expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);
@@ -509,7 +530,7 @@
itSub('should reject transaction if collection doesn\'t exist', async ({helper}) => {
const api = helper.getApi();
- const collectionOwner = accounts.pop()!;
+ const [collectionOwner] = getAccount(1);
// collection has never existed
await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(999999999))).to.be.rejected;
@@ -524,7 +545,7 @@
describe('stopSponsoringCollection', () => {
itSub('can not be called by non-admin', async ({helper}) => {
const api = helper.getApi();
- const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!];
+ const [collectionOwner, nonAdmin] = getAccount(2);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled;
@@ -535,7 +556,7 @@
itSub('should set sponsoring as disabled', async ({helper}) => {
const api = helper.getApi();
- const [collectionOwner, recepient] = [accounts.pop()!, accounts.pop()!];
+ const [collectionOwner, recepient] = getAccount(2);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}});
const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address});
@@ -553,7 +574,7 @@
itSub('should not affect collection which is not sponsored by pallete', async ({helper}) => {
const api = helper.getApi();
- const collectionOwner = accounts.pop()!;
+ const [collectionOwner] = getAccount(1);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: collectionOwner.address});
await collection.confirmSponsorship(collectionOwner);
@@ -563,7 +584,7 @@
});
itSub('should reject transaction if collection does not exist', async ({helper}) => {
- const collectionOwner = accounts.pop()!;
+ const [collectionOwner] = getAccount(1);
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
await collection.burn(collectionOwner);
@@ -637,7 +658,7 @@
});
itEth('can not be set by non admin', async ({helper}) => {
- const nonAdmin = accounts.pop()!;
+ const [nonAdmin] = getAccount(1);
const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner);
const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
@@ -719,7 +740,7 @@
});
itEth('can not be called by non-admin', async ({helper}) => {
- const nonAdmin = accounts.pop()!;
+ const [nonAdmin] = getAccount(1);
const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
const flipper = await helper.eth.deployFlipper(contractOwner);
@@ -729,7 +750,7 @@
});
itEth('should not affect a contract which is not sponsored by pallete', async ({helper}) => {
- const nonAdmin = accounts.pop()!;
+ const [nonAdmin] = getAccount(1);
const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase();
const flipper = await helper.eth.deployFlipper(contractOwner);
const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner);
@@ -741,12 +762,12 @@
describe('payoutStakers', () => {
itSub('can not be called by non admin', async ({helper}) => {
- const nonAdmin = accounts.pop()!;
+ const [nonAdmin] = getAccount(1);
await expect(helper.admin.payoutStakers(nonAdmin, 100)).to.be.rejectedWith('appPromotion.NoPermission');
});
itSub('should increase total staked', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
const totalStakedBefore = await helper.staking.getTotalStaked();
await helper.staking.stake(staker, 100n * nominal);
@@ -763,7 +784,7 @@
});
itSub('should credit 0.05% for staking period', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await waitPromotionPeriodDoesntEnd(helper);
@@ -789,7 +810,7 @@
});
itSub('shoud be paid for more than one period if payments was missed', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
// wait for two rewards are available:
@@ -808,7 +829,7 @@
itSub('should not be credited for pending-unstaked tokens', async ({helper}) => {
// staker unstakes before rewards been payed
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD);
@@ -823,7 +844,7 @@
});
itSub('should bring compound interest', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
@@ -841,7 +862,7 @@
});
itSub('can calculate reward for tiny stake', async ({helper}) => {
- const staker = accounts.pop()!;
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.unstakePartial(staker, 100n * nominal - 1n);
@@ -855,7 +876,8 @@
});
itSub('can eventually pay all rewards', async ({helper}) => {
- const stakers = await helper.arrange.createAccounts(new Array(100).fill(200n), donor);
+ const stakers = getAccount(30);
+ // Create 30 stakes:
await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal)));
let unstakingTxs = [];
@@ -867,7 +889,7 @@
unstakingTxs.push(helper.staking.unstakePartial(staker, 100n * nominal - 1n));
}
- const [staker] = await helper.arrange.createAccounts([1000n], donor);
+ const [staker] = getAccount(1);
await helper.staking.stake(staker, 100n * nominal);
const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block));
tests/src/util/globalSetup.tsdiffbeforeafterboth29 const api = helper.getApi();29 const api = helper.getApi();30 await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));30 await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));31 const nominal = helper.balance.getOneTokenNominal();31 const nominal = helper.balance.getOneTokenNominal();32 await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 1000n * nominal);32 await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 10000n * nominal);33 await helper.balance.transferToSubstrate(superuser, palletAddress, 1000n * nominal);33 await helper.balance.transferToSubstrate(superuser, palletAddress, 10000n * nominal);34 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.configuration34 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.configuration35 .setAppPromotionConfigurationOverride({35 .setAppPromotionConfigurationOverride({36 recalculationInterval: LOCKING_PERIOD,36 recalculationInterval: LOCKING_PERIOD,