Compare commits
34 Commits
@0xproject
...
@0xproject
Author | SHA1 | Date | |
---|---|---|---|
|
f684cc3711 | ||
|
ab0c8c3496 | ||
|
47534b200d | ||
|
f2976af734 | ||
|
ee463058f1 | ||
|
c36a7471a8 | ||
|
6ea8cee551 | ||
|
69806c8839 | ||
|
690036aa30 | ||
|
eda6b8d01b | ||
|
cbf06b2165 | ||
|
e884eb9882 | ||
|
f8cbfea4a1 | ||
|
e01c0f054d | ||
|
12dc8c0d15 | ||
|
cb3582289f | ||
|
734d220d60 | ||
|
d725de7286 | ||
|
3e91773cd9 | ||
|
dc1d2a33a5 | ||
|
ac4074911d | ||
|
66cf60f9cb | ||
|
fffe8c355e | ||
|
b94d13b413 | ||
|
85e16c1233 | ||
|
2d53b7d9a4 | ||
|
23052a5c2e | ||
|
42b3a7c9d7 | ||
|
33315046cd | ||
|
2cf647d5ad | ||
|
b1d88ca643 | ||
|
b79b48cfbe | ||
|
a2bf19efc1 | ||
|
cb11aec84d |
@@ -1,62 +1,47 @@
|
||||
# 0x.js CONTRIBUTING.md
|
||||
0x Contribution Guide
|
||||
---------------------
|
||||
|
||||
Thank you for your interest in contributing to 0x.js! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
||||
Thank you for your interest in contributing to 0x protocol! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
||||
|
||||
## Developer's guide
|
||||
### How to contribute
|
||||
|
||||
## How to contribute
|
||||
If you'd like to contribute to 0x protocol, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check with a core dev first on [our RocketChat #dev channel](http://chat.0xproject.com) to ensure those changes are in-line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
|
||||
|
||||
If you'd like to contribute to 0x.js, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check up with a core dev first on [our gitter channel](https://gitter.im/0xProject/Lobby) or in the `#dev` channel on our [slack](https://slack.0xproject.com/) to ensure those changes are in line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
|
||||
|
||||
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other volunteers know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
|
||||
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other contributors know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
|
||||
|
||||
* Pull requests adding features or refactoring should be opened against the `development` branch
|
||||
* Pull requests fixing bugs in the latest release version should be opened again the `master` branch
|
||||
* Write [good commit messages](https://chris.beams.io/posts/git-commit/)
|
||||
|
||||
## Code quality
|
||||
### Code quality
|
||||
|
||||
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for exceptional code quality. Please follow the existing code standards and conventions. `tslint` and `prettier` (described below) will help you.
|
||||
|
||||
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for excellent code quality. Please follow the existing code standards and conventions. `tslint` (described below) will help you.
|
||||
If you're adding functionality, please also add tests and make sure they pass. We have an automatic coverage reporting tool, so we'll see it if they are missing ;)
|
||||
If you're adding a new public function/member, make sure you document it with Java doc-style comments. We use typedoc to generate [awesome documentation](https://0xproject.com/docs/0xjs) from the comments within our source code.
|
||||
|
||||
## Running and building
|
||||
If the sub-package you are modifying has a `CHANGELOG.md` file, make sure to add an entry in it for the change made to the package. For published packages, only changes that modify the public interface or behavior of the package need a CHANGELOG entry.
|
||||
|
||||
First thing to do with an unknown code base is to run the tests.
|
||||
We assume that you have `npm` and `yarn` installed.
|
||||
### Styleguide
|
||||
|
||||
To do that:
|
||||
|
||||
* Install dependencies: `yarn`
|
||||
* Initialize the testrpc state (migrate the contracts) by doing one of the following:
|
||||
* Manual contracts migration:
|
||||
* Run testrpc: `yarn testrpc`
|
||||
* Clone the `[contracts](https://github.com/0xProject/contracts)` repo and run `yarn migrate`
|
||||
* Use one of the existing testrpc snapshots
|
||||
* Check out `circle.yml` for an example
|
||||
* Run tests: `yarn test`
|
||||
|
||||
To build run: `yarn build`
|
||||
|
||||
We also recommend you read through the tests.
|
||||
|
||||
## Styleguide
|
||||
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/tslint-config-0xproject) to keep our code style consistent.
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x.js/tree/development/packages/tslint-config) to keep our code style consistent.
|
||||
|
||||
To lint your code just run: `yarn lint`
|
||||
|
||||
We also use [Prettier](https://prettier.io/) to auto-format our code. Be sure to either add a [text editor integration](https://prettier.io/docs/en/editors.html) or a [pre-commit hook](https://prettier.io/docs/en/precommit.html) to properly format your code changes.
|
||||
|
||||
If using the Atom text editor, we recommend you install the following packages:
|
||||
|
||||
* [atom-typescript](https://atom.io/packages/atom-typescript)
|
||||
* [linter-tslint](https://atom.io/packages/linter-tslint)
|
||||
* [prettier-atom](https://atom.io/packages/prettier-atom)
|
||||
* [language-ethereum](https://atom.io/packages/language-ethereum)
|
||||
|
||||
Our CI will also run it as a part of the test run when you submit your PR.
|
||||
Our CI will also run TSLint and Prettier as a part of the test run when you submit your PR. Make sure that the CI tests pass for your contribution.
|
||||
|
||||
### Branch structure & versioning
|
||||
|
||||
## Branch structure & versioning
|
||||
|
||||
We use [semantic versioning](http://semver.org/), but before we reach v1.0.0 all breaking changes as well as new features will be minor version bumps.
|
||||
We use [semantic versioning](http://semver.org/), but before a package reaches v1.0.0 all breaking changes as well as new features will be minor version bumps.
|
||||
|
||||
We have two main branches: `master` and `development`.
|
||||
|
||||
|
@@ -1,5 +1,10 @@
|
||||
# CHANGELOG
|
||||
|
||||
v0.29.0 - _December 28, 2017_
|
||||
------------------------
|
||||
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
|
||||
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
|
||||
|
||||
v0.28.0 - _December 20, 2017_
|
||||
------------------------
|
||||
* Add `etherTokenAddress` arg to `depositAsync` and `withdrawAsync` methods on `zeroEx.etherToken` (#267)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "0.27.2",
|
||||
"version": "0.29.0",
|
||||
"description": "A javascript library for interacting with the 0x protocol",
|
||||
"keywords": [
|
||||
"0x.js",
|
||||
@@ -45,10 +45,10 @@
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^0.0.2",
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/types": "^0.1.0",
|
||||
"@0xproject/dev-utils": "^0.0.1",
|
||||
"@0xproject/abi-gen": "^0.0.4",
|
||||
"@0xproject/dev-utils": "^0.0.3",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@0xproject/types": "^0.1.2",
|
||||
"@types/bintrees": "^1.0.2",
|
||||
"@types/jsonschema": "^1.1.1",
|
||||
"@types/lodash": "^4.14.86",
|
||||
@@ -84,10 +84,10 @@
|
||||
"webpack": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.0.7",
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/web3-wrapper": "^0.1.0",
|
||||
"@0xproject/assert": "^0.0.9",
|
||||
"@0xproject/json-schemas": "^0.7.1",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"@0xproject/web3-wrapper": "^0.1.2",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"bintrees": "^1.0.2",
|
||||
"bn.js": "^4.11.8",
|
||||
|
@@ -128,7 +128,7 @@ export class ZeroEx {
|
||||
* @return The amount in units.
|
||||
*/
|
||||
public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
|
||||
assert.isBigNumber('amount', amount);
|
||||
assert.isValidBaseUnitAmount('amount', amount);
|
||||
assert.isNumber('decimals', decimals);
|
||||
|
||||
const aUnit = new BigNumber(10).pow(decimals);
|
||||
@@ -149,6 +149,10 @@ export class ZeroEx {
|
||||
|
||||
const unit = new BigNumber(10).pow(decimals);
|
||||
const baseUnitAmount = amount.times(unit);
|
||||
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
|
||||
if (hasDecimals) {
|
||||
throw new Error(`Invalid unit amount: ${amount.toString()} - Too many decimal places`);
|
||||
}
|
||||
return baseUnitAmount;
|
||||
}
|
||||
/**
|
||||
|
@@ -14,62 +14,62 @@ const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
||||
* It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs`
|
||||
*/
|
||||
export class ExpirationWatcher {
|
||||
private orderHashByExpirationRBTree: RBTree<string>;
|
||||
private expiration: {[orderHash: string]: BigNumber} = {};
|
||||
private orderExpirationCheckingIntervalMs: number;
|
||||
private expirationMarginMs: number;
|
||||
private orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||
private _orderHashByExpirationRBTree: RBTree<string>;
|
||||
private _expiration: {[orderHash: string]: BigNumber} = {};
|
||||
private _orderExpirationCheckingIntervalMs: number;
|
||||
private _expirationMarginMs: number;
|
||||
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||
constructor(expirationMarginIfExistsMs?: number,
|
||||
orderExpirationCheckingIntervalIfExistsMs?: number) {
|
||||
this.expirationMarginMs = expirationMarginIfExistsMs ||
|
||||
this._expirationMarginMs = expirationMarginIfExistsMs ||
|
||||
DEFAULT_EXPIRATION_MARGIN_MS;
|
||||
this.orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
||||
this._orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
||||
DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
||||
const scoreFunction = (orderHash: string) => this.expiration[orderHash].toNumber();
|
||||
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
|
||||
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
|
||||
this.orderHashByExpirationRBTree = new RBTree(comparator);
|
||||
this._orderHashByExpirationRBTree = new RBTree(comparator);
|
||||
}
|
||||
public subscribe(callback: (orderHash: string) => void): void {
|
||||
if (!_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
|
||||
if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||
}
|
||||
this.orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this.pruneExpiredOrders.bind(this, callback), this.orderExpirationCheckingIntervalMs,
|
||||
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this._pruneExpiredOrders.bind(this, callback), this._orderExpirationCheckingIntervalMs,
|
||||
);
|
||||
}
|
||||
public unsubscribe(): void {
|
||||
if (_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
|
||||
if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||
}
|
||||
intervalUtils.clearAsyncExcludingInterval(this.orderExpirationCheckingIntervalIdIfExists);
|
||||
delete this.orderExpirationCheckingIntervalIdIfExists;
|
||||
intervalUtils.clearAsyncExcludingInterval(this._orderExpirationCheckingIntervalIdIfExists);
|
||||
delete this._orderExpirationCheckingIntervalIdIfExists;
|
||||
}
|
||||
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
|
||||
this.expiration[orderHash] = expirationUnixTimestampMs;
|
||||
this.orderHashByExpirationRBTree.insert(orderHash);
|
||||
this._expiration[orderHash] = expirationUnixTimestampMs;
|
||||
this._orderHashByExpirationRBTree.insert(orderHash);
|
||||
}
|
||||
public removeOrder(orderHash: string): void {
|
||||
this.orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this.expiration[orderHash];
|
||||
this._orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this._expiration[orderHash];
|
||||
}
|
||||
private pruneExpiredOrders(callback: (orderHash: string) => void): void {
|
||||
private _pruneExpiredOrders(callback: (orderHash: string) => void): void {
|
||||
const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
|
||||
while (true) {
|
||||
const hasTrakedOrders = this.orderHashByExpirationRBTree.size === 0;
|
||||
const hasTrakedOrders = this._orderHashByExpirationRBTree.size === 0;
|
||||
if (hasTrakedOrders) {
|
||||
break;
|
||||
}
|
||||
const nextOrderHashToExpire = this.orderHashByExpirationRBTree.min();
|
||||
const hasNoExpiredOrders = this.expiration[nextOrderHashToExpire].greaterThan(
|
||||
currentUnixTimestampMs.plus(this.expirationMarginMs),
|
||||
const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min();
|
||||
const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].greaterThan(
|
||||
currentUnixTimestampMs.plus(this._expirationMarginMs),
|
||||
);
|
||||
const isSubscriptionActive = _.isUndefined(this.orderExpirationCheckingIntervalIdIfExists);
|
||||
const isSubscriptionActive = _.isUndefined(this._orderExpirationCheckingIntervalIdIfExists);
|
||||
if (hasNoExpiredOrders || isSubscriptionActive) {
|
||||
break;
|
||||
}
|
||||
const orderHash = this.orderHashByExpirationRBTree.min();
|
||||
this.orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this.expiration[orderHash];
|
||||
const orderHash = this._orderHashByExpirationRBTree.min();
|
||||
this._orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this._expiration[orderHash];
|
||||
callback(orderHash);
|
||||
}
|
||||
}
|
||||
|
@@ -111,7 +111,7 @@ export class OrderStateWatcher {
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
||||
this._orderByOrderHash[orderHash] = signedOrder;
|
||||
this.addToDependentOrderHashes(signedOrder, orderHash);
|
||||
this._addToDependentOrderHashes(signedOrder, orderHash);
|
||||
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
||||
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
||||
}
|
||||
@@ -127,10 +127,10 @@ export class OrderStateWatcher {
|
||||
}
|
||||
delete this._orderByOrderHash[orderHash];
|
||||
delete this._orderStateByOrderHashCache[orderHash];
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||
this.removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||
this.removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||
this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||
this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||
this._expirationWatcher.removeOrder(orderHash);
|
||||
}
|
||||
/**
|
||||
@@ -327,7 +327,7 @@ export class OrderStateWatcher {
|
||||
this._callbackIfExists(orderState);
|
||||
}
|
||||
}
|
||||
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
||||
private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
||||
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
|
||||
this._dependentOrderHashes[signedOrder.maker] = {};
|
||||
}
|
||||
@@ -341,7 +341,7 @@ export class OrderStateWatcher {
|
||||
}
|
||||
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
|
||||
}
|
||||
private removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
|
||||
private _removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
|
||||
this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash);
|
||||
if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
|
||||
delete this._dependentOrderHashes[makerAddress][tokenAddress];
|
||||
@@ -351,7 +351,7 @@ export class OrderStateWatcher {
|
||||
}
|
||||
}
|
||||
private _getZRXTokenAddress(): string {
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||
return zrxTokenAddress;
|
||||
}
|
||||
|
@@ -3,69 +3,69 @@ import {BigNumber} from 'bignumber.js';
|
||||
import {SignedOrder} from '../types';
|
||||
|
||||
export class RemainingFillableCalculator {
|
||||
private signedOrder: SignedOrder;
|
||||
private isMakerTokenZRX: boolean;
|
||||
private _signedOrder: SignedOrder;
|
||||
private _isMakerTokenZRX: boolean;
|
||||
// Transferrable Amount is the minimum of Approval and Balance
|
||||
private transferrableMakerTokenAmount: BigNumber;
|
||||
private transferrableMakerFeeTokenAmount: BigNumber;
|
||||
private remainingMakerTokenAmount: BigNumber;
|
||||
private remainingMakerFeeAmount: BigNumber;
|
||||
private _transferrableMakerTokenAmount: BigNumber;
|
||||
private _transferrableMakerFeeTokenAmount: BigNumber;
|
||||
private _remainingMakerTokenAmount: BigNumber;
|
||||
private _remainingMakerFeeAmount: BigNumber;
|
||||
constructor(signedOrder: SignedOrder,
|
||||
isMakerTokenZRX: boolean,
|
||||
transferrableMakerTokenAmount: BigNumber,
|
||||
transferrableMakerFeeTokenAmount: BigNumber,
|
||||
remainingMakerTokenAmount: BigNumber) {
|
||||
this.signedOrder = signedOrder;
|
||||
this.isMakerTokenZRX = isMakerTokenZRX;
|
||||
this.transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
||||
this.transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
||||
this.remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||
this.remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee)
|
||||
this._signedOrder = signedOrder;
|
||||
this._isMakerTokenZRX = isMakerTokenZRX;
|
||||
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
||||
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
||||
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||
this._remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee)
|
||||
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
||||
}
|
||||
public computeRemainingMakerFillable(): BigNumber {
|
||||
if (this.hasSufficientFundsForFeeAndTransferAmount()) {
|
||||
return this.remainingMakerTokenAmount;
|
||||
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
||||
return this._remainingMakerTokenAmount;
|
||||
}
|
||||
if (this.signedOrder.makerFee.isZero()) {
|
||||
return BigNumber.min(this.remainingMakerTokenAmount, this.transferrableMakerTokenAmount);
|
||||
if (this._signedOrder.makerFee.isZero()) {
|
||||
return BigNumber.min(this._remainingMakerTokenAmount, this._transferrableMakerTokenAmount);
|
||||
}
|
||||
return this.calculatePartiallyFillableMakerTokenAmount();
|
||||
return this._calculatePartiallyFillableMakerTokenAmount();
|
||||
}
|
||||
public computeRemainingTakerFillable(): BigNumber {
|
||||
return this.computeRemainingMakerFillable().times(this.signedOrder.takerTokenAmount)
|
||||
.dividedToIntegerBy(this.signedOrder.makerTokenAmount);
|
||||
return this.computeRemainingMakerFillable().times(this._signedOrder.takerTokenAmount)
|
||||
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
||||
}
|
||||
private hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||
if (this.isMakerTokenZRX) {
|
||||
const totalZRXTransferAmountRequired = this.remainingMakerTokenAmount.plus(this.remainingMakerFeeAmount);
|
||||
const hasSufficientFunds = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||
if (this._isMakerTokenZRX) {
|
||||
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
||||
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
totalZRXTransferAmountRequired);
|
||||
return hasSufficientFunds;
|
||||
} else {
|
||||
const hasSufficientFundsForTransferAmount = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
this.remainingMakerTokenAmount);
|
||||
const hasSufficientFundsForFeeAmount = this.transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||
this.remainingMakerFeeAmount);
|
||||
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
this._remainingMakerTokenAmount);
|
||||
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||
this._remainingMakerFeeAmount);
|
||||
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
||||
return hasSufficientFunds;
|
||||
}
|
||||
}
|
||||
private calculatePartiallyFillableMakerTokenAmount(): BigNumber {
|
||||
private _calculatePartiallyFillableMakerTokenAmount(): BigNumber {
|
||||
// Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1
|
||||
const orderToFeeRatio = this.signedOrder.makerTokenAmount.dividedBy(this.signedOrder.makerFee);
|
||||
const orderToFeeRatio = this._signedOrder.makerTokenAmount.dividedBy(this._signedOrder.makerFee);
|
||||
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
||||
// baseUnit of fee tokens.
|
||||
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
||||
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this.transferrableMakerFeeTokenAmount,
|
||||
this.remainingMakerFeeAmount);
|
||||
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this._transferrableMakerFeeTokenAmount,
|
||||
this._remainingMakerFeeAmount);
|
||||
// The number of times the Maker can fill the order, given the Maker Token Balance
|
||||
// Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time.
|
||||
let fillableTimesInMakerTokenUnits = this.transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||
if (this.isMakerTokenZRX) {
|
||||
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||
if (this._isMakerTokenZRX) {
|
||||
// If ZRX is the maker token, the Fee and the Maker amount need to be removed from the same pool;
|
||||
// 200 ZRXwei for 2ZRXwei fee can only be filled once (need 202 ZRXwei)
|
||||
const totalZRXTokenPooled = this.transferrableMakerTokenAmount;
|
||||
const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
|
||||
// The purchasing power here is less as the tokens are taken from the same Pool
|
||||
// For every one number of fills, we have to take an extra ZRX out of the pool
|
||||
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(
|
||||
@@ -75,11 +75,11 @@ export class RemainingFillableCalculator {
|
||||
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
||||
// This can result in a RoundingError being thrown by the Exchange Contract.
|
||||
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
||||
.times(this.signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this.signedOrder.makerFee);
|
||||
.times(this._signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
||||
.times(this.signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this.signedOrder.makerFee);
|
||||
.times(this._signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
|
||||
partiallyFillableFeeTokenAmount);
|
||||
return partiallyFillableAmount;
|
||||
|
@@ -8,77 +8,77 @@ import {BlockParamLiteral} from '../types';
|
||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||
*/
|
||||
export class BalanceAndProxyAllowanceLazyStore {
|
||||
private token: TokenWrapper;
|
||||
private defaultBlock: BlockParamLiteral;
|
||||
private balance: {
|
||||
private _token: TokenWrapper;
|
||||
private _defaultBlock: BlockParamLiteral;
|
||||
private _balance: {
|
||||
[tokenAddress: string]: {
|
||||
[userAddress: string]: BigNumber;
|
||||
};
|
||||
};
|
||||
private proxyAllowance: {
|
||||
private _proxyAllowance: {
|
||||
[tokenAddress: string]: {
|
||||
[userAddress: string]: BigNumber;
|
||||
};
|
||||
};
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this.token = token;
|
||||
this.defaultBlock = defaultBlock;
|
||||
this.balance = {};
|
||||
this.proxyAllowance = {};
|
||||
this._token = token;
|
||||
this._defaultBlock = defaultBlock;
|
||||
this._balance = {};
|
||||
this._proxyAllowance = {};
|
||||
}
|
||||
public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.balance[tokenAddress]) || _.isUndefined(this.balance[tokenAddress][userAddress])) {
|
||||
if (_.isUndefined(this._balance[tokenAddress]) || _.isUndefined(this._balance[tokenAddress][userAddress])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: this.defaultBlock,
|
||||
defaultBlock: this._defaultBlock,
|
||||
};
|
||||
const balance = await this.token.getBalanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
const balance = await this._token.getBalanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
this.setBalance(tokenAddress, userAddress, balance);
|
||||
}
|
||||
const cachedBalance = this.balance[tokenAddress][userAddress];
|
||||
const cachedBalance = this._balance[tokenAddress][userAddress];
|
||||
return cachedBalance;
|
||||
}
|
||||
public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void {
|
||||
if (_.isUndefined(this.balance[tokenAddress])) {
|
||||
this.balance[tokenAddress] = {};
|
||||
if (_.isUndefined(this._balance[tokenAddress])) {
|
||||
this._balance[tokenAddress] = {};
|
||||
}
|
||||
this.balance[tokenAddress][userAddress] = balance;
|
||||
this._balance[tokenAddress][userAddress] = balance;
|
||||
}
|
||||
public deleteBalance(tokenAddress: string, userAddress: string): void {
|
||||
if (!_.isUndefined(this.balance[tokenAddress])) {
|
||||
delete this.balance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this.balance[tokenAddress])) {
|
||||
delete this.balance[tokenAddress];
|
||||
if (!_.isUndefined(this._balance[tokenAddress])) {
|
||||
delete this._balance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this._balance[tokenAddress])) {
|
||||
delete this._balance[tokenAddress];
|
||||
}
|
||||
}
|
||||
}
|
||||
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.proxyAllowance[tokenAddress]) ||
|
||||
_.isUndefined(this.proxyAllowance[tokenAddress][userAddress])) {
|
||||
if (_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
||||
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: this.defaultBlock,
|
||||
defaultBlock: this._defaultBlock,
|
||||
};
|
||||
const proxyAllowance = await this.token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
const proxyAllowance = await this._token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance);
|
||||
}
|
||||
const cachedProxyAllowance = this.proxyAllowance[tokenAddress][userAddress];
|
||||
const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress];
|
||||
return cachedProxyAllowance;
|
||||
}
|
||||
public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void {
|
||||
if (_.isUndefined(this.proxyAllowance[tokenAddress])) {
|
||||
this.proxyAllowance[tokenAddress] = {};
|
||||
if (_.isUndefined(this._proxyAllowance[tokenAddress])) {
|
||||
this._proxyAllowance[tokenAddress] = {};
|
||||
}
|
||||
this.proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
|
||||
this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
|
||||
}
|
||||
public deleteProxyAllowance(tokenAddress: string, userAddress: string): void {
|
||||
if (!_.isUndefined(this.proxyAllowance[tokenAddress])) {
|
||||
delete this.proxyAllowance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this.proxyAllowance[tokenAddress])) {
|
||||
delete this.proxyAllowance[tokenAddress];
|
||||
if (!_.isUndefined(this._proxyAllowance[tokenAddress])) {
|
||||
delete this._proxyAllowance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this._proxyAllowance[tokenAddress])) {
|
||||
delete this._proxyAllowance[tokenAddress];
|
||||
}
|
||||
}
|
||||
}
|
||||
public deleteAll(): void {
|
||||
this.balance = {};
|
||||
this.proxyAllowance = {};
|
||||
this._balance = {};
|
||||
this._proxyAllowance = {};
|
||||
}
|
||||
}
|
||||
|
@@ -8,54 +8,54 @@ import {BlockParamLiteral} from '../types';
|
||||
* Copy on read store for filled/cancelled taker amounts
|
||||
*/
|
||||
export class OrderFilledCancelledLazyStore {
|
||||
private exchange: ExchangeWrapper;
|
||||
private filledTakerAmount: {
|
||||
private _exchange: ExchangeWrapper;
|
||||
private _filledTakerAmount: {
|
||||
[orderHash: string]: BigNumber;
|
||||
};
|
||||
private cancelledTakerAmount: {
|
||||
private _cancelledTakerAmount: {
|
||||
[orderHash: string]: BigNumber;
|
||||
};
|
||||
constructor(exchange: ExchangeWrapper) {
|
||||
this.exchange = exchange;
|
||||
this.filledTakerAmount = {};
|
||||
this.cancelledTakerAmount = {};
|
||||
this._exchange = exchange;
|
||||
this._filledTakerAmount = {};
|
||||
this._cancelledTakerAmount = {};
|
||||
}
|
||||
public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.filledTakerAmount[orderHash])) {
|
||||
if (_.isUndefined(this._filledTakerAmount[orderHash])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: BlockParamLiteral.Pending,
|
||||
};
|
||||
const filledTakerAmount = await this.exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
|
||||
const filledTakerAmount = await this._exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
|
||||
this.setFilledTakerAmount(orderHash, filledTakerAmount);
|
||||
}
|
||||
const cachedFilled = this.filledTakerAmount[orderHash];
|
||||
const cachedFilled = this._filledTakerAmount[orderHash];
|
||||
return cachedFilled;
|
||||
}
|
||||
public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
|
||||
this.filledTakerAmount[orderHash] = filledTakerAmount;
|
||||
this._filledTakerAmount[orderHash] = filledTakerAmount;
|
||||
}
|
||||
public deleteFilledTakerAmount(orderHash: string): void {
|
||||
delete this.filledTakerAmount[orderHash];
|
||||
delete this._filledTakerAmount[orderHash];
|
||||
}
|
||||
public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.cancelledTakerAmount[orderHash])) {
|
||||
if (_.isUndefined(this._cancelledTakerAmount[orderHash])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: BlockParamLiteral.Pending,
|
||||
};
|
||||
const cancelledTakerAmount = await this.exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
|
||||
const cancelledTakerAmount = await this._exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
|
||||
this.setCancelledTakerAmount(orderHash, cancelledTakerAmount);
|
||||
}
|
||||
const cachedCancelled = this.cancelledTakerAmount[orderHash];
|
||||
const cachedCancelled = this._cancelledTakerAmount[orderHash];
|
||||
return cachedCancelled;
|
||||
}
|
||||
public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void {
|
||||
this.cancelledTakerAmount[orderHash] = cancelledTakerAmount;
|
||||
this._cancelledTakerAmount[orderHash] = cancelledTakerAmount;
|
||||
}
|
||||
public deleteCancelledTakerAmount(orderHash: string): void {
|
||||
delete this.cancelledTakerAmount[orderHash];
|
||||
delete this._cancelledTakerAmount[orderHash];
|
||||
}
|
||||
public deleteAll(): void {
|
||||
this.filledTakerAmount = {};
|
||||
this.cancelledTakerAmount = {};
|
||||
this._filledTakerAmount = {};
|
||||
this._cancelledTakerAmount = {};
|
||||
}
|
||||
}
|
||||
|
@@ -6,9 +6,9 @@ import * as SolidityCoder from 'web3/lib/solidity/coder';
|
||||
import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
|
||||
|
||||
export class AbiDecoder {
|
||||
private savedABIs: Web3.AbiDefinition[] = [];
|
||||
private methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
|
||||
private static padZeros(address: string) {
|
||||
private _savedABIs: Web3.AbiDefinition[] = [];
|
||||
private _methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
|
||||
private static _padZeros(address: string) {
|
||||
let formatted = address;
|
||||
if (_.startsWith(formatted, '0x')) {
|
||||
formatted = formatted.slice(2);
|
||||
@@ -18,13 +18,13 @@ export class AbiDecoder {
|
||||
return `0x${formatted}`;
|
||||
}
|
||||
constructor(abiArrays: Web3.AbiDefinition[][]) {
|
||||
_.map(abiArrays, this.addABI.bind(this));
|
||||
_.map(abiArrays, this._addABI.bind(this));
|
||||
}
|
||||
// This method can only decode logs from the 0x & ERC20 smart contracts
|
||||
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
||||
const methodId = log.topics[0];
|
||||
const event = this.methodIds[methodId];
|
||||
const event = this._methodIds[methodId];
|
||||
if (_.isUndefined(event)) {
|
||||
return log;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export class AbiDecoder {
|
||||
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
||||
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
||||
if (param.type === SolidityTypes.Address) {
|
||||
value = AbiDecoder.padZeros(new BigNumber(value).toString(16));
|
||||
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
|
||||
} else if (param.type === SolidityTypes.Uint256 ||
|
||||
param.type === SolidityTypes.Uint8 ||
|
||||
param.type === SolidityTypes.Uint) {
|
||||
@@ -56,14 +56,14 @@ export class AbiDecoder {
|
||||
args: decodedParams,
|
||||
};
|
||||
}
|
||||
private addABI(abiArray: Web3.AbiDefinition[]): void {
|
||||
private _addABI(abiArray: Web3.AbiDefinition[]): void {
|
||||
_.map(abiArray, (abi: Web3.AbiDefinition) => {
|
||||
if (abi.type === AbiType.Event) {
|
||||
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`;
|
||||
const signatureHash = new Web3().sha3(signature);
|
||||
this.methodIds[signatureHash] = abi;
|
||||
this._methodIds[signatureHash] = abi;
|
||||
}
|
||||
});
|
||||
this.savedABIs = this.savedABIs.concat(abiArray);
|
||||
this._savedABIs = this._savedABIs.concat(abiArray);
|
||||
}
|
||||
}
|
||||
|
@@ -34,16 +34,16 @@ const ERR_MSG_MAPPING = {
|
||||
};
|
||||
|
||||
export class ExchangeTransferSimulator {
|
||||
private store: BalanceAndProxyAllowanceLazyStore;
|
||||
private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private static throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
||||
transferType: TransferType): never {
|
||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private static _throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
||||
transferType: TransferType): never {
|
||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this.store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
}
|
||||
/**
|
||||
* Simulates transferFrom call performed by a proxy
|
||||
@@ -57,33 +57,33 @@ export class ExchangeTransferSimulator {
|
||||
public async transferFromAsync(tokenAddress: string, from: string, to: string,
|
||||
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
|
||||
transferType: TransferType): Promise<void> {
|
||||
const balance = await this.store.getBalanceAsync(tokenAddress, from);
|
||||
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, from);
|
||||
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||
ExchangeTransferSimulator.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
||||
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
||||
}
|
||||
if (balance.lessThan(amountInBaseUnits)) {
|
||||
ExchangeTransferSimulator.throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||
}
|
||||
await this.decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this.decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this.increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||
await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||
}
|
||||
private async decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this.store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
private async _decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
private async increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this.store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||
private async _increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||
}
|
||||
private async decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||
private async _decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
|
@@ -18,9 +18,9 @@ import {
|
||||
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
||||
|
||||
export class OrderStateUtils {
|
||||
private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||
private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||
private static validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
|
||||
private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||
private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||
private static _validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
|
||||
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
|
||||
orderRelevantState.filledTakerTokenAmount,
|
||||
);
|
||||
@@ -53,14 +53,14 @@ export class OrderStateUtils {
|
||||
}
|
||||
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
||||
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) {
|
||||
this.balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||
this.orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||
}
|
||||
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
||||
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
try {
|
||||
OrderStateUtils.validateIfOrderIsValid(signedOrder, orderRelevantState);
|
||||
OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
|
||||
const orderState: OrderStateValid = {
|
||||
isValid: true,
|
||||
orderHash,
|
||||
@@ -81,23 +81,23 @@ export class OrderStateUtils {
|
||||
// If we pass it from the instantiator - there is no opportunity to get it there
|
||||
// because JS doesn't support async constructors.
|
||||
// Moreover - it's cached under the hood so it's equivalent to an async constructor.
|
||||
const exchange = (this.orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
const makerBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
||||
);
|
||||
const makerProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
||||
);
|
||||
const makerFeeBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
zrxTokenAddress, signedOrder.maker,
|
||||
);
|
||||
const makerFeeProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
zrxTokenAddress, signedOrder.maker,
|
||||
);
|
||||
const filledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||
const cancelledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||
orderHash,
|
||||
);
|
||||
const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash);
|
||||
|
@@ -10,7 +10,7 @@ import {utils} from '../utils/utils';
|
||||
import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
|
||||
|
||||
export class OrderValidationUtils {
|
||||
private exchangeWrapper: ExchangeWrapper;
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
public static validateCancelOrderThrowIfInvalid(
|
||||
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
||||
): void {
|
||||
@@ -29,7 +29,7 @@ export class OrderValidationUtils {
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
|
||||
): Promise<void> {
|
||||
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
|
||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
@@ -42,7 +42,7 @@ export class OrderValidationUtils {
|
||||
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
|
||||
TradeSide.Taker, TransferType.Trade,
|
||||
);
|
||||
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
|
||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerFee,
|
||||
@@ -51,7 +51,7 @@ export class OrderValidationUtils {
|
||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
const takerFeeAmount = OrderValidationUtils.getPartialAmount(
|
||||
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.takerFee,
|
||||
@@ -61,21 +61,21 @@ export class OrderValidationUtils {
|
||||
TransferType.Fee,
|
||||
);
|
||||
}
|
||||
private static validateRemainingFillAmountNotZeroOrThrow(
|
||||
private static _validateRemainingFillAmountNotZeroOrThrow(
|
||||
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
||||
) {
|
||||
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
}
|
||||
}
|
||||
private static validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
|
||||
private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
|
||||
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||
if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
||||
}
|
||||
}
|
||||
private static getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
||||
target: BigNumber): BigNumber {
|
||||
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
||||
target: BigNumber): BigNumber {
|
||||
const fillMakerTokenAmount = numerator
|
||||
.mul(target)
|
||||
.div(denominator)
|
||||
@@ -83,22 +83,22 @@ export class OrderValidationUtils {
|
||||
return fillMakerTokenAmount;
|
||||
}
|
||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||
this.exchangeWrapper = exchangeWrapper;
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
}
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
|
||||
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
|
||||
const orderHash = utils.getOrderHashHex(signedOrder);
|
||||
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
||||
);
|
||||
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
|
||||
fillTakerTokenAmount = expectedFillTakerTokenAmount;
|
||||
}
|
||||
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
|
||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
@@ -107,7 +107,7 @@ export class OrderValidationUtils {
|
||||
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
|
||||
TradeSide.Maker, TransferType.Trade,
|
||||
);
|
||||
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
|
||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerFee,
|
||||
@@ -128,14 +128,14 @@ export class OrderValidationUtils {
|
||||
if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
||||
throw new Error(ZeroExError.InvalidSignature);
|
||||
}
|
||||
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
||||
);
|
||||
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
||||
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||
}
|
||||
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
|
||||
remainingTakerTokenAmount :
|
||||
@@ -144,7 +144,7 @@ export class OrderValidationUtils {
|
||||
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = await this.exchangeWrapper.isRoundingErrorAsync(
|
||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
|
||||
);
|
||||
if (wouldRoundingErrorOccur) {
|
||||
|
@@ -114,6 +114,12 @@ describe('ZeroEx library', () => {
|
||||
});
|
||||
});
|
||||
describe('#toUnitAmount', () => {
|
||||
it('should throw if invalid baseUnit amount supplied as argument', () => {
|
||||
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
|
||||
const decimals = 6;
|
||||
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals))
|
||||
.to.throw('amount should be in baseUnits (no decimals), found value: 1000000000.4');
|
||||
});
|
||||
it('Should return the expected unit amount for the decimals passed in', () => {
|
||||
const baseUnitAmount = new BigNumber(1000000000);
|
||||
const decimals = 6;
|
||||
@@ -130,6 +136,12 @@ describe('ZeroEx library', () => {
|
||||
const expectedUnitAmount = new BigNumber(1000000000);
|
||||
expect(baseUnitAmount).to.be.bignumber.equal(expectedUnitAmount);
|
||||
});
|
||||
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
|
||||
const unitAmount = new BigNumber(0.823091);
|
||||
const decimals = 5;
|
||||
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals))
|
||||
.to.throw('Invalid unit amount: 0.823091 - Too many decimal places');
|
||||
});
|
||||
});
|
||||
describe('#getOrderHashHex', () => {
|
||||
const expectedOrderHash = '0x39da987067a3c9e5f1617694f1301326ba8c8b0498ebef5df4863bed394e3c83';
|
||||
|
@@ -65,7 +65,7 @@ describe('ExchangeTransferSimulator', () => {
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
||||
);
|
||||
const store = (exchangeTransferSimulator as any).store;
|
||||
const store = (exchangeTransferSimulator as any)._store;
|
||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
@@ -81,7 +81,7 @@ describe('ExchangeTransferSimulator', () => {
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
||||
);
|
||||
const store = (exchangeTransferSimulator as any).store;
|
||||
const store = (exchangeTransferSimulator as any)._store;
|
||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
|
@@ -11,24 +11,24 @@ import {constants} from './constants';
|
||||
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
||||
|
||||
export class FillScenarios {
|
||||
private zeroEx: ZeroEx;
|
||||
private userAddresses: string[];
|
||||
private tokens: Token[];
|
||||
private coinbase: string;
|
||||
private zrxTokenAddress: string;
|
||||
private exchangeContractAddress: string;
|
||||
private _zeroEx: ZeroEx;
|
||||
private _userAddresses: string[];
|
||||
private _tokens: Token[];
|
||||
private _coinbase: string;
|
||||
private _zrxTokenAddress: string;
|
||||
private _exchangeContractAddress: string;
|
||||
constructor(zeroEx: ZeroEx, userAddresses: string[],
|
||||
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
|
||||
this.zeroEx = zeroEx;
|
||||
this.userAddresses = userAddresses;
|
||||
this.tokens = tokens;
|
||||
this.coinbase = userAddresses[0];
|
||||
this.zrxTokenAddress = zrxTokenAddress;
|
||||
this.exchangeContractAddress = exchangeContractAddress;
|
||||
this._zeroEx = zeroEx;
|
||||
this._userAddresses = userAddresses;
|
||||
this._tokens = tokens;
|
||||
this._coinbase = userAddresses[0];
|
||||
this._zrxTokenAddress = zrxTokenAddress;
|
||||
this._exchangeContractAddress = exchangeContractAddress;
|
||||
}
|
||||
public async initTokenBalancesAsync() {
|
||||
const web3Wrapper = (this.zeroEx as any)._web3Wrapper as Web3Wrapper;
|
||||
for (const token of this.tokens) {
|
||||
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
|
||||
for (const token of this._tokens) {
|
||||
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
||||
const contractInstance = web3Wrapper.getContractInstance(
|
||||
artifacts.DummyTokenArtifact.abi, token.address,
|
||||
@@ -36,10 +36,10 @@ export class FillScenarios {
|
||||
const defaults = {};
|
||||
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
||||
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
||||
const txHash = await dummyToken.setBalance.sendTransactionAsync(this.coinbase, tokenSupply, {
|
||||
from: this.coinbase,
|
||||
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
||||
from: this._coinbase,
|
||||
});
|
||||
await this.zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
await this._zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export class FillScenarios {
|
||||
fillableAmount: BigNumber,
|
||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
|
||||
);
|
||||
@@ -72,7 +72,7 @@ export class FillScenarios {
|
||||
const makerFee = new BigNumber(0);
|
||||
const takerFee = new BigNumber(0);
|
||||
const feeRecepient = constants.NULL_ADDRESS;
|
||||
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
|
||||
);
|
||||
@@ -80,18 +80,18 @@ export class FillScenarios {
|
||||
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
||||
takerAddress: string, fillableAmount: BigNumber,
|
||||
partialFillAmount: BigNumber) {
|
||||
const [makerAddress] = this.userAddresses;
|
||||
const [makerAddress] = this._userAddresses;
|
||||
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
fillableAmount, fillableAmount,
|
||||
);
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||
await this.zeroEx.exchange.fillOrderAsync(
|
||||
await this._zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
);
|
||||
return signedOrder;
|
||||
}
|
||||
private async createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress: string, takerTokenAddress: string,
|
||||
makerFee: BigNumber, takerFee: BigNumber,
|
||||
makerAddress: string, takerAddress: string,
|
||||
@@ -99,39 +99,39 @@ export class FillScenarios {
|
||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
||||
|
||||
await Promise.all([
|
||||
this.increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||
this.increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||
]);
|
||||
await Promise.all([
|
||||
this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, makerAddress, makerFee),
|
||||
this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, takerAddress, takerFee),
|
||||
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
|
||||
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
||||
]);
|
||||
|
||||
const signedOrder = await orderFactory.createSignedOrderAsync(this.zeroEx,
|
||||
const signedOrder = await orderFactory.createSignedOrderAsync(this._zeroEx,
|
||||
makerAddress, takerAddress, makerFee, takerFee,
|
||||
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
|
||||
this.exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
||||
this._exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
||||
return signedOrder;
|
||||
}
|
||||
private async increaseBalanceAndAllowanceAsync(
|
||||
private async _increaseBalanceAndAllowanceAsync(
|
||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
||||
return; // noop
|
||||
}
|
||||
await Promise.all([
|
||||
this.increaseBalanceAsync(tokenAddress, address, amount),
|
||||
this.increaseAllowanceAsync(tokenAddress, address, amount),
|
||||
this._increaseBalanceAsync(tokenAddress, address, amount),
|
||||
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
||||
]);
|
||||
}
|
||||
private async increaseBalanceAsync(
|
||||
private async _increaseBalanceAsync(
|
||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
await this.zeroEx.token.transferAsync(tokenAddress, this.coinbase, address, amount);
|
||||
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
|
||||
}
|
||||
private async increaseAllowanceAsync(
|
||||
private async _increaseAllowanceAsync(
|
||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
const oldMakerAllowance = await this.zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
||||
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
||||
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
||||
await this.zeroEx.token.setProxyAllowanceAsync(
|
||||
await this._zeroEx.token.setProxyAllowanceAsync(
|
||||
tokenAddress, address, newMakerAllowance,
|
||||
);
|
||||
}
|
||||
|
@@ -9,16 +9,16 @@ import {JSONRPCPayload} from '../../../src/types';
|
||||
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||
*/
|
||||
export class FakeGasEstimateSubprovider {
|
||||
private constantGasAmount: number;
|
||||
private _constantGasAmount: number;
|
||||
constructor(constantGasAmount: number) {
|
||||
this.constantGasAmount = constantGasAmount;
|
||||
this._constantGasAmount = constantGasAmount;
|
||||
}
|
||||
// This method needs to be here to satisfy the interface but linter wants it to be static.
|
||||
// tslint:disable-next-line:prefer-function-over-method
|
||||
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
|
||||
switch (payload.method) {
|
||||
case 'eth_estimateGas':
|
||||
end(null, this.constantGasAmount);
|
||||
end(null, this._constantGasAmount);
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@@ -6,26 +6,26 @@ const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
||||
const WETH_TOKEN_SYMBOL = 'WETH';
|
||||
|
||||
export class TokenUtils {
|
||||
private tokens: Token[];
|
||||
private _tokens: Token[];
|
||||
constructor(tokens: Token[]) {
|
||||
this.tokens = tokens;
|
||||
this._tokens = tokens;
|
||||
}
|
||||
public getProtocolTokenOrThrow(): Token {
|
||||
const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
||||
const zrxToken = _.find(this._tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
||||
if (_.isUndefined(zrxToken)) {
|
||||
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
||||
}
|
||||
return zrxToken;
|
||||
}
|
||||
public getWethTokenOrThrow(): Token {
|
||||
const wethToken = _.find(this.tokens, {symbol: WETH_TOKEN_SYMBOL});
|
||||
const wethToken = _.find(this._tokens, {symbol: WETH_TOKEN_SYMBOL});
|
||||
if (_.isUndefined(wethToken)) {
|
||||
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
||||
}
|
||||
return wethToken;
|
||||
}
|
||||
public getDummyTokens(): Token[] {
|
||||
const dummyTokens = _.filter(this.tokens, token => {
|
||||
const dummyTokens = _.filter(this._tokens, token => {
|
||||
return !_.includes([PROTOCOL_TOKEN_SYMBOL, WETH_TOKEN_SYMBOL], token.symbol);
|
||||
});
|
||||
return dummyTokens;
|
||||
|
@@ -5,9 +5,9 @@ It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/w
|
||||
You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.
|
||||
|
||||
For an example of the generated [wrapper files](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js.
|
||||
[Here](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_templates) are the templates used to generate those files.
|
||||
[Here](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/contract_templates) are the templates used to generate those files.
|
||||
|
||||
## Instalation
|
||||
## Installation
|
||||
`yarn add -g @0xproject/abi-gen`
|
||||
## Usage
|
||||
```
|
||||
@@ -29,8 +29,8 @@ We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude
|
||||
|
||||
The abi file should be either a [Truffle](http://truffleframework.com/) contract artifact (a JSON object with an abi key) or a JSON abi array.
|
||||
## How to write custom templates?
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_templates) and start adjusting them for your needs.
|
||||
We use [handlebars](handlebarsjs.com) template engine under the hood.
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/contract_templates) and start adjusting them for your needs.
|
||||
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
|
||||
You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available.
|
||||
## Which data/context do I get in my templates?
|
||||
For now you don't get much on top of methods abi, some useful helpers and a contract name because it was enough for our use-case, but if you need something else - create a PR.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/abi-gen",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.4",
|
||||
"description": "Generate contract wrappers from ABI and handlebars templates",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -33,7 +33,7 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/glob": "^5.0.33",
|
||||
"@types/handlebars": "^4.0.36",
|
||||
"@types/mkdirp": "^0.5.1",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/assert",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.9",
|
||||
"description": "Provides a standard way of performing type and schema validation across 0x projects",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/valid-url": "^1.0.2",
|
||||
@@ -37,8 +37,8 @@
|
||||
"typescript": "~2.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/json-schemas": "^0.7.1",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"lodash": "^4.17.4",
|
||||
"valid-url": "^1.0.9"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/connect",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.2",
|
||||
"description": "A javascript library for interacting with the standard relayer api",
|
||||
"keywords": [
|
||||
"connect",
|
||||
@@ -36,8 +36,9 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.0.7",
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"@0xproject/assert": "^0.0.9",
|
||||
"@0xproject/json-schemas": "^0.7.1",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"lodash": "^4.17.4",
|
||||
@@ -45,7 +46,7 @@
|
||||
"websocket": "^1.0.25"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/fetch-mock": "^5.12.1",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"@types/mocha": "^2.2.42",
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import {assert} from '@0xproject/assert';
|
||||
import {schemas} from '@0xproject/json-schemas';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import 'isomorphic-fetch';
|
||||
import * as _ from 'lodash';
|
||||
import * as queryString from 'query-string';
|
||||
@@ -21,17 +20,12 @@ import {
|
||||
} from './types';
|
||||
import {typeConverters} from './utils/type_converters';
|
||||
|
||||
// TODO: move this and bigNumberConfigs in the 0x.js package into one place
|
||||
BigNumber.config({
|
||||
EXPONENTIAL_AT: 1000,
|
||||
});
|
||||
|
||||
/**
|
||||
* This class includes all the functionality related to interacting with a set of HTTP endpoints
|
||||
* that implement the standard relayer API v0
|
||||
*/
|
||||
export class HttpClient implements Client {
|
||||
private apiEndpointUrl: string;
|
||||
private _apiEndpointUrl: string;
|
||||
/**
|
||||
* Instantiates a new HttpClient instance
|
||||
* @param url The relayer API base HTTP url you would like to interact with
|
||||
@@ -39,7 +33,7 @@ export class HttpClient implements Client {
|
||||
*/
|
||||
constructor(url: string) {
|
||||
assert.isHttpUrl('url', url);
|
||||
this.apiEndpointUrl = url;
|
||||
this._apiEndpointUrl = url;
|
||||
}
|
||||
/**
|
||||
* Retrieve token pair info from the API
|
||||
@@ -152,7 +146,7 @@ export class HttpClient implements Client {
|
||||
const stringifiedParams = queryString.stringify(params);
|
||||
query = `?${stringifiedParams}`;
|
||||
}
|
||||
const url = `${this.apiEndpointUrl}/v0${path}${query}`;
|
||||
const url = `${this._apiEndpointUrl}/v0${path}${query}`;
|
||||
const headers = new Headers({
|
||||
'content-type': 'application/json',
|
||||
});
|
||||
|
@@ -1,3 +1,8 @@
|
||||
import {bigNumberConfigs} from '@0xproject/utils';
|
||||
|
||||
// Customize our BigNumber instances
|
||||
bigNumberConfigs.configure();
|
||||
|
||||
export {HttpClient} from './http_client';
|
||||
export {WebSocketOrderbookChannel} from './ws_orderbook_channel';
|
||||
export {
|
||||
|
@@ -18,10 +18,10 @@ import {orderbookChannelMessageParsers} from './utils/orderbook_channel_message_
|
||||
* that implements the standard relayer API v0
|
||||
*/
|
||||
export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
private apiEndpointUrl: string;
|
||||
private client: WebSocket.client;
|
||||
private connectionIfExists?: WebSocket.connection;
|
||||
private subscriptionCounter = 0;
|
||||
private _apiEndpointUrl: string;
|
||||
private _client: WebSocket.client;
|
||||
private _connectionIfExists?: WebSocket.connection;
|
||||
private _subscriptionCounter = 0;
|
||||
/**
|
||||
* Instantiates a new WebSocketOrderbookChannel instance
|
||||
* @param url The relayer API base WS url you would like to interact with
|
||||
@@ -29,8 +29,8 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
*/
|
||||
constructor(url: string) {
|
||||
assert.isUri('url', url);
|
||||
this.apiEndpointUrl = url;
|
||||
this.client = new WebSocket.client();
|
||||
this._apiEndpointUrl = url;
|
||||
this._client = new WebSocket.client();
|
||||
}
|
||||
/**
|
||||
* Subscribe to orderbook snapshots and updates from the websocket
|
||||
@@ -46,11 +46,11 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate'));
|
||||
assert.isFunction('handler.onError', _.get(handler, 'onError'));
|
||||
assert.isFunction('handler.onClose', _.get(handler, 'onClose'));
|
||||
this.subscriptionCounter += 1;
|
||||
this._subscriptionCounter += 1;
|
||||
const subscribeMessage = {
|
||||
type: 'subscribe',
|
||||
channel: 'orderbook',
|
||||
requestId: this.subscriptionCounter,
|
||||
requestId: this._subscriptionCounter,
|
||||
payload: subscriptionOpts,
|
||||
};
|
||||
this._getConnection((error, connection) => {
|
||||
@@ -74,22 +74,22 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||
* Close the websocket and stop receiving updates
|
||||
*/
|
||||
public close() {
|
||||
if (!_.isUndefined(this.connectionIfExists)) {
|
||||
this.connectionIfExists.close();
|
||||
if (!_.isUndefined(this._connectionIfExists)) {
|
||||
this._connectionIfExists.close();
|
||||
}
|
||||
}
|
||||
private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void) {
|
||||
if (!_.isUndefined(this.connectionIfExists) && this.connectionIfExists.connected) {
|
||||
callback(undefined, this.connectionIfExists);
|
||||
if (!_.isUndefined(this._connectionIfExists) && this._connectionIfExists.connected) {
|
||||
callback(undefined, this._connectionIfExists);
|
||||
} else {
|
||||
this.client.on(WebsocketClientEventType.Connect, connection => {
|
||||
this.connectionIfExists = connection;
|
||||
callback(undefined, this.connectionIfExists);
|
||||
this._client.on(WebsocketClientEventType.Connect, connection => {
|
||||
this._connectionIfExists = connection;
|
||||
callback(undefined, this._connectionIfExists);
|
||||
});
|
||||
this.client.on(WebsocketClientEventType.ConnectFailed, error => {
|
||||
this._client.on(WebsocketClientEventType.ConnectFailed, error => {
|
||||
callback(error, undefined);
|
||||
});
|
||||
this.client.connect(this.apiEndpointUrl);
|
||||
this._client.connect(this._apiEndpointUrl);
|
||||
}
|
||||
}
|
||||
private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||
|
@@ -1,51 +1,65 @@
|
||||
Contracts
|
||||
-----
|
||||
--------
|
||||
|
||||
## Useful 0x Wiki Articles
|
||||
Smart contracts that implement the 0x protocol.
|
||||
|
||||
* [Architecture](https://0xproject.com/wiki#Architecture)
|
||||
* [Contract Interactions](https://0xproject.com/wiki#Contract-Interactions)
|
||||
* [Contract deployed addresses](https://0xproject.com/wiki#Deployed-Addresses)
|
||||
* [0x Protocol Message Format](https://0xproject.com/wiki#Message-Format)
|
||||
* [Bug Bounty Program](https://0xproject.com/wiki#Bug-Bounty)
|
||||
## Usage
|
||||
|
||||
## Setup
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
Install [Node](https://nodejs.org/en/download/releases/)
|
||||
|
||||
Install [yarn](https://yarnpkg.com/lang/en/docs/install/) in order to install the project dependencies more deterministically.
|
||||
|
||||
Install project dependencies:
|
||||
|
||||
```
|
||||
yarn
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
Start Testrpc
|
||||
|
||||
```
|
||||
yarn testrpc
|
||||
```
|
||||
|
||||
Run tests
|
||||
|
||||
```
|
||||
yarn test
|
||||
```
|
||||
* [Docs](https://0xproject.com/docs/contracts)
|
||||
* [Overview of 0x protocol architecture](https://0xproject.com/wiki#Architecture)
|
||||
* [0x smart contract interactions](https://0xproject.com/wiki#Contract-Interactions)
|
||||
* [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses)
|
||||
* [0x protocol message format](https://0xproject.com/wiki#Message-Format)
|
||||
|
||||
## Contributing
|
||||
|
||||
0x protocol is intended to serve as an open technical standard for EVM blockchains and we strongly encourage our community members to help us make improvements and to determine the future direction of the protocol. To report bugs within the 0x smart contracts or unit tests, please create an issue in this repository.
|
||||
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.
|
||||
|
||||
### ZEIPs
|
||||
Significant changes to 0x protocol's smart contracts, architecture, message format or functionality should be proposed in the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository. Follow the contribution guidelines provided therein.
|
||||
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||
|
||||
### Coding conventions
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
We use a custom set of [TSLint](https://palantir.github.io/tslint/) rules to enforce our coding conventions.
|
||||
### Install Dependencies
|
||||
|
||||
In order to see style violation errors, install a tslinter for your text editor. e.g Atom's [atom-typescript](https://atom.io/packages/atom-typescript).
|
||||
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
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
||||
```bash
|
||||
yarn clean
|
||||
```
|
||||
|
||||
### Lint
|
||||
|
||||
```bash
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
|
||||
Before running the tests, you will need to spin up a [TestRPC](https://www.npmjs.com/package/ethereumjs-testrpc) instance.
|
||||
|
||||
In a separate terminal, start TestRPC (a convenience command is provided as part of the [0x.js monorepo](https://github.com/0xProject/0x.js))
|
||||
```bash
|
||||
cd ../..
|
||||
yarn testrpc
|
||||
```
|
||||
|
||||
Then in your main terminal run
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
@@ -19,18 +19,18 @@ import {utils} from './utils/utils';
|
||||
const SOLIDITY_FILE_EXTENSION = '.sol';
|
||||
|
||||
export class Compiler {
|
||||
private contractsDir: string;
|
||||
private networkId: number;
|
||||
private optimizerEnabled: number;
|
||||
private artifactsDir: string;
|
||||
private contractSourcesIfExists?: ContractSources;
|
||||
private solcErrors: Set<string>;
|
||||
private _contractsDir: string;
|
||||
private _networkId: number;
|
||||
private _optimizerEnabled: number;
|
||||
private _artifactsDir: string;
|
||||
private _contractSourcesIfExists?: ContractSources;
|
||||
private _solcErrors: Set<string>;
|
||||
/**
|
||||
* Recursively retrieves Solidity source code from directory.
|
||||
* @param dirPath Directory to search.
|
||||
* @return Mapping of contract name to contract source.
|
||||
*/
|
||||
private static async getContractSourcesAsync(dirPath: string): Promise<ContractSources> {
|
||||
private static async _getContractSourcesAsync(dirPath: string): Promise<ContractSources> {
|
||||
let dirContents: string[] = [];
|
||||
try {
|
||||
dirContents = await fsWrapper.readdirAsync(dirPath);
|
||||
@@ -52,7 +52,7 @@ export class Compiler {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const nestedSources = await Compiler.getContractSourcesAsync(contentPath);
|
||||
const nestedSources = await Compiler._getContractSourcesAsync(contentPath);
|
||||
sources = {
|
||||
...sources,
|
||||
...nestedSources,
|
||||
@@ -69,7 +69,7 @@ export class Compiler {
|
||||
* @param source Source code of contract.
|
||||
* @return Solc compiler version.
|
||||
*/
|
||||
private static parseSolidityVersion(source: string): string {
|
||||
private static _parseSolidityVersion(source: string): string {
|
||||
const solcVersionMatch = source.match(/(?:solidity\s\^?)([0-9]{1,2}[.][0-9]{1,2}[.][0-9]{1,2})/);
|
||||
if (_.isNull(solcVersionMatch)) {
|
||||
throw new Error('Could not find Solidity version in source');
|
||||
@@ -85,7 +85,7 @@ export class Compiler {
|
||||
* @param errMsg An error message from the compiled output.
|
||||
* @return The error message with directories truncated from the contract path.
|
||||
*/
|
||||
private static getNormalizedErrMsg(errMsg: string): string {
|
||||
private static _getNormalizedErrMsg(errMsg: string): string {
|
||||
const errPathMatch = errMsg.match(/(.*\.sol)/);
|
||||
if (_.isNull(errPathMatch)) {
|
||||
throw new Error('Could not find a path in error message');
|
||||
@@ -101,26 +101,26 @@ export class Compiler {
|
||||
* @return An instance of the Compiler class.
|
||||
*/
|
||||
constructor(opts: CompilerOptions) {
|
||||
this.contractsDir = opts.contractsDir;
|
||||
this.networkId = opts.networkId;
|
||||
this.optimizerEnabled = opts.optimizerEnabled;
|
||||
this.artifactsDir = opts.artifactsDir;
|
||||
this.solcErrors = new Set();
|
||||
this._contractsDir = opts.contractsDir;
|
||||
this._networkId = opts.networkId;
|
||||
this._optimizerEnabled = opts.optimizerEnabled;
|
||||
this._artifactsDir = opts.artifactsDir;
|
||||
this._solcErrors = new Set();
|
||||
}
|
||||
/**
|
||||
* Compiles all Solidity files found in contractsDir and writes JSON artifacts to artifactsDir.
|
||||
*/
|
||||
public async compileAllAsync(): Promise<void> {
|
||||
await this.createArtifactsDirIfDoesNotExistAsync();
|
||||
this.contractSourcesIfExists = await Compiler.getContractSourcesAsync(this.contractsDir);
|
||||
await this._createArtifactsDirIfDoesNotExistAsync();
|
||||
this._contractSourcesIfExists = await Compiler._getContractSourcesAsync(this._contractsDir);
|
||||
|
||||
const contractBaseNames = _.keys(this.contractSourcesIfExists);
|
||||
const contractBaseNames = _.keys(this._contractSourcesIfExists);
|
||||
const compiledContractPromises = _.map(contractBaseNames, async (contractBaseName: string): Promise<void> => {
|
||||
return this.compileContractAsync(contractBaseName);
|
||||
return this._compileContractAsync(contractBaseName);
|
||||
});
|
||||
await Promise.all(compiledContractPromises);
|
||||
|
||||
this.solcErrors.forEach(errMsg => {
|
||||
this._solcErrors.forEach(errMsg => {
|
||||
utils.consoleLog(errMsg);
|
||||
});
|
||||
}
|
||||
@@ -128,14 +128,14 @@ export class Compiler {
|
||||
* Compiles contract and saves artifact to artifactsDir.
|
||||
* @param contractBaseName Name of contract with '.sol' extension.
|
||||
*/
|
||||
private async compileContractAsync(contractBaseName: string): Promise<void> {
|
||||
if (_.isUndefined(this.contractSourcesIfExists)) {
|
||||
private async _compileContractAsync(contractBaseName: string): Promise<void> {
|
||||
if (_.isUndefined(this._contractSourcesIfExists)) {
|
||||
throw new Error('Contract sources not yet initialized');
|
||||
}
|
||||
|
||||
const source = this.contractSourcesIfExists[contractBaseName];
|
||||
const source = this._contractSourcesIfExists[contractBaseName];
|
||||
const contractName = path.basename(contractBaseName, SOLIDITY_FILE_EXTENSION);
|
||||
const currentArtifactPath = `${this.artifactsDir}/${contractName}.json`;
|
||||
const currentArtifactPath = `${this._artifactsDir}/${contractName}.json`;
|
||||
const sourceHash = `0x${ethUtil.sha3(source).toString('hex')}`;
|
||||
|
||||
let currentArtifactString: string;
|
||||
@@ -149,10 +149,10 @@ export class Compiler {
|
||||
currentArtifactString = await fsWrapper.readFileAsync(currentArtifactPath, opts);
|
||||
currentArtifact = JSON.parse(currentArtifactString);
|
||||
oldNetworks = currentArtifact.networks;
|
||||
const oldNetwork: ContractData = oldNetworks[this.networkId];
|
||||
const oldNetwork: ContractData = oldNetworks[this._networkId];
|
||||
shouldCompile = _.isUndefined(oldNetwork) ||
|
||||
oldNetwork.keccak256 !== sourceHash ||
|
||||
oldNetwork.optimizer_enabled !== this.optimizerEnabled;
|
||||
oldNetwork.optimizer_enabled !== this._optimizerEnabled;
|
||||
} catch (err) {
|
||||
shouldCompile = true;
|
||||
}
|
||||
@@ -164,7 +164,7 @@ export class Compiler {
|
||||
const input = {
|
||||
[contractBaseName]: source,
|
||||
};
|
||||
const solcVersion = Compiler.parseSolidityVersion(source);
|
||||
const solcVersion = Compiler._parseSolidityVersion(source);
|
||||
const fullSolcVersion = binPaths[solcVersion];
|
||||
const solcBinPath = `./../solc/solc_bin/${fullSolcVersion}`;
|
||||
const solcBin = require(solcBinPath);
|
||||
@@ -175,13 +175,13 @@ export class Compiler {
|
||||
sources: input,
|
||||
};
|
||||
const compiled = solcInstance.compile(sourcesToCompile,
|
||||
this.optimizerEnabled,
|
||||
this.findImportsIfSourcesExist.bind(this));
|
||||
this._optimizerEnabled,
|
||||
this._findImportsIfSourcesExist.bind(this));
|
||||
|
||||
if (!_.isUndefined(compiled.errors)) {
|
||||
_.each(compiled.errors, errMsg => {
|
||||
const normalizedErrMsg = Compiler.getNormalizedErrMsg(errMsg);
|
||||
this.solcErrors.add(normalizedErrMsg);
|
||||
const normalizedErrMsg = Compiler._getNormalizedErrMsg(errMsg);
|
||||
this._solcErrors.add(normalizedErrMsg);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ export class Compiler {
|
||||
const contractData: ContractData = {
|
||||
solc_version: solcVersion,
|
||||
keccak256: sourceHash,
|
||||
optimizer_enabled: this.optimizerEnabled,
|
||||
optimizer_enabled: this._optimizerEnabled,
|
||||
abi,
|
||||
unlinked_binary,
|
||||
updated_at,
|
||||
@@ -204,14 +204,14 @@ export class Compiler {
|
||||
...currentArtifact,
|
||||
networks: {
|
||||
...oldNetworks,
|
||||
[this.networkId]: contractData,
|
||||
[this._networkId]: contractData,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
newArtifact = {
|
||||
contract_name: contractName,
|
||||
networks: {
|
||||
[this.networkId]: contractData,
|
||||
[this._networkId]: contractData,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -226,12 +226,12 @@ export class Compiler {
|
||||
* @param importPath Path to an imported dependency.
|
||||
* @return Import contents object containing source code of dependency.
|
||||
*/
|
||||
private findImportsIfSourcesExist(importPath: string): ImportContents {
|
||||
if (_.isUndefined(this.contractSourcesIfExists)) {
|
||||
private _findImportsIfSourcesExist(importPath: string): ImportContents {
|
||||
if (_.isUndefined(this._contractSourcesIfExists)) {
|
||||
throw new Error('Contract sources not yet initialized');
|
||||
}
|
||||
const contractBaseName = path.basename(importPath);
|
||||
const source = this.contractSourcesIfExists[contractBaseName];
|
||||
const source = this._contractSourcesIfExists[contractBaseName];
|
||||
const importContents: ImportContents = {
|
||||
contents: source,
|
||||
};
|
||||
@@ -240,10 +240,10 @@ export class Compiler {
|
||||
/**
|
||||
* Creates the artifacts directory if it does not already exist.
|
||||
*/
|
||||
private async createArtifactsDirIfDoesNotExistAsync(): Promise<void> {
|
||||
if (!fsWrapper.doesPathExistSync(this.artifactsDir)) {
|
||||
private async _createArtifactsDirIfDoesNotExistAsync(): Promise<void> {
|
||||
if (!fsWrapper.doesPathExistSync(this._artifactsDir)) {
|
||||
utils.consoleLog('Creating artifacts directory...');
|
||||
await fsWrapper.mkdirAsync(this.artifactsDir);
|
||||
await fsWrapper.mkdirAsync(this._artifactsDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,19 +18,19 @@ const EXTRA_GAS = 200000;
|
||||
|
||||
export class Deployer {
|
||||
public web3Wrapper: Web3Wrapper;
|
||||
private artifactsDir: string;
|
||||
private jsonrpcPort: number;
|
||||
private networkId: number;
|
||||
private defaults: Partial<TxData>;
|
||||
private _artifactsDir: string;
|
||||
private _jsonrpcPort: number;
|
||||
private _networkId: number;
|
||||
private _defaults: Partial<TxData>;
|
||||
|
||||
constructor(opts: DeployerOptions) {
|
||||
this.artifactsDir = opts.artifactsDir;
|
||||
this.jsonrpcPort = opts.jsonrpcPort;
|
||||
this.networkId = opts.networkId;
|
||||
const jsonrpcUrl = `http://localhost:${this.jsonrpcPort}`;
|
||||
this._artifactsDir = opts.artifactsDir;
|
||||
this._jsonrpcPort = opts.jsonrpcPort;
|
||||
this._networkId = opts.networkId;
|
||||
const jsonrpcUrl = `http://localhost:${this._jsonrpcPort}`;
|
||||
const web3Provider = new Web3.providers.HttpProvider(jsonrpcUrl);
|
||||
this.defaults = opts.defaults;
|
||||
this.web3Wrapper = new Web3Wrapper(web3Provider, this.defaults);
|
||||
this._defaults = opts.defaults;
|
||||
this.web3Wrapper = new Web3Wrapper(web3Provider, this._defaults);
|
||||
}
|
||||
/**
|
||||
* Loads contract artifact and deploys contract with given arguments.
|
||||
@@ -39,21 +39,21 @@ export class Deployer {
|
||||
* @return Deployed contract instance.
|
||||
*/
|
||||
public async deployAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
|
||||
const contractArtifact: ContractArtifact = this.loadContractArtifactIfExists(contractName);
|
||||
const contractData: ContractData = this.getContractDataFromArtifactIfExists(contractArtifact);
|
||||
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
|
||||
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
|
||||
const data = contractData.unlinked_binary;
|
||||
const from = await this.getFromAddressAsync();
|
||||
const gas = await this.getAllowableGasEstimateAsync(data);
|
||||
const from = await this._getFromAddressAsync();
|
||||
const gas = await this._getAllowableGasEstimateAsync(data);
|
||||
const txData = {
|
||||
gasPrice: this.defaults.gasPrice,
|
||||
gasPrice: this._defaults.gasPrice,
|
||||
from,
|
||||
data,
|
||||
gas,
|
||||
};
|
||||
const abi = contractData.abi;
|
||||
const web3ContractInstance = await this.deployFromAbiAsync(abi, args, txData);
|
||||
const web3ContractInstance = await this._deployFromAbiAsync(abi, args, txData);
|
||||
utils.consoleLog(`${contractName}.sol successfully deployed at ${web3ContractInstance.address}`);
|
||||
const contractInstance = new Contract(web3ContractInstance, this.defaults);
|
||||
const contractInstance = new Contract(web3ContractInstance, this._defaults);
|
||||
return contractInstance;
|
||||
}
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ export class Deployer {
|
||||
*/
|
||||
public async deployAndSaveAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
|
||||
const contractInstance = await this.deployAsync(contractName, args);
|
||||
await this.saveContractDataToArtifactAsync(contractName, contractInstance.address, args);
|
||||
await this._saveContractDataToArtifactAsync(contractName, contractInstance.address, args);
|
||||
return contractInstance;
|
||||
}
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ export class Deployer {
|
||||
* @param txData Tx options used for deployment.
|
||||
* @return Promise that resolves to a web3 contract instance.
|
||||
*/
|
||||
private async deployFromAbiAsync(abi: Web3.ContractAbi, args: any[], txData: Web3.TxData): Promise<any> {
|
||||
private async _deployFromAbiAsync(abi: Web3.ContractAbi, args: any[], txData: Web3.TxData): Promise<any> {
|
||||
const contract: Web3.Contract<Web3.ContractInstance> = this.web3Wrapper.getContractFromAbi(abi);
|
||||
const deployPromise = new Promise((resolve, reject) => {
|
||||
/**
|
||||
@@ -99,10 +99,10 @@ export class Deployer {
|
||||
* @param contractAddress Contract address to save to artifact.
|
||||
* @param args Contract constructor arguments that will be encoded and saved to artifact.
|
||||
*/
|
||||
private async saveContractDataToArtifactAsync(contractName: string,
|
||||
contractAddress: string, args: any[]): Promise<void> {
|
||||
const contractArtifact: ContractArtifact = this.loadContractArtifactIfExists(contractName);
|
||||
const contractData: ContractData = this.getContractDataFromArtifactIfExists(contractArtifact);
|
||||
private async _saveContractDataToArtifactAsync(contractName: string,
|
||||
contractAddress: string, args: any[]): Promise<void> {
|
||||
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
|
||||
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
|
||||
const abi = contractData.abi;
|
||||
const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi);
|
||||
const newContractData = {
|
||||
@@ -114,11 +114,11 @@ export class Deployer {
|
||||
...contractArtifact,
|
||||
networks: {
|
||||
...contractArtifact.networks,
|
||||
[this.networkId]: newContractData,
|
||||
[this._networkId]: newContractData,
|
||||
},
|
||||
};
|
||||
const artifactString = utils.stringifyWithFormatting(newArtifact);
|
||||
const artifactPath = `${this.artifactsDir}/${contractName}.json`;
|
||||
const artifactPath = `${this._artifactsDir}/${contractName}.json`;
|
||||
await fsWrapper.writeFileAsync(artifactPath, artifactString);
|
||||
}
|
||||
/**
|
||||
@@ -126,8 +126,8 @@ export class Deployer {
|
||||
* @param contractName Name of the contract, without the extension.
|
||||
* @return The contract artifact.
|
||||
*/
|
||||
private loadContractArtifactIfExists(contractName: string): ContractArtifact {
|
||||
const artifactPath = `${this.artifactsDir}/${contractName}.json`;
|
||||
private _loadContractArtifactIfExists(contractName: string): ContractArtifact {
|
||||
const artifactPath = `${this._artifactsDir}/${contractName}.json`;
|
||||
try {
|
||||
const contractArtifact: ContractArtifact = require(artifactPath);
|
||||
return contractArtifact;
|
||||
@@ -140,8 +140,8 @@ export class Deployer {
|
||||
* @param contractArtifact The contract artifact.
|
||||
* @return Network specific contract data.
|
||||
*/
|
||||
private getContractDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractData {
|
||||
const contractData = contractArtifact.networks[this.networkId];
|
||||
private _getContractDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractData {
|
||||
const contractData = contractArtifact.networks[this._networkId];
|
||||
if (_.isUndefined(contractData)) {
|
||||
throw new Error(`Data not found in artifact for contract: ${contractArtifact.contract_name}`);
|
||||
}
|
||||
@@ -151,13 +151,13 @@ export class Deployer {
|
||||
* Gets the address to use for sending a transaction.
|
||||
* @return The default from address. If not specified, returns the first address accessible by web3.
|
||||
*/
|
||||
private async getFromAddressAsync(): Promise<string> {
|
||||
private async _getFromAddressAsync(): Promise<string> {
|
||||
let from: string;
|
||||
if (_.isUndefined(this.defaults.from)) {
|
||||
if (_.isUndefined(this._defaults.from)) {
|
||||
const accounts = await this.web3Wrapper.getAvailableAddressesAsync();
|
||||
from = accounts[0];
|
||||
} else {
|
||||
from = this.defaults.from;
|
||||
from = this._defaults.from;
|
||||
}
|
||||
return from;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ export class Deployer {
|
||||
* @param data Bytecode to estimate gas for.
|
||||
* @return Gas estimate for transaction data.
|
||||
*/
|
||||
private async getAllowableGasEstimateAsync(data: string): Promise<number> {
|
||||
private async _getAllowableGasEstimateAsync(data: string): Promise<number> {
|
||||
const block = await this.web3Wrapper.getBlockAsync('latest');
|
||||
let gas: number;
|
||||
try {
|
||||
|
@@ -8,55 +8,55 @@ import {AbiType} from './types';
|
||||
export class Contract implements Web3.ContractInstance {
|
||||
public address: string;
|
||||
public abi: Web3.ContractAbi;
|
||||
private contract: Web3.ContractInstance;
|
||||
private defaults: Partial<Web3.TxData>;
|
||||
private validator: SchemaValidator;
|
||||
private _contract: Web3.ContractInstance;
|
||||
private _defaults: Partial<Web3.TxData>;
|
||||
private _validator: SchemaValidator;
|
||||
// This class instance is going to be populated with functions and events depending on the ABI
|
||||
// and we don't know their types in advance
|
||||
[name: string]: any;
|
||||
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<Web3.TxData>) {
|
||||
this.contract = web3ContractInstance;
|
||||
this._contract = web3ContractInstance;
|
||||
this.address = web3ContractInstance.address;
|
||||
this.abi = web3ContractInstance.abi;
|
||||
this.defaults = defaults;
|
||||
this.populateEvents();
|
||||
this.populateFunctions();
|
||||
this.validator = new SchemaValidator();
|
||||
this._defaults = defaults;
|
||||
this._populateEvents();
|
||||
this._populateFunctions();
|
||||
this._validator = new SchemaValidator();
|
||||
}
|
||||
private populateFunctions(): void {
|
||||
private _populateFunctions(): void {
|
||||
const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function);
|
||||
_.forEach(functionsAbi, (functionAbi: Web3.MethodAbi) => {
|
||||
if (functionAbi.constant) {
|
||||
const cbStyleCallFunction = this.contract[functionAbi.name].call;
|
||||
const cbStyleCallFunction = this._contract[functionAbi.name].call;
|
||||
this[functionAbi.name] = {
|
||||
callAsync: promisify(cbStyleCallFunction, this.contract),
|
||||
callAsync: promisify(cbStyleCallFunction, this._contract),
|
||||
};
|
||||
} else {
|
||||
const cbStyleFunction = this.contract[functionAbi.name];
|
||||
const cbStyleEstimateGasFunction = this.contract[functionAbi.name].estimateGas;
|
||||
const cbStyleFunction = this._contract[functionAbi.name];
|
||||
const cbStyleEstimateGasFunction = this._contract[functionAbi.name].estimateGas;
|
||||
this[functionAbi.name] = {
|
||||
estimateGasAsync: promisify(cbStyleEstimateGasFunction, this.contract),
|
||||
sendTransactionAsync: this.promisifyWithDefaultParams(cbStyleFunction),
|
||||
estimateGasAsync: promisify(cbStyleEstimateGasFunction, this._contract),
|
||||
sendTransactionAsync: this._promisifyWithDefaultParams(cbStyleFunction),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
private populateEvents(): void {
|
||||
private _populateEvents(): void {
|
||||
const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event);
|
||||
_.forEach(eventsAbi, (eventAbi: Web3.EventAbi) => {
|
||||
this[eventAbi.name] = this.contract[eventAbi.name];
|
||||
this[eventAbi.name] = this._contract[eventAbi.name];
|
||||
});
|
||||
}
|
||||
private promisifyWithDefaultParams(fn: (...args: any[]) => void): (...args: any[]) => Promise<any> {
|
||||
private _promisifyWithDefaultParams(fn: (...args: any[]) => void): (...args: any[]) => Promise<any> {
|
||||
const promisifiedWithDefaultParams = async (...args: any[]) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
const lastArg = args[args.length - 1];
|
||||
let txData: Partial<Web3.TxData> = {};
|
||||
if (this.isTxData(lastArg)) {
|
||||
if (this._isTxData(lastArg)) {
|
||||
txData = args.pop();
|
||||
}
|
||||
txData = {
|
||||
...this.defaults,
|
||||
...this._defaults,
|
||||
...txData,
|
||||
};
|
||||
const callback = (err: Error, data: any) => {
|
||||
@@ -68,14 +68,14 @@ export class Contract implements Web3.ContractInstance {
|
||||
};
|
||||
args.push(txData);
|
||||
args.push(callback);
|
||||
fn.apply(this.contract, args);
|
||||
fn.apply(this._contract, args);
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
return promisifiedWithDefaultParams;
|
||||
}
|
||||
private isTxData(lastArg: any): boolean {
|
||||
const isValid = this.validator.isValid(lastArg, schemas.txDataSchema);
|
||||
private _isTxData(lastArg: any): boolean {
|
||||
const isValid = this._validator.isValid(lastArg, schemas.txDataSchema);
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "contracts",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.1",
|
||||
"description": "Smart contract components of 0x protocol",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
@@ -29,9 +29,9 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/contracts/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/dev-utils": "^0.0.1",
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/types": "^0.1.0",
|
||||
"@0xproject/dev-utils": "^0.0.3",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@0xproject/types": "^0.1.2",
|
||||
"@types/bluebird": "^3.5.3",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"@types/node": "^8.0.53",
|
||||
@@ -55,10 +55,10 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"0x.js": "~0.27.2",
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/web3-wrapper": "^0.1.0",
|
||||
"0x.js": "^0.29.0",
|
||||
"@0xproject/json-schemas": "^0.7.1",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"@0xproject/web3-wrapper": "^0.1.2",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"bluebird": "^3.5.0",
|
||||
"bn.js": "^4.11.8",
|
||||
|
@@ -7,16 +7,16 @@ import {BalancesByOwner, ContractInstance} from './types';
|
||||
bigNumberConfigs.configure();
|
||||
|
||||
export class Balances {
|
||||
private tokenContractInstances: ContractInstance[];
|
||||
private ownerAddresses: string[];
|
||||
private _tokenContractInstances: ContractInstance[];
|
||||
private _ownerAddresses: string[];
|
||||
constructor(tokenContractInstances: ContractInstance[], ownerAddresses: string[]) {
|
||||
this.tokenContractInstances = tokenContractInstances;
|
||||
this.ownerAddresses = ownerAddresses;
|
||||
this._tokenContractInstances = tokenContractInstances;
|
||||
this._ownerAddresses = ownerAddresses;
|
||||
}
|
||||
public async getAsync(): Promise<BalancesByOwner> {
|
||||
const balancesByOwner: BalancesByOwner = {};
|
||||
for (const tokenContractInstance of this.tokenContractInstances) {
|
||||
for (const ownerAddress of this.ownerAddresses) {
|
||||
for (const tokenContractInstance of this._tokenContractInstances) {
|
||||
for (const ownerAddress of this._ownerAddresses) {
|
||||
let balance = await tokenContractInstance.balanceOf(ownerAddress);
|
||||
balance = new BigNumber(balance);
|
||||
if (_.isUndefined(balancesByOwner[ownerAddress])) {
|
||||
|
@@ -6,9 +6,9 @@ import {Order} from './order';
|
||||
import {ContractInstance} from './types';
|
||||
|
||||
export class ExchangeWrapper {
|
||||
private exchange: ContractInstance;
|
||||
private _exchange: ContractInstance;
|
||||
constructor(exchangeContractInstance: ContractInstance) {
|
||||
this.exchange = exchangeContractInstance;
|
||||
this._exchange = exchangeContractInstance;
|
||||
}
|
||||
public async fillOrderAsync(order: Order, from: string,
|
||||
opts: {
|
||||
@@ -17,7 +17,7 @@ export class ExchangeWrapper {
|
||||
} = {}) {
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
|
||||
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
|
||||
const tx = await this.exchange.fillOrder(
|
||||
const tx = await this._exchange.fillOrder(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.fillTakerTokenAmount,
|
||||
@@ -33,7 +33,7 @@ export class ExchangeWrapper {
|
||||
public async cancelOrderAsync(order: Order, from: string,
|
||||
opts: {cancelTakerTokenAmount?: BigNumber} = {}) {
|
||||
const params = order.createCancel(opts.cancelTakerTokenAmount);
|
||||
const tx = await this.exchange.cancelOrder(
|
||||
const tx = await this._exchange.cancelOrder(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.cancelTakerTokenAmount,
|
||||
@@ -46,7 +46,7 @@ export class ExchangeWrapper {
|
||||
opts: {fillTakerTokenAmount?: BigNumber} = {}) {
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
|
||||
const tx = await this.exchange.fillOrKillOrder(
|
||||
const tx = await this._exchange.fillOrKillOrder(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.fillTakerTokenAmount,
|
||||
@@ -66,7 +66,7 @@ export class ExchangeWrapper {
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
|
||||
const params = formatters.createBatchFill(
|
||||
orders, shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmounts);
|
||||
const tx = await this.exchange.batchFillOrders(
|
||||
const tx = await this._exchange.batchFillOrders(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.fillTakerTokenAmounts,
|
||||
@@ -82,7 +82,7 @@ export class ExchangeWrapper {
|
||||
public async batchFillOrKillOrdersAsync(orders: Order[], from: string,
|
||||
opts: {fillTakerTokenAmounts?: BigNumber[]} = {}) {
|
||||
const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts);
|
||||
const tx = await this.exchange.batchFillOrKillOrders(
|
||||
const tx = await this._exchange.batchFillOrKillOrders(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.fillTakerTokenAmounts,
|
||||
@@ -103,7 +103,7 @@ export class ExchangeWrapper {
|
||||
const params = formatters.createFillUpTo(orders,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
opts.fillTakerTokenAmount);
|
||||
const tx = await this.exchange.fillOrdersUpTo(
|
||||
const tx = await this._exchange.fillOrdersUpTo(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.fillTakerTokenAmount,
|
||||
@@ -119,7 +119,7 @@ export class ExchangeWrapper {
|
||||
public async batchCancelOrdersAsync(orders: Order[], from: string,
|
||||
opts: {cancelTakerTokenAmounts?: BigNumber[]} = {}) {
|
||||
const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts);
|
||||
const tx = await this.exchange.batchCancelOrders(
|
||||
const tx = await this._exchange.batchCancelOrders(
|
||||
params.orderAddresses,
|
||||
params.orderValues,
|
||||
params.cancelTakerTokenAmounts,
|
||||
@@ -131,11 +131,11 @@ export class ExchangeWrapper {
|
||||
public async getOrderHashAsync(order: Order): Promise<string> {
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance);
|
||||
const orderHash = await this.exchange.getOrderHash(params.orderAddresses, params.orderValues);
|
||||
const orderHash = await this._exchange.getOrderHash(params.orderAddresses, params.orderValues);
|
||||
return orderHash;
|
||||
}
|
||||
public async isValidSignatureAsync(order: Order): Promise<boolean> {
|
||||
const isValidSignature = await this.exchange.isValidSignature(
|
||||
const isValidSignature = await this._exchange.isValidSignature(
|
||||
order.params.maker,
|
||||
order.params.orderHashHex,
|
||||
order.params.v,
|
||||
@@ -146,12 +146,12 @@ export class ExchangeWrapper {
|
||||
}
|
||||
public async isRoundingErrorAsync(numerator: BigNumber, denominator: BigNumber,
|
||||
target: BigNumber): Promise<boolean> {
|
||||
const isRoundingError = await this.exchange.isRoundingError(numerator, denominator, target);
|
||||
const isRoundingError = await this._exchange.isRoundingError(numerator, denominator, target);
|
||||
return isRoundingError;
|
||||
}
|
||||
public async getPartialAmountAsync(numerator: BigNumber, denominator: BigNumber,
|
||||
target: BigNumber): Promise<BigNumber> {
|
||||
const partialAmount = new BigNumber(await this.exchange.getPartialAmount(numerator, denominator, target));
|
||||
const partialAmount = new BigNumber(await this._exchange.getPartialAmount(numerator, denominator, target));
|
||||
return partialAmount;
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ import * as Web3 from 'web3';
|
||||
import {ContractInstance, TransactionDataParams} from './types';
|
||||
|
||||
export class MultiSigWrapper {
|
||||
private multiSig: ContractInstance;
|
||||
private _multiSig: ContractInstance;
|
||||
public static encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) {
|
||||
const abiEntity = _.find(abi, {name}) as Web3.MethodAbi;
|
||||
if (_.isUndefined(abiEntity)) {
|
||||
@@ -22,13 +22,13 @@ export class MultiSigWrapper {
|
||||
return funcSig + argsData.join('');
|
||||
}
|
||||
constructor(multiSigContractInstance: ContractInstance) {
|
||||
this.multiSig = multiSigContractInstance;
|
||||
this._multiSig = multiSigContractInstance;
|
||||
}
|
||||
public async submitTransactionAsync(destination: string, from: string,
|
||||
dataParams: TransactionDataParams,
|
||||
value: number = 0) {
|
||||
const {name, abi, args = []} = dataParams;
|
||||
const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args);
|
||||
return this.multiSig.submitTransaction(destination, value, encoded, {from});
|
||||
return this._multiSig.submitTransaction(destination, value, encoded, {from});
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ export class Order {
|
||||
if (_.isUndefined(v) || _.isUndefined(r) || _.isUndefined(s)) {
|
||||
throw new Error('Cannot call isValidSignature on unsigned order');
|
||||
}
|
||||
const orderHash = this.getOrderHash();
|
||||
const orderHash = this._getOrderHash();
|
||||
const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash));
|
||||
try {
|
||||
const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s));
|
||||
@@ -32,7 +32,7 @@ export class Order {
|
||||
}
|
||||
}
|
||||
public async signAsync() {
|
||||
const orderHash = this.getOrderHash();
|
||||
const orderHash = this._getOrderHash();
|
||||
const signature = await promisify<string>(web3.eth.sign)(this.params.maker, orderHash);
|
||||
const {v, r, s} = ethUtil.fromRpcSig(signature);
|
||||
this.params = _.assign(this.params, {
|
||||
@@ -88,7 +88,7 @@ export class Order {
|
||||
};
|
||||
return cancel;
|
||||
}
|
||||
private getOrderHash(): string {
|
||||
private _getOrderHash(): string {
|
||||
const orderHash = crypto.solSHA3([
|
||||
this.params.exchangeContractAddress,
|
||||
this.params.maker,
|
||||
|
@@ -6,9 +6,9 @@ import {Order} from './order';
|
||||
import {DefaultOrderParams, OptionalOrderParams, OrderParams} from './types';
|
||||
|
||||
export class OrderFactory {
|
||||
private defaultOrderParams: DefaultOrderParams;
|
||||
private _defaultOrderParams: DefaultOrderParams;
|
||||
constructor(defaultOrderParams: DefaultOrderParams) {
|
||||
this.defaultOrderParams = defaultOrderParams;
|
||||
this._defaultOrderParams = defaultOrderParams;
|
||||
}
|
||||
public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) {
|
||||
const randomExpiration = new BigNumber(Math.floor((Date.now() + (Math.random() * 100000000000)) / 1000));
|
||||
@@ -16,7 +16,7 @@ export class OrderFactory {
|
||||
expirationTimestampInSec: randomExpiration,
|
||||
salt: ZeroEx.generatePseudoRandomSalt(),
|
||||
taker: ZeroEx.NULL_ADDRESS,
|
||||
}, this.defaultOrderParams, customOrderParams);
|
||||
}, this._defaultOrderParams, customOrderParams);
|
||||
const order = new Order(orderParams);
|
||||
await order.signAsync();
|
||||
return order;
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import {ContractInstance, Token} from './types';
|
||||
|
||||
export class TokenRegWrapper {
|
||||
private tokenReg: ContractInstance;
|
||||
private _tokenReg: ContractInstance;
|
||||
constructor(tokenRegContractInstance: ContractInstance) {
|
||||
this.tokenReg = tokenRegContractInstance;
|
||||
this._tokenReg = tokenRegContractInstance;
|
||||
}
|
||||
public addTokenAsync(token: Token, from: string) {
|
||||
const tx = this.tokenReg.addToken(
|
||||
const tx = this._tokenReg.addToken(
|
||||
token.address,
|
||||
token.name,
|
||||
token.symbol,
|
||||
@@ -18,7 +18,7 @@ export class TokenRegWrapper {
|
||||
return tx;
|
||||
}
|
||||
public async getTokenMetaDataAsync(tokenAddress: string) {
|
||||
const data = await this.tokenReg.getTokenMetaData(tokenAddress);
|
||||
const data = await this._tokenReg.getTokenMetaData(tokenAddress);
|
||||
const token: Token = {
|
||||
address: data[0],
|
||||
name: data[1],
|
||||
@@ -30,7 +30,7 @@ export class TokenRegWrapper {
|
||||
return token;
|
||||
}
|
||||
public async getTokenByNameAsync(tokenName: string) {
|
||||
const data = await this.tokenReg.getTokenByName(tokenName);
|
||||
const data = await this._tokenReg.getTokenByName(tokenName);
|
||||
const token: Token = {
|
||||
address: data[0],
|
||||
name: data[1],
|
||||
@@ -42,7 +42,7 @@ export class TokenRegWrapper {
|
||||
return token;
|
||||
}
|
||||
public async getTokenBySymbolAsync(tokenSymbol: string) {
|
||||
const data = await this.tokenReg.getTokenBySymbol(tokenSymbol);
|
||||
const data = await this._tokenReg.getTokenBySymbol(tokenSymbol);
|
||||
const token: Token = {
|
||||
address: data[0],
|
||||
name: data[1],
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/dev-utils",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.3",
|
||||
"description": "0x dev TS utils",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -19,14 +19,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.0",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "~2.6.1",
|
||||
"types-bn": "^0.0.1",
|
||||
"types-ethereumjs-util": "0xProject/types-ethereumjs-util"
|
||||
"types-ethereumjs-util": "0xProject/types-ethereumjs-util",
|
||||
"typescript": "~2.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bignumber.js": "~4.1.0",
|
||||
|
@@ -1,21 +1,21 @@
|
||||
import {RPC} from './rpc';
|
||||
|
||||
export class BlockchainLifecycle {
|
||||
private rpc: RPC;
|
||||
private snapshotIdsStack: number[];
|
||||
private _rpc: RPC;
|
||||
private _snapshotIdsStack: number[];
|
||||
constructor(url: string) {
|
||||
this.rpc = new RPC(url);
|
||||
this.snapshotIdsStack = [];
|
||||
this._rpc = new RPC(url);
|
||||
this._snapshotIdsStack = [];
|
||||
}
|
||||
// TODO: In order to run these tests on an actual node, we should check if we are running against
|
||||
// TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test
|
||||
public async startAsync(): Promise<void> {
|
||||
const snapshotId = await this.rpc.takeSnapshotAsync();
|
||||
this.snapshotIdsStack.push(snapshotId);
|
||||
const snapshotId = await this._rpc.takeSnapshotAsync();
|
||||
this._snapshotIdsStack.push(snapshotId);
|
||||
}
|
||||
public async revertAsync(): Promise<void> {
|
||||
const snapshotId = this.snapshotIdsStack.pop() as number;
|
||||
const didRevert = await this.rpc.revertSnapshotAsync(snapshotId);
|
||||
const snapshotId = this._snapshotIdsStack.pop() as number;
|
||||
const didRevert = await this._rpc.revertSnapshotAsync(snapshotId);
|
||||
if (!didRevert) {
|
||||
throw new Error(`Snapshot with id #${snapshotId} failed to revert`);
|
||||
}
|
||||
|
@@ -2,52 +2,52 @@ import * as ethUtil from 'ethereumjs-util';
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
export class RPC {
|
||||
private url: string;
|
||||
private id: number;
|
||||
private _url: string;
|
||||
private _id: number;
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
this.id = 0;
|
||||
this._url = url;
|
||||
this._id = 0;
|
||||
}
|
||||
public async takeSnapshotAsync(): Promise<number> {
|
||||
const method = 'evm_snapshot';
|
||||
const params: any[] = [];
|
||||
const payload = this.toPayload(method, params);
|
||||
const snapshotIdHex = await this.sendAsync(payload);
|
||||
const payload = this._toPayload(method, params);
|
||||
const snapshotIdHex = await this._sendAsync(payload);
|
||||
const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
|
||||
return snapshotId;
|
||||
}
|
||||
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
|
||||
const method = 'evm_revert';
|
||||
const params = [snapshotId];
|
||||
const payload = this.toPayload(method, params);
|
||||
const didRevert = await this.sendAsync(payload);
|
||||
const payload = this._toPayload(method, params);
|
||||
const didRevert = await this._sendAsync(payload);
|
||||
return didRevert;
|
||||
}
|
||||
public async increaseTimeAsync(time: number) {
|
||||
const method = 'evm_increaseTime';
|
||||
const params = [time];
|
||||
const payload = this.toPayload(method, params);
|
||||
return this.sendAsync(payload);
|
||||
const payload = this._toPayload(method, params);
|
||||
return this._sendAsync(payload);
|
||||
}
|
||||
public async mineBlockAsync(): Promise<void> {
|
||||
const method = 'evm_mine';
|
||||
const params: any[] = [];
|
||||
const payload = this.toPayload(method, params);
|
||||
await this.sendAsync(payload);
|
||||
const payload = this._toPayload(method, params);
|
||||
await this._sendAsync(payload);
|
||||
}
|
||||
private toPayload(method: string, params: any[] = []): string {
|
||||
private _toPayload(method: string, params: any[] = []): string {
|
||||
const payload = JSON.stringify({
|
||||
id: this.id,
|
||||
id: this._id,
|
||||
method,
|
||||
params,
|
||||
});
|
||||
this.id += 1;
|
||||
this._url += 1;
|
||||
return payload;
|
||||
}
|
||||
private async sendAsync(payload: string): Promise<any> {
|
||||
private async _sendAsync(payload: string): Promise<any> {
|
||||
const opts = {
|
||||
method: 'POST',
|
||||
uri: this.url,
|
||||
uri: this._url,
|
||||
body: payload,
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/json-schemas",
|
||||
"version": "0.6.10",
|
||||
"version": "0.7.1",
|
||||
"description": "0x-related json schemas",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
@@ -27,8 +27,8 @@
|
||||
"lodash.values": "^4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"@types/lodash.foreach": "^4.5.3",
|
||||
"@types/lodash.values": "^4.3.3",
|
||||
"@types/mocha": "^2.2.42",
|
||||
|
@@ -4,15 +4,15 @@ import values = require('lodash.values');
|
||||
import {schemas} from './schemas';
|
||||
|
||||
export class SchemaValidator {
|
||||
private validator: Validator;
|
||||
private _validator: Validator;
|
||||
constructor() {
|
||||
this.validator = new Validator();
|
||||
this._validator = new Validator();
|
||||
for (const schema of values(schemas)) {
|
||||
this.validator.addSchema(schema, schema.id);
|
||||
this._validator.addSchema(schema, schema.id);
|
||||
}
|
||||
}
|
||||
public addSchema(schema: Schema) {
|
||||
this.validator.addSchema(schema, schema.id);
|
||||
this._validator.addSchema(schema, schema.id);
|
||||
}
|
||||
// In order to validate a complex JS object using jsonschema, we must replace any complex
|
||||
// sub-types (e.g BigNumber) with a simpler string representation. Since BigNumber and other
|
||||
@@ -20,7 +20,7 @@ export class SchemaValidator {
|
||||
// then parse it. The resultant object can then be checked using jsonschema.
|
||||
public validate(instance: any, schema: Schema): ValidatorResult {
|
||||
const jsonSchemaCompatibleObject = JSON.parse(JSON.stringify(instance));
|
||||
return this.validator.validate(jsonSchemaCompatibleObject, schema);
|
||||
return this._validator.validate(jsonSchemaCompatibleObject, schema);
|
||||
}
|
||||
public isValid(instance: any, schema: Schema): boolean {
|
||||
const isValid = this.validate(instance, schema).errors.length === 0;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@0xproject/kovan_faucets",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.2",
|
||||
"description": "A faucet micro-service that dispenses test ERC20 tokens or Ether",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
@@ -14,8 +14,8 @@
|
||||
"author": "Fabio Berger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"0x.js": "~0.27.2",
|
||||
"0x.js": "^0.29.0",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"body-parser": "^1.17.1",
|
||||
"ethereumjs-tx": "^1.3.3",
|
||||
@@ -26,7 +26,7 @@
|
||||
"web3-provider-engine": "^13.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/body-parser": "^1.16.1",
|
||||
"@types/express": "^4.0.35",
|
||||
"@types/lodash": "^4.14.86",
|
||||
|
@@ -18,25 +18,25 @@ import {ZRXRequestQueue} from './zrx_request_queue';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
export class Handler {
|
||||
private etherRequestQueue: EtherRequestQueue;
|
||||
private zrxRequestQueue: ZRXRequestQueue;
|
||||
private web3: Web3;
|
||||
private _etherRequestQueue: EtherRequestQueue;
|
||||
private _zrxRequestQueue: ZRXRequestQueue;
|
||||
private _web3: Web3;
|
||||
constructor() {
|
||||
// Setup provider engine to talk with RPC node
|
||||
const providerObj = this.createProviderEngine(configs.RPC_URL);
|
||||
this.web3 = new Web3(providerObj);
|
||||
const providerObj = this._createProviderEngine(configs.RPC_URL);
|
||||
this._web3 = new Web3(providerObj);
|
||||
|
||||
this.etherRequestQueue = new EtherRequestQueue(this.web3);
|
||||
this.zrxRequestQueue = new ZRXRequestQueue(this.web3);
|
||||
this._etherRequestQueue = new EtherRequestQueue(this._web3);
|
||||
this._zrxRequestQueue = new ZRXRequestQueue(this._web3);
|
||||
}
|
||||
public dispenseEther(req: express.Request, res: express.Response) {
|
||||
const recipientAddress = req.params.recipient;
|
||||
if (_.isUndefined(recipientAddress) || !this.isValidEthereumAddress(recipientAddress)) {
|
||||
if (_.isUndefined(recipientAddress) || !this._isValidEthereumAddress(recipientAddress)) {
|
||||
res.status(400).send('INVALID_REQUEST');
|
||||
return;
|
||||
}
|
||||
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
||||
const didAddToQueue = this.etherRequestQueue.add(lowerCaseRecipientAddress);
|
||||
const didAddToQueue = this._etherRequestQueue.add(lowerCaseRecipientAddress);
|
||||
if (!didAddToQueue) {
|
||||
res.status(503).send('QUEUE_IS_FULL');
|
||||
return;
|
||||
@@ -46,12 +46,12 @@ export class Handler {
|
||||
}
|
||||
public dispenseZRX(req: express.Request, res: express.Response) {
|
||||
const recipientAddress = req.params.recipient;
|
||||
if (_.isUndefined(recipientAddress) || !this.isValidEthereumAddress(recipientAddress)) {
|
||||
if (_.isUndefined(recipientAddress) || !this._isValidEthereumAddress(recipientAddress)) {
|
||||
res.status(400).send('INVALID_REQUEST');
|
||||
return;
|
||||
}
|
||||
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
||||
const didAddToQueue = this.zrxRequestQueue.add(lowerCaseRecipientAddress);
|
||||
const didAddToQueue = this._zrxRequestQueue.add(lowerCaseRecipientAddress);
|
||||
if (!didAddToQueue) {
|
||||
res.status(503).send('QUEUE_IS_FULL');
|
||||
return;
|
||||
@@ -63,18 +63,18 @@ export class Handler {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
const payload = JSON.stringify({
|
||||
ether: {
|
||||
full: this.etherRequestQueue.isFull(),
|
||||
size: this.etherRequestQueue.size(),
|
||||
full: this._etherRequestQueue.isFull(),
|
||||
size: this._etherRequestQueue.size(),
|
||||
},
|
||||
zrx: {
|
||||
full: this.zrxRequestQueue.isFull(),
|
||||
size: this.zrxRequestQueue.size(),
|
||||
full: this._zrxRequestQueue.isFull(),
|
||||
size: this._zrxRequestQueue.size(),
|
||||
},
|
||||
});
|
||||
res.status(200).send(payload);
|
||||
}
|
||||
// tslint:disable-next-line:prefer-function-over-method
|
||||
private createProviderEngine(rpcUrl: string) {
|
||||
private _createProviderEngine(rpcUrl: string) {
|
||||
const engine = new ProviderEngine();
|
||||
engine.addProvider(new NonceSubprovider());
|
||||
engine.addProvider(new HookedWalletSubprovider(idManagement));
|
||||
@@ -84,8 +84,8 @@ export class Handler {
|
||||
engine.start();
|
||||
return engine;
|
||||
}
|
||||
private isValidEthereumAddress(address: string): boolean {
|
||||
private _isValidEthereumAddress(address: string): boolean {
|
||||
const lowercaseAddress = address.toLowerCase();
|
||||
return this.web3.isAddress(lowercaseAddress);
|
||||
return this._web3.isAddress(lowercaseAddress);
|
||||
}
|
||||
}
|
||||
|
@@ -17,20 +17,20 @@ const DISPENSE_AMOUNT_ZRX = new BigNumber(0.1);
|
||||
const QUEUE_INTERVAL_MS = 5000;
|
||||
|
||||
export class ZRXRequestQueue extends RequestQueue {
|
||||
private zeroEx: ZeroEx;
|
||||
private _zeroEx: ZeroEx;
|
||||
constructor(web3: Web3) {
|
||||
super(web3);
|
||||
this.queueIntervalMs = QUEUE_INTERVAL_MS;
|
||||
const zeroExConfig = {
|
||||
networkId: configs.KOVAN_NETWORK_ID,
|
||||
};
|
||||
this.zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
|
||||
this._zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
|
||||
}
|
||||
protected async processNextRequestFireAndForgetAsync(recipientAddress: string) {
|
||||
utils.consoleLog(`Processing ZRX ${recipientAddress}`);
|
||||
const baseUnitAmount = ZeroEx.toBaseUnitAmount(DISPENSE_AMOUNT_ZRX, 18);
|
||||
try {
|
||||
await this.zeroEx.token.transferAsync(
|
||||
await this._zeroEx.token.transferAsync(
|
||||
configs.ZRX_TOKEN_ADDRESS, configs.DISPENSER_ADDRESS, recipientAddress, baseUnitAmount,
|
||||
);
|
||||
utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ZRX} ZRX to ${recipientAddress}`);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/monorepo-scripts",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"private": true,
|
||||
"description": "Helper scripts for the monorepo",
|
||||
"scripts": {
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/monorepo-scripts/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/glob": "^5.0.33",
|
||||
"@types/node": "^8.0.53",
|
||||
"shx": "^0.2.2",
|
||||
|
@@ -1,5 +1,9 @@
|
||||
# CHANGELOG
|
||||
|
||||
v0.3.0 - _December 28, 2017_
|
||||
------------------------
|
||||
* Allow LedgerSubprovider to handle `eth_sign` in addition to `personal_sign` RPC requests
|
||||
|
||||
v0.2.0 - _December 20, 2017_
|
||||
------------------------
|
||||
* Improve the performance of address fetching (#271)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/subproviders",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -17,8 +17,8 @@
|
||||
"test:integration": "run-s clean build run_mocha_integration"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.0.7",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/assert": "^0.0.9",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"bn.js": "^4.11.8",
|
||||
"es6-promisify": "^5.0.0",
|
||||
"ethereumjs-tx": "^1.3.3",
|
||||
@@ -31,8 +31,8 @@
|
||||
"web3-provider-engine": "^13.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^8.0.53",
|
||||
|
@@ -9,29 +9,29 @@ import Web3ProviderEngine = require('web3-provider-engine');
|
||||
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||
*/
|
||||
export class InjectedWeb3Subprovider {
|
||||
private injectedWeb3: Web3;
|
||||
private _injectedWeb3: Web3;
|
||||
constructor(injectedWeb3: Web3) {
|
||||
this.injectedWeb3 = injectedWeb3;
|
||||
this._injectedWeb3 = injectedWeb3;
|
||||
}
|
||||
public handleRequest(
|
||||
payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result: any) => void,
|
||||
) {
|
||||
switch (payload.method) {
|
||||
case 'web3_clientVersion':
|
||||
this.injectedWeb3.version.getNode(end);
|
||||
this._injectedWeb3.version.getNode(end);
|
||||
return;
|
||||
case 'eth_accounts':
|
||||
this.injectedWeb3.eth.getAccounts(end);
|
||||
this._injectedWeb3.eth.getAccounts(end);
|
||||
return;
|
||||
|
||||
case 'eth_sendTransaction':
|
||||
const [txParams] = payload.params;
|
||||
this.injectedWeb3.eth.sendTransaction(txParams, end);
|
||||
this._injectedWeb3.eth.sendTransaction(txParams, end);
|
||||
return;
|
||||
|
||||
case 'eth_sign':
|
||||
const [address, message] = payload.params;
|
||||
this.injectedWeb3.eth.sign(address, message, end);
|
||||
this._injectedWeb3.eth.sign(address, message, end);
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@@ -32,7 +32,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
private _ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync;
|
||||
private _ledgerClientIfExists?: LedgerEthereumClient;
|
||||
private _shouldAlwaysAskForConfirmation: boolean;
|
||||
private static validateSender(sender: string) {
|
||||
private static _validateSender(sender: string) {
|
||||
if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) {
|
||||
throw new Error(LedgerSubproviderErrors.SenderInvalidOrNotSupplied);
|
||||
}
|
||||
@@ -88,8 +88,8 @@ export class LedgerSubprovider extends Subprovider {
|
||||
case 'eth_sendTransaction':
|
||||
txParams = payload.params[0];
|
||||
try {
|
||||
LedgerSubprovider.validateSender(txParams.from);
|
||||
const result = await this.sendTransactionAsync(txParams);
|
||||
LedgerSubprovider._validateSender(txParams.from);
|
||||
const result = await this._sendTransactionAsync(txParams);
|
||||
end(null, result);
|
||||
} catch (err) {
|
||||
end(err);
|
||||
@@ -99,15 +99,16 @@ export class LedgerSubprovider extends Subprovider {
|
||||
case 'eth_signTransaction':
|
||||
txParams = payload.params[0];
|
||||
try {
|
||||
const result = await this.signTransactionWithoutSendingAsync(txParams);
|
||||
const result = await this._signTransactionWithoutSendingAsync(txParams);
|
||||
end(null, result);
|
||||
} catch (err) {
|
||||
end(err);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'eth_sign':
|
||||
case 'personal_sign':
|
||||
const data = payload.params[0];
|
||||
const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0];
|
||||
try {
|
||||
if (_.isUndefined(data)) {
|
||||
throw new Error(LedgerSubproviderErrors.DataMissingForSignPersonalMessage);
|
||||
@@ -126,7 +127,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
}
|
||||
}
|
||||
public async getAccountsAsync(): Promise<string[]> {
|
||||
this._ledgerClientIfExists = await this.createLedgerClientAsync();
|
||||
this._ledgerClientIfExists = await this._createLedgerClientAsync();
|
||||
|
||||
let ledgerResponse;
|
||||
try {
|
||||
@@ -134,7 +135,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
this._derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE,
|
||||
);
|
||||
} finally {
|
||||
await this.destoryLedgerClientAsync();
|
||||
await this._destroyLedgerClientAsync();
|
||||
}
|
||||
|
||||
const hdKey = new HDNode();
|
||||
@@ -155,7 +156,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
return accounts;
|
||||
}
|
||||
public async signTransactionAsync(txParams: PartialTxParams): Promise<string> {
|
||||
this._ledgerClientIfExists = await this.createLedgerClientAsync();
|
||||
this._ledgerClientIfExists = await this._createLedgerClientAsync();
|
||||
|
||||
const tx = new EthereumTx(txParams);
|
||||
|
||||
@@ -166,7 +167,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
|
||||
const txHex = tx.serialize().toString('hex');
|
||||
try {
|
||||
const derivationPath = this.getDerivationPath();
|
||||
const derivationPath = this._getDerivationPath();
|
||||
const result = await this._ledgerClientIfExists.signTransaction_async(derivationPath, txHex);
|
||||
// Store signature in transaction
|
||||
tx.r = Buffer.from(result.r, 'hex');
|
||||
@@ -176,23 +177,23 @@ export class LedgerSubprovider extends Subprovider {
|
||||
// EIP155: v should be chain_id * 2 + {35, 36}
|
||||
const signedChainId = Math.floor((tx.v[0] - 35) / 2);
|
||||
if (signedChainId !== this._networkId) {
|
||||
await this.destoryLedgerClientAsync();
|
||||
await this._destroyLedgerClientAsync();
|
||||
const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware);
|
||||
throw err;
|
||||
}
|
||||
|
||||
const signedTxHex = `0x${tx.serialize().toString('hex')}`;
|
||||
await this.destoryLedgerClientAsync();
|
||||
await this._destroyLedgerClientAsync();
|
||||
return signedTxHex;
|
||||
} catch (err) {
|
||||
await this.destoryLedgerClientAsync();
|
||||
await this._destroyLedgerClientAsync();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
public async signPersonalMessageAsync(data: string): Promise<string> {
|
||||
this._ledgerClientIfExists = await this.createLedgerClientAsync();
|
||||
this._ledgerClientIfExists = await this._createLedgerClientAsync();
|
||||
try {
|
||||
const derivationPath = this.getDerivationPath();
|
||||
const derivationPath = this._getDerivationPath();
|
||||
const result = await this._ledgerClientIfExists.signPersonalMessage_async(
|
||||
derivationPath, ethUtil.stripHexPrefix(data));
|
||||
const v = result.v - 27;
|
||||
@@ -201,18 +202,18 @@ export class LedgerSubprovider extends Subprovider {
|
||||
vHex = `0${v}`;
|
||||
}
|
||||
const signature = `0x${result.r}${result.s}${vHex}`;
|
||||
await this.destoryLedgerClientAsync();
|
||||
await this._destroyLedgerClientAsync();
|
||||
return signature;
|
||||
} catch (err) {
|
||||
await this.destoryLedgerClientAsync();
|
||||
await this._destroyLedgerClientAsync();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
private getDerivationPath() {
|
||||
private _getDerivationPath() {
|
||||
const derivationPath = `${this.getPath()}/${this._derivationPathIndex}`;
|
||||
return derivationPath;
|
||||
}
|
||||
private async createLedgerClientAsync(): Promise<LedgerEthereumClient> {
|
||||
private async _createLedgerClientAsync(): Promise<LedgerEthereumClient> {
|
||||
await this._connectionLock.wait();
|
||||
if (!_.isUndefined(this._ledgerClientIfExists)) {
|
||||
this._connectionLock.signal();
|
||||
@@ -222,7 +223,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
this._connectionLock.signal();
|
||||
return ledgerEthereumClient;
|
||||
}
|
||||
private async destoryLedgerClientAsync() {
|
||||
private async _destroyLedgerClientAsync() {
|
||||
await this._connectionLock.wait();
|
||||
if (_.isUndefined(this._ledgerClientIfExists)) {
|
||||
this._connectionLock.signal();
|
||||
@@ -232,11 +233,11 @@ export class LedgerSubprovider extends Subprovider {
|
||||
this._ledgerClientIfExists = undefined;
|
||||
this._connectionLock.signal();
|
||||
}
|
||||
private async sendTransactionAsync(txParams: PartialTxParams): Promise<Web3.JSONRPCResponsePayload> {
|
||||
private async _sendTransactionAsync(txParams: PartialTxParams): Promise<Web3.JSONRPCResponsePayload> {
|
||||
await this._nonceLock.wait();
|
||||
try {
|
||||
// fill in the extras
|
||||
const filledParams = await this.populateMissingTxParamsAsync(txParams);
|
||||
const filledParams = await this._populateMissingTxParamsAsync(txParams);
|
||||
// sign it
|
||||
const signedTx = await this.signTransactionAsync(filledParams);
|
||||
// emit a submit
|
||||
@@ -252,11 +253,11 @@ export class LedgerSubprovider extends Subprovider {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
private async signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> {
|
||||
private async _signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> {
|
||||
await this._nonceLock.wait();
|
||||
try {
|
||||
// fill in the extras
|
||||
const filledParams = await this.populateMissingTxParamsAsync(txParams);
|
||||
const filledParams = await this._populateMissingTxParamsAsync(txParams);
|
||||
// sign it
|
||||
const signedTx = await this.signTransactionAsync(filledParams);
|
||||
|
||||
@@ -271,7 +272,7 @@ export class LedgerSubprovider extends Subprovider {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
private async populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> {
|
||||
private async _populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> {
|
||||
if (_.isUndefined(txParams.gasPrice)) {
|
||||
const gasPriceResult = await this.emitPayloadAsync({
|
||||
method: 'eth_gasPrice',
|
||||
|
@@ -7,8 +7,8 @@ import {JSONRPCPayload} from '../types';
|
||||
import {Subprovider} from './subprovider';
|
||||
|
||||
export class RedundantRPCSubprovider extends Subprovider {
|
||||
private rpcs: RpcSubprovider[];
|
||||
private static async firstSuccessAsync(
|
||||
private _rpcs: RpcSubprovider[];
|
||||
private static async _firstSuccessAsync(
|
||||
rpcs: RpcSubprovider[], payload: JSONRPCPayload, next: () => void,
|
||||
): Promise<any> {
|
||||
let lastErr: Error|undefined;
|
||||
@@ -27,7 +27,7 @@ export class RedundantRPCSubprovider extends Subprovider {
|
||||
}
|
||||
constructor(endpoints: string[]) {
|
||||
super();
|
||||
this.rpcs = _.map(endpoints, endpoint => {
|
||||
this._rpcs = _.map(endpoints, endpoint => {
|
||||
return new RpcSubprovider({
|
||||
rpcUrl: endpoint,
|
||||
});
|
||||
@@ -36,9 +36,9 @@ export class RedundantRPCSubprovider extends Subprovider {
|
||||
// tslint:disable-next-line:async-suffix
|
||||
public async handleRequest(payload: JSONRPCPayload, next: () => void,
|
||||
end: (err: Error|null, data?: any) => void): Promise<void> {
|
||||
const rpcsCopy = this.rpcs.slice();
|
||||
const rpcsCopy = this._rpcs.slice();
|
||||
try {
|
||||
const data = await RedundantRPCSubprovider.firstSuccessAsync(rpcsCopy, payload, next);
|
||||
const data = await RedundantRPCSubprovider._firstSuccessAsync(rpcsCopy, payload, next);
|
||||
end(null, data);
|
||||
} catch (err) {
|
||||
end(err);
|
||||
|
@@ -10,9 +10,9 @@ import {
|
||||
* Altered version of: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||
*/
|
||||
export class Subprovider {
|
||||
private engine: any;
|
||||
private _engine: any;
|
||||
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
|
||||
private static getRandomId() {
|
||||
private static _getRandomId() {
|
||||
const extraDigits = 3;
|
||||
// 13 time digits
|
||||
const datePart = new Date().getTime() * Math.pow(10, extraDigits);
|
||||
@@ -21,10 +21,10 @@ export class Subprovider {
|
||||
// 16 digits
|
||||
return datePart + extraPart;
|
||||
}
|
||||
private static createFinalPayload(payload: JSONRPCPayload): Web3.JSONRPCRequestPayload {
|
||||
private static _createFinalPayload(payload: JSONRPCPayload): Web3.JSONRPCRequestPayload {
|
||||
const finalPayload = {
|
||||
// defaults
|
||||
id: Subprovider.getRandomId(),
|
||||
id: Subprovider._getRandomId(),
|
||||
jsonrpc: '2.0',
|
||||
params: [],
|
||||
...payload,
|
||||
@@ -32,11 +32,11 @@ export class Subprovider {
|
||||
return finalPayload;
|
||||
}
|
||||
public setEngine(engine: any): void {
|
||||
this.engine = engine;
|
||||
this._engine = engine;
|
||||
}
|
||||
public async emitPayloadAsync(payload: JSONRPCPayload): Promise<any> {
|
||||
const finalPayload = Subprovider.createFinalPayload(payload);
|
||||
const response = await promisify(this.engine.sendAsync, this.engine)(finalPayload);
|
||||
const finalPayload = Subprovider._createFinalPayload(payload);
|
||||
const response = await promisify(this._engine.sendAsync, this._engine)(finalPayload);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@@ -85,7 +85,27 @@ describe('LedgerSubprovider', () => {
|
||||
});
|
||||
ledgerProvider.sendAsync(payload, callback);
|
||||
});
|
||||
it('signs a personal message', (done: DoneCallback) => {
|
||||
it('signs a personal message with eth_sign', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
|
||||
const accounts = await ledgerSubprovider.getAccountsAsync();
|
||||
const signer = accounts[0];
|
||||
const payload = {
|
||||
jsonrpc: '2.0',
|
||||
method: 'eth_sign',
|
||||
params: [signer, messageHex],
|
||||
id: 1,
|
||||
};
|
||||
const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => {
|
||||
expect(err).to.be.a('null');
|
||||
expect(response.result.length).to.be.equal(132);
|
||||
expect(response.result.substr(0, 2)).to.be.equal('0x');
|
||||
done();
|
||||
});
|
||||
ledgerProvider.sendAsync(payload, callback);
|
||||
})().catch(done);
|
||||
});
|
||||
it('signs a personal message with personal_sign', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
|
||||
const accounts = await ledgerSubprovider.getAccountsAsync();
|
||||
|
@@ -117,7 +117,23 @@ describe('LedgerSubprovider', () => {
|
||||
});
|
||||
provider.sendAsync(payload, callback);
|
||||
});
|
||||
it('signs a personal message', (done: DoneCallback) => {
|
||||
it('signs a personal message with eth_sign', (done: DoneCallback) => {
|
||||
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
|
||||
const payload = {
|
||||
jsonrpc: '2.0',
|
||||
method: 'eth_sign',
|
||||
params: ['0x0000000000000000000000000000000000000000', messageHex],
|
||||
id: 1,
|
||||
};
|
||||
const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => {
|
||||
expect(err).to.be.a('null');
|
||||
// tslint:disable-next-line:max-line-length
|
||||
expect(response.result).to.be.equal('0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001');
|
||||
done();
|
||||
});
|
||||
provider.sendAsync(payload, callback);
|
||||
});
|
||||
it('signs a personal message with personal_sign', (done: DoneCallback) => {
|
||||
const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world'));
|
||||
const payload = {
|
||||
jsonrpc: '2.0',
|
||||
@@ -157,6 +173,21 @@ describe('LedgerSubprovider', () => {
|
||||
});
|
||||
});
|
||||
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: Web3.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 = {
|
||||
|
@@ -1,5 +1,10 @@
|
||||
# CHANGELOG
|
||||
|
||||
v0.4.0 - _December 28, 2017_
|
||||
------------------------
|
||||
* Added custom 'underscore-privates' rule, requiring underscores to be prepended to private variable names
|
||||
* Because our tools can be used in both a TS and JS environment, we want to make the private methods of any public facing interface show up at the bottom of auto-complete lists. Additionally, we wanted to remain consistent with respect to our usage of underscores in order to enforce this rule with a linter rule, rather then manual code reviews.
|
||||
|
||||
v0.3.0 - _December 20, 2017_
|
||||
------------------------
|
||||
* Added rules for unused imports, variables and Async suffixes (#265)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/tslint-config",
|
||||
"version": "0.2.1",
|
||||
"version": "0.4.0",
|
||||
"description": "Lint rules related to 0xProject for TSLint",
|
||||
"main": "tslint.json",
|
||||
"scripts": {
|
||||
|
61
packages/tslint-config/rules/underscorePrivatesRule.ts
Normal file
61
packages/tslint-config/rules/underscorePrivatesRule.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as Lint from 'tslint';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const UNDERSCORE = '_';
|
||||
|
||||
type RelevantClassMember =
|
||||
| ts.MethodDeclaration
|
||||
| ts.PropertyDeclaration
|
||||
| ts.GetAccessorDeclaration
|
||||
| ts.SetAccessorDeclaration;
|
||||
|
||||
// Copied from: https://github.com/DanielRosenwasser/underscore-privates-tslint-rule
|
||||
// The version on github is not published on npm
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static FAILURE_STRING = 'private members must be prefixed with an underscore';
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
traverse(ctx.sourceFile);
|
||||
|
||||
function traverse(node: ts.Node): void {
|
||||
checkNodeForViolations(ctx, node);
|
||||
return ts.forEachChild(node, traverse);
|
||||
}
|
||||
}
|
||||
function checkNodeForViolations(ctx: Lint.WalkContext<void>, node: ts.Node): void {
|
||||
if (!isRelevantClassMember(node)) {
|
||||
return;
|
||||
}
|
||||
// The declaration might have a computed property name or a numeric name.
|
||||
const name = node.name;
|
||||
if (!nameIsIdentifier(name)) {
|
||||
return;
|
||||
}
|
||||
if (!nameStartsWithUnderscore(name.text) && memberIsPrivate(node)) {
|
||||
ctx.addFailureAtNode(name, Rule.FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
function isRelevantClassMember(node: ts.Node): node is RelevantClassMember {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.MethodDeclaration:
|
||||
case ts.SyntaxKind.PropertyDeclaration:
|
||||
case ts.SyntaxKind.GetAccessor:
|
||||
case ts.SyntaxKind.SetAccessor:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function nameStartsWithUnderscore(text: string) {
|
||||
return text.charCodeAt(0) === UNDERSCORE.charCodeAt(0);
|
||||
}
|
||||
function memberIsPrivate(node: ts.Declaration) {
|
||||
return Lint.hasModifier(node.modifiers, ts.SyntaxKind.PrivateKeyword);
|
||||
}
|
||||
function nameIsIdentifier(node: ts.Node): node is ts.Identifier {
|
||||
return node.kind === ts.SyntaxKind.Identifier;
|
||||
}
|
@@ -81,6 +81,7 @@
|
||||
],
|
||||
"space-within-parens": false,
|
||||
"type-literal-delimiter": true,
|
||||
"underscore-privates": true,
|
||||
"variable-name": [true,
|
||||
"ban-keywords",
|
||||
"allow-pascal-case"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/types",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"description": "0x types",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/types/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"bignumber.js": "^5.0.0",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/utils",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"description": "0x TS utils",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/web3-wrapper",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"description": "Wraps around web3 and gives a nicer interface",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -19,8 +19,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/web3-wrapper/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/types": "^0.1.0",
|
||||
"@0xproject/tslint-config": "^0.4.0",
|
||||
"@0xproject/types": "^0.1.2",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
@@ -29,7 +29,7 @@
|
||||
"web3-typescript-typings": "^0.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"lodash": "^4.17.4",
|
||||
"web3": "^0.20.0"
|
||||
|
@@ -1,5 +1,8 @@
|
||||
import {TransactionReceipt, TxData} from '@0xproject/types';
|
||||
import {promisify} from '@0xproject/utils';
|
||||
import {
|
||||
bigNumberConfigs,
|
||||
promisify,
|
||||
} from '@0xproject/utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
@@ -15,10 +18,13 @@ interface RawLogEntry {
|
||||
topics: string[];
|
||||
}
|
||||
|
||||
// Customize our BigNumber instances
|
||||
bigNumberConfigs.configure();
|
||||
|
||||
export class Web3Wrapper {
|
||||
private web3: Web3;
|
||||
private defaults: Partial<TxData>;
|
||||
private jsonRpcRequestId: number;
|
||||
private _web3: Web3;
|
||||
private _defaults: Partial<TxData>;
|
||||
private _jsonRpcRequestId: number;
|
||||
constructor(provider: Web3.Provider, defaults?: Partial<TxData>) {
|
||||
if (_.isUndefined((provider as any).sendAsync)) {
|
||||
// Web3@1.0 provider doesn't support synchronous http requests,
|
||||
@@ -26,69 +32,69 @@ export class Web3Wrapper {
|
||||
// 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.web3.setProvider(provider);
|
||||
this.defaults = defaults || {};
|
||||
this.jsonRpcRequestId = 0;
|
||||
this._web3 = new Web3();
|
||||
this._web3.setProvider(provider);
|
||||
this._defaults = defaults || {};
|
||||
this._jsonRpcRequestId = 0;
|
||||
}
|
||||
public getContractDefaults(): Partial<TxData> {
|
||||
return this.defaults;
|
||||
return this._defaults;
|
||||
}
|
||||
public setProvider(provider: Web3.Provider, networkId: number) {
|
||||
this.web3.setProvider(provider);
|
||||
this._web3.setProvider(provider);
|
||||
}
|
||||
public isAddress(address: string): boolean {
|
||||
return this.web3.isAddress(address);
|
||||
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)();
|
||||
const nodeVersion = await promisify<string>(this._web3.version.getNode)();
|
||||
return nodeVersion;
|
||||
}
|
||||
public async getNetworkIdAsync(): Promise<number> {
|
||||
const networkIdStr = await promisify<string>(this.web3.version.getNetwork)();
|
||||
const networkIdStr = await promisify<string>(this._web3.version.getNetwork)();
|
||||
const networkId = _.parseInt(networkIdStr);
|
||||
return networkId;
|
||||
}
|
||||
public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
|
||||
const transactionReceipt = await promisify<TransactionReceipt>(this.web3.eth.getTransactionReceipt)(txHash);
|
||||
const transactionReceipt = await promisify<TransactionReceipt>(this._web3.eth.getTransactionReceipt)(txHash);
|
||||
if (!_.isNull(transactionReceipt)) {
|
||||
transactionReceipt.status = this.normalizeTxReceiptStatus(transactionReceipt.status);
|
||||
transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status);
|
||||
}
|
||||
return transactionReceipt;
|
||||
}
|
||||
public getCurrentProvider(): Web3.Provider {
|
||||
return this.web3.currentProvider;
|
||||
return this._web3.currentProvider;
|
||||
}
|
||||
public toWei(ethAmount: BigNumber): BigNumber {
|
||||
const balanceWei = this.web3.toWei(ethAmount, 'ether');
|
||||
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);
|
||||
let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
|
||||
// Rewrap in a new BigNumber
|
||||
balanceInWei = new BigNumber(balanceInWei);
|
||||
return balanceInWei;
|
||||
}
|
||||
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
|
||||
const code = await promisify<string>(this.web3.eth.getCode)(address);
|
||||
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);
|
||||
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)();
|
||||
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);
|
||||
const block = await promisify<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockParam);
|
||||
return block;
|
||||
}
|
||||
public async getBlockTimestampAsync(blockParam: string|Web3.BlockParam): Promise<number> {
|
||||
@@ -96,17 +102,17 @@ export class Web3Wrapper {
|
||||
return timestamp;
|
||||
}
|
||||
public async getAvailableAddressesAsync(): Promise<string[]> {
|
||||
const addresses = await promisify<string[]>(this.web3.eth.getAccounts)();
|
||||
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);
|
||||
fromBlock = this._web3.toHex(fromBlock);
|
||||
}
|
||||
let toBlock = filter.toBlock;
|
||||
if (_.isNumber(toBlock)) {
|
||||
toBlock = this.web3.toHex(toBlock);
|
||||
toBlock = this._web3.toHex(toBlock);
|
||||
}
|
||||
const serializedFilter = {
|
||||
...filter,
|
||||
@@ -115,16 +121,16 @@ export class Web3Wrapper {
|
||||
};
|
||||
const payload = {
|
||||
jsonrpc: '2.0',
|
||||
id: this.jsonRpcRequestId++,
|
||||
id: this._jsonRpcRequestId++,
|
||||
method: 'eth_getLogs',
|
||||
params: [serializedFilter],
|
||||
};
|
||||
const rawLogs = await this.sendRawPayloadAsync<RawLogEntry[]>(payload);
|
||||
const formattedLogs = _.map(rawLogs, this.formatLog.bind(this));
|
||||
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);
|
||||
const web3Contract = this._web3.eth.contract(abi);
|
||||
return web3Contract;
|
||||
}
|
||||
public getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance {
|
||||
@@ -132,43 +138,43 @@ export class Web3Wrapper {
|
||||
return web3ContractInstance;
|
||||
}
|
||||
public async estimateGasAsync(data: string): Promise<number> {
|
||||
const gas = await promisify<number>(this.web3.eth.estimateGas)({data});
|
||||
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);
|
||||
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 {
|
||||
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;
|
||||
return this._web3.toDecimal(status) as 0|1;
|
||||
} else if (_.isUndefined(status)) {
|
||||
return null;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
private formatLog(rawLog: RawLogEntry): Web3.LogEntry {
|
||||
private _formatLog(rawLog: RawLogEntry): Web3.LogEntry {
|
||||
const formattedLog = {
|
||||
...rawLog,
|
||||
logIndex: this.hexToDecimal(rawLog.logIndex),
|
||||
blockNumber: this.hexToDecimal(rawLog.blockNumber),
|
||||
transactionIndex: this.hexToDecimal(rawLog.transactionIndex),
|
||||
logIndex: this._hexToDecimal(rawLog.logIndex),
|
||||
blockNumber: this._hexToDecimal(rawLog.blockNumber),
|
||||
transactionIndex: this._hexToDecimal(rawLog.transactionIndex),
|
||||
};
|
||||
return formattedLog;
|
||||
}
|
||||
private hexToDecimal(hex: string|null): number|null {
|
||||
private _hexToDecimal(hex: string|null): number|null {
|
||||
if (_.isNull(hex)) {
|
||||
return null;
|
||||
}
|
||||
const decimal = this.web3.toDecimal(hex);
|
||||
const decimal = this._web3.toDecimal(hex);
|
||||
return decimal;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/website",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.4",
|
||||
"private": true,
|
||||
"description": "Website and 0x portal dapp",
|
||||
"scripts": {
|
||||
@@ -18,9 +18,9 @@
|
||||
"author": "Fabio Berger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"0x.js": "~0.27.2",
|
||||
"@0xproject/subproviders": "^0.1.0",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"0x.js": "^0.29.0",
|
||||
"@0xproject/subproviders": "^0.2.0",
|
||||
"@0xproject/utils": "^0.1.2",
|
||||
"accounting": "^0.4.1",
|
||||
"basscss": "^8.0.3",
|
||||
"bignumber.js": "~4.1.0",
|
||||
|
@@ -59,15 +59,15 @@ const BLOCK_NUMBER_BACK_TRACK = 50;
|
||||
export class Blockchain {
|
||||
public networkId: number;
|
||||
public nodeVersion: string;
|
||||
private zeroEx: ZeroEx;
|
||||
private dispatcher: Dispatcher;
|
||||
private web3Wrapper?: Web3Wrapper;
|
||||
private exchangeAddress: string;
|
||||
private userAddress: string;
|
||||
private cachedProvider: Web3.Provider;
|
||||
private ledgerSubprovider: LedgerWalletSubprovider;
|
||||
private zrxPollIntervalId: NodeJS.Timer;
|
||||
private static async onPageLoadAsync() {
|
||||
private _zeroEx: ZeroEx;
|
||||
private _dispatcher: Dispatcher;
|
||||
private _web3Wrapper?: Web3Wrapper;
|
||||
private _exchangeAddress: string;
|
||||
private _userAddress: string;
|
||||
private _cachedProvider: Web3.Provider;
|
||||
private _ledgerSubprovider: LedgerWalletSubprovider;
|
||||
private _zrxPollIntervalId: NodeJS.Timer;
|
||||
private static async _onPageLoadAsync() {
|
||||
if (document.readyState === 'complete') {
|
||||
return; // Already loaded
|
||||
}
|
||||
@@ -75,7 +75,7 @@ export class Blockchain {
|
||||
window.onload = resolve;
|
||||
});
|
||||
}
|
||||
private static getNameGivenProvider(provider: Web3.Provider): string {
|
||||
private static _getNameGivenProvider(provider: Web3.Provider): string {
|
||||
if (!_.isUndefined((provider as any).isMetaMask)) {
|
||||
return constants.PROVIDER_NAME_METAMASK;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export class Blockchain {
|
||||
|
||||
return constants.PROVIDER_NAME_GENERIC;
|
||||
}
|
||||
private static async getProviderAsync(injectedWeb3: Web3, networkIdIfExists: number) {
|
||||
private static async _getProviderAsync(injectedWeb3: Web3, networkIdIfExists: number) {
|
||||
const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
||||
const publicNodeUrlsIfExistsForNetworkId = configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists];
|
||||
const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId);
|
||||
@@ -126,29 +126,29 @@ export class Blockchain {
|
||||
return provider;
|
||||
}
|
||||
constructor(dispatcher: Dispatcher, isSalePage: boolean = false) {
|
||||
this.dispatcher = dispatcher;
|
||||
this.userAddress = '';
|
||||
this._dispatcher = dispatcher;
|
||||
this._userAddress = '';
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.onPageLoadInitFireAndForgetAsync();
|
||||
this._onPageLoadInitFireAndForgetAsync();
|
||||
}
|
||||
public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number) {
|
||||
const isConnected = !_.isUndefined(newNetworkId);
|
||||
if (!isConnected) {
|
||||
this.networkId = newNetworkId;
|
||||
this.dispatcher.encounteredBlockchainError(BlockchainErrs.DisconnectedFromEthereumNode);
|
||||
this.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
this._dispatcher.encounteredBlockchainError(BlockchainErrs.DisconnectedFromEthereumNode);
|
||||
this._dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
} else if (this.networkId !== newNetworkId) {
|
||||
this.networkId = newNetworkId;
|
||||
this.dispatcher.encounteredBlockchainError(BlockchainErrs.NoError);
|
||||
await this.fetchTokenInformationAsync();
|
||||
await this.rehydrateStoreWithContractEvents();
|
||||
this._dispatcher.encounteredBlockchainError(BlockchainErrs.NoError);
|
||||
await this._fetchTokenInformationAsync();
|
||||
await this._rehydrateStoreWithContractEvents();
|
||||
}
|
||||
}
|
||||
public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string) {
|
||||
if (this.userAddress !== newUserAddress) {
|
||||
this.userAddress = newUserAddress;
|
||||
await this.fetchTokenInformationAsync();
|
||||
await this.rehydrateStoreWithContractEvents();
|
||||
if (this._userAddress !== newUserAddress) {
|
||||
this._userAddress = newUserAddress;
|
||||
await this._fetchTokenInformationAsync();
|
||||
await this._rehydrateStoreWithContractEvents();
|
||||
}
|
||||
}
|
||||
public async nodeVersionUpdatedFireAndForgetAsync(nodeVersion: string) {
|
||||
@@ -157,7 +157,7 @@ export class Blockchain {
|
||||
}
|
||||
}
|
||||
public async isAddressInTokenRegistryAsync(tokenAddress: string): Promise<boolean> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
// HACK: temporarily whitelist the new WETH token address `as if` they were
|
||||
// already in the tokenRegistry.
|
||||
// TODO: Remove this hack once we've updated the TokenRegistries
|
||||
@@ -166,30 +166,30 @@ export class Blockchain {
|
||||
tokenAddress === configs.NEW_WRAPPED_ETHERS[this.networkId]) {
|
||||
return true;
|
||||
}
|
||||
const tokenIfExists = await this.zeroEx.tokenRegistry.getTokenIfExistsAsync(tokenAddress);
|
||||
const tokenIfExists = await this._zeroEx.tokenRegistry.getTokenIfExistsAsync(tokenAddress);
|
||||
return !_.isUndefined(tokenIfExists);
|
||||
}
|
||||
public getLedgerDerivationPathIfExists(): string {
|
||||
if (_.isUndefined(this.ledgerSubprovider)) {
|
||||
if (_.isUndefined(this._ledgerSubprovider)) {
|
||||
return undefined;
|
||||
}
|
||||
const path = this.ledgerSubprovider.getPath();
|
||||
const path = this._ledgerSubprovider.getPath();
|
||||
return path;
|
||||
}
|
||||
public updateLedgerDerivationPathIfExists(path: string) {
|
||||
if (_.isUndefined(this.ledgerSubprovider)) {
|
||||
if (_.isUndefined(this._ledgerSubprovider)) {
|
||||
return; // noop
|
||||
}
|
||||
this.ledgerSubprovider.setPath(path);
|
||||
this._ledgerSubprovider.setPath(path);
|
||||
}
|
||||
public updateLedgerDerivationIndex(pathIndex: number) {
|
||||
if (_.isUndefined(this.ledgerSubprovider)) {
|
||||
if (_.isUndefined(this._ledgerSubprovider)) {
|
||||
return; // noop
|
||||
}
|
||||
this.ledgerSubprovider.setPathIndex(pathIndex);
|
||||
this._ledgerSubprovider.setPathIndex(pathIndex);
|
||||
}
|
||||
public async providerTypeUpdatedFireAndForgetAsync(providerType: ProviderType) {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
// Should actually be Web3.Provider|ProviderEngine union type but it causes issues
|
||||
// later on in the logic.
|
||||
let provider;
|
||||
@@ -201,17 +201,17 @@ export class Blockchain {
|
||||
}
|
||||
|
||||
// Cache injected provider so that we can switch the user back to it easily
|
||||
this.cachedProvider = this.web3Wrapper.getProviderObj();
|
||||
this._cachedProvider = this._web3Wrapper.getProviderObj();
|
||||
|
||||
this.dispatcher.updateUserAddress(''); // Clear old userAddress
|
||||
this._dispatcher.updateUserAddress(''); // Clear old userAddress
|
||||
|
||||
provider = new ProviderEngine();
|
||||
const ledgerWalletConfigs = {
|
||||
networkId: this.networkId,
|
||||
ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync,
|
||||
};
|
||||
this.ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
||||
provider.addProvider(this.ledgerSubprovider);
|
||||
this._ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
||||
provider.addProvider(this._ledgerSubprovider);
|
||||
provider.addProvider(new FilterSubprovider());
|
||||
const networkId = configs.IS_MAINNET_ENABLED ?
|
||||
constants.NETWORK_ID_MAINNET :
|
||||
@@ -220,25 +220,25 @@ export class Blockchain {
|
||||
configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId],
|
||||
));
|
||||
provider.start();
|
||||
this.web3Wrapper.destroy();
|
||||
this._web3Wrapper.destroy();
|
||||
const shouldPollUserAddress = false;
|
||||
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress);
|
||||
this.zeroEx.setProvider(provider, networkId);
|
||||
await this.postInstantiationOrUpdatingProviderZeroExAsync();
|
||||
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress);
|
||||
this._zeroEx.setProvider(provider, networkId);
|
||||
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
||||
break;
|
||||
}
|
||||
|
||||
case ProviderType.Injected: {
|
||||
if (_.isUndefined(this.cachedProvider)) {
|
||||
if (_.isUndefined(this._cachedProvider)) {
|
||||
return; // Going from injected to injected, so we noop
|
||||
}
|
||||
provider = this.cachedProvider;
|
||||
provider = this._cachedProvider;
|
||||
const shouldPollUserAddress = true;
|
||||
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress);
|
||||
this.zeroEx.setProvider(provider, this.networkId);
|
||||
await this.postInstantiationOrUpdatingProviderZeroExAsync();
|
||||
delete this.ledgerSubprovider;
|
||||
delete this.cachedProvider;
|
||||
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress);
|
||||
this._zeroEx.setProvider(provider, this.networkId);
|
||||
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
||||
delete this._ledgerSubprovider;
|
||||
delete this._cachedProvider;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -246,28 +246,28 @@ export class Blockchain {
|
||||
throw utils.spawnSwitchErr('providerType', providerType);
|
||||
}
|
||||
|
||||
await this.fetchTokenInformationAsync();
|
||||
await this._fetchTokenInformationAsync();
|
||||
}
|
||||
public async setProxyAllowanceAsync(token: Token, amountInBaseUnits: BigNumber): Promise<void> {
|
||||
utils.assert(this.isValidAddress(token.address), BlockchainCallErrs.TokenAddressIsInvalid);
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
|
||||
const txHash = await this.zeroEx.token.setProxyAllowanceAsync(
|
||||
token.address, this.userAddress, amountInBaseUnits,
|
||||
const txHash = await this._zeroEx.token.setProxyAllowanceAsync(
|
||||
token.address, this._userAddress, amountInBaseUnits,
|
||||
);
|
||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const allowance = amountInBaseUnits;
|
||||
this.dispatcher.replaceTokenAllowanceByAddress(token.address, allowance);
|
||||
this._dispatcher.replaceTokenAllowanceByAddress(token.address, allowance);
|
||||
}
|
||||
public async transferAsync(token: Token, toAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const txHash = await this.zeroEx.token.transferAsync(
|
||||
token.address, this.userAddress, toAddress, amountInBaseUnits,
|
||||
const txHash = await this._zeroEx.token.transferAsync(
|
||||
token.address, this._userAddress, toAddress, amountInBaseUnits,
|
||||
);
|
||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx);
|
||||
this.dispatcher.showFlashMessage(React.createElement(TokenSendCompleted, {
|
||||
this._dispatcher.showFlashMessage(React.createElement(TokenSendCompleted, {
|
||||
etherScanLinkIfExists,
|
||||
token,
|
||||
toAddress,
|
||||
@@ -302,16 +302,16 @@ export class Blockchain {
|
||||
}
|
||||
public async fillOrderAsync(signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||
|
||||
const txHash = await this.zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillTakerTokenAmount, shouldThrowOnInsufficientBalanceOrAllowance, this.userAddress,
|
||||
const txHash = await this._zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillTakerTokenAmount, shouldThrowOnInsufficientBalanceOrAllowance, this._userAddress,
|
||||
);
|
||||
const receipt = await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const logs: Array<LogWithDecodedArgs<ExchangeContractEventArgs>> = receipt.logs as any;
|
||||
this.zeroEx.exchange.throwLogErrorsAsErrors(logs);
|
||||
this._zeroEx.exchange.throwLogErrorsAsErrors(logs);
|
||||
const logFill = _.find(logs, {event: 'LogFill'});
|
||||
const args = logFill.args as any as LogFillContractEventArgs;
|
||||
const filledTakerTokenAmount = args.filledTakerTokenAmount;
|
||||
@@ -319,12 +319,12 @@ export class Blockchain {
|
||||
}
|
||||
public async cancelOrderAsync(signedOrder: SignedOrder,
|
||||
cancelTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
||||
const txHash = await this.zeroEx.exchange.cancelOrderAsync(
|
||||
const txHash = await this._zeroEx.exchange.cancelOrderAsync(
|
||||
signedOrder, cancelTakerTokenAmount,
|
||||
);
|
||||
const receipt = await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const logs: Array<LogWithDecodedArgs<ExchangeContractEventArgs>> = receipt.logs as any;
|
||||
this.zeroEx.exchange.throwLogErrorsAsErrors(logs);
|
||||
this._zeroEx.exchange.throwLogErrorsAsErrors(logs);
|
||||
const logCancel = _.find(logs, {event: ExchangeEvents.LogCancel});
|
||||
const args = logCancel.args as any as LogCancelContractEventArgs;
|
||||
const cancelledTakerTokenAmount = args.cancelledTakerTokenAmount;
|
||||
@@ -332,95 +332,95 @@ export class Blockchain {
|
||||
}
|
||||
public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||
utils.assert(ZeroEx.isValidOrderHash(orderHash), 'Must be valid orderHash');
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
const unavailableTakerAmount = await this.zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash);
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
const unavailableTakerAmount = await this._zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash);
|
||||
return unavailableTakerAmount;
|
||||
}
|
||||
public getExchangeContractAddressIfExists() {
|
||||
return this.exchangeAddress;
|
||||
return this._exchangeAddress;
|
||||
}
|
||||
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string): Promise<void> {
|
||||
await this.zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
await this._zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, fillTakerTokenAmount, takerAddress);
|
||||
}
|
||||
public async validateCancelOrderThrowIfInvalidAsync(order: Order,
|
||||
cancelTakerTokenAmount: BigNumber): Promise<void> {
|
||||
await this.zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(order, cancelTakerTokenAmount);
|
||||
await this._zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(order, cancelTakerTokenAmount);
|
||||
}
|
||||
public isValidAddress(address: string): boolean {
|
||||
const lowercaseAddress = address.toLowerCase();
|
||||
return this.web3Wrapper.isAddress(lowercaseAddress);
|
||||
return this._web3Wrapper.isAddress(lowercaseAddress);
|
||||
}
|
||||
public async pollTokenBalanceAsync(token: Token) {
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
|
||||
const [currBalance] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address);
|
||||
const [currBalance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address);
|
||||
|
||||
this.zrxPollIntervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
||||
const [balance] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address);
|
||||
this._zrxPollIntervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
||||
const [balance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address);
|
||||
if (!balance.eq(currBalance)) {
|
||||
this.dispatcher.replaceTokenBalanceByAddress(token.address, balance);
|
||||
clearInterval(this.zrxPollIntervalId);
|
||||
delete this.zrxPollIntervalId;
|
||||
this._dispatcher.replaceTokenBalanceByAddress(token.address, balance);
|
||||
clearInterval(this._zrxPollIntervalId);
|
||||
delete this._zrxPollIntervalId;
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
public async signOrderHashAsync(orderHash: string): Promise<SignatureData> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
const makerAddress = this.userAddress;
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
const makerAddress = this._userAddress;
|
||||
// If makerAddress is undefined, this means they have a web3 instance injected into their browser
|
||||
// but no account addresses associated with it.
|
||||
if (_.isUndefined(makerAddress)) {
|
||||
throw new Error('Tried to send a sign request but user has no associated addresses');
|
||||
}
|
||||
const ecSignature = await this.zeroEx.signOrderHashAsync(orderHash, makerAddress);
|
||||
const ecSignature = await this._zeroEx.signOrderHashAsync(orderHash, makerAddress);
|
||||
const signatureData = _.extend({}, ecSignature, {
|
||||
hash: orderHash,
|
||||
});
|
||||
this.dispatcher.updateSignatureData(signatureData);
|
||||
this._dispatcher.updateSignatureData(signatureData);
|
||||
return signatureData;
|
||||
}
|
||||
public async mintTestTokensAsync(token: Token) {
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
|
||||
const mintableContract = await this.instantiateContractIfExistsAsync(MintableArtifacts, token.address);
|
||||
const mintableContract = await this._instantiateContractIfExistsAsync(MintableArtifacts, token.address);
|
||||
await mintableContract.mint(constants.MINT_AMOUNT, {
|
||||
from: this.userAddress,
|
||||
from: this._userAddress,
|
||||
});
|
||||
const balanceDelta = constants.MINT_AMOUNT;
|
||||
this.dispatcher.updateTokenBalanceByAddress(token.address, balanceDelta);
|
||||
this._dispatcher.updateTokenBalanceByAddress(token.address, balanceDelta);
|
||||
}
|
||||
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
||||
const balance = await this.web3Wrapper.getBalanceInEthAsync(owner);
|
||||
const balance = await this._web3Wrapper.getBalanceInEthAsync(owner);
|
||||
return balance;
|
||||
}
|
||||
public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
|
||||
const txHash = await this.zeroEx.etherToken.depositAsync(etherTokenAddress, amount, this.userAddress);
|
||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const txHash = await this._zeroEx.etherToken.depositAsync(etherTokenAddress, amount, this._userAddress);
|
||||
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
}
|
||||
public async convertWrappedEthTokensToEthAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
|
||||
const txHash = await this.zeroEx.etherToken.withdrawAsync(etherTokenAddress, amount, this.userAddress);
|
||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
const txHash = await this._zeroEx.etherToken.withdrawAsync(etherTokenAddress, amount, this._userAddress);
|
||||
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||
}
|
||||
public async doesContractExistAtAddressAsync(address: string) {
|
||||
const doesContractExist = await this.web3Wrapper.doesContractExistAtAddressAsync(address);
|
||||
const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(address);
|
||||
return doesContractExist;
|
||||
}
|
||||
public async getCurrentUserTokenBalanceAndAllowanceAsync(tokenAddress: string): Promise<BigNumber[]> {
|
||||
const tokenBalanceAndAllowance = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, tokenAddress);
|
||||
const tokenBalanceAndAllowance = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, tokenAddress);
|
||||
return tokenBalanceAndAllowance;
|
||||
}
|
||||
public async getTokenBalanceAndAllowanceAsync(ownerAddress: string, tokenAddress: string):
|
||||
Promise<BigNumber[]> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
|
||||
if (_.isEmpty(ownerAddress)) {
|
||||
const zero = new BigNumber(0);
|
||||
@@ -428,9 +428,9 @@ export class Blockchain {
|
||||
}
|
||||
let balance = new BigNumber(0);
|
||||
let allowance = new BigNumber(0);
|
||||
if (this.doesUserAddressExist()) {
|
||||
balance = await this.zeroEx.token.getBalanceAsync(tokenAddress, ownerAddress);
|
||||
allowance = await this.zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
||||
if (this._doesUserAddressExist()) {
|
||||
balance = await this._zeroEx.token.getBalanceAsync(tokenAddress, ownerAddress);
|
||||
allowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
||||
}
|
||||
return [balance, allowance];
|
||||
}
|
||||
@@ -439,11 +439,11 @@ export class Blockchain {
|
||||
for (const token of tokens) {
|
||||
let balance = new BigNumber(0);
|
||||
let allowance = new BigNumber(0);
|
||||
if (this.doesUserAddressExist()) {
|
||||
if (this._doesUserAddressExist()) {
|
||||
[
|
||||
balance,
|
||||
allowance,
|
||||
] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address);
|
||||
] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address);
|
||||
}
|
||||
const tokenState = {
|
||||
balance,
|
||||
@@ -451,61 +451,61 @@ export class Blockchain {
|
||||
};
|
||||
tokenStateByAddress[token.address] = tokenState;
|
||||
}
|
||||
this.dispatcher.updateTokenStateByAddress(tokenStateByAddress);
|
||||
this._dispatcher.updateTokenStateByAddress(tokenStateByAddress);
|
||||
}
|
||||
public async getUserAccountsAsync() {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
const userAccountsIfExists = await this.zeroEx.getAvailableAddressesAsync();
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
const userAccountsIfExists = await this._zeroEx.getAvailableAddressesAsync();
|
||||
return userAccountsIfExists;
|
||||
}
|
||||
// HACK: When a user is using a Ledger, we simply dispatch the selected userAddress, which
|
||||
// by-passes the web3Wrapper logic for updating the prevUserAddress. We therefore need to
|
||||
// manually update it. This should only be called by the LedgerConfigDialog.
|
||||
public updateWeb3WrapperPrevUserAddress(newUserAddress: string) {
|
||||
this.web3Wrapper.updatePrevUserAddress(newUserAddress);
|
||||
this._web3Wrapper.updatePrevUserAddress(newUserAddress);
|
||||
}
|
||||
public destroy() {
|
||||
clearInterval(this.zrxPollIntervalId);
|
||||
this.web3Wrapper.destroy();
|
||||
this.stopWatchingExchangeLogFillEvents();
|
||||
clearInterval(this._zrxPollIntervalId);
|
||||
this._web3Wrapper.destroy();
|
||||
this._stopWatchingExchangeLogFillEvents();
|
||||
}
|
||||
private async showEtherScanLinkAndAwaitTransactionMinedAsync(
|
||||
private async _showEtherScanLinkAndAwaitTransactionMinedAsync(
|
||||
txHash: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx);
|
||||
this.dispatcher.showFlashMessage(React.createElement(TransactionSubmitted, {
|
||||
this._dispatcher.showFlashMessage(React.createElement(TransactionSubmitted, {
|
||||
etherScanLinkIfExists,
|
||||
}));
|
||||
const receipt = await this.zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
const receipt = await this._zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
return receipt;
|
||||
}
|
||||
private doesUserAddressExist(): boolean {
|
||||
return this.userAddress !== '';
|
||||
private _doesUserAddressExist(): boolean {
|
||||
return this._userAddress !== '';
|
||||
}
|
||||
private async rehydrateStoreWithContractEvents() {
|
||||
private async _rehydrateStoreWithContractEvents() {
|
||||
// Ensure we are only ever listening to one set of events
|
||||
this.stopWatchingExchangeLogFillEvents();
|
||||
this._stopWatchingExchangeLogFillEvents();
|
||||
|
||||
if (!this.doesUserAddressExist()) {
|
||||
if (!this._doesUserAddressExist()) {
|
||||
return; // short-circuit
|
||||
}
|
||||
|
||||
if (!_.isUndefined(this.zeroEx)) {
|
||||
if (!_.isUndefined(this._zeroEx)) {
|
||||
// Since we do not have an index on the `taker` address and want to show
|
||||
// transactions where an account is either the `maker` or `taker`, we loop
|
||||
// through all fill events, and filter/cache them client-side.
|
||||
const filterIndexObj = {};
|
||||
await this.startListeningForExchangeLogFillEventsAsync(filterIndexObj);
|
||||
await this._startListeningForExchangeLogFillEventsAsync(filterIndexObj);
|
||||
}
|
||||
}
|
||||
private async startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
private async _startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> {
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||
|
||||
// Fetch historical logs
|
||||
await this.fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues);
|
||||
await this._fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues);
|
||||
|
||||
// Start a subscription for new logs
|
||||
this.zeroEx.exchange.subscribe(
|
||||
this._zeroEx.exchange.subscribe(
|
||||
ExchangeEvents.LogFill, indexFilterValues,
|
||||
async (err: Error, decodedLogEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
if (err) {
|
||||
@@ -517,40 +517,40 @@ export class Blockchain {
|
||||
return;
|
||||
} else {
|
||||
const decodedLog = decodedLogEvent.log;
|
||||
if (!this.doesLogEventInvolveUser(decodedLog)) {
|
||||
if (!this._doesLogEventInvolveUser(decodedLog)) {
|
||||
return; // We aren't interested in the fill event
|
||||
}
|
||||
this.updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
||||
const fill = await this.convertDecodedLogToFillAsync(decodedLog);
|
||||
this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
||||
const fill = await this._convertDecodedLogToFillAsync(decodedLog);
|
||||
if (decodedLogEvent.isRemoved) {
|
||||
tradeHistoryStorage.removeFillFromUser(this.userAddress, this.networkId, fill);
|
||||
tradeHistoryStorage.removeFillFromUser(this._userAddress, this.networkId, fill);
|
||||
} else {
|
||||
tradeHistoryStorage.addFillToUser(this.userAddress, this.networkId, fill);
|
||||
tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
private async fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) {
|
||||
const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this.userAddress, this.networkId);
|
||||
private async _fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) {
|
||||
const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this._userAddress, this.networkId);
|
||||
const blockRange: BlockRange = {
|
||||
fromBlock,
|
||||
toBlock: 'latest' as BlockParam,
|
||||
};
|
||||
const decodedLogs = await this.zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
||||
const decodedLogs = await this._zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
||||
ExchangeEvents.LogFill, blockRange, indexFilterValues,
|
||||
);
|
||||
for (const decodedLog of decodedLogs) {
|
||||
if (!this.doesLogEventInvolveUser(decodedLog)) {
|
||||
if (!this._doesLogEventInvolveUser(decodedLog)) {
|
||||
continue; // We aren't interested in the fill event
|
||||
}
|
||||
this.updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
||||
const fill = await this.convertDecodedLogToFillAsync(decodedLog);
|
||||
tradeHistoryStorage.addFillToUser(this.userAddress, this.networkId, fill);
|
||||
this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
||||
const fill = await this._convertDecodedLogToFillAsync(decodedLog);
|
||||
tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill);
|
||||
}
|
||||
}
|
||||
private async convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||
private async _convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||
const args = decodedLog.args;
|
||||
const blockTimestamp = await this.web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash);
|
||||
const blockTimestamp = await this._web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash);
|
||||
const fill = {
|
||||
filledTakerTokenAmount: args.filledTakerTokenAmount,
|
||||
filledMakerTokenAmount: args.filledMakerTokenAmount,
|
||||
@@ -567,13 +567,13 @@ export class Blockchain {
|
||||
};
|
||||
return fill;
|
||||
}
|
||||
private doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||
private _doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||
const args = decodedLog.args;
|
||||
const isUserMakerOrTaker = args.maker === this.userAddress ||
|
||||
args.taker === this.userAddress;
|
||||
const isUserMakerOrTaker = args.maker === this._userAddress ||
|
||||
args.taker === this._userAddress;
|
||||
return isUserMakerOrTaker;
|
||||
}
|
||||
private updateLatestFillsBlockIfNeeded(blockNumber: number) {
|
||||
private _updateLatestFillsBlockIfNeeded(blockNumber: number) {
|
||||
const isBlockPending = _.isNull(blockNumber);
|
||||
if (!isBlockPending) {
|
||||
// Hack: I've observed the behavior where a client won't register certain fill events
|
||||
@@ -585,15 +585,15 @@ export class Blockchain {
|
||||
const blockNumberToSet = blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ?
|
||||
0 :
|
||||
blockNumber - BLOCK_NUMBER_BACK_TRACK;
|
||||
tradeHistoryStorage.setFillsLatestBlock(this.userAddress, this.networkId, blockNumberToSet);
|
||||
tradeHistoryStorage.setFillsLatestBlock(this._userAddress, this.networkId, blockNumberToSet);
|
||||
}
|
||||
}
|
||||
private stopWatchingExchangeLogFillEvents(): void {
|
||||
this.zeroEx.exchange.unsubscribeAll();
|
||||
private _stopWatchingExchangeLogFillEvents(): void {
|
||||
this._zeroEx.exchange.unsubscribeAll();
|
||||
}
|
||||
private async getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
const tokenRegistryTokens = await this.zeroEx.tokenRegistry.getTokensAsync();
|
||||
private async _getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> {
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
const tokenRegistryTokens = await this._zeroEx.tokenRegistry.getTokensAsync();
|
||||
|
||||
const tokenByAddress: TokenByAddress = {};
|
||||
_.each(tokenRegistryTokens, (t: ZeroExToken, i: number) => {
|
||||
@@ -626,8 +626,8 @@ export class Blockchain {
|
||||
});
|
||||
return tokenByAddress;
|
||||
}
|
||||
private async onPageLoadInitFireAndForgetAsync() {
|
||||
await Blockchain.onPageLoadAsync(); // wait for page to load
|
||||
private async _onPageLoadInitFireAndForgetAsync() {
|
||||
await Blockchain._onPageLoadAsync(); // wait for page to load
|
||||
|
||||
// Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in
|
||||
// order to properly instantiate the web3Wrapper. Since we must use the async call, we cannot
|
||||
@@ -645,7 +645,7 @@ export class Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
const provider = await Blockchain.getProviderAsync(injectedWeb3, networkIdIfExists);
|
||||
const provider = await Blockchain._getProviderAsync(injectedWeb3, networkIdIfExists);
|
||||
const networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists :
|
||||
configs.IS_MAINNET_ENABLED ?
|
||||
constants.NETWORK_ID_MAINNET :
|
||||
@@ -653,45 +653,45 @@ export class Blockchain {
|
||||
const zeroExConfigs = {
|
||||
networkId,
|
||||
};
|
||||
this.zeroEx = new ZeroEx(provider, zeroExConfigs);
|
||||
this.updateProviderName(injectedWeb3);
|
||||
this._zeroEx = new ZeroEx(provider, zeroExConfigs);
|
||||
this._updateProviderName(injectedWeb3);
|
||||
const shouldPollUserAddress = true;
|
||||
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, networkId, shouldPollUserAddress);
|
||||
await this.postInstantiationOrUpdatingProviderZeroExAsync();
|
||||
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, networkId, shouldPollUserAddress);
|
||||
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
||||
}
|
||||
// This method should always be run after instantiating or updating the provider
|
||||
// of the ZeroEx instance.
|
||||
private async postInstantiationOrUpdatingProviderZeroExAsync() {
|
||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
||||
this.exchangeAddress = this.zeroEx.exchange.getContractAddress();
|
||||
private async _postInstantiationOrUpdatingProviderZeroExAsync() {
|
||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||
this._exchangeAddress = this._zeroEx.exchange.getContractAddress();
|
||||
}
|
||||
private updateProviderName(injectedWeb3: Web3) {
|
||||
private _updateProviderName(injectedWeb3: Web3) {
|
||||
const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
||||
const providerName = doesInjectedWeb3Exist ?
|
||||
Blockchain.getNameGivenProvider(injectedWeb3.currentProvider) :
|
||||
Blockchain._getNameGivenProvider(injectedWeb3.currentProvider) :
|
||||
constants.PROVIDER_NAME_PUBLIC;
|
||||
this.dispatcher.updateInjectedProviderName(providerName);
|
||||
this._dispatcher.updateInjectedProviderName(providerName);
|
||||
}
|
||||
private async fetchTokenInformationAsync() {
|
||||
private async _fetchTokenInformationAsync() {
|
||||
utils.assert(!_.isUndefined(this.networkId),
|
||||
'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node');
|
||||
|
||||
this.dispatcher.updateBlockchainIsLoaded(false);
|
||||
this.dispatcher.clearTokenByAddress();
|
||||
this._dispatcher.updateBlockchainIsLoaded(false);
|
||||
this._dispatcher.clearTokenByAddress();
|
||||
|
||||
const tokenRegistryTokensByAddress = await this.getTokenRegistryTokensByAddressAsync();
|
||||
const tokenRegistryTokensByAddress = await this._getTokenRegistryTokensByAddressAsync();
|
||||
|
||||
// HACK: We need to fetch the userAddress here because otherwise we cannot save the
|
||||
// tracked tokens in localStorage under the users address nor fetch the token
|
||||
// balances and allowances and we need to do this in order not to trigger the blockchain
|
||||
// loading dialog to show up twice. First to load the contracts, and second to load the
|
||||
// balances and allowances.
|
||||
this.userAddress = await this.web3Wrapper.getFirstAccountIfExistsAsync();
|
||||
if (!_.isEmpty(this.userAddress)) {
|
||||
this.dispatcher.updateUserAddress(this.userAddress);
|
||||
this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync();
|
||||
if (!_.isEmpty(this._userAddress)) {
|
||||
this._dispatcher.updateUserAddress(this._userAddress);
|
||||
}
|
||||
|
||||
let trackedTokensIfExists = trackedTokenStorage.getTrackedTokensIfExists(this.userAddress, this.networkId);
|
||||
let trackedTokensIfExists = trackedTokenStorage.getTrackedTokensIfExists(this._userAddress, this.networkId);
|
||||
const tokenRegistryTokens = _.values(tokenRegistryTokensByAddress);
|
||||
if (_.isUndefined(trackedTokensIfExists)) {
|
||||
trackedTokensIfExists = _.map(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => {
|
||||
@@ -700,7 +700,7 @@ export class Blockchain {
|
||||
return token;
|
||||
});
|
||||
_.each(trackedTokensIfExists, token => {
|
||||
trackedTokenStorage.addTrackedTokenToUser(this.userAddress, this.networkId, token);
|
||||
trackedTokenStorage.addTrackedTokenToUser(this._userAddress, this.networkId, token);
|
||||
});
|
||||
} else {
|
||||
// Properly set all tokenRegistry tokens `isTracked` to true if they are in the existing trackedTokens array
|
||||
@@ -711,7 +711,7 @@ export class Blockchain {
|
||||
});
|
||||
}
|
||||
const allTokens = _.uniq([...tokenRegistryTokens, ...trackedTokensIfExists]);
|
||||
this.dispatcher.updateTokenByAddress(allTokens);
|
||||
this._dispatcher.updateTokenByAddress(allTokens);
|
||||
|
||||
// Get balance/allowance for tracked tokens
|
||||
await this.updateTokenBalancesAndAllowancesAsync(trackedTokensIfExists);
|
||||
@@ -720,13 +720,13 @@ export class Blockchain {
|
||||
_.find(allTokens, {symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[0]}),
|
||||
_.find(allTokens, {symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[1]}),
|
||||
];
|
||||
this.dispatcher.updateChosenAssetTokenAddress(Side.Deposit, mostPopularTradingPairTokens[0].address);
|
||||
this.dispatcher.updateChosenAssetTokenAddress(Side.Receive, mostPopularTradingPairTokens[1].address);
|
||||
this.dispatcher.updateBlockchainIsLoaded(true);
|
||||
this._dispatcher.updateChosenAssetTokenAddress(Side.Deposit, mostPopularTradingPairTokens[0].address);
|
||||
this._dispatcher.updateChosenAssetTokenAddress(Side.Receive, mostPopularTradingPairTokens[1].address);
|
||||
this._dispatcher.updateBlockchainIsLoaded(true);
|
||||
}
|
||||
private async instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> {
|
||||
private async _instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> {
|
||||
const c = await contract(artifact);
|
||||
const providerObj = this.web3Wrapper.getProviderObj();
|
||||
const providerObj = this._web3Wrapper.getProviderObj();
|
||||
c.setProvider(providerObj);
|
||||
|
||||
const artifactNetworkConfigs = artifact.networks[this.networkId];
|
||||
|
@@ -31,7 +31,7 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
||||
const hasWalletAddress = this.props.userAddress !== '';
|
||||
return (
|
||||
<Dialog
|
||||
title={this.getTitle(hasWalletAddress)}
|
||||
title={this._getTitle(hasWalletAddress)}
|
||||
titleStyle={{fontWeight: 100}}
|
||||
actions={dialogActions}
|
||||
open={this.props.isOpen}
|
||||
@@ -40,12 +40,12 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
||||
autoScrollBodyContent={true}
|
||||
>
|
||||
<div className="pt2" style={{color: colors.grey700}}>
|
||||
{this.renderExplanation(hasWalletAddress)}
|
||||
{this._renderExplanation(hasWalletAddress)}
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
private getTitle(hasWalletAddress: boolean) {
|
||||
private _getTitle(hasWalletAddress: boolean) {
|
||||
if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
|
||||
return '0x smart contracts not found';
|
||||
} else if (!hasWalletAddress) {
|
||||
@@ -56,18 +56,18 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
||||
return 'Unexpected error';
|
||||
}
|
||||
}
|
||||
private renderExplanation(hasWalletAddress: boolean) {
|
||||
private _renderExplanation(hasWalletAddress: boolean) {
|
||||
if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
|
||||
return this.renderContractsNotDeployedExplanation();
|
||||
return this._renderContractsNotDeployedExplanation();
|
||||
} else if (!hasWalletAddress) {
|
||||
return this.renderNoWalletFoundExplanation();
|
||||
return this._renderNoWalletFoundExplanation();
|
||||
} else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) {
|
||||
return this.renderDisconnectedFromNode();
|
||||
return this._renderDisconnectedFromNode();
|
||||
} else {
|
||||
return this.renderUnexpectedErrorExplanation();
|
||||
return this._renderUnexpectedErrorExplanation();
|
||||
}
|
||||
}
|
||||
private renderDisconnectedFromNode() {
|
||||
private _renderDisconnectedFromNode() {
|
||||
return (
|
||||
<div>
|
||||
You were disconnected from the backing Ethereum node.
|
||||
@@ -78,14 +78,14 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderUnexpectedErrorExplanation() {
|
||||
private _renderUnexpectedErrorExplanation() {
|
||||
return (
|
||||
<div>
|
||||
We encountered an unexpected error. Please try refreshing the page.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderNoWalletFoundExplanation() {
|
||||
private _renderNoWalletFoundExplanation() {
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
@@ -122,7 +122,7 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderContractsNotDeployedExplanation() {
|
||||
private _renderContractsNotDeployedExplanation() {
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
|
@@ -29,7 +29,7 @@ export class EthWethConversionDialog extends
|
||||
super();
|
||||
this.state = {
|
||||
shouldShowIncompleteErrs: false,
|
||||
hasErrors: true,
|
||||
hasErrors: false,
|
||||
};
|
||||
}
|
||||
public render() {
|
||||
@@ -37,13 +37,13 @@ export class EthWethConversionDialog extends
|
||||
<FlatButton
|
||||
key="cancel"
|
||||
label="Cancel"
|
||||
onTouchTap={this.onCancel.bind(this)}
|
||||
onTouchTap={this._onCancel.bind(this)}
|
||||
/>,
|
||||
<FlatButton
|
||||
key="convert"
|
||||
label="Convert"
|
||||
primary={true}
|
||||
onTouchTap={this.onConvertClick.bind(this)}
|
||||
onTouchTap={this._onConvertClick.bind(this)}
|
||||
/>,
|
||||
];
|
||||
const title = this.props.direction === Side.Deposit ? 'Wrap ETH' : 'Unwrap WETH';
|
||||
@@ -55,11 +55,11 @@ export class EthWethConversionDialog extends
|
||||
contentStyle={{width: 448}}
|
||||
open={this.props.isOpen}
|
||||
>
|
||||
{this.renderConversionDialogBody()}
|
||||
{this._renderConversionDialogBody()}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
private renderConversionDialogBody() {
|
||||
private _renderConversionDialogBody() {
|
||||
const explanation = this.props.direction === Side.Deposit ?
|
||||
'Convert your Ether into a tokenized, tradable form.' :
|
||||
'Convert your Wrapped Ether back into it\'s native form.';
|
||||
@@ -71,14 +71,14 @@ export class EthWethConversionDialog extends
|
||||
</div>
|
||||
<div className="mx-auto" style={{maxWidth: 312}}>
|
||||
<div className="flex">
|
||||
{this.renderCurrency(isWrappedVersion)}
|
||||
{this._renderCurrency(isWrappedVersion)}
|
||||
<div style={{paddingTop: 68}}>
|
||||
<i
|
||||
style={{fontSize: 28, color: colors.darkBlue}}
|
||||
className="zmdi zmdi-arrow-right"
|
||||
/>
|
||||
</div>
|
||||
{this.renderCurrency(!isWrappedVersion)}
|
||||
{this._renderCurrency(!isWrappedVersion)}
|
||||
</div>
|
||||
<div
|
||||
className="pt2 mx-auto"
|
||||
@@ -91,14 +91,14 @@ export class EthWethConversionDialog extends
|
||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||
shouldCheckBalance={true}
|
||||
shouldCheckAllowance={false}
|
||||
onChange={this.onValueChange.bind(this)}
|
||||
onChange={this._onValueChange.bind(this)}
|
||||
amount={this.state.value}
|
||||
onVisitBalancesPageClick={this.props.onCancelled}
|
||||
/> :
|
||||
<EthAmountInput
|
||||
balance={this.props.etherBalance}
|
||||
amount={this.state.value}
|
||||
onChange={this.onValueChange.bind(this)}
|
||||
onChange={this._onValueChange.bind(this)}
|
||||
shouldCheckBalance={true}
|
||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||
onVisitBalancesPageClick={this.props.onCancelled}
|
||||
@@ -112,7 +112,7 @@ export class EthWethConversionDialog extends
|
||||
{this.props.direction === Side.Receive &&
|
||||
<div
|
||||
className="right"
|
||||
onClick={this.onMaxClick.bind(this)}
|
||||
onClick={this._onMaxClick.bind(this)}
|
||||
style={{color: colors.darkBlue, textDecoration: 'underline', cursor: 'pointer'}}
|
||||
>
|
||||
Max
|
||||
@@ -124,7 +124,7 @@ export class EthWethConversionDialog extends
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderCurrency(isWrappedVersion: boolean) {
|
||||
private _renderCurrency(isWrappedVersion: boolean) {
|
||||
const name = isWrappedVersion ? 'Wrapped Ether' : 'Ether';
|
||||
const iconUrl = isWrappedVersion ? '/images/token_icons/ether_erc20.png' : '/images/ether.png';
|
||||
const symbol = isWrappedVersion ? 'WETH' : 'ETH';
|
||||
@@ -145,18 +145,18 @@ export class EthWethConversionDialog extends
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onMaxClick() {
|
||||
private _onMaxClick() {
|
||||
this.setState({
|
||||
value: this.props.tokenState.balance,
|
||||
});
|
||||
}
|
||||
private onValueChange(isValid: boolean, amount?: BigNumber) {
|
||||
private _onValueChange(isValid: boolean, amount?: BigNumber) {
|
||||
this.setState({
|
||||
value: amount,
|
||||
hasErrors: !isValid,
|
||||
});
|
||||
}
|
||||
private onConvertClick() {
|
||||
private _onConvertClick() {
|
||||
if (this.state.hasErrors) {
|
||||
this.setState({
|
||||
shouldShowIncompleteErrs: true,
|
||||
@@ -169,7 +169,7 @@ export class EthWethConversionDialog extends
|
||||
this.props.onComplete(this.props.direction, value);
|
||||
}
|
||||
}
|
||||
private onCancel() {
|
||||
private _onCancel() {
|
||||
this.setState({
|
||||
value: undefined,
|
||||
});
|
||||
|
@@ -62,7 +62,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
<FlatButton
|
||||
key="ledgerConnectCancel"
|
||||
label="Cancel"
|
||||
onTouchTap={this.onClose.bind(this)}
|
||||
onTouchTap={this._onClose.bind(this)}
|
||||
/>,
|
||||
];
|
||||
const dialogTitle = this.state.stepIndex === LedgerSteps.CONNECT ?
|
||||
@@ -74,22 +74,22 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
titleStyle={{fontWeight: 100}}
|
||||
actions={dialogActions}
|
||||
open={this.props.isOpen}
|
||||
onRequestClose={this.onClose.bind(this)}
|
||||
onRequestClose={this._onClose.bind(this)}
|
||||
autoScrollBodyContent={true}
|
||||
bodyStyle={{paddingBottom: 0}}
|
||||
>
|
||||
<div style={{color: colors.grey700, paddingTop: 1}}>
|
||||
{this.state.stepIndex === LedgerSteps.CONNECT &&
|
||||
this.renderConnectStep()
|
||||
this._renderConnectStep()
|
||||
}
|
||||
{this.state.stepIndex === LedgerSteps.SELECT_ADDRESS &&
|
||||
this.renderSelectAddressStep()
|
||||
this._renderSelectAddressStep()
|
||||
}
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
private renderConnectStep() {
|
||||
private _renderConnectStep() {
|
||||
return (
|
||||
<div>
|
||||
<div className="h4 pt3">
|
||||
@@ -113,7 +113,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
labelReady="Connect to Ledger"
|
||||
labelLoading="Connecting..."
|
||||
labelComplete="Connected!"
|
||||
onClickAsyncFn={this.onConnectLedgerClickAsync.bind(this, true)}
|
||||
onClickAsyncFn={this._onConnectLedgerClickAsync.bind(this, true)}
|
||||
/>
|
||||
{this.state.didConnectFail &&
|
||||
<div className="pt2 left-align" style={{color: colors.red200}}>
|
||||
@@ -124,13 +124,13 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderSelectAddressStep() {
|
||||
private _renderSelectAddressStep() {
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<Table
|
||||
bodyStyle={{height: 300}}
|
||||
onRowSelection={this.onAddressSelected.bind(this)}
|
||||
onRowSelection={this._onAddressSelected.bind(this)}
|
||||
>
|
||||
<TableHeader displaySelectAll={false}>
|
||||
<TableRow>
|
||||
@@ -139,7 +139,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{this.renderAddressTableRows()}
|
||||
{this._renderAddressTableRows()}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
@@ -151,7 +151,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
floatingLabelText="Update path derivation (advanced)"
|
||||
value={this.state.derivationPath}
|
||||
errorText={this.state.derivationErrMsg}
|
||||
onChange={this.onDerivationPathChanged.bind(this)}
|
||||
onChange={this._onDerivationPathChanged.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="pl2" style={{paddingTop: 28}}>
|
||||
@@ -159,14 +159,14 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
labelReady="Update"
|
||||
labelLoading="Updating..."
|
||||
labelComplete="Updated!"
|
||||
onClickAsyncFn={this.onFetchAddressesForDerivationPathAsync.bind(this, true)}
|
||||
onClickAsyncFn={this._onFetchAddressesForDerivationPathAsync.bind(this, true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderAddressTableRows() {
|
||||
private _renderAddressTableRows() {
|
||||
const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => {
|
||||
const balance = this.state.addressBalances[i];
|
||||
const addressTooltipId = `address-${userAddress}`;
|
||||
@@ -201,14 +201,14 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
private onClose() {
|
||||
private _onClose() {
|
||||
this.setState({
|
||||
didConnectFail: false,
|
||||
});
|
||||
const isOpen = false;
|
||||
this.props.toggleDialogFn(isOpen);
|
||||
}
|
||||
private onAddressSelected(selectedRowIndexes: number[]) {
|
||||
private _onAddressSelected(selectedRowIndexes: number[]) {
|
||||
const selectedRowIndex = selectedRowIndexes[0];
|
||||
this.props.blockchain.updateLedgerDerivationIndex(selectedRowIndex);
|
||||
const selectedAddress = this.state.userAddresses[selectedRowIndex];
|
||||
@@ -222,13 +222,13 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
const isOpen = false;
|
||||
this.props.toggleDialogFn(isOpen);
|
||||
}
|
||||
private async onFetchAddressesForDerivationPathAsync() {
|
||||
private async _onFetchAddressesForDerivationPathAsync() {
|
||||
const currentlySetPath = this.props.blockchain.getLedgerDerivationPathIfExists();
|
||||
if (currentlySetPath === this.state.derivationPath) {
|
||||
return;
|
||||
}
|
||||
this.props.blockchain.updateLedgerDerivationPathIfExists(this.state.derivationPath);
|
||||
const didSucceed = await this.fetchAddressesAndBalancesAsync();
|
||||
const didSucceed = await this._fetchAddressesAndBalancesAsync();
|
||||
if (!didSucceed) {
|
||||
this.setState({
|
||||
derivationErrMsg: 'Failed to connect to Ledger.',
|
||||
@@ -236,11 +236,11 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
}
|
||||
return didSucceed;
|
||||
}
|
||||
private async fetchAddressesAndBalancesAsync() {
|
||||
private async _fetchAddressesAndBalancesAsync() {
|
||||
let userAddresses: string[];
|
||||
const addressBalances: BigNumber[] = [];
|
||||
try {
|
||||
userAddresses = await this.getUserAddressesAsync();
|
||||
userAddresses = await this._getUserAddressesAsync();
|
||||
for (const address of userAddresses) {
|
||||
const balance = await this.props.blockchain.getBalanceInEthAsync(address);
|
||||
addressBalances.push(balance);
|
||||
@@ -258,7 +258,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
private onDerivationPathChanged(e: any, derivationPath: string) {
|
||||
private _onDerivationPathChanged(e: any, derivationPath: string) {
|
||||
let derivationErrMsg = '';
|
||||
if (!_.startsWith(derivationPath, VALID_ETHEREUM_DERIVATION_PATH_PREFIX)) {
|
||||
derivationErrMsg = 'Must be valid Ethereum path.';
|
||||
@@ -269,8 +269,8 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
derivationErrMsg,
|
||||
});
|
||||
}
|
||||
private async onConnectLedgerClickAsync() {
|
||||
const didSucceed = await this.fetchAddressesAndBalancesAsync();
|
||||
private async _onConnectLedgerClickAsync() {
|
||||
const didSucceed = await this._fetchAddressesAndBalancesAsync();
|
||||
if (didSucceed) {
|
||||
this.setState({
|
||||
stepIndex: LedgerSteps.SELECT_ADDRESS,
|
||||
@@ -278,7 +278,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
||||
}
|
||||
return didSucceed;
|
||||
}
|
||||
private async getUserAddressesAsync(): Promise<string[]> {
|
||||
private async _getUserAddressesAsync(): Promise<string[]> {
|
||||
let userAddresses: string[];
|
||||
userAddresses = await this.props.blockchain.getUserAccountsAsync();
|
||||
|
||||
|
@@ -36,14 +36,14 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
||||
<FlatButton
|
||||
key="cancelTransfer"
|
||||
label="Cancel"
|
||||
onTouchTap={this.onCancel.bind(this)}
|
||||
onTouchTap={this._onCancel.bind(this)}
|
||||
/>,
|
||||
<FlatButton
|
||||
key="sendTransfer"
|
||||
disabled={this.hasErrors()}
|
||||
disabled={this._hasErrors()}
|
||||
label="Send"
|
||||
primary={true}
|
||||
onTouchTap={this.onSendClick.bind(this)}
|
||||
onTouchTap={this._onSendClick.bind(this)}
|
||||
/>,
|
||||
];
|
||||
return (
|
||||
@@ -53,17 +53,17 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
||||
actions={transferDialogActions}
|
||||
open={this.props.isOpen}
|
||||
>
|
||||
{this.renderSendDialogBody()}
|
||||
{this._renderSendDialogBody()}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
private renderSendDialogBody() {
|
||||
private _renderSendDialogBody() {
|
||||
return (
|
||||
<div className="mx-auto" style={{maxWidth: 300}}>
|
||||
<div style={{height: 80}}>
|
||||
<AddressInput
|
||||
initialAddress={this.state.recipient}
|
||||
updateAddress={this.onRecipientChange.bind(this)}
|
||||
updateAddress={this._onRecipientChange.bind(this)}
|
||||
isRequired={true}
|
||||
label={'Recipient address'}
|
||||
hintText={'Address'}
|
||||
@@ -76,27 +76,27 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||
shouldCheckBalance={true}
|
||||
shouldCheckAllowance={false}
|
||||
onChange={this.onValueChange.bind(this)}
|
||||
onChange={this._onValueChange.bind(this)}
|
||||
amount={this.state.value}
|
||||
onVisitBalancesPageClick={this.props.onCancelled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onRecipientChange(recipient?: string) {
|
||||
private _onRecipientChange(recipient?: string) {
|
||||
this.setState({
|
||||
shouldShowIncompleteErrs: false,
|
||||
recipient,
|
||||
});
|
||||
}
|
||||
private onValueChange(isValid: boolean, amount?: BigNumber) {
|
||||
private _onValueChange(isValid: boolean, amount?: BigNumber) {
|
||||
this.setState({
|
||||
isAmountValid: isValid,
|
||||
value: amount,
|
||||
});
|
||||
}
|
||||
private onSendClick() {
|
||||
if (this.hasErrors()) {
|
||||
private _onSendClick() {
|
||||
if (this._hasErrors()) {
|
||||
this.setState({
|
||||
shouldShowIncompleteErrs: true,
|
||||
});
|
||||
@@ -109,13 +109,13 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
||||
this.props.onComplete(this.state.recipient, value);
|
||||
}
|
||||
}
|
||||
private onCancel() {
|
||||
private _onCancel() {
|
||||
this.setState({
|
||||
value: undefined,
|
||||
});
|
||||
this.props.onCancelled();
|
||||
}
|
||||
private hasErrors() {
|
||||
private _hasErrors() {
|
||||
return _.isUndefined(this.state.recipient) ||
|
||||
_.isUndefined(this.state.value) ||
|
||||
!this.state.isAmountValid;
|
||||
|
@@ -41,12 +41,12 @@ export class TrackTokenConfirmationDialog extends
|
||||
<FlatButton
|
||||
key="trackNo"
|
||||
label="No"
|
||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, false)}
|
||||
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, false)}
|
||||
/>,
|
||||
<FlatButton
|
||||
key="trackYes"
|
||||
label="Yes"
|
||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, true)}
|
||||
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, true)}
|
||||
/>,
|
||||
]}
|
||||
open={this.props.isOpen}
|
||||
@@ -64,7 +64,7 @@ export class TrackTokenConfirmationDialog extends
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
private async onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
||||
private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
||||
if (!didUserAcceptTracking) {
|
||||
this.props.onToggleDialog(didUserAcceptTracking);
|
||||
return;
|
||||
|
@@ -59,13 +59,13 @@ export class EthWethConversionButton extends
|
||||
labelStyle={labelStyle}
|
||||
disabled={this.props.isDisabled || this.state.isEthConversionHappening}
|
||||
label={this.state.isEthConversionHappening ? inProgressLabel : callToActionLabel}
|
||||
onClick={this.toggleConversionDialog.bind(this)}
|
||||
onClick={this._toggleConversionDialog.bind(this)}
|
||||
/>
|
||||
<EthWethConversionDialog
|
||||
direction={this.props.direction}
|
||||
isOpen={this.state.isEthConversionDialogVisible}
|
||||
onComplete={this.onConversionAmountSelectedAsync.bind(this)}
|
||||
onCancelled={this.toggleConversionDialog.bind(this)}
|
||||
onComplete={this._onConversionAmountSelectedAsync.bind(this)}
|
||||
onCancelled={this._toggleConversionDialog.bind(this)}
|
||||
etherBalance={this.props.userEtherBalance}
|
||||
token={this.props.ethToken}
|
||||
tokenState={this.props.ethTokenState}
|
||||
@@ -73,16 +73,16 @@ export class EthWethConversionButton extends
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private toggleConversionDialog() {
|
||||
private _toggleConversionDialog() {
|
||||
this.setState({
|
||||
isEthConversionDialogVisible: !this.state.isEthConversionDialogVisible,
|
||||
});
|
||||
}
|
||||
private async onConversionAmountSelectedAsync(direction: Side, value: BigNumber) {
|
||||
private async _onConversionAmountSelectedAsync(direction: Side, value: BigNumber) {
|
||||
this.setState({
|
||||
isEthConversionHappening: true,
|
||||
});
|
||||
this.toggleConversionDialog();
|
||||
this._toggleConversionDialog();
|
||||
const token = this.props.ethToken;
|
||||
const tokenState = this.props.ethTokenState;
|
||||
let balance = tokenState.balance;
|
||||
@@ -109,11 +109,11 @@ export class EthWethConversionButton extends
|
||||
} else if (!_.includes(errMsg, 'User denied transaction')) {
|
||||
utils.consoleLog(`Unexpected error encountered: ${err}`);
|
||||
utils.consoleLog(err.stack);
|
||||
await errorReporter.reportAsync(err);
|
||||
const errorMsg = direction === Side.Deposit ?
|
||||
'Failed to wrap your ETH. Please try again.' :
|
||||
'Failed to unwrap your WETH. Please try again.';
|
||||
this.props.dispatcher.showFlashMessage(errorMsg);
|
||||
await errorReporter.reportAsync(err);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
|
@@ -61,7 +61,7 @@ interface EthWrappersState {
|
||||
export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
|
||||
constructor(props: EthWrappersProps) {
|
||||
super(props);
|
||||
const outdatedWETHAddresses = this.getOutdatedWETHAddresses();
|
||||
const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
|
||||
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
|
||||
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
||||
_.each(outdatedWETHAddresses, outdatedWETHAddress => {
|
||||
@@ -79,7 +79,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
public componentDidMount() {
|
||||
window.scrollTo(0, 0);
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.fetchOutdatedWETHStateAsync();
|
||||
this._fetchOutdatedWETHStateAsync();
|
||||
}
|
||||
public render() {
|
||||
const tokens = _.values(this.props.tokenByAddress);
|
||||
@@ -90,7 +90,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
const etherscanUrl = utils.getEtherScanLinkIfExists(
|
||||
etherToken.address, this.props.networkId, EtherscanLinkSuffixes.Address,
|
||||
);
|
||||
const tokenLabel = this.renderToken('Wrapped Ether', etherToken.address, configs.ICON_URL_BY_SYMBOL.WETH);
|
||||
const tokenLabel = this._renderToken('Wrapped Ether', etherToken.address, configs.ICON_URL_BY_SYMBOL.WETH);
|
||||
return (
|
||||
<div className="clearfix lg-px4 md-px4 sm-px2" style={{minHeight: 600}}>
|
||||
<div className="relative">
|
||||
@@ -125,7 +125,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
<TableHeaderColumn>ETH Token</TableHeaderColumn>
|
||||
<TableHeaderColumn>Balance</TableHeaderColumn>
|
||||
<TableHeaderColumn className="center">
|
||||
{this.renderActionColumnTitle(isBidirectional)}
|
||||
{this._renderActionColumnTitle(isBidirectional)}
|
||||
</TableHeaderColumn>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -162,7 +162,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
</TableRow>
|
||||
<TableRow key="WETH">
|
||||
<TableRowColumn className="py1">
|
||||
{this.renderTokenLink(tokenLabel, etherscanUrl)}
|
||||
{this._renderTokenLink(tokenLabel, etherscanUrl)}
|
||||
</TableRowColumn>
|
||||
<TableRowColumn>
|
||||
{wethBalance.toFixed(PRECISION)} WETH
|
||||
@@ -207,12 +207,12 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
<TableHeaderColumn>WETH Version</TableHeaderColumn>
|
||||
<TableHeaderColumn>Balance</TableHeaderColumn>
|
||||
<TableHeaderColumn className="center">
|
||||
{this.renderActionColumnTitle(!isBidirectional)}
|
||||
{this._renderActionColumnTitle(!isBidirectional)}
|
||||
</TableHeaderColumn>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody displayRowCheckbox={false}>
|
||||
{this.renderOutdatedWeths(etherToken, etherTokenState)}
|
||||
{this._renderOutdatedWeths(etherToken, etherTokenState)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
@@ -220,7 +220,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderActionColumnTitle(isBidirectional: boolean) {
|
||||
private _renderActionColumnTitle(isBidirectional: boolean) {
|
||||
let iconClass = 'zmdi-long-arrow-right';
|
||||
let leftSymbol = 'WETH';
|
||||
let rightSymbol = 'ETH';
|
||||
@@ -242,7 +242,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderOutdatedWeths(etherToken: Token, etherTokenState: TokenState) {
|
||||
private _renderOutdatedWeths(etherToken: Token, etherTokenState: TokenState) {
|
||||
const rows = _.map(configs.OUTDATED_WRAPPED_ETHERS,
|
||||
(outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => {
|
||||
const outdatedWETHIfExists = outdatedWETHByNetworkId[this.props.networkId];
|
||||
@@ -269,17 +269,17 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH,
|
||||
).toFixed(PRECISION) :
|
||||
undefined;
|
||||
const onConversionSuccessful = this.onOutdatedConversionSuccessfulAsync.bind(
|
||||
const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind(
|
||||
this, outdatedWETHIfExists.address,
|
||||
);
|
||||
const etherscanUrl = utils.getEtherScanLinkIfExists(
|
||||
outdatedWETHIfExists.address, this.props.networkId, EtherscanLinkSuffixes.Address,
|
||||
);
|
||||
const tokenLabel = this.renderToken(dateRange, outdatedEtherToken.address, OUTDATED_WETH_ICON_PATH);
|
||||
const tokenLabel = this._renderToken(dateRange, outdatedEtherToken.address, OUTDATED_WETH_ICON_PATH);
|
||||
return (
|
||||
<TableRow key={`weth-${outdatedWETHIfExists.address}`}>
|
||||
<TableRowColumn className="py1">
|
||||
{this.renderTokenLink(tokenLabel, etherscanUrl)}
|
||||
{this._renderTokenLink(tokenLabel, etherscanUrl)}
|
||||
</TableRowColumn>
|
||||
<TableRowColumn>
|
||||
{isStateLoaded ?
|
||||
@@ -305,7 +305,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
private renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string) {
|
||||
private _renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string) {
|
||||
return (
|
||||
<span>
|
||||
{_.isUndefined(etherscanUrl) ?
|
||||
@@ -317,7 +317,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
</span>
|
||||
);
|
||||
}
|
||||
private renderToken(name: string, address: string, imgPath: string) {
|
||||
private _renderToken(name: string, address: string, imgPath: string) {
|
||||
const tooltipId = `tooltip-${address}`;
|
||||
return (
|
||||
<div className="flex">
|
||||
@@ -340,7 +340,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private async onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) {
|
||||
private async _onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) {
|
||||
this.setState({
|
||||
outdatedWETHAddressToIsStateLoaded: {
|
||||
...this.state.outdatedWETHAddressToIsStateLoaded,
|
||||
@@ -364,8 +364,8 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
},
|
||||
});
|
||||
}
|
||||
private async fetchOutdatedWETHStateAsync() {
|
||||
const outdatedWETHAddresses = this.getOutdatedWETHAddresses();
|
||||
private async _fetchOutdatedWETHStateAsync() {
|
||||
const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
|
||||
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
|
||||
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
||||
for (const address of outdatedWETHAddresses) {
|
||||
@@ -383,7 +383,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
||||
outdatedWETHAddressToIsStateLoaded,
|
||||
});
|
||||
}
|
||||
private getOutdatedWETHAddresses(): string[] {
|
||||
private _getOutdatedWETHAddresses(): string[] {
|
||||
const outdatedWETHAddresses = _.compact(_.map(configs.OUTDATED_WRAPPED_ETHERS,
|
||||
outdatedWrappedEtherByNetwork => {
|
||||
const outdatedWrappedEtherIfExists = outdatedWrappedEtherByNetwork[this.props.networkId];
|
||||
|
@@ -66,7 +66,7 @@ interface FillOrderState {
|
||||
}
|
||||
|
||||
export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
private validator: SchemaValidator;
|
||||
private _validator: SchemaValidator;
|
||||
constructor(props: FillOrderProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -87,12 +87,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
isConfirmingTokenTracking: false,
|
||||
tokensToTrack: [],
|
||||
};
|
||||
this.validator = new SchemaValidator();
|
||||
this._validator = new SchemaValidator();
|
||||
}
|
||||
public componentWillMount() {
|
||||
if (!_.isEmpty(this.state.orderJSON)) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.validateFillOrderFireAndForgetAsync(this.state.orderJSON);
|
||||
this._validateFillOrderFireAndForgetAsync(this.state.orderJSON);
|
||||
}
|
||||
}
|
||||
public componentDidMount() {
|
||||
@@ -115,15 +115,15 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
networkId={this.props.networkId}
|
||||
orderJSON={this.state.orderJSON}
|
||||
onFillOrderJSONChanged={this.onFillOrderJSONChanged.bind(this)}
|
||||
onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
|
||||
/>
|
||||
{this.renderOrderJsonNotices()}
|
||||
{this._renderOrderJsonNotices()}
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
{!_.isUndefined(this.state.parsedOrder) && this.state.didOrderValidationRun
|
||||
&& this.state.areAllInvolvedTokensTracked &&
|
||||
this.renderVisualOrder()
|
||||
this._renderVisualOrder()
|
||||
}
|
||||
</div>
|
||||
{this.props.isOrderInUrl &&
|
||||
@@ -140,17 +140,17 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
networkId={this.props.networkId}
|
||||
orderJSON={this.state.orderJSON}
|
||||
onFillOrderJSONChanged={this.onFillOrderJSONChanged.bind(this)}
|
||||
onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
|
||||
/>
|
||||
</CardText>
|
||||
</Card>
|
||||
{this.renderOrderJsonNotices()}
|
||||
{this._renderOrderJsonNotices()}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<FillWarningDialog
|
||||
isOpen={this.state.isFillWarningDialogOpen}
|
||||
onToggleDialog={this.onFillWarningClosed.bind(this)}
|
||||
onToggleDialog={this._onFillWarningClosed.bind(this)}
|
||||
/>
|
||||
<TrackTokenConfirmationDialog
|
||||
userAddress={this.props.userAddress}
|
||||
@@ -160,12 +160,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
dispatcher={this.props.dispatcher}
|
||||
tokens={this.state.tokensToTrack}
|
||||
isOpen={this.state.isConfirmingTokenTracking}
|
||||
onToggleDialog={this.onToggleTrackConfirmDialog.bind(this)}
|
||||
onToggleDialog={this._onToggleTrackConfirmDialog.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderOrderJsonNotices() {
|
||||
private _renderOrderJsonNotices() {
|
||||
return (
|
||||
<div>
|
||||
{!_.isUndefined(this.props.initialOrder) && !this.state.didOrderValidationRun &&
|
||||
@@ -182,7 +182,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderVisualOrder() {
|
||||
private _renderVisualOrder() {
|
||||
const takerTokenAddress = this.state.parsedOrder.taker.token.address;
|
||||
const takerToken = this.props.tokenByAddress[takerTokenAddress];
|
||||
const orderTakerAmount = new BigNumber(this.state.parsedOrder.taker.amount);
|
||||
@@ -211,7 +211,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
let orderReceiveAmount = 0;
|
||||
if (!_.isUndefined(this.props.orderFillAmount)) {
|
||||
const orderReceiveAmountBigNumber = exchangeRate.mul(this.props.orderFillAmount);
|
||||
orderReceiveAmount = this.formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals);
|
||||
orderReceiveAmount = this._formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals);
|
||||
}
|
||||
const isUserMaker = !_.isUndefined(this.state.parsedOrder) &&
|
||||
this.state.parsedOrder.maker.address === this.props.userAddress;
|
||||
@@ -261,7 +261,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
<div className="clearfix mx-auto relative" style={{width: 235, height: 108}}>
|
||||
<TokenAmountInput
|
||||
label="Fill amount"
|
||||
onChange={this.onFillAmountChange.bind(this)}
|
||||
onChange={this._onFillAmountChange.bind(this)}
|
||||
shouldShowIncompleteErrs={false}
|
||||
token={fillToken}
|
||||
tokenState={fillTokenState}
|
||||
@@ -284,12 +284,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
style={{width: '100%'}}
|
||||
disabled={this.state.isCancelling}
|
||||
label={this.state.isCancelling ? 'Cancelling order...' : 'Cancel order'}
|
||||
onClick={this.onCancelOrderClickFireAndForgetAsync.bind(this)}
|
||||
onClick={this._onCancelOrderClickFireAndForgetAsync.bind(this)}
|
||||
/>
|
||||
{this.state.didCancelOrderSucceed &&
|
||||
<Alert
|
||||
type={AlertTypes.SUCCESS}
|
||||
message={this.renderCancelSuccessMsg()}
|
||||
message={this._renderCancelSuccessMsg()}
|
||||
/>
|
||||
}
|
||||
</div> :
|
||||
@@ -298,7 +298,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
style={{width: '100%'}}
|
||||
disabled={this.state.isFilling}
|
||||
label={this.state.isFilling ? 'Filling order...' : 'Fill order'}
|
||||
onClick={this.onFillOrderClick.bind(this)}
|
||||
onClick={this._onFillOrderClick.bind(this)}
|
||||
/>
|
||||
{!_.isEmpty(this.state.globalErrMsg) &&
|
||||
<Alert type={AlertTypes.ERROR} message={this.state.globalErrMsg} />
|
||||
@@ -306,7 +306,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
{this.state.didFillOrderSucceed &&
|
||||
<Alert
|
||||
type={AlertTypes.SUCCESS}
|
||||
message={this.renderFillSuccessMsg()}
|
||||
message={this._renderFillSuccessMsg()}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
@@ -315,7 +315,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderFillSuccessMsg() {
|
||||
private _renderFillSuccessMsg() {
|
||||
return (
|
||||
<div>
|
||||
Order successfully filled. See the trade details in your{' '}
|
||||
@@ -328,45 +328,45 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderCancelSuccessMsg() {
|
||||
private _renderCancelSuccessMsg() {
|
||||
return (
|
||||
<div>
|
||||
Order successfully cancelled.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onFillOrderClick() {
|
||||
private _onFillOrderClick() {
|
||||
if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) {
|
||||
this.setState({
|
||||
isFillWarningDialogOpen: true,
|
||||
});
|
||||
} else {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.onFillOrderClickFireAndForgetAsync();
|
||||
this._onFillOrderClickFireAndForgetAsync();
|
||||
}
|
||||
}
|
||||
private onFillWarningClosed(didUserCancel: boolean) {
|
||||
private _onFillWarningClosed(didUserCancel: boolean) {
|
||||
this.setState({
|
||||
isFillWarningDialogOpen: false,
|
||||
});
|
||||
if (!didUserCancel) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.onFillOrderClickFireAndForgetAsync();
|
||||
this._onFillOrderClickFireAndForgetAsync();
|
||||
}
|
||||
}
|
||||
private onFillAmountChange(isValid: boolean, amount?: BigNumber) {
|
||||
private _onFillAmountChange(isValid: boolean, amount?: BigNumber) {
|
||||
this.props.dispatcher.updateOrderFillAmount(amount);
|
||||
}
|
||||
private onFillOrderJSONChanged(event: any) {
|
||||
private _onFillOrderJSONChanged(event: any) {
|
||||
const orderJSON = event.target.value;
|
||||
this.setState({
|
||||
didOrderValidationRun: _.isEmpty(orderJSON) && _.isEmpty(this.state.orderJSONErrMsg),
|
||||
didFillOrderSucceed: false,
|
||||
});
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.validateFillOrderFireAndForgetAsync(orderJSON);
|
||||
this._validateFillOrderFireAndForgetAsync(orderJSON);
|
||||
}
|
||||
private async checkForUntrackedTokensAndAskToAdd() {
|
||||
private async _checkForUntrackedTokensAndAskToAdd() {
|
||||
if (!_.isEmpty(this.state.orderJSONErrMsg)) {
|
||||
return;
|
||||
}
|
||||
@@ -410,12 +410,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
});
|
||||
}
|
||||
}
|
||||
private async validateFillOrderFireAndForgetAsync(orderJSON: string) {
|
||||
private async _validateFillOrderFireAndForgetAsync(orderJSON: string) {
|
||||
let orderJSONErrMsg = '';
|
||||
let parsedOrder: Order;
|
||||
try {
|
||||
const order = JSON.parse(orderJSON);
|
||||
const validationResult = this.validator.validate(order, orderSchema);
|
||||
const validationResult = this._validator.validate(order, orderSchema);
|
||||
if (validationResult.errors.length > 0) {
|
||||
orderJSONErrMsg = 'Submitted order JSON is not a valid order';
|
||||
utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`);
|
||||
@@ -508,9 +508,9 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
unavailableTakerAmount,
|
||||
});
|
||||
|
||||
await this.checkForUntrackedTokensAndAskToAdd();
|
||||
await this._checkForUntrackedTokensAndAskToAdd();
|
||||
}
|
||||
private async onFillOrderClickFireAndForgetAsync(): Promise<void> {
|
||||
private async _onFillOrderClickFireAndForgetAsync(): Promise<void> {
|
||||
if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) {
|
||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
return;
|
||||
@@ -594,14 +594,14 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
}
|
||||
globalErrMsg = 'Failed to fill order, please refresh and try again';
|
||||
utils.consoleLog(`${err}`);
|
||||
await errorReporter.reportAsync(err);
|
||||
this.setState({
|
||||
globalErrMsg,
|
||||
});
|
||||
await errorReporter.reportAsync(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
private async onCancelOrderClickFireAndForgetAsync(): Promise<void> {
|
||||
private async _onCancelOrderClickFireAndForgetAsync(): Promise<void> {
|
||||
if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) {
|
||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
return;
|
||||
@@ -677,19 +677,19 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||
}
|
||||
globalErrMsg = 'Failed to cancel order, please refresh and try again';
|
||||
utils.consoleLog(`${err}`);
|
||||
await errorReporter.reportAsync(err);
|
||||
this.setState({
|
||||
globalErrMsg,
|
||||
});
|
||||
await errorReporter.reportAsync(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
private formatCurrencyAmount(amount: BigNumber, decimals: number): number {
|
||||
private _formatCurrencyAmount(amount: BigNumber, decimals: number): number {
|
||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||
const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000;
|
||||
return roundedUnitAmount;
|
||||
}
|
||||
private onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) {
|
||||
private _onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) {
|
||||
if (!didConfirmTokenTracking) {
|
||||
this.setState({
|
||||
orderJSON: '',
|
||||
|
@@ -133,20 +133,20 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
<div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4">
|
||||
<div className="col lg-col-4 md-col-4 col-12">
|
||||
<div className="lg-right md-right sm-center">
|
||||
{this.renderHeader(Sections.Documentation)}
|
||||
{_.map(menuItemsBySection[Sections.Documentation], this.renderMenuItem.bind(this))}
|
||||
{this._renderHeader(Sections.Documentation)}
|
||||
{_.map(menuItemsBySection[Sections.Documentation], this._renderMenuItem.bind(this))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
|
||||
<div className="lg-right md-right sm-center">
|
||||
{this.renderHeader(Sections.Community)}
|
||||
{_.map(menuItemsBySection[Sections.Community], this.renderMenuItem.bind(this))}
|
||||
{this._renderHeader(Sections.Community)}
|
||||
{_.map(menuItemsBySection[Sections.Community], this._renderMenuItem.bind(this))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col lg-col-4 md-col-4 col-12">
|
||||
<div className="lg-right md-right sm-center">
|
||||
{this.renderHeader(Sections.Organization)}
|
||||
{_.map(menuItemsBySection[Sections.Organization], this.renderMenuItem.bind(this))}
|
||||
{this._renderHeader(Sections.Organization)}
|
||||
{_.map(menuItemsBySection[Sections.Organization], this._renderMenuItem.bind(this))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,14 +154,14 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderIcon(fileName: string) {
|
||||
private _renderIcon(fileName: string) {
|
||||
return (
|
||||
<div style={{height: ICON_DIMENSION, width: ICON_DIMENSION}}>
|
||||
<img src={`/images/social/${fileName}`} style={{width: ICON_DIMENSION}} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderMenuItem(item: FooterMenuItem) {
|
||||
private _renderMenuItem(item: FooterMenuItem) {
|
||||
const iconIfExists = titleToIcon[item.title];
|
||||
return (
|
||||
<div
|
||||
@@ -180,7 +180,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
<div className="sm-mx-auto" style={{width: 65}}>
|
||||
<div className="flex">
|
||||
<div className="pr1">
|
||||
{this.renderIcon(iconIfExists)}
|
||||
{this._renderIcon(iconIfExists)}
|
||||
</div>
|
||||
<div>{item.title}</div>
|
||||
</div>
|
||||
@@ -196,7 +196,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
<div>
|
||||
{!_.isUndefined(iconIfExists) &&
|
||||
<div className="pr1">
|
||||
{this.renderIcon(iconIfExists)}
|
||||
{this._renderIcon(iconIfExists)}
|
||||
</div>
|
||||
}
|
||||
{item.title}
|
||||
@@ -206,7 +206,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderHeader(title: string) {
|
||||
private _renderHeader(title: string) {
|
||||
const headerStyle = {
|
||||
textTransform: 'uppercase',
|
||||
color: colors.grey400,
|
||||
|
@@ -47,7 +47,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
public static defaultProps: Partial<AssetPickerProps> = {
|
||||
tokenVisibility: TokenVisibility.ALL,
|
||||
};
|
||||
private dialogConfigsByAssetView: {[assetView: string]: DialogConfigs};
|
||||
private _dialogConfigsByAssetView: {[assetView: string]: DialogConfigs};
|
||||
constructor(props: AssetPickerProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -56,7 +56,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
chosenTrackTokenAddress: undefined,
|
||||
isAddingTokenToTracked: false,
|
||||
};
|
||||
this.dialogConfigsByAssetView = {
|
||||
this._dialogConfigsByAssetView = {
|
||||
[AssetViews.ASSET_PICKER]: {
|
||||
title: 'Select token',
|
||||
isModal: false,
|
||||
@@ -74,19 +74,19 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
<FlatButton
|
||||
key="noTracking"
|
||||
label="No"
|
||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, false)}
|
||||
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, false)}
|
||||
/>,
|
||||
<FlatButton
|
||||
key="yesTrack"
|
||||
label="Yes"
|
||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, true)}
|
||||
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, true)}
|
||||
/>,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
public render() {
|
||||
const dialogConfigs: DialogConfigs = this.dialogConfigsByAssetView[this.state.assetView];
|
||||
const dialogConfigs: DialogConfigs = this._dialogConfigsByAssetView[this.state.assetView];
|
||||
return (
|
||||
<Dialog
|
||||
title={dialogConfigs.title}
|
||||
@@ -94,25 +94,25 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
modal={dialogConfigs.isModal}
|
||||
open={this.props.isOpen}
|
||||
actions={dialogConfigs.actions}
|
||||
onRequestClose={this.onCloseDialog.bind(this)}
|
||||
onRequestClose={this._onCloseDialog.bind(this)}
|
||||
>
|
||||
{this.state.assetView === AssetViews.ASSET_PICKER &&
|
||||
this.renderAssetPicker()
|
||||
this._renderAssetPicker()
|
||||
}
|
||||
{this.state.assetView === AssetViews.NEW_TOKEN_FORM &&
|
||||
<NewTokenForm
|
||||
blockchain={this.props.blockchain}
|
||||
onNewTokenSubmitted={this.onNewTokenSubmitted.bind(this)}
|
||||
onNewTokenSubmitted={this._onNewTokenSubmitted.bind(this)}
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
/>
|
||||
}
|
||||
{this.state.assetView === AssetViews.CONFIRM_TRACK_TOKEN &&
|
||||
this.renderConfirmTrackToken()
|
||||
this._renderConfirmTrackToken()
|
||||
}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
private renderConfirmTrackToken() {
|
||||
private _renderConfirmTrackToken() {
|
||||
const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress];
|
||||
return (
|
||||
<TrackTokenConfirmation
|
||||
@@ -123,17 +123,17 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
/>
|
||||
);
|
||||
}
|
||||
private renderAssetPicker() {
|
||||
private _renderAssetPicker() {
|
||||
return (
|
||||
<div
|
||||
className="clearfix flex flex-wrap"
|
||||
style={{overflowY: 'auto', maxWidth: 720, maxHeight: 356, marginBottom: 10}}
|
||||
>
|
||||
{this.renderGridTiles()}
|
||||
{this._renderGridTiles()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderGridTiles() {
|
||||
private _renderGridTiles() {
|
||||
let isHovered;
|
||||
let tileStyles;
|
||||
const gridTiles = _.map(this.props.tokenByAddress, (token: Token, address: string) => {
|
||||
@@ -151,9 +151,9 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
key={address}
|
||||
style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}}
|
||||
className="p2 mx-auto"
|
||||
onClick={this.onChooseToken.bind(this, address)}
|
||||
onMouseEnter={this.onToggleHover.bind(this, address, true)}
|
||||
onMouseLeave={this.onToggleHover.bind(this, address, false)}
|
||||
onClick={this._onChooseToken.bind(this, address)}
|
||||
onMouseEnter={this._onToggleHover.bind(this, address, true)}
|
||||
onMouseLeave={this._onToggleHover.bind(this, address, false)}
|
||||
>
|
||||
<div className="p1 center">
|
||||
<TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} />
|
||||
@@ -174,9 +174,9 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
key={otherTokenKey}
|
||||
style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}}
|
||||
className="p2 mx-auto"
|
||||
onClick={this.onCustomAssetChosen.bind(this)}
|
||||
onMouseEnter={this.onToggleHover.bind(this, otherTokenKey, true)}
|
||||
onMouseLeave={this.onToggleHover.bind(this, otherTokenKey, false)}
|
||||
onClick={this._onCustomAssetChosen.bind(this)}
|
||||
onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)}
|
||||
onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)}
|
||||
>
|
||||
<div className="p1 center">
|
||||
<i
|
||||
@@ -190,19 +190,19 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
}
|
||||
return gridTiles;
|
||||
}
|
||||
private onToggleHover(address: string, isHovered: boolean) {
|
||||
private _onToggleHover(address: string, isHovered: boolean) {
|
||||
const hoveredAddress = isHovered ? address : undefined;
|
||||
this.setState({
|
||||
hoveredAddress,
|
||||
});
|
||||
}
|
||||
private onCloseDialog() {
|
||||
private _onCloseDialog() {
|
||||
this.setState({
|
||||
assetView: AssetViews.ASSET_PICKER,
|
||||
});
|
||||
this.props.onTokenChosen(this.props.currentTokenAddress);
|
||||
}
|
||||
private onChooseToken(tokenAddress: string) {
|
||||
private _onChooseToken(tokenAddress: string) {
|
||||
const token = this.props.tokenByAddress[tokenAddress];
|
||||
if (token.isTracked) {
|
||||
this.props.onTokenChosen(tokenAddress);
|
||||
@@ -213,12 +213,12 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
});
|
||||
}
|
||||
}
|
||||
private onCustomAssetChosen() {
|
||||
private _onCustomAssetChosen() {
|
||||
this.setState({
|
||||
assetView: AssetViews.NEW_TOKEN_FORM,
|
||||
});
|
||||
}
|
||||
private onNewTokenSubmitted(newToken: Token, newTokenState: TokenState) {
|
||||
private _onNewTokenSubmitted(newToken: Token, newTokenState: TokenState) {
|
||||
this.props.dispatcher.updateTokenStateByAddress({
|
||||
[newToken.address]: newTokenState,
|
||||
});
|
||||
@@ -229,14 +229,14 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
||||
});
|
||||
this.props.onTokenChosen(newToken.address);
|
||||
}
|
||||
private async onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
||||
private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
||||
if (!didUserAcceptTracking) {
|
||||
this.setState({
|
||||
isAddingTokenToTracked: false,
|
||||
assetView: AssetViews.ASSET_PICKER,
|
||||
chosenTrackTokenAddress: undefined,
|
||||
});
|
||||
this.onCloseDialog();
|
||||
this._onCloseDialog();
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
|
@@ -63,7 +63,7 @@ interface GenerateOrderFormState {
|
||||
}
|
||||
|
||||
export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> {
|
||||
private validator: SchemaValidator;
|
||||
private _validator: SchemaValidator;
|
||||
constructor(props: GenerateOrderFormProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -71,7 +71,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
shouldShowIncompleteErrs: false,
|
||||
signingState: SigningState.UNSIGNED,
|
||||
};
|
||||
this.validator = new SchemaValidator();
|
||||
this._validator = new SchemaValidator();
|
||||
}
|
||||
public componentDidMount() {
|
||||
window.scrollTo(0, 0);
|
||||
@@ -113,7 +113,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
token={depositToken}
|
||||
tokenState={depositTokenState}
|
||||
amount={this.props.sideToAssetToken[Side.Deposit].amount}
|
||||
onChange={this.onTokenAmountChange.bind(this, depositToken, Side.Deposit)}
|
||||
onChange={this._onTokenAmountChange.bind(this, depositToken, Side.Deposit)}
|
||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||
shouldCheckBalance={true}
|
||||
shouldCheckAllowance={true}
|
||||
@@ -144,7 +144,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
token={receiveToken}
|
||||
tokenState={receiveTokenState}
|
||||
amount={this.props.sideToAssetToken[Side.Receive].amount}
|
||||
onChange={this.onTokenAmountChange.bind(this, receiveToken, Side.Receive)}
|
||||
onChange={this._onTokenAmountChange.bind(this, receiveToken, Side.Receive)}
|
||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||
shouldCheckBalance={false}
|
||||
shouldCheckAllowance={false}
|
||||
@@ -165,7 +165,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
<IdenticonAddressInput
|
||||
label="Taker"
|
||||
initialAddress={this.props.orderTakerAddress}
|
||||
updateOrderAddress={this.updateOrderAddress.bind(this)}
|
||||
updateOrderAddress={this._updateOrderAddress.bind(this)}
|
||||
/>
|
||||
<div className="pt3">
|
||||
<div className="pl1">
|
||||
@@ -189,7 +189,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
labelReady="Sign hash"
|
||||
labelLoading="Signing..."
|
||||
labelComplete="Hash signed!"
|
||||
onClickAsyncFn={this.onSignClickedAsync.bind(this)}
|
||||
onClickAsyncFn={this._onSignClickedAsync.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
{this.state.globalErrMsg !== '' &&
|
||||
@@ -202,7 +202,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
titleStyle={{fontWeight: 100}}
|
||||
modal={false}
|
||||
open={this.state.signingState === SigningState.SIGNED}
|
||||
onRequestClose={this.onCloseOrderJSONDialog.bind(this)}
|
||||
onRequestClose={this._onCloseOrderJSONDialog.bind(this)}
|
||||
>
|
||||
<OrderJSON
|
||||
exchangeContractIfExists={exchangeContractIfExists}
|
||||
@@ -222,10 +222,10 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onTokenAmountChange(token: Token, side: Side, isValid: boolean, amount?: BigNumber) {
|
||||
private _onTokenAmountChange(token: Token, side: Side, isValid: boolean, amount?: BigNumber) {
|
||||
this.props.dispatcher.updateChosenAssetToken(side, {address: token.address, amount});
|
||||
}
|
||||
private onCloseOrderJSONDialog() {
|
||||
private _onCloseOrderJSONDialog() {
|
||||
// Upon closing the order JSON dialog, we update the orderSalt stored in the Redux store
|
||||
// with a new value so that if a user signs the identical order again, the newly signed
|
||||
// orderHash will not collide with the previously generated orderHash.
|
||||
@@ -234,7 +234,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
signingState: SigningState.UNSIGNED,
|
||||
});
|
||||
}
|
||||
private async onSignClickedAsync(): Promise<boolean> {
|
||||
private async _onSignClickedAsync(): Promise<boolean> {
|
||||
if (this.props.blockchainErr !== BlockchainErrs.NoError) {
|
||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
return false;
|
||||
@@ -249,7 +249,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
debitToken.amount.gt(0) && receiveAmount.gt(0) &&
|
||||
this.props.userAddress !== '' &&
|
||||
debitBalance.gte(debitToken.amount) && debitAllowance.gte(debitToken.amount)) {
|
||||
const didSignSuccessfully = await this.signTransactionAsync();
|
||||
const didSignSuccessfully = await this._signTransactionAsync();
|
||||
if (didSignSuccessfully) {
|
||||
this.setState({
|
||||
globalErrMsg: '',
|
||||
@@ -270,7 +270,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private async signTransactionAsync(): Promise<boolean> {
|
||||
private async _signTransactionAsync(): Promise<boolean> {
|
||||
this.setState({
|
||||
signingState: SigningState.SIGNING,
|
||||
});
|
||||
@@ -308,7 +308,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
this.props.userAddress, hashData.makerFee, hashData.takerFee,
|
||||
hashData.feeRecipientAddress, signatureData, this.props.tokenByAddress,
|
||||
hashData.orderSalt);
|
||||
const validationResult = this.validator.validate(order, orderSchema);
|
||||
const validationResult = this._validator.validate(order, orderSchema);
|
||||
if (validationResult.errors.length > 0) {
|
||||
globalErrMsg = 'Order signing failed. Please refresh and try again';
|
||||
utils.consoleLog(`Unexpected error occured: Order validation failed:
|
||||
@@ -331,7 +331,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
||||
});
|
||||
return globalErrMsg === '';
|
||||
}
|
||||
private updateOrderAddress(address?: string): void {
|
||||
private _updateOrderAddress(address?: string): void {
|
||||
if (!_.isUndefined(address)) {
|
||||
this.props.dispatcher.updateOrderTakerAddress(address);
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
floatingLabelText={<RequiredLabel label="Name" />}
|
||||
value={this.state.name}
|
||||
errorText={this.state.nameErrText}
|
||||
onChange={this.onTokenNameChanged.bind(this)}
|
||||
onChange={this._onTokenNameChanged.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -63,7 +63,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
floatingLabelText={<RequiredLabel label="Symbol" />}
|
||||
value={this.state.symbol}
|
||||
errorText={this.state.symbolErrText}
|
||||
onChange={this.onTokenSymbolChanged.bind(this)}
|
||||
onChange={this._onTokenSymbolChanged.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -72,7 +72,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
label="Contract address"
|
||||
initialAddress=""
|
||||
shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr}
|
||||
updateAddress={this.onTokenAddressChanged.bind(this)}
|
||||
updateAddress={this._onTokenAddressChanged.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -82,7 +82,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
floatingLabelText={<RequiredLabel label="Decimals" />}
|
||||
value={this.state.decimals}
|
||||
errorText={this.state.decimalsErrText}
|
||||
onChange={this.onTokenDecimalsChanged.bind(this)}
|
||||
onChange={this._onTokenDecimalsChanged.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="pt2 mx-auto" style={{width: 120}}>
|
||||
@@ -90,7 +90,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
labelReady="Add"
|
||||
labelLoading="Adding..."
|
||||
labelComplete="Added!"
|
||||
onClickAsyncFn={this.onAddNewTokenClickAsync.bind(this)}
|
||||
onClickAsyncFn={this._onAddNewTokenClickAsync.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
{this.state.globalErrMsg !== '' &&
|
||||
@@ -99,11 +99,11 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private async onAddNewTokenClickAsync() {
|
||||
private async _onAddNewTokenClickAsync() {
|
||||
// Trigger validation of name and symbol
|
||||
this.onTokenNameChanged(undefined, this.state.name);
|
||||
this.onTokenSymbolChanged(undefined, this.state.symbol);
|
||||
this.onTokenDecimalsChanged(undefined, this.state.decimals);
|
||||
this._onTokenNameChanged(undefined, this.state.name);
|
||||
this._onTokenSymbolChanged(undefined, this.state.symbol);
|
||||
this._onTokenDecimalsChanged(undefined, this.state.decimals);
|
||||
|
||||
const isAddressIncomplete = this.state.address === '';
|
||||
let doesContractExist = false;
|
||||
@@ -160,7 +160,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
};
|
||||
this.props.onNewTokenSubmitted(newToken, newTokenState);
|
||||
}
|
||||
private onTokenNameChanged(e: any, name: string) {
|
||||
private _onTokenNameChanged(e: any, name: string) {
|
||||
let nameErrText = '';
|
||||
const maxLength = 30;
|
||||
const tokens = _.values(this.props.tokenByAddress);
|
||||
@@ -168,7 +168,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
const tokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
|
||||
if (name === '') {
|
||||
nameErrText = 'Name is required';
|
||||
} else if (!this.isValidName(name)) {
|
||||
} else if (!this._isValidName(name)) {
|
||||
nameErrText = 'Name should only contain letters, digits and spaces';
|
||||
} else if (name.length > maxLength) {
|
||||
nameErrText = `Max length is ${maxLength}`;
|
||||
@@ -181,14 +181,14 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
nameErrText,
|
||||
});
|
||||
}
|
||||
private onTokenSymbolChanged(e: any, symbol: string) {
|
||||
private _onTokenSymbolChanged(e: any, symbol: string) {
|
||||
let symbolErrText = '';
|
||||
const maxLength = 5;
|
||||
const tokens = _.values(this.props.tokenByAddress);
|
||||
const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, {symbol}));
|
||||
if (symbol === '') {
|
||||
symbolErrText = 'Symbol is required';
|
||||
} else if (!this.isLetters(symbol)) {
|
||||
} else if (!this._isLetters(symbol)) {
|
||||
symbolErrText = 'Can only include letters';
|
||||
} else if (symbol.length > maxLength) {
|
||||
symbolErrText = `Max length is ${maxLength}`;
|
||||
@@ -201,12 +201,12 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
symbolErrText,
|
||||
});
|
||||
}
|
||||
private onTokenDecimalsChanged(e: any, decimals: string) {
|
||||
private _onTokenDecimalsChanged(e: any, decimals: string) {
|
||||
let decimalsErrText = '';
|
||||
const maxLength = 2;
|
||||
if (decimals === '') {
|
||||
decimalsErrText = 'Decimals is required';
|
||||
} else if (!this.isInteger(decimals)) {
|
||||
} else if (!this._isInteger(decimals)) {
|
||||
decimalsErrText = 'Must be an integer';
|
||||
} else if (decimals.length > maxLength) {
|
||||
decimalsErrText = `Max length is ${maxLength}`;
|
||||
@@ -217,20 +217,20 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
||||
decimalsErrText,
|
||||
});
|
||||
}
|
||||
private onTokenAddressChanged(address?: string) {
|
||||
private _onTokenAddressChanged(address?: string) {
|
||||
if (!_.isUndefined(address)) {
|
||||
this.setState({
|
||||
address,
|
||||
});
|
||||
}
|
||||
}
|
||||
private isValidName(input: string) {
|
||||
private _isValidName(input: string) {
|
||||
return /^[a-z0-9 ]+$/i.test(input);
|
||||
}
|
||||
private isInteger(input: string) {
|
||||
private _isInteger(input: string) {
|
||||
return /^[0-9]+$/i.test(input);
|
||||
}
|
||||
private isLetters(input: string) {
|
||||
private _isLetters(input: string) {
|
||||
return /^[a-zA-Z]+$/i.test(input);
|
||||
}
|
||||
}
|
||||
|
@@ -54,12 +54,12 @@ export class AddressInput extends React.Component<AddressInputProps, AddressInpu
|
||||
floatingLabelText={label}
|
||||
errorText={this.state.errMsg}
|
||||
value={this.state.address}
|
||||
onChange={this.onOrderTakerAddressUpdated.bind(this)}
|
||||
onChange={this._onOrderTakerAddressUpdated.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onOrderTakerAddressUpdated(e: any) {
|
||||
private _onOrderTakerAddressUpdated(e: any) {
|
||||
const address = e.target.value.toLowerCase();
|
||||
const isValidAddress = addressUtils.isAddress(address) || address === '';
|
||||
const errMsg = isValidAddress ? '' : 'Invalid ethereum address';
|
||||
|
@@ -46,8 +46,8 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
||||
<div>
|
||||
<Toggle
|
||||
disabled={this.state.isSpinnerVisible}
|
||||
toggled={this.isAllowanceSet()}
|
||||
onToggle={this.onToggleAllowanceAsync.bind(this, this.props.token)}
|
||||
toggled={this._isAllowanceSet()}
|
||||
onToggle={this._onToggleAllowanceAsync.bind(this, this.props.token)}
|
||||
/>
|
||||
</div>
|
||||
{this.state.isSpinnerVisible &&
|
||||
@@ -58,7 +58,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private async onToggleAllowanceAsync() {
|
||||
private async _onToggleAllowanceAsync() {
|
||||
if (this.props.userAddress === '') {
|
||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
return false;
|
||||
@@ -69,7 +69,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
||||
});
|
||||
|
||||
let newAllowanceAmountInBaseUnits = new BigNumber(0);
|
||||
if (!this.isAllowanceSet()) {
|
||||
if (!this._isAllowanceSet()) {
|
||||
newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
|
||||
}
|
||||
try {
|
||||
@@ -84,11 +84,11 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
||||
}
|
||||
utils.consoleLog(`Unexpected error encountered: ${err}`);
|
||||
utils.consoleLog(err.stack);
|
||||
await errorReporter.reportAsync(err);
|
||||
this.props.onErrorOccurred(BalanceErrs.allowanceSettingFailed);
|
||||
await errorReporter.reportAsync(err);
|
||||
}
|
||||
}
|
||||
private isAllowanceSet() {
|
||||
private _isAllowanceSet() {
|
||||
return !this.props.tokenState.allowance.eq(0);
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ export class BalanceBoundedInput extends
|
||||
super(props);
|
||||
const amountString = this.props.amount ? this.props.amount.toString() : '';
|
||||
this.state = {
|
||||
errMsg: this.validate(amountString, props.balance),
|
||||
errMsg: this._validate(amountString, props.balance),
|
||||
amountString,
|
||||
};
|
||||
}
|
||||
@@ -57,14 +57,14 @@ export class BalanceBoundedInput extends
|
||||
if (shouldResetState) {
|
||||
const amountString = nextProps.amount.toString();
|
||||
this.setState({
|
||||
errMsg: this.validate(amountString, nextProps.balance),
|
||||
errMsg: this._validate(amountString, nextProps.balance),
|
||||
amountString,
|
||||
});
|
||||
}
|
||||
} else if (isCurrentAmountNumeric) {
|
||||
const amountString = '';
|
||||
this.setState({
|
||||
errMsg: this.validate(amountString, nextProps.balance),
|
||||
errMsg: this._validate(amountString, nextProps.balance),
|
||||
amountString,
|
||||
});
|
||||
}
|
||||
@@ -87,13 +87,13 @@ export class BalanceBoundedInput extends
|
||||
errorText={errorText}
|
||||
value={this.state.amountString}
|
||||
hintText={<span style={{textTransform: 'capitalize'}}>amount</span>}
|
||||
onChange={this.onValueChange.bind(this)}
|
||||
onChange={this._onValueChange.bind(this)}
|
||||
underlineStyle={{width: 'calc(100% + 50px)'}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
private onValueChange(e: any, amountString: string) {
|
||||
const errMsg = this.validate(amountString, this.props.balance);
|
||||
private _onValueChange(e: any, amountString: string) {
|
||||
const errMsg = this._validate(amountString, this.props.balance);
|
||||
this.setState({
|
||||
amountString,
|
||||
errMsg,
|
||||
@@ -106,7 +106,7 @@ export class BalanceBoundedInput extends
|
||||
}
|
||||
});
|
||||
}
|
||||
private validate(amountString: string, balance: BigNumber): InputErrMsg {
|
||||
private _validate(amountString: string, balance: BigNumber): InputErrMsg {
|
||||
if (!utils.isNumeric(amountString)) {
|
||||
return amountString !== '' ? 'Must be a number' : '';
|
||||
}
|
||||
@@ -118,14 +118,14 @@ export class BalanceBoundedInput extends
|
||||
return (
|
||||
<span>
|
||||
Insufficient balance.{' '}
|
||||
{this.renderIncreaseBalanceLink()}
|
||||
{this._renderIncreaseBalanceLink()}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
|
||||
return errMsg;
|
||||
}
|
||||
private renderIncreaseBalanceLink() {
|
||||
private _renderIncreaseBalanceLink() {
|
||||
if (this.props.shouldHideVisitBalancesLink) {
|
||||
return null;
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou
|
||||
label={this.props.label}
|
||||
balance={this.props.balance}
|
||||
amount={amount}
|
||||
onChange={this.onChange.bind(this)}
|
||||
onChange={this._onChange.bind(this)}
|
||||
shouldCheckBalance={this.props.shouldCheckBalance}
|
||||
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
|
||||
onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
|
||||
@@ -42,7 +42,7 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onChange(isValid: boolean, amount?: BigNumber) {
|
||||
private _onChange(isValid: boolean, amount?: BigNumber) {
|
||||
const baseUnitAmountIfExists = _.isUndefined(amount) ?
|
||||
undefined :
|
||||
ZeroEx.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH);
|
||||
|
@@ -17,11 +17,11 @@ interface ExpirationInputState {
|
||||
}
|
||||
|
||||
export class ExpirationInput extends React.Component<ExpirationInputProps, ExpirationInputState> {
|
||||
private earliestPickableMoment: moment.Moment;
|
||||
private _earliestPickableMoment: moment.Moment;
|
||||
constructor(props: ExpirationInputProps) {
|
||||
super(props);
|
||||
// Set the earliest pickable date to today at 00:00, so users can only pick the current or later dates
|
||||
this.earliestPickableMoment = moment().startOf('day');
|
||||
this._earliestPickableMoment = moment().startOf('day');
|
||||
const expirationMoment = utils.convertToMomentFromUnixTimestamp(props.orderExpiryTimestamp);
|
||||
const initialOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec();
|
||||
const didUserSetExpiry = !initialOrderExpiryTimestamp.eq(props.orderExpiryTimestamp);
|
||||
@@ -42,8 +42,8 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
||||
mode="landscape"
|
||||
autoOk={true}
|
||||
value={date}
|
||||
onChange={this.onDateChanged.bind(this)}
|
||||
shouldDisableDate={this.shouldDisableDate.bind(this)}
|
||||
onChange={this._onDateChanged.bind(this)}
|
||||
shouldDisableDate={this._shouldDisableDate.bind(this)}
|
||||
/>
|
||||
<div
|
||||
className="absolute"
|
||||
@@ -58,7 +58,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
||||
hintText="Time"
|
||||
autoOk={true}
|
||||
value={time}
|
||||
onChange={this.onTimeChanged.bind(this)}
|
||||
onChange={this._onTimeChanged.bind(this)}
|
||||
/>
|
||||
<div
|
||||
className="absolute"
|
||||
@@ -68,7 +68,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
onClick={this.clearDates.bind(this)}
|
||||
onClick={this._clearDates.bind(this)}
|
||||
className="col col-1 pt2"
|
||||
style={{textAlign: 'right'}}
|
||||
>
|
||||
@@ -77,10 +77,10 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private shouldDisableDate(date: Date): boolean {
|
||||
return moment(date).startOf('day').isBefore(this.earliestPickableMoment);
|
||||
private _shouldDisableDate(date: Date): boolean {
|
||||
return moment(date).startOf('day').isBefore(this._earliestPickableMoment);
|
||||
}
|
||||
private clearDates() {
|
||||
private _clearDates() {
|
||||
this.setState({
|
||||
dateMoment: undefined,
|
||||
timeMoment: undefined,
|
||||
@@ -88,7 +88,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
||||
const defaultDateTime = utils.initialOrderExpiryUnixTimestampSec();
|
||||
this.props.updateOrderExpiry(defaultDateTime);
|
||||
}
|
||||
private onDateChanged(e: any, date: Date) {
|
||||
private _onDateChanged(e: any, date: Date) {
|
||||
const dateMoment = moment(date);
|
||||
this.setState({
|
||||
dateMoment,
|
||||
@@ -96,7 +96,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
||||
const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, this.state.timeMoment);
|
||||
this.props.updateOrderExpiry(timestamp);
|
||||
}
|
||||
private onTimeChanged(e: any, time: Date) {
|
||||
private _onTimeChanged(e: any, time: Date) {
|
||||
const timeMoment = moment(time);
|
||||
this.setState({
|
||||
timeMoment,
|
||||
|
@@ -27,7 +27,7 @@ interface HashInputState {}
|
||||
|
||||
export class HashInput extends React.Component<HashInputProps, HashInputState> {
|
||||
public render() {
|
||||
const msgHashHex = this.props.blockchainIsLoaded ? this.generateMessageHashHex() : '';
|
||||
const msgHashHex = this.props.blockchainIsLoaded ? this._generateMessageHashHex() : '';
|
||||
return (
|
||||
<div>
|
||||
<FakeTextField label={this.props.label}>
|
||||
@@ -43,7 +43,7 @@ export class HashInput extends React.Component<HashInputProps, HashInputState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private generateMessageHashHex() {
|
||||
private _generateMessageHashHex() {
|
||||
const exchangeContractAddress = this.props.blockchain.getExchangeContractAddressIfExists();
|
||||
const hashData = this.props.hashData;
|
||||
const order: Order = {
|
||||
|
@@ -38,14 +38,14 @@ export class IdenticonAddressInput extends React.Component<IdenticonAddressInput
|
||||
hintText="e.g 0x75bE4F78AA3699B3A348c84bDB2a96c3Db..."
|
||||
shouldHideLabel={true}
|
||||
initialAddress={this.props.initialAddress}
|
||||
updateAddress={this.updateAddress.bind(this)}
|
||||
updateAddress={this._updateAddress.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private updateAddress(address?: string): void {
|
||||
private _updateAddress(address?: string): void {
|
||||
this.setState({
|
||||
address,
|
||||
});
|
||||
|
@@ -33,8 +33,8 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
|
||||
label={this.props.label}
|
||||
amount={amount}
|
||||
balance={ZeroEx.toUnitAmount(this.props.tokenState.balance, this.props.token.decimals)}
|
||||
onChange={this.onChange.bind(this)}
|
||||
validate={this.validate.bind(this)}
|
||||
onChange={this._onChange.bind(this)}
|
||||
validate={this._validate.bind(this)}
|
||||
shouldCheckBalance={this.props.shouldCheckBalance}
|
||||
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
|
||||
onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
|
||||
@@ -45,14 +45,14 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onChange(isValid: boolean, amount?: BigNumber) {
|
||||
private _onChange(isValid: boolean, amount?: BigNumber) {
|
||||
let baseUnitAmount;
|
||||
if (!_.isUndefined(amount)) {
|
||||
baseUnitAmount = ZeroEx.toBaseUnitAmount(amount, this.props.token.decimals);
|
||||
}
|
||||
this.props.onChange(isValid, baseUnitAmount);
|
||||
}
|
||||
private validate(amount: BigNumber): InputErrMsg {
|
||||
private _validate(amount: BigNumber): InputErrMsg {
|
||||
if (this.props.shouldCheckAllowance && amount.gt(this.props.tokenState.allowance)) {
|
||||
return (
|
||||
<span>
|
||||
|
@@ -52,9 +52,9 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState
|
||||
<Paper
|
||||
zDepth={1}
|
||||
style={{cursor: 'pointer'}}
|
||||
onMouseEnter={this.onToggleHover.bind(this, true)}
|
||||
onMouseLeave={this.onToggleHover.bind(this, false)}
|
||||
onClick={this.onAssetClicked.bind(this)}
|
||||
onMouseEnter={this._onToggleHover.bind(this, true)}
|
||||
onMouseLeave={this._onToggleHover.bind(this, false)}
|
||||
onClick={this._onAssetClicked.bind(this)}
|
||||
>
|
||||
<div
|
||||
className="mx-auto pt2"
|
||||
@@ -73,13 +73,13 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState
|
||||
dispatcher={this.props.dispatcher}
|
||||
isOpen={this.state.isPickerOpen}
|
||||
currentTokenAddress={this.props.assetToken.address}
|
||||
onTokenChosen={this.onTokenChosen.bind(this)}
|
||||
onTokenChosen={this._onTokenChosen.bind(this)}
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onTokenChosen(tokenAddress: string) {
|
||||
private _onTokenChosen(tokenAddress: string) {
|
||||
const assetToken: AssetToken = {
|
||||
address: tokenAddress,
|
||||
amount: this.props.assetToken.amount,
|
||||
@@ -89,12 +89,12 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState
|
||||
isPickerOpen: false,
|
||||
});
|
||||
}
|
||||
private onToggleHover(isHoveringIcon: boolean) {
|
||||
private _onToggleHover(isHoveringIcon: boolean) {
|
||||
this.setState({
|
||||
isHoveringIcon,
|
||||
});
|
||||
}
|
||||
private onAssetClicked() {
|
||||
private _onAssetClicked() {
|
||||
if (this.props.blockchainErr !== BlockchainErrs.NoError) {
|
||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
return;
|
||||
|
@@ -36,7 +36,7 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
|
||||
shareLink: '',
|
||||
};
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.setShareLinkAsync();
|
||||
this._setShareLinkAsync();
|
||||
}
|
||||
public render() {
|
||||
const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists,
|
||||
@@ -88,21 +88,21 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
|
||||
<div>
|
||||
<i
|
||||
style={{cursor: 'pointer', fontSize: 29}}
|
||||
onClick={this.shareViaFacebook.bind(this)}
|
||||
onClick={this._shareViaFacebook.bind(this)}
|
||||
className="zmdi zmdi-facebook-box"
|
||||
/>
|
||||
</div>
|
||||
<div className="pl1" style={{position: 'relative', width: 28}}>
|
||||
<i
|
||||
style={{cursor: 'pointer', fontSize: 32, position: 'absolute', top: -2, left: 8}}
|
||||
onClick={this.shareViaEmailAsync.bind(this)}
|
||||
onClick={this._shareViaEmailAsync.bind(this)}
|
||||
className="zmdi zmdi-email"
|
||||
/>
|
||||
</div>
|
||||
<div className="pl1">
|
||||
<i
|
||||
style={{cursor: 'pointer', fontSize: 29}}
|
||||
onClick={this.shareViaTwitterAsync.bind(this)}
|
||||
onClick={this._shareViaTwitterAsync.bind(this)}
|
||||
className="zmdi zmdi-twitter-box"
|
||||
/>
|
||||
</div>
|
||||
@@ -111,32 +111,32 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private async shareViaTwitterAsync() {
|
||||
private async _shareViaTwitterAsync() {
|
||||
const tweetText = encodeURIComponent(`Fill my order using the 0x protocol: ${this.state.shareLink}`);
|
||||
window.open(`https://twitter.com/intent/tweet?text=${tweetText}`, 'Share your order', 'width=500,height=400');
|
||||
}
|
||||
private async shareViaFacebook() {
|
||||
private async _shareViaFacebook() {
|
||||
(window as any).FB.ui({
|
||||
display: 'popup',
|
||||
href: this.state.shareLink,
|
||||
method: 'share',
|
||||
}, _.noop);
|
||||
}
|
||||
private async shareViaEmailAsync() {
|
||||
private async _shareViaEmailAsync() {
|
||||
const encodedSubject = encodeURIComponent('Let\'s trade using the 0x protocol');
|
||||
const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol.
|
||||
You can see and fill it here: ${this.state.shareLink}`);
|
||||
const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`;
|
||||
window.open(mailToLink, '_blank');
|
||||
}
|
||||
private async setShareLinkAsync() {
|
||||
const shareLink = await this.generateShareLinkAsync();
|
||||
private async _setShareLinkAsync() {
|
||||
const shareLink = await this._generateShareLinkAsync();
|
||||
this.setState({
|
||||
shareLink,
|
||||
});
|
||||
}
|
||||
private async generateShareLinkAsync(): Promise<string> {
|
||||
const longUrl = encodeURIComponent(this.getOrderUrl());
|
||||
private async _generateShareLinkAsync(): Promise<string> {
|
||||
const longUrl = encodeURIComponent(this._getOrderUrl());
|
||||
const bitlyRequestUrl =
|
||||
`${constants.URL_BITLY_API}/v3/shorten?access_token=${configs.BITLY_ACCESS_TOKEN}&longUrl=${longUrl}`;
|
||||
const response = await fetch(bitlyRequestUrl);
|
||||
@@ -150,7 +150,7 @@ You can see and fill it here: ${this.state.shareLink}`);
|
||||
}
|
||||
return (bodyObj).data.url;
|
||||
}
|
||||
private getOrderUrl() {
|
||||
private _getOrderUrl() {
|
||||
const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists,
|
||||
this.props.sideToAssetToken, this.props.orderExpiryTimestamp, this.props.orderTakerAddress,
|
||||
this.props.orderMakerAddress, this.props.orderMakerFee, this.props.orderTakerFee,
|
||||
|
@@ -70,9 +70,9 @@ interface PortalAllState {
|
||||
}
|
||||
|
||||
export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
private blockchain: Blockchain;
|
||||
private sharedOrderIfExists: Order;
|
||||
private throttledScreenWidthUpdate: () => void;
|
||||
private _blockchain: Blockchain;
|
||||
private _sharedOrderIfExists: Order;
|
||||
private _throttledScreenWidthUpdate: () => void;
|
||||
public static hasAlreadyDismissedWethNotice() {
|
||||
const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE);
|
||||
const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) &&
|
||||
@@ -81,8 +81,8 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
}
|
||||
constructor(props: PortalAllProps) {
|
||||
super(props);
|
||||
this.sharedOrderIfExists = this.getSharedOrderIfExists();
|
||||
this.throttledScreenWidthUpdate = _.throttle(this.updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||
this._sharedOrderIfExists = this._getSharedOrderIfExists();
|
||||
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||
|
||||
const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`);
|
||||
const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice();
|
||||
@@ -100,15 +100,15 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
};
|
||||
}
|
||||
public componentDidMount() {
|
||||
window.addEventListener('resize', this.throttledScreenWidthUpdate);
|
||||
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
public componentWillMount() {
|
||||
this.blockchain = new Blockchain(this.props.dispatcher);
|
||||
this._blockchain = new Blockchain(this.props.dispatcher);
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
this.blockchain.destroy();
|
||||
window.removeEventListener('resize', this.throttledScreenWidthUpdate);
|
||||
this._blockchain.destroy();
|
||||
window.removeEventListener('resize', this._throttledScreenWidthUpdate);
|
||||
// We re-set the entire redux state when the portal is unmounted so that when it is re-rendered
|
||||
// the initialization process always occurs from the same base state. This helps avoid
|
||||
// initialization inconsistencies (i.e While the portal was unrendered, the user might have
|
||||
@@ -118,19 +118,19 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
public componentWillReceiveProps(nextProps: PortalAllProps) {
|
||||
if (nextProps.networkId !== this.state.prevNetworkId) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
|
||||
this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
|
||||
this.setState({
|
||||
prevNetworkId: nextProps.networkId,
|
||||
});
|
||||
}
|
||||
if (nextProps.userAddress !== this.state.prevUserAddress) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress);
|
||||
this._blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress);
|
||||
if (!_.isEmpty(nextProps.userAddress) &&
|
||||
nextProps.blockchainIsLoaded) {
|
||||
const tokens = _.values(nextProps.tokenByAddress);
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.updateBalanceAndAllowanceWithLoadingScreenAsync(tokens);
|
||||
this._updateBalanceAndAllowanceWithLoadingScreenAsync(tokens);
|
||||
}
|
||||
this.setState({
|
||||
prevUserAddress: nextProps.userAddress,
|
||||
@@ -138,7 +138,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
}
|
||||
if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
this.blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
|
||||
this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
|
||||
}
|
||||
if (nextProps.location.pathname !== this.state.prevPathname) {
|
||||
const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`);
|
||||
@@ -206,23 +206,23 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
<Switch>
|
||||
<Route
|
||||
path={`${WebsitePaths.Portal}/weth`}
|
||||
render={this.renderEthWrapper.bind(this)}
|
||||
render={this._renderEthWrapper.bind(this)}
|
||||
/>
|
||||
<Route
|
||||
path={`${WebsitePaths.Portal}/fill`}
|
||||
render={this.renderFillOrder.bind(this)}
|
||||
render={this._renderFillOrder.bind(this)}
|
||||
/>
|
||||
<Route
|
||||
path={`${WebsitePaths.Portal}/balances`}
|
||||
render={this.renderTokenBalances.bind(this)}
|
||||
render={this._renderTokenBalances.bind(this)}
|
||||
/>
|
||||
<Route
|
||||
path={`${WebsitePaths.Portal}/trades`}
|
||||
component={this.renderTradeHistory.bind(this)}
|
||||
component={this._renderTradeHistory.bind(this)}
|
||||
/>
|
||||
<Route
|
||||
path={`${WebsitePaths.Home}`}
|
||||
render={this.renderGenerateOrderForm.bind(this)}
|
||||
render={this._renderGenerateOrderForm.bind(this)}
|
||||
/>
|
||||
</Switch> :
|
||||
<Loading />
|
||||
@@ -233,7 +233,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
}
|
||||
</Paper>
|
||||
<BlockchainErrDialog
|
||||
blockchain={this.blockchain}
|
||||
blockchain={this._blockchain}
|
||||
blockchainErr={this.props.blockchainErr}
|
||||
isOpen={this.props.shouldBlockchainErrDialogBeOpen}
|
||||
userAddress={this.props.userAddress}
|
||||
@@ -242,11 +242,11 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
/>
|
||||
<WrappedEthSectionNoticeDialog
|
||||
isOpen={this.state.isWethNoticeDialogOpen}
|
||||
onToggleDialog={this.onWethNoticeAccepted.bind(this)}
|
||||
onToggleDialog={this._onWethNoticeAccepted.bind(this)}
|
||||
/>
|
||||
<PortalDisclaimerDialog
|
||||
isOpen={this.state.isDisclaimerDialogOpen}
|
||||
onToggleDialog={this.onPortalDisclaimerAccepted.bind(this)}
|
||||
onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
|
||||
/>
|
||||
<FlashMessage
|
||||
dispatcher={this.props.dispatcher}
|
||||
@@ -257,11 +257,11 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderEthWrapper() {
|
||||
private _renderEthWrapper() {
|
||||
return (
|
||||
<EthWrappers
|
||||
networkId={this.props.networkId}
|
||||
blockchain={this.blockchain}
|
||||
blockchain={this._blockchain}
|
||||
dispatcher={this.props.dispatcher}
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
tokenStateByAddress={this.props.tokenStateByAddress}
|
||||
@@ -270,7 +270,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
/>
|
||||
);
|
||||
}
|
||||
private renderTradeHistory() {
|
||||
private _renderTradeHistory() {
|
||||
return (
|
||||
<TradeHistory
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
@@ -279,10 +279,10 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
/>
|
||||
);
|
||||
}
|
||||
private renderTokenBalances() {
|
||||
private _renderTokenBalances() {
|
||||
return (
|
||||
<TokenBalances
|
||||
blockchain={this.blockchain}
|
||||
blockchain={this._blockchain}
|
||||
blockchainErr={this.props.blockchainErr}
|
||||
blockchainIsLoaded={this.props.blockchainIsLoaded}
|
||||
dispatcher={this.props.dispatcher}
|
||||
@@ -295,16 +295,16 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
/>
|
||||
);
|
||||
}
|
||||
private renderFillOrder(match: any, location: Location, history: History) {
|
||||
private _renderFillOrder(match: any, location: Location, history: History) {
|
||||
const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) ?
|
||||
this.props.userSuppliedOrderCache :
|
||||
this.sharedOrderIfExists;
|
||||
this._sharedOrderIfExists;
|
||||
return (
|
||||
<FillOrder
|
||||
blockchain={this.blockchain}
|
||||
blockchain={this._blockchain}
|
||||
blockchainErr={this.props.blockchainErr}
|
||||
initialOrder={initialFillOrder}
|
||||
isOrderInUrl={!_.isUndefined(this.sharedOrderIfExists)}
|
||||
isOrderInUrl={!_.isUndefined(this._sharedOrderIfExists)}
|
||||
orderFillAmount={this.props.orderFillAmount}
|
||||
networkId={this.props.networkId}
|
||||
userAddress={this.props.userAddress}
|
||||
@@ -314,28 +314,28 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
/>
|
||||
);
|
||||
}
|
||||
private renderGenerateOrderForm(match: any, location: Location, history: History) {
|
||||
private _renderGenerateOrderForm(match: any, location: Location, history: History) {
|
||||
return (
|
||||
<GenerateOrderForm
|
||||
blockchain={this.blockchain}
|
||||
blockchain={this._blockchain}
|
||||
hashData={this.props.hashData}
|
||||
dispatcher={this.props.dispatcher}
|
||||
/>
|
||||
);
|
||||
}
|
||||
private onPortalDisclaimerAccepted() {
|
||||
private _onPortalDisclaimerAccepted() {
|
||||
localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
|
||||
this.setState({
|
||||
isDisclaimerDialogOpen: false,
|
||||
});
|
||||
}
|
||||
private onWethNoticeAccepted() {
|
||||
private _onWethNoticeAccepted() {
|
||||
localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set');
|
||||
this.setState({
|
||||
isWethNoticeDialogOpen: false,
|
||||
});
|
||||
}
|
||||
private getSharedOrderIfExists(): Order {
|
||||
private _getSharedOrderIfExists(): Order {
|
||||
const queryString = window.location.search;
|
||||
if (queryString.length === 0) {
|
||||
return;
|
||||
@@ -362,13 +362,13 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||
}
|
||||
return order;
|
||||
}
|
||||
private updateScreenWidth() {
|
||||
private _updateScreenWidth() {
|
||||
const newScreenWidth = utils.getScreenWidth();
|
||||
this.props.dispatcher.updateScreenWidth(newScreenWidth);
|
||||
}
|
||||
private async updateBalanceAndAllowanceWithLoadingScreenAsync(tokens: Token[]) {
|
||||
private async _updateBalanceAndAllowanceWithLoadingScreenAsync(tokens: Token[]) {
|
||||
this.props.dispatcher.updateBlockchainIsLoaded(false);
|
||||
await this.blockchain.updateTokenBalancesAndAllowancesAsync(tokens);
|
||||
await this._blockchain.updateTokenBalancesAndAllowancesAsync(tokens);
|
||||
this.props.dispatcher.updateBlockchainIsLoaded(true);
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
||||
to={`${WebsitePaths.Portal}`}
|
||||
onClick={this.props.onClick.bind(this)}
|
||||
>
|
||||
{this.renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')}
|
||||
{this._renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
style={this.props.menuItemStyle}
|
||||
@@ -31,7 +31,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
||||
to={`${WebsitePaths.Portal}/fill`}
|
||||
onClick={this.props.onClick.bind(this)}
|
||||
>
|
||||
{this.renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')}
|
||||
{this._renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
style={this.props.menuItemStyle}
|
||||
@@ -39,7 +39,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
||||
to={`${WebsitePaths.Portal}/balances`}
|
||||
onClick={this.props.onClick.bind(this)}
|
||||
>
|
||||
{this.renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')}
|
||||
{this._renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
style={this.props.menuItemStyle}
|
||||
@@ -47,7 +47,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
||||
to={`${WebsitePaths.Portal}/trades`}
|
||||
onClick={this.props.onClick.bind(this)}
|
||||
>
|
||||
{this.renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')}
|
||||
{this._renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
style={this.props.menuItemStyle}
|
||||
@@ -55,12 +55,12 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
||||
to={`${WebsitePaths.Portal}/weth`}
|
||||
onClick={this.props.onClick.bind(this)}
|
||||
>
|
||||
{this.renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
|
||||
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
|
||||
</MenuItem>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderMenuItemWithIcon(title: string, iconName: string) {
|
||||
private _renderMenuItemWithIcon(title: string, iconName: string) {
|
||||
return (
|
||||
<div className="flex" style={{fontWeight: 100}}>
|
||||
<div className="pr1 pl2">
|
||||
|
@@ -39,28 +39,28 @@ export class SendButton extends React.Component<SendButtonProps, SendButtonState
|
||||
labelStyle={labelStyle}
|
||||
disabled={this.state.isSending}
|
||||
label={this.state.isSending ? 'Sending...' : 'Send'}
|
||||
onClick={this.toggleSendDialog.bind(this)}
|
||||
onClick={this._toggleSendDialog.bind(this)}
|
||||
/>
|
||||
<SendDialog
|
||||
isOpen={this.state.isSendDialogVisible}
|
||||
onComplete={this.onSendAmountSelectedAsync.bind(this)}
|
||||
onCancelled={this.toggleSendDialog.bind(this)}
|
||||
onComplete={this._onSendAmountSelectedAsync.bind(this)}
|
||||
onCancelled={this._toggleSendDialog.bind(this)}
|
||||
token={this.props.token}
|
||||
tokenState={this.props.tokenState}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private toggleSendDialog() {
|
||||
private _toggleSendDialog() {
|
||||
this.setState({
|
||||
isSendDialogVisible: !this.state.isSendDialogVisible,
|
||||
});
|
||||
}
|
||||
private async onSendAmountSelectedAsync(recipient: string, value: BigNumber) {
|
||||
private async _onSendAmountSelectedAsync(recipient: string, value: BigNumber) {
|
||||
this.setState({
|
||||
isSending: true,
|
||||
});
|
||||
this.toggleSendDialog();
|
||||
this._toggleSendDialog();
|
||||
const token = this.props.token;
|
||||
const tokenState = this.props.tokenState;
|
||||
let balance = tokenState.balance;
|
||||
|
@@ -133,7 +133,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
key="errorOkBtn"
|
||||
label="Ok"
|
||||
primary={true}
|
||||
onTouchTap={this.onErrorDialogToggle.bind(this, false)}
|
||||
onTouchTap={this._onErrorDialogToggle.bind(this, false)}
|
||||
/>,
|
||||
];
|
||||
const dharmaDialogActions = [
|
||||
@@ -141,7 +141,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
key="dharmaCloseBtn"
|
||||
label="Close"
|
||||
primary={true}
|
||||
onTouchTap={this.onDharmaDialogToggle.bind(this, false)}
|
||||
onTouchTap={this._onDharmaDialogToggle.bind(this, false)}
|
||||
/>,
|
||||
];
|
||||
const isTestNetwork = this.props.networkId === constants.NETWORK_ID_TESTNET;
|
||||
@@ -239,7 +239,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
labelReady="Request"
|
||||
labelLoading="Sending..."
|
||||
labelComplete="Sent!"
|
||||
onClickAsyncFn={this.faucetRequestAsync.bind(this, true)}
|
||||
onClickAsyncFn={this._faucetRequestAsync.bind(this, true)}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
}
|
||||
@@ -249,7 +249,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
<RaisedButton
|
||||
label="Request"
|
||||
style={{width: '100%'}}
|
||||
onTouchTap={this.onDharmaDialogToggle.bind(this)}
|
||||
onTouchTap={this._onDharmaDialogToggle.bind(this)}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
}
|
||||
@@ -266,7 +266,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
<FloatingActionButton
|
||||
mini={true}
|
||||
zDepth={0}
|
||||
onClick={this.onAddTokenClicked.bind(this)}
|
||||
onClick={this._onAddTokenClicked.bind(this)}
|
||||
>
|
||||
<ContentAdd />
|
||||
</FloatingActionButton>
|
||||
@@ -275,7 +275,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
<FloatingActionButton
|
||||
mini={true}
|
||||
zDepth={0}
|
||||
onClick={this.onRemoveTokenClicked.bind(this)}
|
||||
onClick={this._onRemoveTokenClicked.bind(this)}
|
||||
>
|
||||
<ContentRemove />
|
||||
</FloatingActionButton>
|
||||
@@ -319,7 +319,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody displayRowCheckbox={false}>
|
||||
{this.renderTokenTableRows()}
|
||||
{this._renderTokenTableRows()}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Dialog
|
||||
@@ -327,9 +327,9 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
titleStyle={{fontWeight: 100}}
|
||||
actions={errorDialogActions}
|
||||
open={!_.isUndefined(this.state.errorType)}
|
||||
onRequestClose={this.onErrorDialogToggle.bind(this, false)}
|
||||
onRequestClose={this._onErrorDialogToggle.bind(this, false)}
|
||||
>
|
||||
{this.renderErrorDialogBody()}
|
||||
{this._renderErrorDialogBody()}
|
||||
</Dialog>
|
||||
<Dialog
|
||||
title="Request Dharma Loan"
|
||||
@@ -340,7 +340,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
actions={dharmaDialogActions}
|
||||
open={this.state.isDharmaDialogVisible}
|
||||
>
|
||||
{this.renderDharmaLoanFrame()}
|
||||
{this._renderDharmaLoanFrame()}
|
||||
</Dialog>
|
||||
<AssetPicker
|
||||
userAddress={this.props.userAddress}
|
||||
@@ -349,14 +349,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
dispatcher={this.props.dispatcher}
|
||||
isOpen={this.state.isTokenPickerOpen}
|
||||
currentTokenAddress={''}
|
||||
onTokenChosen={this.onAssetTokenPicked.bind(this)}
|
||||
onTokenChosen={this._onAssetTokenPicked.bind(this)}
|
||||
tokenByAddress={this.props.tokenByAddress}
|
||||
tokenVisibility={this.state.isAddingToken ? TokenVisibility.UNTRACKED : TokenVisibility.TRACKED}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderTokenTableRows() {
|
||||
private _renderTokenTableRows() {
|
||||
if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== BlockchainErrs.NoError) {
|
||||
return '';
|
||||
}
|
||||
@@ -372,11 +372,11 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
);
|
||||
const tableRows = _.map(
|
||||
trackedTokensStartingWithEtherToken,
|
||||
this.renderTokenRow.bind(this, tokenColSpan, actionPaddingX),
|
||||
this._renderTokenRow.bind(this, tokenColSpan, actionPaddingX),
|
||||
);
|
||||
return tableRows;
|
||||
}
|
||||
private renderTokenRow(tokenColSpan: number, actionPaddingX: number, token: Token) {
|
||||
private _renderTokenRow(tokenColSpan: number, actionPaddingX: number, token: Token) {
|
||||
const tokenState = this.props.tokenStateByAddress[token.address];
|
||||
const tokenLink = utils.getEtherScanLinkIfExists(token.address, this.props.networkId,
|
||||
EtherscanLinkSuffixes.Address);
|
||||
@@ -388,14 +388,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
colSpan={tokenColSpan}
|
||||
>
|
||||
{_.isUndefined(tokenLink) ?
|
||||
this.renderTokenName(token) :
|
||||
this._renderTokenName(token) :
|
||||
<a href={tokenLink} target="_blank" style={{textDecoration: 'none'}}>
|
||||
{this.renderTokenName(token)}
|
||||
{this._renderTokenName(token)}
|
||||
</a>
|
||||
}
|
||||
</TableRowColumn>
|
||||
<TableRowColumn style={{paddingRight: 3, paddingLeft: 3}}>
|
||||
{this.renderAmount(tokenState.balance, token.decimals)} {token.symbol}
|
||||
{this._renderAmount(tokenState.balance, token.decimals)} {token.symbol}
|
||||
{this.state.isZRXSpinnerVisible && token.symbol === ZRX_TOKEN_SYMBOL &&
|
||||
<span className="pl1">
|
||||
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
||||
@@ -408,7 +408,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
dispatcher={this.props.dispatcher}
|
||||
token={token}
|
||||
tokenState={tokenState}
|
||||
onErrorOccurred={this.onErrorOccurred.bind(this)}
|
||||
onErrorOccurred={this._onErrorOccurred.bind(this)}
|
||||
userAddress={this.props.userAddress}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
@@ -420,7 +420,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
labelReady="Mint"
|
||||
labelLoading={<span style={{fontSize: 12}}>Minting...</span>}
|
||||
labelComplete="Minted!"
|
||||
onClickAsyncFn={this.onMintTestTokensAsync.bind(this, token)}
|
||||
onClickAsyncFn={this._onMintTestTokensAsync.bind(this, token)}
|
||||
/>
|
||||
}
|
||||
{token.symbol === ZRX_TOKEN_SYMBOL && this.props.networkId === constants.NETWORK_ID_TESTNET &&
|
||||
@@ -428,7 +428,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
labelReady="Request"
|
||||
labelLoading="Sending..."
|
||||
labelComplete="Sent!"
|
||||
onClickAsyncFn={this.faucetRequestAsync.bind(this, false)}
|
||||
onClickAsyncFn={this._faucetRequestAsync.bind(this, false)}
|
||||
/>
|
||||
}
|
||||
</TableRowColumn>
|
||||
@@ -441,14 +441,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
dispatcher={this.props.dispatcher}
|
||||
token={token}
|
||||
tokenState={tokenState}
|
||||
onError={this.onSendFailed.bind(this)}
|
||||
onError={this._onSendFailed.bind(this)}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
}
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
private onAssetTokenPicked(tokenAddress: string) {
|
||||
private _onAssetTokenPicked(tokenAddress: string) {
|
||||
if (_.isEmpty(tokenAddress)) {
|
||||
this.setState({
|
||||
isTokenPickerOpen: false,
|
||||
@@ -477,16 +477,16 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
isTokenPickerOpen: false,
|
||||
});
|
||||
}
|
||||
private onSendFailed() {
|
||||
private _onSendFailed() {
|
||||
this.setState({
|
||||
errorType: BalanceErrs.sendFailed,
|
||||
});
|
||||
}
|
||||
private renderAmount(amount: BigNumber, decimals: number) {
|
||||
private _renderAmount(amount: BigNumber, decimals: number) {
|
||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||
return unitAmount.toNumber().toFixed(PRECISION);
|
||||
}
|
||||
private renderTokenName(token: Token) {
|
||||
private _renderTokenName(token: Token) {
|
||||
const tooltipId = `tooltip-${token.address}`;
|
||||
return (
|
||||
<div className="flex">
|
||||
@@ -502,7 +502,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderErrorDialogBody() {
|
||||
private _renderErrorDialogBody() {
|
||||
switch (this.state.errorType) {
|
||||
case BalanceErrs.incorrectNetworkForFaucet:
|
||||
return (
|
||||
@@ -550,7 +550,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
throw utils.spawnSwitchErr('errorType', this.state.errorType);
|
||||
}
|
||||
}
|
||||
private renderDharmaLoanFrame() {
|
||||
private _renderDharmaLoanFrame() {
|
||||
if (utils.isUserOnMobile()) {
|
||||
return (
|
||||
<h4 style={{textAlign: 'center'}}>
|
||||
@@ -568,12 +568,12 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
);
|
||||
}
|
||||
}
|
||||
private onErrorOccurred(errorType: BalanceErrs) {
|
||||
private _onErrorOccurred(errorType: BalanceErrs) {
|
||||
this.setState({
|
||||
errorType,
|
||||
});
|
||||
}
|
||||
private async onMintTestTokensAsync(token: Token): Promise<boolean> {
|
||||
private async _onMintTestTokensAsync(token: Token): Promise<boolean> {
|
||||
try {
|
||||
await this.props.blockchain.mintTestTokensAsync(token);
|
||||
const amount = ZeroEx.toUnitAmount(constants.MINT_AMOUNT, token.decimals);
|
||||
@@ -590,14 +590,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
}
|
||||
utils.consoleLog(`Unexpected error encountered: ${err}`);
|
||||
utils.consoleLog(err.stack);
|
||||
await errorReporter.reportAsync(err);
|
||||
this.setState({
|
||||
errorType: BalanceErrs.mintingFailed,
|
||||
});
|
||||
await errorReporter.reportAsync(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private async faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> {
|
||||
private async _faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> {
|
||||
if (this.props.userAddress === '') {
|
||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||
return false;
|
||||
@@ -619,13 +619,13 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
const responseBody = await response.text();
|
||||
if (response.status !== constants.SUCCESS_STATUS) {
|
||||
utils.consoleLog(`Unexpected status code: ${response.status} -> ${responseBody}`);
|
||||
await errorReporter.reportAsync(new Error(`Faucet returned non-200: ${JSON.stringify(response)}`));
|
||||
const errorType = response.status === constants.UNAVAILABLE_STATUS ?
|
||||
BalanceErrs.faucetQueueIsFull :
|
||||
BalanceErrs.faucetRequestFailed;
|
||||
this.setState({
|
||||
errorType,
|
||||
});
|
||||
await errorReporter.reportAsync(new Error(`Faucet returned non-200: ${JSON.stringify(response)}`));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -646,23 +646,23 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private onErrorDialogToggle(isOpen: boolean) {
|
||||
private _onErrorDialogToggle(isOpen: boolean) {
|
||||
this.setState({
|
||||
errorType: undefined,
|
||||
});
|
||||
}
|
||||
private onDharmaDialogToggle() {
|
||||
private _onDharmaDialogToggle() {
|
||||
this.setState({
|
||||
isDharmaDialogVisible: !this.state.isDharmaDialogVisible,
|
||||
});
|
||||
}
|
||||
private onAddTokenClicked() {
|
||||
private _onAddTokenClicked() {
|
||||
this.setState({
|
||||
isTokenPickerOpen: true,
|
||||
isAddingToken: true,
|
||||
});
|
||||
}
|
||||
private onRemoveTokenClicked() {
|
||||
private _onRemoveTokenClicked() {
|
||||
this.setState({
|
||||
isTokenPickerOpen: true,
|
||||
isAddingToken: false,
|
||||
|
@@ -127,7 +127,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
<MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="Whitepaper" />
|
||||
</a>,
|
||||
];
|
||||
const bottomBorderStyle = this.shouldDisplayBottomBar() ? styles.bottomBar : {};
|
||||
const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
|
||||
const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
|
||||
const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
|
||||
const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
|
||||
@@ -147,7 +147,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
</div>
|
||||
<div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} />
|
||||
<div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} />
|
||||
{!this.isViewingPortal() &&
|
||||
{!this._isViewingPortal() &&
|
||||
<div
|
||||
className={menuClasses}
|
||||
>
|
||||
@@ -183,37 +183,37 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
}
|
||||
{this.props.blockchainIsLoaded && !_.isEmpty(this.props.userAddress) &&
|
||||
<div className="col col-5">
|
||||
{this.renderUser()}
|
||||
{this._renderUser()}
|
||||
</div>
|
||||
}
|
||||
{!this.isViewingPortal() &&
|
||||
{!this._isViewingPortal() &&
|
||||
<div
|
||||
className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}
|
||||
>
|
||||
<div style={menuIconStyle}>
|
||||
<i
|
||||
className="zmdi zmdi-menu"
|
||||
onClick={this.onMenuButtonClick.bind(this)}
|
||||
onClick={this._onMenuButtonClick.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{this.renderDrawer()}
|
||||
{this._renderDrawer()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderDrawer() {
|
||||
private _renderDrawer() {
|
||||
return (
|
||||
<Drawer
|
||||
open={this.state.isDrawerOpen}
|
||||
docked={false}
|
||||
openSecondary={true}
|
||||
onRequestChange={this.onMenuButtonClick.bind(this)}
|
||||
onRequestChange={this._onMenuButtonClick.bind(this)}
|
||||
>
|
||||
{this.renderPortalMenu()}
|
||||
{this.renderDocsMenu()}
|
||||
{this.renderWiki()}
|
||||
{this._renderPortalMenu()}
|
||||
{this._renderDocsMenu()}
|
||||
{this._renderWiki()}
|
||||
<div className="pl1 py1 mt3" style={{backgroundColor: colors.lightGrey}}>Website</div>
|
||||
<Link to={WebsitePaths.Home} className="text-decoration-none">
|
||||
<MenuItem className="py2">Home</MenuItem>
|
||||
@@ -221,22 +221,22 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
<Link to={`${WebsitePaths.Wiki}`} className="text-decoration-none">
|
||||
<MenuItem className="py2">Wiki</MenuItem>
|
||||
</Link>
|
||||
{!this.isViewing0xjsDocs() &&
|
||||
{!this._isViewing0xjsDocs() &&
|
||||
<Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
|
||||
<MenuItem className="py2">0x.js Docs</MenuItem>
|
||||
</Link>
|
||||
}
|
||||
{!this.isViewingConnectDocs() &&
|
||||
{!this._isViewingConnectDocs() &&
|
||||
<Link to={WebsitePaths.Connect} className="text-decoration-none">
|
||||
<MenuItem className="py2">0x Connect Docs</MenuItem>
|
||||
</Link>
|
||||
}
|
||||
{!this.isViewingSmartContractsDocs() &&
|
||||
{!this._isViewingSmartContractsDocs() &&
|
||||
<Link to={WebsitePaths.SmartContracts} className="text-decoration-none">
|
||||
<MenuItem className="py2">Smart Contract Docs</MenuItem>
|
||||
</Link>
|
||||
}
|
||||
{!this.isViewingPortal() &&
|
||||
{!this._isViewingPortal() &&
|
||||
<Link to={`${WebsitePaths.Portal}`} className="text-decoration-none">
|
||||
<MenuItem className="py2">Portal DApp</MenuItem>
|
||||
</Link>
|
||||
@@ -261,7 +261,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
<Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none">
|
||||
<MenuItem
|
||||
className="py2"
|
||||
onTouchTap={this.onMenuButtonClick.bind(this)}
|
||||
onTouchTap={this._onMenuButtonClick.bind(this)}
|
||||
>
|
||||
FAQ
|
||||
</MenuItem>
|
||||
@@ -269,8 +269,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
private renderDocsMenu() {
|
||||
if (!this.isViewing0xjsDocs() && !this.isViewingSmartContractsDocs() && !this.isViewingConnectDocs()
|
||||
private _renderDocsMenu() {
|
||||
if (!this._isViewing0xjsDocs() && !this._isViewingSmartContractsDocs() && !this._isViewingConnectDocs()
|
||||
|| _.isUndefined(this.props.menu)) {
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +283,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
topLevelMenu={this.props.menu}
|
||||
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
|
||||
shouldDisplaySectionHeaders={false}
|
||||
onMenuItemClick={this.onMenuButtonClick.bind(this)}
|
||||
onMenuItemClick={this._onMenuButtonClick.bind(this)}
|
||||
selectedVersion={this.props.docsVersion}
|
||||
docPath={this.props.docsInfo.websitePath}
|
||||
versions={this.props.availableDocVersions}
|
||||
@@ -291,8 +291,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderWiki() {
|
||||
if (!this.isViewingWiki()) {
|
||||
private _renderWiki() {
|
||||
if (!this._isViewingWiki()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -303,13 +303,13 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
topLevelMenu={this.props.menuSubsectionsBySection}
|
||||
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
|
||||
shouldDisplaySectionHeaders={false}
|
||||
onMenuItemClick={this.onMenuButtonClick.bind(this)}
|
||||
onMenuItemClick={this._onMenuButtonClick.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderPortalMenu() {
|
||||
if (!this.isViewingPortal()) {
|
||||
private _renderPortalMenu() {
|
||||
if (!this._isViewingPortal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -318,12 +318,12 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
<div className="pl1 py1" style={{backgroundColor: colors.lightGrey}}>Portal DApp</div>
|
||||
<PortalMenu
|
||||
menuItemStyle={{color: 'black'}}
|
||||
onClick={this.onMenuButtonClick.bind(this)}
|
||||
onClick={this._onMenuButtonClick.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderUser() {
|
||||
private _renderUser() {
|
||||
const userAddress = this.props.userAddress;
|
||||
const identiconDiameter = 26;
|
||||
return (
|
||||
@@ -345,31 +345,31 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onMenuButtonClick() {
|
||||
private _onMenuButtonClick() {
|
||||
this.setState({
|
||||
isDrawerOpen: !this.state.isDrawerOpen,
|
||||
});
|
||||
}
|
||||
private isViewingPortal() {
|
||||
private _isViewingPortal() {
|
||||
return _.includes(this.props.location.pathname, WebsitePaths.Portal);
|
||||
}
|
||||
private isViewingFAQ() {
|
||||
private _isViewingFAQ() {
|
||||
return _.includes(this.props.location.pathname, WebsitePaths.FAQ);
|
||||
}
|
||||
private isViewing0xjsDocs() {
|
||||
private _isViewing0xjsDocs() {
|
||||
return _.includes(this.props.location.pathname, WebsitePaths.ZeroExJs);
|
||||
}
|
||||
private isViewingConnectDocs() {
|
||||
private _isViewingConnectDocs() {
|
||||
return _.includes(this.props.location.pathname, WebsitePaths.Connect);
|
||||
}
|
||||
private isViewingSmartContractsDocs() {
|
||||
private _isViewingSmartContractsDocs() {
|
||||
return _.includes(this.props.location.pathname, WebsitePaths.SmartContracts);
|
||||
}
|
||||
private isViewingWiki() {
|
||||
private _isViewingWiki() {
|
||||
return _.includes(this.props.location.pathname, WebsitePaths.Wiki);
|
||||
}
|
||||
private shouldDisplayBottomBar() {
|
||||
return this.isViewingWiki() || this.isViewing0xjsDocs() || this.isViewingFAQ() ||
|
||||
this.isViewingSmartContractsDocs() || this.isViewingConnectDocs();
|
||||
private _shouldDisplayBottomBar() {
|
||||
return this._isViewingWiki() || this._isViewing0xjsDocs() || this._isViewingFAQ() ||
|
||||
this._isViewingSmartContractsDocs() || this._isViewingConnectDocs();
|
||||
}
|
||||
}
|
||||
|
@@ -20,19 +20,19 @@ interface TradeHistoryState {
|
||||
}
|
||||
|
||||
export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> {
|
||||
private fillPollingIntervalId: number;
|
||||
private _fillPollingIntervalId: number;
|
||||
public constructor(props: TradeHistoryProps) {
|
||||
super(props);
|
||||
const sortedFills = this.getSortedFills();
|
||||
const sortedFills = this._getSortedFills();
|
||||
this.state = {
|
||||
sortedFills,
|
||||
};
|
||||
}
|
||||
public componentWillMount() {
|
||||
this.startPollingForFills();
|
||||
this._startPollingForFills();
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
this.stopPollingForFills();
|
||||
this._stopPollingForFills();
|
||||
}
|
||||
public componentDidMount() {
|
||||
window.scrollTo(0, 0);
|
||||
@@ -43,15 +43,15 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
||||
<h3>Trade history</h3>
|
||||
<Divider />
|
||||
<div className="pt2" style={{height: 608, overflow: 'scroll'}}>
|
||||
{this.renderTrades()}
|
||||
{this._renderTrades()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderTrades() {
|
||||
const numNonCustomFills = this.numFillsWithoutCustomERC20Tokens();
|
||||
private _renderTrades() {
|
||||
const numNonCustomFills = this._numFillsWithoutCustomERC20Tokens();
|
||||
if (numNonCustomFills === 0) {
|
||||
return this.renderEmptyNotice();
|
||||
return this._renderEmptyNotice();
|
||||
}
|
||||
|
||||
return _.map(this.state.sortedFills, (fill, index) => {
|
||||
@@ -66,14 +66,14 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
||||
);
|
||||
});
|
||||
}
|
||||
private renderEmptyNotice() {
|
||||
private _renderEmptyNotice() {
|
||||
return (
|
||||
<Paper className="mt1 p2 mx-auto center" style={{width: '80%'}}>
|
||||
No filled orders yet.
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
private numFillsWithoutCustomERC20Tokens() {
|
||||
private _numFillsWithoutCustomERC20Tokens() {
|
||||
let numNonCustomFills = 0;
|
||||
const tokens = _.values(this.props.tokenByAddress);
|
||||
_.each(this.state.sortedFills, fill => {
|
||||
@@ -93,9 +93,9 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
||||
});
|
||||
return numNonCustomFills;
|
||||
}
|
||||
private startPollingForFills() {
|
||||
this.fillPollingIntervalId = window.setInterval(() => {
|
||||
const sortedFills = this.getSortedFills();
|
||||
private _startPollingForFills() {
|
||||
this._fillPollingIntervalId = window.setInterval(() => {
|
||||
const sortedFills = this._getSortedFills();
|
||||
if (!utils.deepEqual(sortedFills, this.state.sortedFills)) {
|
||||
this.setState({
|
||||
sortedFills,
|
||||
@@ -103,10 +103,10 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
||||
}
|
||||
}, FILL_POLLING_INTERVAL);
|
||||
}
|
||||
private stopPollingForFills() {
|
||||
clearInterval(this.fillPollingIntervalId);
|
||||
private _stopPollingForFills() {
|
||||
clearInterval(this._fillPollingIntervalId);
|
||||
}
|
||||
private getSortedFills() {
|
||||
private _getSortedFills() {
|
||||
const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId);
|
||||
const fills = _.values(fillsByHash);
|
||||
const sortedFills = _.sortBy(fills, [(fill: Fill) => fill.blockTimestamp * -1]);
|
||||
|
@@ -54,7 +54,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
||||
>
|
||||
<div className="clearfix">
|
||||
<div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3">
|
||||
{this.renderDate()}
|
||||
{this._renderDate()}
|
||||
</div>
|
||||
<div
|
||||
className="col col-12 lg-col-6 md-col-6 lg-pl3 md-pl3"
|
||||
@@ -80,7 +80,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
||||
className={amountColClassNames}
|
||||
style={amountColStyle}
|
||||
>
|
||||
{this.renderAmounts(makerToken, takerToken)}
|
||||
{this._renderAmounts(makerToken, takerToken)}
|
||||
</div>
|
||||
<div className="col col-12 lg-col-1 md-col-1 lg-pr3 md-pr3 lg-py3 md-py3 sm-pb1 sm-center">
|
||||
<div className="pt1 lg-right md-right sm-mx-auto" style={{width: 13}}>
|
||||
@@ -95,7 +95,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
private renderAmounts(makerToken: Token, takerToken: Token) {
|
||||
private _renderAmounts(makerToken: Token, takerToken: Token) {
|
||||
const fill = this.props.fill;
|
||||
const filledTakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledTakerTokenAmount, takerToken.decimals);
|
||||
const filledMakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledMakerTokenAmount, takerToken.decimals);
|
||||
@@ -133,14 +133,14 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
||||
style={{color: colors.green400, fontSize: 16}}
|
||||
>
|
||||
<span>+{' '}</span>
|
||||
{this.renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)}
|
||||
{this._renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)}
|
||||
</div>
|
||||
<div
|
||||
className="pb1 inline-block"
|
||||
style={{color: colors.red200, fontSize: 16}}
|
||||
>
|
||||
<span>-{' '}</span>
|
||||
{this.renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)}
|
||||
{this._renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)}
|
||||
</div>
|
||||
<div style={{color: colors.grey400, fontSize: 14}}>
|
||||
{exchangeRate.toFixed(PRECISION)} {givenToken.symbol}/{receiveToken.symbol}
|
||||
@@ -148,7 +148,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderDate() {
|
||||
private _renderDate() {
|
||||
const blockMoment = moment.unix(this.props.fill.blockTimestamp);
|
||||
if (!blockMoment.isValid()) {
|
||||
return null;
|
||||
@@ -170,7 +170,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderAmount(amount: BigNumber, symbol: string, decimals: number) {
|
||||
private _renderAmount(amount: BigNumber, symbol: string, decimals: number) {
|
||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||
return (
|
||||
<span>
|
||||
|
@@ -42,14 +42,14 @@ export class Badge extends React.Component<BadgeProps, BadgeState> {
|
||||
<div
|
||||
className="p1 center"
|
||||
style={badgeStyle}
|
||||
onMouseOver={this.setHoverState.bind(this, true)}
|
||||
onMouseOut={this.setHoverState.bind(this, false)}
|
||||
onMouseOver={this._setHoverState.bind(this, true)}
|
||||
onMouseOut={this._setHoverState.bind(this, false)}
|
||||
>
|
||||
{this.props.title}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private setHoverState(isHovering: boolean) {
|
||||
private _setHoverState(isHovering: boolean) {
|
||||
this.setState({
|
||||
isHovering,
|
||||
});
|
||||
|
@@ -15,8 +15,8 @@ interface CopyIconState {
|
||||
}
|
||||
|
||||
export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
||||
private copyTooltipTimeoutId: number;
|
||||
private copyable: HTMLInputElement;
|
||||
private _copyTooltipTimeoutId: number;
|
||||
private _copyable: HTMLInputElement;
|
||||
constructor(props: CopyIconProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -25,25 +25,25 @@ export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
||||
}
|
||||
public componentDidUpdate() {
|
||||
// Remove tooltip if hover away
|
||||
if (!this.state.isHovering && this.copyTooltipTimeoutId) {
|
||||
clearInterval(this.copyTooltipTimeoutId);
|
||||
this.hideTooltip();
|
||||
if (!this.state.isHovering && this._copyTooltipTimeoutId) {
|
||||
clearInterval(this._copyTooltipTimeoutId);
|
||||
this._hideTooltip();
|
||||
}
|
||||
}
|
||||
public render() {
|
||||
return (
|
||||
<div className="inline-block">
|
||||
<CopyToClipboard text={this.props.data} onCopy={this.onCopy.bind(this)}>
|
||||
<CopyToClipboard text={this.props.data} onCopy={this._onCopy.bind(this)}>
|
||||
<div
|
||||
className="inline flex"
|
||||
style={{cursor: 'pointer', color: colors.amber600}}
|
||||
ref={this.setRefToProperty.bind(this)}
|
||||
ref={this._setRefToProperty.bind(this)}
|
||||
data-tip={true}
|
||||
data-for="copy"
|
||||
data-event="click"
|
||||
data-iscapture={true} // This let's the click event continue to propogate
|
||||
onMouseOver={this.setHoverState.bind(this, true)}
|
||||
onMouseOut={this.setHoverState.bind(this, false)}
|
||||
onMouseOver={this._setHoverState.bind(this, true)}
|
||||
onMouseOut={this._setHoverState.bind(this, false)}
|
||||
>
|
||||
<div>
|
||||
<i style={{fontSize: 15}} className="zmdi zmdi-copy" />
|
||||
@@ -57,25 +57,25 @@ export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private setRefToProperty(el: HTMLInputElement) {
|
||||
this.copyable = el;
|
||||
private _setRefToProperty(el: HTMLInputElement) {
|
||||
this._copyable = el;
|
||||
}
|
||||
private setHoverState(isHovering: boolean) {
|
||||
private _setHoverState(isHovering: boolean) {
|
||||
this.setState({
|
||||
isHovering,
|
||||
});
|
||||
}
|
||||
private onCopy() {
|
||||
if (this.copyTooltipTimeoutId) {
|
||||
clearInterval(this.copyTooltipTimeoutId);
|
||||
private _onCopy() {
|
||||
if (this._copyTooltipTimeoutId) {
|
||||
clearInterval(this._copyTooltipTimeoutId);
|
||||
}
|
||||
|
||||
const tooltipLifespanMs = 1000;
|
||||
this.copyTooltipTimeoutId = window.setTimeout(() => {
|
||||
this.hideTooltip();
|
||||
this._copyTooltipTimeoutId = window.setTimeout(() => {
|
||||
this._hideTooltip();
|
||||
}, tooltipLifespanMs);
|
||||
}
|
||||
private hideTooltip() {
|
||||
ReactTooltip.hide(ReactDOM.findDOMNode(this.copyable));
|
||||
private _hideTooltip() {
|
||||
ReactTooltip.hide(ReactDOM.findDOMNode(this._copyable));
|
||||
}
|
||||
}
|
||||
|
@@ -28,8 +28,8 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
||||
menuItemStyle: DEFAULT_STYLE,
|
||||
isNightVersion: false,
|
||||
};
|
||||
private isHovering: boolean;
|
||||
private popoverCloseCheckIntervalId: number;
|
||||
private _isHovering: boolean;
|
||||
private _popoverCloseCheckIntervalId: number;
|
||||
constructor(props: DropDownMenuItemProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -37,20 +37,20 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
||||
};
|
||||
}
|
||||
public componentDidMount() {
|
||||
this.popoverCloseCheckIntervalId = window.setInterval(() => {
|
||||
this.checkIfShouldClosePopover();
|
||||
this._popoverCloseCheckIntervalId = window.setInterval(() => {
|
||||
this._checkIfShouldClosePopover();
|
||||
}, CHECK_CLOSE_POPOVER_INTERVAL_MS);
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
window.clearInterval(this.popoverCloseCheckIntervalId);
|
||||
window.clearInterval(this._popoverCloseCheckIntervalId);
|
||||
}
|
||||
public render() {
|
||||
const colorStyle = this.props.isNightVersion ? 'white' : this.props.style.color;
|
||||
return (
|
||||
<div
|
||||
style={{...this.props.style, color: colorStyle}}
|
||||
onMouseEnter={this.onHover.bind(this)}
|
||||
onMouseLeave={this.onHoverOff.bind(this)}
|
||||
onMouseEnter={this._onHover.bind(this)}
|
||||
onMouseLeave={this._onHoverOff.bind(this)}
|
||||
>
|
||||
<div className="flex relative">
|
||||
<div style={{paddingRight: 10}}>
|
||||
@@ -65,12 +65,12 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
||||
anchorEl={this.state.anchorEl}
|
||||
anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}}
|
||||
targetOrigin={{horizontal: 'middle', vertical: 'top'}}
|
||||
onRequestClose={this.closePopover.bind(this)}
|
||||
onRequestClose={this._closePopover.bind(this)}
|
||||
useLayerForClickAway={false}
|
||||
>
|
||||
<div
|
||||
onMouseEnter={this.onHover.bind(this)}
|
||||
onMouseLeave={this.onHoverOff.bind(this)}
|
||||
onMouseEnter={this._onHover.bind(this)}
|
||||
onMouseLeave={this._onHoverOff.bind(this)}
|
||||
>
|
||||
<Menu style={{color: colors.grey}}>
|
||||
{this.props.subMenuItems}
|
||||
@@ -80,11 +80,11 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onHover(event: React.FormEvent<HTMLInputElement>) {
|
||||
this.isHovering = true;
|
||||
this.checkIfShouldOpenPopover(event);
|
||||
private _onHover(event: React.FormEvent<HTMLInputElement>) {
|
||||
this._isHovering = true;
|
||||
this._checkIfShouldOpenPopover(event);
|
||||
}
|
||||
private checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>) {
|
||||
private _checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>) {
|
||||
if (this.state.isDropDownOpen) {
|
||||
return; // noop
|
||||
}
|
||||
@@ -94,16 +94,16 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
||||
anchorEl: event.currentTarget,
|
||||
});
|
||||
}
|
||||
private onHoverOff(event: React.FormEvent<HTMLInputElement>) {
|
||||
this.isHovering = false;
|
||||
private _onHoverOff(event: React.FormEvent<HTMLInputElement>) {
|
||||
this._isHovering = false;
|
||||
}
|
||||
private checkIfShouldClosePopover() {
|
||||
if (!this.state.isDropDownOpen || this.isHovering) {
|
||||
private _checkIfShouldClosePopover() {
|
||||
if (!this.state.isDropDownOpen || this._isHovering) {
|
||||
return; // noop
|
||||
}
|
||||
this.closePopover();
|
||||
this._closePopover();
|
||||
}
|
||||
private closePopover() {
|
||||
private _closePopover() {
|
||||
this.setState({
|
||||
isDropDownOpen: false,
|
||||
});
|
||||
|
@@ -26,7 +26,7 @@ export class FlashMessage extends React.Component<FlashMessageProps, FlashMessag
|
||||
open={true}
|
||||
message={this.props.flashMessage}
|
||||
autoHideDuration={this.props.showDurationMs}
|
||||
onRequestClose={this.onClose.bind(this)}
|
||||
onRequestClose={this._onClose.bind(this)}
|
||||
bodyStyle={this.props.bodyStyle}
|
||||
/>
|
||||
);
|
||||
@@ -34,7 +34,7 @@ export class FlashMessage extends React.Component<FlashMessageProps, FlashMessag
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private onClose() {
|
||||
private _onClose() {
|
||||
this.props.dispatcher.hideFlashMessage();
|
||||
}
|
||||
}
|
||||
|
@@ -35,8 +35,8 @@ export class LifeCycleRaisedButton extends
|
||||
backgroundColor: colors.white,
|
||||
labelColor: colors.darkGrey,
|
||||
};
|
||||
private buttonTimeoutId: number;
|
||||
private didUnmount: boolean;
|
||||
private _buttonTimeoutId: number;
|
||||
private _didUnmount: boolean;
|
||||
constructor(props: LifeCycleRaisedButtonProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -44,8 +44,8 @@ export class LifeCycleRaisedButton extends
|
||||
};
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
clearTimeout(this.buttonTimeoutId);
|
||||
this.didUnmount = true;
|
||||
clearTimeout(this._buttonTimeoutId);
|
||||
this._didUnmount = true;
|
||||
}
|
||||
public render() {
|
||||
if (this.props.isHidden) {
|
||||
@@ -83,14 +83,14 @@ export class LifeCycleRaisedButton extends
|
||||
buttonState: ButtonState.LOADING,
|
||||
});
|
||||
const didSucceed = await this.props.onClickAsyncFn();
|
||||
if (this.didUnmount) {
|
||||
if (this._didUnmount) {
|
||||
return; // noop since unmount called before async callback returned.
|
||||
}
|
||||
if (didSucceed) {
|
||||
this.setState({
|
||||
buttonState: ButtonState.COMPLETE,
|
||||
});
|
||||
this.buttonTimeoutId = window.setTimeout(() => {
|
||||
this._buttonTimeoutId = window.setTimeout(() => {
|
||||
this.setState({
|
||||
buttonState: ButtonState.READY,
|
||||
});
|
||||
|
@@ -35,15 +35,15 @@ export class MenuItem extends React.Component<MenuItemProps, MenuItemState> {
|
||||
onClick={this.props.onClick.bind(this)}
|
||||
className={`mx-auto ${this.props.className}`}
|
||||
style={menuItemStyles}
|
||||
onMouseEnter={this.onToggleHover.bind(this, true)}
|
||||
onMouseLeave={this.onToggleHover.bind(this, false)}
|
||||
onMouseEnter={this._onToggleHover.bind(this, true)}
|
||||
onMouseLeave={this._onToggleHover.bind(this, false)}
|
||||
>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
private onToggleHover(isHovering: boolean) {
|
||||
private _onToggleHover(isHovering: boolean) {
|
||||
this.setState({
|
||||
isHovering,
|
||||
});
|
||||
|
@@ -27,8 +27,8 @@ export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> {
|
||||
className="mx-auto pt4"
|
||||
style={{cursor: 'pointer', height: 50, width: 37.5}}
|
||||
onClick={this.props.swapTokensFn}
|
||||
onMouseEnter={this.onToggleHover.bind(this, true)}
|
||||
onMouseLeave={this.onToggleHover.bind(this, false)}
|
||||
onMouseEnter={this._onToggleHover.bind(this, true)}
|
||||
onMouseLeave={this._onToggleHover.bind(this, false)}
|
||||
>
|
||||
<i
|
||||
style={swapStyles}
|
||||
@@ -37,7 +37,7 @@ export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private onToggleHover(isHovering: boolean) {
|
||||
private _onToggleHover(isHovering: boolean) {
|
||||
this.setState({
|
||||
isHovering,
|
||||
});
|
||||
|
@@ -42,13 +42,13 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt
|
||||
</div>
|
||||
<div className="col col-2 center pt1">
|
||||
<div className="pb1">
|
||||
{this.renderAmount(this.props.takerAssetToken, this.props.takerToken)}
|
||||
{this._renderAmount(this.props.takerAssetToken, this.props.takerToken)}
|
||||
</div>
|
||||
<div className="lg-p2 md-p2 sm-p1">
|
||||
<img src="/images/trade_arrows.png" style={{width: 47}} />
|
||||
</div>
|
||||
<div className="pt1">
|
||||
{this.renderAmount(this.props.makerAssetToken, this.props.makerToken)}
|
||||
{this._renderAmount(this.props.makerAssetToken, this.props.makerToken)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col col-5 center">
|
||||
@@ -65,7 +65,7 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt
|
||||
</div>
|
||||
);
|
||||
}
|
||||
private renderAmount(assetToken: AssetToken, token: Token) {
|
||||
private _renderAmount(assetToken: AssetToken, token: Token) {
|
||||
const unitAmount = ZeroEx.toUnitAmount(assetToken.amount, token.decimals);
|
||||
return (
|
||||
<div style={{fontSize: 13}}>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user