git.delta.rocks / unique-network / refs/commits / 8138c78fd9cb

difftreelog

source

tests/src/util/playgrounds/unique.dev.ts6.7 KiBsourcehistory
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}