aboutsummaryrefslogtreecommitdiffstats
path: root/packages/web3-wrapper
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-07-04 14:54:43 +0800
committerFabio Berger <me@fabioberger.com>2018-07-04 14:54:43 +0800
commitcd766ea2a1fb56282fc45a1a19d991bbcae8db99 (patch)
tree2e7c8dc464131b3afae269b7384a21d5d6c802a2 /packages/web3-wrapper
parent590033bcb27c9e8299c1cb56b75f9a64d674affb (diff)
downloaddexon-sol-tools-cd766ea2a1fb56282fc45a1a19d991bbcae8db99.tar.gz
dexon-sol-tools-cd766ea2a1fb56282fc45a1a19d991bbcae8db99.tar.zst
dexon-sol-tools-cd766ea2a1fb56282fc45a1a19d991bbcae8db99.zip
Add more assertions to Web3Wrapper public methods
Diffstat (limited to 'packages/web3-wrapper')
-rw-r--r--packages/web3-wrapper/src/web3_wrapper.ts57
-rw-r--r--packages/web3-wrapper/test/web3_wrapper_test.ts50
2 files changed, 104 insertions, 3 deletions
diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts
index 6ea69883c..e66c7073f 100644
--- a/packages/web3-wrapper/src/web3_wrapper.ts
+++ b/packages/web3-wrapper/src/web3_wrapper.ts
@@ -1,6 +1,8 @@
+import { assert } from '@0xproject/assert';
import { AbiDecoder, addressUtils, BigNumber, intervalUtils, promisify } from '@0xproject/utils';
import {
BlockParam,
+ BlockParamLiteral,
BlockWithoutTransactionData,
BlockWithTransactionData,
CallData,
@@ -60,6 +62,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;
@@ -73,6 +77,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;
@@ -87,10 +93,30 @@ 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}`);
+ }
+ }
+ }
/**
* Instantiates a new Web3Wrapper.
* @param provider The Web3 provider instance you would like the Web3Wrapper to use for interacting with
@@ -99,6 +125,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`
@@ -130,6 +157,7 @@ export class Web3Wrapper {
* @param provider The new Web3 provider to be set
*/
public setProvider(provider: Provider): void {
+ assert.isWeb3Provider('provider', provider);
this._web3.setProvider(provider);
}
/**
@@ -140,6 +168,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);
@@ -179,10 +208,13 @@ export class Web3Wrapper {
* @returns Balance in wei
*/
public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
- let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
+ assert.isETHAddressHex('owner', owner);
+ const balanceInWei = await this._sendRawPayloadAsync<string>({
+ method: 'eth_getBalance',
+ params: [owner],
+ });
// Rewrap in a new BigNumber
- balanceInWei = new BigNumber(balanceInWei);
- return balanceInWei;
+ return new BigNumber(balanceInWei);
}
/**
* Check if a contract exists at a given address
@@ -190,6 +222,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);
@@ -201,6 +234,7 @@ export class Web3Wrapper {
* @return Code of the contract
*/
public async getContractCodeAsync(address: string): Promise<string> {
+ assert.isETHAddressHex('address', address);
const code = await promisify<string>(this._web3.eth.getCode)(address);
return code;
}
@@ -211,6 +245,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],
@@ -224,6 +259,8 @@ export class Web3Wrapper {
* @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 promisify<string>(this._web3.eth.sign)(address, message);
return signData;
}
@@ -241,6 +278,7 @@ export class Web3Wrapper {
* @returns The requested block without transaction data
*/
public async getBlockAsync(blockParam: string | BlockParam): Promise<BlockWithoutTransactionData> {
+ Web3Wrapper._assertBlockParamOrString(blockParam);
const shouldIncludeTransactionData = false;
const blockWithoutTransactionData = await promisify<BlockWithoutTransactionData>(this._web3.eth.getBlock)(
blockParam,
@@ -254,6 +292,7 @@ export class Web3Wrapper {
* @returns The requested block with transaction data
*/
public async getBlockWithTransactionDataAsync(blockParam: string | BlockParam): Promise<BlockWithTransactionData> {
+ Web3Wrapper._assertBlockParamOrString(blockParam);
const shouldIncludeTransactionData = true;
const blockWithTransactionData = await promisify<BlockWithTransactionData>(this._web3.eth.getBlock)(
blockParam,
@@ -267,6 +306,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;
}
@@ -293,6 +333,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;
}
@@ -308,6 +349,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)) {
@@ -371,6 +413,9 @@ export class Web3Wrapper {
* @returns The raw call result
*/
public async callAsync(callData: CallData, defaultBlock?: BlockParam): Promise<string> {
+ if (!_.isUndefined(defaultBlock)) {
+ Web3Wrapper._assertBlockParam(defaultBlock);
+ }
const rawCallResult = await promisify<string>(this._web3.eth.call)(callData, defaultBlock);
if (rawCallResult === '0x') {
throw new Error('Contract call failed (returned null)');
@@ -402,6 +447,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)) {
@@ -487,6 +537,7 @@ export class Web3Wrapper {
* @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: [this._web3.toHex(blockNumber)] });
}
private async _sendRawPayloadAsync<A>(payload: Partial<JSONRPCRequestPayload>): Promise<A> {
diff --git a/packages/web3-wrapper/test/web3_wrapper_test.ts b/packages/web3-wrapper/test/web3_wrapper_test.ts
index 35eab3aa2..8919775c2 100644
--- a/packages/web3-wrapper/test/web3_wrapper_test.ts
+++ b/packages/web3-wrapper/test/web3_wrapper_test.ts
@@ -1,4 +1,5 @@
import * as chai from 'chai';
+import { BlockParamLiteral } from 'ethereum-types';
import * as Ganache from 'ganache-core';
import 'mocha';
@@ -9,6 +10,8 @@ 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 });
@@ -36,4 +39,51 @@ 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 addresses = await web3Wrapper.getAvailableAddressesAsync();
+ expect(addresses.length).to.be.equal(NUM_GANACHE_ADDRESSES);
+ });
+ });
+ 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;
+ 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('#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);
+ });
+ 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();
+ });
+ });
});