difftreelog
Tests up
in: master
4 files changed
tests/src/app-promotion.test.tsdiffbeforeafterboth--- a/tests/src/app-promotion.test.ts
+++ b/tests/src/app-promotion.test.ts
@@ -63,36 +63,37 @@
});
describe('app-promotions.stake extrinsic', () => {
- it('should "lock" some balance in system.account, add it to "staked" map, and increase "totalStaked" amount', async () => {
+ it('should "lock" staking balance, add it to "staked" map, and increase "totalStaked" amount', async () => {
await usingPlaygrounds(async (helper) => {
const totalStakedBefore = await helper.staking.getTotalStaked();
const [staker, recepient] = await helper.arrange.createAccounts([400n, 0n], alice);
-
+
// Minimum stake amount is 100:
await expect(helper.staking.stake(staker, 100n * nominal - 1n)).to.be.eventually.rejected;
await helper.staking.stake(staker, 100n * nominal);
- // Staker balance is: miscFrozen: 100, feeFrozen: 100, reserved: 0n, free less than 300...
+ // Staker balance is: miscFrozen: 100, feeFrozen: 100, reserved: 0n...
// ...so he can not transfer 300
expect (await helper.balance.getSubstrateFull(staker.address)).to.contain({miscFrozen: 100n * nominal, feeFrozen: 100n * nominal, reserved: 0n});
await expect(helper.balance.transferToSubstrate(staker, recepient.address, 300n * nominal)).to.be.rejected;
+ // 100 -> 24 locked 100; staked 0; 24 => locked 100 staked 100
expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(100n * nominal);
- // TODO add helpers to assert bigints. Check balance close to 100
- expect(await helper.balance.getSubstrate(staker.address) - 99n * nominal >= (nominal / 2n)).to.be.true;
+ // TODO should be 0
expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(100n * nominal);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(399n);
// it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo?
expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 100n * nominal); // total tokens amount staked in app-promotion increased
await helper.staking.stake(staker, 200n * nominal);
- expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(300n * nominal);
- const stakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map((x) => x[1]);
- expect(stakedPerBlock).to.be.deep.equal([100n * nominal, 200n * nominal]);
+ expect(await helper.staking.getTotalStakingLocked({Substrate: staker.address})).to.be.equal(300n * nominal);
+ expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal);
+ expect((await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map((x) => x[1])).to.be.deep.equal([100n * nominal, 200n * nominal]);
});
});
- it('should reject transaction if stake amount is more than total free balance', async () => {
+ it('should reject transaction if stake amount is more than total free balance minus frozen', async () => {
await usingPlaygrounds(async helper => {
const [staker] = await helper.arrange.createAccounts([300n], alice);
@@ -100,7 +101,7 @@
await expect(helper.staking.stake(staker, 300n * nominal)).to.be.eventually.rejected;
await helper.staking.stake(staker, 150n * nominal);
- // Can't stake 4 tkn because Alice has ~3 free tkn, and 7 locked
+ // Can't stake 150 tkn because Alice has Less than 150 free - frozen tokens;
await expect(helper.staking.stake(staker, 150n * nominal)).to.be.eventually.rejected;
expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(150n * nominal);
});
@@ -117,9 +118,6 @@
expect(crowdStakes).to.deep.equal([100n * nominal, 100n * nominal, 100n * nominal, 100n * nominal]);
});
});
- // TODO it('Staker stakes 5 times in one block with nonce');
- // TODO it('Staked balance appears as locked in the balance pallet');
- // TODO it('Alice stakes huge amount of tokens');
});
describe('unstake balance extrinsic', () => {
@@ -130,6 +128,8 @@
await helper.staking.stake(staker, 500n * nominal);
await helper.staking.unstake(staker);
+ // balance state still
+
// Stakers balance now: {free: <100n, reserved: 500n, miscFrozen: 0, feeFrozen: 0};
// Staker can not transfer
// TODO expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 500n * nominal, miscFrozen: 0n, feeFrozen: 0n});
@@ -138,11 +138,20 @@
expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(500n * nominal);
expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n);
expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore);
+ });
+ });
+
+ it('should unlock balance after unlocking period ends and subtract it from "pendingUnstake"', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [staker] = await helper.arrange.createAccounts([1000n], alice);
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.unstake(staker);
+ await waitForRelayBlock(helper.api!, 20);
- // Wait for unstaking period. Balance now free ~600, and reserved, frozen, miscFrozeb 0n
+ // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n
await waitForRelayBlock(helper.api!, 20);
expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n * nominal, miscFrozen: 0n, feeFrozen: 0n});
- expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(599n);
+ expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n);
});
});
@@ -212,17 +221,6 @@
expect(unstakingPerBlock).has.length(2);
expect(unstakingPerBlock[0][1]).to.equal(100n * nominal);
expect(unstakingPerBlock[1][1]).to.equal(120n * nominal);
- });
- });
-
- it('should unlock balance after unlocking period ends and subtract it from "pendingUnstake"', async () => {
- await usingPlaygrounds(async (helper) => {
- const [staker] = await helper.arrange.createAccounts([1000n], alice);
- await helper.staking.stake(staker, 100n * nominal);
- await helper.staking.unstake(staker);
- await waitForRelayBlock(helper.api!, 20);
- // expect balance unlocked
- expect.fail('Not implemented');
});
});
@@ -376,13 +374,11 @@
it('should reject transaction if collection doesn\'t exist', async () => {
await usingPlaygrounds(async (helper) => {
- await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(999999999))).to.be.eventually.rejected;
- });
- });
-
- it('should reject transaction if collection was burnt', async () => {
- await usingPlaygrounds(async (helper) => {
const [collectionOwner] = await helper.arrange.createAccounts([10n], alice);
+
+ // collection has never existed
+ await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(999999999))).to.be.eventually.rejected;
+ // collection has been burned
const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
await collection.burn(collectionOwner);
@@ -406,13 +402,20 @@
it('should set sponsoring as disabled', async () => {
await usingPlaygrounds(async (helper) => {
- const [collectionOwner] = await helper.arrange.createAccounts([10n, 10n], alice);
- const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
+ const [collectionOwner, recepient] = await helper.arrange.createAccounts([10n, 0n], alice);
+ 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});
- await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.fulfilled;
- await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsoringCollection(collection.collectionId))).to.be.eventually.fulfilled;
+ await helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collection.collectionId));
+ await helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsoringCollection(collection.collectionId));
expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');
+
+ // Transactions are not sponsored anymore:
+ const ownerBalanceBefore = await helper.balance.getSubstrate(collectionOwner.address);
+ await token.transfer(collectionOwner, {Substrate: recepient.address});
+ const ownerBalanceAfter = await helper.balance.getSubstrate(collectionOwner.address);
+ expect(ownerBalanceAfter < ownerBalanceBefore).to.be.equal(true);
});
});
@@ -615,39 +618,57 @@
});
describe('app-promotion rewards', () => {
+ it('can not be called by non admin', async () => {
+ await usingPlaygrounds(async (helper) => {
+ const [nonAdmin] = await helper.arrange.createAccounts([10n], alice);
+ await expect(helper.signTransaction(nonAdmin, helper.api!.tx.promotion.payoutStakers(50))).to.be.rejected;
+ });
+ });
+
it('should credit 0.05% for staking period', async () => {
+ // TODO flaky test
await usingPlaygrounds(async helper => {
const [staker] = await helper.arrange.createAccounts([5000n], alice);
await helper.staking.stake(staker, 100n * nominal);
await helper.staking.stake(staker, 200n * nominal);
- await waitForRelayBlock(helper.api!, 40);
+ await waitForRelayBlock(helper.api!, 30);
await helper.signTransaction(palletAdmin, helper.api!.tx.promotion.payoutStakers(50));
-
+
const totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
expect(totalStakedPerBlock).to.be.deep.equal([calculateIncome(100n * nominal, 10n), calculateIncome(200n * nominal, 10n)]);
});
});
- it('can not be initialized by non admin', async () => {
+ it('shoud be paid for more than one period if payments was missed', async () => {
await usingPlaygrounds(async (helper) => {
- expect.fail('Test not implemented');
- });
- });
+ const [staker] = await helper.arrange.createAccounts([400n], alice);
+
+ await helper.staking.stake(staker, 100n * nominal);
+ await helper.staking.stake(staker, 200n * nominal);
+
+ await waitForRelayBlock(helper.api!, 55);
+ await helper.signTransaction(palletAdmin, helper.api!.tx.promotion.payoutStakers(50));
+ const stakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address});
+ expect(stakedPerBlock[0][1]).to.be.equal(calculateIncome(100n * nominal, 10n, 2));
+ expect(stakedPerBlock[1][1]).to.be.equal(calculateIncome(200n * nominal, 10n, 2));
- it('shoud be paid for more than one period if payments was missed', async () => {
- await usingPlaygrounds(async (helper) => {
- expect.fail('Test not implemented');
+ const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address);
+ const frozenBalanceShouldBe = calculateIncome(300n * nominal, 10n, 2);
+
+ expect(stakerFullBalance).to.contain({reserved: 0n, feeFrozen: frozenBalanceShouldBe, miscFrozen: frozenBalanceShouldBe});
});
});
it('should not be credited for unstaked (reserved) balance', async () => {
+ expect.fail('Test not implemented');
await usingPlaygrounds(async helper => {
- expect.fail('Implement me after unstake method will be fixed');
+ const staker = await helper.arrange.createAccounts([1000n], alice);
});
});
it('should bring compound interest', async () => {
+ // TODO flaky test
await usingPlaygrounds(async helper => {
const [staker] = await helper.arrange.createAccounts([800n], alice);
tests/src/util/playgrounds/types.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/types.ts
+++ b/tests/src/util/playgrounds/types.ts
@@ -101,6 +101,23 @@
tokenId: number;
}
+export interface IBlock {
+ extrinsics: IExtrinsic[]
+ header: {
+ parentHash: string,
+ number: number,
+ };
+}
+
+export interface IExtrinsic {
+ isSigned: boolean,
+ method: {
+ method: string,
+ section: string,
+ args: any[]
+ }
+}
+
export interface ICollectionCreationOptions {
name: string | number[];
description: string | number[];
tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034import {mnemonicGenerate} from '@polkadot/util-crypto';5import {UniqueHelper} from './unique';6import {ApiPromise, WsProvider} from '@polkadot/api';7import * as defs from '../../interfaces/definitions';8import {IKeyringPair} from '@polkadot/types/types';91011export class DevUniqueHelper extends UniqueHelper {12 /**13 * Arrange methods for tests14 */15 arrange: ArrangeGroup;1617 constructor(logger: { log: (msg: any, level: any) => void, level: any }) {18 super(logger);19 this.arrange = new ArrangeGroup(this);20 }2122 async connect(wsEndpoint: string, listeners?: any): Promise<void> {23 const wsProvider = new WsProvider(wsEndpoint);24 this.api = new ApiPromise({25 provider: wsProvider,26 signedExtensions: {27 ContractHelpers: {28 extrinsic: {},29 payload: {},30 },31 FakeTransactionFinalizer: {32 extrinsic: {},33 payload: {},34 },35 },36 rpc: {37 unique: defs.unique.rpc,38 appPromotion: defs.appPromotion.rpc,39 rmrk: defs.rmrk.rpc,40 eth: {41 feeHistory: {42 description: 'Dummy',43 params: [],44 type: 'u8',45 },46 maxPriorityFeePerGas: {47 description: 'Dummy',48 params: [],49 type: 'u8',50 },51 },52 },53 });54 await this.api.isReadyOrError;55 this.network = await UniqueHelper.detectNetwork(this.api);56 }57}5859class ArrangeGroup {60 helper: UniqueHelper;6162 constructor(helper: UniqueHelper) {63 this.helper = helper;64 }6566 /**67 * Generates accounts with the specified UNQ token balance 68 * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.69 * @param donor donor account for balances70 * @returns array of newly created accounts71 * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); 72 */73 createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {74 let nonce = await this.helper.chain.getNonce(donor.address);75 const tokenNominal = this.helper.balance.getOneTokenNominal();76 const transactions = [];77 const accounts: IKeyringPair[] = [];78 for (const balance of balances) {79 const recepient = this.helper.util.fromSeed(mnemonicGenerate());80 accounts.push(recepient);81 if (balance !== 0n) {82 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);83 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));84 nonce++;85 }86 }8788 await Promise.all(transactions).catch(e => {});89 90 //#region TODO remove this region, when nonce problem will be solved91 const checkBalances = async () => {92 let isSuccess = true;93 for (let i = 0; i < balances.length; i++) {94 const balance = await this.helper.balance.getSubstrate(accounts[i].address);95 if (balance !== balances[i] * tokenNominal) {96 isSuccess = false;97 break;98 }99 }100 return isSuccess;101 };102103 let accountsCreated = false;104 // checkBalances retry up to 5 blocks105 for (let index = 0; index < 5; index++) {106 accountsCreated = await checkBalances();107 if(accountsCreated) break;108 await this.waitNewBlocks(1);109 }110111 if (!accountsCreated) throw Error('Accounts generation failed');112 //#endregion113114 return accounts;115 };116117 // TODO combine this method and createAccounts into one118 createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {119 let transactions: any = [];120 const accounts: IKeyringPair[] = [];121122 const createAsManyAsCan = async () => {123 let nonce = await this.helper.chain.getNonce(donor.address);124 const tokenNominal = this.helper.balance.getOneTokenNominal();125 for (let i = 0; i < accountsToCreate; i++) {126 if (i === 500) { // if there are too many accounts to create127 await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled 128 transactions = []; //129 nonce = await this.helper.chain.getNonce(donor.address); // update nonce 130 }131 const recepient = this.helper.util.fromSeed(mnemonicGenerate());132 accounts.push(recepient);133 if (withBalance !== 0n) {134 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, withBalance * tokenNominal]);135 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));136 nonce++;137 }138 }139 140 const fullfilledAccounts = [];141 await Promise.allSettled(transactions);142 for (const account of accounts) {143 const accountBalance = await this.helper.balance.getSubstrate(account.address);144 if (accountBalance === withBalance * tokenNominal) {145 fullfilledAccounts.push(account);146 }147 }148 return fullfilledAccounts;149 };150151 152 const crowd: IKeyringPair[] = [];153 // do up to 5 retries154 for (let index = 0; index < 5 && accountsToCreate !== 0; index++) {155 const asManyAsCan = await createAsManyAsCan();156 crowd.push(...asManyAsCan);157 accountsToCreate -= asManyAsCan.length;158 }159160 if (accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);161162 return crowd;163 };164165 isDevNode = async () => {166 const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));167 const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));168 const findCreationDate = async (block: any) => {169 const humanBlock = block.toHuman();170 let date;171 humanBlock.block.extrinsics.forEach((ext: any) => {172 if(ext.method.section === 'timestamp') {173 date = Number(ext.method.args.now.replaceAll(',', ''));174 }175 });176 return date;177 };178 const block1date = await findCreationDate(block1);179 const block2date = await findCreationDate(block2);180 if(block2date! - block1date! < 9000) return true;181 };182183 /**184 * Wait for specified bnumber of blocks185 * @param blocksCount number of blocks to wait186 * @returns 187 */188 async waitNewBlocks(blocksCount = 1): Promise<void> {189 const promise = new Promise<void>(async (resolve) => {190 const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {191 if (blocksCount > 0) {192 blocksCount--;193 } else {194 unsubscribe();195 resolve();196 }197 });198 });199 return promise;200 }201}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034import {mnemonicGenerate} from '@polkadot/util-crypto';5import {UniqueHelper} from './unique';6import {ApiPromise, WsProvider} from '@polkadot/api';7import * as defs from '../../interfaces/definitions';8import {IKeyringPair} from '@polkadot/types/types';91011export class DevUniqueHelper extends UniqueHelper {12 /**13 * Arrange methods for tests14 */15 arrange: ArrangeGroup;1617 constructor(logger: { log: (msg: any, level: any) => void, level: any }) {18 super(logger);19 this.arrange = new ArrangeGroup(this);20 }2122 async connect(wsEndpoint: string, listeners?: any): Promise<void> {23 const wsProvider = new WsProvider(wsEndpoint);24 this.api = new ApiPromise({25 provider: wsProvider,26 signedExtensions: {27 ContractHelpers: {28 extrinsic: {},29 payload: {},30 },31 FakeTransactionFinalizer: {32 extrinsic: {},33 payload: {},34 },35 },36 rpc: {37 unique: defs.unique.rpc,38 appPromotion: defs.appPromotion.rpc,39 rmrk: defs.rmrk.rpc,40 eth: {41 feeHistory: {42 description: 'Dummy',43 params: [],44 type: 'u8',45 },46 maxPriorityFeePerGas: {47 description: 'Dummy',48 params: [],49 type: 'u8',50 },51 },52 },53 });54 await this.api.isReadyOrError;55 this.network = await UniqueHelper.detectNetwork(this.api);56 }57}5859class ArrangeGroup {60 helper: UniqueHelper;6162 constructor(helper: UniqueHelper) {63 this.helper = helper;64 }6566 /**67 * Generates accounts with the specified UNQ token balance 68 * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.69 * @param donor donor account for balances70 * @returns array of newly created accounts71 * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); 72 */73 createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {74 let nonce = await this.helper.chain.getNonce(donor.address);75 const tokenNominal = this.helper.balance.getOneTokenNominal();76 const transactions = [];77 const accounts: IKeyringPair[] = [];78 for (const balance of balances) {79 const recepient = this.helper.util.fromSeed(mnemonicGenerate());80 accounts.push(recepient);81 if (balance !== 0n) {82 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);83 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));84 nonce++;85 }86 }8788 await Promise.all(transactions).catch(e => {});89 90 //#region TODO remove this region, when nonce problem will be solved91 const checkBalances = async () => {92 let isSuccess = true;93 for (let i = 0; i < balances.length; i++) {94 const balance = await this.helper.balance.getSubstrate(accounts[i].address);95 if (balance !== balances[i] * tokenNominal) {96 isSuccess = false;97 break;98 }99 }100 return isSuccess;101 };102103 let accountsCreated = false;104 // checkBalances retry up to 5 blocks105 for (let index = 0; index < 5; index++) {106 accountsCreated = await checkBalances();107 if(accountsCreated) break;108 await this.waitNewBlocks(1);109 }110111 if (!accountsCreated) throw Error('Accounts generation failed');112 //#endregion113114 return accounts;115 };116117 // TODO combine this method and createAccounts into one118 createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {119 let transactions: any = [];120 const accounts: IKeyringPair[] = [];121122 const createAsManyAsCan = async () => {123 let nonce = await this.helper.chain.getNonce(donor.address);124 const tokenNominal = this.helper.balance.getOneTokenNominal();125 for (let i = 0; i < accountsToCreate; i++) {126 if (i === 500) { // if there are too many accounts to create127 await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled 128 transactions = []; //129 nonce = await this.helper.chain.getNonce(donor.address); // update nonce 130 }131 const recepient = this.helper.util.fromSeed(mnemonicGenerate());132 accounts.push(recepient);133 if (withBalance !== 0n) {134 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, withBalance * tokenNominal]);135 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));136 nonce++;137 }138 }139 140 const fullfilledAccounts = [];141 await Promise.allSettled(transactions);142 for (const account of accounts) {143 const accountBalance = await this.helper.balance.getSubstrate(account.address);144 if (accountBalance === withBalance * tokenNominal) {145 fullfilledAccounts.push(account);146 }147 }148 return fullfilledAccounts;149 };150151 152 const crowd: IKeyringPair[] = [];153 // do up to 5 retries154 for (let index = 0; index < 5 && accountsToCreate !== 0; index++) {155 const asManyAsCan = await createAsManyAsCan();156 crowd.push(...asManyAsCan);157 accountsToCreate -= asManyAsCan.length;158 }159160 if (accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);161162 return crowd;163 };164165 isDevNode = async () => {166 const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));167 const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));168 const findCreationDate = async (block: any) => {169 const humanBlock = block.toHuman();170 let date;171 humanBlock.block.extrinsics.forEach((ext: any) => {172 if(ext.method.section === 'timestamp') {173 date = Number(ext.method.args.now.replaceAll(',', ''));174 }175 });176 return date;177 };178 const block1date = await findCreationDate(block1);179 const block2date = await findCreationDate(block2);180 if(block2date! - block1date! < 9000) return true;181 };182183 /**184 * Wait for specified bnumber of blocks185 * @param blocksCount number of blocks to wait186 * @returns 187 */188 async waitNewBlocks(blocksCount = 1): Promise<void> {189 const promise = new Promise<void>(async (resolve) => {190 const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {191 if (blocksCount > 0) {192 blocksCount--;193 } else {194 unsubscribe();195 resolve();196 }197 });198 });199 return promise;200 }201}tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -9,7 +9,7 @@
import {ApiInterfaceEvents} from '@polkadot/api/types';
import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
import {IKeyringPair} from '@polkadot/types/types';
-import {IApiListeners, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
+import {IApiListeners, IBlock, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
const address = {} as ICrossAccountId;
@@ -1860,6 +1860,13 @@
return blockHash;
}
+ // TODO add docs
+ async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {
+ const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);
+ if (!blockHash) return null;
+ return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;
+ }
+
/**
* Get account nonce
* @param address substrate address