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 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 80 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 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 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 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}