123456import {WsProvider, ApiPromise} from '@polkadot/api';7import {EventRecord} from '@polkadot/types/interfaces/system/types';8import {ExtrinsicStatus} from '@polkadot/types/interfaces/author/types';9import {IKeyringPair} from '@polkadot/types/types';1011import config from '../config';12import promisifySubstrate from './promisify-substrate';13import {ApiOptions, SubmittableExtrinsic, ApiTypes} from '@polkadot/api/types';14import * as defs from '../interfaces/definitions';151617function defaultApiOptions(): ApiOptions {18 const wsProvider = new WsProvider(config.substrateUrl);19 return {20 provider: wsProvider, signedExtensions: {21 ContractHelpers: {22 extrinsic: {},23 payload: {},24 },25 },26 rpc: {27 unique: defs.unique.rpc,28 },29 };30}3132export default async function usingApi<T = void>(action: (api: ApiPromise) => Promise<T>, settings: ApiOptions | undefined = undefined): Promise<T> {33 settings = settings || defaultApiOptions();34 const api: ApiPromise = new ApiPromise(settings);35 let result: T = null as unknown as T;3637 38 39 const consoleErr = console.error;40 const consoleLog = console.log;41 const consoleWarn = console.warn;4243 const outFn = (printer: any) => (...args: any[]) => {44 for (const arg of args) {45 if (typeof arg !== 'string')46 continue;47 if (arg.includes('1000:: Normal connection closure' || arg === 'Normal connection closure'))48 return;49 }50 printer(...args);51 };5253 console.error = outFn(consoleErr.bind(console));54 console.log = outFn(consoleLog.bind(console));55 console.warn = outFn(consoleWarn.bind(console));5657 try {58 await promisifySubstrate(api, async () => {59 if (api) {60 await api.isReadyOrError;61 result = await action(api);62 }63 })();64 } finally {65 await api.disconnect();66 console.error = consoleErr;67 console.log = consoleLog;68 console.warn = consoleWarn;69 }70 return result as T;71}7273enum TransactionStatus {74 Success,75 Fail,76 NotReady77}7879function getTransactionStatus(events: EventRecord[], status: ExtrinsicStatus): TransactionStatus {80 if (status.isReady) {81 return TransactionStatus.NotReady;82 }83 if (status.isBroadcast) {84 return TransactionStatus.NotReady;85 }86 if (status.isInBlock || status.isFinalized) {87 if(events.filter(e => e.event.data.method === 'ExtrinsicFailed').length > 0) {88 return TransactionStatus.Fail;89 }90 if(events.filter(e => e.event.data.method === 'ExtrinsicSuccess').length > 0) {91 return TransactionStatus.Success;92 }93 }9495 return TransactionStatus.Fail;96}9798export function executeTransaction(api: ApiPromise, sender: IKeyringPair, transaction: SubmittableExtrinsic<'promise'>): Promise<EventRecord[]> {99 return new Promise(async (res, rej) => {100 try {101 await transaction.signAndSend(sender, ({events, status}) => {102 if (!status.isInBlock && !status.isFinalized) return;103 for (const {event} of events) {104 if (api.events.system.ExtrinsicSuccess.is(event)) {105 res(events);106 } else if (api.events.system.ExtrinsicFailed.is(event)) {107 const {data: [error]} = event;108 if (error.isModule) {109 const decoded = api.registry.findMetaError(error.asModule);110 const {method, section} = decoded;111 rej(new Error(`${section}.${method}`));112 } else {113 rej(new Error(error.toString()));114 }115 }116 }117 });118 } catch (e) {119 rej(e);120 }121 });122}123124export function125submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {126 127 return new Promise(async (resolve, reject) => {128 try {129 await transaction.signAndSend(sender, ({events = [], status}) => {130 const transactionStatus = getTransactionStatus(events, status);131132 if (transactionStatus === TransactionStatus.Success) {133 resolve(events);134 } else if (transactionStatus === TransactionStatus.Fail) {135 console.log(`Something went wrong with transaction. Status: ${status}`);136 reject(events);137 }138 });139 } catch (e) {140 console.log('Error: ', e);141 reject(e);142 }143 });144}145146export function submitTransactionExpectFailAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {147 console.error = () => {};148 console.log = () => {};149150 151 return new Promise<EventRecord[]>(async function(res, rej) {152 const resolve = (rec: EventRecord[]) => {153 setTimeout(() => {154 res(rec);155 });156 };157 const reject = (errror: any) => {158 setTimeout(() => {159 rej(errror);160 });161 };162 try {163 await transaction.signAndSend(sender, ({events = [], status}) => {164 const transactionStatus = getTransactionStatus(events, status);165166 167168 if (transactionStatus === TransactionStatus.Success) {169 resolve(events);170 } else if (transactionStatus === TransactionStatus.Fail) {171 reject(events);172 }173 });174 } catch (e) {175 reject(e);176 }177 });178}