Merge pull request #821 from 0xProject/remove-web3-from-wrapper
Remove Web3.js From 0x-monorepo 🍾
This commit is contained in:
@@ -1,4 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "0.2.13",
|
||||
"changes": [
|
||||
{
|
||||
"note":
|
||||
"Fix bug in string enum assertion. We erroneously were checking against the enum keys, not values",
|
||||
"pr": 821
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1529397769,
|
||||
"version": "0.2.12",
|
||||
|
@@ -41,8 +41,8 @@ export const assert = {
|
||||
value: string,
|
||||
stringEnum: any /* There is no base type for every string enum */,
|
||||
): void {
|
||||
const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]);
|
||||
const enumValues = _.keys(stringEnum);
|
||||
const enumValues = _.values(stringEnum);
|
||||
const doesBelongToStringEnum = _.includes(enumValues, value);
|
||||
const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`);
|
||||
const enumValuesAsString = enumValuesAsStrings.join(', ');
|
||||
assert.assert(
|
||||
|
@@ -80,7 +80,7 @@ export class BaseContract {
|
||||
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
|
||||
} as any;
|
||||
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
|
||||
txDataWithDefaults.gas = await estimateGasAsync(txData);
|
||||
txDataWithDefaults.gas = await estimateGasAsync(txDataWithDefaults as any);
|
||||
}
|
||||
return txDataWithDefaults;
|
||||
}
|
||||
|
@@ -5,6 +5,10 @@
|
||||
{
|
||||
"note": "Update schemas for V2",
|
||||
"pr": 615
|
||||
},
|
||||
{
|
||||
"note": "Added CallData schema",
|
||||
"pr": 821
|
||||
}
|
||||
]
|
||||
},
|
||||
|
27
packages/json-schemas/schemas/call_data_schema.ts
Normal file
27
packages/json-schemas/schemas/call_data_schema.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export const callDataSchema = {
|
||||
id: '/TxData',
|
||||
properties: {
|
||||
from: { $ref: '/Address' },
|
||||
to: { $ref: '/Address' },
|
||||
value: {
|
||||
oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
|
||||
},
|
||||
gas: {
|
||||
oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
|
||||
},
|
||||
gasPrice: {
|
||||
oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }],
|
||||
},
|
||||
data: {
|
||||
type: 'string',
|
||||
pattern: '^0x[0-9a-f]*$',
|
||||
},
|
||||
nonce: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
};
|
@@ -1,5 +1,6 @@
|
||||
import { addressSchema, hexSchema, numberSchema } from '../schemas/basic_type_schemas';
|
||||
import { blockParamSchema, blockRangeSchema } from '../schemas/block_range_schema';
|
||||
import { callDataSchema } from '../schemas/call_data_schema';
|
||||
import { ecSignatureSchema } from '../schemas/ec_signature_schema';
|
||||
import { indexFilterValuesSchema } from '../schemas/index_filter_values_schema';
|
||||
import { orderCancellationRequestsSchema } from '../schemas/order_cancel_schema';
|
||||
@@ -31,6 +32,7 @@ import { jsNumber, txDataSchema } from '../schemas/tx_data_schema';
|
||||
export const schemas = {
|
||||
numberSchema,
|
||||
addressSchema,
|
||||
callDataSchema,
|
||||
hexSchema,
|
||||
ecSignatureSchema,
|
||||
indexFilterValuesSchema,
|
||||
|
@@ -64,12 +64,14 @@
|
||||
"typescript": "2.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.2.12",
|
||||
"@0xproject/json-schemas": "^1.0.0",
|
||||
"@0xproject/typescript-typings": "^0.4.1",
|
||||
"@0xproject/utils": "^0.7.1",
|
||||
"ethereum-types": "^0.0.2",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "3.0.22",
|
||||
"lodash": "^4.17.4",
|
||||
"web3": "^0.20.0"
|
||||
"lodash": "^4.17.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
149
packages/web3-wrapper/src/marshaller.ts
Normal file
149
packages/web3-wrapper/src/marshaller.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { addressUtils } from '@0xproject/utils';
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
BlockWithoutTransactionData,
|
||||
BlockWithTransactionData,
|
||||
CallData,
|
||||
CallTxDataBase,
|
||||
LogEntry,
|
||||
RawLogEntry,
|
||||
Transaction,
|
||||
TxData,
|
||||
} from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { utils } from './utils';
|
||||
|
||||
import {
|
||||
BlockWithoutTransactionDataRPC,
|
||||
BlockWithTransactionDataRPC,
|
||||
CallDataRPC,
|
||||
CallTxDataBaseRPC,
|
||||
TransactionRPC,
|
||||
TxDataRPC,
|
||||
} from './types';
|
||||
|
||||
export const marshaller = {
|
||||
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;
|
||||
},
|
||||
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 = this.unmarshalTransaction(tx);
|
||||
return transaction;
|
||||
});
|
||||
return block;
|
||||
},
|
||||
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;
|
||||
},
|
||||
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 = this._marshalCallTxDataBase(callTxDataBase);
|
||||
const txDataRPC = {
|
||||
...callTxDataBaseRPC,
|
||||
from: this.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;
|
||||
},
|
||||
marshalCallData(callData: Partial<CallData>): Partial<CallDataRPC> {
|
||||
const callTxDataBase = {
|
||||
...callData,
|
||||
};
|
||||
delete callTxDataBase.from;
|
||||
const callTxDataBaseRPC = this._marshalCallTxDataBase(callTxDataBase);
|
||||
const callDataRPC = {
|
||||
...callTxDataBaseRPC,
|
||||
from: _.isUndefined(callData.from) ? undefined : this.marshalAddress(callData.from),
|
||||
};
|
||||
return callDataRPC;
|
||||
},
|
||||
marshalAddress(address: string): string {
|
||||
if (addressUtils.isAddress(address)) {
|
||||
return ethUtil.addHexPrefix(address);
|
||||
}
|
||||
throw new Error(`Invalid address encountered: ${address}`);
|
||||
},
|
||||
marshalBlockParam(blockParam: BlockParam | string | number | undefined): string | undefined {
|
||||
if (_.isUndefined(blockParam)) {
|
||||
return BlockParamLiteral.Latest;
|
||||
}
|
||||
const encodedBlockParam = _.isNumber(blockParam) ? utils.numberToHex(blockParam) : blockParam;
|
||||
return encodedBlockParam;
|
||||
},
|
||||
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 : this.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;
|
||||
},
|
||||
};
|
@@ -1,3 +1,59 @@
|
||||
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 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;
|
||||
}
|
||||
|
58
packages/web3-wrapper/src/utils.ts
Normal file
58
packages/web3-wrapper/src/utils.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export const utils = {
|
||||
isBigNumber(value: any): boolean {
|
||||
const isBigNumber = _.isObject(value) && value.isBigNumber;
|
||||
return isBigNumber;
|
||||
},
|
||||
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 = this.convertHexToNumber(hex);
|
||||
return decimal;
|
||||
},
|
||||
convertAmountToBigNumber(value: string | number | BigNumber): BigNumber {
|
||||
const num = value || 0;
|
||||
const isBigNumber = utils.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.lessThan(0) ? '-0x' + valueHex.substr(1) : '0x' + valueHex;
|
||||
},
|
||||
numberToHex(value: number): string {
|
||||
if (!isFinite(value) && !this.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)
|
||||
);
|
||||
},
|
||||
};
|
@@ -1,10 +1,12 @@
|
||||
import { assert } from '@0xproject/assert';
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { AbiDecoder, addressUtils, BigNumber, intervalUtils, promisify } from '@0xproject/utils';
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
BlockWithoutTransactionData,
|
||||
BlockWithTransactionData,
|
||||
CallData,
|
||||
ContractAbi,
|
||||
FilterObject,
|
||||
JSONRPCRequestPayload,
|
||||
JSONRPCResponsePayload,
|
||||
@@ -18,9 +20,10 @@ import {
|
||||
TxData,
|
||||
} from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { Web3WrapperErrors } from './types';
|
||||
import { marshaller } from './marshaller';
|
||||
import { BlockWithoutTransactionDataRPC, BlockWithTransactionDataRPC, Web3WrapperErrors } from './types';
|
||||
import { utils } from './utils';
|
||||
|
||||
const BASE_TEN = 10;
|
||||
|
||||
@@ -38,7 +41,7 @@ export enum NodeType {
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around the Web3.js 0.x library that provides a consistent, clean promise-based interface.
|
||||
* An alternative to the Web3.js library that provides a consistent, clean, promise-based interface.
|
||||
*/
|
||||
export class Web3Wrapper {
|
||||
/**
|
||||
@@ -46,7 +49,7 @@ export class Web3Wrapper {
|
||||
*/
|
||||
public isZeroExWeb3Wrapper = true;
|
||||
public abiDecoder: AbiDecoder;
|
||||
private _web3: Web3;
|
||||
private _provider: Provider;
|
||||
private _txDefaults: Partial<TxData>;
|
||||
private _jsonRpcRequestId: number;
|
||||
/**
|
||||
@@ -66,6 +69,8 @@ export class Web3Wrapper {
|
||||
* @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;
|
||||
@@ -79,6 +84,8 @@ export class Web3Wrapper {
|
||||
* @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;
|
||||
@@ -93,10 +100,44 @@ export class Web3Wrapper {
|
||||
* @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
|
||||
@@ -105,6 +146,7 @@ export class Web3Wrapper {
|
||||
* @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`
|
||||
@@ -112,8 +154,7 @@ export class Web3Wrapper {
|
||||
(provider as any).sendAsync = (provider as any).send;
|
||||
}
|
||||
this.abiDecoder = new AbiDecoder([]);
|
||||
this._web3 = new Web3();
|
||||
this._web3.setProvider(provider);
|
||||
this._provider = provider;
|
||||
this._txDefaults = txDefaults || {};
|
||||
this._jsonRpcRequestId = 0;
|
||||
}
|
||||
@@ -129,14 +170,15 @@ export class Web3Wrapper {
|
||||
* @return Web3 provider instance
|
||||
*/
|
||||
public getProvider(): Provider {
|
||||
return this._web3.currentProvider;
|
||||
return this._provider;
|
||||
}
|
||||
/**
|
||||
* Update the used Web3 provider
|
||||
* @param provider The new Web3 provider to be set
|
||||
*/
|
||||
public setProvider(provider: Provider): void {
|
||||
this._web3.setProvider(provider);
|
||||
assert.isWeb3Provider('provider', provider);
|
||||
this._provider = provider;
|
||||
}
|
||||
/**
|
||||
* Check whether an address is available through the backing provider. This can be
|
||||
@@ -146,6 +188,7 @@ export class Web3Wrapper {
|
||||
* @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);
|
||||
@@ -173,9 +216,13 @@ export class Web3Wrapper {
|
||||
* @returns The transaction receipt, including it's status (0: failed, 1: succeeded or undefined: not found)
|
||||
*/
|
||||
public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
|
||||
const transactionReceipt = await promisify<TransactionReceipt>(this._web3.eth.getTransactionReceipt)(txHash);
|
||||
assert.isHexString('txHash', txHash);
|
||||
const transactionReceipt = await this._sendRawPayloadAsync<TransactionReceipt>({
|
||||
method: 'eth_getTransactionReceipt',
|
||||
params: [txHash],
|
||||
});
|
||||
if (!_.isNull(transactionReceipt)) {
|
||||
transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status);
|
||||
transactionReceipt.status = Web3Wrapper._normalizeTxReceiptStatus(transactionReceipt.status);
|
||||
}
|
||||
return transactionReceipt;
|
||||
}
|
||||
@@ -184,11 +231,19 @@ export class Web3Wrapper {
|
||||
* @param owner Account whose balance you wish to check
|
||||
* @returns Balance in wei
|
||||
*/
|
||||
public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
|
||||
let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
|
||||
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
|
||||
balanceInWei = new BigNumber(balanceInWei);
|
||||
return balanceInWei;
|
||||
return new BigNumber(balanceInWei);
|
||||
}
|
||||
/**
|
||||
* Check if a contract exists at a given address
|
||||
@@ -196,6 +251,7 @@ export class Web3Wrapper {
|
||||
* @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);
|
||||
@@ -204,10 +260,20 @@ export class Web3Wrapper {
|
||||
/**
|
||||
* 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): Promise<string> {
|
||||
const code = await promisify<string>(this._web3.eth.getCode)(address);
|
||||
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;
|
||||
}
|
||||
/**
|
||||
@@ -217,6 +283,7 @@ export class Web3Wrapper {
|
||||
* @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],
|
||||
@@ -230,7 +297,13 @@ export class Web3Wrapper {
|
||||
* @returns Signature string (might be VRS or RSV depending on the Signer)
|
||||
*/
|
||||
public async signMessageAsync(address: string, message: string): Promise<string> {
|
||||
const signData = await promisify<string>(this._web3.eth.sign)(address, message);
|
||||
assert.isETHAddressHex('address', address);
|
||||
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;
|
||||
}
|
||||
/**
|
||||
@@ -238,8 +311,12 @@ export class Web3Wrapper {
|
||||
* @returns Block number
|
||||
*/
|
||||
public async getBlockNumberAsync(): Promise<number> {
|
||||
const blockNumber = await promisify<number>(this._web3.eth.getBlockNumber)();
|
||||
return blockNumber;
|
||||
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
|
||||
@@ -247,10 +324,18 @@ export class Web3Wrapper {
|
||||
* @returns The requested block without transaction data
|
||||
*/
|
||||
public async getBlockAsync(blockParam: string | BlockParam): Promise<BlockWithoutTransactionData> {
|
||||
Web3Wrapper._assertBlockParamOrString(blockParam);
|
||||
const encodedBlockParam = marshaller.marshalBlockParam(blockParam);
|
||||
const method = utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber';
|
||||
const shouldIncludeTransactionData = false;
|
||||
const blockWithoutTransactionData = await promisify<BlockWithoutTransactionData>(this._web3.eth.getBlock)(
|
||||
blockParam,
|
||||
shouldIncludeTransactionData,
|
||||
const blockWithoutTransactionDataWithHexValues = await this._sendRawPayloadAsync<
|
||||
BlockWithoutTransactionDataRPC
|
||||
>({
|
||||
method,
|
||||
params: [encodedBlockParam, shouldIncludeTransactionData],
|
||||
});
|
||||
const blockWithoutTransactionData = marshaller.unmarshalIntoBlockWithoutTransactionData(
|
||||
blockWithoutTransactionDataWithHexValues,
|
||||
);
|
||||
return blockWithoutTransactionData;
|
||||
}
|
||||
@@ -260,12 +345,21 @@ export class Web3Wrapper {
|
||||
* @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 blockWithTransactionData = await promisify<BlockWithTransactionData>(this._web3.eth.getBlock)(
|
||||
blockParam,
|
||||
shouldIncludeTransactionData,
|
||||
const blockWithTransactionDataWithHexValues = await this._sendRawPayloadAsync<BlockWithTransactionDataRPC>({
|
||||
method,
|
||||
params: [encodedBlockParam, shouldIncludeTransactionData],
|
||||
});
|
||||
const blockWithoutTransactionData = marshaller.unmarshalIntoBlockWithTransactionData(
|
||||
blockWithTransactionDataWithHexValues,
|
||||
);
|
||||
return blockWithTransactionData;
|
||||
return blockWithoutTransactionData;
|
||||
}
|
||||
/**
|
||||
* Fetch a block's timestamp
|
||||
@@ -273,6 +367,7 @@ export class Web3Wrapper {
|
||||
* @returns The block's timestamp
|
||||
*/
|
||||
public async getBlockTimestampAsync(blockParam: string | BlockParam): Promise<number> {
|
||||
Web3Wrapper._assertBlockParamOrString(blockParam);
|
||||
const { timestamp } = await this.getBlockAsync(blockParam);
|
||||
return timestamp;
|
||||
}
|
||||
@@ -281,7 +376,10 @@ export class Web3Wrapper {
|
||||
* @returns Available user addresses
|
||||
*/
|
||||
public async getAvailableAddressesAsync(): Promise<string[]> {
|
||||
const addresses = await promisify<string[]>(this._web3.eth.getAccounts)();
|
||||
const addresses = await this._sendRawPayloadAsync<string>({
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
});
|
||||
const normalizedAddresses = _.map(addresses, address => address.toLowerCase());
|
||||
return normalizedAddresses;
|
||||
}
|
||||
@@ -299,6 +397,7 @@ export class Web3Wrapper {
|
||||
* @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;
|
||||
}
|
||||
@@ -314,6 +413,7 @@ export class Web3Wrapper {
|
||||
* @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)) {
|
||||
@@ -332,11 +432,11 @@ export class Web3Wrapper {
|
||||
public async getLogsAsync(filter: FilterObject): Promise<LogEntry[]> {
|
||||
let fromBlock = filter.fromBlock;
|
||||
if (_.isNumber(fromBlock)) {
|
||||
fromBlock = this._web3.toHex(fromBlock);
|
||||
fromBlock = utils.numberToHex(fromBlock);
|
||||
}
|
||||
let toBlock = filter.toBlock;
|
||||
if (_.isNumber(toBlock)) {
|
||||
toBlock = this._web3.toHex(toBlock);
|
||||
toBlock = utils.numberToHex(toBlock);
|
||||
}
|
||||
const serializedFilter = {
|
||||
...filter,
|
||||
@@ -344,30 +444,27 @@ export class Web3Wrapper {
|
||||
toBlock,
|
||||
};
|
||||
const payload = {
|
||||
jsonrpc: '2.0',
|
||||
method: 'eth_getLogs',
|
||||
params: [serializedFilter],
|
||||
};
|
||||
const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload);
|
||||
const formattedLogs = _.map(rawLogs, this._formatLog.bind(this));
|
||||
const formattedLogs = _.map(rawLogs, marshaller.unmarshalLog.bind(marshaller));
|
||||
return formattedLogs;
|
||||
}
|
||||
/**
|
||||
* Get a Web3 contract factory instance for a given ABI
|
||||
* @param abi Smart contract ABI
|
||||
* @returns Web3 contract factory which can create Web3 Contract instances from the supplied ABI
|
||||
*/
|
||||
public getContractFromAbi(abi: ContractAbi): Web3.Contract<any> {
|
||||
const web3Contract = this._web3.eth.contract(abi);
|
||||
return web3Contract;
|
||||
}
|
||||
/**
|
||||
* 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> {
|
||||
const gas = await promisify<number>(this._web3.eth.estimateGas)(txData);
|
||||
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;
|
||||
}
|
||||
/**
|
||||
@@ -377,7 +474,20 @@ export class Web3Wrapper {
|
||||
* @returns The raw call result
|
||||
*/
|
||||
public async callAsync(callData: CallData, defaultBlock?: BlockParam): Promise<string> {
|
||||
const rawCallResult = await promisify<string>(this._web3.eth.call)(callData, defaultBlock);
|
||||
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],
|
||||
});
|
||||
if (rawCallResult === '0x') {
|
||||
throw new Error('Contract call failed (returned null)');
|
||||
}
|
||||
@@ -389,7 +499,13 @@ export class Web3Wrapper {
|
||||
* @returns Transaction hash
|
||||
*/
|
||||
public async sendTransactionAsync(txData: TxData): Promise<string> {
|
||||
const txHash = await promisify<string>(this._web3.eth.sendTransaction)(txData);
|
||||
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;
|
||||
}
|
||||
/**
|
||||
@@ -408,6 +524,11 @@ export class Web3Wrapper {
|
||||
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.getTransactionReceiptAsync(txHash);
|
||||
if (!_.isNull(transactionReceipt)) {
|
||||
@@ -493,7 +614,8 @@ export class Web3Wrapper {
|
||||
* @param blockNumber The block number to reset to.
|
||||
*/
|
||||
public async setHeadAsync(blockNumber: number): Promise<void> {
|
||||
await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [this._web3.toHex(blockNumber)] });
|
||||
assert.isNumber('blockNumber', blockNumber);
|
||||
await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [utils.numberToHex(blockNumber)] });
|
||||
}
|
||||
/**
|
||||
* Returns either NodeType.Geth or NodeType.Ganache depending on the type of
|
||||
@@ -510,7 +632,7 @@ export class Web3Wrapper {
|
||||
}
|
||||
}
|
||||
private async _sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> {
|
||||
const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider);
|
||||
const sendAsync = this._provider.sendAsync.bind(this._provider);
|
||||
const payloadWithDefaults = {
|
||||
id: this._jsonRpcRequestId++,
|
||||
params: [],
|
||||
@@ -521,34 +643,4 @@ export class Web3Wrapper {
|
||||
const result = response.result;
|
||||
return result;
|
||||
}
|
||||
private _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 this._web3.toDecimal(status) as 0 | 1;
|
||||
} else if (_.isUndefined(status)) {
|
||||
return null;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
private _formatLog(rawLog: RawLogEntry): LogEntry {
|
||||
const formattedLog = {
|
||||
...rawLog,
|
||||
logIndex: this._hexToDecimal(rawLog.logIndex),
|
||||
blockNumber: this._hexToDecimal(rawLog.blockNumber),
|
||||
transactionIndex: this._hexToDecimal(rawLog.transactionIndex),
|
||||
};
|
||||
return formattedLog;
|
||||
}
|
||||
private _hexToDecimal(hex: string | null): number | null {
|
||||
if (_.isNull(hex)) {
|
||||
return null;
|
||||
}
|
||||
const decimal = this._web3.toDecimal(hex);
|
||||
return decimal;
|
||||
}
|
||||
} // tslint:disable-line:max-file-line-count
|
||||
|
@@ -1,18 +1,27 @@
|
||||
import * as chai from 'chai';
|
||||
import { BlockParamLiteral } from 'ethereum-types';
|
||||
import * as Ganache from 'ganache-core';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
|
||||
import { Web3Wrapper } from '../src';
|
||||
import { utils } from '../src/utils';
|
||||
import { Web3Wrapper } from '../src/web3_wrapper';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
chaiSetup.configure();
|
||||
|
||||
const { expect } = chai;
|
||||
|
||||
const NUM_GANACHE_ADDRESSES = 10;
|
||||
|
||||
describe('Web3Wrapper tests', () => {
|
||||
const NETWORK_ID = 50;
|
||||
const provider = Ganache.provider({ network_id: NETWORK_ID });
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
let addresses: string[];
|
||||
before(async () => {
|
||||
addresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
});
|
||||
describe('#isAddress', () => {
|
||||
it('correctly checks if a string is a valid ethereum address', () => {
|
||||
expect(Web3Wrapper.isAddress('0x0')).to.be.false();
|
||||
@@ -36,4 +45,88 @@ describe('Web3Wrapper tests', () => {
|
||||
expect(networkId).to.be.equal(NETWORK_ID);
|
||||
});
|
||||
});
|
||||
describe('#getNetworkIdAsync', () => {
|
||||
it('gets the network id', async () => {
|
||||
const networkId = await web3Wrapper.getNetworkIdAsync();
|
||||
expect(networkId).to.be.equal(NETWORK_ID);
|
||||
});
|
||||
});
|
||||
describe('#getAvailableAddressesAsync', () => {
|
||||
it('gets the available addresses', async () => {
|
||||
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||
expect(availableAddresses.length).to.be.equal(NUM_GANACHE_ADDRESSES);
|
||||
expect(Web3Wrapper.isAddress(availableAddresses[0])).to.equal(true);
|
||||
});
|
||||
});
|
||||
describe('#getBalanceInWeiAsync', () => {
|
||||
it('gets the users balance in wei', async () => {
|
||||
const secondAccount = addresses[1];
|
||||
const balanceInWei = await web3Wrapper.getBalanceInWeiAsync(secondAccount);
|
||||
const tenEthInWei = 100000000000000000000;
|
||||
expect(balanceInWei).to.be.bignumber.equal(tenEthInWei);
|
||||
});
|
||||
it('should throw if supplied owner not an Ethereum address hex string', async () => {
|
||||
const invalidEthAddress = 'deadbeef';
|
||||
expect(web3Wrapper.getBalanceInWeiAsync(invalidEthAddress)).to.eventually.to.be.rejected();
|
||||
});
|
||||
});
|
||||
describe('#signMessageAsync', () => {
|
||||
it('should sign message', async () => {
|
||||
const message = '0xdeadbeef';
|
||||
const signer = addresses[1];
|
||||
const signature = await web3Wrapper.signMessageAsync(signer, message);
|
||||
const signatureLength = 132;
|
||||
expect(signature.length).to.be.equal(signatureLength);
|
||||
});
|
||||
});
|
||||
describe('#getBlockNumberAsync', () => {
|
||||
it('get block number', async () => {
|
||||
const blockNumber = await web3Wrapper.getBlockNumberAsync();
|
||||
expect(typeof blockNumber).to.be.equal('number');
|
||||
});
|
||||
});
|
||||
describe('#getBlockAsync', () => {
|
||||
it('gets block when supplied a valid BlockParamLiteral value', async () => {
|
||||
const blockParamLiteral = BlockParamLiteral.Earliest;
|
||||
const block = await web3Wrapper.getBlockAsync(blockParamLiteral);
|
||||
expect(block.number).to.be.equal(0);
|
||||
expect(utils.isBigNumber(block.difficulty)).to.equal(true);
|
||||
expect(_.isNumber(block.gasLimit)).to.equal(true);
|
||||
});
|
||||
it('gets block when supplied a block number', async () => {
|
||||
const blockParamLiteral = 0;
|
||||
const block = await web3Wrapper.getBlockAsync(blockParamLiteral);
|
||||
expect(block.number).to.be.equal(0);
|
||||
});
|
||||
it('gets block when supplied a block hash', async () => {
|
||||
const blockParamLiteral = 0;
|
||||
const block = await web3Wrapper.getBlockAsync(blockParamLiteral);
|
||||
const sameBlock = await web3Wrapper.getBlockAsync(block.hash as string);
|
||||
expect(sameBlock.number).to.be.equal(0);
|
||||
});
|
||||
it('should throw if supplied invalid blockParam value', async () => {
|
||||
const invalidBlockParam = 'deadbeef';
|
||||
expect(web3Wrapper.getBlockAsync(invalidBlockParam)).to.eventually.to.be.rejected();
|
||||
});
|
||||
});
|
||||
describe('#getBlockWithTransactionDataAsync', () => {
|
||||
it('gets block when supplied a valid BlockParamLiteral value', async () => {
|
||||
const blockParamLiteral = BlockParamLiteral.Earliest;
|
||||
const block = await web3Wrapper.getBlockWithTransactionDataAsync(blockParamLiteral);
|
||||
expect(block.number).to.be.equal(0);
|
||||
expect(utils.isBigNumber(block.difficulty)).to.equal(true);
|
||||
expect(_.isNumber(block.gasLimit)).to.equal(true);
|
||||
});
|
||||
it('should throw if supplied invalid blockParam value', async () => {
|
||||
const invalidBlockParam = 'deadbeef';
|
||||
expect(web3Wrapper.getBlockWithTransactionDataAsync(invalidBlockParam)).to.eventually.to.be.rejected();
|
||||
});
|
||||
});
|
||||
describe('#getBlockTimestampAsync', () => {
|
||||
it('gets block timestamp', async () => {
|
||||
const blockParamLiteral = BlockParamLiteral.Earliest;
|
||||
const timestamp = await web3Wrapper.getBlockTimestampAsync(blockParamLiteral);
|
||||
expect(_.isNumber(timestamp)).to.be.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
10
yarn.lock
10
yarn.lock
@@ -12721,16 +12721,6 @@ web3@^0.18.0:
|
||||
xhr2 "*"
|
||||
xmlhttprequest "*"
|
||||
|
||||
web3@^0.20.0:
|
||||
version "0.20.6"
|
||||
resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.6.tgz#3e97306ae024fb24e10a3d75c884302562215120"
|
||||
dependencies:
|
||||
bignumber.js "git+https://github.com/frozeman/bignumber.js-nolookahead.git"
|
||||
crypto-js "^3.1.4"
|
||||
utf8 "^2.1.1"
|
||||
xhr2 "*"
|
||||
xmlhttprequest "*"
|
||||
|
||||
web3@^1.0.0-beta.34:
|
||||
version "1.0.0-beta.34"
|
||||
resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.34.tgz#347e561b784098cb5563315f490479a1d91f2ab1"
|
||||
|
Reference in New Issue
Block a user