merge development

This commit is contained in:
Fabio Berger 2018-04-09 14:34:36 +09:00
commit e05b55d4a5
44 changed files with 1422 additions and 311 deletions

View File

@ -1,5 +1,9 @@
## 0x.js
A TypeScript/Javascript library for interacting with the 0x protocol.
### Read the [Documentation](0xproject.com/docs/0xjs).
## Installation
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
@ -38,10 +42,66 @@ Download the UMD module from our [releases page](https://github.com/0xProject/0x
<script type="text/javascript" src="0x.js"></script>
```
## Documentation
## Contributing
Extensive documentation of 0x.js can be found on [our website][docs-url].
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
[website-url]: https://0xproject.com/
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
[docs-url]: https://0xproject.com/docs/0xjs
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@ -57,3 +57,61 @@ See the [type definition](https://github.com/0xProject/0x-monorepo/tree/developm
## Output files
Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten.
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```

View File

@ -26,11 +26,11 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -46,10 +46,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -23,11 +23,11 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -43,10 +43,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -34,11 +34,25 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch

View File

@ -41,11 +41,11 @@ var Compiler = require('@0xproject/deployer').Compiler;
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -61,16 +61,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -26,3 +26,67 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
"typeRoots": ["node_modules/@0xproject/typescript-typings/types", "node_modules/@types"],
}
```
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@ -32,11 +32,11 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -52,16 +52,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -16,11 +16,11 @@ This will list out any dependencies that differ in versions between packages.
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -36,11 +36,25 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
@ -57,3 +71,9 @@ yarn clean
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@ -20,7 +20,19 @@ Then install dependencies
yarn install
```
#### Start the dev server
### Initial setup
The **first** time you work with this package, you must build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Note: If you move this package out of the monorepo, it will work without this step. Make sure you copy it out on the `master` branch since the `development` version might rely on not-yet published changes to other packages.
### Run dev server
The the `react-docs-example` root directory, run:
```bash
yarn dev
@ -42,6 +54,12 @@ yarn deploy_example
yarn build
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -51,11 +51,11 @@ Feel free to contribute to these improvements!
## Contributing
We strongly encourage the community to help us make improvements. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -71,10 +71,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -18,11 +18,11 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -38,18 +38,38 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@ -24,11 +24,11 @@ var CoverageSubprovider = require('@0xproject/sol-cov').CoverageSubprovider;
## Contributing
We strongly encourage the community to help us make improvements. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -42,8 +42,46 @@ Then install dependencies
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@ -87,11 +87,11 @@ In order to provide a custom environment to the tool, perform the following step
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -107,10 +107,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -6,6 +6,10 @@
"note":
"Refactor RedundantRPCSubprovider into RedundantSubprovider where it now accepts an array of subproviders rather then an array of RPC endpoints",
"pr": 500
},
{
"note": "Add private key subprovider and refactor shared functionality into a base wallet subprovider",
"pr": 506
}
]
},

View File

@ -22,11 +22,11 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -34,17 +34,33 @@ If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch

View File

@ -12,6 +12,7 @@ export { LedgerSubprovider } from './subproviders/ledger';
export { GanacheSubprovider } from './subproviders/ganache';
export { Subprovider } from './subproviders/subprovider';
export { NonceTrackerSubprovider } from './subproviders/nonce_tracker';
export { PrivateKeyWalletSubprovider } from './subproviders/private_key_wallet_subprovider';
export {
Callback,
ErrorCallback,

View File

@ -0,0 +1,137 @@
import { assert } from '@0xproject/assert';
import { JSONRPCRequestPayload, JSONRPCResponsePayload } from '@0xproject/types';
import { addressUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import { Callback, ErrorCallback, PartialTxParams, ResponseWithTxParams, WalletSubproviderErrors } from '../types';
import { Subprovider } from './subprovider';
export abstract class BaseWalletSubprovider extends Subprovider {
protected static _validateTxParams(txParams: PartialTxParams) {
assert.isETHAddressHex('to', txParams.to);
assert.isHexString('nonce', txParams.nonce);
assert.isHexString('gas', txParams.gas);
}
private static _validateSender(sender: string) {
if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) {
throw new Error(WalletSubproviderErrors.SenderInvalidOrNotSupplied);
}
}
public abstract async getAccountsAsync(): Promise<string[]>;
public abstract async signTransactionAsync(txParams: PartialTxParams): Promise<string>;
public abstract async signPersonalMessageAsync(data: string): Promise<string>;
/**
* This method conforms to the web3-provider-engine interface.
* It is called internally by the ProviderEngine when it is this subproviders
* turn to handle a JSON RPC request.
* @param payload JSON RPC payload
* @param next Callback to call if this subprovider decides not to handle the request
* @param end Callback to call if subprovider handled the request and wants to pass back the request.
*/
// tslint:disable-next-line:async-suffix
public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback) {
let accounts;
let txParams;
switch (payload.method) {
case 'eth_coinbase':
try {
accounts = await this.getAccountsAsync();
end(null, accounts[0]);
} catch (err) {
end(err);
}
return;
case 'eth_accounts':
try {
accounts = await this.getAccountsAsync();
end(null, accounts);
} catch (err) {
end(err);
}
return;
case 'eth_sendTransaction':
txParams = payload.params[0];
try {
BaseWalletSubprovider._validateSender(txParams.from);
const filledParams = await this._populateMissingTxParamsAsync(txParams);
const signedTx = await this.signTransactionAsync(filledParams);
const response = await this._emitSendTransactionAsync(signedTx);
end(null, response.result);
} catch (err) {
end(err);
}
return;
case 'eth_signTransaction':
txParams = payload.params[0];
try {
const filledParams = await this._populateMissingTxParamsAsync(txParams);
const signedTx = await this.signTransactionAsync(filledParams);
const result = {
raw: signedTx,
tx: txParams,
};
end(null, result);
} catch (err) {
end(err);
}
return;
case 'eth_sign':
case 'personal_sign':
const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0];
try {
const ecSignatureHex = await this.signPersonalMessageAsync(data);
end(null, ecSignatureHex);
} catch (err) {
end(err);
}
return;
default:
next();
return;
}
}
private async _emitSendTransactionAsync(signedTx: string): Promise<JSONRPCResponsePayload> {
const payload = {
method: 'eth_sendRawTransaction',
params: [signedTx],
};
const result = await this.emitPayloadAsync(payload);
return result;
}
private async _populateMissingTxParamsAsync(partialTxParams: PartialTxParams): Promise<PartialTxParams> {
let txParams = partialTxParams;
if (_.isUndefined(partialTxParams.gasPrice)) {
const gasPriceResult = await this.emitPayloadAsync({
method: 'eth_gasPrice',
params: [],
});
const gasPrice = gasPriceResult.result.toString();
txParams = { ...txParams, gasPrice };
}
if (_.isUndefined(partialTxParams.nonce)) {
const nonceResult = await this.emitPayloadAsync({
method: 'eth_getTransactionCount',
params: [partialTxParams.from, 'pending'],
});
const nonce = nonceResult.result;
txParams = { ...txParams, nonce };
}
if (_.isUndefined(partialTxParams.gas)) {
const gasResult = await this.emitPayloadAsync({
method: 'eth_estimateGas',
params: [partialTxParams],
});
const gas = gasResult.result.toString();
txParams = { ...txParams, gas };
}
return txParams;
}
}

View File

@ -15,9 +15,10 @@ import {
LedgerSubproviderErrors,
PartialTxParams,
ResponseWithTxParams,
WalletSubproviderErrors,
} from '../types';
import { Subprovider } from './subprovider';
import { BaseWalletSubprovider } from './base_wallet_subprovider';
const DEFAULT_DERIVATION_PATH = `44'/60'/0'`;
const DEFAULT_NUM_ADDRESSES_TO_FETCH = 10;
@ -29,7 +30,7 @@ const SHOULD_GET_CHAIN_CODE = true;
* This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and
* re-routes them to a Ledger device plugged into the users computer.
*/
export class LedgerSubprovider extends Subprovider {
export class LedgerSubprovider extends BaseWalletSubprovider {
private _nonceLock = new Lock();
private _connectionLock = new Lock();
private _networkId: number;
@ -38,11 +39,6 @@ export class LedgerSubprovider extends Subprovider {
private _ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync;
private _ledgerClientIfExists?: LedgerEthereumClient;
private _shouldAlwaysAskForConfirmation: boolean;
private static _validateSender(sender: string) {
if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) {
throw new Error(LedgerSubproviderErrors.SenderInvalidOrNotSupplied);
}
}
/**
* Instantiates a LedgerSubprovider. Defaults to derivationPath set to `44'/60'/0'`.
* TestRPC/Ganache defaults to `m/44'/60'/0'/0`, so set this in the configs if desired.
@ -133,6 +129,7 @@ export class LedgerSubprovider extends Subprovider {
* @return Signed transaction hex string
*/
public async signTransactionAsync(txParams: PartialTxParams): Promise<string> {
LedgerSubprovider._validateTxParams(txParams);
this._ledgerClientIfExists = await this._createLedgerClientAsync();
const tx = new EthereumTx(txParams);
@ -168,7 +165,7 @@ export class LedgerSubprovider extends Subprovider {
}
}
/**
* Sign a personal Ethereum signed message. The signing address will be to one
* Sign a personal Ethereum signed message. The signing address will be the one
* retrieved given a derivationPath and pathIndex set on the subprovider.
* The Ledger adds the Ethereum signed message prefix on-device. If you've added
* the LedgerSubprovider to your app's provider, you can simply send an `eth_sign`
@ -178,6 +175,10 @@ export class LedgerSubprovider extends Subprovider {
* @return Signature hex string (order: rsv)
*/
public async signPersonalMessageAsync(data: string): Promise<string> {
if (_.isUndefined(data)) {
throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage);
}
assert.isHexString('data', data);
this._ledgerClientIfExists = await this._createLedgerClientAsync();
try {
const derivationPath = this._getDerivationPath();
@ -198,82 +199,6 @@ export class LedgerSubprovider extends Subprovider {
throw err;
}
}
/**
* This method conforms to the web3-provider-engine interface.
* It is called internally by the ProviderEngine when it is this subproviders
* turn to handle a JSON RPC request.
* @param payload JSON RPC payload
* @param next Callback to call if this subprovider decides not to handle the request
* @param end Callback to call if subprovider handled the request and wants to pass back the request.
*/
// tslint:disable-next-line:async-suffix
public async handleRequest(
payload: JSONRPCRequestPayload,
next: Callback,
end: (err: Error | null, result?: any) => void,
) {
let accounts;
let txParams;
switch (payload.method) {
case 'eth_coinbase':
try {
accounts = await this.getAccountsAsync();
end(null, accounts[0]);
} catch (err) {
end(err);
}
return;
case 'eth_accounts':
try {
accounts = await this.getAccountsAsync();
end(null, accounts);
} catch (err) {
end(err);
}
return;
case 'eth_sendTransaction':
txParams = payload.params[0];
try {
LedgerSubprovider._validateSender(txParams.from);
const result = await this._sendTransactionAsync(txParams);
end(null, result);
} catch (err) {
end(err);
}
return;
case 'eth_signTransaction':
txParams = payload.params[0];
try {
const result = await this._signTransactionWithoutSendingAsync(txParams);
end(null, result);
} catch (err) {
end(err);
}
return;
case 'eth_sign':
case 'personal_sign':
const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0];
try {
if (_.isUndefined(data)) {
throw new Error(LedgerSubproviderErrors.DataMissingForSignPersonalMessage);
}
assert.isHexString('data', data);
const ecSignatureHex = await this.signPersonalMessageAsync(data);
end(null, ecSignatureHex);
} catch (err) {
end(err);
}
return;
default:
next();
return;
}
}
private _getDerivationPath() {
const derivationPath = `${this.getPath()}/${this._derivationPathIndex}`;
return derivationPath;
@ -298,70 +223,4 @@ export class LedgerSubprovider extends Subprovider {
this._ledgerClientIfExists = undefined;
this._connectionLock.release();
}
private async _sendTransactionAsync(txParams: PartialTxParams): Promise<string> {
await this._nonceLock.acquire();
try {
// fill in the extras
const filledParams = await this._populateMissingTxParamsAsync(txParams);
// sign it
const signedTx = await this.signTransactionAsync(filledParams);
// emit a submit
const payload = {
method: 'eth_sendRawTransaction',
params: [signedTx],
};
const result = await this.emitPayloadAsync(payload);
this._nonceLock.release();
return result.result;
} catch (err) {
this._nonceLock.release();
throw err;
}
}
private async _signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> {
await this._nonceLock.acquire();
try {
// fill in the extras
const filledParams = await this._populateMissingTxParamsAsync(txParams);
// sign it
const signedTx = await this.signTransactionAsync(filledParams);
this._nonceLock.release();
const result = {
raw: signedTx,
tx: txParams,
};
return result;
} catch (err) {
this._nonceLock.release();
throw err;
}
}
private async _populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> {
if (_.isUndefined(txParams.gasPrice)) {
const gasPriceResult = await this.emitPayloadAsync({
method: 'eth_gasPrice',
params: [],
});
const gasPrice = gasPriceResult.result.toString();
txParams.gasPrice = gasPrice;
}
if (_.isUndefined(txParams.nonce)) {
const nonceResult = await this.emitPayloadAsync({
method: 'eth_getTransactionCount',
params: [txParams.from, 'pending'],
});
const nonce = nonceResult.result;
txParams.nonce = nonce;
}
if (_.isUndefined(txParams.gas)) {
const gasResult = await this.emitPayloadAsync({
method: 'eth_estimateGas',
params: [txParams],
});
const gas = gasResult.result.toString();
txParams.gas = gas;
}
return txParams;
}
}

View File

@ -0,0 +1,70 @@
import { assert } from '@0xproject/assert';
import { JSONRPCRequestPayload } from '@0xproject/types';
import EthereumTx = require('ethereumjs-tx');
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { Callback, ErrorCallback, PartialTxParams, ResponseWithTxParams, WalletSubproviderErrors } from '../types';
import { BaseWalletSubprovider } from './base_wallet_subprovider';
import { Subprovider } from './subprovider';
/**
* This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface.
* This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles
* all requests with the supplied Ethereum private key.
*/
export class PrivateKeyWalletSubprovider extends BaseWalletSubprovider {
private _address: string;
private _privateKeyBuffer: Buffer;
constructor(privateKey: string) {
assert.isString('privateKey', privateKey);
super();
this._privateKeyBuffer = new Buffer(privateKey, 'hex');
this._address = `0x${ethUtil.privateToAddress(this._privateKeyBuffer).toString('hex')}`;
}
/**
* Retrieve the account associated with the supplied private key.
* This method is implicitly called when issuing a `eth_accounts` JSON RPC request
* via your providerEngine instance.
* @return An array of accounts
*/
public async getAccountsAsync(): Promise<string[]> {
return [this._address];
}
/**
* Sign a transaction with the private key. If you've added this Subprovider to your
* app's provider, you can simply send an `eth_sendTransaction` JSON RPC request, and
* this method will be called auto-magically. If you are not using this via a ProviderEngine
* instance, you can call it directly.
* @param txParams Parameters of the transaction to sign
* @return Signed transaction hex string
*/
public async signTransactionAsync(txParams: PartialTxParams): Promise<string> {
PrivateKeyWalletSubprovider._validateTxParams(txParams);
const tx = new EthereumTx(txParams);
tx.sign(this._privateKeyBuffer);
const rawTx = `0x${tx.serialize().toString('hex')}`;
return rawTx;
}
/**
* Sign a personal Ethereum signed message. The signing address will be
* calculated from the private key.
* If you've added the PKWalletSubprovider to your app's provider, you can simply send an `eth_sign`
* or `personal_sign` JSON RPC request, and this method will be called auto-magically.
* If you are not using this via a ProviderEngine instance, you can call it directly.
* @param data Message to sign
* @return Signature hex string (order: rsv)
*/
public async signPersonalMessageAsync(dataIfExists: string): Promise<string> {
if (_.isUndefined(dataIfExists)) {
throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage);
}
assert.isHexString('data', dataIfExists);
const dataBuff = ethUtil.toBuffer(dataIfExists);
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
const sig = ethUtil.ecsign(msgHashBuff, this._privateKeyBuffer);
const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s);
return rpcSig;
}
}

View File

@ -95,11 +95,13 @@ export interface ResponseWithTxParams {
tx: PartialTxParams;
}
export enum WalletSubproviderErrors {
DataMissingForSignPersonalMessage = 'DATA_MISSING_FOR_SIGN_PERSONAL_MESSAGE',
SenderInvalidOrNotSupplied = 'SENDER_INVALID_OR_NOT_SUPPLIED',
}
export enum LedgerSubproviderErrors {
TooOldLedgerFirmware = 'TOO_OLD_LEDGER_FIRMWARE',
FromAddressMissingOrInvalid = 'FROM_ADDRESS_MISSING_OR_INVALID',
DataMissingForSignPersonalMessage = 'DATA_MISSING_FOR_SIGN_PERSONAL_MESSAGE',
SenderInvalidOrNotSupplied = 'SENDER_INVALID_OR_NOT_SUPPLIED',
MultipleOpenConnectionsDisallowed = 'MULTIPLE_OPEN_CONNECTIONS_DISALLOWED',
}

View File

@ -14,6 +14,7 @@ import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import { LedgerSubprovider } from '../../src';
import { DoneCallback, LedgerEthereumClient } from '../../src/types';
import { chaiSetup } from '../chai_setup';
import { fixtureData } from '../utils/fixture_data';
import { reportCallbackErrors } from '../utils/report_callback_errors';
chaiSetup.configure();
@ -25,17 +26,14 @@ async function ledgerEthereumNodeJsClientFactoryAsync(): Promise<LedgerEthereumC
return ledgerEthClient;
}
const TESTRPC_DERIVATION_PATH = `m/44'/60'/0'/0`;
const TEST_RPC_ACCOUNT_0 = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
describe('LedgerSubprovider', () => {
let ledgerSubprovider: LedgerSubprovider;
const networkId: number = 42;
const networkId: number = fixtureData.NETWORK_ID;
before(async () => {
ledgerSubprovider = new LedgerSubprovider({
networkId,
ledgerEthereumClientFactoryAsync: ledgerEthereumNodeJsClientFactoryAsync,
derivationPath: TESTRPC_DERIVATION_PATH,
derivationPath: fixtureData.TESTRPC_DERIVATION_PATH,
});
});
describe('direct method calls', () => {
@ -46,7 +44,7 @@ describe('LedgerSubprovider', () => {
});
it('returns the expected first account from a ledger set up with the test mnemonic', async () => {
const accounts = await ledgerSubprovider.getAccountsAsync();
expect(accounts[0]).to.be.equal(TEST_RPC_ACCOUNT_0);
expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
});
it('returns requested number of accounts', async () => {
const numberOfAccounts = 20;
@ -55,24 +53,14 @@ describe('LedgerSubprovider', () => {
expect(accounts.length).to.be.equal(numberOfAccounts);
});
it('signs a personal message', async () => {
const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(data);
expect(ecSignatureHex.length).to.be.equal(132);
expect(ecSignatureHex.substr(0, 2)).to.be.equal('0x');
expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT);
});
it('signs a transaction', async () => {
const tx = {
nonce: '0x00',
gas: '0x2710',
to: '0x0000000000000000000000000000000000000000',
value: '0x00',
chainId: 3,
from: TEST_RPC_ACCOUNT_0,
};
const txHex = await ledgerSubprovider.signTransactionAsync(tx);
expect(txHex).to.be.equal(
'0xf85f8080822710940000000000000000000000000000000000000000808078a0712854c73c69445cc1b22a7c3d7312ff9a97fe4ffba35fd636e8236b211b6e7ca0647cee031615e52d916c7c707025bc64ad525d8f1b9876c3435a863b42743178',
);
const txHex = await ledgerSubprovider.signTransactionAsync(fixtureData.TX_DATA);
expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT);
});
});
describe('calls through a provider', () => {
@ -146,20 +134,15 @@ describe('LedgerSubprovider', () => {
})().catch(done);
});
it('signs a transaction', (done: DoneCallback) => {
const tx = {
to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66',
value: '0x00',
};
const payload = {
jsonrpc: '2.0',
method: 'eth_signTransaction',
params: [tx],
params: [fixtureData.TX_DATA],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result.raw.length).to.be.equal(206);
expect(response.result.raw.substr(0, 2)).to.be.equal('0x');
expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT);
done();
});
ledgerProvider.sendAsync(payload, callback);
@ -171,7 +154,7 @@ describe('LedgerSubprovider', () => {
// Give first account on Ledger sufficient ETH to complete tx send
let tx = {
to: accounts[0],
from: TEST_RPC_ACCOUNT_0,
from: fixtureData.TEST_RPC_ACCOUNT_0,
value: '0x8ac7230489e80000', // 10 ETH
};
let payload = {

View File

@ -6,8 +6,14 @@ import Web3 = require('web3');
import Web3ProviderEngine = require('web3-provider-engine');
import { LedgerSubprovider } from '../../src';
import { DoneCallback, LedgerCommunicationClient, LedgerSubproviderErrors } from '../../src/types';
import {
DoneCallback,
LedgerCommunicationClient,
LedgerSubproviderErrors,
WalletSubproviderErrors,
} from '../../src/types';
import { chaiSetup } from '../chai_setup';
import { fixtureData } from '../utils/fixture_data';
import { ganacheSubprovider } from '../utils/ganache_subprovider';
import { reportCallbackErrors } from '../utils/report_callback_errors';
@ -75,7 +81,7 @@ describe('LedgerSubprovider', () => {
expect(accounts.length).to.be.equal(numberOfAccounts);
});
it('signs a personal message', async () => {
const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(data);
expect(ecSignatureHex).to.be.equal(
'0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001',
@ -136,7 +142,7 @@ describe('LedgerSubprovider', () => {
provider.sendAsync(payload, callback);
});
it('signs a personal message with personal_sign', (done: DoneCallback) => {
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const payload = {
jsonrpc: '2.0',
method: 'personal_sign',
@ -219,7 +225,7 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.not.be.a('null');
expect(err.message).to.be.equal(LedgerSubproviderErrors.SenderInvalidOrNotSupplied);
expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied);
done();
});
provider.sendAsync(payload, callback);
@ -238,7 +244,7 @@ describe('LedgerSubprovider', () => {
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.not.be.a('null');
expect(err.message).to.be.equal(LedgerSubproviderErrors.SenderInvalidOrNotSupplied);
expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied);
done();
});
provider.sendAsync(payload, callback);

View File

@ -0,0 +1,170 @@
import { JSONRPCResponsePayload } from '@0xproject/types';
import * as chai from 'chai';
import * as ethUtils from 'ethereumjs-util';
import * as _ from 'lodash';
import Web3ProviderEngine = require('web3-provider-engine');
import { GanacheSubprovider, PrivateKeyWalletSubprovider } from '../../src/';
import {
DoneCallback,
LedgerCommunicationClient,
LedgerSubproviderErrors,
WalletSubproviderErrors,
} from '../../src/types';
import { chaiSetup } from '../chai_setup';
import { fixtureData } from '../utils/fixture_data';
import { reportCallbackErrors } from '../utils/report_callback_errors';
chaiSetup.configure();
const expect = chai.expect;
describe('PrivateKeyWalletSubprovider', () => {
let subprovider: PrivateKeyWalletSubprovider;
before(async () => {
subprovider = new PrivateKeyWalletSubprovider(fixtureData.TEST_RPC_ACCOUNT_0_ACCOUNT_PRIVATE_KEY);
});
describe('direct method calls', () => {
describe('success cases', () => {
it('returns the account', async () => {
const accounts = await subprovider.getAccountsAsync();
expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
expect(accounts.length).to.be.equal(1);
});
it('signs a personal message', async () => {
const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const ecSignatureHex = await subprovider.signPersonalMessageAsync(data);
expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT);
});
it('signs a transaction', async () => {
const txHex = await subprovider.signTransactionAsync(fixtureData.TX_DATA);
expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT);
});
});
});
describe('calls through a provider', () => {
let provider: Web3ProviderEngine;
before(() => {
provider = new Web3ProviderEngine();
provider.addProvider(subprovider);
const ganacheSubprovider = new GanacheSubprovider({});
provider.addProvider(ganacheSubprovider);
provider.start();
});
describe('success cases', () => {
it('returns a list of accounts', (done: DoneCallback) => {
const payload = {
jsonrpc: '2.0',
method: 'eth_accounts',
params: [],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0);
expect(response.result.length).to.be.equal(1);
done();
});
provider.sendAsync(payload, callback);
});
it('signs a personal message with eth_sign', (done: DoneCallback) => {
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const payload = {
jsonrpc: '2.0',
method: 'eth_sign',
params: ['0x0000000000000000000000000000000000000000', messageHex],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT);
done();
});
provider.sendAsync(payload, callback);
});
it('signs a personal message with personal_sign', (done: DoneCallback) => {
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING));
const payload = {
jsonrpc: '2.0',
method: 'personal_sign',
params: [messageHex, '0x0000000000000000000000000000000000000000'],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.be.a('null');
expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT);
done();
});
provider.sendAsync(payload, callback);
});
});
describe('failure cases', () => {
it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => {
const nonHexMessage = 'hello world';
const payload = {
jsonrpc: '2.0',
method: 'eth_sign',
params: ['0x0000000000000000000000000000000000000000', nonHexMessage],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.not.be.a('null');
expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world');
done();
});
provider.sendAsync(payload, callback);
});
it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => {
const nonHexMessage = 'hello world';
const payload = {
jsonrpc: '2.0',
method: 'personal_sign',
params: [nonHexMessage, '0x0000000000000000000000000000000000000000'],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.not.be.a('null');
expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world');
done();
});
provider.sendAsync(payload, callback);
});
it('should throw if `from` param missing when calling eth_sendTransaction', (done: DoneCallback) => {
const tx = {
to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66',
value: '0xde0b6b3a7640000',
};
const payload = {
jsonrpc: '2.0',
method: 'eth_sendTransaction',
params: [tx],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.not.be.a('null');
expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied);
done();
});
provider.sendAsync(payload, callback);
});
it('should throw if `from` param invalid address when calling eth_sendTransaction', (done: DoneCallback) => {
const tx = {
to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66',
from: '0xIncorrectEthereumAddress',
value: '0xde0b6b3a7640000',
};
const payload = {
jsonrpc: '2.0',
method: 'eth_sendTransaction',
params: [tx],
id: 1,
};
const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => {
expect(err).to.not.be.a('null');
expect(err.message).to.be.equal(WalletSubproviderErrors.SenderInvalidOrNotSupplied);
done();
});
provider.sendAsync(payload, callback);
});
});
});
});

View File

@ -0,0 +1,23 @@
const TEST_RPC_ACCOUNT_0 = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
const networkId = 42;
export const fixtureData = {
TEST_RPC_ACCOUNT_0,
TEST_RPC_ACCOUNT_0_ACCOUNT_PRIVATE_KEY: 'F2F48EE19680706196E2E339E5DA3491186E0C4C5030670656B0E0164837257D',
PERSONAL_MESSAGE_STRING: 'hello world',
PERSONAL_MESSAGE_SIGNED_RESULT:
'0x1b0ec5e2908e993d0c8ab6b46da46be2688fdf03c7ea6686075de37392e50a7d7fcc531446699132fbda915bd989882e0064d417018773a315fb8d43ed063c9b00',
TESTRPC_DERIVATION_PATH: `m/44'/60'/0'/0`,
NETWORK_ID: networkId,
TX_DATA: {
nonce: '0x00',
gasPrice: '0x0',
gas: '0x2710',
to: '0x0000000000000000000000000000000000000000',
value: '0x00',
chainId: networkId,
from: TEST_RPC_ACCOUNT_0,
},
// This is the signed result of the abouve Transaction Data
TX_DATA_SIGNED_RESULT:
'0xf85f8080822710940000000000000000000000000000000000000000808078a0712854c73c69445cc1b22a7c3d7312ff9a97fe4ffba35fd636e8236b211b6e7ca0647cee031615e52d916c7c707025bc64ad525d8f1b9876c3435a863b42743178',
};

View File

@ -4,15 +4,15 @@ This faucet dispenses 0.1 test ether to one recipient per second and 0.1 test ZR
## Installation
This is a private package and therefore is not published to npm. In order to build and run this package locally, see the [Install Dependencies](#Install-Dependencies) section and onwards below.
This is a private package and therefore is not published to npm. In order to build and run this package locally, see the contributing instructions below.
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -26,6 +26,44 @@ Then install dependencies
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Start
Set the following environment variables:
@ -125,9 +163,3 @@ docker run -d \
-e INFURA_API_KEY=$INFURA_API_KEY \
testnet-faucets
```
### Lint
```bash
yarn lint
```

View File

@ -9,15 +9,13 @@ import * as Web3 from 'web3';
// we are not running in a browser env.
// Filed issue: https://github.com/ethereum/web3.js/issues/844
(global as any).XMLHttpRequest = undefined;
import { NonceTrackerSubprovider } from '@0xproject/subproviders';
import { NonceTrackerSubprovider, PrivateKeyWalletSubprovider } from '@0xproject/subproviders';
import ProviderEngine = require('web3-provider-engine');
import HookedWalletSubprovider = require('web3-provider-engine/subproviders/hooked-wallet');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import { configs } from './configs';
import { DispatchQueue } from './dispatch_queue';
import { dispenseAssetTasks } from './dispense_asset_tasks';
import { idManagement } from './id_management';
import { rpcUrls } from './rpc_urls';
interface NetworkConfig {
@ -41,9 +39,12 @@ const FIVE_DAYS_IN_MS = 4.32e8; // TODO: make this configurable
export class Handler {
private _networkConfigByNetworkId: ItemByNetworkId<NetworkConfig> = {};
private static _createProviderEngine(rpcUrl: string) {
if (_.isUndefined(configs.DISPENSER_PRIVATE_KEY)) {
throw new Error('Dispenser Private key not found');
}
const engine = new ProviderEngine();
engine.addProvider(new NonceTrackerSubprovider());
engine.addProvider(new HookedWalletSubprovider(idManagement));
engine.addProvider(new PrivateKeyWalletSubprovider(configs.DISPENSER_PRIVATE_KEY));
engine.addProvider(
new RpcSubprovider({
rpcUrl,

View File

@ -1,35 +0,0 @@
import EthereumTx = require('ethereumjs-tx');
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { configs } from './configs';
type Callback = (err: Error | null, result: any) => void;
export const idManagement = {
getAccounts(callback: Callback) {
callback(null, [configs.DISPENSER_ADDRESS]);
},
approveTransaction(txData: object, callback: Callback) {
callback(null, true);
},
signTransaction(txData: object, callback: Callback) {
const tx = new EthereumTx(txData);
const privateKeyBuffer = new Buffer(configs.DISPENSER_PRIVATE_KEY as string, 'hex');
tx.sign(privateKeyBuffer);
const rawTx = `0x${tx.serialize().toString('hex')}`;
callback(null, rawTx);
},
signMessage(message: object, callback: Callback) {
const dataIfExists = _.get(message, 'data');
if (_.isUndefined(dataIfExists)) {
callback(new Error('NO_DATA_TO_SIGN'), null);
}
const privateKeyBuffer = new Buffer(configs.DISPENSER_PRIVATE_KEY as string, 'hex');
const dataBuff = ethUtil.toBuffer(dataIfExists);
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
const sig = ethUtil.ecsign(msgHashBuff, privateKeyBuffer);
const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s);
callback(null, rpcSig);
},
};

View File

@ -20,11 +20,11 @@ Add the following to your `tslint.json` file
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -40,16 +40,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -24,13 +24,13 @@ import { TransactionReceipt, TxData, TxDataPayable } from '@0xproject/types';
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces e`nabled (Yarn < v1.0) - enable them:
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
@ -44,16 +44,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -20,11 +20,11 @@ This will allow the TS compiler to first look into that repo and then fallback t
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -38,6 +38,38 @@ Then install dependencies
yarn install
```
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -24,11 +24,11 @@ import { addressUtils, bigNumberConfigs, classUtils, intervalUtils, promisify }
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -44,16 +44,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -20,11 +20,11 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
@ -40,16 +40,36 @@ yarn install
### Build
If this is your **first** time building this package, you must first build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn lerna:rebuild
```
Or continuously rebuild on change:
```bash
yarn dev
```
You can also build this specific package by running the following from within its directory:
```bash
yarn build
```
or
or continuously rebuild on change:
```bash
yarn build:watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash

View File

@ -28,20 +28,24 @@ Add the following to your `/etc/hosts` file:
yarn install
```
### Run dev server
### Initial setup
The **first** time you work with this package, you must build **all** packages within the monorepo. This is because packages that depend on other packages located inside this monorepo are symlinked when run from **within** the monorepo. This allows you to make changes across multiple packages without first publishing dependent packages to NPM. To build all packages, run the following from the monorepo root directory:
```bash
yarn run dev
yarn lerna:rebuild
```
### Run dev server
The the `website` root directory, run:
```bash
yarn dev
```
Visit [0xproject.localhost:3572](http://0xproject.localhost:3572) in your browser.
### Build
```bash
yarn build
```
### Clean
```bash

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -15,6 +15,7 @@ import { EthWrappers } from 'ts/components/eth_wrappers';
import { FillOrder } from 'ts/components/fill_order';
import { Footer } from 'ts/components/footer';
import { PortalMenu } from 'ts/components/portal_menu';
import { RelayerIndex } from 'ts/components/relayer_index/relayer_index';
import { TokenBalances } from 'ts/components/token_balances';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { TradeHistory } from 'ts/components/trade_history/trade_history';
@ -155,6 +156,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
this.props.dispatcher,
);
const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT;
const portalStyle: React.CSSProperties = {
minHeight: '100vh',
display: 'flex',
@ -204,12 +206,18 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
<div className="py2" style={{ backgroundColor: colors.grey50 }}>
{this.props.blockchainIsLoaded ? (
<Switch>
{configs.ENVIRONMENT === Environments.DEVELOPMENT && (
{isDevelopment && (
<Route
path={`${WebsitePaths.Portal}/wallet`}
render={this._renderWallet.bind(this)}
/>
)}
{isDevelopment && (
<Route
path={`${WebsitePaths.Portal}/relayers`}
render={this._renderRelayers.bind(this)}
/>
)}
<Route
path={`${WebsitePaths.Portal}/weth`}
render={this._renderEthWrapper.bind(this)}
@ -313,6 +321,15 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
</div>
);
}
private _renderRelayers() {
return (
<div className="flex flex-center">
<div className="mx-auto" style={{ width: 800 }}>
<RelayerIndex networkId={this.props.networkId} />
</div>
</div>
);
}
private _renderEthWrapper() {
return (
<EthWrappers

View File

@ -59,14 +59,24 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
</MenuItem>
{configs.ENVIRONMENT === Environments.DEVELOPMENT && (
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/wallet`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')}
</MenuItem>
<div>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/wallet`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')}
</MenuItem>
<MenuItem
style={this.props.menuItemStyle}
className="py2"
to={`${WebsitePaths.Portal}/relayers`}
onClick={this.props.onClick.bind(this)}
>
{this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')}
</MenuItem>
</div>
)}
</div>
);

View File

@ -0,0 +1,84 @@
import { colors, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import { GridTile } from 'material-ui/GridList';
import * as React from 'react';
import { TopTokens } from 'ts/components/relayer_index/relayer_top_tokens';
import { TokenIcon } from 'ts/components/ui/token_icon';
import { RelayerInfo, Token } from 'ts/types';
export interface RelayerGridTileProps {
relayerInfo: RelayerInfo;
networkId: number;
}
const styles: Styles = {
root: {
backgroundColor: colors.white,
borderBottomRightRadius: 10,
borderBottomLeftRadius: 10,
borderTopRightRadius: 10,
borderTopLeftRadius: 10,
boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`,
overflow: 'hidden',
boxSizing: 'border-box',
},
innerDiv: {
padding: 6,
height: '100%',
boxSizing: 'border-box',
},
header: {
height: '50%',
width: '100%',
objectFit: 'cover',
borderBottomRightRadius: 4,
borderBottomLeftRadius: 4,
borderTopRightRadius: 4,
borderTopLeftRadius: 4,
},
body: {
paddingLeft: 6,
paddingRight: 6,
height: '50%',
width: '100%',
boxSizing: 'border-box',
},
marketShareBar: {
height: 14,
width: '100%',
backgroundColor: colors.mediumBlue,
},
subLabel: {
fontSize: 12,
color: colors.lightGrey,
},
relayerNameLabel: {
fontSize: 16,
fontWeight: 'bold',
color: colors.black,
},
};
export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => {
return (
<GridTile style={styles.root}>
<div style={styles.innerDiv}>
<img src={props.relayerInfo.headerUrl} style={styles.header} />
<div style={styles.body}>
<div className="py1" style={styles.relayerNameLabel}>
{props.relayerInfo.name}
</div>
<div style={styles.marketShareBar} />
<div className="py1" style={styles.subLabel}>
Market share
</div>
<TopTokens tokens={props.relayerInfo.topTokens} networkId={props.networkId} />
<div className="py1" style={styles.subLabel}>
Top tokens
</div>
</div>
</div>
</GridTile>
);
};

View File

@ -0,0 +1,118 @@
import { colors, Styles } from '@0xproject/react-shared';
import { GridList } from 'material-ui/GridList';
import * as React from 'react';
import { RelayerGridTile } from 'ts/components/relayer_index/relayer_grid_tile';
import { RelayerInfo } from 'ts/types';
export interface RelayerIndexProps {
networkId: number;
}
const styles: Styles = {
root: {
width: '100%',
},
item: {
backgroundColor: colors.white,
borderBottomRightRadius: 10,
borderBottomLeftRadius: 10,
borderTopRightRadius: 10,
borderTopLeftRadius: 10,
boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`,
overflow: 'hidden',
padding: 4,
},
};
// TODO: replace fake data with real, remote data
const topTokens = [
{
address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba',
decimals: 18,
iconUrl: '/images/token_icons/makerdao.png',
isRegistered: true,
isTracked: true,
name: 'Maker DAO',
symbol: 'MKR',
},
{
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
decimals: 18,
iconUrl: '/images/token_icons/melon.png',
isRegistered: true,
isTracked: true,
name: 'Melon Token',
symbol: 'MLN',
},
{
address: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
decimals: 18,
iconUrl: '/images/token_icons/augur.png',
isRegistered: true,
isTracked: true,
name: 'Augur Reputation Token',
symbol: 'REP',
},
];
const relayerInfos: RelayerInfo[] = [
{
id: '1',
headerUrl: '/images/og_image.png',
name: 'Radar Relay',
marketShare: 0.5,
topTokens,
},
{
id: '2',
headerUrl: '/images/og_image.png',
name: 'Paradex',
marketShare: 0.5,
topTokens,
},
{
id: '3',
headerUrl: '/images/og_image.png',
name: 'yo',
marketShare: 0.5,
topTokens,
},
{
id: '4',
headerUrl: '/images/og_image.png',
name: 'test',
marketShare: 0.5,
topTokens,
},
{
id: '5',
headerUrl: '/images/og_image.png',
name: 'blahg',
marketShare: 0.5,
topTokens,
},
{
id: '6',
headerUrl: '/images/og_image.png',
name: 'hello',
marketShare: 0.5,
topTokens,
},
];
const CELL_HEIGHT = 260;
const NUMBER_OF_COLUMNS = 4;
const GRID_PADDING = 16;
export const RelayerIndex: React.StatelessComponent<RelayerIndexProps> = (props: RelayerIndexProps) => {
return (
<div style={styles.root}>
<GridList cellHeight={CELL_HEIGHT} cols={NUMBER_OF_COLUMNS} padding={GRID_PADDING} style={styles.gridList}>
{relayerInfos.map((relayerInfo: RelayerInfo) => (
<RelayerGridTile key={relayerInfo.id} relayerInfo={relayerInfo} networkId={props.networkId} />
))}
</GridList>
</div>
);
};

View File

@ -0,0 +1,46 @@
import { colors, EtherscanLinkSuffixes, Styles, utils as sharedUtils } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { TokenIcon } from 'ts/components/ui/token_icon';
import { Token } from 'ts/types';
export interface TopTokensProps {
tokens: Token[];
networkId: number;
}
const styles: Styles = {
tokenLabel: {
textDecoration: 'none',
color: colors.mediumBlue,
},
followingTokenLabel: {
paddingLeft: 16,
},
};
export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => {
return (
<div className="flex">
{_.map(props.tokens, (token: Token, index: number) => {
const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel };
const style = index !== 0 ? firstItemStyle : styles.tokenLabel;
return (
<a
key={token.address}
href={tokenLinkFromToken(token, props.networkId)}
target="_blank"
style={style}
>
{token.symbol}
</a>
);
})}
</div>
);
};
function tokenLinkFromToken(token: Token, networkId: number) {
return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address);
}

View File

@ -71,7 +71,7 @@ interface AccessoryItemConfig {
}
const styles: Styles = {
wallet: {
root: {
width: 346,
backgroundColor: colors.white,
borderBottomRightRadius: 10,
@ -121,6 +121,10 @@ const ZRX_TOKEN_SYMBOL = 'ZRX';
const ETHER_SYMBOL = 'ETH';
const ICON_DIMENSION = 24;
const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
const HEADER_ITEM_KEY = 'HEADER';
const FOOTER_ITEM_KEY = 'FOOTER';
const DISCONNECTED_ITEM_KEY = 'DISCONNECTED';
const ETHER_ITEM_KEY = 'ETHER';
export class Wallet extends React.Component<WalletProps, WalletState> {
private _isUnmounted: boolean;
@ -174,7 +178,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
}
public render() {
const isReadyToRender = this.props.blockchainIsLoaded && this.props.blockchainErr === BlockchainErrs.NoError;
return <div style={styles.wallet}>{isReadyToRender && this._renderRows()}</div>;
return <div style={styles.root}>{isReadyToRender && this._renderRows()}</div>;
}
private _renderRows() {
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
@ -196,6 +200,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
const primaryText = 'wallet';
return (
<ListItem
key={HEADER_ITEM_KEY}
primaryText={primaryText.toUpperCase()}
leftIcon={<ActionAccountBalanceWallet color={colors.mediumBlue} />}
style={styles.paddedItem}
@ -206,6 +211,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
private _renderDisconnectedRows() {
return (
<WalletDisconnectedItem
key={DISCONNECTED_ITEM_KEY}
providerType={this.props.providerType}
injectedProviderName={this.props.injectedProviderName}
onToggleLedgerDialog={this.props.onToggleLedgerDialog}
@ -217,6 +223,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
const primaryText = utils.getAddressBeginAndEnd(userAddress);
return (
<ListItem
key={HEADER_ITEM_KEY}
primaryText={primaryText}
leftIcon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
style={{ ...styles.paddedItem, ...styles.borderedItem }}
@ -226,7 +233,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
}
private _renderFooterRows() {
const primaryText = '+ other tokens';
return <ListItem primaryText={primaryText} innerDivStyle={styles.footerItemInnerDiv} />;
return <ListItem key={FOOTER_ITEM_KEY} primaryText={primaryText} innerDivStyle={styles.footerItemInnerDiv} />;
}
private _renderEthRows() {
const primaryText = this._renderAmount(
@ -245,7 +252,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
const etherToken = this._getEthToken();
return (
<div>
<div key={ETHER_ITEM_KEY}>
<ListItem
primaryText={primaryText}
leftIcon={<img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />}
@ -304,7 +311,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
const etherToken = this._getEthToken();
return (
<div>
<div key={token.address}>
<ListItem
primaryText={amount}
leftIcon={this._renderTokenIcon(token, tokenLink)}

View File

@ -111,7 +111,7 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
disableTouchRipple={true}
style={walletItemStyles.focusedItem}
innerDivStyle={styles.innerDiv}
leftIcon={this.state.isEthConversionHappening && this._renderIsEthConversionHappeningSpinner()}
leftIcon={this._renderIsEthConversionHappeningSpinner()}
rightAvatar={this._renderWrapEtherConfirmationButton()}
/>
);
@ -123,11 +123,11 @@ export class WrapEtherItem extends React.Component<WrapEtherItemProps, WrapEther
});
}
private _renderIsEthConversionHappeningSpinner() {
return (
return this.state.isEthConversionHappening ? (
<div className="pl1" style={{ paddingTop: 10 }}>
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
</div>
);
) : null;
}
private _renderWrapEtherConfirmationButton() {
const isWrappingEth = this.props.direction === Side.Deposit;

View File

@ -39,7 +39,7 @@ const docsInfoConfig: DocsInfoConfig = {
[docSections.installation]: InstallationMarkdown,
},
sectionNameToModulePath: {
[docSections.web3Wrapper]: ['"web3-wrapper/src/index"'],
[docSections.web3Wrapper]: ['"web3-wrapper/src/web3_wrapper"'],
[docSections.types]: ['"types/src/index"'],
},
menuSubsectionToVersionWhenIntroduced: {},

View File

@ -490,4 +490,12 @@ export interface TokenState {
allowance: BigNumber;
isLoaded: boolean;
}
export interface RelayerInfo {
headerUrl: string;
id: string;
name: string;
marketShare: number;
topTokens: Token[];
}
// tslint:disable:max-file-line-count