UNPKG

@parity/api

Version:

The Parity Promise-based API library for interfacing with Ethereum over RPC

574 lines (488 loc) 13.9 kB
// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Parity. // // SPDX-License-Identifier: MIT /* eslint-disable @typescript-eslint/no-use-before-define */ import BigNumber from 'bignumber.js'; import { isString } from '@parity/abi/lib/util/types'; import { toChecksumAddress } from '@parity/abi/lib/util/address'; import { AccountInfo, Block, ChainStatus, Condition, Histogram, HwAccountInfo, Log, NodeKind, Peer, PeerProtocolItem, PeerProtocol, Peers, Receipt, SignerRequest, SigningPayload, Syncing, Trace, TraceReplay, Transaction, VaultMeta } from '../types'; import { SerializedAccountInfo, SerializedBlock, SerializedChainStatus, SerializedCondition, SerializedHistogram, SerializedHwAccountInfo, SerializedLog, SerializedPeer, SerializedPeers, SerializedReceipt, SerializedSignerRequest, SerializedSigningPayload, SerializedSyncing, SerializedTrace, SerializedTraceReplay, SerializedTransaction, SerializedVaultMeta, SerializedNumber } from './types.serialized'; export function outAccountInfo (infos: SerializedAccountInfo) { return Object.keys(infos).reduce( (ret, _address) => { const info = infos[_address]; const address = outAddress(_address); ret[address] = { name: info.name }; if (info.meta) { ret[address].uuid = info.uuid; try { ret[address].meta = JSON.parse(info.meta); } catch (e) { console.error( `Couldn't parse meta field of JSON key file ${info.uuid}` ); } } return ret; }, {} as AccountInfo ); } export function outAddress (address?: string) { return toChecksumAddress(address); } export function outAddresses (addresses: string[]) { return (addresses || []).map(outAddress); } export function outBlock (block: SerializedBlock) { const result: Block = {}; if (block) { Object.keys(block).forEach(key => { switch (key) { case 'author': case 'miner': result[key] = outAddress(block[key]); break; case 'difficulty': case 'gasLimit': case 'gasUsed': case 'nonce': case 'number': case 'totalDifficulty': result[key] = outNumber(block[key]); break; case 'timestamp': result[key] = outDate(block[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = block[key]; } }); } return result; } export function outBlockReceipts (receipts: SerializedReceipt[]) { if (receipts) { return receipts.map(outReceipt); } return receipts; } export function outChainStatus (status?: SerializedChainStatus) { const result: ChainStatus = {}; if (status) { Object.keys(status).forEach(key => { switch (key) { case 'blockGap': result[key] = status[key] ? (status[key] as number[]).map(outNumber) : undefined; break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = status[key]; } }); } return result; } export function outDate (date?: number | string | Date) { if (date instanceof Date && typeof date.toISOString === 'function') { return date; } try { if (typeof date === 'string' && new Date(date).toISOString() === date) { return new Date(date); } } catch (error) { /* Do nothing */ } return new Date(outNumber(date as number).toNumber() * 1000); } export function outHistogram (histogram: SerializedHistogram) { const result: Histogram = {}; if (histogram) { Object.keys(histogram).forEach(key => { switch (key) { case 'bucketBounds': case 'counts': // @ts-ignore "Object is possibly 'undefined'." No it's not. result[key] = histogram[key].map(outNumber); break; } }); } return result; } export function outLog (log: SerializedLog) { const result: Log = {}; Object.keys(log).forEach(key => { switch (key) { case 'blockNumber': case 'logIndex': case 'transactionIndex': result[key] = outNumber(log[key]); break; case 'address': result[key] = outAddress(log[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = log[key]; } }); return result; } export function outHwAccountInfo (infos: SerializedHwAccountInfo) { return Object.keys(infos).reduce( (ret, _address) => { const address = outAddress(_address); ret[address] = infos[_address]; return ret; }, {} as HwAccountInfo ); } export function outNodeKind (info: NodeKind) { return info; } export function outNumber (n?: SerializedNumber) { return new BigNumber(n || 0); } export function outPeer (peer: SerializedPeer) { const protocols = Object.keys(peer.protocols).reduce( (obj, key) => { if (peer.protocols[key as PeerProtocol]) { // @ts-ignore obj[key as PeerProtocol] = Object.assign( {}, peer.protocols[key as PeerProtocol], { difficulty: outNumber( // @ts-ignore "Object is possibly 'undefined'." No it's not. peer.protocols[key as PeerProtocol].difficulty ) } ); } return obj; }, {} as { les?: PeerProtocolItem; par?: PeerProtocolItem } ); return { caps: peer.caps, id: peer.id, name: peer.name, network: peer.network, protocols } as Peer; } export function outPeers (peers: SerializedPeers) { return { active: outNumber(peers.active), connected: outNumber(peers.connected), max: outNumber(peers.max), peers: peers.peers.map(peer => outPeer(peer)) } as Peers; } export function outPrivateReceipt (receipt: SerializedReceipt) { const result: Receipt = {}; if (receipt) { Object.keys(receipt).forEach(key => { switch (key) { case 'status': result[key] = outNumber(receipt[key]); break; case 'contractAddress': result[key] = outAddress(receipt[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = receipt[key]; } }); } return result; } export function outReceipt (receipt: SerializedReceipt) { const result: Receipt = {}; if (receipt) { Object.keys(receipt).forEach(key => { switch (key) { case 'blockNumber': case 'cumulativeGasUsed': case 'gasUsed': case 'transactionIndex': result[key] = outNumber(receipt[key]); break; case 'contractAddress': result[key] = outAddress(receipt[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = receipt[key]; } }); } return result; } export function outSignerRequest (request: SerializedSignerRequest) { const result: SignerRequest = {}; if (request) { Object.keys(request).forEach(key => { switch (key) { case 'id': result[key] = outNumber(request[key]); break; case 'payload': result[key] = {}; // @ts-ignore "Object is possibly 'undefined'." No it's not. result[key].decrypt = outSigningPayload(request[key].decrypt); // @ts-ignore "Object is possibly 'undefined'." No it's not. result[key].sign = outSigningPayload(request[key].sign); // @ts-ignore "Object is possibly 'undefined'." No it's not. result[key].signTransaction = outTransaction( // @ts-ignore "Object is possibly 'undefined'." No it's not. request[key].signTransaction ); // @ts-ignore "Object is possibly 'undefined'." No it's not. result[key].sendTransaction = outTransaction( // @ts-ignore "Object is possibly 'undefined'." No it's not. request[key].sendTransaction ); break; case 'origin': /* eslint-disable no-case-declarations */ // @ts-ignore "Object is possibly 'undefined'." No it's not. const type = Object.keys(result[key])[0]; // @ts-ignore "Object is possibly 'undefined'." No it's not. const details = result[key][type]; /* eslint-enable no-case-declarations */ request[key] = { type, details }; break; } }); } return result; } export function outSyncing (syncing: SerializedSyncing | false) { let result: Syncing | false = false; if (syncing && syncing !== 'false') { result = {}; Object.keys(syncing).forEach(key => { switch (key) { case 'currentBlock': case 'highestBlock': case 'startingBlock': case 'warpChunksAmount': case 'warpChunksProcessed': (result as Syncing)[key] = outNumber(syncing[key]); break; case 'blockGap': (result as Syncing)[key] = syncing[key] ? (syncing[key] as number[]).map(outNumber) : undefined; break; } }); } return result; } export function outTransactionCondition ( condition?: SerializedCondition | null ) { let result: Condition | null = null; if (condition) { result = {}; if (condition.block) { result.block = outNumber(condition.block); } else if (condition.time) { result.time = outDate(condition.time); } } return result; } export function outTransaction (tx: SerializedTransaction) { const result: Transaction = {}; if (tx) { Object.keys(tx).forEach(key => { switch (key) { case 'blockNumber': case 'gasPrice': case 'gas': case 'nonce': case 'transactionIndex': case 'value': result[key] = outNumber(tx[key]); break; case 'condition': result[key] = outTransactionCondition(tx[key]); break; case 'creates': case 'from': case 'to': result[key] = outAddress(tx[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = tx[key]; } }); } return result; } export function outSigningPayload (payload: SerializedSigningPayload) { const result: SigningPayload = {}; if (payload) { Object.keys(payload).forEach(key => { switch (key) { case 'address': result[key] = outAddress(payload[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = payload[key]; } }); } return payload; } export function outTrace (trace: SerializedTrace) { const result: Trace = {}; if (trace) { Object.keys(trace).forEach(key => { switch (key) { case 'subtraces': case 'transactionPosition': case 'blockNumber': result[key] = outNumber(trace[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result[key] = trace[key]; } }); if (trace.action) { result.action = {}; Object.keys(trace.action).forEach(key => { switch (key) { case 'gas': case 'value': case 'balance': // @ts-ignore "Object is possibly 'undefined'." No it's not. result.action[key] = outNumber(trace.action[key]); break; case 'from': case 'to': case 'address': case 'refundAddress': // @ts-ignore "Object is possibly 'undefined'." No it's not. result.action[key] = outAddress(trace.action[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result.action[key] = trace.action[key]; } }); } if (trace.result) { result.result = {}; Object.keys(trace.result).forEach(key => { switch (key) { case 'gasUsed': // @ts-ignore "Object is possibly 'undefined'." No it's not. result.result[key] = outNumber(trace.result[key]); break; case 'address': // @ts-ignore "Object is possibly 'undefined'." No it's not. result.action[key] = outAddress(trace.action[key]); break; default: // @ts-ignore Here, we explicitly pass down extra keys, if they exist result.result[key] = trace.result[key]; } }); } if (trace.traceAddress) { result.traceAddress = []; trace.traceAddress.forEach((address, index) => { // @ts-ignore "Object is possibly 'undefined'." No it's not. result.traceAddress[index] = outNumber(address); }); } } return result; } export function outTraces (traces?: SerializedTrace[]) { if (traces) { return traces.map(outTrace); } return traces; } export function outTraceReplay (trace: SerializedTraceReplay) { const result: TraceReplay = {}; if (trace) { Object.keys(trace).forEach(key => { switch (key) { case 'trace': result[key] = outTraces(trace[key]); break; } }); } return result; } export function outVaultMeta (meta: SerializedVaultMeta) { if (isString(meta)) { try { const obj = JSON.parse(meta); return obj as VaultMeta; } catch (error) { return {}; } } return meta || {}; }