import * as _ from 'lodash'; import * as Web3 from 'web3'; import * as BigNumber from 'bignumber.js'; import promisify = require('es6-promisify'); import {ZeroExError} from './types'; import {Contract} from './contract'; export class Web3Wrapper { private web3: Web3; private defaults: Partial; private networkIdIfExists?: number; constructor(provider: Web3.Provider, defaults: Partial) { this.web3 = new Web3(); this.web3.setProvider(provider); this.defaults = defaults; } public setProvider(provider: Web3.Provider) { delete this.networkIdIfExists; this.web3.setProvider(provider); } public isAddress(address: string): boolean { return this.web3.isAddress(address); } public async isSenderAddressAvailableAsync(senderAddress: string): Promise { const addresses = await this.getAvailableAddressesAsync(); return _.includes(addresses, senderAddress); } public async getNodeVersionAsync(): Promise { const nodeVersion = await promisify(this.web3.version.getNode)(); return nodeVersion; } public async getTransactionReceiptAsync(txHash: string): Promise { const transactionReceipt = await promisify(this.web3.eth.getTransactionReceipt)(txHash); return transactionReceipt; } public getCurrentProvider(): Web3.Provider { return this.web3.currentProvider; } public async getNetworkIdIfExistsAsync(): Promise { if (!_.isUndefined(this.networkIdIfExists)) { return this.networkIdIfExists; } try { const networkId = await this.getNetworkAsync(); this.networkIdIfExists = Number(networkId); return this.networkIdIfExists; } catch (err) { return undefined; } } public async getContractInstanceFromArtifactAsync(artifact: Artifact, address?: string): Promise { let contractAddress: string; if (_.isUndefined(address)) { const networkIdIfExists = await this.getNetworkIdIfExistsAsync(); if (_.isUndefined(networkIdIfExists)) { throw new Error(ZeroExError.NoNetworkId); } if (_.isUndefined(artifact.networks[networkIdIfExists])) { throw new Error(ZeroExError.ContractNotDeployedOnNetwork); } contractAddress = artifact.networks[networkIdIfExists].address.toLowerCase(); } else { contractAddress = address; } const doesContractExist = await this.doesContractExistAtAddressAsync(contractAddress); if (!doesContractExist) { throw new Error(ZeroExError.ContractDoesNotExist); } const contractInstance = this.getContractInstance( artifact.abi, contractAddress, ); return contractInstance; } public toWei(ethAmount: BigNumber.BigNumber): BigNumber.BigNumber { const balanceWei = this.web3.toWei(ethAmount, 'ether'); return balanceWei; } public async getBalanceInWeiAsync(owner: string): Promise { let balanceInWei = await promisify(this.web3.eth.getBalance)(owner); balanceInWei = new BigNumber(balanceInWei); return balanceInWei; } public async doesContractExistAtAddressAsync(address: string): Promise { const code = await promisify(this.web3.eth.getCode)(address); // Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients const codeIsEmpty = /^0x0{0,40}$/i.test(code); return !codeIsEmpty; } public async signTransactionAsync(address: string, message: string): Promise { const signData = await promisify(this.web3.eth.sign)(address, message); return signData; } public async getBlockTimestampAsync(blockHash: string): Promise { const {timestamp} = await promisify(this.web3.eth.getBlock)(blockHash); return timestamp; } public async getAvailableAddressesAsync(): Promise { const addresses: string[] = await promisify(this.web3.eth.getAccounts)(); return addresses; } private getContractInstance(abi: Web3.ContractAbi, address: string): A { const web3ContractInstance = this.web3.eth.contract(abi).at(address); const contractInstance = new Contract(web3ContractInstance, this.defaults) as any as A; return contractInstance; } private async getNetworkAsync(): Promise { const networkId = await promisify(this.web3.version.getNetwork)(); return networkId; } }