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.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034import {5 usingPlaygrounds, Pallets, DONOR_FUNDING, MINIMUM_DONOR_FUND, LOCKING_PERIOD, UNLOCKING_PERIOD,6} from './index';7import * as path from 'path';8import {promises as fs} from 'fs';910// This function should be called before running test suites.11const globalSetup = async (): Promise<void> => {12 await usingPlaygrounds(async (helper, privateKey) => {13 try {14 // 1. Wait node producing blocks15 await helper.wait.newBlocks(1, 600_000);1617 // 2. Create donors for test files18 await fundFilenamesWithRetries(3)19 .then((result) => {20 if (!result) throw Error('Some problems with fundFilenamesWithRetries');21 });2223 // 3. Configure App Promotion24 const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]);25 if (missingPallets.length === 0) {26 const superuser = await privateKey('//Alice');27 const palletAddress = helper.arrange.calculatePalletAddress('appstake');28 const palletAdmin = await privateKey('//PromotionAdmin');29 const api = helper.getApi();30 await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));31 const nominal = helper.balance.getOneTokenNominal();32 await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 1000n * nominal);33 await helper.balance.transferToSubstrate(superuser, palletAddress, 1000n * nominal);34 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.configuration35 .setAppPromotionConfigurationOverride({36 recalculationInterval: LOCKING_PERIOD,37 pendingInterval: UNLOCKING_PERIOD})], true);38 }39 } catch (error) {40 console.error(error);41 throw Error('Error during globalSetup');42 }43 });44};4546async function getFiles(rootPath: string): Promise<string[]> {47 const files = await fs.readdir(rootPath, {withFileTypes: true});48 const filenames: string[] = [];49 for (const entry of files) {50 const res = path.resolve(rootPath, entry.name);51 if (entry.isDirectory()) {52 filenames.push(...await getFiles(res));53 } else {54 filenames.push(res);55 }56 }57 return filenames;58}5960const fundFilenames = async () => {61 await usingPlaygrounds(async (helper, privateKey) => {62 const oneToken = helper.balance.getOneTokenNominal();63 const alice = await privateKey('//Alice');64 const nonce = await helper.chain.getNonce(alice.address);65 const filenames = await getFiles(path.resolve(__dirname, '..'));6667 // batching is actually undesireable, it takes away the time while all the transactions actually succeed68 const batchSize = 300;69 let balanceGrantedCounter = 0;70 for (let b = 0; b < filenames.length; b += batchSize) {71 const tx = [];72 let batchBalanceGrantedCounter = 0;73 for (let i = 0; batchBalanceGrantedCounter < batchSize && b + i < filenames.length; i++) {74 const f = filenames[b + i];75 if (!f.endsWith('.test.ts') && !f.endsWith('seqtest.ts') || f.includes('.outdated')) continue;76 const account = await privateKey({filename: f, ignoreFundsPresence: true});77 const aliceBalance = await helper.balance.getSubstrate(account.address);7879 if (aliceBalance < MINIMUM_DONOR_FUND * oneToken) {80 tx.push(helper.executeExtrinsic(81 alice,82 'api.tx.balances.transfer',83 [account.address, DONOR_FUNDING * oneToken],84 true,85 {nonce: nonce + balanceGrantedCounter++},86 ).then(() => true).catch(() => {console.error(`Transaction to ${path.basename(f)} registered as failed. Strange.`); return false;}));87 batchBalanceGrantedCounter++;88 }89 }9091 if(tx.length > 0) {92 console.log(`Granting funds to ${batchBalanceGrantedCounter} filename accounts.`);93 const result = await Promise.all(tx);94 if (result && result.lastIndexOf(false) > -1) throw new Error('The transactions actually probably succeeded, should check the balances.');95 }96 }9798 if (balanceGrantedCounter == 0) console.log('No account needs additional funding.');99 });100};101102const fundFilenamesWithRetries = (retriesLeft: number): Promise<boolean> => {103 if (retriesLeft <= 0) return Promise.resolve(false);104 return fundFilenames()105 .then(() => Promise.resolve(true))106 .catch(e => {107 console.error(e);108 console.error(`Some transactions might have failed. ${retriesLeft>1'Retrying...''Something is wrong.'}\n`);109 return fundFilenamesWithRetries(--retriesLeft);110 });111};112113globalSetup().catch(() => process.exit(1));1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034import {5 usingPlaygrounds, Pallets, DONOR_FUNDING, MINIMUM_DONOR_FUND, LOCKING_PERIOD, UNLOCKING_PERIOD,6} from './index';7import * as path from 'path';8import {promises as fs} from 'fs';910// This function should be called before running test suites.11const globalSetup = async (): Promise<void> => {12 await usingPlaygrounds(async (helper, privateKey) => {13 try {14 // 1. Wait node producing blocks15 await helper.wait.newBlocks(1, 600_000);1617 // 2. Create donors for test files18 await fundFilenamesWithRetries(3)19 .then((result) => {20 if (!result) throw Error('Some problems with fundFilenamesWithRetries');21 });2223 // 3. Configure App Promotion24 const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]);25 if (missingPallets.length === 0) {26 const superuser = await privateKey('//Alice');27 const palletAddress = helper.arrange.calculatePalletAddress('appstake');28 const palletAdmin = await privateKey('//PromotionAdmin');29 const api = helper.getApi();30 await helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})));31 const nominal = helper.balance.getOneTokenNominal();32 await helper.balance.transferToSubstrate(superuser, palletAdmin.address, 10000n * nominal);33 await helper.balance.transferToSubstrate(superuser, palletAddress, 10000n * nominal);34 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [api.tx.configuration35 .setAppPromotionConfigurationOverride({36 recalculationInterval: LOCKING_PERIOD,37 pendingInterval: UNLOCKING_PERIOD})], true);38 }39 } catch (error) {40 console.error(error);41 throw Error('Error during globalSetup');42 }43 });44};4546async function getFiles(rootPath: string): Promise<string[]> {47 const files = await fs.readdir(rootPath, {withFileTypes: true});48 const filenames: string[] = [];49 for (const entry of files) {50 const res = path.resolve(rootPath, entry.name);51 if (entry.isDirectory()) {52 filenames.push(...await getFiles(res));53 } else {54 filenames.push(res);55 }56 }57 return filenames;58}5960const fundFilenames = async () => {61 await usingPlaygrounds(async (helper, privateKey) => {62 const oneToken = helper.balance.getOneTokenNominal();63 const alice = await privateKey('//Alice');64 const nonce = await helper.chain.getNonce(alice.address);65 const filenames = await getFiles(path.resolve(__dirname, '..'));6667 // batching is actually undesireable, it takes away the time while all the transactions actually succeed68 const batchSize = 300;69 let balanceGrantedCounter = 0;70 for (let b = 0; b < filenames.length; b += batchSize) {71 const tx = [];72 let batchBalanceGrantedCounter = 0;73 for (let i = 0; batchBalanceGrantedCounter < batchSize && b + i < filenames.length; i++) {74 const f = filenames[b + i];75 if (!f.endsWith('.test.ts') && !f.endsWith('seqtest.ts') || f.includes('.outdated')) continue;76 const account = await privateKey({filename: f, ignoreFundsPresence: true});77 const aliceBalance = await helper.balance.getSubstrate(account.address);7879 if (aliceBalance < MINIMUM_DONOR_FUND * oneToken) {80 tx.push(helper.executeExtrinsic(81 alice,82 'api.tx.balances.transfer',83 [account.address, DONOR_FUNDING * oneToken],84 true,85 {nonce: nonce + balanceGrantedCounter++},86 ).then(() => true).catch(() => {console.error(`Transaction to ${path.basename(f)} registered as failed. Strange.`); return false;}));87 batchBalanceGrantedCounter++;88 }89 }9091 if(tx.length > 0) {92 console.log(`Granting funds to ${batchBalanceGrantedCounter} filename accounts.`);93 const result = await Promise.all(tx);94 if (result && result.lastIndexOf(false) > -1) throw new Error('The transactions actually probably succeeded, should check the balances.');95 }96 }9798 if (balanceGrantedCounter == 0) console.log('No account needs additional funding.');99 });100};101102const fundFilenamesWithRetries = (retriesLeft: number): Promise<boolean> => {103 if (retriesLeft <= 0) return Promise.resolve(false);104 return fundFilenames()105 .then(() => Promise.resolve(true))106 .catch(e => {107 console.error(e);108 console.error(`Some transactions might have failed. ${retriesLeft>1'Retrying...''Something is wrong.'}\n`);109 return fundFilenamesWithRetries(--retriesLeft);110 });111};112113globalSetup().catch(() => process.exit(1));