aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-07-05 06:36:01 +0800
committerFabio Berger <me@fabioberger.com>2018-07-05 06:36:01 +0800
commit1050ecdf3c9e0dbc881342b8ff377180ed1b0dad (patch)
tree5f1fd590b3a21237eaf35c8cb8e68b069be46ce8
parentd712dc47d97d3051e2938bf11b9088aba657b869 (diff)
downloaddexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.tar
dexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.tar.gz
dexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.tar.bz2
dexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.tar.lz
dexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.tar.xz
dexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.tar.zst
dexon-sol-tools-1050ecdf3c9e0dbc881342b8ff377180ed1b0dad.zip
Refactor Web3Wrapper to no longer use Web3.js & add more test coverage
-rw-r--r--packages/web3-wrapper/package.json5
-rw-r--r--packages/web3-wrapper/src/globals.d.ts8
-rw-r--r--packages/web3-wrapper/src/marshaller.ts177
-rw-r--r--packages/web3-wrapper/src/types.ts56
-rw-r--r--packages/web3-wrapper/src/utils.ts8
-rw-r--r--packages/web3-wrapper/src/web3_wrapper.ts158
-rw-r--r--packages/web3-wrapper/test/web3_wrapper_test.ts51
-rw-r--r--yarn.lock2
8 files changed, 397 insertions, 68 deletions
diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json
index d6d86b699..f12142d3c 100644
--- a/packages/web3-wrapper/package.json
+++ b/packages/web3-wrapper/package.json
@@ -67,10 +67,13 @@
"@0xproject/assert": "^0.2.12",
"@0xproject/typescript-typings": "^0.4.1",
"@0xproject/utils": "^0.7.1",
+ "bn.js": "^4.11.8",
"ethereum-types": "^0.0.1",
+ "ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
"lodash": "^4.17.4",
- "web3": "^0.20.0"
+ "web3": "^0.20.0",
+ "web3-utils": "^1.0.0-beta.34"
},
"publishConfig": {
"access": "public"
diff --git a/packages/web3-wrapper/src/globals.d.ts b/packages/web3-wrapper/src/globals.d.ts
index 94e63a32d..09c9fd819 100644
--- a/packages/web3-wrapper/src/globals.d.ts
+++ b/packages/web3-wrapper/src/globals.d.ts
@@ -1,3 +1,11 @@
+declare module 'web3-utils' {
+ import * as BigNumber from 'bignumber.js';
+
+ const toHex: (val: any) => string;
+ const isHexStrict: (val: any) => boolean;
+ const toDecimal: (val: any) => number;
+}
+
declare module '*.json' {
const json: any;
/* tslint:disable */
diff --git a/packages/web3-wrapper/src/marshaller.ts b/packages/web3-wrapper/src/marshaller.ts
new file mode 100644
index 000000000..06556ce90
--- /dev/null
+++ b/packages/web3-wrapper/src/marshaller.ts
@@ -0,0 +1,177 @@
+import { addressUtils, BigNumber } 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 web3Utils = require('web3-utils');
+
+import { utils } from './utils';
+
+import {
+ AbstractBlockRPC,
+ BlockWithoutTransactionDataRPC,
+ BlockWithTransactionDataRPC,
+ CallDataRPC,
+ CallTxDataBaseRPC,
+ TransactionRPC,
+ TxDataRPC,
+} from './types';
+
+export const marshaller = {
+ unmarshalIntoBlockWithoutTransactionData(
+ blockWithHexValues: BlockWithoutTransactionDataRPC,
+ ): BlockWithoutTransactionData {
+ const block = {
+ ...blockWithHexValues,
+ gasLimit: web3Utils.toDecimal(blockWithHexValues.gasLimit),
+ gasUsed: web3Utils.toDecimal(blockWithHexValues.gasUsed),
+ size: web3Utils.toDecimal(blockWithHexValues.size),
+ timestamp: web3Utils.toDecimal(blockWithHexValues.timestamp),
+ number: _.isNull(blockWithHexValues.number) ? null : web3Utils.toDecimal(blockWithHexValues.number),
+ difficulty: this._convertAmountToBigNumber(blockWithHexValues.difficulty),
+ totalDifficulty: this._convertAmountToBigNumber(blockWithHexValues.totalDifficulty),
+ };
+ return block;
+ },
+ unmarshalIntoBlockWithTransactionData(blockWithHexValues: BlockWithTransactionDataRPC): BlockWithTransactionData {
+ const block = {
+ ...blockWithHexValues,
+ gasLimit: web3Utils.toDecimal(blockWithHexValues.gasLimit),
+ gasUsed: web3Utils.toDecimal(blockWithHexValues.gasUsed),
+ size: web3Utils.toDecimal(blockWithHexValues.size),
+ timestamp: web3Utils.toDecimal(blockWithHexValues.timestamp),
+ number: _.isNull(blockWithHexValues.number) ? null : web3Utils.toDecimal(blockWithHexValues.number),
+ difficulty: this._convertAmountToBigNumber(blockWithHexValues.difficulty),
+ totalDifficulty: this._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) ? web3Utils.toDecimal(txRpc.blockNumber) : null,
+ transactionIndex: !_.isNull(txRpc.transactionIndex) ? web3Utils.toDecimal(txRpc.transactionIndex) : null,
+ nonce: web3Utils.toDecimal(txRpc.nonce),
+ gas: web3Utils.toDecimal(txRpc.gas),
+ gasPrice: this._convertAmountToBigNumber(txRpc.gasPrice),
+ value: this._convertAmountToBigNumber(txRpc.value),
+ };
+ return tx;
+ },
+ marshalTxData(txData: Partial<TxData>): Partial<TxDataRPC> {
+ if (_.isUndefined(txData.from)) {
+ throw new Error(`txData is missing required "from" address.`);
+ }
+ 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) ? web3Utils.toHex(blockParam) : blockParam;
+ return encodedBlockParam;
+ },
+ unmarshalLog(rawLog: RawLogEntry): LogEntry {
+ const formattedLog = {
+ ...rawLog,
+ logIndex: this.convertHexToNumberOrNull(rawLog.logIndex),
+ blockNumber: this.convertHexToNumberOrNull(rawLog.blockNumber),
+ transactionIndex: this.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
+ : this._encodeAmountAsHexString(callTxDataBase.gasPrice),
+ gas: _.isUndefined(callTxDataBase.gas) ? undefined : this._encodeAmountAsHexString(callTxDataBase.gas),
+ value: _.isUndefined(callTxDataBase.value)
+ ? undefined
+ : this._encodeAmountAsHexString(callTxDataBase.value),
+ nonce: _.isUndefined(callTxDataBase.nonce)
+ ? undefined
+ : this._encodeAmountAsHexString(callTxDataBase.nonce),
+ };
+
+ return callTxDataBaseRPC;
+ },
+ convertHexToNumberOrNull(hex: string | null): number | null {
+ if (_.isNull(hex)) {
+ return null;
+ }
+ const decimal = web3Utils.toDecimal(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 = this._convertAmountToBigNumber(value);
+ const hexBase = 16;
+ const valueHex = valueBigNumber.toString(hexBase);
+
+ return valueBigNumber.lessThan(0) ? '-0x' + valueHex.substr(1) : '0x' + valueHex;
+ },
+};
diff --git a/packages/web3-wrapper/src/types.ts b/packages/web3-wrapper/src/types.ts
index 79542da10..54a5f3f0e 100644
--- a/packages/web3-wrapper/src/types.ts
+++ b/packages/web3-wrapper/src/types.ts
@@ -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: number;
+ 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;
+}
diff --git a/packages/web3-wrapper/src/utils.ts b/packages/web3-wrapper/src/utils.ts
new file mode 100644
index 000000000..376f7e89b
--- /dev/null
+++ b/packages/web3-wrapper/src/utils.ts
@@ -0,0 +1,8 @@
+import * as _ from 'lodash';
+
+export const utils = {
+ isBigNumber(value: any): boolean {
+ const isBigNumber = _.isObject(value) && (value as any).isBigNumber;
+ return isBigNumber;
+ },
+};
diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts
index 640d3eac9..29adb18ff 100644
--- a/packages/web3-wrapper/src/web3_wrapper.ts
+++ b/packages/web3-wrapper/src/web3_wrapper.ts
@@ -20,9 +20,15 @@ import {
TxData,
} from 'ethereum-types';
import * as _ from 'lodash';
-import * as Web3 from 'web3';
+import * as web3Utils from 'web3-utils';
-import { Web3WrapperErrors } from './types';
+import { marshaller } from './marshaller';
+import {
+ BlockWithoutTransactionDataRPC,
+ BlockWithTransactionDataRPC,
+ TransactionRPC,
+ Web3WrapperErrors,
+} from './types';
const BASE_TEN = 10;
@@ -34,7 +40,7 @@ export const uniqueVersionIds = {
};
/**
- * 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 {
/**
@@ -42,7 +48,7 @@ export class Web3Wrapper {
*/
public isZeroExWeb3Wrapper = true;
public abiDecoder: AbiDecoder;
- private _web3: Web3;
+ private _provider: Provider;
private _txDefaults: Partial<TxData>;
private _jsonRpcRequestId: number;
/**
@@ -117,6 +123,20 @@ export class Web3Wrapper {
}
}
}
+ 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 web3Utils.toDecimal(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
@@ -133,8 +153,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;
}
@@ -150,7 +169,7 @@ export class Web3Wrapper {
* @return Web3 provider instance
*/
public getProvider(): Provider {
- return this._web3.currentProvider;
+ return this._provider;
}
/**
* Update the used Web3 provider
@@ -158,7 +177,7 @@ export class Web3Wrapper {
*/
public setProvider(provider: Provider): void {
assert.isWeb3Provider('provider', provider);
- this._web3.setProvider(provider);
+ this._provider = provider;
}
/**
* Check whether an address is available through the backing provider. This can be
@@ -196,9 +215,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;
}
@@ -233,9 +256,17 @@ export class Web3Wrapper {
* @param address Address of the contract
* @return Code of the contract
*/
- public async getContractCodeAsync(address: string): Promise<string> {
+ public async getContractCodeAsync(address: string, defaultBlock?: BlockParam): Promise<string> {
assert.isETHAddressHex('address', address);
- const code = await promisify<string>(this._web3.eth.getCode)(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;
}
/**
@@ -260,8 +291,12 @@ export class Web3Wrapper {
*/
public async signMessageAsync(address: string, message: string): Promise<string> {
assert.isETHAddressHex('address', address);
+ assert.isETHAddressHex('address', address);
assert.isString('message', message); // TODO: Should this be stricter? Hex string?
- const signData = await promisify<string>(this._web3.eth.sign)(address, message);
+ const signData = await this._sendRawPayloadAsync<string>({
+ method: 'eth_sign',
+ params: [address, message],
+ });
return signData;
}
/**
@@ -269,8 +304,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 = marshaller.convertHexToNumberOrNull(blockNumberHex);
+ return blockNumber as number;
}
/**
* Fetch a specific Ethereum block without transaction data
@@ -279,10 +318,17 @@ export class Web3Wrapper {
*/
public async getBlockAsync(blockParam: string | BlockParam): Promise<BlockWithoutTransactionData> {
Web3Wrapper._assertBlockParamOrString(blockParam);
+ const encodedBlockParam = marshaller.marshalBlockParam(blockParam);
+ const method = web3Utils.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;
}
@@ -293,12 +339,20 @@ export class Web3Wrapper {
*/
public async getBlockWithTransactionDataAsync(blockParam: string | BlockParam): Promise<BlockWithTransactionData> {
Web3Wrapper._assertBlockParamOrString(blockParam);
+ let encodedBlockParam = blockParam;
+ if (_.isNumber(blockParam)) {
+ encodedBlockParam = web3Utils.toHex(blockParam);
+ }
+ const method = web3Utils.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
@@ -315,7 +369,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;
}
@@ -368,11 +425,11 @@ export class Web3Wrapper {
public async getLogsAsync(filter: FilterObject): Promise<LogEntry[]> {
let fromBlock = filter.fromBlock;
if (_.isNumber(fromBlock)) {
- fromBlock = this._web3.toHex(fromBlock);
+ fromBlock = web3Utils.toHex(fromBlock);
}
let toBlock = filter.toBlock;
if (_.isNumber(toBlock)) {
- toBlock = this._web3.toHex(toBlock);
+ toBlock = web3Utils.toHex(toBlock);
}
const serializedFilter = {
...filter,
@@ -380,12 +437,11 @@ 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;
}
/**
@@ -394,7 +450,9 @@ export class Web3Wrapper {
* @returns Estimated gas cost
*/
public async estimateGasAsync(txData: Partial<TxData>): Promise<number> {
- const gas = await promisify<number>(this._web3.eth.estimateGas)(txData);
+ const txDataHex = marshaller.marshalTxData(txData);
+ const gasHex = await this._sendRawPayloadAsync<string>({ method: 'eth_estimateGas', params: [txDataHex] });
+ const gas = web3Utils.toDecimal(gasHex);
return gas;
}
/**
@@ -407,7 +465,12 @@ export class Web3Wrapper {
if (!_.isUndefined(defaultBlock)) {
Web3Wrapper._assertBlockParam(defaultBlock);
}
- const rawCallResult = await promisify<string>(this._web3.eth.call)(callData, 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)');
}
@@ -419,7 +482,8 @@ export class Web3Wrapper {
* @returns Transaction hash
*/
public async sendTransactionAsync(txData: TxData): Promise<string> {
- const txHash = await promisify<string>(this._web3.eth.sendTransaction)(txData);
+ const txDataHex = marshaller.marshalTxData(txData);
+ const txHash = await this._sendRawPayloadAsync<string>({ method: 'eth_sendTransaction', params: [txDataHex] });
return txHash;
}
/**
@@ -529,10 +593,10 @@ export class Web3Wrapper {
*/
public async setHeadAsync(blockNumber: number): Promise<void> {
assert.isNumber('blockNumber', blockNumber);
- await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [this._web3.toHex(blockNumber)] });
+ await this._sendRawPayloadAsync<void>({ method: 'debug_setHead', params: [web3Utils.toHex(blockNumber)] });
}
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: [],
@@ -543,34 +607,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
diff --git a/packages/web3-wrapper/test/web3_wrapper_test.ts b/packages/web3-wrapper/test/web3_wrapper_test.ts
index 8919775c2..b4fd8bb44 100644
--- a/packages/web3-wrapper/test/web3_wrapper_test.ts
+++ b/packages/web3-wrapper/test/web3_wrapper_test.ts
@@ -1,9 +1,11 @@
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();
@@ -16,6 +18,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();
@@ -47,13 +53,13 @@ describe('Web3Wrapper tests', () => {
});
describe('#getAvailableAddressesAsync', () => {
it('gets the available addresses', async () => {
- const addresses = await web3Wrapper.getAvailableAddressesAsync();
- expect(addresses.length).to.be.equal(NUM_GANACHE_ADDRESSES);
+ 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 addresses = await web3Wrapper.getAvailableAddressesAsync();
const secondAccount = addresses[1];
const balanceInWei = await web3Wrapper.getBalanceInWeiAsync(secondAccount);
const tenEthInWei = 100000000000000000000;
@@ -64,11 +70,28 @@ describe('Web3Wrapper tests', () => {
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;
@@ -86,4 +109,24 @@ describe('Web3Wrapper tests', () => {
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);
+ });
+ });
});
diff --git a/yarn.lock b/yarn.lock
index fae380f11..b44f45c0f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12649,7 +12649,7 @@ web3-typescript-typings@^0.10.2:
dependencies:
bignumber.js "~4.1.0"
-web3-utils@1.0.0-beta.34:
+web3-utils@1.0.0-beta.34, web3-utils@^1.0.0-beta.34:
version "1.0.0-beta.34"
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.34.tgz#9411fc39aaef39ca4e06169f762297d9ff020970"
dependencies: