aboutsummaryrefslogtreecommitdiffstats
path: root/packages/web3-wrapper/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/web3-wrapper/src')
-rw-r--r--packages/web3-wrapper/src/globals.d.ts6
-rw-r--r--packages/web3-wrapper/src/index.ts60
-rw-r--r--packages/web3-wrapper/src/marshaller.ts230
-rw-r--r--packages/web3-wrapper/src/types.ts92
-rw-r--r--packages/web3-wrapper/src/utils.ts54
-rw-r--r--packages/web3-wrapper/src/web3_wrapper.ts703
6 files changed, 0 insertions, 1145 deletions
diff --git a/packages/web3-wrapper/src/globals.d.ts b/packages/web3-wrapper/src/globals.d.ts
deleted file mode 100644
index 94e63a32d..000000000
--- a/packages/web3-wrapper/src/globals.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-declare module '*.json' {
- const json: any;
- /* tslint:disable */
- export default json;
- /* tslint:enable */
-}
diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts
deleted file mode 100644
index 4d20ba9be..000000000
--- a/packages/web3-wrapper/src/index.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-export { Web3Wrapper } from './web3_wrapper';
-export { marshaller } from './marshaller';
-
-export { AbiDecoder } from '@0x/utils';
-
-export {
- BlockParam,
- TxData,
- Provider,
- TransactionReceipt,
- Transaction,
- TraceParams,
- TransactionTrace,
- BlockWithoutTransactionData,
- LogEntry,
- FilterObject,
- CallData,
- TransactionReceiptWithDecodedLogs,
- BlockWithTransactionData,
- LogTopic,
- JSONRPCRequestPayload,
- TransactionReceiptStatus,
- DecodedLogArgs,
- StructLog,
- JSONRPCErrorCallback,
- BlockParamLiteral,
- ContractEventArg,
- DecodedLogEntry,
- LogEntryEvent,
- OpCode,
- TxDataPayable,
- JSONRPCResponsePayload,
- JSONRPCResponseError,
- RawLogEntry,
- DecodedLogEntryEvent,
- LogWithDecodedArgs,
- AbiDefinition,
- RawLog,
- FunctionAbi,
- EventAbi,
- EventParameter,
- MethodAbi,
- ConstructorAbi,
- FallbackAbi,
- DataItem,
- ConstructorStateMutability,
- StateMutability,
-} from 'ethereum-types';
-export {
- Web3WrapperErrors,
- NodeType,
- CallDataRPC,
- BlockWithoutTransactionDataRPC,
- BlockWithTransactionDataRPC,
- TransactionReceiptStatusRPC,
- TransactionReceiptRPC,
- LogEntryRPC,
- TransactionRPC,
- TxDataRPC,
-} from './types';
diff --git a/packages/web3-wrapper/src/marshaller.ts b/packages/web3-wrapper/src/marshaller.ts
deleted file mode 100644
index 4230f8eab..000000000
--- a/packages/web3-wrapper/src/marshaller.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-import { addressUtils } from '@0x/utils';
-import {
- BlockParam,
- BlockParamLiteral,
- BlockWithoutTransactionData,
- BlockWithTransactionData,
- CallData,
- CallTxDataBase,
- LogEntry,
- RawLogEntry,
- Transaction,
- TransactionReceipt,
- TxData,
-} from 'ethereum-types';
-import ethUtil = require('ethereumjs-util');
-import * as _ from 'lodash';
-
-import { utils } from './utils';
-
-import {
- BlockWithoutTransactionDataRPC,
- BlockWithTransactionDataRPC,
- CallDataRPC,
- CallTxDataBaseRPC,
- TransactionReceiptRPC,
- TransactionRPC,
- TxDataRPC,
-} from './types';
-
-/**
- * Utils to convert ethereum structures from user-space format to RPC format. (marshall/unmarshall)
- */
-export const marshaller = {
- /**
- * Unmarshall block without transaction data
- * @param blockWithHexValues block to unmarshall
- * @return unmarshalled block without transaction data
- */
- unmarshalIntoBlockWithoutTransactionData(
- blockWithHexValues: BlockWithoutTransactionDataRPC,
- ): BlockWithoutTransactionData {
- const block = {
- ...blockWithHexValues,
- gasLimit: utils.convertHexToNumber(blockWithHexValues.gasLimit),
- gasUsed: utils.convertHexToNumber(blockWithHexValues.gasUsed),
- size: utils.convertHexToNumber(blockWithHexValues.size),
- timestamp: utils.convertHexToNumber(blockWithHexValues.timestamp),
- number: _.isNull(blockWithHexValues.number) ? null : utils.convertHexToNumber(blockWithHexValues.number),
- difficulty: utils.convertAmountToBigNumber(blockWithHexValues.difficulty),
- totalDifficulty: utils.convertAmountToBigNumber(blockWithHexValues.totalDifficulty),
- };
- return block;
- },
- /**
- * Unmarshall block with transaction data
- * @param blockWithHexValues block to unmarshall
- * @return unmarshalled block with transaction data
- */
- unmarshalIntoBlockWithTransactionData(blockWithHexValues: BlockWithTransactionDataRPC): BlockWithTransactionData {
- const block = {
- ...blockWithHexValues,
- gasLimit: utils.convertHexToNumber(blockWithHexValues.gasLimit),
- gasUsed: utils.convertHexToNumber(blockWithHexValues.gasUsed),
- size: utils.convertHexToNumber(blockWithHexValues.size),
- timestamp: utils.convertHexToNumber(blockWithHexValues.timestamp),
- number: _.isNull(blockWithHexValues.number) ? null : utils.convertHexToNumber(blockWithHexValues.number),
- difficulty: utils.convertAmountToBigNumber(blockWithHexValues.difficulty),
- totalDifficulty: utils.convertAmountToBigNumber(blockWithHexValues.totalDifficulty),
- transactions: [] as Transaction[],
- };
- block.transactions = _.map(blockWithHexValues.transactions, (tx: TransactionRPC) => {
- const transaction = marshaller.unmarshalTransaction(tx);
- return transaction;
- });
- return block;
- },
- /**
- * Unmarshall transaction
- * @param txRpc transaction to unmarshall
- * @return unmarshalled transaction
- */
- unmarshalTransaction(txRpc: TransactionRPC): Transaction {
- const tx = {
- ...txRpc,
- blockNumber: !_.isNull(txRpc.blockNumber) ? utils.convertHexToNumber(txRpc.blockNumber) : null,
- transactionIndex: !_.isNull(txRpc.transactionIndex)
- ? utils.convertHexToNumber(txRpc.transactionIndex)
- : null,
- nonce: utils.convertHexToNumber(txRpc.nonce),
- gas: utils.convertHexToNumber(txRpc.gas),
- gasPrice: utils.convertAmountToBigNumber(txRpc.gasPrice),
- value: utils.convertAmountToBigNumber(txRpc.value),
- };
- return tx;
- },
- /**
- * Unmarshall transaction receipt
- * @param txReceiptRpc transaction receipt to unmarshall
- * @return unmarshalled transaction receipt
- */
- unmarshalTransactionReceipt(txReceiptRpc: TransactionReceiptRPC): TransactionReceipt {
- const txReceipt = {
- ...txReceiptRpc,
- blockNumber: utils.convertHexToNumber(txReceiptRpc.blockNumber),
- transactionIndex: utils.convertHexToNumber(txReceiptRpc.transactionIndex),
- cumulativeGasUsed: utils.convertHexToNumber(txReceiptRpc.cumulativeGasUsed),
- gasUsed: utils.convertHexToNumber(txReceiptRpc.gasUsed),
- logs: _.map(txReceiptRpc.logs, marshaller.unmarshalLog.bind(marshaller)),
- };
- return txReceipt;
- },
- /**
- * Unmarshall transaction data
- * @param txDataRpc transaction data to unmarshall
- * @return unmarshalled transaction data
- */
- unmarshalTxData(txDataRpc: TxDataRPC): TxData {
- if (_.isUndefined(txDataRpc.from)) {
- throw new Error(`txData must include valid 'from' value.`);
- }
- const txData = {
- ...txDataRpc,
- value: !_.isUndefined(txDataRpc.value) ? utils.convertAmountToBigNumber(txDataRpc.value) : undefined,
- gas: !_.isUndefined(txDataRpc.gas) ? utils.convertHexToNumber(txDataRpc.gas) : undefined,
- gasPrice: !_.isUndefined(txDataRpc.gasPrice)
- ? utils.convertAmountToBigNumber(txDataRpc.gasPrice)
- : undefined,
- nonce: !_.isUndefined(txDataRpc.nonce) ? utils.convertHexToNumber(txDataRpc.nonce) : undefined,
- };
- return txData;
- },
- /**
- * Marshall transaction data
- * @param txData transaction data to marshall
- * @return marshalled transaction data
- */
- marshalTxData(txData: Partial<TxData>): Partial<TxDataRPC> {
- if (_.isUndefined(txData.from)) {
- throw new Error(`txData must include valid 'from' value.`);
- }
- const callTxDataBase = {
- ...txData,
- };
- delete callTxDataBase.from;
- const callTxDataBaseRPC = marshaller._marshalCallTxDataBase(callTxDataBase);
- const txDataRPC = {
- ...callTxDataBaseRPC,
- from: marshaller.marshalAddress(txData.from),
- };
- const prunableIfUndefined = ['gasPrice', 'gas', 'value', 'nonce'];
- _.each(txDataRPC, (value: any, key: string) => {
- if (_.isUndefined(value) && _.includes(prunableIfUndefined, key)) {
- delete (txDataRPC as any)[key];
- }
- });
- return txDataRPC;
- },
- /**
- * Marshall call data
- * @param callData call data to marshall
- * @return marshalled call data
- */
- marshalCallData(callData: Partial<CallData>): Partial<CallDataRPC> {
- const callTxDataBase = {
- ...callData,
- };
- delete callTxDataBase.from;
- const callTxDataBaseRPC = marshaller._marshalCallTxDataBase(callTxDataBase);
- const callDataRPC = {
- ...callTxDataBaseRPC,
- from: _.isUndefined(callData.from) ? undefined : marshaller.marshalAddress(callData.from),
- };
- return callDataRPC;
- },
- /**
- * Marshall address
- * @param address address to marshall
- * @return marshalled address
- */
- marshalAddress(address: string): string {
- if (addressUtils.isAddress(address)) {
- return ethUtil.addHexPrefix(address);
- }
- throw new Error(`Invalid address encountered: ${address}`);
- },
- /**
- * Marshall block param
- * @param blockParam block param to marshall
- * @return marshalled block param
- */
- marshalBlockParam(blockParam: BlockParam | string | number | undefined): string | undefined {
- if (_.isUndefined(blockParam)) {
- return BlockParamLiteral.Latest;
- }
- const encodedBlockParam = _.isNumber(blockParam) ? utils.numberToHex(blockParam) : blockParam;
- return encodedBlockParam;
- },
- /**
- * Unmarshall log
- * @param rawLog log to unmarshall
- * @return unmarshalled log
- */
- unmarshalLog(rawLog: RawLogEntry): LogEntry {
- const formattedLog = {
- ...rawLog,
- logIndex: utils.convertHexToNumberOrNull(rawLog.logIndex),
- blockNumber: utils.convertHexToNumberOrNull(rawLog.blockNumber),
- transactionIndex: utils.convertHexToNumberOrNull(rawLog.transactionIndex),
- };
- return formattedLog;
- },
- _marshalCallTxDataBase(callTxDataBase: Partial<CallTxDataBase>): Partial<CallTxDataBaseRPC> {
- const callTxDataBaseRPC = {
- ...callTxDataBase,
- to: _.isUndefined(callTxDataBase.to) ? undefined : marshaller.marshalAddress(callTxDataBase.to),
- gasPrice: _.isUndefined(callTxDataBase.gasPrice)
- ? undefined
- : utils.encodeAmountAsHexString(callTxDataBase.gasPrice),
- gas: _.isUndefined(callTxDataBase.gas) ? undefined : utils.encodeAmountAsHexString(callTxDataBase.gas),
- value: _.isUndefined(callTxDataBase.value)
- ? undefined
- : utils.encodeAmountAsHexString(callTxDataBase.value),
- nonce: _.isUndefined(callTxDataBase.nonce)
- ? undefined
- : utils.encodeAmountAsHexString(callTxDataBase.nonce),
- };
-
- return callTxDataBaseRPC;
- },
-};
diff --git a/packages/web3-wrapper/src/types.ts b/packages/web3-wrapper/src/types.ts
deleted file mode 100644
index eb5a35f07..000000000
--- a/packages/web3-wrapper/src/types.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-export enum Web3WrapperErrors {
- TransactionMiningTimeout = 'TRANSACTION_MINING_TIMEOUT',
-}
-
-export interface AbstractBlockRPC {
- number: string | null;
- hash: string | null;
- parentHash: string;
- nonce: string | null;
- sha3Uncles: string;
- logsBloom: string | null;
- transactionsRoot: string;
- stateRoot: string;
- miner: string;
- difficulty: string;
- totalDifficulty: string;
- extraData: string;
- size: string;
- gasLimit: string;
- gasUsed: string;
- timestamp: string;
- uncles: string[];
-}
-export interface BlockWithoutTransactionDataRPC extends AbstractBlockRPC {
- transactions: string[];
-}
-export interface BlockWithTransactionDataRPC extends AbstractBlockRPC {
- transactions: TransactionRPC[];
-}
-export interface TransactionRPC {
- hash: string;
- nonce: string;
- blockHash: string | null;
- blockNumber: string | null;
- transactionIndex: string | null;
- from: string;
- to: string | null;
- value: string;
- gasPrice: string;
- gas: string;
- input: string;
-}
-
-export interface TransactionReceiptRPC {
- blockHash: string;
- blockNumber: string;
- transactionHash: string;
- transactionIndex: string;
- from: string;
- to: string;
- status: TransactionReceiptStatusRPC;
- cumulativeGasUsed: string;
- gasUsed: string;
- contractAddress: string | null;
- logs: LogEntryRPC[];
-}
-
-export interface LogEntryRPC {
- logIndex: string | null;
- transactionIndex: string | null;
- transactionHash: string;
- blockHash: string | null;
- blockNumber: string | null;
- address: string;
- data: string;
- topics: string[];
-}
-
-export type TransactionReceiptStatusRPC = null | string | 0 | 1;
-
-export interface CallTxDataBaseRPC {
- to?: string;
- value?: string;
- gas?: string;
- gasPrice?: string;
- data?: string;
- nonce?: string;
-}
-
-export interface TxDataRPC extends CallTxDataBaseRPC {
- from: string;
-}
-
-export interface CallDataRPC extends CallTxDataBaseRPC {
- from?: string;
-}
-
-// NodeType represents the type of the backing Ethereum node.
-export enum NodeType {
- Geth = 'GETH',
- Ganache = 'GANACHE',
-}
diff --git a/packages/web3-wrapper/src/utils.ts b/packages/web3-wrapper/src/utils.ts
deleted file mode 100644
index 1aba3c75a..000000000
--- a/packages/web3-wrapper/src/utils.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-
-export const utils = {
- convertHexToNumber(value: string): number {
- const valueBigNumber = new BigNumber(value);
- const valueNumber = valueBigNumber.toNumber();
- return valueNumber;
- },
- convertHexToNumberOrNull(hex: string | null): number | null {
- if (_.isNull(hex)) {
- return null;
- }
- const decimal = utils.convertHexToNumber(hex);
- return decimal;
- },
- convertAmountToBigNumber(value: string | number | BigNumber): BigNumber {
- const num = value || 0;
- const isBigNumber = BigNumber.isBigNumber(num);
- if (isBigNumber) {
- return num as BigNumber;
- }
-
- if (_.isString(num) && (num.indexOf('0x') === 0 || num.indexOf('-0x') === 0)) {
- return new BigNumber(num.replace('0x', ''), 16);
- }
-
- const baseTen = 10;
- return new BigNumber((num as number).toString(baseTen), baseTen);
- },
- encodeAmountAsHexString(value: string | number | BigNumber): string {
- const valueBigNumber = utils.convertAmountToBigNumber(value);
- const hexBase = 16;
- const valueHex = valueBigNumber.toString(hexBase);
-
- return valueBigNumber.isLessThan(0) ? `-0x${valueHex.substr(1)}` : `0x${valueHex}`;
- },
- numberToHex(value: number): string {
- if (!isFinite(value) && !utils.isHexStrict(value)) {
- throw new Error(`Given input ${value} is not a number.`);
- }
-
- const valueBigNumber = new BigNumber(value);
- const hexBase = 16;
- const result = valueBigNumber.toString(hexBase);
-
- return valueBigNumber.lt(0) ? `-0x${result.substr(1)}` : `0x${result}`;
- },
- isHexStrict(hex: string | number): boolean {
- return (
- (_.isString(hex) || _.isNumber(hex)) && /^(-)?0x[0-9a-f]*$/i.test(_.isNumber(hex) ? hex.toString() : hex)
- );
- },
-};
diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts
deleted file mode 100644
index 76cae4b01..000000000
--- a/packages/web3-wrapper/src/web3_wrapper.ts
+++ /dev/null
@@ -1,703 +0,0 @@
-import { assert } from '@0x/assert';
-import { schemas } from '@0x/json-schemas';
-import { AbiDecoder, addressUtils, BigNumber, intervalUtils, promisify } from '@0x/utils';
-import {
- BlockParam,
- BlockParamLiteral,
- BlockWithoutTransactionData,
- BlockWithTransactionData,
- CallData,
- FilterObject,
- JSONRPCRequestPayload,
- JSONRPCResponsePayload,
- LogEntry,
- Provider,
- RawLogEntry,
- TraceParams,
- Transaction,
- TransactionReceipt,
- TransactionReceiptWithDecodedLogs,
- TransactionTrace,
- TxData,
-} from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { marshaller } from './marshaller';
-import {
- BlockWithoutTransactionDataRPC,
- BlockWithTransactionDataRPC,
- NodeType,
- TransactionReceiptRPC,
- TransactionRPC,
- Web3WrapperErrors,
-} from './types';
-import { utils } from './utils';
-
-const BASE_TEN = 10;
-
-// These are unique identifiers contained in the response of the
-// web3_clientVersion call.
-const uniqueVersionIds = {
- geth: 'Geth',
- ganache: 'EthereumJS TestRPC',
-};
-
-/**
- * An alternative to the Web3.js library that provides a consistent, clean, promise-based interface.
- */
-export class Web3Wrapper {
- /**
- * Flag to check if this instance is of type Web3Wrapper
- */
- public isZeroExWeb3Wrapper = true;
- public abiDecoder: AbiDecoder;
- private _provider: Provider;
- private readonly _txDefaults: Partial<TxData>;
- private _jsonRpcRequestId: number;
- /**
- * Check if an address is a valid Ethereum address
- * @param address Address to check
- * @returns Whether the address is a valid Ethereum address
- */
- public static isAddress(address: string): boolean {
- return addressUtils.isAddress(address);
- }
- /**
- * A unit amount is defined as the amount of a token above the specified decimal places (integer part).
- * E.g: If a currency has 18 decimal places, 1e18 or one quintillion of the currency is equivalent
- * to 1 unit.
- * @param amount The amount in baseUnits that you would like converted to units.
- * @param decimals The number of decimal places the unit amount has.
- * @return The amount in units.
- */
- public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
- assert.isValidBaseUnitAmount('amount', amount);
- assert.isNumber('decimals', decimals);
- const aUnit = new BigNumber(BASE_TEN).pow(decimals);
- const unit = amount.div(aUnit);
- return unit;
- }
- /**
- * A baseUnit is defined as the smallest denomination of a token. An amount expressed in baseUnits
- * is the amount expressed in the smallest denomination.
- * E.g: 1 unit of a token with 18 decimal places is expressed in baseUnits as 1000000000000000000
- * @param amount The amount of units that you would like converted to baseUnits.
- * @param decimals The number of decimal places the unit amount has.
- * @return The amount in baseUnits.
- */
- public static toBaseUnitAmount(amount: BigNumber, decimals: number): BigNumber {
- assert.isBigNumber('amount', amount);
- assert.isNumber('decimals', decimals);
- const unit = new BigNumber(BASE_TEN).pow(decimals);
- const baseUnitAmount = amount.times(unit);
- const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
- if (hasDecimals) {
- throw new Error(`Invalid unit amount: ${amount.toString()} - Too many decimal places`);
- }
- return baseUnitAmount;
- }
- /**
- * Convert an Ether amount from ETH to Wei
- * @param ethAmount Amount of Ether to convert to wei
- * @returns Amount in wei
- */
- public static toWei(ethAmount: BigNumber): BigNumber {
- assert.isBigNumber('ethAmount', ethAmount);
- const ETH_DECIMALS = 18;
- const balanceWei = Web3Wrapper.toBaseUnitAmount(ethAmount, ETH_DECIMALS);
- return balanceWei;
- }
- private static _assertBlockParam(blockParam: string | BlockParam): void {
- if (_.isNumber(blockParam)) {
- return;
- } else if (_.isString(blockParam)) {
- assert.doesBelongToStringEnum('blockParam', blockParam, BlockParamLiteral);
- }
- }
- private static _assertBlockParamOrString(blockParam: string | BlockParam): void {
- try {
- Web3Wrapper._assertBlockParam(blockParam);
- } catch (err) {
- try {
- assert.isHexString('blockParam', blockParam as string);
- return;
- } catch (err) {
- throw new Error(`Expected blockParam to be of type "string | BlockParam", encountered ${blockParam}`);
- }
- }
- }
- private static _normalizeTxReceiptStatus(status: undefined | null | string | 0 | 1): null | 0 | 1 {
- // Transaction status might have four values
- // undefined - Testrpc and other old clients
- // null - New clients on old transactions
- // number - Parity
- // hex - Geth
- if (_.isString(status)) {
- return utils.convertHexToNumber(status) as 0 | 1;
- } else if (_.isUndefined(status)) {
- return null;
- } else {
- return status;
- }
- }
- /**
- * Instantiates a new Web3Wrapper.
- * @param provider The Web3 provider instance you would like the Web3Wrapper to use for interacting with
- * the backing Ethereum node.
- * @param txDefaults Override TxData defaults sent with RPC requests to the backing Ethereum node.
- * @return An instance of the Web3Wrapper class.
- */
- constructor(provider: Provider, txDefaults?: Partial<TxData>) {
- assert.isWeb3Provider('provider', provider);
- if (_.isUndefined((provider as any).sendAsync)) {
- // Web3@1.0 provider doesn't support synchronous http requests,
- // so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x`
- // We re-assign the send method so that Web3@1.0 providers work with @0x/web3-wrapper
- (provider as any).sendAsync = (provider as any).send;
- }
- this.abiDecoder = new AbiDecoder([]);
- this._provider = provider;
- this._txDefaults = txDefaults || {};
- this._jsonRpcRequestId = 1;
- }
- /**
- * Get the contract defaults set to the Web3Wrapper instance
- * @return TxData defaults (e.g gas, gasPrice, nonce, etc...)
- */
- public getContractDefaults(): Partial<TxData> {
- return this._txDefaults;
- }
- /**
- * Retrieve the Web3 provider
- * @return Web3 provider instance
- */
- public getProvider(): Provider {
- return this._provider;
- }
- /**
- * Update the used Web3 provider
- * @param provider The new Web3 provider to be set
- */
- public setProvider(provider: Provider): void {
- assert.isWeb3Provider('provider', provider);
- this._provider = provider;
- }
- /**
- * Check whether an address is available through the backing provider. This can be
- * useful if you want to know whether a user can sign messages or transactions from
- * a given Ethereum address.
- * @param senderAddress Address to check availability for
- * @returns Whether the address is available through the provider.
- */
- public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
- assert.isETHAddressHex('senderAddress', senderAddress);
- const addresses = await this.getAvailableAddressesAsync();
- const normalizedAddress = senderAddress.toLowerCase();
- return _.includes(addresses, normalizedAddress);
- }
- /**
- * Fetch the backing Ethereum node's version string (e.g `MetaMask/v4.2.0`)
- * @returns Ethereum node's version string
- */
- public async getNodeVersionAsync(): Promise<string> {
- const nodeVersion = await this.sendRawPayloadAsync<string>({ method: 'web3_clientVersion' });
- return nodeVersion;
- }
- /**
- * Fetches the networkId of the backing Ethereum node
- * @returns The network id
- */
- public async getNetworkIdAsync(): Promise<number> {
- const networkIdStr = await this.sendRawPayloadAsync<string>({ method: 'net_version' });
- const networkId = _.parseInt(networkIdStr);
- return networkId;
- }
- /**
- * Retrieves the transaction receipt for a given transaction hash if found
- * @param txHash Transaction hash
- * @returns The transaction receipt, including it's status (0: failed, 1: succeeded). Returns undefined if transaction not found.
- */
- public async getTransactionReceiptIfExistsAsync(txHash: string): Promise<TransactionReceipt | undefined> {
- assert.isHexString('txHash', txHash);
- const transactionReceiptRpc = await this.sendRawPayloadAsync<TransactionReceiptRPC>({
- method: 'eth_getTransactionReceipt',
- params: [txHash],
- });
- // HACK Parity can return a pending transaction receipt. We check for a non null
- // block number before continuing with returning a fully realised receipt.
- // ref: https://github.com/paritytech/parity-ethereum/issues/1180
- if (!_.isNull(transactionReceiptRpc) && !_.isNull(transactionReceiptRpc.blockNumber)) {
- transactionReceiptRpc.status = Web3Wrapper._normalizeTxReceiptStatus(transactionReceiptRpc.status);
- const transactionReceipt = marshaller.unmarshalTransactionReceipt(transactionReceiptRpc);
- return transactionReceipt;
- } else {
- return undefined;
- }
- }
- /**
- * Retrieves the transaction data for a given transaction
- * @param txHash Transaction hash
- * @returns The raw transaction data
- */
- public async getTransactionByHashAsync(txHash: string): Promise<Transaction> {
- assert.isHexString('txHash', txHash);
- const transactionRpc = await this.sendRawPayloadAsync<TransactionRPC>({
- method: 'eth_getTransactionByHash',
- params: [txHash],
- });
- const transaction = marshaller.unmarshalTransaction(transactionRpc);
- return transaction;
- }
- /**
- * Retrieves an accounts Ether balance in wei
- * @param owner Account whose balance you wish to check
- * @param defaultBlock The block depth at which to fetch the balance (default=latest)
- * @returns Balance in wei
- */
- public async getBalanceInWeiAsync(owner: string, defaultBlock?: BlockParam): Promise<BigNumber> {
- assert.isETHAddressHex('owner', owner);
- if (!_.isUndefined(defaultBlock)) {
- Web3Wrapper._assertBlockParam(defaultBlock);
- }
- const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
- const encodedOwner = marshaller.marshalAddress(owner);
- const balanceInWei = await this.sendRawPayloadAsync<string>({
- method: 'eth_getBalance',
- params: [encodedOwner, marshalledDefaultBlock],
- });
- // Rewrap in a new BigNumber
- return new BigNumber(balanceInWei);
- }
- /**
- * Check if a contract exists at a given address
- * @param address Address to which to check
- * @returns Whether or not contract code was found at the supplied address
- */
- public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
- assert.isETHAddressHex('address', address);
- const code = await this.getContractCodeAsync(address);
- // Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients
- const isCodeEmpty = /^0x0{0,40}$/i.test(code);
- return !isCodeEmpty;
- }
- /**
- * Gets the contract code by address
- * @param address Address of the contract
- * @param defaultBlock Block height at which to make the call. Defaults to `latest`
- * @return Code of the contract
- */
- public async getContractCodeAsync(address: string, defaultBlock?: BlockParam): Promise<string> {
- assert.isETHAddressHex('address', address);
- if (!_.isUndefined(defaultBlock)) {
- Web3Wrapper._assertBlockParam(defaultBlock);
- }
- const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
- const encodedAddress = marshaller.marshalAddress(address);
- const code = await this.sendRawPayloadAsync<string>({
- method: 'eth_getCode',
- params: [encodedAddress, marshalledDefaultBlock],
- });
- return code;
- }
- /**
- * Gets the debug trace of a transaction
- * @param txHash Hash of the transactuon to get a trace for
- * @param traceParams Config object allowing you to specify if you need memory/storage/stack traces.
- * @return Transaction trace
- */
- public async getTransactionTraceAsync(txHash: string, traceParams: TraceParams): Promise<TransactionTrace> {
- assert.isHexString('txHash', txHash);
- const trace = await this.sendRawPayloadAsync<TransactionTrace>({
- method: 'debug_traceTransaction',
- params: [txHash, traceParams],
- });
- return trace;
- }
- /**
- * Sign a message with a specific address's private key (`eth_sign`)
- * @param address Address of signer
- * @param message Message to sign
- * @returns Signature string (might be VRS or RSV depending on the Signer)
- */
- public async signMessageAsync(address: string, message: string): Promise<string> {
- assert.isETHAddressHex('address', address);
- assert.isString('message', message); // TODO: Should this be stricter? Hex string?
- const signData = await this.sendRawPayloadAsync<string>({
- method: 'eth_sign',
- params: [address, message],
- });
- return signData;
- }
- /**
- * Sign an EIP712 typed data message with a specific address's private key (`eth_signTypedData`)
- * @param address Address of signer
- * @param typedData Typed data message to sign
- * @returns Signature string (as RSV)
- */
- public async signTypedDataAsync(address: string, typedData: any): Promise<string> {
- assert.isETHAddressHex('address', address);
- assert.doesConformToSchema('typedData', typedData, schemas.eip712TypedDataSchema);
- const signData = await this.sendRawPayloadAsync<string>({
- method: 'eth_signTypedData',
- params: [address, typedData],
- });
- return signData;
- }
- /**
- * Fetches the latest block number
- * @returns Block number
- */
- public async getBlockNumberAsync(): Promise<number> {
- const blockNumberHex = await this.sendRawPayloadAsync<string>({
- method: 'eth_blockNumber',
- params: [],
- });
- const blockNumber = utils.convertHexToNumberOrNull(blockNumberHex);
- return blockNumber as number;
- }
- /**
- * Fetch a specific Ethereum block without transaction data
- * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral)
- * @returns The requested block without transaction data, or undefined if block was not found
- * (e.g the node isn't fully synced, there was a block re-org and the requested block was uncles, etc...)
- */
- public async getBlockIfExistsAsync(
- blockParam: string | BlockParam,
- ): Promise<BlockWithoutTransactionData | undefined> {
- Web3Wrapper._assertBlockParamOrString(blockParam);
- const encodedBlockParam = marshaller.marshalBlockParam(blockParam);
- const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber';
- const shouldIncludeTransactionData = false;
- const blockWithoutTransactionDataWithHexValuesOrNull = await this.sendRawPayloadAsync<
- BlockWithoutTransactionDataRPC
- >({
- method,
- params: [encodedBlockParam, shouldIncludeTransactionData],
- });
- let blockWithoutTransactionDataIfExists;
- if (!_.isNull(blockWithoutTransactionDataWithHexValuesOrNull)) {
- blockWithoutTransactionDataIfExists = marshaller.unmarshalIntoBlockWithoutTransactionData(
- blockWithoutTransactionDataWithHexValuesOrNull,
- );
- }
- return blockWithoutTransactionDataIfExists;
- }
- /**
- * Fetch a specific Ethereum block with transaction data
- * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral)
- * @returns The requested block with transaction data
- */
- public async getBlockWithTransactionDataAsync(blockParam: string | BlockParam): Promise<BlockWithTransactionData> {
- Web3Wrapper._assertBlockParamOrString(blockParam);
- let encodedBlockParam = blockParam;
- if (_.isNumber(blockParam)) {
- encodedBlockParam = utils.numberToHex(blockParam);
- }
- const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber';
- const shouldIncludeTransactionData = true;
- const blockWithTransactionDataWithHexValues = await this.sendRawPayloadAsync<BlockWithTransactionDataRPC>({
- method,
- params: [encodedBlockParam, shouldIncludeTransactionData],
- });
- const blockWithoutTransactionData = marshaller.unmarshalIntoBlockWithTransactionData(
- blockWithTransactionDataWithHexValues,
- );
- return blockWithoutTransactionData;
- }
- /**
- * Fetch a block's timestamp
- * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral)
- * @returns The block's timestamp
- */
- public async getBlockTimestampAsync(blockParam: string | BlockParam): Promise<number> {
- Web3Wrapper._assertBlockParamOrString(blockParam);
- const blockIfExists = await this.getBlockIfExistsAsync(blockParam);
- if (_.isUndefined(blockIfExists)) {
- throw new Error(`Failed to fetch block with blockParam: ${JSON.stringify(blockParam)}`);
- }
- return blockIfExists.timestamp;
- }
- /**
- * Retrieve the user addresses available through the backing provider
- * @returns Available user addresses
- */
- public async getAvailableAddressesAsync(): Promise<string[]> {
- const addresses = await this.sendRawPayloadAsync<string>({
- method: 'eth_accounts',
- params: [],
- });
- const normalizedAddresses = _.map(addresses, address => address.toLowerCase());
- return normalizedAddresses;
- }
- /**
- * Take a snapshot of the blockchain state on a TestRPC/Ganache local node
- * @returns The snapshot id. This can be used to revert to this snapshot
- */
- public async takeSnapshotAsync(): Promise<number> {
- const snapshotId = Number(await this.sendRawPayloadAsync<string>({ method: 'evm_snapshot', params: [] }));
- return snapshotId;
- }
- /**
- * Revert the blockchain state to a previous snapshot state on TestRPC/Ganache local node
- * @param snapshotId snapshot id to revert to
- * @returns Whether the revert was successful
- */
- public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
- assert.isNumber('snapshotId', snapshotId);
- const didRevert = await this.sendRawPayloadAsync<boolean>({ method: 'evm_revert', params: [snapshotId] });
- return didRevert;
- }
- /**
- * Mine a block on a TestRPC/Ganache local node
- */
- public async mineBlockAsync(): Promise<void> {
- await this.sendRawPayloadAsync<string>({ method: 'evm_mine', params: [] });
- }
- /**
- * Increase the next blocks timestamp on TestRPC/Ganache or Geth local node.
- * Will throw if provider is neither TestRPC/Ganache or Geth.
- * @param timeDelta Amount of time to add in seconds
- */
- public async increaseTimeAsync(timeDelta: number): Promise<number> {
- assert.isNumber('timeDelta', timeDelta);
- // Detect Geth vs. Ganache and use appropriate endpoint.
- const version = await this.getNodeVersionAsync();
- if (_.includes(version, uniqueVersionIds.geth)) {
- return this.sendRawPayloadAsync<number>({ method: 'debug_increaseTime', params: [timeDelta] });
- } else if (_.includes(version, uniqueVersionIds.ganache)) {
- return this.sendRawPayloadAsync<number>({ method: 'evm_increaseTime', params: [timeDelta] });
- } else {
- throw new Error(`Unknown client version: ${version}`);
- }
- }
- /**
- * Retrieve smart contract logs for a given filter
- * @param filter Parameters by which to filter which logs to retrieve
- * @returns The corresponding log entries
- */
- public async getLogsAsync(filter: FilterObject): Promise<LogEntry[]> {
- if (!_.isUndefined(filter.blockHash) && (!_.isUndefined(filter.fromBlock) || !_.isUndefined(filter.toBlock))) {
- throw new Error(
- `Cannot specify 'blockHash' as well as 'fromBlock'/'toBlock' in the filter supplied to 'getLogsAsync'`,
- );
- }
-
- let fromBlock = filter.fromBlock;
- if (_.isNumber(fromBlock)) {
- fromBlock = utils.numberToHex(fromBlock);
- }
- let toBlock = filter.toBlock;
- if (_.isNumber(toBlock)) {
- toBlock = utils.numberToHex(toBlock);
- }
- const serializedFilter = {
- ...filter,
- fromBlock,
- toBlock,
- };
- const payload = {
- method: 'eth_getLogs',
- params: [serializedFilter],
- };
- const rawLogs = await this.sendRawPayloadAsync<RawLogEntry[]>(payload);
- const formattedLogs = _.map(rawLogs, marshaller.unmarshalLog.bind(marshaller));
- return formattedLogs;
- }
- /**
- * Calculate the estimated gas cost for a given transaction
- * @param txData Transaction data
- * @returns Estimated gas cost
- */
- public async estimateGasAsync(txData: Partial<TxData>): Promise<number> {
- assert.doesConformToSchema('txData', txData, schemas.txDataSchema, [
- schemas.addressSchema,
- schemas.numberSchema,
- schemas.jsNumber,
- ]);
- const txDataHex = marshaller.marshalTxData(txData);
- const gasHex = await this.sendRawPayloadAsync<string>({ method: 'eth_estimateGas', params: [txDataHex] });
- const gas = utils.convertHexToNumber(gasHex);
- return gas;
- }
- /**
- * Call a smart contract method at a given block height
- * @param callData Call data
- * @param defaultBlock Block height at which to make the call. Defaults to `latest`
- * @returns The raw call result
- */
- public async callAsync(callData: CallData, defaultBlock?: BlockParam): Promise<string> {
- assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
- schemas.addressSchema,
- schemas.numberSchema,
- schemas.jsNumber,
- ]);
- if (!_.isUndefined(defaultBlock)) {
- Web3Wrapper._assertBlockParam(defaultBlock);
- }
- const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
- const callDataHex = marshaller.marshalCallData(callData);
- const rawCallResult = await this.sendRawPayloadAsync<string>({
- method: 'eth_call',
- params: [callDataHex, marshalledDefaultBlock],
- });
- return rawCallResult;
- }
- /**
- * Send a transaction
- * @param txData Transaction data
- * @returns Transaction hash
- */
- public async sendTransactionAsync(txData: TxData): Promise<string> {
- assert.doesConformToSchema('txData', txData, schemas.txDataSchema, [
- schemas.addressSchema,
- schemas.numberSchema,
- schemas.jsNumber,
- ]);
- const txDataHex = marshaller.marshalTxData(txData);
- const txHash = await this.sendRawPayloadAsync<string>({ method: 'eth_sendTransaction', params: [txDataHex] });
- return txHash;
- }
- /**
- * Waits for a transaction to be mined and returns the transaction receipt.
- * Note that just because a transaction was mined does not mean it was
- * successful. You need to check the status code of the transaction receipt
- * to find out if it was successful, or use the helper method
- * awaitTransactionSuccessAsync.
- * @param txHash Transaction hash
- * @param pollingIntervalMs How often (in ms) should we check if the transaction is mined.
- * @param timeoutMs How long (in ms) to poll for transaction mined until aborting.
- * @return Transaction receipt with decoded log args.
- */
- public async awaitTransactionMinedAsync(
- txHash: string,
- pollingIntervalMs: number = 1000,
- timeoutMs?: number,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- assert.isHexString('txHash', txHash);
- assert.isNumber('pollingIntervalMs', pollingIntervalMs);
- if (!_.isUndefined(timeoutMs)) {
- assert.isNumber('timeoutMs', timeoutMs);
- }
- // Immediately check if the transaction has already been mined.
- let transactionReceipt = await this.getTransactionReceiptIfExistsAsync(txHash);
- if (!_.isUndefined(transactionReceipt)) {
- const logsWithDecodedArgs = _.map(
- transactionReceipt.logs,
- this.abiDecoder.tryToDecodeLogOrNoop.bind(this.abiDecoder),
- );
- const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
- ...transactionReceipt,
- logs: logsWithDecodedArgs,
- };
- return transactionReceiptWithDecodedLogArgs;
- }
-
- // Otherwise, check again every pollingIntervalMs.
- let wasTimeoutExceeded = false;
- if (timeoutMs) {
- setTimeout(() => (wasTimeoutExceeded = true), timeoutMs);
- }
-
- const txReceiptPromise = new Promise(
- (resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
- const intervalId = intervalUtils.setAsyncExcludingInterval(
- async () => {
- if (wasTimeoutExceeded) {
- intervalUtils.clearAsyncExcludingInterval(intervalId);
- return reject(Web3WrapperErrors.TransactionMiningTimeout);
- }
-
- transactionReceipt = await this.getTransactionReceiptIfExistsAsync(txHash);
- if (!_.isUndefined(transactionReceipt)) {
- intervalUtils.clearAsyncExcludingInterval(intervalId);
- const logsWithDecodedArgs = _.map(
- transactionReceipt.logs,
- this.abiDecoder.tryToDecodeLogOrNoop.bind(this.abiDecoder),
- );
- const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
- ...transactionReceipt,
- logs: logsWithDecodedArgs,
- };
- resolve(transactionReceiptWithDecodedLogArgs);
- }
- },
- pollingIntervalMs,
- (err: Error) => {
- intervalUtils.clearAsyncExcludingInterval(intervalId);
- reject(err);
- },
- );
- },
- );
- const txReceipt = await txReceiptPromise;
- return txReceipt;
- }
- /**
- * Waits for a transaction to be mined and returns the transaction receipt.
- * Unlike awaitTransactionMinedAsync, it will throw if the receipt has a
- * status that is not equal to 1. A status of 0 or null indicates that the
- * transaction was mined, but failed. See:
- * https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgettransactionreceipt
- * @param txHash Transaction hash
- * @param pollingIntervalMs How often (in ms) should we check if the transaction is mined.
- * @param timeoutMs How long (in ms) to poll for transaction mined until aborting.
- * @return Transaction receipt with decoded log args.
- */
- public async awaitTransactionSuccessAsync(
- txHash: string,
- pollingIntervalMs: number = 1000,
- timeoutMs?: number,
- ): Promise<TransactionReceiptWithDecodedLogs> {
- const receipt = await this.awaitTransactionMinedAsync(txHash, pollingIntervalMs, timeoutMs);
- if (receipt.status !== 1) {
- throw new Error(`Transaction failed: ${txHash}`);
- }
- return receipt;
- }
- /**
- * Calls the 'debug_setHead' JSON RPC method, which sets the current head of
- * the local chain by block number. Note, this is a destructive action and
- * may severely damage your chain. Use with extreme caution. As of now, this
- * is only supported by Geth. It sill throw if the 'debug_setHead' method is
- * not supported.
- * @param blockNumber The block number to reset to.
- */
- public async setHeadAsync(blockNumber: number): Promise<void> {
- assert.isNumber('blockNumber', blockNumber);
- await this.sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [utils.numberToHex(blockNumber)] });
- }
- /**
- * Sends a raw Ethereum JSON RPC payload and returns the response's `result` key
- * @param payload A partial JSON RPC payload. No need to include version, id, params (if none needed)
- * @return The contents nested under the result key of the response body
- */
- public async sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> {
- const sendAsync = this._provider.sendAsync.bind(this._provider);
- const payloadWithDefaults = {
- id: this._jsonRpcRequestId++,
- params: [],
- jsonrpc: '2.0',
- ...payload,
- };
- const response = await promisify<JSONRPCResponsePayload>(sendAsync)(payloadWithDefaults);
- if (response.error) {
- throw new Error(response.error.message);
- }
- const result = response.result;
- return result;
- }
- /**
- * Returns either NodeType.Geth or NodeType.Ganache depending on the type of
- * the backing Ethereum node. Throws for any other type of node.
- */
- public async getNodeTypeAsync(): Promise<NodeType> {
- const version = await this.getNodeVersionAsync();
- if (_.includes(version, uniqueVersionIds.geth)) {
- return NodeType.Geth;
- } else if (_.includes(version, uniqueVersionIds.ganache)) {
- return NodeType.Ganache;
- } else {
- throw new Error(`Unknown client version: ${version}`);
- }
- }
-} // tslint:disable-line:max-file-line-count