git.delta.rocks / unique-network / refs/commits / 36c9f569dead

difftreelog

source

tests/src/util/playgrounds/unique.dev.ts6.6 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        rmrk: defs.rmrk.rpc,39        eth: {40          feeHistory: {41            description: 'Dummy',42            params: [],43            type: 'u8',44          },45          maxPriorityFeePerGas: {46            description: 'Dummy',47            params: [],48            type: 'u8',49          },50        },51      },52    });53    await this.api.isReadyOrError;54    this.network = await UniqueHelper.detectNetwork(this.api);55  }56}5758class ArrangeGroup {59  helper: UniqueHelper;6061  constructor(helper: UniqueHelper) {62    this.helper = helper;63  }6465  /**66   * Generates accounts with the specified UNQ token balance 67   * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal.68   * @param donor donor account for balances69   * @returns array of newly created accounts70   * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); 71   */72  createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {73    let nonce = await this.helper.chain.getNonce(donor.address);74    const tokenNominal = this.helper.balance.getOneTokenNominal();75    const transactions = [];76    const accounts: IKeyringPair[] = [];77    for (const balance of balances) {78      const recepient = this.helper.util.fromSeed(mnemonicGenerate());79      accounts.push(recepient);80      if (balance !== 0n) {81        const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);82        transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));83        nonce++;84      }85    }8687    await Promise.all(transactions).catch(e => {});88    89    //#region TODO remove this region, when nonce problem will be solved90    const checkBalances = async () => {91      let isSuccess = true;92      for (let i = 0; i < balances.length; i++) {93        const balance = await this.helper.balance.getSubstrate(accounts[i].address);94        if (balance !== balances[i] * tokenNominal) {95          isSuccess = false;96          break;97        }98      }99      return isSuccess;100    };101102    let accountsCreated = false;103    // checkBalances retry up to 5 blocks104    for (let index = 0; index < 5; index++) {105      accountsCreated = await checkBalances();106      if(accountsCreated) break;107      await this.waitNewBlocks(1);108    }109110    if (!accountsCreated) throw Error('Accounts generation failed');111    //#endregion112113    return accounts;114  };115116  // TODO combine this method and createAccounts into one117  createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {118    let transactions: any = [];119    const accounts: IKeyringPair[] = [];120121    const createAsManyAsCan = async () => {122      let nonce = await this.helper.chain.getNonce(donor.address);123      const tokenNominal = this.helper.balance.getOneTokenNominal();124      for (let i = 0; i < accountsToCreate; i++) {125        if (i === 500) { // if there are too many accounts to create126          await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled 127          transactions = []; //128          nonce = await this.helper.chain.getNonce(donor.address); // update nonce 129        }130        const recepient = this.helper.util.fromSeed(mnemonicGenerate());131        accounts.push(recepient);132        if (withBalance !== 0n) {133          const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, withBalance * tokenNominal]);134          transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));135          nonce++;136        }137      }138      139      const fullfilledAccounts = [];140      await Promise.allSettled(transactions);141      for (const account of accounts) {142        const accountBalance = await this.helper.balance.getSubstrate(account.address);143        if (accountBalance === withBalance * tokenNominal) {144          fullfilledAccounts.push(account);145        }146      }147      return fullfilledAccounts;148    };149150    151    const crowd: IKeyringPair[] = [];152    // do up to 5 retries153    for (let index = 0; index < 5 && accountsToCreate !== 0; index++) {154      const asManyAsCan = await createAsManyAsCan();155      crowd.push(...asManyAsCan);156      accountsToCreate -= asManyAsCan.length;157    }158159    if (accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);160161    return crowd;162  };163164  isDevNode = async () => {165    const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));166    const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));167    const findCreationDate = async (block: any) => {168      const humanBlock = block.toHuman();169      let date;170      humanBlock.block.extrinsics.forEach((ext: any) => {171        if(ext.method.section === 'timestamp') {172          date = Number(ext.method.args.now.replaceAll(',', ''));173        }174      });175      return date;176    };177    const block1date = await findCreationDate(block1);178    const block2date = await findCreationDate(block2);179    if(block2date! - block1date! < 9000) return true;180  };181182  /**183   * Wait for specified bnumber of blocks184   * @param blocksCount number of blocks to wait185   * @returns 186   */187  async waitNewBlocks(blocksCount = 1): Promise<void> {188    const promise = new Promise<void>(async (resolve) => {189      const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {190        if (blocksCount > 0) {191          blocksCount--;192        } else {193          unsubscribe();194          resolve();195        }196      });197    });198    return promise;199  }200}