git.delta.rocks / unique-network / refs/commits / 5b36ad8fb241

difftreelog

source

tests/src/substrate/substrate-api.ts7.0 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {ApiPromise, WsProvider} from '@polkadot/api';18import {ApiOptions, ApiTypes, SubmittableExtrinsic} from '@polkadot/api/types';19import {ExtrinsicStatus} from '@polkadot/types/interfaces/author/types';20import {EventRecord} from '@polkadot/types/interfaces/system/types';21import {IKeyringPair} from '@polkadot/types/types';22import config from '../config';23import '../interfaces/augment-api-events';24import * as defs from '../interfaces/definitions';25import privateKey from './privateKey';26import promisifySubstrate from './promisify-substrate';27282930function defaultApiOptions(): ApiOptions {31  const wsProvider = new WsProvider(config.substrateUrl);32  return {33    provider: wsProvider, signedExtensions: {34      ContractHelpers: {35        extrinsic: {},36        payload: {},37      },38      FakeTransactionFinalizer: {39        extrinsic: {},40        payload: {},41      },42    },43    rpc: {44      unique: defs.unique.rpc,45      appPromotion: defs.appPromotion.rpc,46      rmrk: defs.rmrk.rpc,47      eth: {48        feeHistory: {49          description: 'Dummy',50          params: [],51          type: 'u8',52        },53        maxPriorityFeePerGas: {54          description: 'Dummy',55          params: [],56          type: 'u8',57        },58      },59    },60  };61}6263export async function getApiConnection(settings: ApiOptions | undefined = undefined): Promise<ApiPromise> {64  settings = settings || defaultApiOptions();65  const api = new ApiPromise(settings);6667  if (api) {68    await api.isReadyOrError;69  }7071  return api;72}7374export default async function usingApi<T = void>(action: (api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair) => Promise<T>, settings: ApiOptions | undefined = undefined): Promise<T> {75  settings = settings || defaultApiOptions();76  const api: ApiPromise = new ApiPromise(settings);77  let result: T = null as unknown as T;7879  // TODO: Remove, this is temporary: Filter unneeded API output80  // (Jaco promised it will be removed in the next version)81  const consoleErr = console.error;82  const consoleLog = console.log;83  const consoleWarn = console.warn;8485  const outFn = (printer: any) => (...args: any[]) => {86    for (const arg of args) {87      if (typeof arg !== 'string')88        continue;89      if (arg.includes('1000:: Normal connection closure' || arg === 'Normal connection closure'))90        return;91    }92    printer(...args);93  };9495  console.error = outFn(consoleErr.bind(console));96  console.log = outFn(consoleLog.bind(console));97  console.warn = outFn(consoleWarn.bind(console));9899  try {100    await promisifySubstrate(api, async () => {101      if (api) {102        await api.isReadyOrError;103        const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;104        const privateKeyWrapper = (account: string) => privateKey(account, Number(ss58Format));105        result = await action(api, privateKeyWrapper);106      }107    })();108  } finally {109    await api.disconnect();110    console.error = consoleErr;111    console.log = consoleLog;112    console.warn = consoleWarn;113  }114  return result as T;115}116117enum TransactionStatus {118  Success,119  Fail,120  NotReady121}122123function getTransactionStatus(events: EventRecord[], status: ExtrinsicStatus): TransactionStatus {124  if (status.isReady) {125    return TransactionStatus.NotReady;126  }127  if (status.isBroadcast) {128    return TransactionStatus.NotReady;129  }130  if (status.isInBlock || status.isFinalized) {131    if(events.filter(e => e.event.data.method === 'ExtrinsicFailed').length > 0) {132      return TransactionStatus.Fail;133    }134    if(events.filter(e => e.event.data.method === 'ExtrinsicSuccess').length > 0) {135      return TransactionStatus.Success;136    }137  }138139  return TransactionStatus.Fail;140}141142export function executeTransaction(api: ApiPromise, sender: IKeyringPair, transaction: SubmittableExtrinsic<'promise'>): Promise<EventRecord[]> {143  return new Promise(async (res, rej) => {144    try {145      await transaction.signAndSend(sender, ({events, status}) => {146        if (!status.isInBlock && !status.isFinalized) return;147        for (const {event} of events) {148          if (api.events.system.ExtrinsicSuccess.is(event)) {149            res(events);150          } else if (api.events.system.ExtrinsicFailed.is(event)) {151            const {data: [error]} = event;152            if (error.isModule) {153              const decoded = api.registry.findMetaError(error.asModule);154              const {method, section} = decoded;155              rej(new Error(`${section}.${method}`));156            } else {157              rej(new Error(error.toString()));158            }159          }160        }161      });162    } catch (e) {163      rej(e);164    }165  });166}167168export function169submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {170  /* eslint no-async-promise-executor: "off" */171  return new Promise(async (resolve, reject) => {172    try {173      await transaction.signAndSend(sender, ({events = [], status}) => {174        const transactionStatus = getTransactionStatus(events, status);175176        if (transactionStatus === TransactionStatus.Success) {177          resolve(events);178        } else if (transactionStatus === TransactionStatus.Fail) {179          console.log(`Something went wrong with transaction. Status: ${status}`);180          reject(events);181        }182      });183    } catch (e) {184      console.log('Error: ', e);185      reject(e);186    }187  });188}189190export function submitTransactionExpectFailAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {191  console.error = () => {};192  console.log = () => {};193194  /* eslint no-async-promise-executor: "off" */195  return new Promise<EventRecord[]>(async function(res, rej) {196    const resolve = (rec: EventRecord[]) => {197      setTimeout(() => {198        res(rec);199      });200    };201    const reject = (errror: any) => {202      setTimeout(() => {203        rej(errror);204      });205    };206    try {207      await transaction.signAndSend(sender, ({events = [], status}) => {208        const transactionStatus = getTransactionStatus(events, status);209210        // console.log('transactionStatus', transactionStatus, 'events', events);211212        if (transactionStatus === TransactionStatus.Success) {213          resolve(events);214        } else if (transactionStatus === TransactionStatus.Fail) {215          reject(events);216        }217      });218    } catch (e) {219      reject(e);220    }221  });222}