aboutsummaryrefslogtreecommitdiffstats
path: root/packages/web3-wrapper
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2017-12-07 01:55:09 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2017-12-07 01:55:09 +0800
commitf1b267cc9fe7f6e5566dc2535b064b92aef92df1 (patch)
treec07a9dd32c5b959d33587ce2d38098dfe397badb /packages/web3-wrapper
parent598f1dd2d8a89b0e3ab04b2917138997031bafc6 (diff)
downloaddexon-0x-contracts-f1b267cc9fe7f6e5566dc2535b064b92aef92df1.tar.gz
dexon-0x-contracts-f1b267cc9fe7f6e5566dc2535b064b92aef92df1.tar.zst
dexon-0x-contracts-f1b267cc9fe7f6e5566dc2535b064b92aef92df1.zip
Refactor web3Wrapper to a separate package
Diffstat (limited to 'packages/web3-wrapper')
-rw-r--r--packages/web3-wrapper/README.md10
-rw-r--r--packages/web3-wrapper/package.json37
-rw-r--r--packages/web3-wrapper/src/index.ts181
-rw-r--r--packages/web3-wrapper/tsconfig.json16
-rw-r--r--packages/web3-wrapper/tslint.json5
5 files changed, 249 insertions, 0 deletions
diff --git a/packages/web3-wrapper/README.md b/packages/web3-wrapper/README.md
new file mode 100644
index 000000000..0df8c6333
--- /dev/null
+++ b/packages/web3-wrapper/README.md
@@ -0,0 +1,10 @@
+Web3 wrapper
+------
+
+Wrapped version of web3 with nicer interface to be used across 0x projects and packages
+
+## Install
+
+```bash
+yarn add @0xproject/web3-wrapper
+```
diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json
new file mode 100644
index 000000000..dd1cd54fb
--- /dev/null
+++ b/packages/web3-wrapper/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@0xproject/web3-wrapper",
+ "version": "0.0.1",
+ "description": "Wraps around web3 and gives a nicer interface",
+ "main": "lib/index.js",
+ "types": "lib/index.d.ts",
+ "scripts": {
+ "build": "tsc",
+ "clean": "shx rm -rf lib",
+ "lint": "tslint --project . 'src/**/*.ts'"
+ },
+ "license": "Apache-2.0",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/0xProject/0x.js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/0xProject/0x.js/issues"
+ },
+ "homepage": "https://github.com/0xProject/0x.js/packages/web3-wrapper/README.md",
+ "devDependencies": {
+ "@0xproject/tslint-config": "^0.2.0",
+ "@types/lodash": "^4.14.86",
+ "npm-run-all": "^4.1.2",
+ "shx": "^0.2.2",
+ "tslint": "5.8.0",
+ "typescript": "~2.6.1",
+ "web3-typescript-typings": "^0.7.2"
+ },
+ "dependencies": {
+ "@0xproject/utils": "^0.0.1",
+ "@0xproject/types": "^0.0.1",
+ "bignumber.js": "~4.1.0",
+ "lodash": "^4.17.4",
+ "web3": "^0.20.0"
+ }
+}
diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts
new file mode 100644
index 000000000..9b37e5a0d
--- /dev/null
+++ b/packages/web3-wrapper/src/index.ts
@@ -0,0 +1,181 @@
+import {TransactionReceipt, TxData} from '@0xproject/types';
+import {promisify} from '@0xproject/utils';
+import BigNumber from 'bignumber.js';
+import * as _ from 'lodash';
+import * as Web3 from 'web3';
+
+interface RawLogEntry {
+ logIndex: string|null;
+ transactionIndex: string|null;
+ transactionHash: string;
+ blockHash: string|null;
+ blockNumber: string|null;
+ address: string;
+ data: string;
+ topics: string[];
+}
+
+export class Web3Wrapper {
+ private web3: Web3;
+ private networkId: number;
+ private defaults: Partial<TxData>;
+ private jsonRpcRequestId: number;
+ constructor(provider: Web3.Provider, networkId: number, defaults?: Partial<TxData>) {
+ 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.js
+ (provider as any).sendAsync = (provider as any).send;
+ }
+ this.web3 = new Web3();
+ this.networkId = networkId;
+ this.web3.setProvider(provider);
+ this.defaults = defaults || {};
+ this.jsonRpcRequestId = 0;
+ }
+ public getContractDefaults(): Partial<TxData> {
+ return this.defaults;
+ }
+ public setProvider(provider: Web3.Provider, networkId: number) {
+ this.networkId = networkId;
+ this.web3.setProvider(provider);
+ }
+ public isAddress(address: string): boolean {
+ return this.web3.isAddress(address);
+ }
+ public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
+ const addresses = await this.getAvailableAddressesAsync();
+ return _.includes(addresses, senderAddress);
+ }
+ public async getNodeVersionAsync(): Promise<string> {
+ const nodeVersion = await promisify<string>(this.web3.version.getNode)();
+ return nodeVersion;
+ }
+ public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
+ const transactionReceipt = await promisify<TransactionReceipt>(this.web3.eth.getTransactionReceipt)(txHash);
+ if (!_.isNull(transactionReceipt)) {
+ transactionReceipt.status = this.normalizeTxReceiptStatus(transactionReceipt.status);
+ }
+ return transactionReceipt;
+ }
+ public getCurrentProvider(): Web3.Provider {
+ return this.web3.currentProvider;
+ }
+ public getNetworkId(): number {
+ return this.networkId;
+ }
+ public toWei(ethAmount: BigNumber): BigNumber {
+ const balanceWei = this.web3.toWei(ethAmount, 'ether');
+ return balanceWei;
+ }
+ public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
+ let balanceInWei = await promisify<BigNumber>(this.web3.eth.getBalance)(owner);
+ // Rewrap in a new BigNumber
+ balanceInWei = new BigNumber(balanceInWei);
+ return balanceInWei;
+ }
+ public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
+ const balanceInWei = await this.getBalanceInWeiAsync(owner);
+ const balanceEthOldBigNumber = this.web3.fromWei(balanceInWei, 'ether');
+ const balanceEth = new BigNumber(balanceEthOldBigNumber);
+ return balanceEth;
+ }
+ public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
+ const code = await promisify<string>(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<string> {
+ const signData = await promisify<string>(this.web3.eth.sign)(address, message);
+ return signData;
+ }
+ public async getBlockNumberAsync(): Promise<number> {
+ const blockNumber = await promisify<number>(this.web3.eth.getBlockNumber)();
+ return blockNumber;
+ }
+ public async getBlockAsync(blockParam: string|Web3.BlockParam): Promise<Web3.BlockWithoutTransactionData> {
+ const block = await promisify<Web3.BlockWithoutTransactionData>(this.web3.eth.getBlock)(blockParam);
+ return block;
+ }
+ public async getBlockTimestampAsync(blockParam: string|Web3.BlockParam): Promise<number> {
+ const {timestamp} = await this.getBlockAsync(blockParam);
+ return timestamp;
+ }
+ public async getAvailableAddressesAsync(): Promise<string[]> {
+ const addresses = await promisify<string[]>(this.web3.eth.getAccounts)();
+ return addresses;
+ }
+ public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> {
+ let fromBlock = filter.fromBlock;
+ if (_.isNumber(fromBlock)) {
+ fromBlock = this.web3.toHex(fromBlock);
+ }
+ let toBlock = filter.toBlock;
+ if (_.isNumber(toBlock)) {
+ toBlock = this.web3.toHex(toBlock);
+ }
+ const serializedFilter = {
+ ...filter,
+ fromBlock,
+ toBlock,
+ };
+ const payload = {
+ jsonrpc: '2.0',
+ id: this.jsonRpcRequestId++,
+ method: 'eth_getLogs',
+ params: [serializedFilter],
+ };
+ const rawLogs = await this.sendRawPayloadAsync<RawLogEntry[]>(payload);
+ const formattedLogs = _.map(rawLogs, this.formatLog.bind(this));
+ return formattedLogs;
+ }
+ public getContractFromAbi(abi: Web3.ContractAbi): Web3.Contract<any> {
+ const web3Contract = this.web3.eth.contract(abi);
+ return web3Contract;
+ }
+ public getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance {
+ const web3ContractInstance = this.getContractFromAbi(abi).at(address);
+ return web3ContractInstance;
+ }
+ public async estimateGasAsync(data: string): Promise<number> {
+ const gas = await promisify<number>(this.web3.eth.estimateGas)({data});
+ return gas;
+ }
+ private async sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> {
+ const sendAsync = this.web3.currentProvider.sendAsync.bind(this.web3.currentProvider);
+ const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload);
+ 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): Web3.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;
+ }
+}
diff --git a/packages/web3-wrapper/tsconfig.json b/packages/web3-wrapper/tsconfig.json
new file mode 100644
index 000000000..de186cfc4
--- /dev/null
+++ b/packages/web3-wrapper/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "es5",
+ "lib": [ "es2017", "dom"],
+ "outDir": "lib",
+ "sourceMap": true,
+ "declaration": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true
+ },
+ "include": [
+ "./src/**/*",
+ "../../node_modules/web3-typescript-typings/index.d.ts"
+ ]
+}
diff --git a/packages/web3-wrapper/tslint.json b/packages/web3-wrapper/tslint.json
new file mode 100644
index 000000000..a07795151
--- /dev/null
+++ b/packages/web3-wrapper/tslint.json
@@ -0,0 +1,5 @@
+{
+ "extends": [
+ "@0xproject/tslint-config"
+ ]
+}