1234567891011121314151617import {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 rmrk: defs.rmrk.rpc,46 eth: {47 feeHistory: {48 description: 'Dummy',49 params: [],50 type: 'u8',51 },52 maxPriorityFeePerGas: {53 description: 'Dummy',54 params: [],55 type: 'u8',56 },57 },58 },59 };60}6162export default async function usingApi<T = void>(action: (api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair) => Promise<T>, settings: ApiOptions | undefined = undefined): Promise<T> {63 settings = settings || defaultApiOptions();64 const api: ApiPromise = new ApiPromise(settings);65 let result: T = null as unknown as T;6667 68 69 const consoleErr = console.error;70 const consoleLog = console.log;71 const consoleWarn = console.warn;7273 const outFn = (printer: any) => (...args: any[]) => {74 for (const arg of args) {75 if (typeof arg !== 'string')76 continue;77 if (arg.includes('1000:: Normal connection closure' || arg === 'Normal connection closure'))78 return;79 }80 printer(...args);81 };8283 console.error = outFn(consoleErr.bind(console));84 console.log = outFn(consoleLog.bind(console));85 console.warn = outFn(consoleWarn.bind(console));8687 try {88 await promisifySubstrate(api, async () => {89 if (api) {90 await api.isReadyOrError;91 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;92 const privateKeyWrapper = (account: string) => privateKey(account, Number(ss58Format));93 result = await action(api, privateKeyWrapper);94 }95 })();96 } finally {97 await api.disconnect();98 console.error = consoleErr;99 console.log = consoleLog;100 console.warn = consoleWarn;101 }102 return result as T;103}104105enum TransactionStatus {106 Success,107 Fail,108 NotReady109}110111function getTransactionStatus(events: EventRecord[], status: ExtrinsicStatus): TransactionStatus {112 if (status.isReady) {113 return TransactionStatus.NotReady;114 }115 if (status.isBroadcast) {116 return TransactionStatus.NotReady;117 }118 if (status.isInBlock || status.isFinalized) {119 if(events.filter(e => e.event.data.method === 'ExtrinsicFailed').length > 0) {120 return TransactionStatus.Fail;121 }122 if(events.filter(e => e.event.data.method === 'ExtrinsicSuccess').length > 0) {123 return TransactionStatus.Success;124 }125 }126127 return TransactionStatus.Fail;128}129130export function executeTransaction(api: ApiPromise, sender: IKeyringPair, transaction: SubmittableExtrinsic<'promise'>): Promise<EventRecord[]> {131 return new Promise(async (res, rej) => {132 try {133 await transaction.signAndSend(sender, ({events, status}) => {134 if (!status.isInBlock && !status.isFinalized) return;135 for (const {event} of events) {136 if (api.events.system.ExtrinsicSuccess.is(event)) {137 res(events);138 } else if (api.events.system.ExtrinsicFailed.is(event)) {139 const {data: [error]} = event;140 if (error.isModule) {141 const decoded = api.registry.findMetaError(error.asModule);142 const {method, section} = decoded;143 rej(new Error(`${section}.${method}`));144 } else {145 rej(new Error(error.toString()));146 }147 }148 }149 });150 } catch (e) {151 rej(e);152 }153 });154}155156export function157submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {158 159 return new Promise(async (resolve, reject) => {160 try {161 await transaction.signAndSend(sender, ({events = [], status}) => {162 const transactionStatus = getTransactionStatus(events, status);163164 if (transactionStatus === TransactionStatus.Success) {165 resolve(events);166 } else if (transactionStatus === TransactionStatus.Fail) {167 console.log(`Something went wrong with transaction. Status: ${status}`);168 reject(events);169 }170 });171 } catch (e) {172 console.log('Error: ', e);173 reject(e);174 }175 });176}177178export function submitTransactionExpectFailAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {179 console.error = () => {};180 console.log = () => {};181182 183 return new Promise<EventRecord[]>(async function(res, rej) {184 const resolve = (rec: EventRecord[]) => {185 setTimeout(() => {186 res(rec);187 });188 };189 const reject = (errror: any) => {190 setTimeout(() => {191 rej(errror);192 });193 };194 try {195 await transaction.signAndSend(sender, ({events = [], status}) => {196 const transactionStatus = getTransactionStatus(events, status);197198 199200 if (transactionStatus === TransactionStatus.Success) {201 resolve(events);202 } else if (transactionStatus === TransactionStatus.Fail) {203 reject(events);204 }205 });206 } catch (e) {207 reject(e);208 }209 });210}