Merge pull request #285 from 0xProject/fix/underscorePrivate
Add new underscore-privates rule to @0xproject/tslint-config and fix …
This commit is contained in:
@@ -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`
|
* It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs`
|
||||||
*/
|
*/
|
||||||
export class ExpirationWatcher {
|
export class ExpirationWatcher {
|
||||||
private orderHashByExpirationRBTree: RBTree<string>;
|
private _orderHashByExpirationRBTree: RBTree<string>;
|
||||||
private expiration: {[orderHash: string]: BigNumber} = {};
|
private _expiration: {[orderHash: string]: BigNumber} = {};
|
||||||
private orderExpirationCheckingIntervalMs: number;
|
private _orderExpirationCheckingIntervalMs: number;
|
||||||
private expirationMarginMs: number;
|
private _expirationMarginMs: number;
|
||||||
private orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||||
constructor(expirationMarginIfExistsMs?: number,
|
constructor(expirationMarginIfExistsMs?: number,
|
||||||
orderExpirationCheckingIntervalIfExistsMs?: number) {
|
orderExpirationCheckingIntervalIfExistsMs?: number) {
|
||||||
this.expirationMarginMs = expirationMarginIfExistsMs ||
|
this._expirationMarginMs = expirationMarginIfExistsMs ||
|
||||||
DEFAULT_EXPIRATION_MARGIN_MS;
|
DEFAULT_EXPIRATION_MARGIN_MS;
|
||||||
this.orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
this._orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
||||||
DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
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);
|
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 {
|
public subscribe(callback: (orderHash: string) => void): void {
|
||||||
if (!_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
|
if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
}
|
}
|
||||||
this.orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this.pruneExpiredOrders.bind(this, callback), this.orderExpirationCheckingIntervalMs,
|
this._pruneExpiredOrders.bind(this, callback), this._orderExpirationCheckingIntervalMs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public unsubscribe(): void {
|
public unsubscribe(): void {
|
||||||
if (_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
|
if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||||
}
|
}
|
||||||
intervalUtils.clearAsyncExcludingInterval(this.orderExpirationCheckingIntervalIdIfExists);
|
intervalUtils.clearAsyncExcludingInterval(this._orderExpirationCheckingIntervalIdIfExists);
|
||||||
delete this.orderExpirationCheckingIntervalIdIfExists;
|
delete this._orderExpirationCheckingIntervalIdIfExists;
|
||||||
}
|
}
|
||||||
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
|
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
|
||||||
this.expiration[orderHash] = expirationUnixTimestampMs;
|
this._expiration[orderHash] = expirationUnixTimestampMs;
|
||||||
this.orderHashByExpirationRBTree.insert(orderHash);
|
this._orderHashByExpirationRBTree.insert(orderHash);
|
||||||
}
|
}
|
||||||
public removeOrder(orderHash: string): void {
|
public removeOrder(orderHash: string): void {
|
||||||
this.orderHashByExpirationRBTree.remove(orderHash);
|
this._orderHashByExpirationRBTree.remove(orderHash);
|
||||||
delete this.expiration[orderHash];
|
delete this._expiration[orderHash];
|
||||||
}
|
}
|
||||||
private pruneExpiredOrders(callback: (orderHash: string) => void): void {
|
private _pruneExpiredOrders(callback: (orderHash: string) => void): void {
|
||||||
const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
|
const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
|
||||||
while (true) {
|
while (true) {
|
||||||
const hasTrakedOrders = this.orderHashByExpirationRBTree.size === 0;
|
const hasTrakedOrders = this._orderHashByExpirationRBTree.size === 0;
|
||||||
if (hasTrakedOrders) {
|
if (hasTrakedOrders) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const nextOrderHashToExpire = this.orderHashByExpirationRBTree.min();
|
const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min();
|
||||||
const hasNoExpiredOrders = this.expiration[nextOrderHashToExpire].greaterThan(
|
const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].greaterThan(
|
||||||
currentUnixTimestampMs.plus(this.expirationMarginMs),
|
currentUnixTimestampMs.plus(this._expirationMarginMs),
|
||||||
);
|
);
|
||||||
const isSubscriptionActive = _.isUndefined(this.orderExpirationCheckingIntervalIdIfExists);
|
const isSubscriptionActive = _.isUndefined(this._orderExpirationCheckingIntervalIdIfExists);
|
||||||
if (hasNoExpiredOrders || isSubscriptionActive) {
|
if (hasNoExpiredOrders || isSubscriptionActive) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const orderHash = this.orderHashByExpirationRBTree.min();
|
const orderHash = this._orderHashByExpirationRBTree.min();
|
||||||
this.orderHashByExpirationRBTree.remove(orderHash);
|
this._orderHashByExpirationRBTree.remove(orderHash);
|
||||||
delete this.expiration[orderHash];
|
delete this._expiration[orderHash];
|
||||||
callback(orderHash);
|
callback(orderHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -111,7 +111,7 @@ export class OrderStateWatcher {
|
|||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
||||||
this._orderByOrderHash[orderHash] = signedOrder;
|
this._orderByOrderHash[orderHash] = signedOrder;
|
||||||
this.addToDependentOrderHashes(signedOrder, orderHash);
|
this._addToDependentOrderHashes(signedOrder, orderHash);
|
||||||
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
||||||
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
||||||
}
|
}
|
||||||
@@ -127,10 +127,10 @@ export class OrderStateWatcher {
|
|||||||
}
|
}
|
||||||
delete this._orderByOrderHash[orderHash];
|
delete this._orderByOrderHash[orderHash];
|
||||||
delete this._orderStateByOrderHashCache[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();
|
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||||
this.removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||||
this.removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||||
this._expirationWatcher.removeOrder(orderHash);
|
this._expirationWatcher.removeOrder(orderHash);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -327,7 +327,7 @@ export class OrderStateWatcher {
|
|||||||
this._callbackIfExists(orderState);
|
this._callbackIfExists(orderState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
||||||
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
|
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
|
||||||
this._dependentOrderHashes[signedOrder.maker] = {};
|
this._dependentOrderHashes[signedOrder.maker] = {};
|
||||||
}
|
}
|
||||||
@@ -341,7 +341,7 @@ export class OrderStateWatcher {
|
|||||||
}
|
}
|
||||||
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
|
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);
|
this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash);
|
||||||
if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
|
if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
|
||||||
delete this._dependentOrderHashes[makerAddress][tokenAddress];
|
delete this._dependentOrderHashes[makerAddress][tokenAddress];
|
||||||
@@ -351,7 +351,7 @@ export class OrderStateWatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _getZRXTokenAddress(): string {
|
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();
|
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||||
return zrxTokenAddress;
|
return zrxTokenAddress;
|
||||||
}
|
}
|
||||||
|
@@ -3,69 +3,69 @@ import {BigNumber} from 'bignumber.js';
|
|||||||
import {SignedOrder} from '../types';
|
import {SignedOrder} from '../types';
|
||||||
|
|
||||||
export class RemainingFillableCalculator {
|
export class RemainingFillableCalculator {
|
||||||
private signedOrder: SignedOrder;
|
private _signedOrder: SignedOrder;
|
||||||
private isMakerTokenZRX: boolean;
|
private _isMakerTokenZRX: boolean;
|
||||||
// Transferrable Amount is the minimum of Approval and Balance
|
// Transferrable Amount is the minimum of Approval and Balance
|
||||||
private transferrableMakerTokenAmount: BigNumber;
|
private _transferrableMakerTokenAmount: BigNumber;
|
||||||
private transferrableMakerFeeTokenAmount: BigNumber;
|
private _transferrableMakerFeeTokenAmount: BigNumber;
|
||||||
private remainingMakerTokenAmount: BigNumber;
|
private _remainingMakerTokenAmount: BigNumber;
|
||||||
private remainingMakerFeeAmount: BigNumber;
|
private _remainingMakerFeeAmount: BigNumber;
|
||||||
constructor(signedOrder: SignedOrder,
|
constructor(signedOrder: SignedOrder,
|
||||||
isMakerTokenZRX: boolean,
|
isMakerTokenZRX: boolean,
|
||||||
transferrableMakerTokenAmount: BigNumber,
|
transferrableMakerTokenAmount: BigNumber,
|
||||||
transferrableMakerFeeTokenAmount: BigNumber,
|
transferrableMakerFeeTokenAmount: BigNumber,
|
||||||
remainingMakerTokenAmount: BigNumber) {
|
remainingMakerTokenAmount: BigNumber) {
|
||||||
this.signedOrder = signedOrder;
|
this._signedOrder = signedOrder;
|
||||||
this.isMakerTokenZRX = isMakerTokenZRX;
|
this._isMakerTokenZRX = isMakerTokenZRX;
|
||||||
this.transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
||||||
this.transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
||||||
this.remainingMakerTokenAmount = remainingMakerTokenAmount;
|
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||||
this.remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee)
|
this._remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee)
|
||||||
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
||||||
}
|
}
|
||||||
public computeRemainingMakerFillable(): BigNumber {
|
public computeRemainingMakerFillable(): BigNumber {
|
||||||
if (this.hasSufficientFundsForFeeAndTransferAmount()) {
|
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
||||||
return this.remainingMakerTokenAmount;
|
return this._remainingMakerTokenAmount;
|
||||||
}
|
}
|
||||||
if (this.signedOrder.makerFee.isZero()) {
|
if (this._signedOrder.makerFee.isZero()) {
|
||||||
return BigNumber.min(this.remainingMakerTokenAmount, this.transferrableMakerTokenAmount);
|
return BigNumber.min(this._remainingMakerTokenAmount, this._transferrableMakerTokenAmount);
|
||||||
}
|
}
|
||||||
return this.calculatePartiallyFillableMakerTokenAmount();
|
return this._calculatePartiallyFillableMakerTokenAmount();
|
||||||
}
|
}
|
||||||
public computeRemainingTakerFillable(): BigNumber {
|
public computeRemainingTakerFillable(): BigNumber {
|
||||||
return this.computeRemainingMakerFillable().times(this.signedOrder.takerTokenAmount)
|
return this.computeRemainingMakerFillable().times(this._signedOrder.takerTokenAmount)
|
||||||
.dividedToIntegerBy(this.signedOrder.makerTokenAmount);
|
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
||||||
}
|
}
|
||||||
private hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||||
if (this.isMakerTokenZRX) {
|
if (this._isMakerTokenZRX) {
|
||||||
const totalZRXTransferAmountRequired = this.remainingMakerTokenAmount.plus(this.remainingMakerFeeAmount);
|
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
||||||
const hasSufficientFunds = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||||
totalZRXTransferAmountRequired);
|
totalZRXTransferAmountRequired);
|
||||||
return hasSufficientFunds;
|
return hasSufficientFunds;
|
||||||
} else {
|
} else {
|
||||||
const hasSufficientFundsForTransferAmount = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||||
this.remainingMakerTokenAmount);
|
this._remainingMakerTokenAmount);
|
||||||
const hasSufficientFundsForFeeAmount = this.transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||||
this.remainingMakerFeeAmount);
|
this._remainingMakerFeeAmount);
|
||||||
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
||||||
return hasSufficientFunds;
|
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
|
// 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
|
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
||||||
// baseUnit of fee tokens.
|
// baseUnit of fee tokens.
|
||||||
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
// 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,
|
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this._transferrableMakerFeeTokenAmount,
|
||||||
this.remainingMakerFeeAmount);
|
this._remainingMakerFeeAmount);
|
||||||
// The number of times the Maker can fill the order, given the Maker Token Balance
|
// 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.
|
// 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);
|
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||||
if (this.isMakerTokenZRX) {
|
if (this._isMakerTokenZRX) {
|
||||||
// If ZRX is the maker token, the Fee and the Maker amount need to be removed from the same pool;
|
// 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)
|
// 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
|
// 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
|
// For every one number of fills, we have to take an extra ZRX out of the pool
|
||||||
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(
|
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.
|
// 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.
|
// This can result in a RoundingError being thrown by the Exchange Contract.
|
||||||
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
||||||
.times(this.signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerTokenAmount)
|
||||||
.dividedToIntegerBy(this.signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
||||||
.times(this.signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerTokenAmount)
|
||||||
.dividedToIntegerBy(this.signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
|
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
|
||||||
partiallyFillableFeeTokenAmount);
|
partiallyFillableFeeTokenAmount);
|
||||||
return partiallyFillableAmount;
|
return partiallyFillableAmount;
|
||||||
|
@@ -8,77 +8,77 @@ import {BlockParamLiteral} from '../types';
|
|||||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||||
*/
|
*/
|
||||||
export class BalanceAndProxyAllowanceLazyStore {
|
export class BalanceAndProxyAllowanceLazyStore {
|
||||||
private token: TokenWrapper;
|
private _token: TokenWrapper;
|
||||||
private defaultBlock: BlockParamLiteral;
|
private _defaultBlock: BlockParamLiteral;
|
||||||
private balance: {
|
private _balance: {
|
||||||
[tokenAddress: string]: {
|
[tokenAddress: string]: {
|
||||||
[userAddress: string]: BigNumber;
|
[userAddress: string]: BigNumber;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
private proxyAllowance: {
|
private _proxyAllowance: {
|
||||||
[tokenAddress: string]: {
|
[tokenAddress: string]: {
|
||||||
[userAddress: string]: BigNumber;
|
[userAddress: string]: BigNumber;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||||
this.token = token;
|
this._token = token;
|
||||||
this.defaultBlock = defaultBlock;
|
this._defaultBlock = defaultBlock;
|
||||||
this.balance = {};
|
this._balance = {};
|
||||||
this.proxyAllowance = {};
|
this._proxyAllowance = {};
|
||||||
}
|
}
|
||||||
public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
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 = {
|
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);
|
this.setBalance(tokenAddress, userAddress, balance);
|
||||||
}
|
}
|
||||||
const cachedBalance = this.balance[tokenAddress][userAddress];
|
const cachedBalance = this._balance[tokenAddress][userAddress];
|
||||||
return cachedBalance;
|
return cachedBalance;
|
||||||
}
|
}
|
||||||
public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void {
|
public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void {
|
||||||
if (_.isUndefined(this.balance[tokenAddress])) {
|
if (_.isUndefined(this._balance[tokenAddress])) {
|
||||||
this.balance[tokenAddress] = {};
|
this._balance[tokenAddress] = {};
|
||||||
}
|
}
|
||||||
this.balance[tokenAddress][userAddress] = balance;
|
this._balance[tokenAddress][userAddress] = balance;
|
||||||
}
|
}
|
||||||
public deleteBalance(tokenAddress: string, userAddress: string): void {
|
public deleteBalance(tokenAddress: string, userAddress: string): void {
|
||||||
if (!_.isUndefined(this.balance[tokenAddress])) {
|
if (!_.isUndefined(this._balance[tokenAddress])) {
|
||||||
delete this.balance[tokenAddress][userAddress];
|
delete this._balance[tokenAddress][userAddress];
|
||||||
if (_.isEmpty(this.balance[tokenAddress])) {
|
if (_.isEmpty(this._balance[tokenAddress])) {
|
||||||
delete this.balance[tokenAddress];
|
delete this._balance[tokenAddress];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||||
if (_.isUndefined(this.proxyAllowance[tokenAddress]) ||
|
if (_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
||||||
_.isUndefined(this.proxyAllowance[tokenAddress][userAddress])) {
|
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) {
|
||||||
const methodOpts = {
|
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);
|
this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance);
|
||||||
}
|
}
|
||||||
const cachedProxyAllowance = this.proxyAllowance[tokenAddress][userAddress];
|
const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress];
|
||||||
return cachedProxyAllowance;
|
return cachedProxyAllowance;
|
||||||
}
|
}
|
||||||
public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void {
|
public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void {
|
||||||
if (_.isUndefined(this.proxyAllowance[tokenAddress])) {
|
if (_.isUndefined(this._proxyAllowance[tokenAddress])) {
|
||||||
this.proxyAllowance[tokenAddress] = {};
|
this._proxyAllowance[tokenAddress] = {};
|
||||||
}
|
}
|
||||||
this.proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
|
this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
|
||||||
}
|
}
|
||||||
public deleteProxyAllowance(tokenAddress: string, userAddress: string): void {
|
public deleteProxyAllowance(tokenAddress: string, userAddress: string): void {
|
||||||
if (!_.isUndefined(this.proxyAllowance[tokenAddress])) {
|
if (!_.isUndefined(this._proxyAllowance[tokenAddress])) {
|
||||||
delete this.proxyAllowance[tokenAddress][userAddress];
|
delete this._proxyAllowance[tokenAddress][userAddress];
|
||||||
if (_.isEmpty(this.proxyAllowance[tokenAddress])) {
|
if (_.isEmpty(this._proxyAllowance[tokenAddress])) {
|
||||||
delete this.proxyAllowance[tokenAddress];
|
delete this._proxyAllowance[tokenAddress];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public deleteAll(): void {
|
public deleteAll(): void {
|
||||||
this.balance = {};
|
this._balance = {};
|
||||||
this.proxyAllowance = {};
|
this._proxyAllowance = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,54 +8,54 @@ import {BlockParamLiteral} from '../types';
|
|||||||
* Copy on read store for filled/cancelled taker amounts
|
* Copy on read store for filled/cancelled taker amounts
|
||||||
*/
|
*/
|
||||||
export class OrderFilledCancelledLazyStore {
|
export class OrderFilledCancelledLazyStore {
|
||||||
private exchange: ExchangeWrapper;
|
private _exchange: ExchangeWrapper;
|
||||||
private filledTakerAmount: {
|
private _filledTakerAmount: {
|
||||||
[orderHash: string]: BigNumber;
|
[orderHash: string]: BigNumber;
|
||||||
};
|
};
|
||||||
private cancelledTakerAmount: {
|
private _cancelledTakerAmount: {
|
||||||
[orderHash: string]: BigNumber;
|
[orderHash: string]: BigNumber;
|
||||||
};
|
};
|
||||||
constructor(exchange: ExchangeWrapper) {
|
constructor(exchange: ExchangeWrapper) {
|
||||||
this.exchange = exchange;
|
this._exchange = exchange;
|
||||||
this.filledTakerAmount = {};
|
this._filledTakerAmount = {};
|
||||||
this.cancelledTakerAmount = {};
|
this._cancelledTakerAmount = {};
|
||||||
}
|
}
|
||||||
public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||||
if (_.isUndefined(this.filledTakerAmount[orderHash])) {
|
if (_.isUndefined(this._filledTakerAmount[orderHash])) {
|
||||||
const methodOpts = {
|
const methodOpts = {
|
||||||
defaultBlock: BlockParamLiteral.Pending,
|
defaultBlock: BlockParamLiteral.Pending,
|
||||||
};
|
};
|
||||||
const filledTakerAmount = await this.exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
|
const filledTakerAmount = await this._exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
|
||||||
this.setFilledTakerAmount(orderHash, filledTakerAmount);
|
this.setFilledTakerAmount(orderHash, filledTakerAmount);
|
||||||
}
|
}
|
||||||
const cachedFilled = this.filledTakerAmount[orderHash];
|
const cachedFilled = this._filledTakerAmount[orderHash];
|
||||||
return cachedFilled;
|
return cachedFilled;
|
||||||
}
|
}
|
||||||
public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
|
public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
|
||||||
this.filledTakerAmount[orderHash] = filledTakerAmount;
|
this._filledTakerAmount[orderHash] = filledTakerAmount;
|
||||||
}
|
}
|
||||||
public deleteFilledTakerAmount(orderHash: string): void {
|
public deleteFilledTakerAmount(orderHash: string): void {
|
||||||
delete this.filledTakerAmount[orderHash];
|
delete this._filledTakerAmount[orderHash];
|
||||||
}
|
}
|
||||||
public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||||
if (_.isUndefined(this.cancelledTakerAmount[orderHash])) {
|
if (_.isUndefined(this._cancelledTakerAmount[orderHash])) {
|
||||||
const methodOpts = {
|
const methodOpts = {
|
||||||
defaultBlock: BlockParamLiteral.Pending,
|
defaultBlock: BlockParamLiteral.Pending,
|
||||||
};
|
};
|
||||||
const cancelledTakerAmount = await this.exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
|
const cancelledTakerAmount = await this._exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
|
||||||
this.setCancelledTakerAmount(orderHash, cancelledTakerAmount);
|
this.setCancelledTakerAmount(orderHash, cancelledTakerAmount);
|
||||||
}
|
}
|
||||||
const cachedCancelled = this.cancelledTakerAmount[orderHash];
|
const cachedCancelled = this._cancelledTakerAmount[orderHash];
|
||||||
return cachedCancelled;
|
return cachedCancelled;
|
||||||
}
|
}
|
||||||
public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void {
|
public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void {
|
||||||
this.cancelledTakerAmount[orderHash] = cancelledTakerAmount;
|
this._cancelledTakerAmount[orderHash] = cancelledTakerAmount;
|
||||||
}
|
}
|
||||||
public deleteCancelledTakerAmount(orderHash: string): void {
|
public deleteCancelledTakerAmount(orderHash: string): void {
|
||||||
delete this.cancelledTakerAmount[orderHash];
|
delete this._cancelledTakerAmount[orderHash];
|
||||||
}
|
}
|
||||||
public deleteAll(): void {
|
public deleteAll(): void {
|
||||||
this.filledTakerAmount = {};
|
this._filledTakerAmount = {};
|
||||||
this.cancelledTakerAmount = {};
|
this._cancelledTakerAmount = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,9 +6,9 @@ import * as SolidityCoder from 'web3/lib/solidity/coder';
|
|||||||
import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
|
import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
|
||||||
|
|
||||||
export class AbiDecoder {
|
export class AbiDecoder {
|
||||||
private savedABIs: Web3.AbiDefinition[] = [];
|
private _savedABIs: Web3.AbiDefinition[] = [];
|
||||||
private methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
|
private _methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
|
||||||
private static padZeros(address: string) {
|
private static _padZeros(address: string) {
|
||||||
let formatted = address;
|
let formatted = address;
|
||||||
if (_.startsWith(formatted, '0x')) {
|
if (_.startsWith(formatted, '0x')) {
|
||||||
formatted = formatted.slice(2);
|
formatted = formatted.slice(2);
|
||||||
@@ -18,13 +18,13 @@ export class AbiDecoder {
|
|||||||
return `0x${formatted}`;
|
return `0x${formatted}`;
|
||||||
}
|
}
|
||||||
constructor(abiArrays: Web3.AbiDefinition[][]) {
|
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
|
// This method can only decode logs from the 0x & ERC20 smart contracts
|
||||||
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
||||||
const methodId = log.topics[0];
|
const methodId = log.topics[0];
|
||||||
const event = this.methodIds[methodId];
|
const event = this._methodIds[methodId];
|
||||||
if (_.isUndefined(event)) {
|
if (_.isUndefined(event)) {
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ export class AbiDecoder {
|
|||||||
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
||||||
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
||||||
if (param.type === SolidityTypes.Address) {
|
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 ||
|
} else if (param.type === SolidityTypes.Uint256 ||
|
||||||
param.type === SolidityTypes.Uint8 ||
|
param.type === SolidityTypes.Uint8 ||
|
||||||
param.type === SolidityTypes.Uint) {
|
param.type === SolidityTypes.Uint) {
|
||||||
@@ -56,14 +56,14 @@ export class AbiDecoder {
|
|||||||
args: decodedParams,
|
args: decodedParams,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private addABI(abiArray: Web3.AbiDefinition[]): void {
|
private _addABI(abiArray: Web3.AbiDefinition[]): void {
|
||||||
_.map(abiArray, (abi: Web3.AbiDefinition) => {
|
_.map(abiArray, (abi: Web3.AbiDefinition) => {
|
||||||
if (abi.type === AbiType.Event) {
|
if (abi.type === AbiType.Event) {
|
||||||
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`;
|
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`;
|
||||||
const signatureHash = new Web3().sha3(signature);
|
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 {
|
export class ExchangeTransferSimulator {
|
||||||
private store: BalanceAndProxyAllowanceLazyStore;
|
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||||
private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||||
private static throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
private static _throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
||||||
transferType: TransferType): never {
|
transferType: TransferType): never {
|
||||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||||
this.store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||||
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Simulates transferFrom call performed by a proxy
|
* Simulates transferFrom call performed by a proxy
|
||||||
@@ -57,33 +57,33 @@ export class ExchangeTransferSimulator {
|
|||||||
public async transferFromAsync(tokenAddress: string, from: string, to: string,
|
public async transferFromAsync(tokenAddress: string, from: string, to: string,
|
||||||
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
|
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
|
||||||
transferType: TransferType): Promise<void> {
|
transferType: TransferType): Promise<void> {
|
||||||
const balance = await this.store.getBalanceAsync(tokenAddress, from);
|
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
||||||
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, from);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
||||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||||
ExchangeTransferSimulator.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
||||||
}
|
}
|
||||||
if (balance.lessThan(amountInBaseUnits)) {
|
if (balance.lessThan(amountInBaseUnits)) {
|
||||||
ExchangeTransferSimulator.throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||||
}
|
}
|
||||||
await this.decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
|
await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||||
await this.decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||||
await this.increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||||
}
|
}
|
||||||
private async decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
private async _decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
amountInBaseUnits: BigNumber): Promise<void> {
|
||||||
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||||
if (!proxyAllowance.eq(this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||||
this.store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
private async _increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
amountInBaseUnits: BigNumber): Promise<void> {
|
||||||
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
|
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||||
this.store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
private async decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
private async _decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
amountInBaseUnits: BigNumber): Promise<void> {
|
||||||
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
|
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||||
this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,9 +18,9 @@ import {
|
|||||||
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
||||||
|
|
||||||
export class OrderStateUtils {
|
export class OrderStateUtils {
|
||||||
private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||||
private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||||
private static validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
|
private static _validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
|
||||||
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
|
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
|
||||||
orderRelevantState.filledTakerTokenAmount,
|
orderRelevantState.filledTakerTokenAmount,
|
||||||
);
|
);
|
||||||
@@ -53,14 +53,14 @@ export class OrderStateUtils {
|
|||||||
}
|
}
|
||||||
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
||||||
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) {
|
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) {
|
||||||
this.balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||||
this.orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||||
}
|
}
|
||||||
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
||||||
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
|
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
try {
|
try {
|
||||||
OrderStateUtils.validateIfOrderIsValid(signedOrder, orderRelevantState);
|
OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
|
||||||
const orderState: OrderStateValid = {
|
const orderState: OrderStateValid = {
|
||||||
isValid: true,
|
isValid: true,
|
||||||
orderHash,
|
orderHash,
|
||||||
@@ -81,23 +81,23 @@ export class OrderStateUtils {
|
|||||||
// If we pass it from the instantiator - there is no opportunity to get it there
|
// If we pass it from the instantiator - there is no opportunity to get it there
|
||||||
// because JS doesn't support async constructors.
|
// because JS doesn't support async constructors.
|
||||||
// Moreover - it's cached under the hood so it's equivalent to an async constructor.
|
// 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 zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const makerBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
signedOrder.makerTokenAddress, signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
signedOrder.makerTokenAddress, signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerFeeBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||||
zrxTokenAddress, signedOrder.maker,
|
zrxTokenAddress, signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerFeeProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||||
zrxTokenAddress, signedOrder.maker,
|
zrxTokenAddress, signedOrder.maker,
|
||||||
);
|
);
|
||||||
const filledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||||
const cancelledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||||
orderHash,
|
orderHash,
|
||||||
);
|
);
|
||||||
const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash);
|
||||||
|
@@ -10,7 +10,7 @@ import {utils} from '../utils/utils';
|
|||||||
import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
|
import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
|
||||||
|
|
||||||
export class OrderValidationUtils {
|
export class OrderValidationUtils {
|
||||||
private exchangeWrapper: ExchangeWrapper;
|
private _exchangeWrapper: ExchangeWrapper;
|
||||||
public static validateCancelOrderThrowIfInvalid(
|
public static validateCancelOrderThrowIfInvalid(
|
||||||
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
||||||
): void {
|
): void {
|
||||||
@@ -29,7 +29,7 @@ export class OrderValidationUtils {
|
|||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
||||||
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
|
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
|
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
signedOrder.takerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
signedOrder.makerTokenAmount,
|
signedOrder.makerTokenAmount,
|
||||||
@@ -42,7 +42,7 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
|
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
|
||||||
TradeSide.Taker, TransferType.Trade,
|
TradeSide.Taker, TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
|
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
signedOrder.takerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
@@ -51,7 +51,7 @@ export class OrderValidationUtils {
|
|||||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
|
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
|
||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
const takerFeeAmount = OrderValidationUtils.getPartialAmount(
|
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
signedOrder.takerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
signedOrder.takerFee,
|
signedOrder.takerFee,
|
||||||
@@ -61,21 +61,21 @@ export class OrderValidationUtils {
|
|||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private static validateRemainingFillAmountNotZeroOrThrow(
|
private static _validateRemainingFillAmountNotZeroOrThrow(
|
||||||
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
||||||
) {
|
) {
|
||||||
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
|
private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
|
||||||
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||||
if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
|
if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
||||||
target: BigNumber): BigNumber {
|
target: BigNumber): BigNumber {
|
||||||
const fillMakerTokenAmount = numerator
|
const fillMakerTokenAmount = numerator
|
||||||
.mul(target)
|
.mul(target)
|
||||||
.div(denominator)
|
.div(denominator)
|
||||||
@@ -83,22 +83,22 @@ export class OrderValidationUtils {
|
|||||||
return fillMakerTokenAmount;
|
return fillMakerTokenAmount;
|
||||||
}
|
}
|
||||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||||
this.exchangeWrapper = exchangeWrapper;
|
this._exchangeWrapper = exchangeWrapper;
|
||||||
}
|
}
|
||||||
public async validateOrderFillableOrThrowAsync(
|
public async validateOrderFillableOrThrowAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
|
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
|
||||||
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
|
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
|
||||||
const orderHash = utils.getOrderHashHex(signedOrder);
|
const orderHash = utils.getOrderHashHex(signedOrder);
|
||||||
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
|
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||||
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
|
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
|
||||||
fillTakerTokenAmount = expectedFillTakerTokenAmount;
|
fillTakerTokenAmount = expectedFillTakerTokenAmount;
|
||||||
}
|
}
|
||||||
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
|
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
signedOrder.takerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
signedOrder.makerTokenAmount,
|
signedOrder.makerTokenAmount,
|
||||||
@@ -107,7 +107,7 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
|
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
|
||||||
TradeSide.Maker, TransferType.Trade,
|
TradeSide.Maker, TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
|
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
signedOrder.takerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
@@ -128,14 +128,14 @@ export class OrderValidationUtils {
|
|||||||
if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
||||||
throw new Error(ZeroExError.InvalidSignature);
|
throw new Error(ZeroExError.InvalidSignature);
|
||||||
}
|
}
|
||||||
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
|
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
||||||
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||||
}
|
}
|
||||||
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||||
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
|
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
|
||||||
remainingTakerTokenAmount :
|
remainingTakerTokenAmount :
|
||||||
@@ -144,7 +144,7 @@ export class OrderValidationUtils {
|
|||||||
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
|
||||||
);
|
);
|
||||||
|
|
||||||
const wouldRoundingErrorOccur = await this.exchangeWrapper.isRoundingErrorAsync(
|
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||||
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
|
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
if (wouldRoundingErrorOccur) {
|
if (wouldRoundingErrorOccur) {
|
||||||
|
@@ -65,7 +65,7 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
await exchangeTransferSimulator.transferFromAsync(
|
await exchangeTransferSimulator.transferFromAsync(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
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 senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||||
@@ -81,7 +81,7 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
await exchangeTransferSimulator.transferFromAsync(
|
await exchangeTransferSimulator.transferFromAsync(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
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 senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
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);
|
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
||||||
|
|
||||||
export class FillScenarios {
|
export class FillScenarios {
|
||||||
private zeroEx: ZeroEx;
|
private _zeroEx: ZeroEx;
|
||||||
private userAddresses: string[];
|
private _userAddresses: string[];
|
||||||
private tokens: Token[];
|
private _tokens: Token[];
|
||||||
private coinbase: string;
|
private _coinbase: string;
|
||||||
private zrxTokenAddress: string;
|
private _zrxTokenAddress: string;
|
||||||
private exchangeContractAddress: string;
|
private _exchangeContractAddress: string;
|
||||||
constructor(zeroEx: ZeroEx, userAddresses: string[],
|
constructor(zeroEx: ZeroEx, userAddresses: string[],
|
||||||
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
|
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
|
||||||
this.zeroEx = zeroEx;
|
this._zeroEx = zeroEx;
|
||||||
this.userAddresses = userAddresses;
|
this._userAddresses = userAddresses;
|
||||||
this.tokens = tokens;
|
this._tokens = tokens;
|
||||||
this.coinbase = userAddresses[0];
|
this._coinbase = userAddresses[0];
|
||||||
this.zrxTokenAddress = zrxTokenAddress;
|
this._zrxTokenAddress = zrxTokenAddress;
|
||||||
this.exchangeContractAddress = exchangeContractAddress;
|
this._exchangeContractAddress = exchangeContractAddress;
|
||||||
}
|
}
|
||||||
public async initTokenBalancesAsync() {
|
public async initTokenBalancesAsync() {
|
||||||
const web3Wrapper = (this.zeroEx as any)._web3Wrapper as Web3Wrapper;
|
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
|
||||||
for (const token of this.tokens) {
|
for (const token of this._tokens) {
|
||||||
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
||||||
const contractInstance = web3Wrapper.getContractInstance(
|
const contractInstance = web3Wrapper.getContractInstance(
|
||||||
artifacts.DummyTokenArtifact.abi, token.address,
|
artifacts.DummyTokenArtifact.abi, token.address,
|
||||||
@@ -36,10 +36,10 @@ export class FillScenarios {
|
|||||||
const defaults = {};
|
const defaults = {};
|
||||||
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
||||||
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
|
||||||
const txHash = await dummyToken.setBalance.sendTransactionAsync(this.coinbase, tokenSupply, {
|
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
||||||
from: this.coinbase,
|
from: this._coinbase,
|
||||||
});
|
});
|
||||||
await this.zeroEx.awaitTransactionMinedAsync(txHash);
|
await this._zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ export class FillScenarios {
|
|||||||
fillableAmount: BigNumber,
|
fillableAmount: BigNumber,
|
||||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
|
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
|
||||||
): Promise<SignedOrder> {
|
): Promise<SignedOrder> {
|
||||||
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
|
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||||
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
|
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
@@ -72,7 +72,7 @@ export class FillScenarios {
|
|||||||
const makerFee = new BigNumber(0);
|
const makerFee = new BigNumber(0);
|
||||||
const takerFee = new BigNumber(0);
|
const takerFee = new BigNumber(0);
|
||||||
const feeRecepient = constants.NULL_ADDRESS;
|
const feeRecepient = constants.NULL_ADDRESS;
|
||||||
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
|
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||||
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
|
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
@@ -80,18 +80,18 @@ export class FillScenarios {
|
|||||||
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
||||||
takerAddress: string, fillableAmount: BigNumber,
|
takerAddress: string, fillableAmount: BigNumber,
|
||||||
partialFillAmount: BigNumber) {
|
partialFillAmount: BigNumber) {
|
||||||
const [makerAddress] = this.userAddresses;
|
const [makerAddress] = this._userAddresses;
|
||||||
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||||
fillableAmount, fillableAmount,
|
fillableAmount, fillableAmount,
|
||||||
);
|
);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||||
await this.zeroEx.exchange.fillOrderAsync(
|
await this._zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||||
);
|
);
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
}
|
}
|
||||||
private async createAsymmetricFillableSignedOrderWithFeesAsync(
|
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string,
|
makerTokenAddress: string, takerTokenAddress: string,
|
||||||
makerFee: BigNumber, takerFee: BigNumber,
|
makerFee: BigNumber, takerFee: BigNumber,
|
||||||
makerAddress: string, takerAddress: string,
|
makerAddress: string, takerAddress: string,
|
||||||
@@ -99,39 +99,39 @@ export class FillScenarios {
|
|||||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||||
this.increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||||
]);
|
]);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, makerAddress, makerFee),
|
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
|
||||||
this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, takerAddress, takerFee),
|
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const signedOrder = await orderFactory.createSignedOrderAsync(this.zeroEx,
|
const signedOrder = await orderFactory.createSignedOrderAsync(this._zeroEx,
|
||||||
makerAddress, takerAddress, makerFee, takerFee,
|
makerAddress, takerAddress, makerFee, takerFee,
|
||||||
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
|
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
|
||||||
this.exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
this._exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
}
|
}
|
||||||
private async increaseBalanceAndAllowanceAsync(
|
private async _increaseBalanceAndAllowanceAsync(
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||||
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.increaseBalanceAsync(tokenAddress, address, amount),
|
this._increaseBalanceAsync(tokenAddress, address, amount),
|
||||||
this.increaseAllowanceAsync(tokenAddress, address, amount),
|
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
private async increaseBalanceAsync(
|
private async _increaseBalanceAsync(
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
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> {
|
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);
|
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
||||||
await this.zeroEx.token.setProxyAllowanceAsync(
|
await this._zeroEx.token.setProxyAllowanceAsync(
|
||||||
tokenAddress, address, newMakerAllowance,
|
tokenAddress, address, newMakerAllowance,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -9,16 +9,16 @@ import {JSONRPCPayload} from '../../../src/types';
|
|||||||
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||||
*/
|
*/
|
||||||
export class FakeGasEstimateSubprovider {
|
export class FakeGasEstimateSubprovider {
|
||||||
private constantGasAmount: number;
|
private _constantGasAmount: number;
|
||||||
constructor(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.
|
// 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
|
// tslint:disable-next-line:prefer-function-over-method
|
||||||
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
|
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
|
||||||
switch (payload.method) {
|
switch (payload.method) {
|
||||||
case 'eth_estimateGas':
|
case 'eth_estimateGas':
|
||||||
end(null, this.constantGasAmount);
|
end(null, this._constantGasAmount);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@@ -6,26 +6,26 @@ const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
|||||||
const WETH_TOKEN_SYMBOL = 'WETH';
|
const WETH_TOKEN_SYMBOL = 'WETH';
|
||||||
|
|
||||||
export class TokenUtils {
|
export class TokenUtils {
|
||||||
private tokens: Token[];
|
private _tokens: Token[];
|
||||||
constructor(tokens: Token[]) {
|
constructor(tokens: Token[]) {
|
||||||
this.tokens = tokens;
|
this._tokens = tokens;
|
||||||
}
|
}
|
||||||
public getProtocolTokenOrThrow(): Token {
|
public getProtocolTokenOrThrow(): Token {
|
||||||
const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
const zrxToken = _.find(this._tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
||||||
if (_.isUndefined(zrxToken)) {
|
if (_.isUndefined(zrxToken)) {
|
||||||
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
||||||
}
|
}
|
||||||
return zrxToken;
|
return zrxToken;
|
||||||
}
|
}
|
||||||
public getWethTokenOrThrow(): Token {
|
public getWethTokenOrThrow(): Token {
|
||||||
const wethToken = _.find(this.tokens, {symbol: WETH_TOKEN_SYMBOL});
|
const wethToken = _.find(this._tokens, {symbol: WETH_TOKEN_SYMBOL});
|
||||||
if (_.isUndefined(wethToken)) {
|
if (_.isUndefined(wethToken)) {
|
||||||
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
||||||
}
|
}
|
||||||
return wethToken;
|
return wethToken;
|
||||||
}
|
}
|
||||||
public getDummyTokens(): Token[] {
|
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 !_.includes([PROTOCOL_TOKEN_SYMBOL, WETH_TOKEN_SYMBOL], token.symbol);
|
||||||
});
|
});
|
||||||
return dummyTokens;
|
return dummyTokens;
|
||||||
|
@@ -31,7 +31,7 @@ BigNumber.config({
|
|||||||
* that implement the standard relayer API v0
|
* that implement the standard relayer API v0
|
||||||
*/
|
*/
|
||||||
export class HttpClient implements Client {
|
export class HttpClient implements Client {
|
||||||
private apiEndpointUrl: string;
|
private _apiEndpointUrl: string;
|
||||||
/**
|
/**
|
||||||
* Instantiates a new HttpClient instance
|
* Instantiates a new HttpClient instance
|
||||||
* @param url The relayer API base HTTP url you would like to interact with
|
* @param url The relayer API base HTTP url you would like to interact with
|
||||||
@@ -39,7 +39,7 @@ export class HttpClient implements Client {
|
|||||||
*/
|
*/
|
||||||
constructor(url: string) {
|
constructor(url: string) {
|
||||||
assert.isHttpUrl('url', url);
|
assert.isHttpUrl('url', url);
|
||||||
this.apiEndpointUrl = url;
|
this._apiEndpointUrl = url;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Retrieve token pair info from the API
|
* Retrieve token pair info from the API
|
||||||
@@ -152,7 +152,7 @@ export class HttpClient implements Client {
|
|||||||
const stringifiedParams = queryString.stringify(params);
|
const stringifiedParams = queryString.stringify(params);
|
||||||
query = `?${stringifiedParams}`;
|
query = `?${stringifiedParams}`;
|
||||||
}
|
}
|
||||||
const url = `${this.apiEndpointUrl}/v0${path}${query}`;
|
const url = `${this._apiEndpointUrl}/v0${path}${query}`;
|
||||||
const headers = new Headers({
|
const headers = new Headers({
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
});
|
});
|
||||||
|
@@ -18,10 +18,10 @@ import {orderbookChannelMessageParsers} from './utils/orderbook_channel_message_
|
|||||||
* that implements the standard relayer API v0
|
* that implements the standard relayer API v0
|
||||||
*/
|
*/
|
||||||
export class WebSocketOrderbookChannel implements OrderbookChannel {
|
export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||||
private apiEndpointUrl: string;
|
private _apiEndpointUrl: string;
|
||||||
private client: WebSocket.client;
|
private _client: WebSocket.client;
|
||||||
private connectionIfExists?: WebSocket.connection;
|
private _connectionIfExists?: WebSocket.connection;
|
||||||
private subscriptionCounter = 0;
|
private _subscriptionCounter = 0;
|
||||||
/**
|
/**
|
||||||
* Instantiates a new WebSocketOrderbookChannel instance
|
* Instantiates a new WebSocketOrderbookChannel instance
|
||||||
* @param url The relayer API base WS url you would like to interact with
|
* @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) {
|
constructor(url: string) {
|
||||||
assert.isUri('url', url);
|
assert.isUri('url', url);
|
||||||
this.apiEndpointUrl = url;
|
this._apiEndpointUrl = url;
|
||||||
this.client = new WebSocket.client();
|
this._client = new WebSocket.client();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Subscribe to orderbook snapshots and updates from the websocket
|
* 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.onUpdate', _.get(handler, 'onUpdate'));
|
||||||
assert.isFunction('handler.onError', _.get(handler, 'onError'));
|
assert.isFunction('handler.onError', _.get(handler, 'onError'));
|
||||||
assert.isFunction('handler.onClose', _.get(handler, 'onClose'));
|
assert.isFunction('handler.onClose', _.get(handler, 'onClose'));
|
||||||
this.subscriptionCounter += 1;
|
this._subscriptionCounter += 1;
|
||||||
const subscribeMessage = {
|
const subscribeMessage = {
|
||||||
type: 'subscribe',
|
type: 'subscribe',
|
||||||
channel: 'orderbook',
|
channel: 'orderbook',
|
||||||
requestId: this.subscriptionCounter,
|
requestId: this._subscriptionCounter,
|
||||||
payload: subscriptionOpts,
|
payload: subscriptionOpts,
|
||||||
};
|
};
|
||||||
this._getConnection((error, connection) => {
|
this._getConnection((error, connection) => {
|
||||||
@@ -74,22 +74,22 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
|||||||
* Close the websocket and stop receiving updates
|
* Close the websocket and stop receiving updates
|
||||||
*/
|
*/
|
||||||
public close() {
|
public close() {
|
||||||
if (!_.isUndefined(this.connectionIfExists)) {
|
if (!_.isUndefined(this._connectionIfExists)) {
|
||||||
this.connectionIfExists.close();
|
this._connectionIfExists.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void) {
|
private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void) {
|
||||||
if (!_.isUndefined(this.connectionIfExists) && this.connectionIfExists.connected) {
|
if (!_.isUndefined(this._connectionIfExists) && this._connectionIfExists.connected) {
|
||||||
callback(undefined, this.connectionIfExists);
|
callback(undefined, this._connectionIfExists);
|
||||||
} else {
|
} else {
|
||||||
this.client.on(WebsocketClientEventType.Connect, connection => {
|
this._client.on(WebsocketClientEventType.Connect, connection => {
|
||||||
this.connectionIfExists = connection;
|
this._connectionIfExists = connection;
|
||||||
callback(undefined, this.connectionIfExists);
|
callback(undefined, this._connectionIfExists);
|
||||||
});
|
});
|
||||||
this.client.on(WebsocketClientEventType.ConnectFailed, error => {
|
this._client.on(WebsocketClientEventType.ConnectFailed, error => {
|
||||||
callback(error, undefined);
|
callback(error, undefined);
|
||||||
});
|
});
|
||||||
this.client.connect(this.apiEndpointUrl);
|
this._client.connect(this._apiEndpointUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||||
|
@@ -19,18 +19,18 @@ import {utils} from './utils/utils';
|
|||||||
const SOLIDITY_FILE_EXTENSION = '.sol';
|
const SOLIDITY_FILE_EXTENSION = '.sol';
|
||||||
|
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
private contractsDir: string;
|
private _contractsDir: string;
|
||||||
private networkId: number;
|
private _networkId: number;
|
||||||
private optimizerEnabled: number;
|
private _optimizerEnabled: number;
|
||||||
private artifactsDir: string;
|
private _artifactsDir: string;
|
||||||
private contractSourcesIfExists?: ContractSources;
|
private _contractSourcesIfExists?: ContractSources;
|
||||||
private solcErrors: Set<string>;
|
private _solcErrors: Set<string>;
|
||||||
/**
|
/**
|
||||||
* Recursively retrieves Solidity source code from directory.
|
* Recursively retrieves Solidity source code from directory.
|
||||||
* @param dirPath Directory to search.
|
* @param dirPath Directory to search.
|
||||||
* @return Mapping of contract name to contract source.
|
* @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[] = [];
|
let dirContents: string[] = [];
|
||||||
try {
|
try {
|
||||||
dirContents = await fsWrapper.readdirAsync(dirPath);
|
dirContents = await fsWrapper.readdirAsync(dirPath);
|
||||||
@@ -52,7 +52,7 @@ export class Compiler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const nestedSources = await Compiler.getContractSourcesAsync(contentPath);
|
const nestedSources = await Compiler._getContractSourcesAsync(contentPath);
|
||||||
sources = {
|
sources = {
|
||||||
...sources,
|
...sources,
|
||||||
...nestedSources,
|
...nestedSources,
|
||||||
@@ -69,7 +69,7 @@ export class Compiler {
|
|||||||
* @param source Source code of contract.
|
* @param source Source code of contract.
|
||||||
* @return Solc compiler version.
|
* @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})/);
|
const solcVersionMatch = source.match(/(?:solidity\s\^?)([0-9]{1,2}[.][0-9]{1,2}[.][0-9]{1,2})/);
|
||||||
if (_.isNull(solcVersionMatch)) {
|
if (_.isNull(solcVersionMatch)) {
|
||||||
throw new Error('Could not find Solidity version in source');
|
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.
|
* @param errMsg An error message from the compiled output.
|
||||||
* @return The error message with directories truncated from the contract path.
|
* @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)/);
|
const errPathMatch = errMsg.match(/(.*\.sol)/);
|
||||||
if (_.isNull(errPathMatch)) {
|
if (_.isNull(errPathMatch)) {
|
||||||
throw new Error('Could not find a path in error message');
|
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.
|
* @return An instance of the Compiler class.
|
||||||
*/
|
*/
|
||||||
constructor(opts: CompilerOptions) {
|
constructor(opts: CompilerOptions) {
|
||||||
this.contractsDir = opts.contractsDir;
|
this._contractsDir = opts.contractsDir;
|
||||||
this.networkId = opts.networkId;
|
this._networkId = opts.networkId;
|
||||||
this.optimizerEnabled = opts.optimizerEnabled;
|
this._optimizerEnabled = opts.optimizerEnabled;
|
||||||
this.artifactsDir = opts.artifactsDir;
|
this._artifactsDir = opts.artifactsDir;
|
||||||
this.solcErrors = new Set();
|
this._solcErrors = new Set();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Compiles all Solidity files found in contractsDir and writes JSON artifacts to artifactsDir.
|
* Compiles all Solidity files found in contractsDir and writes JSON artifacts to artifactsDir.
|
||||||
*/
|
*/
|
||||||
public async compileAllAsync(): Promise<void> {
|
public async compileAllAsync(): Promise<void> {
|
||||||
await this.createArtifactsDirIfDoesNotExistAsync();
|
await this._createArtifactsDirIfDoesNotExistAsync();
|
||||||
this.contractSourcesIfExists = await Compiler.getContractSourcesAsync(this.contractsDir);
|
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> => {
|
const compiledContractPromises = _.map(contractBaseNames, async (contractBaseName: string): Promise<void> => {
|
||||||
return this.compileContractAsync(contractBaseName);
|
return this._compileContractAsync(contractBaseName);
|
||||||
});
|
});
|
||||||
await Promise.all(compiledContractPromises);
|
await Promise.all(compiledContractPromises);
|
||||||
|
|
||||||
this.solcErrors.forEach(errMsg => {
|
this._solcErrors.forEach(errMsg => {
|
||||||
utils.consoleLog(errMsg);
|
utils.consoleLog(errMsg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -128,14 +128,14 @@ export class Compiler {
|
|||||||
* Compiles contract and saves artifact to artifactsDir.
|
* Compiles contract and saves artifact to artifactsDir.
|
||||||
* @param contractBaseName Name of contract with '.sol' extension.
|
* @param contractBaseName Name of contract with '.sol' extension.
|
||||||
*/
|
*/
|
||||||
private async compileContractAsync(contractBaseName: string): Promise<void> {
|
private async _compileContractAsync(contractBaseName: string): Promise<void> {
|
||||||
if (_.isUndefined(this.contractSourcesIfExists)) {
|
if (_.isUndefined(this._contractSourcesIfExists)) {
|
||||||
throw new Error('Contract sources not yet initialized');
|
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 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')}`;
|
const sourceHash = `0x${ethUtil.sha3(source).toString('hex')}`;
|
||||||
|
|
||||||
let currentArtifactString: string;
|
let currentArtifactString: string;
|
||||||
@@ -149,10 +149,10 @@ export class Compiler {
|
|||||||
currentArtifactString = await fsWrapper.readFileAsync(currentArtifactPath, opts);
|
currentArtifactString = await fsWrapper.readFileAsync(currentArtifactPath, opts);
|
||||||
currentArtifact = JSON.parse(currentArtifactString);
|
currentArtifact = JSON.parse(currentArtifactString);
|
||||||
oldNetworks = currentArtifact.networks;
|
oldNetworks = currentArtifact.networks;
|
||||||
const oldNetwork: ContractData = oldNetworks[this.networkId];
|
const oldNetwork: ContractData = oldNetworks[this._networkId];
|
||||||
shouldCompile = _.isUndefined(oldNetwork) ||
|
shouldCompile = _.isUndefined(oldNetwork) ||
|
||||||
oldNetwork.keccak256 !== sourceHash ||
|
oldNetwork.keccak256 !== sourceHash ||
|
||||||
oldNetwork.optimizer_enabled !== this.optimizerEnabled;
|
oldNetwork.optimizer_enabled !== this._optimizerEnabled;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
shouldCompile = true;
|
shouldCompile = true;
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ export class Compiler {
|
|||||||
const input = {
|
const input = {
|
||||||
[contractBaseName]: source,
|
[contractBaseName]: source,
|
||||||
};
|
};
|
||||||
const solcVersion = Compiler.parseSolidityVersion(source);
|
const solcVersion = Compiler._parseSolidityVersion(source);
|
||||||
const fullSolcVersion = binPaths[solcVersion];
|
const fullSolcVersion = binPaths[solcVersion];
|
||||||
const solcBinPath = `./../solc/solc_bin/${fullSolcVersion}`;
|
const solcBinPath = `./../solc/solc_bin/${fullSolcVersion}`;
|
||||||
const solcBin = require(solcBinPath);
|
const solcBin = require(solcBinPath);
|
||||||
@@ -175,13 +175,13 @@ export class Compiler {
|
|||||||
sources: input,
|
sources: input,
|
||||||
};
|
};
|
||||||
const compiled = solcInstance.compile(sourcesToCompile,
|
const compiled = solcInstance.compile(sourcesToCompile,
|
||||||
this.optimizerEnabled,
|
this._optimizerEnabled,
|
||||||
this.findImportsIfSourcesExist.bind(this));
|
this._findImportsIfSourcesExist.bind(this));
|
||||||
|
|
||||||
if (!_.isUndefined(compiled.errors)) {
|
if (!_.isUndefined(compiled.errors)) {
|
||||||
_.each(compiled.errors, errMsg => {
|
_.each(compiled.errors, errMsg => {
|
||||||
const normalizedErrMsg = Compiler.getNormalizedErrMsg(errMsg);
|
const normalizedErrMsg = Compiler._getNormalizedErrMsg(errMsg);
|
||||||
this.solcErrors.add(normalizedErrMsg);
|
this._solcErrors.add(normalizedErrMsg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ export class Compiler {
|
|||||||
const contractData: ContractData = {
|
const contractData: ContractData = {
|
||||||
solc_version: solcVersion,
|
solc_version: solcVersion,
|
||||||
keccak256: sourceHash,
|
keccak256: sourceHash,
|
||||||
optimizer_enabled: this.optimizerEnabled,
|
optimizer_enabled: this._optimizerEnabled,
|
||||||
abi,
|
abi,
|
||||||
unlinked_binary,
|
unlinked_binary,
|
||||||
updated_at,
|
updated_at,
|
||||||
@@ -204,14 +204,14 @@ export class Compiler {
|
|||||||
...currentArtifact,
|
...currentArtifact,
|
||||||
networks: {
|
networks: {
|
||||||
...oldNetworks,
|
...oldNetworks,
|
||||||
[this.networkId]: contractData,
|
[this._networkId]: contractData,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
newArtifact = {
|
newArtifact = {
|
||||||
contract_name: contractName,
|
contract_name: contractName,
|
||||||
networks: {
|
networks: {
|
||||||
[this.networkId]: contractData,
|
[this._networkId]: contractData,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -226,12 +226,12 @@ export class Compiler {
|
|||||||
* @param importPath Path to an imported dependency.
|
* @param importPath Path to an imported dependency.
|
||||||
* @return Import contents object containing source code of dependency.
|
* @return Import contents object containing source code of dependency.
|
||||||
*/
|
*/
|
||||||
private findImportsIfSourcesExist(importPath: string): ImportContents {
|
private _findImportsIfSourcesExist(importPath: string): ImportContents {
|
||||||
if (_.isUndefined(this.contractSourcesIfExists)) {
|
if (_.isUndefined(this._contractSourcesIfExists)) {
|
||||||
throw new Error('Contract sources not yet initialized');
|
throw new Error('Contract sources not yet initialized');
|
||||||
}
|
}
|
||||||
const contractBaseName = path.basename(importPath);
|
const contractBaseName = path.basename(importPath);
|
||||||
const source = this.contractSourcesIfExists[contractBaseName];
|
const source = this._contractSourcesIfExists[contractBaseName];
|
||||||
const importContents: ImportContents = {
|
const importContents: ImportContents = {
|
||||||
contents: source,
|
contents: source,
|
||||||
};
|
};
|
||||||
@@ -240,10 +240,10 @@ export class Compiler {
|
|||||||
/**
|
/**
|
||||||
* Creates the artifacts directory if it does not already exist.
|
* Creates the artifacts directory if it does not already exist.
|
||||||
*/
|
*/
|
||||||
private async createArtifactsDirIfDoesNotExistAsync(): Promise<void> {
|
private async _createArtifactsDirIfDoesNotExistAsync(): Promise<void> {
|
||||||
if (!fsWrapper.doesPathExistSync(this.artifactsDir)) {
|
if (!fsWrapper.doesPathExistSync(this._artifactsDir)) {
|
||||||
utils.consoleLog('Creating artifacts directory...');
|
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 {
|
export class Deployer {
|
||||||
public web3Wrapper: Web3Wrapper;
|
public web3Wrapper: Web3Wrapper;
|
||||||
private artifactsDir: string;
|
private _artifactsDir: string;
|
||||||
private jsonrpcPort: number;
|
private _jsonrpcPort: number;
|
||||||
private networkId: number;
|
private _networkId: number;
|
||||||
private defaults: Partial<TxData>;
|
private _defaults: Partial<TxData>;
|
||||||
|
|
||||||
constructor(opts: DeployerOptions) {
|
constructor(opts: DeployerOptions) {
|
||||||
this.artifactsDir = opts.artifactsDir;
|
this._artifactsDir = opts.artifactsDir;
|
||||||
this.jsonrpcPort = opts.jsonrpcPort;
|
this._jsonrpcPort = opts.jsonrpcPort;
|
||||||
this.networkId = opts.networkId;
|
this._networkId = opts.networkId;
|
||||||
const jsonrpcUrl = `http://localhost:${this.jsonrpcPort}`;
|
const jsonrpcUrl = `http://localhost:${this._jsonrpcPort}`;
|
||||||
const web3Provider = new Web3.providers.HttpProvider(jsonrpcUrl);
|
const web3Provider = new Web3.providers.HttpProvider(jsonrpcUrl);
|
||||||
this.defaults = opts.defaults;
|
this._defaults = opts.defaults;
|
||||||
this.web3Wrapper = new Web3Wrapper(web3Provider, this.defaults);
|
this.web3Wrapper = new Web3Wrapper(web3Provider, this._defaults);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Loads contract artifact and deploys contract with given arguments.
|
* Loads contract artifact and deploys contract with given arguments.
|
||||||
@@ -39,21 +39,21 @@ export class Deployer {
|
|||||||
* @return Deployed contract instance.
|
* @return Deployed contract instance.
|
||||||
*/
|
*/
|
||||||
public async deployAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
|
public async deployAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
|
||||||
const contractArtifact: ContractArtifact = this.loadContractArtifactIfExists(contractName);
|
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
|
||||||
const contractData: ContractData = this.getContractDataFromArtifactIfExists(contractArtifact);
|
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
|
||||||
const data = contractData.unlinked_binary;
|
const data = contractData.unlinked_binary;
|
||||||
const from = await this.getFromAddressAsync();
|
const from = await this._getFromAddressAsync();
|
||||||
const gas = await this.getAllowableGasEstimateAsync(data);
|
const gas = await this._getAllowableGasEstimateAsync(data);
|
||||||
const txData = {
|
const txData = {
|
||||||
gasPrice: this.defaults.gasPrice,
|
gasPrice: this._defaults.gasPrice,
|
||||||
from,
|
from,
|
||||||
data,
|
data,
|
||||||
gas,
|
gas,
|
||||||
};
|
};
|
||||||
const abi = contractData.abi;
|
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}`);
|
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;
|
return contractInstance;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +64,7 @@ export class Deployer {
|
|||||||
*/
|
*/
|
||||||
public async deployAndSaveAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
|
public async deployAndSaveAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
|
||||||
const contractInstance = await this.deployAsync(contractName, args);
|
const contractInstance = await this.deployAsync(contractName, args);
|
||||||
await this.saveContractDataToArtifactAsync(contractName, contractInstance.address, args);
|
await this._saveContractDataToArtifactAsync(contractName, contractInstance.address, args);
|
||||||
return contractInstance;
|
return contractInstance;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +74,7 @@ export class Deployer {
|
|||||||
* @param txData Tx options used for deployment.
|
* @param txData Tx options used for deployment.
|
||||||
* @return Promise that resolves to a web3 contract instance.
|
* @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 contract: Web3.Contract<Web3.ContractInstance> = this.web3Wrapper.getContractFromAbi(abi);
|
||||||
const deployPromise = new Promise((resolve, reject) => {
|
const deployPromise = new Promise((resolve, reject) => {
|
||||||
/**
|
/**
|
||||||
@@ -99,10 +99,10 @@ export class Deployer {
|
|||||||
* @param contractAddress Contract address to save to artifact.
|
* @param contractAddress Contract address to save to artifact.
|
||||||
* @param args Contract constructor arguments that will be encoded and saved to artifact.
|
* @param args Contract constructor arguments that will be encoded and saved to artifact.
|
||||||
*/
|
*/
|
||||||
private async saveContractDataToArtifactAsync(contractName: string,
|
private async _saveContractDataToArtifactAsync(contractName: string,
|
||||||
contractAddress: string, args: any[]): Promise<void> {
|
contractAddress: string, args: any[]): Promise<void> {
|
||||||
const contractArtifact: ContractArtifact = this.loadContractArtifactIfExists(contractName);
|
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
|
||||||
const contractData: ContractData = this.getContractDataFromArtifactIfExists(contractArtifact);
|
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
|
||||||
const abi = contractData.abi;
|
const abi = contractData.abi;
|
||||||
const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi);
|
const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi);
|
||||||
const newContractData = {
|
const newContractData = {
|
||||||
@@ -114,11 +114,11 @@ export class Deployer {
|
|||||||
...contractArtifact,
|
...contractArtifact,
|
||||||
networks: {
|
networks: {
|
||||||
...contractArtifact.networks,
|
...contractArtifact.networks,
|
||||||
[this.networkId]: newContractData,
|
[this._networkId]: newContractData,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const artifactString = utils.stringifyWithFormatting(newArtifact);
|
const artifactString = utils.stringifyWithFormatting(newArtifact);
|
||||||
const artifactPath = `${this.artifactsDir}/${contractName}.json`;
|
const artifactPath = `${this._artifactsDir}/${contractName}.json`;
|
||||||
await fsWrapper.writeFileAsync(artifactPath, artifactString);
|
await fsWrapper.writeFileAsync(artifactPath, artifactString);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -126,8 +126,8 @@ export class Deployer {
|
|||||||
* @param contractName Name of the contract, without the extension.
|
* @param contractName Name of the contract, without the extension.
|
||||||
* @return The contract artifact.
|
* @return The contract artifact.
|
||||||
*/
|
*/
|
||||||
private loadContractArtifactIfExists(contractName: string): ContractArtifact {
|
private _loadContractArtifactIfExists(contractName: string): ContractArtifact {
|
||||||
const artifactPath = `${this.artifactsDir}/${contractName}.json`;
|
const artifactPath = `${this._artifactsDir}/${contractName}.json`;
|
||||||
try {
|
try {
|
||||||
const contractArtifact: ContractArtifact = require(artifactPath);
|
const contractArtifact: ContractArtifact = require(artifactPath);
|
||||||
return contractArtifact;
|
return contractArtifact;
|
||||||
@@ -140,8 +140,8 @@ export class Deployer {
|
|||||||
* @param contractArtifact The contract artifact.
|
* @param contractArtifact The contract artifact.
|
||||||
* @return Network specific contract data.
|
* @return Network specific contract data.
|
||||||
*/
|
*/
|
||||||
private getContractDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractData {
|
private _getContractDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractData {
|
||||||
const contractData = contractArtifact.networks[this.networkId];
|
const contractData = contractArtifact.networks[this._networkId];
|
||||||
if (_.isUndefined(contractData)) {
|
if (_.isUndefined(contractData)) {
|
||||||
throw new Error(`Data not found in artifact for contract: ${contractArtifact.contract_name}`);
|
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.
|
* Gets the address to use for sending a transaction.
|
||||||
* @return The default from address. If not specified, returns the first address accessible by web3.
|
* @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;
|
let from: string;
|
||||||
if (_.isUndefined(this.defaults.from)) {
|
if (_.isUndefined(this._defaults.from)) {
|
||||||
const accounts = await this.web3Wrapper.getAvailableAddressesAsync();
|
const accounts = await this.web3Wrapper.getAvailableAddressesAsync();
|
||||||
from = accounts[0];
|
from = accounts[0];
|
||||||
} else {
|
} else {
|
||||||
from = this.defaults.from;
|
from = this._defaults.from;
|
||||||
}
|
}
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ export class Deployer {
|
|||||||
* @param data Bytecode to estimate gas for.
|
* @param data Bytecode to estimate gas for.
|
||||||
* @return Gas estimate for transaction data.
|
* @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');
|
const block = await this.web3Wrapper.getBlockAsync('latest');
|
||||||
let gas: number;
|
let gas: number;
|
||||||
try {
|
try {
|
||||||
|
@@ -8,55 +8,55 @@ import {AbiType} from './types';
|
|||||||
export class Contract implements Web3.ContractInstance {
|
export class Contract implements Web3.ContractInstance {
|
||||||
public address: string;
|
public address: string;
|
||||||
public abi: Web3.ContractAbi;
|
public abi: Web3.ContractAbi;
|
||||||
private contract: Web3.ContractInstance;
|
private _contract: Web3.ContractInstance;
|
||||||
private defaults: Partial<Web3.TxData>;
|
private _defaults: Partial<Web3.TxData>;
|
||||||
private validator: SchemaValidator;
|
private _validator: SchemaValidator;
|
||||||
// This class instance is going to be populated with functions and events depending on the ABI
|
// 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
|
// and we don't know their types in advance
|
||||||
[name: string]: any;
|
[name: string]: any;
|
||||||
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<Web3.TxData>) {
|
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<Web3.TxData>) {
|
||||||
this.contract = web3ContractInstance;
|
this._contract = web3ContractInstance;
|
||||||
this.address = web3ContractInstance.address;
|
this.address = web3ContractInstance.address;
|
||||||
this.abi = web3ContractInstance.abi;
|
this.abi = web3ContractInstance.abi;
|
||||||
this.defaults = defaults;
|
this._defaults = defaults;
|
||||||
this.populateEvents();
|
this._populateEvents();
|
||||||
this.populateFunctions();
|
this._populateFunctions();
|
||||||
this.validator = new SchemaValidator();
|
this._validator = new SchemaValidator();
|
||||||
}
|
}
|
||||||
private populateFunctions(): void {
|
private _populateFunctions(): void {
|
||||||
const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function);
|
const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function);
|
||||||
_.forEach(functionsAbi, (functionAbi: Web3.MethodAbi) => {
|
_.forEach(functionsAbi, (functionAbi: Web3.MethodAbi) => {
|
||||||
if (functionAbi.constant) {
|
if (functionAbi.constant) {
|
||||||
const cbStyleCallFunction = this.contract[functionAbi.name].call;
|
const cbStyleCallFunction = this._contract[functionAbi.name].call;
|
||||||
this[functionAbi.name] = {
|
this[functionAbi.name] = {
|
||||||
callAsync: promisify(cbStyleCallFunction, this.contract),
|
callAsync: promisify(cbStyleCallFunction, this._contract),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const cbStyleFunction = this.contract[functionAbi.name];
|
const cbStyleFunction = this._contract[functionAbi.name];
|
||||||
const cbStyleEstimateGasFunction = this.contract[functionAbi.name].estimateGas;
|
const cbStyleEstimateGasFunction = this._contract[functionAbi.name].estimateGas;
|
||||||
this[functionAbi.name] = {
|
this[functionAbi.name] = {
|
||||||
estimateGasAsync: promisify(cbStyleEstimateGasFunction, this.contract),
|
estimateGasAsync: promisify(cbStyleEstimateGasFunction, this._contract),
|
||||||
sendTransactionAsync: this.promisifyWithDefaultParams(cbStyleFunction),
|
sendTransactionAsync: this._promisifyWithDefaultParams(cbStyleFunction),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private populateEvents(): void {
|
private _populateEvents(): void {
|
||||||
const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event);
|
const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event);
|
||||||
_.forEach(eventsAbi, (eventAbi: Web3.EventAbi) => {
|
_.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 promisifiedWithDefaultParams = async (...args: any[]) => {
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
const lastArg = args[args.length - 1];
|
const lastArg = args[args.length - 1];
|
||||||
let txData: Partial<Web3.TxData> = {};
|
let txData: Partial<Web3.TxData> = {};
|
||||||
if (this.isTxData(lastArg)) {
|
if (this._isTxData(lastArg)) {
|
||||||
txData = args.pop();
|
txData = args.pop();
|
||||||
}
|
}
|
||||||
txData = {
|
txData = {
|
||||||
...this.defaults,
|
...this._defaults,
|
||||||
...txData,
|
...txData,
|
||||||
};
|
};
|
||||||
const callback = (err: Error, data: any) => {
|
const callback = (err: Error, data: any) => {
|
||||||
@@ -68,14 +68,14 @@ export class Contract implements Web3.ContractInstance {
|
|||||||
};
|
};
|
||||||
args.push(txData);
|
args.push(txData);
|
||||||
args.push(callback);
|
args.push(callback);
|
||||||
fn.apply(this.contract, args);
|
fn.apply(this._contract, args);
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
};
|
};
|
||||||
return promisifiedWithDefaultParams;
|
return promisifiedWithDefaultParams;
|
||||||
}
|
}
|
||||||
private isTxData(lastArg: any): boolean {
|
private _isTxData(lastArg: any): boolean {
|
||||||
const isValid = this.validator.isValid(lastArg, schemas.txDataSchema);
|
const isValid = this._validator.isValid(lastArg, schemas.txDataSchema);
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,16 +7,16 @@ import {BalancesByOwner, ContractInstance} from './types';
|
|||||||
bigNumberConfigs.configure();
|
bigNumberConfigs.configure();
|
||||||
|
|
||||||
export class Balances {
|
export class Balances {
|
||||||
private tokenContractInstances: ContractInstance[];
|
private _tokenContractInstances: ContractInstance[];
|
||||||
private ownerAddresses: string[];
|
private _ownerAddresses: string[];
|
||||||
constructor(tokenContractInstances: ContractInstance[], ownerAddresses: string[]) {
|
constructor(tokenContractInstances: ContractInstance[], ownerAddresses: string[]) {
|
||||||
this.tokenContractInstances = tokenContractInstances;
|
this._tokenContractInstances = tokenContractInstances;
|
||||||
this.ownerAddresses = ownerAddresses;
|
this._ownerAddresses = ownerAddresses;
|
||||||
}
|
}
|
||||||
public async getAsync(): Promise<BalancesByOwner> {
|
public async getAsync(): Promise<BalancesByOwner> {
|
||||||
const balancesByOwner: BalancesByOwner = {};
|
const balancesByOwner: BalancesByOwner = {};
|
||||||
for (const tokenContractInstance of this.tokenContractInstances) {
|
for (const tokenContractInstance of this._tokenContractInstances) {
|
||||||
for (const ownerAddress of this.ownerAddresses) {
|
for (const ownerAddress of this._ownerAddresses) {
|
||||||
let balance = await tokenContractInstance.balanceOf(ownerAddress);
|
let balance = await tokenContractInstance.balanceOf(ownerAddress);
|
||||||
balance = new BigNumber(balance);
|
balance = new BigNumber(balance);
|
||||||
if (_.isUndefined(balancesByOwner[ownerAddress])) {
|
if (_.isUndefined(balancesByOwner[ownerAddress])) {
|
||||||
|
@@ -6,9 +6,9 @@ import {Order} from './order';
|
|||||||
import {ContractInstance} from './types';
|
import {ContractInstance} from './types';
|
||||||
|
|
||||||
export class ExchangeWrapper {
|
export class ExchangeWrapper {
|
||||||
private exchange: ContractInstance;
|
private _exchange: ContractInstance;
|
||||||
constructor(exchangeContractInstance: ContractInstance) {
|
constructor(exchangeContractInstance: ContractInstance) {
|
||||||
this.exchange = exchangeContractInstance;
|
this._exchange = exchangeContractInstance;
|
||||||
}
|
}
|
||||||
public async fillOrderAsync(order: Order, from: string,
|
public async fillOrderAsync(order: Order, from: string,
|
||||||
opts: {
|
opts: {
|
||||||
@@ -17,7 +17,7 @@ export class ExchangeWrapper {
|
|||||||
} = {}) {
|
} = {}) {
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
|
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
|
||||||
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
|
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
|
||||||
const tx = await this.exchange.fillOrder(
|
const tx = await this._exchange.fillOrder(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.fillTakerTokenAmount,
|
params.fillTakerTokenAmount,
|
||||||
@@ -33,7 +33,7 @@ export class ExchangeWrapper {
|
|||||||
public async cancelOrderAsync(order: Order, from: string,
|
public async cancelOrderAsync(order: Order, from: string,
|
||||||
opts: {cancelTakerTokenAmount?: BigNumber} = {}) {
|
opts: {cancelTakerTokenAmount?: BigNumber} = {}) {
|
||||||
const params = order.createCancel(opts.cancelTakerTokenAmount);
|
const params = order.createCancel(opts.cancelTakerTokenAmount);
|
||||||
const tx = await this.exchange.cancelOrder(
|
const tx = await this._exchange.cancelOrder(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.cancelTakerTokenAmount,
|
params.cancelTakerTokenAmount,
|
||||||
@@ -46,7 +46,7 @@ export class ExchangeWrapper {
|
|||||||
opts: {fillTakerTokenAmount?: BigNumber} = {}) {
|
opts: {fillTakerTokenAmount?: BigNumber} = {}) {
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
|
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount);
|
||||||
const tx = await this.exchange.fillOrKillOrder(
|
const tx = await this._exchange.fillOrKillOrder(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.fillTakerTokenAmount,
|
params.fillTakerTokenAmount,
|
||||||
@@ -66,7 +66,7 @@ export class ExchangeWrapper {
|
|||||||
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
|
const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance;
|
||||||
const params = formatters.createBatchFill(
|
const params = formatters.createBatchFill(
|
||||||
orders, shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmounts);
|
orders, shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmounts);
|
||||||
const tx = await this.exchange.batchFillOrders(
|
const tx = await this._exchange.batchFillOrders(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.fillTakerTokenAmounts,
|
params.fillTakerTokenAmounts,
|
||||||
@@ -82,7 +82,7 @@ export class ExchangeWrapper {
|
|||||||
public async batchFillOrKillOrdersAsync(orders: Order[], from: string,
|
public async batchFillOrKillOrdersAsync(orders: Order[], from: string,
|
||||||
opts: {fillTakerTokenAmounts?: BigNumber[]} = {}) {
|
opts: {fillTakerTokenAmounts?: BigNumber[]} = {}) {
|
||||||
const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts);
|
const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts);
|
||||||
const tx = await this.exchange.batchFillOrKillOrders(
|
const tx = await this._exchange.batchFillOrKillOrders(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.fillTakerTokenAmounts,
|
params.fillTakerTokenAmounts,
|
||||||
@@ -103,7 +103,7 @@ export class ExchangeWrapper {
|
|||||||
const params = formatters.createFillUpTo(orders,
|
const params = formatters.createFillUpTo(orders,
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
opts.fillTakerTokenAmount);
|
opts.fillTakerTokenAmount);
|
||||||
const tx = await this.exchange.fillOrdersUpTo(
|
const tx = await this._exchange.fillOrdersUpTo(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.fillTakerTokenAmount,
|
params.fillTakerTokenAmount,
|
||||||
@@ -119,7 +119,7 @@ export class ExchangeWrapper {
|
|||||||
public async batchCancelOrdersAsync(orders: Order[], from: string,
|
public async batchCancelOrdersAsync(orders: Order[], from: string,
|
||||||
opts: {cancelTakerTokenAmounts?: BigNumber[]} = {}) {
|
opts: {cancelTakerTokenAmounts?: BigNumber[]} = {}) {
|
||||||
const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts);
|
const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts);
|
||||||
const tx = await this.exchange.batchCancelOrders(
|
const tx = await this._exchange.batchCancelOrders(
|
||||||
params.orderAddresses,
|
params.orderAddresses,
|
||||||
params.orderValues,
|
params.orderValues,
|
||||||
params.cancelTakerTokenAmounts,
|
params.cancelTakerTokenAmounts,
|
||||||
@@ -131,11 +131,11 @@ export class ExchangeWrapper {
|
|||||||
public async getOrderHashAsync(order: Order): Promise<string> {
|
public async getOrderHashAsync(order: Order): Promise<string> {
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||||
const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance);
|
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;
|
return orderHash;
|
||||||
}
|
}
|
||||||
public async isValidSignatureAsync(order: Order): Promise<boolean> {
|
public async isValidSignatureAsync(order: Order): Promise<boolean> {
|
||||||
const isValidSignature = await this.exchange.isValidSignature(
|
const isValidSignature = await this._exchange.isValidSignature(
|
||||||
order.params.maker,
|
order.params.maker,
|
||||||
order.params.orderHashHex,
|
order.params.orderHashHex,
|
||||||
order.params.v,
|
order.params.v,
|
||||||
@@ -146,12 +146,12 @@ export class ExchangeWrapper {
|
|||||||
}
|
}
|
||||||
public async isRoundingErrorAsync(numerator: BigNumber, denominator: BigNumber,
|
public async isRoundingErrorAsync(numerator: BigNumber, denominator: BigNumber,
|
||||||
target: BigNumber): Promise<boolean> {
|
target: BigNumber): Promise<boolean> {
|
||||||
const isRoundingError = await this.exchange.isRoundingError(numerator, denominator, target);
|
const isRoundingError = await this._exchange.isRoundingError(numerator, denominator, target);
|
||||||
return isRoundingError;
|
return isRoundingError;
|
||||||
}
|
}
|
||||||
public async getPartialAmountAsync(numerator: BigNumber, denominator: BigNumber,
|
public async getPartialAmountAsync(numerator: BigNumber, denominator: BigNumber,
|
||||||
target: BigNumber): Promise<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;
|
return partialAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ import * as Web3 from 'web3';
|
|||||||
import {ContractInstance, TransactionDataParams} from './types';
|
import {ContractInstance, TransactionDataParams} from './types';
|
||||||
|
|
||||||
export class MultiSigWrapper {
|
export class MultiSigWrapper {
|
||||||
private multiSig: ContractInstance;
|
private _multiSig: ContractInstance;
|
||||||
public static encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) {
|
public static encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) {
|
||||||
const abiEntity = _.find(abi, {name}) as Web3.MethodAbi;
|
const abiEntity = _.find(abi, {name}) as Web3.MethodAbi;
|
||||||
if (_.isUndefined(abiEntity)) {
|
if (_.isUndefined(abiEntity)) {
|
||||||
@@ -22,13 +22,13 @@ export class MultiSigWrapper {
|
|||||||
return funcSig + argsData.join('');
|
return funcSig + argsData.join('');
|
||||||
}
|
}
|
||||||
constructor(multiSigContractInstance: ContractInstance) {
|
constructor(multiSigContractInstance: ContractInstance) {
|
||||||
this.multiSig = multiSigContractInstance;
|
this._multiSig = multiSigContractInstance;
|
||||||
}
|
}
|
||||||
public async submitTransactionAsync(destination: string, from: string,
|
public async submitTransactionAsync(destination: string, from: string,
|
||||||
dataParams: TransactionDataParams,
|
dataParams: TransactionDataParams,
|
||||||
value: number = 0) {
|
value: number = 0) {
|
||||||
const {name, abi, args = []} = dataParams;
|
const {name, abi, args = []} = dataParams;
|
||||||
const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args);
|
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)) {
|
if (_.isUndefined(v) || _.isUndefined(r) || _.isUndefined(s)) {
|
||||||
throw new Error('Cannot call isValidSignature on unsigned order');
|
throw new Error('Cannot call isValidSignature on unsigned order');
|
||||||
}
|
}
|
||||||
const orderHash = this.getOrderHash();
|
const orderHash = this._getOrderHash();
|
||||||
const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash));
|
const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash));
|
||||||
try {
|
try {
|
||||||
const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s));
|
const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s));
|
||||||
@@ -32,7 +32,7 @@ export class Order {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async signAsync() {
|
public async signAsync() {
|
||||||
const orderHash = this.getOrderHash();
|
const orderHash = this._getOrderHash();
|
||||||
const signature = await promisify<string>(web3.eth.sign)(this.params.maker, orderHash);
|
const signature = await promisify<string>(web3.eth.sign)(this.params.maker, orderHash);
|
||||||
const {v, r, s} = ethUtil.fromRpcSig(signature);
|
const {v, r, s} = ethUtil.fromRpcSig(signature);
|
||||||
this.params = _.assign(this.params, {
|
this.params = _.assign(this.params, {
|
||||||
@@ -88,7 +88,7 @@ export class Order {
|
|||||||
};
|
};
|
||||||
return cancel;
|
return cancel;
|
||||||
}
|
}
|
||||||
private getOrderHash(): string {
|
private _getOrderHash(): string {
|
||||||
const orderHash = crypto.solSHA3([
|
const orderHash = crypto.solSHA3([
|
||||||
this.params.exchangeContractAddress,
|
this.params.exchangeContractAddress,
|
||||||
this.params.maker,
|
this.params.maker,
|
||||||
|
@@ -6,9 +6,9 @@ import {Order} from './order';
|
|||||||
import {DefaultOrderParams, OptionalOrderParams, OrderParams} from './types';
|
import {DefaultOrderParams, OptionalOrderParams, OrderParams} from './types';
|
||||||
|
|
||||||
export class OrderFactory {
|
export class OrderFactory {
|
||||||
private defaultOrderParams: DefaultOrderParams;
|
private _defaultOrderParams: DefaultOrderParams;
|
||||||
constructor(defaultOrderParams: DefaultOrderParams) {
|
constructor(defaultOrderParams: DefaultOrderParams) {
|
||||||
this.defaultOrderParams = defaultOrderParams;
|
this._defaultOrderParams = defaultOrderParams;
|
||||||
}
|
}
|
||||||
public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) {
|
public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) {
|
||||||
const randomExpiration = new BigNumber(Math.floor((Date.now() + (Math.random() * 100000000000)) / 1000));
|
const randomExpiration = new BigNumber(Math.floor((Date.now() + (Math.random() * 100000000000)) / 1000));
|
||||||
@@ -16,7 +16,7 @@ export class OrderFactory {
|
|||||||
expirationTimestampInSec: randomExpiration,
|
expirationTimestampInSec: randomExpiration,
|
||||||
salt: ZeroEx.generatePseudoRandomSalt(),
|
salt: ZeroEx.generatePseudoRandomSalt(),
|
||||||
taker: ZeroEx.NULL_ADDRESS,
|
taker: ZeroEx.NULL_ADDRESS,
|
||||||
}, this.defaultOrderParams, customOrderParams);
|
}, this._defaultOrderParams, customOrderParams);
|
||||||
const order = new Order(orderParams);
|
const order = new Order(orderParams);
|
||||||
await order.signAsync();
|
await order.signAsync();
|
||||||
return order;
|
return order;
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
import {ContractInstance, Token} from './types';
|
import {ContractInstance, Token} from './types';
|
||||||
|
|
||||||
export class TokenRegWrapper {
|
export class TokenRegWrapper {
|
||||||
private tokenReg: ContractInstance;
|
private _tokenReg: ContractInstance;
|
||||||
constructor(tokenRegContractInstance: ContractInstance) {
|
constructor(tokenRegContractInstance: ContractInstance) {
|
||||||
this.tokenReg = tokenRegContractInstance;
|
this._tokenReg = tokenRegContractInstance;
|
||||||
}
|
}
|
||||||
public addTokenAsync(token: Token, from: string) {
|
public addTokenAsync(token: Token, from: string) {
|
||||||
const tx = this.tokenReg.addToken(
|
const tx = this._tokenReg.addToken(
|
||||||
token.address,
|
token.address,
|
||||||
token.name,
|
token.name,
|
||||||
token.symbol,
|
token.symbol,
|
||||||
@@ -18,7 +18,7 @@ export class TokenRegWrapper {
|
|||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
public async getTokenMetaDataAsync(tokenAddress: string) {
|
public async getTokenMetaDataAsync(tokenAddress: string) {
|
||||||
const data = await this.tokenReg.getTokenMetaData(tokenAddress);
|
const data = await this._tokenReg.getTokenMetaData(tokenAddress);
|
||||||
const token: Token = {
|
const token: Token = {
|
||||||
address: data[0],
|
address: data[0],
|
||||||
name: data[1],
|
name: data[1],
|
||||||
@@ -30,7 +30,7 @@ export class TokenRegWrapper {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public async getTokenByNameAsync(tokenName: string) {
|
public async getTokenByNameAsync(tokenName: string) {
|
||||||
const data = await this.tokenReg.getTokenByName(tokenName);
|
const data = await this._tokenReg.getTokenByName(tokenName);
|
||||||
const token: Token = {
|
const token: Token = {
|
||||||
address: data[0],
|
address: data[0],
|
||||||
name: data[1],
|
name: data[1],
|
||||||
@@ -42,7 +42,7 @@ export class TokenRegWrapper {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public async getTokenBySymbolAsync(tokenSymbol: string) {
|
public async getTokenBySymbolAsync(tokenSymbol: string) {
|
||||||
const data = await this.tokenReg.getTokenBySymbol(tokenSymbol);
|
const data = await this._tokenReg.getTokenBySymbol(tokenSymbol);
|
||||||
const token: Token = {
|
const token: Token = {
|
||||||
address: data[0],
|
address: data[0],
|
||||||
name: data[1],
|
name: data[1],
|
||||||
|
@@ -1,21 +1,21 @@
|
|||||||
import {RPC} from './rpc';
|
import {RPC} from './rpc';
|
||||||
|
|
||||||
export class BlockchainLifecycle {
|
export class BlockchainLifecycle {
|
||||||
private rpc: RPC;
|
private _rpc: RPC;
|
||||||
private snapshotIdsStack: number[];
|
private _snapshotIdsStack: number[];
|
||||||
constructor(url: string) {
|
constructor(url: string) {
|
||||||
this.rpc = new RPC(url);
|
this._rpc = new RPC(url);
|
||||||
this.snapshotIdsStack = [];
|
this._snapshotIdsStack = [];
|
||||||
}
|
}
|
||||||
// TODO: In order to run these tests on an actual node, we should check if we are running against
|
// 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
|
// TestRPC, if so, use snapshots, otherwise re-deploy contracts before every test
|
||||||
public async startAsync(): Promise<void> {
|
public async startAsync(): Promise<void> {
|
||||||
const snapshotId = await this.rpc.takeSnapshotAsync();
|
const snapshotId = await this._rpc.takeSnapshotAsync();
|
||||||
this.snapshotIdsStack.push(snapshotId);
|
this._snapshotIdsStack.push(snapshotId);
|
||||||
}
|
}
|
||||||
public async revertAsync(): Promise<void> {
|
public async revertAsync(): Promise<void> {
|
||||||
const snapshotId = this.snapshotIdsStack.pop() as number;
|
const snapshotId = this._snapshotIdsStack.pop() as number;
|
||||||
const didRevert = await this.rpc.revertSnapshotAsync(snapshotId);
|
const didRevert = await this._rpc.revertSnapshotAsync(snapshotId);
|
||||||
if (!didRevert) {
|
if (!didRevert) {
|
||||||
throw new Error(`Snapshot with id #${snapshotId} failed to revert`);
|
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';
|
import * as request from 'request-promise-native';
|
||||||
|
|
||||||
export class RPC {
|
export class RPC {
|
||||||
private url: string;
|
private _url: string;
|
||||||
private id: number;
|
private _id: number;
|
||||||
constructor(url: string) {
|
constructor(url: string) {
|
||||||
this.url = url;
|
this._url = url;
|
||||||
this.id = 0;
|
this._id = 0;
|
||||||
}
|
}
|
||||||
public async takeSnapshotAsync(): Promise<number> {
|
public async takeSnapshotAsync(): Promise<number> {
|
||||||
const method = 'evm_snapshot';
|
const method = 'evm_snapshot';
|
||||||
const params: any[] = [];
|
const params: any[] = [];
|
||||||
const payload = this.toPayload(method, params);
|
const payload = this._toPayload(method, params);
|
||||||
const snapshotIdHex = await this.sendAsync(payload);
|
const snapshotIdHex = await this._sendAsync(payload);
|
||||||
const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
|
const snapshotId = ethUtil.bufferToInt(ethUtil.toBuffer(snapshotIdHex));
|
||||||
return snapshotId;
|
return snapshotId;
|
||||||
}
|
}
|
||||||
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
|
public async revertSnapshotAsync(snapshotId: number): Promise<boolean> {
|
||||||
const method = 'evm_revert';
|
const method = 'evm_revert';
|
||||||
const params = [snapshotId];
|
const params = [snapshotId];
|
||||||
const payload = this.toPayload(method, params);
|
const payload = this._toPayload(method, params);
|
||||||
const didRevert = await this.sendAsync(payload);
|
const didRevert = await this._sendAsync(payload);
|
||||||
return didRevert;
|
return didRevert;
|
||||||
}
|
}
|
||||||
public async increaseTimeAsync(time: number) {
|
public async increaseTimeAsync(time: number) {
|
||||||
const method = 'evm_increaseTime';
|
const method = 'evm_increaseTime';
|
||||||
const params = [time];
|
const params = [time];
|
||||||
const payload = this.toPayload(method, params);
|
const payload = this._toPayload(method, params);
|
||||||
return this.sendAsync(payload);
|
return this._sendAsync(payload);
|
||||||
}
|
}
|
||||||
public async mineBlockAsync(): Promise<void> {
|
public async mineBlockAsync(): Promise<void> {
|
||||||
const method = 'evm_mine';
|
const method = 'evm_mine';
|
||||||
const params: any[] = [];
|
const params: any[] = [];
|
||||||
const payload = this.toPayload(method, params);
|
const payload = this._toPayload(method, params);
|
||||||
await this.sendAsync(payload);
|
await this._sendAsync(payload);
|
||||||
}
|
}
|
||||||
private toPayload(method: string, params: any[] = []): string {
|
private _toPayload(method: string, params: any[] = []): string {
|
||||||
const payload = JSON.stringify({
|
const payload = JSON.stringify({
|
||||||
id: this.id,
|
id: this._id,
|
||||||
method,
|
method,
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
this.id += 1;
|
this._url += 1;
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
private async sendAsync(payload: string): Promise<any> {
|
private async _sendAsync(payload: string): Promise<any> {
|
||||||
const opts = {
|
const opts = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
uri: this.url,
|
uri: this._url,
|
||||||
body: payload,
|
body: payload,
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
|
@@ -4,15 +4,15 @@ import values = require('lodash.values');
|
|||||||
import {schemas} from './schemas';
|
import {schemas} from './schemas';
|
||||||
|
|
||||||
export class SchemaValidator {
|
export class SchemaValidator {
|
||||||
private validator: Validator;
|
private _validator: Validator;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.validator = new Validator();
|
this._validator = new Validator();
|
||||||
for (const schema of values(schemas)) {
|
for (const schema of values(schemas)) {
|
||||||
this.validator.addSchema(schema, schema.id);
|
this._validator.addSchema(schema, schema.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public addSchema(schema: Schema) {
|
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
|
// 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
|
// 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.
|
// then parse it. The resultant object can then be checked using jsonschema.
|
||||||
public validate(instance: any, schema: Schema): ValidatorResult {
|
public validate(instance: any, schema: Schema): ValidatorResult {
|
||||||
const jsonSchemaCompatibleObject = JSON.parse(JSON.stringify(instance));
|
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 {
|
public isValid(instance: any, schema: Schema): boolean {
|
||||||
const isValid = this.validate(instance, schema).errors.length === 0;
|
const isValid = this.validate(instance, schema).errors.length === 0;
|
||||||
|
@@ -18,25 +18,25 @@ import {ZRXRequestQueue} from './zrx_request_queue';
|
|||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
export class Handler {
|
export class Handler {
|
||||||
private etherRequestQueue: EtherRequestQueue;
|
private _etherRequestQueue: EtherRequestQueue;
|
||||||
private zrxRequestQueue: ZRXRequestQueue;
|
private _zrxRequestQueue: ZRXRequestQueue;
|
||||||
private web3: Web3;
|
private _web3: Web3;
|
||||||
constructor() {
|
constructor() {
|
||||||
// Setup provider engine to talk with RPC node
|
// Setup provider engine to talk with RPC node
|
||||||
const providerObj = this.createProviderEngine(configs.RPC_URL);
|
const providerObj = this._createProviderEngine(configs.RPC_URL);
|
||||||
this.web3 = new Web3(providerObj);
|
this._web3 = new Web3(providerObj);
|
||||||
|
|
||||||
this.etherRequestQueue = new EtherRequestQueue(this.web3);
|
this._etherRequestQueue = new EtherRequestQueue(this._web3);
|
||||||
this.zrxRequestQueue = new ZRXRequestQueue(this.web3);
|
this._zrxRequestQueue = new ZRXRequestQueue(this._web3);
|
||||||
}
|
}
|
||||||
public dispenseEther(req: express.Request, res: express.Response) {
|
public dispenseEther(req: express.Request, res: express.Response) {
|
||||||
const recipientAddress = req.params.recipient;
|
const recipientAddress = req.params.recipient;
|
||||||
if (_.isUndefined(recipientAddress) || !this.isValidEthereumAddress(recipientAddress)) {
|
if (_.isUndefined(recipientAddress) || !this._isValidEthereumAddress(recipientAddress)) {
|
||||||
res.status(400).send('INVALID_REQUEST');
|
res.status(400).send('INVALID_REQUEST');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
||||||
const didAddToQueue = this.etherRequestQueue.add(lowerCaseRecipientAddress);
|
const didAddToQueue = this._etherRequestQueue.add(lowerCaseRecipientAddress);
|
||||||
if (!didAddToQueue) {
|
if (!didAddToQueue) {
|
||||||
res.status(503).send('QUEUE_IS_FULL');
|
res.status(503).send('QUEUE_IS_FULL');
|
||||||
return;
|
return;
|
||||||
@@ -46,12 +46,12 @@ export class Handler {
|
|||||||
}
|
}
|
||||||
public dispenseZRX(req: express.Request, res: express.Response) {
|
public dispenseZRX(req: express.Request, res: express.Response) {
|
||||||
const recipientAddress = req.params.recipient;
|
const recipientAddress = req.params.recipient;
|
||||||
if (_.isUndefined(recipientAddress) || !this.isValidEthereumAddress(recipientAddress)) {
|
if (_.isUndefined(recipientAddress) || !this._isValidEthereumAddress(recipientAddress)) {
|
||||||
res.status(400).send('INVALID_REQUEST');
|
res.status(400).send('INVALID_REQUEST');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
const lowerCaseRecipientAddress = recipientAddress.toLowerCase();
|
||||||
const didAddToQueue = this.zrxRequestQueue.add(lowerCaseRecipientAddress);
|
const didAddToQueue = this._zrxRequestQueue.add(lowerCaseRecipientAddress);
|
||||||
if (!didAddToQueue) {
|
if (!didAddToQueue) {
|
||||||
res.status(503).send('QUEUE_IS_FULL');
|
res.status(503).send('QUEUE_IS_FULL');
|
||||||
return;
|
return;
|
||||||
@@ -63,18 +63,18 @@ export class Handler {
|
|||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
const payload = JSON.stringify({
|
const payload = JSON.stringify({
|
||||||
ether: {
|
ether: {
|
||||||
full: this.etherRequestQueue.isFull(),
|
full: this._etherRequestQueue.isFull(),
|
||||||
size: this.etherRequestQueue.size(),
|
size: this._etherRequestQueue.size(),
|
||||||
},
|
},
|
||||||
zrx: {
|
zrx: {
|
||||||
full: this.zrxRequestQueue.isFull(),
|
full: this._zrxRequestQueue.isFull(),
|
||||||
size: this.zrxRequestQueue.size(),
|
size: this._zrxRequestQueue.size(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
}
|
}
|
||||||
// tslint:disable-next-line:prefer-function-over-method
|
// tslint:disable-next-line:prefer-function-over-method
|
||||||
private createProviderEngine(rpcUrl: string) {
|
private _createProviderEngine(rpcUrl: string) {
|
||||||
const engine = new ProviderEngine();
|
const engine = new ProviderEngine();
|
||||||
engine.addProvider(new NonceSubprovider());
|
engine.addProvider(new NonceSubprovider());
|
||||||
engine.addProvider(new HookedWalletSubprovider(idManagement));
|
engine.addProvider(new HookedWalletSubprovider(idManagement));
|
||||||
@@ -84,8 +84,8 @@ export class Handler {
|
|||||||
engine.start();
|
engine.start();
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
private isValidEthereumAddress(address: string): boolean {
|
private _isValidEthereumAddress(address: string): boolean {
|
||||||
const lowercaseAddress = address.toLowerCase();
|
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;
|
const QUEUE_INTERVAL_MS = 5000;
|
||||||
|
|
||||||
export class ZRXRequestQueue extends RequestQueue {
|
export class ZRXRequestQueue extends RequestQueue {
|
||||||
private zeroEx: ZeroEx;
|
private _zeroEx: ZeroEx;
|
||||||
constructor(web3: Web3) {
|
constructor(web3: Web3) {
|
||||||
super(web3);
|
super(web3);
|
||||||
this.queueIntervalMs = QUEUE_INTERVAL_MS;
|
this.queueIntervalMs = QUEUE_INTERVAL_MS;
|
||||||
const zeroExConfig = {
|
const zeroExConfig = {
|
||||||
networkId: configs.KOVAN_NETWORK_ID,
|
networkId: configs.KOVAN_NETWORK_ID,
|
||||||
};
|
};
|
||||||
this.zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
|
this._zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
|
||||||
}
|
}
|
||||||
protected async processNextRequestFireAndForgetAsync(recipientAddress: string) {
|
protected async processNextRequestFireAndForgetAsync(recipientAddress: string) {
|
||||||
utils.consoleLog(`Processing ZRX ${recipientAddress}`);
|
utils.consoleLog(`Processing ZRX ${recipientAddress}`);
|
||||||
const baseUnitAmount = ZeroEx.toBaseUnitAmount(DISPENSE_AMOUNT_ZRX, 18);
|
const baseUnitAmount = ZeroEx.toBaseUnitAmount(DISPENSE_AMOUNT_ZRX, 18);
|
||||||
try {
|
try {
|
||||||
await this.zeroEx.token.transferAsync(
|
await this._zeroEx.token.transferAsync(
|
||||||
configs.ZRX_TOKEN_ADDRESS, configs.DISPENSER_ADDRESS, recipientAddress, baseUnitAmount,
|
configs.ZRX_TOKEN_ADDRESS, configs.DISPENSER_ADDRESS, recipientAddress, baseUnitAmount,
|
||||||
);
|
);
|
||||||
utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ZRX} ZRX to ${recipientAddress}`);
|
utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ZRX} ZRX to ${recipientAddress}`);
|
||||||
|
@@ -9,29 +9,29 @@ import Web3ProviderEngine = require('web3-provider-engine');
|
|||||||
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||||
*/
|
*/
|
||||||
export class InjectedWeb3Subprovider {
|
export class InjectedWeb3Subprovider {
|
||||||
private injectedWeb3: Web3;
|
private _injectedWeb3: Web3;
|
||||||
constructor(injectedWeb3: Web3) {
|
constructor(injectedWeb3: Web3) {
|
||||||
this.injectedWeb3 = injectedWeb3;
|
this._injectedWeb3 = injectedWeb3;
|
||||||
}
|
}
|
||||||
public handleRequest(
|
public handleRequest(
|
||||||
payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result: any) => void,
|
payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result: any) => void,
|
||||||
) {
|
) {
|
||||||
switch (payload.method) {
|
switch (payload.method) {
|
||||||
case 'web3_clientVersion':
|
case 'web3_clientVersion':
|
||||||
this.injectedWeb3.version.getNode(end);
|
this._injectedWeb3.version.getNode(end);
|
||||||
return;
|
return;
|
||||||
case 'eth_accounts':
|
case 'eth_accounts':
|
||||||
this.injectedWeb3.eth.getAccounts(end);
|
this._injectedWeb3.eth.getAccounts(end);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'eth_sendTransaction':
|
case 'eth_sendTransaction':
|
||||||
const [txParams] = payload.params;
|
const [txParams] = payload.params;
|
||||||
this.injectedWeb3.eth.sendTransaction(txParams, end);
|
this._injectedWeb3.eth.sendTransaction(txParams, end);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'eth_sign':
|
case 'eth_sign':
|
||||||
const [address, message] = payload.params;
|
const [address, message] = payload.params;
|
||||||
this.injectedWeb3.eth.sign(address, message, end);
|
this._injectedWeb3.eth.sign(address, message, end);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@@ -32,7 +32,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
private _ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync;
|
private _ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync;
|
||||||
private _ledgerClientIfExists?: LedgerEthereumClient;
|
private _ledgerClientIfExists?: LedgerEthereumClient;
|
||||||
private _shouldAlwaysAskForConfirmation: boolean;
|
private _shouldAlwaysAskForConfirmation: boolean;
|
||||||
private static validateSender(sender: string) {
|
private static _validateSender(sender: string) {
|
||||||
if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) {
|
if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) {
|
||||||
throw new Error(LedgerSubproviderErrors.SenderInvalidOrNotSupplied);
|
throw new Error(LedgerSubproviderErrors.SenderInvalidOrNotSupplied);
|
||||||
}
|
}
|
||||||
@@ -88,8 +88,8 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
case 'eth_sendTransaction':
|
case 'eth_sendTransaction':
|
||||||
txParams = payload.params[0];
|
txParams = payload.params[0];
|
||||||
try {
|
try {
|
||||||
LedgerSubprovider.validateSender(txParams.from);
|
LedgerSubprovider._validateSender(txParams.from);
|
||||||
const result = await this.sendTransactionAsync(txParams);
|
const result = await this._sendTransactionAsync(txParams);
|
||||||
end(null, result);
|
end(null, result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
end(err);
|
end(err);
|
||||||
@@ -99,7 +99,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
case 'eth_signTransaction':
|
case 'eth_signTransaction':
|
||||||
txParams = payload.params[0];
|
txParams = payload.params[0];
|
||||||
try {
|
try {
|
||||||
const result = await this.signTransactionWithoutSendingAsync(txParams);
|
const result = await this._signTransactionWithoutSendingAsync(txParams);
|
||||||
end(null, result);
|
end(null, result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
end(err);
|
end(err);
|
||||||
@@ -126,7 +126,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async getAccountsAsync(): Promise<string[]> {
|
public async getAccountsAsync(): Promise<string[]> {
|
||||||
this._ledgerClientIfExists = await this.createLedgerClientAsync();
|
this._ledgerClientIfExists = await this._createLedgerClientAsync();
|
||||||
|
|
||||||
let ledgerResponse;
|
let ledgerResponse;
|
||||||
try {
|
try {
|
||||||
@@ -134,7 +134,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
this._derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE,
|
this._derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE,
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
await this.destoryLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
const hdKey = new HDNode();
|
const hdKey = new HDNode();
|
||||||
@@ -155,7 +155,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
return accounts;
|
return accounts;
|
||||||
}
|
}
|
||||||
public async signTransactionAsync(txParams: PartialTxParams): Promise<string> {
|
public async signTransactionAsync(txParams: PartialTxParams): Promise<string> {
|
||||||
this._ledgerClientIfExists = await this.createLedgerClientAsync();
|
this._ledgerClientIfExists = await this._createLedgerClientAsync();
|
||||||
|
|
||||||
const tx = new EthereumTx(txParams);
|
const tx = new EthereumTx(txParams);
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
|
|
||||||
const txHex = tx.serialize().toString('hex');
|
const txHex = tx.serialize().toString('hex');
|
||||||
try {
|
try {
|
||||||
const derivationPath = this.getDerivationPath();
|
const derivationPath = this._getDerivationPath();
|
||||||
const result = await this._ledgerClientIfExists.signTransaction_async(derivationPath, txHex);
|
const result = await this._ledgerClientIfExists.signTransaction_async(derivationPath, txHex);
|
||||||
// Store signature in transaction
|
// Store signature in transaction
|
||||||
tx.r = Buffer.from(result.r, 'hex');
|
tx.r = Buffer.from(result.r, 'hex');
|
||||||
@@ -176,23 +176,23 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
// EIP155: v should be chain_id * 2 + {35, 36}
|
// EIP155: v should be chain_id * 2 + {35, 36}
|
||||||
const signedChainId = Math.floor((tx.v[0] - 35) / 2);
|
const signedChainId = Math.floor((tx.v[0] - 35) / 2);
|
||||||
if (signedChainId !== this._networkId) {
|
if (signedChainId !== this._networkId) {
|
||||||
await this.destoryLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware);
|
const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const signedTxHex = `0x${tx.serialize().toString('hex')}`;
|
const signedTxHex = `0x${tx.serialize().toString('hex')}`;
|
||||||
await this.destoryLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
return signedTxHex;
|
return signedTxHex;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await this.destoryLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async signPersonalMessageAsync(data: string): Promise<string> {
|
public async signPersonalMessageAsync(data: string): Promise<string> {
|
||||||
this._ledgerClientIfExists = await this.createLedgerClientAsync();
|
this._ledgerClientIfExists = await this._createLedgerClientAsync();
|
||||||
try {
|
try {
|
||||||
const derivationPath = this.getDerivationPath();
|
const derivationPath = this._getDerivationPath();
|
||||||
const result = await this._ledgerClientIfExists.signPersonalMessage_async(
|
const result = await this._ledgerClientIfExists.signPersonalMessage_async(
|
||||||
derivationPath, ethUtil.stripHexPrefix(data));
|
derivationPath, ethUtil.stripHexPrefix(data));
|
||||||
const v = result.v - 27;
|
const v = result.v - 27;
|
||||||
@@ -201,18 +201,18 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
vHex = `0${v}`;
|
vHex = `0${v}`;
|
||||||
}
|
}
|
||||||
const signature = `0x${result.r}${result.s}${vHex}`;
|
const signature = `0x${result.r}${result.s}${vHex}`;
|
||||||
await this.destoryLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
return signature;
|
return signature;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await this.destoryLedgerClientAsync();
|
await this._destroyLedgerClientAsync();
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private getDerivationPath() {
|
private _getDerivationPath() {
|
||||||
const derivationPath = `${this.getPath()}/${this._derivationPathIndex}`;
|
const derivationPath = `${this.getPath()}/${this._derivationPathIndex}`;
|
||||||
return derivationPath;
|
return derivationPath;
|
||||||
}
|
}
|
||||||
private async createLedgerClientAsync(): Promise<LedgerEthereumClient> {
|
private async _createLedgerClientAsync(): Promise<LedgerEthereumClient> {
|
||||||
await this._connectionLock.wait();
|
await this._connectionLock.wait();
|
||||||
if (!_.isUndefined(this._ledgerClientIfExists)) {
|
if (!_.isUndefined(this._ledgerClientIfExists)) {
|
||||||
this._connectionLock.signal();
|
this._connectionLock.signal();
|
||||||
@@ -222,7 +222,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
this._connectionLock.signal();
|
this._connectionLock.signal();
|
||||||
return ledgerEthereumClient;
|
return ledgerEthereumClient;
|
||||||
}
|
}
|
||||||
private async destoryLedgerClientAsync() {
|
private async _destroyLedgerClientAsync() {
|
||||||
await this._connectionLock.wait();
|
await this._connectionLock.wait();
|
||||||
if (_.isUndefined(this._ledgerClientIfExists)) {
|
if (_.isUndefined(this._ledgerClientIfExists)) {
|
||||||
this._connectionLock.signal();
|
this._connectionLock.signal();
|
||||||
@@ -232,11 +232,11 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
this._ledgerClientIfExists = undefined;
|
this._ledgerClientIfExists = undefined;
|
||||||
this._connectionLock.signal();
|
this._connectionLock.signal();
|
||||||
}
|
}
|
||||||
private async sendTransactionAsync(txParams: PartialTxParams): Promise<Web3.JSONRPCResponsePayload> {
|
private async _sendTransactionAsync(txParams: PartialTxParams): Promise<Web3.JSONRPCResponsePayload> {
|
||||||
await this._nonceLock.wait();
|
await this._nonceLock.wait();
|
||||||
try {
|
try {
|
||||||
// fill in the extras
|
// fill in the extras
|
||||||
const filledParams = await this.populateMissingTxParamsAsync(txParams);
|
const filledParams = await this._populateMissingTxParamsAsync(txParams);
|
||||||
// sign it
|
// sign it
|
||||||
const signedTx = await this.signTransactionAsync(filledParams);
|
const signedTx = await this.signTransactionAsync(filledParams);
|
||||||
// emit a submit
|
// emit a submit
|
||||||
@@ -252,11 +252,11 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> {
|
private async _signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> {
|
||||||
await this._nonceLock.wait();
|
await this._nonceLock.wait();
|
||||||
try {
|
try {
|
||||||
// fill in the extras
|
// fill in the extras
|
||||||
const filledParams = await this.populateMissingTxParamsAsync(txParams);
|
const filledParams = await this._populateMissingTxParamsAsync(txParams);
|
||||||
// sign it
|
// sign it
|
||||||
const signedTx = await this.signTransactionAsync(filledParams);
|
const signedTx = await this.signTransactionAsync(filledParams);
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ export class LedgerSubprovider extends Subprovider {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> {
|
private async _populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> {
|
||||||
if (_.isUndefined(txParams.gasPrice)) {
|
if (_.isUndefined(txParams.gasPrice)) {
|
||||||
const gasPriceResult = await this.emitPayloadAsync({
|
const gasPriceResult = await this.emitPayloadAsync({
|
||||||
method: 'eth_gasPrice',
|
method: 'eth_gasPrice',
|
||||||
|
@@ -7,8 +7,8 @@ import {JSONRPCPayload} from '../types';
|
|||||||
import {Subprovider} from './subprovider';
|
import {Subprovider} from './subprovider';
|
||||||
|
|
||||||
export class RedundantRPCSubprovider extends Subprovider {
|
export class RedundantRPCSubprovider extends Subprovider {
|
||||||
private rpcs: RpcSubprovider[];
|
private _rpcs: RpcSubprovider[];
|
||||||
private static async firstSuccessAsync(
|
private static async _firstSuccessAsync(
|
||||||
rpcs: RpcSubprovider[], payload: JSONRPCPayload, next: () => void,
|
rpcs: RpcSubprovider[], payload: JSONRPCPayload, next: () => void,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
let lastErr: Error|undefined;
|
let lastErr: Error|undefined;
|
||||||
@@ -27,7 +27,7 @@ export class RedundantRPCSubprovider extends Subprovider {
|
|||||||
}
|
}
|
||||||
constructor(endpoints: string[]) {
|
constructor(endpoints: string[]) {
|
||||||
super();
|
super();
|
||||||
this.rpcs = _.map(endpoints, endpoint => {
|
this._rpcs = _.map(endpoints, endpoint => {
|
||||||
return new RpcSubprovider({
|
return new RpcSubprovider({
|
||||||
rpcUrl: endpoint,
|
rpcUrl: endpoint,
|
||||||
});
|
});
|
||||||
@@ -36,9 +36,9 @@ export class RedundantRPCSubprovider extends Subprovider {
|
|||||||
// tslint:disable-next-line:async-suffix
|
// tslint:disable-next-line:async-suffix
|
||||||
public async handleRequest(payload: JSONRPCPayload, next: () => void,
|
public async handleRequest(payload: JSONRPCPayload, next: () => void,
|
||||||
end: (err: Error|null, data?: any) => void): Promise<void> {
|
end: (err: Error|null, data?: any) => void): Promise<void> {
|
||||||
const rpcsCopy = this.rpcs.slice();
|
const rpcsCopy = this._rpcs.slice();
|
||||||
try {
|
try {
|
||||||
const data = await RedundantRPCSubprovider.firstSuccessAsync(rpcsCopy, payload, next);
|
const data = await RedundantRPCSubprovider._firstSuccessAsync(rpcsCopy, payload, next);
|
||||||
end(null, data);
|
end(null, data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
end(err);
|
end(err);
|
||||||
|
@@ -10,9 +10,9 @@ import {
|
|||||||
* Altered version of: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
* Altered version of: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||||
*/
|
*/
|
||||||
export class Subprovider {
|
export class Subprovider {
|
||||||
private engine: any;
|
private _engine: any;
|
||||||
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
|
// Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
|
||||||
private static getRandomId() {
|
private static _getRandomId() {
|
||||||
const extraDigits = 3;
|
const extraDigits = 3;
|
||||||
// 13 time digits
|
// 13 time digits
|
||||||
const datePart = new Date().getTime() * Math.pow(10, extraDigits);
|
const datePart = new Date().getTime() * Math.pow(10, extraDigits);
|
||||||
@@ -21,10 +21,10 @@ export class Subprovider {
|
|||||||
// 16 digits
|
// 16 digits
|
||||||
return datePart + extraPart;
|
return datePart + extraPart;
|
||||||
}
|
}
|
||||||
private static createFinalPayload(payload: JSONRPCPayload): Web3.JSONRPCRequestPayload {
|
private static _createFinalPayload(payload: JSONRPCPayload): Web3.JSONRPCRequestPayload {
|
||||||
const finalPayload = {
|
const finalPayload = {
|
||||||
// defaults
|
// defaults
|
||||||
id: Subprovider.getRandomId(),
|
id: Subprovider._getRandomId(),
|
||||||
jsonrpc: '2.0',
|
jsonrpc: '2.0',
|
||||||
params: [],
|
params: [],
|
||||||
...payload,
|
...payload,
|
||||||
@@ -32,11 +32,11 @@ export class Subprovider {
|
|||||||
return finalPayload;
|
return finalPayload;
|
||||||
}
|
}
|
||||||
public setEngine(engine: any): void {
|
public setEngine(engine: any): void {
|
||||||
this.engine = engine;
|
this._engine = engine;
|
||||||
}
|
}
|
||||||
public async emitPayloadAsync(payload: JSONRPCPayload): Promise<any> {
|
public async emitPayloadAsync(payload: JSONRPCPayload): Promise<any> {
|
||||||
const finalPayload = Subprovider.createFinalPayload(payload);
|
const finalPayload = Subprovider._createFinalPayload(payload);
|
||||||
const response = await promisify(this.engine.sendAsync, this.engine)(finalPayload);
|
const response = await promisify(this._engine.sendAsync, this._engine)(finalPayload);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
v0.x.x - TBD
|
||||||
|
------------------------
|
||||||
|
* 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_
|
v0.3.0 - _December 20, 2017_
|
||||||
------------------------
|
------------------------
|
||||||
* Added rules for unused imports, variables and Async suffixes (#265)
|
* Added rules for unused imports, variables and Async suffixes (#265)
|
||||||
|
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,
|
"space-within-parens": false,
|
||||||
"type-literal-delimiter": true,
|
"type-literal-delimiter": true,
|
||||||
|
"underscore-privates": true,
|
||||||
"variable-name": [true,
|
"variable-name": [true,
|
||||||
"ban-keywords",
|
"ban-keywords",
|
||||||
"allow-pascal-case"
|
"allow-pascal-case"
|
||||||
|
@@ -16,9 +16,9 @@ interface RawLogEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Web3Wrapper {
|
export class Web3Wrapper {
|
||||||
private web3: Web3;
|
private _web3: Web3;
|
||||||
private defaults: Partial<TxData>;
|
private _defaults: Partial<TxData>;
|
||||||
private jsonRpcRequestId: number;
|
private _jsonRpcRequestId: number;
|
||||||
constructor(provider: Web3.Provider, defaults?: Partial<TxData>) {
|
constructor(provider: Web3.Provider, defaults?: Partial<TxData>) {
|
||||||
if (_.isUndefined((provider as any).sendAsync)) {
|
if (_.isUndefined((provider as any).sendAsync)) {
|
||||||
// Web3@1.0 provider doesn't support synchronous http requests,
|
// Web3@1.0 provider doesn't support synchronous http requests,
|
||||||
@@ -26,69 +26,69 @@ export class Web3Wrapper {
|
|||||||
// We re-assign the send method so that Web3@1.0 providers work with 0x.js
|
// We re-assign the send method so that Web3@1.0 providers work with 0x.js
|
||||||
(provider as any).sendAsync = (provider as any).send;
|
(provider as any).sendAsync = (provider as any).send;
|
||||||
}
|
}
|
||||||
this.web3 = new Web3();
|
this._web3 = new Web3();
|
||||||
this.web3.setProvider(provider);
|
this._web3.setProvider(provider);
|
||||||
this.defaults = defaults || {};
|
this._defaults = defaults || {};
|
||||||
this.jsonRpcRequestId = 0;
|
this._jsonRpcRequestId = 0;
|
||||||
}
|
}
|
||||||
public getContractDefaults(): Partial<TxData> {
|
public getContractDefaults(): Partial<TxData> {
|
||||||
return this.defaults;
|
return this._defaults;
|
||||||
}
|
}
|
||||||
public setProvider(provider: Web3.Provider, networkId: number) {
|
public setProvider(provider: Web3.Provider, networkId: number) {
|
||||||
this.web3.setProvider(provider);
|
this._web3.setProvider(provider);
|
||||||
}
|
}
|
||||||
public isAddress(address: string): boolean {
|
public isAddress(address: string): boolean {
|
||||||
return this.web3.isAddress(address);
|
return this._web3.isAddress(address);
|
||||||
}
|
}
|
||||||
public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
|
public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> {
|
||||||
const addresses = await this.getAvailableAddressesAsync();
|
const addresses = await this.getAvailableAddressesAsync();
|
||||||
return _.includes(addresses, senderAddress);
|
return _.includes(addresses, senderAddress);
|
||||||
}
|
}
|
||||||
public async getNodeVersionAsync(): Promise<string> {
|
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;
|
return nodeVersion;
|
||||||
}
|
}
|
||||||
public async getNetworkIdAsync(): Promise<number> {
|
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);
|
const networkId = _.parseInt(networkIdStr);
|
||||||
return networkId;
|
return networkId;
|
||||||
}
|
}
|
||||||
public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> {
|
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)) {
|
if (!_.isNull(transactionReceipt)) {
|
||||||
transactionReceipt.status = this.normalizeTxReceiptStatus(transactionReceipt.status);
|
transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status);
|
||||||
}
|
}
|
||||||
return transactionReceipt;
|
return transactionReceipt;
|
||||||
}
|
}
|
||||||
public getCurrentProvider(): Web3.Provider {
|
public getCurrentProvider(): Web3.Provider {
|
||||||
return this.web3.currentProvider;
|
return this._web3.currentProvider;
|
||||||
}
|
}
|
||||||
public toWei(ethAmount: BigNumber): BigNumber {
|
public toWei(ethAmount: BigNumber): BigNumber {
|
||||||
const balanceWei = this.web3.toWei(ethAmount, 'ether');
|
const balanceWei = this._web3.toWei(ethAmount, 'ether');
|
||||||
return balanceWei;
|
return balanceWei;
|
||||||
}
|
}
|
||||||
public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
|
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
|
// Rewrap in a new BigNumber
|
||||||
balanceInWei = new BigNumber(balanceInWei);
|
balanceInWei = new BigNumber(balanceInWei);
|
||||||
return balanceInWei;
|
return balanceInWei;
|
||||||
}
|
}
|
||||||
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
|
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
|
// Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients
|
||||||
const codeIsEmpty = /^0x0{0,40}$/i.test(code);
|
const codeIsEmpty = /^0x0{0,40}$/i.test(code);
|
||||||
return !codeIsEmpty;
|
return !codeIsEmpty;
|
||||||
}
|
}
|
||||||
public async signTransactionAsync(address: string, message: string): Promise<string> {
|
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;
|
return signData;
|
||||||
}
|
}
|
||||||
public async getBlockNumberAsync(): Promise<number> {
|
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;
|
return blockNumber;
|
||||||
}
|
}
|
||||||
public async getBlockAsync(blockParam: string|Web3.BlockParam): Promise<Web3.BlockWithoutTransactionData> {
|
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;
|
return block;
|
||||||
}
|
}
|
||||||
public async getBlockTimestampAsync(blockParam: string|Web3.BlockParam): Promise<number> {
|
public async getBlockTimestampAsync(blockParam: string|Web3.BlockParam): Promise<number> {
|
||||||
@@ -96,17 +96,17 @@ export class Web3Wrapper {
|
|||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
public async getAvailableAddressesAsync(): Promise<string[]> {
|
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;
|
return addresses;
|
||||||
}
|
}
|
||||||
public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> {
|
public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> {
|
||||||
let fromBlock = filter.fromBlock;
|
let fromBlock = filter.fromBlock;
|
||||||
if (_.isNumber(fromBlock)) {
|
if (_.isNumber(fromBlock)) {
|
||||||
fromBlock = this.web3.toHex(fromBlock);
|
fromBlock = this._web3.toHex(fromBlock);
|
||||||
}
|
}
|
||||||
let toBlock = filter.toBlock;
|
let toBlock = filter.toBlock;
|
||||||
if (_.isNumber(toBlock)) {
|
if (_.isNumber(toBlock)) {
|
||||||
toBlock = this.web3.toHex(toBlock);
|
toBlock = this._web3.toHex(toBlock);
|
||||||
}
|
}
|
||||||
const serializedFilter = {
|
const serializedFilter = {
|
||||||
...filter,
|
...filter,
|
||||||
@@ -115,16 +115,16 @@ export class Web3Wrapper {
|
|||||||
};
|
};
|
||||||
const payload = {
|
const payload = {
|
||||||
jsonrpc: '2.0',
|
jsonrpc: '2.0',
|
||||||
id: this.jsonRpcRequestId++,
|
id: this._jsonRpcRequestId++,
|
||||||
method: 'eth_getLogs',
|
method: 'eth_getLogs',
|
||||||
params: [serializedFilter],
|
params: [serializedFilter],
|
||||||
};
|
};
|
||||||
const rawLogs = await this.sendRawPayloadAsync<RawLogEntry[]>(payload);
|
const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload);
|
||||||
const formattedLogs = _.map(rawLogs, this.formatLog.bind(this));
|
const formattedLogs = _.map(rawLogs, this._formatLog.bind(this));
|
||||||
return formattedLogs;
|
return formattedLogs;
|
||||||
}
|
}
|
||||||
public getContractFromAbi(abi: Web3.ContractAbi): Web3.Contract<any> {
|
public getContractFromAbi(abi: Web3.ContractAbi): Web3.Contract<any> {
|
||||||
const web3Contract = this.web3.eth.contract(abi);
|
const web3Contract = this._web3.eth.contract(abi);
|
||||||
return web3Contract;
|
return web3Contract;
|
||||||
}
|
}
|
||||||
public getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance {
|
public getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance {
|
||||||
@@ -132,43 +132,43 @@ export class Web3Wrapper {
|
|||||||
return web3ContractInstance;
|
return web3ContractInstance;
|
||||||
}
|
}
|
||||||
public async estimateGasAsync(data: string): Promise<number> {
|
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;
|
return gas;
|
||||||
}
|
}
|
||||||
private async sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> {
|
private async _sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> {
|
||||||
const sendAsync = this.web3.currentProvider.sendAsync.bind(this.web3.currentProvider);
|
const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider);
|
||||||
const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload);
|
const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload);
|
||||||
const result = response.result;
|
const result = response.result;
|
||||||
return 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
|
// Transaction status might have four values
|
||||||
// undefined - Testrpc and other old clients
|
// undefined - Testrpc and other old clients
|
||||||
// null - New clients on old transactions
|
// null - New clients on old transactions
|
||||||
// number - Parity
|
// number - Parity
|
||||||
// hex - Geth
|
// hex - Geth
|
||||||
if (_.isString(status)) {
|
if (_.isString(status)) {
|
||||||
return this.web3.toDecimal(status) as 0|1;
|
return this._web3.toDecimal(status) as 0|1;
|
||||||
} else if (_.isUndefined(status)) {
|
} else if (_.isUndefined(status)) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private formatLog(rawLog: RawLogEntry): Web3.LogEntry {
|
private _formatLog(rawLog: RawLogEntry): Web3.LogEntry {
|
||||||
const formattedLog = {
|
const formattedLog = {
|
||||||
...rawLog,
|
...rawLog,
|
||||||
logIndex: this.hexToDecimal(rawLog.logIndex),
|
logIndex: this._hexToDecimal(rawLog.logIndex),
|
||||||
blockNumber: this.hexToDecimal(rawLog.blockNumber),
|
blockNumber: this._hexToDecimal(rawLog.blockNumber),
|
||||||
transactionIndex: this.hexToDecimal(rawLog.transactionIndex),
|
transactionIndex: this._hexToDecimal(rawLog.transactionIndex),
|
||||||
};
|
};
|
||||||
return formattedLog;
|
return formattedLog;
|
||||||
}
|
}
|
||||||
private hexToDecimal(hex: string|null): number|null {
|
private _hexToDecimal(hex: string|null): number|null {
|
||||||
if (_.isNull(hex)) {
|
if (_.isNull(hex)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const decimal = this.web3.toDecimal(hex);
|
const decimal = this._web3.toDecimal(hex);
|
||||||
return decimal;
|
return decimal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -59,15 +59,15 @@ const BLOCK_NUMBER_BACK_TRACK = 50;
|
|||||||
export class Blockchain {
|
export class Blockchain {
|
||||||
public networkId: number;
|
public networkId: number;
|
||||||
public nodeVersion: string;
|
public nodeVersion: string;
|
||||||
private zeroEx: ZeroEx;
|
private _zeroEx: ZeroEx;
|
||||||
private dispatcher: Dispatcher;
|
private _dispatcher: Dispatcher;
|
||||||
private web3Wrapper?: Web3Wrapper;
|
private _web3Wrapper?: Web3Wrapper;
|
||||||
private exchangeAddress: string;
|
private _exchangeAddress: string;
|
||||||
private userAddress: string;
|
private _userAddress: string;
|
||||||
private cachedProvider: Web3.Provider;
|
private _cachedProvider: Web3.Provider;
|
||||||
private ledgerSubprovider: LedgerWalletSubprovider;
|
private _ledgerSubprovider: LedgerWalletSubprovider;
|
||||||
private zrxPollIntervalId: NodeJS.Timer;
|
private _zrxPollIntervalId: NodeJS.Timer;
|
||||||
private static async onPageLoadAsync() {
|
private static async _onPageLoadAsync() {
|
||||||
if (document.readyState === 'complete') {
|
if (document.readyState === 'complete') {
|
||||||
return; // Already loaded
|
return; // Already loaded
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ export class Blockchain {
|
|||||||
window.onload = resolve;
|
window.onload = resolve;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private static getNameGivenProvider(provider: Web3.Provider): string {
|
private static _getNameGivenProvider(provider: Web3.Provider): string {
|
||||||
if (!_.isUndefined((provider as any).isMetaMask)) {
|
if (!_.isUndefined((provider as any).isMetaMask)) {
|
||||||
return constants.PROVIDER_NAME_METAMASK;
|
return constants.PROVIDER_NAME_METAMASK;
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ export class Blockchain {
|
|||||||
|
|
||||||
return constants.PROVIDER_NAME_GENERIC;
|
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 doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
||||||
const publicNodeUrlsIfExistsForNetworkId = configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists];
|
const publicNodeUrlsIfExistsForNetworkId = configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists];
|
||||||
const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId);
|
const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId);
|
||||||
@@ -126,29 +126,29 @@ export class Blockchain {
|
|||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
constructor(dispatcher: Dispatcher, isSalePage: boolean = false) {
|
constructor(dispatcher: Dispatcher, isSalePage: boolean = false) {
|
||||||
this.dispatcher = dispatcher;
|
this._dispatcher = dispatcher;
|
||||||
this.userAddress = '';
|
this._userAddress = '';
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.onPageLoadInitFireAndForgetAsync();
|
this._onPageLoadInitFireAndForgetAsync();
|
||||||
}
|
}
|
||||||
public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number) {
|
public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number) {
|
||||||
const isConnected = !_.isUndefined(newNetworkId);
|
const isConnected = !_.isUndefined(newNetworkId);
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
this.networkId = newNetworkId;
|
this.networkId = newNetworkId;
|
||||||
this.dispatcher.encounteredBlockchainError(BlockchainErrs.DisconnectedFromEthereumNode);
|
this._dispatcher.encounteredBlockchainError(BlockchainErrs.DisconnectedFromEthereumNode);
|
||||||
this.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this._dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
} else if (this.networkId !== newNetworkId) {
|
} else if (this.networkId !== newNetworkId) {
|
||||||
this.networkId = newNetworkId;
|
this.networkId = newNetworkId;
|
||||||
this.dispatcher.encounteredBlockchainError(BlockchainErrs.NoError);
|
this._dispatcher.encounteredBlockchainError(BlockchainErrs.NoError);
|
||||||
await this.fetchTokenInformationAsync();
|
await this._fetchTokenInformationAsync();
|
||||||
await this.rehydrateStoreWithContractEvents();
|
await this._rehydrateStoreWithContractEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string) {
|
public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string) {
|
||||||
if (this.userAddress !== newUserAddress) {
|
if (this._userAddress !== newUserAddress) {
|
||||||
this.userAddress = newUserAddress;
|
this._userAddress = newUserAddress;
|
||||||
await this.fetchTokenInformationAsync();
|
await this._fetchTokenInformationAsync();
|
||||||
await this.rehydrateStoreWithContractEvents();
|
await this._rehydrateStoreWithContractEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async nodeVersionUpdatedFireAndForgetAsync(nodeVersion: string) {
|
public async nodeVersionUpdatedFireAndForgetAsync(nodeVersion: string) {
|
||||||
@@ -157,7 +157,7 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async isAddressInTokenRegistryAsync(tokenAddress: string): Promise<boolean> {
|
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
|
// HACK: temporarily whitelist the new WETH token address `as if` they were
|
||||||
// already in the tokenRegistry.
|
// already in the tokenRegistry.
|
||||||
// TODO: Remove this hack once we've updated the TokenRegistries
|
// TODO: Remove this hack once we've updated the TokenRegistries
|
||||||
@@ -166,30 +166,30 @@ export class Blockchain {
|
|||||||
tokenAddress === configs.NEW_WRAPPED_ETHERS[this.networkId]) {
|
tokenAddress === configs.NEW_WRAPPED_ETHERS[this.networkId]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const tokenIfExists = await this.zeroEx.tokenRegistry.getTokenIfExistsAsync(tokenAddress);
|
const tokenIfExists = await this._zeroEx.tokenRegistry.getTokenIfExistsAsync(tokenAddress);
|
||||||
return !_.isUndefined(tokenIfExists);
|
return !_.isUndefined(tokenIfExists);
|
||||||
}
|
}
|
||||||
public getLedgerDerivationPathIfExists(): string {
|
public getLedgerDerivationPathIfExists(): string {
|
||||||
if (_.isUndefined(this.ledgerSubprovider)) {
|
if (_.isUndefined(this._ledgerSubprovider)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const path = this.ledgerSubprovider.getPath();
|
const path = this._ledgerSubprovider.getPath();
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
public updateLedgerDerivationPathIfExists(path: string) {
|
public updateLedgerDerivationPathIfExists(path: string) {
|
||||||
if (_.isUndefined(this.ledgerSubprovider)) {
|
if (_.isUndefined(this._ledgerSubprovider)) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
this.ledgerSubprovider.setPath(path);
|
this._ledgerSubprovider.setPath(path);
|
||||||
}
|
}
|
||||||
public updateLedgerDerivationIndex(pathIndex: number) {
|
public updateLedgerDerivationIndex(pathIndex: number) {
|
||||||
if (_.isUndefined(this.ledgerSubprovider)) {
|
if (_.isUndefined(this._ledgerSubprovider)) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
this.ledgerSubprovider.setPathIndex(pathIndex);
|
this._ledgerSubprovider.setPathIndex(pathIndex);
|
||||||
}
|
}
|
||||||
public async providerTypeUpdatedFireAndForgetAsync(providerType: ProviderType) {
|
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
|
// Should actually be Web3.Provider|ProviderEngine union type but it causes issues
|
||||||
// later on in the logic.
|
// later on in the logic.
|
||||||
let provider;
|
let provider;
|
||||||
@@ -201,17 +201,17 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache injected provider so that we can switch the user back to it easily
|
// 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();
|
provider = new ProviderEngine();
|
||||||
const ledgerWalletConfigs = {
|
const ledgerWalletConfigs = {
|
||||||
networkId: this.networkId,
|
networkId: this.networkId,
|
||||||
ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync,
|
ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync,
|
||||||
};
|
};
|
||||||
this.ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
this._ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs);
|
||||||
provider.addProvider(this.ledgerSubprovider);
|
provider.addProvider(this._ledgerSubprovider);
|
||||||
provider.addProvider(new FilterSubprovider());
|
provider.addProvider(new FilterSubprovider());
|
||||||
const networkId = configs.IS_MAINNET_ENABLED ?
|
const networkId = configs.IS_MAINNET_ENABLED ?
|
||||||
constants.NETWORK_ID_MAINNET :
|
constants.NETWORK_ID_MAINNET :
|
||||||
@@ -220,25 +220,25 @@ export class Blockchain {
|
|||||||
configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId],
|
configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId],
|
||||||
));
|
));
|
||||||
provider.start();
|
provider.start();
|
||||||
this.web3Wrapper.destroy();
|
this._web3Wrapper.destroy();
|
||||||
const shouldPollUserAddress = false;
|
const shouldPollUserAddress = false;
|
||||||
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress);
|
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress);
|
||||||
this.zeroEx.setProvider(provider, networkId);
|
this._zeroEx.setProvider(provider, networkId);
|
||||||
await this.postInstantiationOrUpdatingProviderZeroExAsync();
|
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ProviderType.Injected: {
|
case ProviderType.Injected: {
|
||||||
if (_.isUndefined(this.cachedProvider)) {
|
if (_.isUndefined(this._cachedProvider)) {
|
||||||
return; // Going from injected to injected, so we noop
|
return; // Going from injected to injected, so we noop
|
||||||
}
|
}
|
||||||
provider = this.cachedProvider;
|
provider = this._cachedProvider;
|
||||||
const shouldPollUserAddress = true;
|
const shouldPollUserAddress = true;
|
||||||
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress);
|
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress);
|
||||||
this.zeroEx.setProvider(provider, this.networkId);
|
this._zeroEx.setProvider(provider, this.networkId);
|
||||||
await this.postInstantiationOrUpdatingProviderZeroExAsync();
|
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
||||||
delete this.ledgerSubprovider;
|
delete this._ledgerSubprovider;
|
||||||
delete this.cachedProvider;
|
delete this._cachedProvider;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,28 +246,28 @@ export class Blockchain {
|
|||||||
throw utils.spawnSwitchErr('providerType', providerType);
|
throw utils.spawnSwitchErr('providerType', providerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.fetchTokenInformationAsync();
|
await this._fetchTokenInformationAsync();
|
||||||
}
|
}
|
||||||
public async setProxyAllowanceAsync(token: Token, amountInBaseUnits: BigNumber): Promise<void> {
|
public async setProxyAllowanceAsync(token: Token, amountInBaseUnits: BigNumber): Promise<void> {
|
||||||
utils.assert(this.isValidAddress(token.address), BlockchainCallErrs.TokenAddressIsInvalid);
|
utils.assert(this.isValidAddress(token.address), BlockchainCallErrs.TokenAddressIsInvalid);
|
||||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
|
|
||||||
const txHash = await this.zeroEx.token.setProxyAllowanceAsync(
|
const txHash = await this._zeroEx.token.setProxyAllowanceAsync(
|
||||||
token.address, this.userAddress, amountInBaseUnits,
|
token.address, this._userAddress, amountInBaseUnits,
|
||||||
);
|
);
|
||||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
const allowance = amountInBaseUnits;
|
const allowance = amountInBaseUnits;
|
||||||
this.dispatcher.replaceTokenAllowanceByAddress(token.address, allowance);
|
this._dispatcher.replaceTokenAllowanceByAddress(token.address, allowance);
|
||||||
}
|
}
|
||||||
public async transferAsync(token: Token, toAddress: string,
|
public async transferAsync(token: Token, toAddress: string,
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
amountInBaseUnits: BigNumber): Promise<void> {
|
||||||
const txHash = await this.zeroEx.token.transferAsync(
|
const txHash = await this._zeroEx.token.transferAsync(
|
||||||
token.address, this.userAddress, toAddress, amountInBaseUnits,
|
token.address, this._userAddress, toAddress, amountInBaseUnits,
|
||||||
);
|
);
|
||||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx);
|
const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx);
|
||||||
this.dispatcher.showFlashMessage(React.createElement(TokenSendCompleted, {
|
this._dispatcher.showFlashMessage(React.createElement(TokenSendCompleted, {
|
||||||
etherScanLinkIfExists,
|
etherScanLinkIfExists,
|
||||||
token,
|
token,
|
||||||
toAddress,
|
toAddress,
|
||||||
@@ -302,16 +302,16 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
public async fillOrderAsync(signedOrder: SignedOrder,
|
public async fillOrderAsync(signedOrder: SignedOrder,
|
||||||
fillTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
fillTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
||||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
|
|
||||||
const txHash = await this.zeroEx.exchange.fillOrderAsync(
|
const txHash = await this._zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillTakerTokenAmount, shouldThrowOnInsufficientBalanceOrAllowance, this.userAddress,
|
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;
|
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 logFill = _.find(logs, {event: 'LogFill'});
|
||||||
const args = logFill.args as any as LogFillContractEventArgs;
|
const args = logFill.args as any as LogFillContractEventArgs;
|
||||||
const filledTakerTokenAmount = args.filledTakerTokenAmount;
|
const filledTakerTokenAmount = args.filledTakerTokenAmount;
|
||||||
@@ -319,12 +319,12 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
public async cancelOrderAsync(signedOrder: SignedOrder,
|
public async cancelOrderAsync(signedOrder: SignedOrder,
|
||||||
cancelTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
cancelTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
||||||
const txHash = await this.zeroEx.exchange.cancelOrderAsync(
|
const txHash = await this._zeroEx.exchange.cancelOrderAsync(
|
||||||
signedOrder, cancelTakerTokenAmount,
|
signedOrder, cancelTakerTokenAmount,
|
||||||
);
|
);
|
||||||
const receipt = await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
const logs: Array<LogWithDecodedArgs<ExchangeContractEventArgs>> = receipt.logs as any;
|
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 logCancel = _.find(logs, {event: ExchangeEvents.LogCancel});
|
||||||
const args = logCancel.args as any as LogCancelContractEventArgs;
|
const args = logCancel.args as any as LogCancelContractEventArgs;
|
||||||
const cancelledTakerTokenAmount = args.cancelledTakerTokenAmount;
|
const cancelledTakerTokenAmount = args.cancelledTakerTokenAmount;
|
||||||
@@ -332,95 +332,95 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||||
utils.assert(ZeroEx.isValidOrderHash(orderHash), 'Must be valid orderHash');
|
utils.assert(ZeroEx.isValidOrderHash(orderHash), 'Must be valid orderHash');
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
const unavailableTakerAmount = await this.zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerAmount = await this._zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash);
|
||||||
return unavailableTakerAmount;
|
return unavailableTakerAmount;
|
||||||
}
|
}
|
||||||
public getExchangeContractAddressIfExists() {
|
public getExchangeContractAddressIfExists() {
|
||||||
return this.exchangeAddress;
|
return this._exchangeAddress;
|
||||||
}
|
}
|
||||||
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
||||||
fillTakerTokenAmount: BigNumber,
|
fillTakerTokenAmount: BigNumber,
|
||||||
takerAddress: string): Promise<void> {
|
takerAddress: string): Promise<void> {
|
||||||
await this.zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
await this._zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||||
signedOrder, fillTakerTokenAmount, takerAddress);
|
signedOrder, fillTakerTokenAmount, takerAddress);
|
||||||
}
|
}
|
||||||
public async validateCancelOrderThrowIfInvalidAsync(order: Order,
|
public async validateCancelOrderThrowIfInvalidAsync(order: Order,
|
||||||
cancelTakerTokenAmount: BigNumber): Promise<void> {
|
cancelTakerTokenAmount: BigNumber): Promise<void> {
|
||||||
await this.zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(order, cancelTakerTokenAmount);
|
await this._zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(order, cancelTakerTokenAmount);
|
||||||
}
|
}
|
||||||
public isValidAddress(address: string): boolean {
|
public isValidAddress(address: string): boolean {
|
||||||
const lowercaseAddress = address.toLowerCase();
|
const lowercaseAddress = address.toLowerCase();
|
||||||
return this.web3Wrapper.isAddress(lowercaseAddress);
|
return this._web3Wrapper.isAddress(lowercaseAddress);
|
||||||
}
|
}
|
||||||
public async pollTokenBalanceAsync(token: Token) {
|
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 () => {
|
this._zrxPollIntervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
||||||
const [balance] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address);
|
const [balance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address);
|
||||||
if (!balance.eq(currBalance)) {
|
if (!balance.eq(currBalance)) {
|
||||||
this.dispatcher.replaceTokenBalanceByAddress(token.address, balance);
|
this._dispatcher.replaceTokenBalanceByAddress(token.address, balance);
|
||||||
clearInterval(this.zrxPollIntervalId);
|
clearInterval(this._zrxPollIntervalId);
|
||||||
delete this.zrxPollIntervalId;
|
delete this._zrxPollIntervalId;
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
public async signOrderHashAsync(orderHash: string): Promise<SignatureData> {
|
public async signOrderHashAsync(orderHash: string): Promise<SignatureData> {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
const makerAddress = this.userAddress;
|
const makerAddress = this._userAddress;
|
||||||
// If makerAddress is undefined, this means they have a web3 instance injected into their browser
|
// If makerAddress is undefined, this means they have a web3 instance injected into their browser
|
||||||
// but no account addresses associated with it.
|
// but no account addresses associated with it.
|
||||||
if (_.isUndefined(makerAddress)) {
|
if (_.isUndefined(makerAddress)) {
|
||||||
throw new Error('Tried to send a sign request but user has no associated addresses');
|
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, {
|
const signatureData = _.extend({}, ecSignature, {
|
||||||
hash: orderHash,
|
hash: orderHash,
|
||||||
});
|
});
|
||||||
this.dispatcher.updateSignatureData(signatureData);
|
this._dispatcher.updateSignatureData(signatureData);
|
||||||
return signatureData;
|
return signatureData;
|
||||||
}
|
}
|
||||||
public async mintTestTokensAsync(token: Token) {
|
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, {
|
await mintableContract.mint(constants.MINT_AMOUNT, {
|
||||||
from: this.userAddress,
|
from: this._userAddress,
|
||||||
});
|
});
|
||||||
const balanceDelta = constants.MINT_AMOUNT;
|
const balanceDelta = constants.MINT_AMOUNT;
|
||||||
this.dispatcher.updateTokenBalanceByAddress(token.address, balanceDelta);
|
this._dispatcher.updateTokenBalanceByAddress(token.address, balanceDelta);
|
||||||
}
|
}
|
||||||
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
||||||
const balance = await this.web3Wrapper.getBalanceInEthAsync(owner);
|
const balance = await this._web3Wrapper.getBalanceInEthAsync(owner);
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
|
public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
const txHash = await this.zeroEx.etherToken.depositAsync(etherTokenAddress, amount, this.userAddress);
|
const txHash = await this._zeroEx.etherToken.depositAsync(etherTokenAddress, amount, this._userAddress);
|
||||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
}
|
}
|
||||||
public async convertWrappedEthTokensToEthAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
|
public async convertWrappedEthTokensToEthAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
const txHash = await this.zeroEx.etherToken.withdrawAsync(etherTokenAddress, amount, this.userAddress);
|
const txHash = await this._zeroEx.etherToken.withdrawAsync(etherTokenAddress, amount, this._userAddress);
|
||||||
await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
}
|
}
|
||||||
public async doesContractExistAtAddressAsync(address: string) {
|
public async doesContractExistAtAddressAsync(address: string) {
|
||||||
const doesContractExist = await this.web3Wrapper.doesContractExistAtAddressAsync(address);
|
const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(address);
|
||||||
return doesContractExist;
|
return doesContractExist;
|
||||||
}
|
}
|
||||||
public async getCurrentUserTokenBalanceAndAllowanceAsync(tokenAddress: string): Promise<BigNumber[]> {
|
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;
|
return tokenBalanceAndAllowance;
|
||||||
}
|
}
|
||||||
public async getTokenBalanceAndAllowanceAsync(ownerAddress: string, tokenAddress: string):
|
public async getTokenBalanceAndAllowanceAsync(ownerAddress: string, tokenAddress: string):
|
||||||
Promise<BigNumber[]> {
|
Promise<BigNumber[]> {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
|
|
||||||
if (_.isEmpty(ownerAddress)) {
|
if (_.isEmpty(ownerAddress)) {
|
||||||
const zero = new BigNumber(0);
|
const zero = new BigNumber(0);
|
||||||
@@ -428,9 +428,9 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
let balance = new BigNumber(0);
|
let balance = new BigNumber(0);
|
||||||
let allowance = new BigNumber(0);
|
let allowance = new BigNumber(0);
|
||||||
if (this.doesUserAddressExist()) {
|
if (this._doesUserAddressExist()) {
|
||||||
balance = await this.zeroEx.token.getBalanceAsync(tokenAddress, ownerAddress);
|
balance = await this._zeroEx.token.getBalanceAsync(tokenAddress, ownerAddress);
|
||||||
allowance = await this.zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
allowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
||||||
}
|
}
|
||||||
return [balance, allowance];
|
return [balance, allowance];
|
||||||
}
|
}
|
||||||
@@ -439,11 +439,11 @@ export class Blockchain {
|
|||||||
for (const token of tokens) {
|
for (const token of tokens) {
|
||||||
let balance = new BigNumber(0);
|
let balance = new BigNumber(0);
|
||||||
let allowance = new BigNumber(0);
|
let allowance = new BigNumber(0);
|
||||||
if (this.doesUserAddressExist()) {
|
if (this._doesUserAddressExist()) {
|
||||||
[
|
[
|
||||||
balance,
|
balance,
|
||||||
allowance,
|
allowance,
|
||||||
] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address);
|
] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address);
|
||||||
}
|
}
|
||||||
const tokenState = {
|
const tokenState = {
|
||||||
balance,
|
balance,
|
||||||
@@ -451,61 +451,61 @@ export class Blockchain {
|
|||||||
};
|
};
|
||||||
tokenStateByAddress[token.address] = tokenState;
|
tokenStateByAddress[token.address] = tokenState;
|
||||||
}
|
}
|
||||||
this.dispatcher.updateTokenStateByAddress(tokenStateByAddress);
|
this._dispatcher.updateTokenStateByAddress(tokenStateByAddress);
|
||||||
}
|
}
|
||||||
public async getUserAccountsAsync() {
|
public async getUserAccountsAsync() {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
const userAccountsIfExists = await this.zeroEx.getAvailableAddressesAsync();
|
const userAccountsIfExists = await this._zeroEx.getAvailableAddressesAsync();
|
||||||
return userAccountsIfExists;
|
return userAccountsIfExists;
|
||||||
}
|
}
|
||||||
// HACK: When a user is using a Ledger, we simply dispatch the selected userAddress, which
|
// 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
|
// by-passes the web3Wrapper logic for updating the prevUserAddress. We therefore need to
|
||||||
// manually update it. This should only be called by the LedgerConfigDialog.
|
// manually update it. This should only be called by the LedgerConfigDialog.
|
||||||
public updateWeb3WrapperPrevUserAddress(newUserAddress: string) {
|
public updateWeb3WrapperPrevUserAddress(newUserAddress: string) {
|
||||||
this.web3Wrapper.updatePrevUserAddress(newUserAddress);
|
this._web3Wrapper.updatePrevUserAddress(newUserAddress);
|
||||||
}
|
}
|
||||||
public destroy() {
|
public destroy() {
|
||||||
clearInterval(this.zrxPollIntervalId);
|
clearInterval(this._zrxPollIntervalId);
|
||||||
this.web3Wrapper.destroy();
|
this._web3Wrapper.destroy();
|
||||||
this.stopWatchingExchangeLogFillEvents();
|
this._stopWatchingExchangeLogFillEvents();
|
||||||
}
|
}
|
||||||
private async showEtherScanLinkAndAwaitTransactionMinedAsync(
|
private async _showEtherScanLinkAndAwaitTransactionMinedAsync(
|
||||||
txHash: string): Promise<TransactionReceiptWithDecodedLogs> {
|
txHash: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx);
|
const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx);
|
||||||
this.dispatcher.showFlashMessage(React.createElement(TransactionSubmitted, {
|
this._dispatcher.showFlashMessage(React.createElement(TransactionSubmitted, {
|
||||||
etherScanLinkIfExists,
|
etherScanLinkIfExists,
|
||||||
}));
|
}));
|
||||||
const receipt = await this.zeroEx.awaitTransactionMinedAsync(txHash);
|
const receipt = await this._zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
return receipt;
|
return receipt;
|
||||||
}
|
}
|
||||||
private doesUserAddressExist(): boolean {
|
private _doesUserAddressExist(): boolean {
|
||||||
return this.userAddress !== '';
|
return this._userAddress !== '';
|
||||||
}
|
}
|
||||||
private async rehydrateStoreWithContractEvents() {
|
private async _rehydrateStoreWithContractEvents() {
|
||||||
// Ensure we are only ever listening to one set of events
|
// Ensure we are only ever listening to one set of events
|
||||||
this.stopWatchingExchangeLogFillEvents();
|
this._stopWatchingExchangeLogFillEvents();
|
||||||
|
|
||||||
if (!this.doesUserAddressExist()) {
|
if (!this._doesUserAddressExist()) {
|
||||||
return; // short-circuit
|
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
|
// 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
|
// transactions where an account is either the `maker` or `taker`, we loop
|
||||||
// through all fill events, and filter/cache them client-side.
|
// through all fill events, and filter/cache them client-side.
|
||||||
const filterIndexObj = {};
|
const filterIndexObj = {};
|
||||||
await this.startListeningForExchangeLogFillEventsAsync(filterIndexObj);
|
await this._startListeningForExchangeLogFillEventsAsync(filterIndexObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> {
|
private async _startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
// Fetch historical logs
|
// Fetch historical logs
|
||||||
await this.fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues);
|
await this._fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues);
|
||||||
|
|
||||||
// Start a subscription for new logs
|
// Start a subscription for new logs
|
||||||
this.zeroEx.exchange.subscribe(
|
this._zeroEx.exchange.subscribe(
|
||||||
ExchangeEvents.LogFill, indexFilterValues,
|
ExchangeEvents.LogFill, indexFilterValues,
|
||||||
async (err: Error, decodedLogEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
async (err: Error, decodedLogEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -517,40 +517,40 @@ export class Blockchain {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const decodedLog = decodedLogEvent.log;
|
const decodedLog = decodedLogEvent.log;
|
||||||
if (!this.doesLogEventInvolveUser(decodedLog)) {
|
if (!this._doesLogEventInvolveUser(decodedLog)) {
|
||||||
return; // We aren't interested in the fill event
|
return; // We aren't interested in the fill event
|
||||||
}
|
}
|
||||||
this.updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
||||||
const fill = await this.convertDecodedLogToFillAsync(decodedLog);
|
const fill = await this._convertDecodedLogToFillAsync(decodedLog);
|
||||||
if (decodedLogEvent.isRemoved) {
|
if (decodedLogEvent.isRemoved) {
|
||||||
tradeHistoryStorage.removeFillFromUser(this.userAddress, this.networkId, fill);
|
tradeHistoryStorage.removeFillFromUser(this._userAddress, this.networkId, fill);
|
||||||
} else {
|
} else {
|
||||||
tradeHistoryStorage.addFillToUser(this.userAddress, this.networkId, fill);
|
tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) {
|
private async _fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) {
|
||||||
const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this.userAddress, this.networkId);
|
const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this._userAddress, this.networkId);
|
||||||
const blockRange: BlockRange = {
|
const blockRange: BlockRange = {
|
||||||
fromBlock,
|
fromBlock,
|
||||||
toBlock: 'latest' as BlockParam,
|
toBlock: 'latest' as BlockParam,
|
||||||
};
|
};
|
||||||
const decodedLogs = await this.zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
const decodedLogs = await this._zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
||||||
ExchangeEvents.LogFill, blockRange, indexFilterValues,
|
ExchangeEvents.LogFill, blockRange, indexFilterValues,
|
||||||
);
|
);
|
||||||
for (const decodedLog of decodedLogs) {
|
for (const decodedLog of decodedLogs) {
|
||||||
if (!this.doesLogEventInvolveUser(decodedLog)) {
|
if (!this._doesLogEventInvolveUser(decodedLog)) {
|
||||||
continue; // We aren't interested in the fill event
|
continue; // We aren't interested in the fill event
|
||||||
}
|
}
|
||||||
this.updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber);
|
||||||
const fill = await this.convertDecodedLogToFillAsync(decodedLog);
|
const fill = await this._convertDecodedLogToFillAsync(decodedLog);
|
||||||
tradeHistoryStorage.addFillToUser(this.userAddress, this.networkId, fill);
|
tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
private async _convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||||
const args = decodedLog.args;
|
const args = decodedLog.args;
|
||||||
const blockTimestamp = await this.web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash);
|
const blockTimestamp = await this._web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash);
|
||||||
const fill = {
|
const fill = {
|
||||||
filledTakerTokenAmount: args.filledTakerTokenAmount,
|
filledTakerTokenAmount: args.filledTakerTokenAmount,
|
||||||
filledMakerTokenAmount: args.filledMakerTokenAmount,
|
filledMakerTokenAmount: args.filledMakerTokenAmount,
|
||||||
@@ -567,13 +567,13 @@ export class Blockchain {
|
|||||||
};
|
};
|
||||||
return fill;
|
return fill;
|
||||||
}
|
}
|
||||||
private doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
private _doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||||
const args = decodedLog.args;
|
const args = decodedLog.args;
|
||||||
const isUserMakerOrTaker = args.maker === this.userAddress ||
|
const isUserMakerOrTaker = args.maker === this._userAddress ||
|
||||||
args.taker === this.userAddress;
|
args.taker === this._userAddress;
|
||||||
return isUserMakerOrTaker;
|
return isUserMakerOrTaker;
|
||||||
}
|
}
|
||||||
private updateLatestFillsBlockIfNeeded(blockNumber: number) {
|
private _updateLatestFillsBlockIfNeeded(blockNumber: number) {
|
||||||
const isBlockPending = _.isNull(blockNumber);
|
const isBlockPending = _.isNull(blockNumber);
|
||||||
if (!isBlockPending) {
|
if (!isBlockPending) {
|
||||||
// Hack: I've observed the behavior where a client won't register certain fill events
|
// 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 ?
|
const blockNumberToSet = blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ?
|
||||||
0 :
|
0 :
|
||||||
blockNumber - BLOCK_NUMBER_BACK_TRACK;
|
blockNumber - BLOCK_NUMBER_BACK_TRACK;
|
||||||
tradeHistoryStorage.setFillsLatestBlock(this.userAddress, this.networkId, blockNumberToSet);
|
tradeHistoryStorage.setFillsLatestBlock(this._userAddress, this.networkId, blockNumberToSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private stopWatchingExchangeLogFillEvents(): void {
|
private _stopWatchingExchangeLogFillEvents(): void {
|
||||||
this.zeroEx.exchange.unsubscribeAll();
|
this._zeroEx.exchange.unsubscribeAll();
|
||||||
}
|
}
|
||||||
private async getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> {
|
private async _getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
const tokenRegistryTokens = await this.zeroEx.tokenRegistry.getTokensAsync();
|
const tokenRegistryTokens = await this._zeroEx.tokenRegistry.getTokensAsync();
|
||||||
|
|
||||||
const tokenByAddress: TokenByAddress = {};
|
const tokenByAddress: TokenByAddress = {};
|
||||||
_.each(tokenRegistryTokens, (t: ZeroExToken, i: number) => {
|
_.each(tokenRegistryTokens, (t: ZeroExToken, i: number) => {
|
||||||
@@ -626,8 +626,8 @@ export class Blockchain {
|
|||||||
});
|
});
|
||||||
return tokenByAddress;
|
return tokenByAddress;
|
||||||
}
|
}
|
||||||
private async onPageLoadInitFireAndForgetAsync() {
|
private async _onPageLoadInitFireAndForgetAsync() {
|
||||||
await Blockchain.onPageLoadAsync(); // wait for page to load
|
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
|
// 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
|
// 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 :
|
const networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists :
|
||||||
configs.IS_MAINNET_ENABLED ?
|
configs.IS_MAINNET_ENABLED ?
|
||||||
constants.NETWORK_ID_MAINNET :
|
constants.NETWORK_ID_MAINNET :
|
||||||
@@ -653,45 +653,45 @@ export class Blockchain {
|
|||||||
const zeroExConfigs = {
|
const zeroExConfigs = {
|
||||||
networkId,
|
networkId,
|
||||||
};
|
};
|
||||||
this.zeroEx = new ZeroEx(provider, zeroExConfigs);
|
this._zeroEx = new ZeroEx(provider, zeroExConfigs);
|
||||||
this.updateProviderName(injectedWeb3);
|
this._updateProviderName(injectedWeb3);
|
||||||
const shouldPollUserAddress = true;
|
const shouldPollUserAddress = true;
|
||||||
this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, networkId, shouldPollUserAddress);
|
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, networkId, shouldPollUserAddress);
|
||||||
await this.postInstantiationOrUpdatingProviderZeroExAsync();
|
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
||||||
}
|
}
|
||||||
// This method should always be run after instantiating or updating the provider
|
// This method should always be run after instantiating or updating the provider
|
||||||
// of the ZeroEx instance.
|
// of the ZeroEx instance.
|
||||||
private async postInstantiationOrUpdatingProviderZeroExAsync() {
|
private async _postInstantiationOrUpdatingProviderZeroExAsync() {
|
||||||
utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
this.exchangeAddress = this.zeroEx.exchange.getContractAddress();
|
this._exchangeAddress = this._zeroEx.exchange.getContractAddress();
|
||||||
}
|
}
|
||||||
private updateProviderName(injectedWeb3: Web3) {
|
private _updateProviderName(injectedWeb3: Web3) {
|
||||||
const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
||||||
const providerName = doesInjectedWeb3Exist ?
|
const providerName = doesInjectedWeb3Exist ?
|
||||||
Blockchain.getNameGivenProvider(injectedWeb3.currentProvider) :
|
Blockchain._getNameGivenProvider(injectedWeb3.currentProvider) :
|
||||||
constants.PROVIDER_NAME_PUBLIC;
|
constants.PROVIDER_NAME_PUBLIC;
|
||||||
this.dispatcher.updateInjectedProviderName(providerName);
|
this._dispatcher.updateInjectedProviderName(providerName);
|
||||||
}
|
}
|
||||||
private async fetchTokenInformationAsync() {
|
private async _fetchTokenInformationAsync() {
|
||||||
utils.assert(!_.isUndefined(this.networkId),
|
utils.assert(!_.isUndefined(this.networkId),
|
||||||
'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node');
|
'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node');
|
||||||
|
|
||||||
this.dispatcher.updateBlockchainIsLoaded(false);
|
this._dispatcher.updateBlockchainIsLoaded(false);
|
||||||
this.dispatcher.clearTokenByAddress();
|
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
|
// 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
|
// 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
|
// 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
|
// loading dialog to show up twice. First to load the contracts, and second to load the
|
||||||
// balances and allowances.
|
// balances and allowances.
|
||||||
this.userAddress = await this.web3Wrapper.getFirstAccountIfExistsAsync();
|
this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync();
|
||||||
if (!_.isEmpty(this.userAddress)) {
|
if (!_.isEmpty(this._userAddress)) {
|
||||||
this.dispatcher.updateUserAddress(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);
|
const tokenRegistryTokens = _.values(tokenRegistryTokensByAddress);
|
||||||
if (_.isUndefined(trackedTokensIfExists)) {
|
if (_.isUndefined(trackedTokensIfExists)) {
|
||||||
trackedTokensIfExists = _.map(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => {
|
trackedTokensIfExists = _.map(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => {
|
||||||
@@ -700,7 +700,7 @@ export class Blockchain {
|
|||||||
return token;
|
return token;
|
||||||
});
|
});
|
||||||
_.each(trackedTokensIfExists, token => {
|
_.each(trackedTokensIfExists, token => {
|
||||||
trackedTokenStorage.addTrackedTokenToUser(this.userAddress, this.networkId, token);
|
trackedTokenStorage.addTrackedTokenToUser(this._userAddress, this.networkId, token);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Properly set all tokenRegistry tokens `isTracked` to true if they are in the existing trackedTokens array
|
// 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]);
|
const allTokens = _.uniq([...tokenRegistryTokens, ...trackedTokensIfExists]);
|
||||||
this.dispatcher.updateTokenByAddress(allTokens);
|
this._dispatcher.updateTokenByAddress(allTokens);
|
||||||
|
|
||||||
// Get balance/allowance for tracked tokens
|
// Get balance/allowance for tracked tokens
|
||||||
await this.updateTokenBalancesAndAllowancesAsync(trackedTokensIfExists);
|
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[0]}),
|
||||||
_.find(allTokens, {symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[1]}),
|
_.find(allTokens, {symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[1]}),
|
||||||
];
|
];
|
||||||
this.dispatcher.updateChosenAssetTokenAddress(Side.Deposit, mostPopularTradingPairTokens[0].address);
|
this._dispatcher.updateChosenAssetTokenAddress(Side.Deposit, mostPopularTradingPairTokens[0].address);
|
||||||
this.dispatcher.updateChosenAssetTokenAddress(Side.Receive, mostPopularTradingPairTokens[1].address);
|
this._dispatcher.updateChosenAssetTokenAddress(Side.Receive, mostPopularTradingPairTokens[1].address);
|
||||||
this.dispatcher.updateBlockchainIsLoaded(true);
|
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 c = await contract(artifact);
|
||||||
const providerObj = this.web3Wrapper.getProviderObj();
|
const providerObj = this._web3Wrapper.getProviderObj();
|
||||||
c.setProvider(providerObj);
|
c.setProvider(providerObj);
|
||||||
|
|
||||||
const artifactNetworkConfigs = artifact.networks[this.networkId];
|
const artifactNetworkConfigs = artifact.networks[this.networkId];
|
||||||
|
@@ -31,7 +31,7 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
|||||||
const hasWalletAddress = this.props.userAddress !== '';
|
const hasWalletAddress = this.props.userAddress !== '';
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
title={this.getTitle(hasWalletAddress)}
|
title={this._getTitle(hasWalletAddress)}
|
||||||
titleStyle={{fontWeight: 100}}
|
titleStyle={{fontWeight: 100}}
|
||||||
actions={dialogActions}
|
actions={dialogActions}
|
||||||
open={this.props.isOpen}
|
open={this.props.isOpen}
|
||||||
@@ -40,12 +40,12 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
|||||||
autoScrollBodyContent={true}
|
autoScrollBodyContent={true}
|
||||||
>
|
>
|
||||||
<div className="pt2" style={{color: colors.grey700}}>
|
<div className="pt2" style={{color: colors.grey700}}>
|
||||||
{this.renderExplanation(hasWalletAddress)}
|
{this._renderExplanation(hasWalletAddress)}
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private getTitle(hasWalletAddress: boolean) {
|
private _getTitle(hasWalletAddress: boolean) {
|
||||||
if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
|
if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
|
||||||
return '0x smart contracts not found';
|
return '0x smart contracts not found';
|
||||||
} else if (!hasWalletAddress) {
|
} else if (!hasWalletAddress) {
|
||||||
@@ -56,18 +56,18 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
|||||||
return 'Unexpected error';
|
return 'Unexpected error';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private renderExplanation(hasWalletAddress: boolean) {
|
private _renderExplanation(hasWalletAddress: boolean) {
|
||||||
if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
|
if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) {
|
||||||
return this.renderContractsNotDeployedExplanation();
|
return this._renderContractsNotDeployedExplanation();
|
||||||
} else if (!hasWalletAddress) {
|
} else if (!hasWalletAddress) {
|
||||||
return this.renderNoWalletFoundExplanation();
|
return this._renderNoWalletFoundExplanation();
|
||||||
} else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) {
|
} else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) {
|
||||||
return this.renderDisconnectedFromNode();
|
return this._renderDisconnectedFromNode();
|
||||||
} else {
|
} else {
|
||||||
return this.renderUnexpectedErrorExplanation();
|
return this._renderUnexpectedErrorExplanation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private renderDisconnectedFromNode() {
|
private _renderDisconnectedFromNode() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
You were disconnected from the backing Ethereum node.
|
You were disconnected from the backing Ethereum node.
|
||||||
@@ -78,14 +78,14 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderUnexpectedErrorExplanation() {
|
private _renderUnexpectedErrorExplanation() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
We encountered an unexpected error. Please try refreshing the page.
|
We encountered an unexpected error. Please try refreshing the page.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderNoWalletFoundExplanation() {
|
private _renderNoWalletFoundExplanation() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@@ -122,7 +122,7 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderContractsNotDeployedExplanation() {
|
private _renderContractsNotDeployedExplanation() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
@@ -37,13 +37,13 @@ export class EthWethConversionDialog extends
|
|||||||
<FlatButton
|
<FlatButton
|
||||||
key="cancel"
|
key="cancel"
|
||||||
label="Cancel"
|
label="Cancel"
|
||||||
onTouchTap={this.onCancel.bind(this)}
|
onTouchTap={this._onCancel.bind(this)}
|
||||||
/>,
|
/>,
|
||||||
<FlatButton
|
<FlatButton
|
||||||
key="convert"
|
key="convert"
|
||||||
label="Convert"
|
label="Convert"
|
||||||
primary={true}
|
primary={true}
|
||||||
onTouchTap={this.onConvertClick.bind(this)}
|
onTouchTap={this._onConvertClick.bind(this)}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
const title = this.props.direction === Side.Deposit ? 'Wrap ETH' : 'Unwrap WETH';
|
const title = this.props.direction === Side.Deposit ? 'Wrap ETH' : 'Unwrap WETH';
|
||||||
@@ -55,11 +55,11 @@ export class EthWethConversionDialog extends
|
|||||||
contentStyle={{width: 448}}
|
contentStyle={{width: 448}}
|
||||||
open={this.props.isOpen}
|
open={this.props.isOpen}
|
||||||
>
|
>
|
||||||
{this.renderConversionDialogBody()}
|
{this._renderConversionDialogBody()}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderConversionDialogBody() {
|
private _renderConversionDialogBody() {
|
||||||
const explanation = this.props.direction === Side.Deposit ?
|
const explanation = this.props.direction === Side.Deposit ?
|
||||||
'Convert your Ether into a tokenized, tradable form.' :
|
'Convert your Ether into a tokenized, tradable form.' :
|
||||||
'Convert your Wrapped Ether back into it\'s native form.';
|
'Convert your Wrapped Ether back into it\'s native form.';
|
||||||
@@ -71,14 +71,14 @@ export class EthWethConversionDialog extends
|
|||||||
</div>
|
</div>
|
||||||
<div className="mx-auto" style={{maxWidth: 312}}>
|
<div className="mx-auto" style={{maxWidth: 312}}>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{this.renderCurrency(isWrappedVersion)}
|
{this._renderCurrency(isWrappedVersion)}
|
||||||
<div style={{paddingTop: 68}}>
|
<div style={{paddingTop: 68}}>
|
||||||
<i
|
<i
|
||||||
style={{fontSize: 28, color: colors.darkBlue}}
|
style={{fontSize: 28, color: colors.darkBlue}}
|
||||||
className="zmdi zmdi-arrow-right"
|
className="zmdi zmdi-arrow-right"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.renderCurrency(!isWrappedVersion)}
|
{this._renderCurrency(!isWrappedVersion)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="pt2 mx-auto"
|
className="pt2 mx-auto"
|
||||||
@@ -91,14 +91,14 @@ export class EthWethConversionDialog extends
|
|||||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||||
shouldCheckBalance={true}
|
shouldCheckBalance={true}
|
||||||
shouldCheckAllowance={false}
|
shouldCheckAllowance={false}
|
||||||
onChange={this.onValueChange.bind(this)}
|
onChange={this._onValueChange.bind(this)}
|
||||||
amount={this.state.value}
|
amount={this.state.value}
|
||||||
onVisitBalancesPageClick={this.props.onCancelled}
|
onVisitBalancesPageClick={this.props.onCancelled}
|
||||||
/> :
|
/> :
|
||||||
<EthAmountInput
|
<EthAmountInput
|
||||||
balance={this.props.etherBalance}
|
balance={this.props.etherBalance}
|
||||||
amount={this.state.value}
|
amount={this.state.value}
|
||||||
onChange={this.onValueChange.bind(this)}
|
onChange={this._onValueChange.bind(this)}
|
||||||
shouldCheckBalance={true}
|
shouldCheckBalance={true}
|
||||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||||
onVisitBalancesPageClick={this.props.onCancelled}
|
onVisitBalancesPageClick={this.props.onCancelled}
|
||||||
@@ -112,7 +112,7 @@ export class EthWethConversionDialog extends
|
|||||||
{this.props.direction === Side.Receive &&
|
{this.props.direction === Side.Receive &&
|
||||||
<div
|
<div
|
||||||
className="right"
|
className="right"
|
||||||
onClick={this.onMaxClick.bind(this)}
|
onClick={this._onMaxClick.bind(this)}
|
||||||
style={{color: colors.darkBlue, textDecoration: 'underline', cursor: 'pointer'}}
|
style={{color: colors.darkBlue, textDecoration: 'underline', cursor: 'pointer'}}
|
||||||
>
|
>
|
||||||
Max
|
Max
|
||||||
@@ -124,7 +124,7 @@ export class EthWethConversionDialog extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderCurrency(isWrappedVersion: boolean) {
|
private _renderCurrency(isWrappedVersion: boolean) {
|
||||||
const name = isWrappedVersion ? 'Wrapped Ether' : 'Ether';
|
const name = isWrappedVersion ? 'Wrapped Ether' : 'Ether';
|
||||||
const iconUrl = isWrappedVersion ? '/images/token_icons/ether_erc20.png' : '/images/ether.png';
|
const iconUrl = isWrappedVersion ? '/images/token_icons/ether_erc20.png' : '/images/ether.png';
|
||||||
const symbol = isWrappedVersion ? 'WETH' : 'ETH';
|
const symbol = isWrappedVersion ? 'WETH' : 'ETH';
|
||||||
@@ -145,18 +145,18 @@ export class EthWethConversionDialog extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onMaxClick() {
|
private _onMaxClick() {
|
||||||
this.setState({
|
this.setState({
|
||||||
value: this.props.tokenState.balance,
|
value: this.props.tokenState.balance,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onValueChange(isValid: boolean, amount?: BigNumber) {
|
private _onValueChange(isValid: boolean, amount?: BigNumber) {
|
||||||
this.setState({
|
this.setState({
|
||||||
value: amount,
|
value: amount,
|
||||||
hasErrors: !isValid,
|
hasErrors: !isValid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onConvertClick() {
|
private _onConvertClick() {
|
||||||
if (this.state.hasErrors) {
|
if (this.state.hasErrors) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowIncompleteErrs: true,
|
shouldShowIncompleteErrs: true,
|
||||||
@@ -169,7 +169,7 @@ export class EthWethConversionDialog extends
|
|||||||
this.props.onComplete(this.props.direction, value);
|
this.props.onComplete(this.props.direction, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private onCancel() {
|
private _onCancel() {
|
||||||
this.setState({
|
this.setState({
|
||||||
value: undefined,
|
value: undefined,
|
||||||
});
|
});
|
||||||
|
@@ -62,7 +62,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
<FlatButton
|
<FlatButton
|
||||||
key="ledgerConnectCancel"
|
key="ledgerConnectCancel"
|
||||||
label="Cancel"
|
label="Cancel"
|
||||||
onTouchTap={this.onClose.bind(this)}
|
onTouchTap={this._onClose.bind(this)}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
const dialogTitle = this.state.stepIndex === LedgerSteps.CONNECT ?
|
const dialogTitle = this.state.stepIndex === LedgerSteps.CONNECT ?
|
||||||
@@ -74,22 +74,22 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
titleStyle={{fontWeight: 100}}
|
titleStyle={{fontWeight: 100}}
|
||||||
actions={dialogActions}
|
actions={dialogActions}
|
||||||
open={this.props.isOpen}
|
open={this.props.isOpen}
|
||||||
onRequestClose={this.onClose.bind(this)}
|
onRequestClose={this._onClose.bind(this)}
|
||||||
autoScrollBodyContent={true}
|
autoScrollBodyContent={true}
|
||||||
bodyStyle={{paddingBottom: 0}}
|
bodyStyle={{paddingBottom: 0}}
|
||||||
>
|
>
|
||||||
<div style={{color: colors.grey700, paddingTop: 1}}>
|
<div style={{color: colors.grey700, paddingTop: 1}}>
|
||||||
{this.state.stepIndex === LedgerSteps.CONNECT &&
|
{this.state.stepIndex === LedgerSteps.CONNECT &&
|
||||||
this.renderConnectStep()
|
this._renderConnectStep()
|
||||||
}
|
}
|
||||||
{this.state.stepIndex === LedgerSteps.SELECT_ADDRESS &&
|
{this.state.stepIndex === LedgerSteps.SELECT_ADDRESS &&
|
||||||
this.renderSelectAddressStep()
|
this._renderSelectAddressStep()
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderConnectStep() {
|
private _renderConnectStep() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="h4 pt3">
|
<div className="h4 pt3">
|
||||||
@@ -113,7 +113,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
labelReady="Connect to Ledger"
|
labelReady="Connect to Ledger"
|
||||||
labelLoading="Connecting..."
|
labelLoading="Connecting..."
|
||||||
labelComplete="Connected!"
|
labelComplete="Connected!"
|
||||||
onClickAsyncFn={this.onConnectLedgerClickAsync.bind(this, true)}
|
onClickAsyncFn={this._onConnectLedgerClickAsync.bind(this, true)}
|
||||||
/>
|
/>
|
||||||
{this.state.didConnectFail &&
|
{this.state.didConnectFail &&
|
||||||
<div className="pt2 left-align" style={{color: colors.red200}}>
|
<div className="pt2 left-align" style={{color: colors.red200}}>
|
||||||
@@ -124,13 +124,13 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderSelectAddressStep() {
|
private _renderSelectAddressStep() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<Table
|
<Table
|
||||||
bodyStyle={{height: 300}}
|
bodyStyle={{height: 300}}
|
||||||
onRowSelection={this.onAddressSelected.bind(this)}
|
onRowSelection={this._onAddressSelected.bind(this)}
|
||||||
>
|
>
|
||||||
<TableHeader displaySelectAll={false}>
|
<TableHeader displaySelectAll={false}>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
@@ -139,7 +139,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{this.renderAddressTableRows()}
|
{this._renderAddressTableRows()}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,7 +151,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
floatingLabelText="Update path derivation (advanced)"
|
floatingLabelText="Update path derivation (advanced)"
|
||||||
value={this.state.derivationPath}
|
value={this.state.derivationPath}
|
||||||
errorText={this.state.derivationErrMsg}
|
errorText={this.state.derivationErrMsg}
|
||||||
onChange={this.onDerivationPathChanged.bind(this)}
|
onChange={this._onDerivationPathChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pl2" style={{paddingTop: 28}}>
|
<div className="pl2" style={{paddingTop: 28}}>
|
||||||
@@ -159,14 +159,14 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
labelReady="Update"
|
labelReady="Update"
|
||||||
labelLoading="Updating..."
|
labelLoading="Updating..."
|
||||||
labelComplete="Updated!"
|
labelComplete="Updated!"
|
||||||
onClickAsyncFn={this.onFetchAddressesForDerivationPathAsync.bind(this, true)}
|
onClickAsyncFn={this._onFetchAddressesForDerivationPathAsync.bind(this, true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderAddressTableRows() {
|
private _renderAddressTableRows() {
|
||||||
const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => {
|
const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => {
|
||||||
const balance = this.state.addressBalances[i];
|
const balance = this.state.addressBalances[i];
|
||||||
const addressTooltipId = `address-${userAddress}`;
|
const addressTooltipId = `address-${userAddress}`;
|
||||||
@@ -201,14 +201,14 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
});
|
});
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
private onClose() {
|
private _onClose() {
|
||||||
this.setState({
|
this.setState({
|
||||||
didConnectFail: false,
|
didConnectFail: false,
|
||||||
});
|
});
|
||||||
const isOpen = false;
|
const isOpen = false;
|
||||||
this.props.toggleDialogFn(isOpen);
|
this.props.toggleDialogFn(isOpen);
|
||||||
}
|
}
|
||||||
private onAddressSelected(selectedRowIndexes: number[]) {
|
private _onAddressSelected(selectedRowIndexes: number[]) {
|
||||||
const selectedRowIndex = selectedRowIndexes[0];
|
const selectedRowIndex = selectedRowIndexes[0];
|
||||||
this.props.blockchain.updateLedgerDerivationIndex(selectedRowIndex);
|
this.props.blockchain.updateLedgerDerivationIndex(selectedRowIndex);
|
||||||
const selectedAddress = this.state.userAddresses[selectedRowIndex];
|
const selectedAddress = this.state.userAddresses[selectedRowIndex];
|
||||||
@@ -222,13 +222,13 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
const isOpen = false;
|
const isOpen = false;
|
||||||
this.props.toggleDialogFn(isOpen);
|
this.props.toggleDialogFn(isOpen);
|
||||||
}
|
}
|
||||||
private async onFetchAddressesForDerivationPathAsync() {
|
private async _onFetchAddressesForDerivationPathAsync() {
|
||||||
const currentlySetPath = this.props.blockchain.getLedgerDerivationPathIfExists();
|
const currentlySetPath = this.props.blockchain.getLedgerDerivationPathIfExists();
|
||||||
if (currentlySetPath === this.state.derivationPath) {
|
if (currentlySetPath === this.state.derivationPath) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.props.blockchain.updateLedgerDerivationPathIfExists(this.state.derivationPath);
|
this.props.blockchain.updateLedgerDerivationPathIfExists(this.state.derivationPath);
|
||||||
const didSucceed = await this.fetchAddressesAndBalancesAsync();
|
const didSucceed = await this._fetchAddressesAndBalancesAsync();
|
||||||
if (!didSucceed) {
|
if (!didSucceed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
derivationErrMsg: 'Failed to connect to Ledger.',
|
derivationErrMsg: 'Failed to connect to Ledger.',
|
||||||
@@ -236,11 +236,11 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
}
|
}
|
||||||
return didSucceed;
|
return didSucceed;
|
||||||
}
|
}
|
||||||
private async fetchAddressesAndBalancesAsync() {
|
private async _fetchAddressesAndBalancesAsync() {
|
||||||
let userAddresses: string[];
|
let userAddresses: string[];
|
||||||
const addressBalances: BigNumber[] = [];
|
const addressBalances: BigNumber[] = [];
|
||||||
try {
|
try {
|
||||||
userAddresses = await this.getUserAddressesAsync();
|
userAddresses = await this._getUserAddressesAsync();
|
||||||
for (const address of userAddresses) {
|
for (const address of userAddresses) {
|
||||||
const balance = await this.props.blockchain.getBalanceInEthAsync(address);
|
const balance = await this.props.blockchain.getBalanceInEthAsync(address);
|
||||||
addressBalances.push(balance);
|
addressBalances.push(balance);
|
||||||
@@ -258,7 +258,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
private onDerivationPathChanged(e: any, derivationPath: string) {
|
private _onDerivationPathChanged(e: any, derivationPath: string) {
|
||||||
let derivationErrMsg = '';
|
let derivationErrMsg = '';
|
||||||
if (!_.startsWith(derivationPath, VALID_ETHEREUM_DERIVATION_PATH_PREFIX)) {
|
if (!_.startsWith(derivationPath, VALID_ETHEREUM_DERIVATION_PATH_PREFIX)) {
|
||||||
derivationErrMsg = 'Must be valid Ethereum path.';
|
derivationErrMsg = 'Must be valid Ethereum path.';
|
||||||
@@ -269,8 +269,8 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
derivationErrMsg,
|
derivationErrMsg,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async onConnectLedgerClickAsync() {
|
private async _onConnectLedgerClickAsync() {
|
||||||
const didSucceed = await this.fetchAddressesAndBalancesAsync();
|
const didSucceed = await this._fetchAddressesAndBalancesAsync();
|
||||||
if (didSucceed) {
|
if (didSucceed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
stepIndex: LedgerSteps.SELECT_ADDRESS,
|
stepIndex: LedgerSteps.SELECT_ADDRESS,
|
||||||
@@ -278,7 +278,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
}
|
}
|
||||||
return didSucceed;
|
return didSucceed;
|
||||||
}
|
}
|
||||||
private async getUserAddressesAsync(): Promise<string[]> {
|
private async _getUserAddressesAsync(): Promise<string[]> {
|
||||||
let userAddresses: string[];
|
let userAddresses: string[];
|
||||||
userAddresses = await this.props.blockchain.getUserAccountsAsync();
|
userAddresses = await this.props.blockchain.getUserAccountsAsync();
|
||||||
|
|
||||||
|
@@ -36,14 +36,14 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
|||||||
<FlatButton
|
<FlatButton
|
||||||
key="cancelTransfer"
|
key="cancelTransfer"
|
||||||
label="Cancel"
|
label="Cancel"
|
||||||
onTouchTap={this.onCancel.bind(this)}
|
onTouchTap={this._onCancel.bind(this)}
|
||||||
/>,
|
/>,
|
||||||
<FlatButton
|
<FlatButton
|
||||||
key="sendTransfer"
|
key="sendTransfer"
|
||||||
disabled={this.hasErrors()}
|
disabled={this._hasErrors()}
|
||||||
label="Send"
|
label="Send"
|
||||||
primary={true}
|
primary={true}
|
||||||
onTouchTap={this.onSendClick.bind(this)}
|
onTouchTap={this._onSendClick.bind(this)}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
@@ -53,17 +53,17 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
|||||||
actions={transferDialogActions}
|
actions={transferDialogActions}
|
||||||
open={this.props.isOpen}
|
open={this.props.isOpen}
|
||||||
>
|
>
|
||||||
{this.renderSendDialogBody()}
|
{this._renderSendDialogBody()}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderSendDialogBody() {
|
private _renderSendDialogBody() {
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto" style={{maxWidth: 300}}>
|
<div className="mx-auto" style={{maxWidth: 300}}>
|
||||||
<div style={{height: 80}}>
|
<div style={{height: 80}}>
|
||||||
<AddressInput
|
<AddressInput
|
||||||
initialAddress={this.state.recipient}
|
initialAddress={this.state.recipient}
|
||||||
updateAddress={this.onRecipientChange.bind(this)}
|
updateAddress={this._onRecipientChange.bind(this)}
|
||||||
isRequired={true}
|
isRequired={true}
|
||||||
label={'Recipient address'}
|
label={'Recipient address'}
|
||||||
hintText={'Address'}
|
hintText={'Address'}
|
||||||
@@ -76,27 +76,27 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
|||||||
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||||
shouldCheckBalance={true}
|
shouldCheckBalance={true}
|
||||||
shouldCheckAllowance={false}
|
shouldCheckAllowance={false}
|
||||||
onChange={this.onValueChange.bind(this)}
|
onChange={this._onValueChange.bind(this)}
|
||||||
amount={this.state.value}
|
amount={this.state.value}
|
||||||
onVisitBalancesPageClick={this.props.onCancelled}
|
onVisitBalancesPageClick={this.props.onCancelled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onRecipientChange(recipient?: string) {
|
private _onRecipientChange(recipient?: string) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowIncompleteErrs: false,
|
shouldShowIncompleteErrs: false,
|
||||||
recipient,
|
recipient,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onValueChange(isValid: boolean, amount?: BigNumber) {
|
private _onValueChange(isValid: boolean, amount?: BigNumber) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isAmountValid: isValid,
|
isAmountValid: isValid,
|
||||||
value: amount,
|
value: amount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onSendClick() {
|
private _onSendClick() {
|
||||||
if (this.hasErrors()) {
|
if (this._hasErrors()) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowIncompleteErrs: true,
|
shouldShowIncompleteErrs: true,
|
||||||
});
|
});
|
||||||
@@ -109,13 +109,13 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState
|
|||||||
this.props.onComplete(this.state.recipient, value);
|
this.props.onComplete(this.state.recipient, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private onCancel() {
|
private _onCancel() {
|
||||||
this.setState({
|
this.setState({
|
||||||
value: undefined,
|
value: undefined,
|
||||||
});
|
});
|
||||||
this.props.onCancelled();
|
this.props.onCancelled();
|
||||||
}
|
}
|
||||||
private hasErrors() {
|
private _hasErrors() {
|
||||||
return _.isUndefined(this.state.recipient) ||
|
return _.isUndefined(this.state.recipient) ||
|
||||||
_.isUndefined(this.state.value) ||
|
_.isUndefined(this.state.value) ||
|
||||||
!this.state.isAmountValid;
|
!this.state.isAmountValid;
|
||||||
|
@@ -41,12 +41,12 @@ export class TrackTokenConfirmationDialog extends
|
|||||||
<FlatButton
|
<FlatButton
|
||||||
key="trackNo"
|
key="trackNo"
|
||||||
label="No"
|
label="No"
|
||||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, false)}
|
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, false)}
|
||||||
/>,
|
/>,
|
||||||
<FlatButton
|
<FlatButton
|
||||||
key="trackYes"
|
key="trackYes"
|
||||||
label="Yes"
|
label="Yes"
|
||||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, true)}
|
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, true)}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
open={this.props.isOpen}
|
open={this.props.isOpen}
|
||||||
@@ -64,7 +64,7 @@ export class TrackTokenConfirmationDialog extends
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private async onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
||||||
if (!didUserAcceptTracking) {
|
if (!didUserAcceptTracking) {
|
||||||
this.props.onToggleDialog(didUserAcceptTracking);
|
this.props.onToggleDialog(didUserAcceptTracking);
|
||||||
return;
|
return;
|
||||||
|
@@ -59,13 +59,13 @@ export class EthWethConversionButton extends
|
|||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
disabled={this.props.isDisabled || this.state.isEthConversionHappening}
|
disabled={this.props.isDisabled || this.state.isEthConversionHappening}
|
||||||
label={this.state.isEthConversionHappening ? inProgressLabel : callToActionLabel}
|
label={this.state.isEthConversionHappening ? inProgressLabel : callToActionLabel}
|
||||||
onClick={this.toggleConversionDialog.bind(this)}
|
onClick={this._toggleConversionDialog.bind(this)}
|
||||||
/>
|
/>
|
||||||
<EthWethConversionDialog
|
<EthWethConversionDialog
|
||||||
direction={this.props.direction}
|
direction={this.props.direction}
|
||||||
isOpen={this.state.isEthConversionDialogVisible}
|
isOpen={this.state.isEthConversionDialogVisible}
|
||||||
onComplete={this.onConversionAmountSelectedAsync.bind(this)}
|
onComplete={this._onConversionAmountSelectedAsync.bind(this)}
|
||||||
onCancelled={this.toggleConversionDialog.bind(this)}
|
onCancelled={this._toggleConversionDialog.bind(this)}
|
||||||
etherBalance={this.props.userEtherBalance}
|
etherBalance={this.props.userEtherBalance}
|
||||||
token={this.props.ethToken}
|
token={this.props.ethToken}
|
||||||
tokenState={this.props.ethTokenState}
|
tokenState={this.props.ethTokenState}
|
||||||
@@ -73,16 +73,16 @@ export class EthWethConversionButton extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private toggleConversionDialog() {
|
private _toggleConversionDialog() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isEthConversionDialogVisible: !this.state.isEthConversionDialogVisible,
|
isEthConversionDialogVisible: !this.state.isEthConversionDialogVisible,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async onConversionAmountSelectedAsync(direction: Side, value: BigNumber) {
|
private async _onConversionAmountSelectedAsync(direction: Side, value: BigNumber) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isEthConversionHappening: true,
|
isEthConversionHappening: true,
|
||||||
});
|
});
|
||||||
this.toggleConversionDialog();
|
this._toggleConversionDialog();
|
||||||
const token = this.props.ethToken;
|
const token = this.props.ethToken;
|
||||||
const tokenState = this.props.ethTokenState;
|
const tokenState = this.props.ethTokenState;
|
||||||
let balance = tokenState.balance;
|
let balance = tokenState.balance;
|
||||||
|
@@ -61,7 +61,7 @@ interface EthWrappersState {
|
|||||||
export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
|
export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
|
||||||
constructor(props: EthWrappersProps) {
|
constructor(props: EthWrappersProps) {
|
||||||
super(props);
|
super(props);
|
||||||
const outdatedWETHAddresses = this.getOutdatedWETHAddresses();
|
const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
|
||||||
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
|
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
|
||||||
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
||||||
_.each(outdatedWETHAddresses, outdatedWETHAddress => {
|
_.each(outdatedWETHAddresses, outdatedWETHAddress => {
|
||||||
@@ -79,7 +79,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.fetchOutdatedWETHStateAsync();
|
this._fetchOutdatedWETHStateAsync();
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
@@ -90,7 +90,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
const etherscanUrl = utils.getEtherScanLinkIfExists(
|
const etherscanUrl = utils.getEtherScanLinkIfExists(
|
||||||
etherToken.address, this.props.networkId, EtherscanLinkSuffixes.Address,
|
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 (
|
return (
|
||||||
<div className="clearfix lg-px4 md-px4 sm-px2" style={{minHeight: 600}}>
|
<div className="clearfix lg-px4 md-px4 sm-px2" style={{minHeight: 600}}>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -125,7 +125,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
<TableHeaderColumn>ETH Token</TableHeaderColumn>
|
<TableHeaderColumn>ETH Token</TableHeaderColumn>
|
||||||
<TableHeaderColumn>Balance</TableHeaderColumn>
|
<TableHeaderColumn>Balance</TableHeaderColumn>
|
||||||
<TableHeaderColumn className="center">
|
<TableHeaderColumn className="center">
|
||||||
{this.renderActionColumnTitle(isBidirectional)}
|
{this._renderActionColumnTitle(isBidirectional)}
|
||||||
</TableHeaderColumn>
|
</TableHeaderColumn>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
@@ -162,7 +162,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow key="WETH">
|
<TableRow key="WETH">
|
||||||
<TableRowColumn className="py1">
|
<TableRowColumn className="py1">
|
||||||
{this.renderTokenLink(tokenLabel, etherscanUrl)}
|
{this._renderTokenLink(tokenLabel, etherscanUrl)}
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn>
|
<TableRowColumn>
|
||||||
{wethBalance.toFixed(PRECISION)} WETH
|
{wethBalance.toFixed(PRECISION)} WETH
|
||||||
@@ -207,12 +207,12 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
<TableHeaderColumn>WETH Version</TableHeaderColumn>
|
<TableHeaderColumn>WETH Version</TableHeaderColumn>
|
||||||
<TableHeaderColumn>Balance</TableHeaderColumn>
|
<TableHeaderColumn>Balance</TableHeaderColumn>
|
||||||
<TableHeaderColumn className="center">
|
<TableHeaderColumn className="center">
|
||||||
{this.renderActionColumnTitle(!isBidirectional)}
|
{this._renderActionColumnTitle(!isBidirectional)}
|
||||||
</TableHeaderColumn>
|
</TableHeaderColumn>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody displayRowCheckbox={false}>
|
<TableBody displayRowCheckbox={false}>
|
||||||
{this.renderOutdatedWeths(etherToken, etherTokenState)}
|
{this._renderOutdatedWeths(etherToken, etherTokenState)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
@@ -220,7 +220,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderActionColumnTitle(isBidirectional: boolean) {
|
private _renderActionColumnTitle(isBidirectional: boolean) {
|
||||||
let iconClass = 'zmdi-long-arrow-right';
|
let iconClass = 'zmdi-long-arrow-right';
|
||||||
let leftSymbol = 'WETH';
|
let leftSymbol = 'WETH';
|
||||||
let rightSymbol = 'ETH';
|
let rightSymbol = 'ETH';
|
||||||
@@ -242,7 +242,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderOutdatedWeths(etherToken: Token, etherTokenState: TokenState) {
|
private _renderOutdatedWeths(etherToken: Token, etherTokenState: TokenState) {
|
||||||
const rows = _.map(configs.OUTDATED_WRAPPED_ETHERS,
|
const rows = _.map(configs.OUTDATED_WRAPPED_ETHERS,
|
||||||
(outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => {
|
(outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => {
|
||||||
const outdatedWETHIfExists = outdatedWETHByNetworkId[this.props.networkId];
|
const outdatedWETHIfExists = outdatedWETHByNetworkId[this.props.networkId];
|
||||||
@@ -269,17 +269,17 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH,
|
outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH,
|
||||||
).toFixed(PRECISION) :
|
).toFixed(PRECISION) :
|
||||||
undefined;
|
undefined;
|
||||||
const onConversionSuccessful = this.onOutdatedConversionSuccessfulAsync.bind(
|
const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind(
|
||||||
this, outdatedWETHIfExists.address,
|
this, outdatedWETHIfExists.address,
|
||||||
);
|
);
|
||||||
const etherscanUrl = utils.getEtherScanLinkIfExists(
|
const etherscanUrl = utils.getEtherScanLinkIfExists(
|
||||||
outdatedWETHIfExists.address, this.props.networkId, EtherscanLinkSuffixes.Address,
|
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 (
|
return (
|
||||||
<TableRow key={`weth-${outdatedWETHIfExists.address}`}>
|
<TableRow key={`weth-${outdatedWETHIfExists.address}`}>
|
||||||
<TableRowColumn className="py1">
|
<TableRowColumn className="py1">
|
||||||
{this.renderTokenLink(tokenLabel, etherscanUrl)}
|
{this._renderTokenLink(tokenLabel, etherscanUrl)}
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn>
|
<TableRowColumn>
|
||||||
{isStateLoaded ?
|
{isStateLoaded ?
|
||||||
@@ -305,7 +305,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
});
|
});
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
private renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string) {
|
private _renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{_.isUndefined(etherscanUrl) ?
|
{_.isUndefined(etherscanUrl) ?
|
||||||
@@ -317,7 +317,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderToken(name: string, address: string, imgPath: string) {
|
private _renderToken(name: string, address: string, imgPath: string) {
|
||||||
const tooltipId = `tooltip-${address}`;
|
const tooltipId = `tooltip-${address}`;
|
||||||
return (
|
return (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
@@ -340,7 +340,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private async onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) {
|
private async _onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) {
|
||||||
this.setState({
|
this.setState({
|
||||||
outdatedWETHAddressToIsStateLoaded: {
|
outdatedWETHAddressToIsStateLoaded: {
|
||||||
...this.state.outdatedWETHAddressToIsStateLoaded,
|
...this.state.outdatedWETHAddressToIsStateLoaded,
|
||||||
@@ -364,8 +364,8 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async fetchOutdatedWETHStateAsync() {
|
private async _fetchOutdatedWETHStateAsync() {
|
||||||
const outdatedWETHAddresses = this.getOutdatedWETHAddresses();
|
const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
|
||||||
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
|
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
|
||||||
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
||||||
for (const address of outdatedWETHAddresses) {
|
for (const address of outdatedWETHAddresses) {
|
||||||
@@ -383,7 +383,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
outdatedWETHAddressToIsStateLoaded,
|
outdatedWETHAddressToIsStateLoaded,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private getOutdatedWETHAddresses(): string[] {
|
private _getOutdatedWETHAddresses(): string[] {
|
||||||
const outdatedWETHAddresses = _.compact(_.map(configs.OUTDATED_WRAPPED_ETHERS,
|
const outdatedWETHAddresses = _.compact(_.map(configs.OUTDATED_WRAPPED_ETHERS,
|
||||||
outdatedWrappedEtherByNetwork => {
|
outdatedWrappedEtherByNetwork => {
|
||||||
const outdatedWrappedEtherIfExists = outdatedWrappedEtherByNetwork[this.props.networkId];
|
const outdatedWrappedEtherIfExists = outdatedWrappedEtherByNetwork[this.props.networkId];
|
||||||
|
@@ -66,7 +66,7 @@ interface FillOrderState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
||||||
private validator: SchemaValidator;
|
private _validator: SchemaValidator;
|
||||||
constructor(props: FillOrderProps) {
|
constructor(props: FillOrderProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -87,12 +87,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
isConfirmingTokenTracking: false,
|
isConfirmingTokenTracking: false,
|
||||||
tokensToTrack: [],
|
tokensToTrack: [],
|
||||||
};
|
};
|
||||||
this.validator = new SchemaValidator();
|
this._validator = new SchemaValidator();
|
||||||
}
|
}
|
||||||
public componentWillMount() {
|
public componentWillMount() {
|
||||||
if (!_.isEmpty(this.state.orderJSON)) {
|
if (!_.isEmpty(this.state.orderJSON)) {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.validateFillOrderFireAndForgetAsync(this.state.orderJSON);
|
this._validateFillOrderFireAndForgetAsync(this.state.orderJSON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
@@ -115,15 +115,15 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
networkId={this.props.networkId}
|
networkId={this.props.networkId}
|
||||||
orderJSON={this.state.orderJSON}
|
orderJSON={this.state.orderJSON}
|
||||||
onFillOrderJSONChanged={this.onFillOrderJSONChanged.bind(this)}
|
onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
{this.renderOrderJsonNotices()}
|
{this._renderOrderJsonNotices()}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div>
|
<div>
|
||||||
{!_.isUndefined(this.state.parsedOrder) && this.state.didOrderValidationRun
|
{!_.isUndefined(this.state.parsedOrder) && this.state.didOrderValidationRun
|
||||||
&& this.state.areAllInvolvedTokensTracked &&
|
&& this.state.areAllInvolvedTokensTracked &&
|
||||||
this.renderVisualOrder()
|
this._renderVisualOrder()
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{this.props.isOrderInUrl &&
|
{this.props.isOrderInUrl &&
|
||||||
@@ -140,17 +140,17 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
networkId={this.props.networkId}
|
networkId={this.props.networkId}
|
||||||
orderJSON={this.state.orderJSON}
|
orderJSON={this.state.orderJSON}
|
||||||
onFillOrderJSONChanged={this.onFillOrderJSONChanged.bind(this)}
|
onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
</CardText>
|
</CardText>
|
||||||
</Card>
|
</Card>
|
||||||
{this.renderOrderJsonNotices()}
|
{this._renderOrderJsonNotices()}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<FillWarningDialog
|
<FillWarningDialog
|
||||||
isOpen={this.state.isFillWarningDialogOpen}
|
isOpen={this.state.isFillWarningDialogOpen}
|
||||||
onToggleDialog={this.onFillWarningClosed.bind(this)}
|
onToggleDialog={this._onFillWarningClosed.bind(this)}
|
||||||
/>
|
/>
|
||||||
<TrackTokenConfirmationDialog
|
<TrackTokenConfirmationDialog
|
||||||
userAddress={this.props.userAddress}
|
userAddress={this.props.userAddress}
|
||||||
@@ -160,12 +160,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
tokens={this.state.tokensToTrack}
|
tokens={this.state.tokensToTrack}
|
||||||
isOpen={this.state.isConfirmingTokenTracking}
|
isOpen={this.state.isConfirmingTokenTracking}
|
||||||
onToggleDialog={this.onToggleTrackConfirmDialog.bind(this)}
|
onToggleDialog={this._onToggleTrackConfirmDialog.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderOrderJsonNotices() {
|
private _renderOrderJsonNotices() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{!_.isUndefined(this.props.initialOrder) && !this.state.didOrderValidationRun &&
|
{!_.isUndefined(this.props.initialOrder) && !this.state.didOrderValidationRun &&
|
||||||
@@ -182,7 +182,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderVisualOrder() {
|
private _renderVisualOrder() {
|
||||||
const takerTokenAddress = this.state.parsedOrder.taker.token.address;
|
const takerTokenAddress = this.state.parsedOrder.taker.token.address;
|
||||||
const takerToken = this.props.tokenByAddress[takerTokenAddress];
|
const takerToken = this.props.tokenByAddress[takerTokenAddress];
|
||||||
const orderTakerAmount = new BigNumber(this.state.parsedOrder.taker.amount);
|
const orderTakerAmount = new BigNumber(this.state.parsedOrder.taker.amount);
|
||||||
@@ -211,7 +211,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
let orderReceiveAmount = 0;
|
let orderReceiveAmount = 0;
|
||||||
if (!_.isUndefined(this.props.orderFillAmount)) {
|
if (!_.isUndefined(this.props.orderFillAmount)) {
|
||||||
const orderReceiveAmountBigNumber = exchangeRate.mul(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) &&
|
const isUserMaker = !_.isUndefined(this.state.parsedOrder) &&
|
||||||
this.state.parsedOrder.maker.address === this.props.userAddress;
|
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}}>
|
<div className="clearfix mx-auto relative" style={{width: 235, height: 108}}>
|
||||||
<TokenAmountInput
|
<TokenAmountInput
|
||||||
label="Fill amount"
|
label="Fill amount"
|
||||||
onChange={this.onFillAmountChange.bind(this)}
|
onChange={this._onFillAmountChange.bind(this)}
|
||||||
shouldShowIncompleteErrs={false}
|
shouldShowIncompleteErrs={false}
|
||||||
token={fillToken}
|
token={fillToken}
|
||||||
tokenState={fillTokenState}
|
tokenState={fillTokenState}
|
||||||
@@ -284,12 +284,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
style={{width: '100%'}}
|
style={{width: '100%'}}
|
||||||
disabled={this.state.isCancelling}
|
disabled={this.state.isCancelling}
|
||||||
label={this.state.isCancelling ? 'Cancelling order...' : 'Cancel order'}
|
label={this.state.isCancelling ? 'Cancelling order...' : 'Cancel order'}
|
||||||
onClick={this.onCancelOrderClickFireAndForgetAsync.bind(this)}
|
onClick={this._onCancelOrderClickFireAndForgetAsync.bind(this)}
|
||||||
/>
|
/>
|
||||||
{this.state.didCancelOrderSucceed &&
|
{this.state.didCancelOrderSucceed &&
|
||||||
<Alert
|
<Alert
|
||||||
type={AlertTypes.SUCCESS}
|
type={AlertTypes.SUCCESS}
|
||||||
message={this.renderCancelSuccessMsg()}
|
message={this._renderCancelSuccessMsg()}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div> :
|
</div> :
|
||||||
@@ -298,7 +298,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
style={{width: '100%'}}
|
style={{width: '100%'}}
|
||||||
disabled={this.state.isFilling}
|
disabled={this.state.isFilling}
|
||||||
label={this.state.isFilling ? 'Filling order...' : 'Fill order'}
|
label={this.state.isFilling ? 'Filling order...' : 'Fill order'}
|
||||||
onClick={this.onFillOrderClick.bind(this)}
|
onClick={this._onFillOrderClick.bind(this)}
|
||||||
/>
|
/>
|
||||||
{!_.isEmpty(this.state.globalErrMsg) &&
|
{!_.isEmpty(this.state.globalErrMsg) &&
|
||||||
<Alert type={AlertTypes.ERROR} message={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 &&
|
{this.state.didFillOrderSucceed &&
|
||||||
<Alert
|
<Alert
|
||||||
type={AlertTypes.SUCCESS}
|
type={AlertTypes.SUCCESS}
|
||||||
message={this.renderFillSuccessMsg()}
|
message={this._renderFillSuccessMsg()}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -315,7 +315,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderFillSuccessMsg() {
|
private _renderFillSuccessMsg() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Order successfully filled. See the trade details in your{' '}
|
Order successfully filled. See the trade details in your{' '}
|
||||||
@@ -328,45 +328,45 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderCancelSuccessMsg() {
|
private _renderCancelSuccessMsg() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Order successfully cancelled.
|
Order successfully cancelled.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onFillOrderClick() {
|
private _onFillOrderClick() {
|
||||||
if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) {
|
if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isFillWarningDialogOpen: true,
|
isFillWarningDialogOpen: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.onFillOrderClickFireAndForgetAsync();
|
this._onFillOrderClickFireAndForgetAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private onFillWarningClosed(didUserCancel: boolean) {
|
private _onFillWarningClosed(didUserCancel: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isFillWarningDialogOpen: false,
|
isFillWarningDialogOpen: false,
|
||||||
});
|
});
|
||||||
if (!didUserCancel) {
|
if (!didUserCancel) {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// 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);
|
this.props.dispatcher.updateOrderFillAmount(amount);
|
||||||
}
|
}
|
||||||
private onFillOrderJSONChanged(event: any) {
|
private _onFillOrderJSONChanged(event: any) {
|
||||||
const orderJSON = event.target.value;
|
const orderJSON = event.target.value;
|
||||||
this.setState({
|
this.setState({
|
||||||
didOrderValidationRun: _.isEmpty(orderJSON) && _.isEmpty(this.state.orderJSONErrMsg),
|
didOrderValidationRun: _.isEmpty(orderJSON) && _.isEmpty(this.state.orderJSONErrMsg),
|
||||||
didFillOrderSucceed: false,
|
didFillOrderSucceed: false,
|
||||||
});
|
});
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.validateFillOrderFireAndForgetAsync(orderJSON);
|
this._validateFillOrderFireAndForgetAsync(orderJSON);
|
||||||
}
|
}
|
||||||
private async checkForUntrackedTokensAndAskToAdd() {
|
private async _checkForUntrackedTokensAndAskToAdd() {
|
||||||
if (!_.isEmpty(this.state.orderJSONErrMsg)) {
|
if (!_.isEmpty(this.state.orderJSONErrMsg)) {
|
||||||
return;
|
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 orderJSONErrMsg = '';
|
||||||
let parsedOrder: Order;
|
let parsedOrder: Order;
|
||||||
try {
|
try {
|
||||||
const order = JSON.parse(orderJSON);
|
const order = JSON.parse(orderJSON);
|
||||||
const validationResult = this.validator.validate(order, orderSchema);
|
const validationResult = this._validator.validate(order, orderSchema);
|
||||||
if (validationResult.errors.length > 0) {
|
if (validationResult.errors.length > 0) {
|
||||||
orderJSONErrMsg = 'Submitted order JSON is not a valid order';
|
orderJSONErrMsg = 'Submitted order JSON is not a valid order';
|
||||||
utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`);
|
utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`);
|
||||||
@@ -508,9 +508,9 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
unavailableTakerAmount,
|
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)) {
|
if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
return;
|
return;
|
||||||
@@ -601,7 +601,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async onCancelOrderClickFireAndForgetAsync(): Promise<void> {
|
private async _onCancelOrderClickFireAndForgetAsync(): Promise<void> {
|
||||||
if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) {
|
if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
return;
|
return;
|
||||||
@@ -684,12 +684,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private formatCurrencyAmount(amount: BigNumber, decimals: number): number {
|
private _formatCurrencyAmount(amount: BigNumber, decimals: number): number {
|
||||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||||
const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000;
|
const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000;
|
||||||
return roundedUnitAmount;
|
return roundedUnitAmount;
|
||||||
}
|
}
|
||||||
private onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) {
|
private _onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) {
|
||||||
if (!didConfirmTokenTracking) {
|
if (!didConfirmTokenTracking) {
|
||||||
this.setState({
|
this.setState({
|
||||||
orderJSON: '',
|
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-8 md-col-8 col-12 lg-pl4 md-pl4">
|
||||||
<div className="col lg-col-4 md-col-4 col-12">
|
<div className="col lg-col-4 md-col-4 col-12">
|
||||||
<div className="lg-right md-right sm-center">
|
<div className="lg-right md-right sm-center">
|
||||||
{this.renderHeader(Sections.Documentation)}
|
{this._renderHeader(Sections.Documentation)}
|
||||||
{_.map(menuItemsBySection[Sections.Documentation], this.renderMenuItem.bind(this))}
|
{_.map(menuItemsBySection[Sections.Documentation], this._renderMenuItem.bind(this))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
|
<div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2">
|
||||||
<div className="lg-right md-right sm-center">
|
<div className="lg-right md-right sm-center">
|
||||||
{this.renderHeader(Sections.Community)}
|
{this._renderHeader(Sections.Community)}
|
||||||
{_.map(menuItemsBySection[Sections.Community], this.renderMenuItem.bind(this))}
|
{_.map(menuItemsBySection[Sections.Community], this._renderMenuItem.bind(this))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col lg-col-4 md-col-4 col-12">
|
<div className="col lg-col-4 md-col-4 col-12">
|
||||||
<div className="lg-right md-right sm-center">
|
<div className="lg-right md-right sm-center">
|
||||||
{this.renderHeader(Sections.Organization)}
|
{this._renderHeader(Sections.Organization)}
|
||||||
{_.map(menuItemsBySection[Sections.Organization], this.renderMenuItem.bind(this))}
|
{_.map(menuItemsBySection[Sections.Organization], this._renderMenuItem.bind(this))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,14 +154,14 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderIcon(fileName: string) {
|
private _renderIcon(fileName: string) {
|
||||||
return (
|
return (
|
||||||
<div style={{height: ICON_DIMENSION, width: ICON_DIMENSION}}>
|
<div style={{height: ICON_DIMENSION, width: ICON_DIMENSION}}>
|
||||||
<img src={`/images/social/${fileName}`} style={{width: ICON_DIMENSION}} />
|
<img src={`/images/social/${fileName}`} style={{width: ICON_DIMENSION}} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderMenuItem(item: FooterMenuItem) {
|
private _renderMenuItem(item: FooterMenuItem) {
|
||||||
const iconIfExists = titleToIcon[item.title];
|
const iconIfExists = titleToIcon[item.title];
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -180,7 +180,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
|||||||
<div className="sm-mx-auto" style={{width: 65}}>
|
<div className="sm-mx-auto" style={{width: 65}}>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="pr1">
|
<div className="pr1">
|
||||||
{this.renderIcon(iconIfExists)}
|
{this._renderIcon(iconIfExists)}
|
||||||
</div>
|
</div>
|
||||||
<div>{item.title}</div>
|
<div>{item.title}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -196,7 +196,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
|||||||
<div>
|
<div>
|
||||||
{!_.isUndefined(iconIfExists) &&
|
{!_.isUndefined(iconIfExists) &&
|
||||||
<div className="pr1">
|
<div className="pr1">
|
||||||
{this.renderIcon(iconIfExists)}
|
{this._renderIcon(iconIfExists)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{item.title}
|
{item.title}
|
||||||
@@ -206,7 +206,7 @@ export class Footer extends React.Component<FooterProps, FooterState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderHeader(title: string) {
|
private _renderHeader(title: string) {
|
||||||
const headerStyle = {
|
const headerStyle = {
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
color: colors.grey400,
|
color: colors.grey400,
|
||||||
|
@@ -47,7 +47,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
public static defaultProps: Partial<AssetPickerProps> = {
|
public static defaultProps: Partial<AssetPickerProps> = {
|
||||||
tokenVisibility: TokenVisibility.ALL,
|
tokenVisibility: TokenVisibility.ALL,
|
||||||
};
|
};
|
||||||
private dialogConfigsByAssetView: {[assetView: string]: DialogConfigs};
|
private _dialogConfigsByAssetView: {[assetView: string]: DialogConfigs};
|
||||||
constructor(props: AssetPickerProps) {
|
constructor(props: AssetPickerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -56,7 +56,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
chosenTrackTokenAddress: undefined,
|
chosenTrackTokenAddress: undefined,
|
||||||
isAddingTokenToTracked: false,
|
isAddingTokenToTracked: false,
|
||||||
};
|
};
|
||||||
this.dialogConfigsByAssetView = {
|
this._dialogConfigsByAssetView = {
|
||||||
[AssetViews.ASSET_PICKER]: {
|
[AssetViews.ASSET_PICKER]: {
|
||||||
title: 'Select token',
|
title: 'Select token',
|
||||||
isModal: false,
|
isModal: false,
|
||||||
@@ -74,19 +74,19 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
<FlatButton
|
<FlatButton
|
||||||
key="noTracking"
|
key="noTracking"
|
||||||
label="No"
|
label="No"
|
||||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, false)}
|
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, false)}
|
||||||
/>,
|
/>,
|
||||||
<FlatButton
|
<FlatButton
|
||||||
key="yesTrack"
|
key="yesTrack"
|
||||||
label="Yes"
|
label="Yes"
|
||||||
onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, true)}
|
onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, true)}
|
||||||
/>,
|
/>,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const dialogConfigs: DialogConfigs = this.dialogConfigsByAssetView[this.state.assetView];
|
const dialogConfigs: DialogConfigs = this._dialogConfigsByAssetView[this.state.assetView];
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
title={dialogConfigs.title}
|
title={dialogConfigs.title}
|
||||||
@@ -94,25 +94,25 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
modal={dialogConfigs.isModal}
|
modal={dialogConfigs.isModal}
|
||||||
open={this.props.isOpen}
|
open={this.props.isOpen}
|
||||||
actions={dialogConfigs.actions}
|
actions={dialogConfigs.actions}
|
||||||
onRequestClose={this.onCloseDialog.bind(this)}
|
onRequestClose={this._onCloseDialog.bind(this)}
|
||||||
>
|
>
|
||||||
{this.state.assetView === AssetViews.ASSET_PICKER &&
|
{this.state.assetView === AssetViews.ASSET_PICKER &&
|
||||||
this.renderAssetPicker()
|
this._renderAssetPicker()
|
||||||
}
|
}
|
||||||
{this.state.assetView === AssetViews.NEW_TOKEN_FORM &&
|
{this.state.assetView === AssetViews.NEW_TOKEN_FORM &&
|
||||||
<NewTokenForm
|
<NewTokenForm
|
||||||
blockchain={this.props.blockchain}
|
blockchain={this.props.blockchain}
|
||||||
onNewTokenSubmitted={this.onNewTokenSubmitted.bind(this)}
|
onNewTokenSubmitted={this._onNewTokenSubmitted.bind(this)}
|
||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{this.state.assetView === AssetViews.CONFIRM_TRACK_TOKEN &&
|
{this.state.assetView === AssetViews.CONFIRM_TRACK_TOKEN &&
|
||||||
this.renderConfirmTrackToken()
|
this._renderConfirmTrackToken()
|
||||||
}
|
}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderConfirmTrackToken() {
|
private _renderConfirmTrackToken() {
|
||||||
const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress];
|
const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress];
|
||||||
return (
|
return (
|
||||||
<TrackTokenConfirmation
|
<TrackTokenConfirmation
|
||||||
@@ -123,17 +123,17 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderAssetPicker() {
|
private _renderAssetPicker() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="clearfix flex flex-wrap"
|
className="clearfix flex flex-wrap"
|
||||||
style={{overflowY: 'auto', maxWidth: 720, maxHeight: 356, marginBottom: 10}}
|
style={{overflowY: 'auto', maxWidth: 720, maxHeight: 356, marginBottom: 10}}
|
||||||
>
|
>
|
||||||
{this.renderGridTiles()}
|
{this._renderGridTiles()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderGridTiles() {
|
private _renderGridTiles() {
|
||||||
let isHovered;
|
let isHovered;
|
||||||
let tileStyles;
|
let tileStyles;
|
||||||
const gridTiles = _.map(this.props.tokenByAddress, (token: Token, address: string) => {
|
const gridTiles = _.map(this.props.tokenByAddress, (token: Token, address: string) => {
|
||||||
@@ -151,9 +151,9 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
key={address}
|
key={address}
|
||||||
style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}}
|
style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}}
|
||||||
className="p2 mx-auto"
|
className="p2 mx-auto"
|
||||||
onClick={this.onChooseToken.bind(this, address)}
|
onClick={this._onChooseToken.bind(this, address)}
|
||||||
onMouseEnter={this.onToggleHover.bind(this, address, true)}
|
onMouseEnter={this._onToggleHover.bind(this, address, true)}
|
||||||
onMouseLeave={this.onToggleHover.bind(this, address, false)}
|
onMouseLeave={this._onToggleHover.bind(this, address, false)}
|
||||||
>
|
>
|
||||||
<div className="p1 center">
|
<div className="p1 center">
|
||||||
<TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} />
|
<TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} />
|
||||||
@@ -174,9 +174,9 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
key={otherTokenKey}
|
key={otherTokenKey}
|
||||||
style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}}
|
style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}}
|
||||||
className="p2 mx-auto"
|
className="p2 mx-auto"
|
||||||
onClick={this.onCustomAssetChosen.bind(this)}
|
onClick={this._onCustomAssetChosen.bind(this)}
|
||||||
onMouseEnter={this.onToggleHover.bind(this, otherTokenKey, true)}
|
onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)}
|
||||||
onMouseLeave={this.onToggleHover.bind(this, otherTokenKey, false)}
|
onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)}
|
||||||
>
|
>
|
||||||
<div className="p1 center">
|
<div className="p1 center">
|
||||||
<i
|
<i
|
||||||
@@ -190,19 +190,19 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
}
|
}
|
||||||
return gridTiles;
|
return gridTiles;
|
||||||
}
|
}
|
||||||
private onToggleHover(address: string, isHovered: boolean) {
|
private _onToggleHover(address: string, isHovered: boolean) {
|
||||||
const hoveredAddress = isHovered ? address : undefined;
|
const hoveredAddress = isHovered ? address : undefined;
|
||||||
this.setState({
|
this.setState({
|
||||||
hoveredAddress,
|
hoveredAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onCloseDialog() {
|
private _onCloseDialog() {
|
||||||
this.setState({
|
this.setState({
|
||||||
assetView: AssetViews.ASSET_PICKER,
|
assetView: AssetViews.ASSET_PICKER,
|
||||||
});
|
});
|
||||||
this.props.onTokenChosen(this.props.currentTokenAddress);
|
this.props.onTokenChosen(this.props.currentTokenAddress);
|
||||||
}
|
}
|
||||||
private onChooseToken(tokenAddress: string) {
|
private _onChooseToken(tokenAddress: string) {
|
||||||
const token = this.props.tokenByAddress[tokenAddress];
|
const token = this.props.tokenByAddress[tokenAddress];
|
||||||
if (token.isTracked) {
|
if (token.isTracked) {
|
||||||
this.props.onTokenChosen(tokenAddress);
|
this.props.onTokenChosen(tokenAddress);
|
||||||
@@ -213,12 +213,12 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private onCustomAssetChosen() {
|
private _onCustomAssetChosen() {
|
||||||
this.setState({
|
this.setState({
|
||||||
assetView: AssetViews.NEW_TOKEN_FORM,
|
assetView: AssetViews.NEW_TOKEN_FORM,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onNewTokenSubmitted(newToken: Token, newTokenState: TokenState) {
|
private _onNewTokenSubmitted(newToken: Token, newTokenState: TokenState) {
|
||||||
this.props.dispatcher.updateTokenStateByAddress({
|
this.props.dispatcher.updateTokenStateByAddress({
|
||||||
[newToken.address]: newTokenState,
|
[newToken.address]: newTokenState,
|
||||||
});
|
});
|
||||||
@@ -229,14 +229,14 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt
|
|||||||
});
|
});
|
||||||
this.props.onTokenChosen(newToken.address);
|
this.props.onTokenChosen(newToken.address);
|
||||||
}
|
}
|
||||||
private async onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) {
|
||||||
if (!didUserAcceptTracking) {
|
if (!didUserAcceptTracking) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isAddingTokenToTracked: false,
|
isAddingTokenToTracked: false,
|
||||||
assetView: AssetViews.ASSET_PICKER,
|
assetView: AssetViews.ASSET_PICKER,
|
||||||
chosenTrackTokenAddress: undefined,
|
chosenTrackTokenAddress: undefined,
|
||||||
});
|
});
|
||||||
this.onCloseDialog();
|
this._onCloseDialog();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@@ -63,7 +63,7 @@ interface GenerateOrderFormState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> {
|
export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> {
|
||||||
private validator: SchemaValidator;
|
private _validator: SchemaValidator;
|
||||||
constructor(props: GenerateOrderFormProps) {
|
constructor(props: GenerateOrderFormProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -71,7 +71,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
shouldShowIncompleteErrs: false,
|
shouldShowIncompleteErrs: false,
|
||||||
signingState: SigningState.UNSIGNED,
|
signingState: SigningState.UNSIGNED,
|
||||||
};
|
};
|
||||||
this.validator = new SchemaValidator();
|
this._validator = new SchemaValidator();
|
||||||
}
|
}
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
@@ -113,7 +113,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
token={depositToken}
|
token={depositToken}
|
||||||
tokenState={depositTokenState}
|
tokenState={depositTokenState}
|
||||||
amount={this.props.sideToAssetToken[Side.Deposit].amount}
|
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}
|
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||||
shouldCheckBalance={true}
|
shouldCheckBalance={true}
|
||||||
shouldCheckAllowance={true}
|
shouldCheckAllowance={true}
|
||||||
@@ -144,7 +144,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
token={receiveToken}
|
token={receiveToken}
|
||||||
tokenState={receiveTokenState}
|
tokenState={receiveTokenState}
|
||||||
amount={this.props.sideToAssetToken[Side.Receive].amount}
|
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}
|
shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
|
||||||
shouldCheckBalance={false}
|
shouldCheckBalance={false}
|
||||||
shouldCheckAllowance={false}
|
shouldCheckAllowance={false}
|
||||||
@@ -165,7 +165,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
<IdenticonAddressInput
|
<IdenticonAddressInput
|
||||||
label="Taker"
|
label="Taker"
|
||||||
initialAddress={this.props.orderTakerAddress}
|
initialAddress={this.props.orderTakerAddress}
|
||||||
updateOrderAddress={this.updateOrderAddress.bind(this)}
|
updateOrderAddress={this._updateOrderAddress.bind(this)}
|
||||||
/>
|
/>
|
||||||
<div className="pt3">
|
<div className="pt3">
|
||||||
<div className="pl1">
|
<div className="pl1">
|
||||||
@@ -189,7 +189,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
labelReady="Sign hash"
|
labelReady="Sign hash"
|
||||||
labelLoading="Signing..."
|
labelLoading="Signing..."
|
||||||
labelComplete="Hash signed!"
|
labelComplete="Hash signed!"
|
||||||
onClickAsyncFn={this.onSignClickedAsync.bind(this)}
|
onClickAsyncFn={this._onSignClickedAsync.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.state.globalErrMsg !== '' &&
|
{this.state.globalErrMsg !== '' &&
|
||||||
@@ -202,7 +202,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
titleStyle={{fontWeight: 100}}
|
titleStyle={{fontWeight: 100}}
|
||||||
modal={false}
|
modal={false}
|
||||||
open={this.state.signingState === SigningState.SIGNED}
|
open={this.state.signingState === SigningState.SIGNED}
|
||||||
onRequestClose={this.onCloseOrderJSONDialog.bind(this)}
|
onRequestClose={this._onCloseOrderJSONDialog.bind(this)}
|
||||||
>
|
>
|
||||||
<OrderJSON
|
<OrderJSON
|
||||||
exchangeContractIfExists={exchangeContractIfExists}
|
exchangeContractIfExists={exchangeContractIfExists}
|
||||||
@@ -222,10 +222,10 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
</div>
|
</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});
|
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
|
// 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
|
// 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.
|
// orderHash will not collide with the previously generated orderHash.
|
||||||
@@ -234,7 +234,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
signingState: SigningState.UNSIGNED,
|
signingState: SigningState.UNSIGNED,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async onSignClickedAsync(): Promise<boolean> {
|
private async _onSignClickedAsync(): Promise<boolean> {
|
||||||
if (this.props.blockchainErr !== BlockchainErrs.NoError) {
|
if (this.props.blockchainErr !== BlockchainErrs.NoError) {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
return false;
|
return false;
|
||||||
@@ -249,7 +249,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
debitToken.amount.gt(0) && receiveAmount.gt(0) &&
|
debitToken.amount.gt(0) && receiveAmount.gt(0) &&
|
||||||
this.props.userAddress !== '' &&
|
this.props.userAddress !== '' &&
|
||||||
debitBalance.gte(debitToken.amount) && debitAllowance.gte(debitToken.amount)) {
|
debitBalance.gte(debitToken.amount) && debitAllowance.gte(debitToken.amount)) {
|
||||||
const didSignSuccessfully = await this.signTransactionAsync();
|
const didSignSuccessfully = await this._signTransactionAsync();
|
||||||
if (didSignSuccessfully) {
|
if (didSignSuccessfully) {
|
||||||
this.setState({
|
this.setState({
|
||||||
globalErrMsg: '',
|
globalErrMsg: '',
|
||||||
@@ -270,7 +270,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async signTransactionAsync(): Promise<boolean> {
|
private async _signTransactionAsync(): Promise<boolean> {
|
||||||
this.setState({
|
this.setState({
|
||||||
signingState: SigningState.SIGNING,
|
signingState: SigningState.SIGNING,
|
||||||
});
|
});
|
||||||
@@ -308,7 +308,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
this.props.userAddress, hashData.makerFee, hashData.takerFee,
|
this.props.userAddress, hashData.makerFee, hashData.takerFee,
|
||||||
hashData.feeRecipientAddress, signatureData, this.props.tokenByAddress,
|
hashData.feeRecipientAddress, signatureData, this.props.tokenByAddress,
|
||||||
hashData.orderSalt);
|
hashData.orderSalt);
|
||||||
const validationResult = this.validator.validate(order, orderSchema);
|
const validationResult = this._validator.validate(order, orderSchema);
|
||||||
if (validationResult.errors.length > 0) {
|
if (validationResult.errors.length > 0) {
|
||||||
globalErrMsg = 'Order signing failed. Please refresh and try again';
|
globalErrMsg = 'Order signing failed. Please refresh and try again';
|
||||||
utils.consoleLog(`Unexpected error occured: Order validation failed:
|
utils.consoleLog(`Unexpected error occured: Order validation failed:
|
||||||
@@ -331,7 +331,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
});
|
});
|
||||||
return globalErrMsg === '';
|
return globalErrMsg === '';
|
||||||
}
|
}
|
||||||
private updateOrderAddress(address?: string): void {
|
private _updateOrderAddress(address?: string): void {
|
||||||
if (!_.isUndefined(address)) {
|
if (!_.isUndefined(address)) {
|
||||||
this.props.dispatcher.updateOrderTakerAddress(address);
|
this.props.dispatcher.updateOrderTakerAddress(address);
|
||||||
}
|
}
|
||||||
|
@@ -53,7 +53,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
floatingLabelText={<RequiredLabel label="Name" />}
|
floatingLabelText={<RequiredLabel label="Name" />}
|
||||||
value={this.state.name}
|
value={this.state.name}
|
||||||
errorText={this.state.nameErrText}
|
errorText={this.state.nameErrText}
|
||||||
onChange={this.onTokenNameChanged.bind(this)}
|
onChange={this._onTokenNameChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -63,7 +63,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
floatingLabelText={<RequiredLabel label="Symbol" />}
|
floatingLabelText={<RequiredLabel label="Symbol" />}
|
||||||
value={this.state.symbol}
|
value={this.state.symbol}
|
||||||
errorText={this.state.symbolErrText}
|
errorText={this.state.symbolErrText}
|
||||||
onChange={this.onTokenSymbolChanged.bind(this)}
|
onChange={this._onTokenSymbolChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -72,7 +72,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
label="Contract address"
|
label="Contract address"
|
||||||
initialAddress=""
|
initialAddress=""
|
||||||
shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr}
|
shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr}
|
||||||
updateAddress={this.onTokenAddressChanged.bind(this)}
|
updateAddress={this._onTokenAddressChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -82,7 +82,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
floatingLabelText={<RequiredLabel label="Decimals" />}
|
floatingLabelText={<RequiredLabel label="Decimals" />}
|
||||||
value={this.state.decimals}
|
value={this.state.decimals}
|
||||||
errorText={this.state.decimalsErrText}
|
errorText={this.state.decimalsErrText}
|
||||||
onChange={this.onTokenDecimalsChanged.bind(this)}
|
onChange={this._onTokenDecimalsChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt2 mx-auto" style={{width: 120}}>
|
<div className="pt2 mx-auto" style={{width: 120}}>
|
||||||
@@ -90,7 +90,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
labelReady="Add"
|
labelReady="Add"
|
||||||
labelLoading="Adding..."
|
labelLoading="Adding..."
|
||||||
labelComplete="Added!"
|
labelComplete="Added!"
|
||||||
onClickAsyncFn={this.onAddNewTokenClickAsync.bind(this)}
|
onClickAsyncFn={this._onAddNewTokenClickAsync.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.state.globalErrMsg !== '' &&
|
{this.state.globalErrMsg !== '' &&
|
||||||
@@ -99,11 +99,11 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private async onAddNewTokenClickAsync() {
|
private async _onAddNewTokenClickAsync() {
|
||||||
// Trigger validation of name and symbol
|
// Trigger validation of name and symbol
|
||||||
this.onTokenNameChanged(undefined, this.state.name);
|
this._onTokenNameChanged(undefined, this.state.name);
|
||||||
this.onTokenSymbolChanged(undefined, this.state.symbol);
|
this._onTokenSymbolChanged(undefined, this.state.symbol);
|
||||||
this.onTokenDecimalsChanged(undefined, this.state.decimals);
|
this._onTokenDecimalsChanged(undefined, this.state.decimals);
|
||||||
|
|
||||||
const isAddressIncomplete = this.state.address === '';
|
const isAddressIncomplete = this.state.address === '';
|
||||||
let doesContractExist = false;
|
let doesContractExist = false;
|
||||||
@@ -160,7 +160,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
};
|
};
|
||||||
this.props.onNewTokenSubmitted(newToken, newTokenState);
|
this.props.onNewTokenSubmitted(newToken, newTokenState);
|
||||||
}
|
}
|
||||||
private onTokenNameChanged(e: any, name: string) {
|
private _onTokenNameChanged(e: any, name: string) {
|
||||||
let nameErrText = '';
|
let nameErrText = '';
|
||||||
const maxLength = 30;
|
const maxLength = 30;
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
@@ -168,7 +168,7 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
const tokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
|
const tokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
|
||||||
if (name === '') {
|
if (name === '') {
|
||||||
nameErrText = 'Name is required';
|
nameErrText = 'Name is required';
|
||||||
} else if (!this.isValidName(name)) {
|
} else if (!this._isValidName(name)) {
|
||||||
nameErrText = 'Name should only contain letters, digits and spaces';
|
nameErrText = 'Name should only contain letters, digits and spaces';
|
||||||
} else if (name.length > maxLength) {
|
} else if (name.length > maxLength) {
|
||||||
nameErrText = `Max length is ${maxLength}`;
|
nameErrText = `Max length is ${maxLength}`;
|
||||||
@@ -181,14 +181,14 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
nameErrText,
|
nameErrText,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onTokenSymbolChanged(e: any, symbol: string) {
|
private _onTokenSymbolChanged(e: any, symbol: string) {
|
||||||
let symbolErrText = '';
|
let symbolErrText = '';
|
||||||
const maxLength = 5;
|
const maxLength = 5;
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, {symbol}));
|
const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, {symbol}));
|
||||||
if (symbol === '') {
|
if (symbol === '') {
|
||||||
symbolErrText = 'Symbol is required';
|
symbolErrText = 'Symbol is required';
|
||||||
} else if (!this.isLetters(symbol)) {
|
} else if (!this._isLetters(symbol)) {
|
||||||
symbolErrText = 'Can only include letters';
|
symbolErrText = 'Can only include letters';
|
||||||
} else if (symbol.length > maxLength) {
|
} else if (symbol.length > maxLength) {
|
||||||
symbolErrText = `Max length is ${maxLength}`;
|
symbolErrText = `Max length is ${maxLength}`;
|
||||||
@@ -201,12 +201,12 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
symbolErrText,
|
symbolErrText,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onTokenDecimalsChanged(e: any, decimals: string) {
|
private _onTokenDecimalsChanged(e: any, decimals: string) {
|
||||||
let decimalsErrText = '';
|
let decimalsErrText = '';
|
||||||
const maxLength = 2;
|
const maxLength = 2;
|
||||||
if (decimals === '') {
|
if (decimals === '') {
|
||||||
decimalsErrText = 'Decimals is required';
|
decimalsErrText = 'Decimals is required';
|
||||||
} else if (!this.isInteger(decimals)) {
|
} else if (!this._isInteger(decimals)) {
|
||||||
decimalsErrText = 'Must be an integer';
|
decimalsErrText = 'Must be an integer';
|
||||||
} else if (decimals.length > maxLength) {
|
} else if (decimals.length > maxLength) {
|
||||||
decimalsErrText = `Max length is ${maxLength}`;
|
decimalsErrText = `Max length is ${maxLength}`;
|
||||||
@@ -217,20 +217,20 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor
|
|||||||
decimalsErrText,
|
decimalsErrText,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onTokenAddressChanged(address?: string) {
|
private _onTokenAddressChanged(address?: string) {
|
||||||
if (!_.isUndefined(address)) {
|
if (!_.isUndefined(address)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
address,
|
address,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private isValidName(input: string) {
|
private _isValidName(input: string) {
|
||||||
return /^[a-z0-9 ]+$/i.test(input);
|
return /^[a-z0-9 ]+$/i.test(input);
|
||||||
}
|
}
|
||||||
private isInteger(input: string) {
|
private _isInteger(input: string) {
|
||||||
return /^[0-9]+$/i.test(input);
|
return /^[0-9]+$/i.test(input);
|
||||||
}
|
}
|
||||||
private isLetters(input: string) {
|
private _isLetters(input: string) {
|
||||||
return /^[a-zA-Z]+$/i.test(input);
|
return /^[a-zA-Z]+$/i.test(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -54,12 +54,12 @@ export class AddressInput extends React.Component<AddressInputProps, AddressInpu
|
|||||||
floatingLabelText={label}
|
floatingLabelText={label}
|
||||||
errorText={this.state.errMsg}
|
errorText={this.state.errMsg}
|
||||||
value={this.state.address}
|
value={this.state.address}
|
||||||
onChange={this.onOrderTakerAddressUpdated.bind(this)}
|
onChange={this._onOrderTakerAddressUpdated.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onOrderTakerAddressUpdated(e: any) {
|
private _onOrderTakerAddressUpdated(e: any) {
|
||||||
const address = e.target.value.toLowerCase();
|
const address = e.target.value.toLowerCase();
|
||||||
const isValidAddress = addressUtils.isAddress(address) || address === '';
|
const isValidAddress = addressUtils.isAddress(address) || address === '';
|
||||||
const errMsg = isValidAddress ? '' : 'Invalid ethereum address';
|
const errMsg = isValidAddress ? '' : 'Invalid ethereum address';
|
||||||
|
@@ -46,8 +46,8 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
|||||||
<div>
|
<div>
|
||||||
<Toggle
|
<Toggle
|
||||||
disabled={this.state.isSpinnerVisible}
|
disabled={this.state.isSpinnerVisible}
|
||||||
toggled={this.isAllowanceSet()}
|
toggled={this._isAllowanceSet()}
|
||||||
onToggle={this.onToggleAllowanceAsync.bind(this, this.props.token)}
|
onToggle={this._onToggleAllowanceAsync.bind(this, this.props.token)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.state.isSpinnerVisible &&
|
{this.state.isSpinnerVisible &&
|
||||||
@@ -58,7 +58,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private async onToggleAllowanceAsync() {
|
private async _onToggleAllowanceAsync() {
|
||||||
if (this.props.userAddress === '') {
|
if (this.props.userAddress === '') {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
return false;
|
return false;
|
||||||
@@ -69,7 +69,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
|||||||
});
|
});
|
||||||
|
|
||||||
let newAllowanceAmountInBaseUnits = new BigNumber(0);
|
let newAllowanceAmountInBaseUnits = new BigNumber(0);
|
||||||
if (!this.isAllowanceSet()) {
|
if (!this._isAllowanceSet()) {
|
||||||
newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
|
newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -88,7 +88,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
|||||||
await errorReporter.reportAsync(err);
|
await errorReporter.reportAsync(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private isAllowanceSet() {
|
private _isAllowanceSet() {
|
||||||
return !this.props.tokenState.allowance.eq(0);
|
return !this.props.tokenState.allowance.eq(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,7 @@ export class BalanceBoundedInput extends
|
|||||||
super(props);
|
super(props);
|
||||||
const amountString = this.props.amount ? this.props.amount.toString() : '';
|
const amountString = this.props.amount ? this.props.amount.toString() : '';
|
||||||
this.state = {
|
this.state = {
|
||||||
errMsg: this.validate(amountString, props.balance),
|
errMsg: this._validate(amountString, props.balance),
|
||||||
amountString,
|
amountString,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -57,14 +57,14 @@ export class BalanceBoundedInput extends
|
|||||||
if (shouldResetState) {
|
if (shouldResetState) {
|
||||||
const amountString = nextProps.amount.toString();
|
const amountString = nextProps.amount.toString();
|
||||||
this.setState({
|
this.setState({
|
||||||
errMsg: this.validate(amountString, nextProps.balance),
|
errMsg: this._validate(amountString, nextProps.balance),
|
||||||
amountString,
|
amountString,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (isCurrentAmountNumeric) {
|
} else if (isCurrentAmountNumeric) {
|
||||||
const amountString = '';
|
const amountString = '';
|
||||||
this.setState({
|
this.setState({
|
||||||
errMsg: this.validate(amountString, nextProps.balance),
|
errMsg: this._validate(amountString, nextProps.balance),
|
||||||
amountString,
|
amountString,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -87,13 +87,13 @@ export class BalanceBoundedInput extends
|
|||||||
errorText={errorText}
|
errorText={errorText}
|
||||||
value={this.state.amountString}
|
value={this.state.amountString}
|
||||||
hintText={<span style={{textTransform: 'capitalize'}}>amount</span>}
|
hintText={<span style={{textTransform: 'capitalize'}}>amount</span>}
|
||||||
onChange={this.onValueChange.bind(this)}
|
onChange={this._onValueChange.bind(this)}
|
||||||
underlineStyle={{width: 'calc(100% + 50px)'}}
|
underlineStyle={{width: 'calc(100% + 50px)'}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onValueChange(e: any, amountString: string) {
|
private _onValueChange(e: any, amountString: string) {
|
||||||
const errMsg = this.validate(amountString, this.props.balance);
|
const errMsg = this._validate(amountString, this.props.balance);
|
||||||
this.setState({
|
this.setState({
|
||||||
amountString,
|
amountString,
|
||||||
errMsg,
|
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)) {
|
if (!utils.isNumeric(amountString)) {
|
||||||
return amountString !== '' ? 'Must be a number' : '';
|
return amountString !== '' ? 'Must be a number' : '';
|
||||||
}
|
}
|
||||||
@@ -118,14 +118,14 @@ export class BalanceBoundedInput extends
|
|||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
Insufficient balance.{' '}
|
Insufficient balance.{' '}
|
||||||
{this.renderIncreaseBalanceLink()}
|
{this._renderIncreaseBalanceLink()}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
|
const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
|
||||||
return errMsg;
|
return errMsg;
|
||||||
}
|
}
|
||||||
private renderIncreaseBalanceLink() {
|
private _renderIncreaseBalanceLink() {
|
||||||
if (this.props.shouldHideVisitBalancesLink) {
|
if (this.props.shouldHideVisitBalancesLink) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou
|
|||||||
label={this.props.label}
|
label={this.props.label}
|
||||||
balance={this.props.balance}
|
balance={this.props.balance}
|
||||||
amount={amount}
|
amount={amount}
|
||||||
onChange={this.onChange.bind(this)}
|
onChange={this._onChange.bind(this)}
|
||||||
shouldCheckBalance={this.props.shouldCheckBalance}
|
shouldCheckBalance={this.props.shouldCheckBalance}
|
||||||
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
|
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
|
||||||
onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
|
onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
|
||||||
@@ -42,7 +42,7 @@ export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmou
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onChange(isValid: boolean, amount?: BigNumber) {
|
private _onChange(isValid: boolean, amount?: BigNumber) {
|
||||||
const baseUnitAmountIfExists = _.isUndefined(amount) ?
|
const baseUnitAmountIfExists = _.isUndefined(amount) ?
|
||||||
undefined :
|
undefined :
|
||||||
ZeroEx.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH);
|
ZeroEx.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH);
|
||||||
|
@@ -17,11 +17,11 @@ interface ExpirationInputState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ExpirationInput extends React.Component<ExpirationInputProps, ExpirationInputState> {
|
export class ExpirationInput extends React.Component<ExpirationInputProps, ExpirationInputState> {
|
||||||
private earliestPickableMoment: moment.Moment;
|
private _earliestPickableMoment: moment.Moment;
|
||||||
constructor(props: ExpirationInputProps) {
|
constructor(props: ExpirationInputProps) {
|
||||||
super(props);
|
super(props);
|
||||||
// Set the earliest pickable date to today at 00:00, so users can only pick the current or later dates
|
// 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 expirationMoment = utils.convertToMomentFromUnixTimestamp(props.orderExpiryTimestamp);
|
||||||
const initialOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec();
|
const initialOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec();
|
||||||
const didUserSetExpiry = !initialOrderExpiryTimestamp.eq(props.orderExpiryTimestamp);
|
const didUserSetExpiry = !initialOrderExpiryTimestamp.eq(props.orderExpiryTimestamp);
|
||||||
@@ -42,8 +42,8 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
|||||||
mode="landscape"
|
mode="landscape"
|
||||||
autoOk={true}
|
autoOk={true}
|
||||||
value={date}
|
value={date}
|
||||||
onChange={this.onDateChanged.bind(this)}
|
onChange={this._onDateChanged.bind(this)}
|
||||||
shouldDisableDate={this.shouldDisableDate.bind(this)}
|
shouldDisableDate={this._shouldDisableDate.bind(this)}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="absolute"
|
className="absolute"
|
||||||
@@ -58,7 +58,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
|||||||
hintText="Time"
|
hintText="Time"
|
||||||
autoOk={true}
|
autoOk={true}
|
||||||
value={time}
|
value={time}
|
||||||
onChange={this.onTimeChanged.bind(this)}
|
onChange={this._onTimeChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="absolute"
|
className="absolute"
|
||||||
@@ -68,7 +68,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
onClick={this.clearDates.bind(this)}
|
onClick={this._clearDates.bind(this)}
|
||||||
className="col col-1 pt2"
|
className="col col-1 pt2"
|
||||||
style={{textAlign: 'right'}}
|
style={{textAlign: 'right'}}
|
||||||
>
|
>
|
||||||
@@ -77,10 +77,10 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private shouldDisableDate(date: Date): boolean {
|
private _shouldDisableDate(date: Date): boolean {
|
||||||
return moment(date).startOf('day').isBefore(this.earliestPickableMoment);
|
return moment(date).startOf('day').isBefore(this._earliestPickableMoment);
|
||||||
}
|
}
|
||||||
private clearDates() {
|
private _clearDates() {
|
||||||
this.setState({
|
this.setState({
|
||||||
dateMoment: undefined,
|
dateMoment: undefined,
|
||||||
timeMoment: undefined,
|
timeMoment: undefined,
|
||||||
@@ -88,7 +88,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
|||||||
const defaultDateTime = utils.initialOrderExpiryUnixTimestampSec();
|
const defaultDateTime = utils.initialOrderExpiryUnixTimestampSec();
|
||||||
this.props.updateOrderExpiry(defaultDateTime);
|
this.props.updateOrderExpiry(defaultDateTime);
|
||||||
}
|
}
|
||||||
private onDateChanged(e: any, date: Date) {
|
private _onDateChanged(e: any, date: Date) {
|
||||||
const dateMoment = moment(date);
|
const dateMoment = moment(date);
|
||||||
this.setState({
|
this.setState({
|
||||||
dateMoment,
|
dateMoment,
|
||||||
@@ -96,7 +96,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir
|
|||||||
const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, this.state.timeMoment);
|
const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, this.state.timeMoment);
|
||||||
this.props.updateOrderExpiry(timestamp);
|
this.props.updateOrderExpiry(timestamp);
|
||||||
}
|
}
|
||||||
private onTimeChanged(e: any, time: Date) {
|
private _onTimeChanged(e: any, time: Date) {
|
||||||
const timeMoment = moment(time);
|
const timeMoment = moment(time);
|
||||||
this.setState({
|
this.setState({
|
||||||
timeMoment,
|
timeMoment,
|
||||||
|
@@ -27,7 +27,7 @@ interface HashInputState {}
|
|||||||
|
|
||||||
export class HashInput extends React.Component<HashInputProps, HashInputState> {
|
export class HashInput extends React.Component<HashInputProps, HashInputState> {
|
||||||
public render() {
|
public render() {
|
||||||
const msgHashHex = this.props.blockchainIsLoaded ? this.generateMessageHashHex() : '';
|
const msgHashHex = this.props.blockchainIsLoaded ? this._generateMessageHashHex() : '';
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FakeTextField label={this.props.label}>
|
<FakeTextField label={this.props.label}>
|
||||||
@@ -43,7 +43,7 @@ export class HashInput extends React.Component<HashInputProps, HashInputState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private generateMessageHashHex() {
|
private _generateMessageHashHex() {
|
||||||
const exchangeContractAddress = this.props.blockchain.getExchangeContractAddressIfExists();
|
const exchangeContractAddress = this.props.blockchain.getExchangeContractAddressIfExists();
|
||||||
const hashData = this.props.hashData;
|
const hashData = this.props.hashData;
|
||||||
const order: Order = {
|
const order: Order = {
|
||||||
|
@@ -38,14 +38,14 @@ export class IdenticonAddressInput extends React.Component<IdenticonAddressInput
|
|||||||
hintText="e.g 0x75bE4F78AA3699B3A348c84bDB2a96c3Db..."
|
hintText="e.g 0x75bE4F78AA3699B3A348c84bDB2a96c3Db..."
|
||||||
shouldHideLabel={true}
|
shouldHideLabel={true}
|
||||||
initialAddress={this.props.initialAddress}
|
initialAddress={this.props.initialAddress}
|
||||||
updateAddress={this.updateAddress.bind(this)}
|
updateAddress={this._updateAddress.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private updateAddress(address?: string): void {
|
private _updateAddress(address?: string): void {
|
||||||
this.setState({
|
this.setState({
|
||||||
address,
|
address,
|
||||||
});
|
});
|
||||||
|
@@ -33,8 +33,8 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
|
|||||||
label={this.props.label}
|
label={this.props.label}
|
||||||
amount={amount}
|
amount={amount}
|
||||||
balance={ZeroEx.toUnitAmount(this.props.tokenState.balance, this.props.token.decimals)}
|
balance={ZeroEx.toUnitAmount(this.props.tokenState.balance, this.props.token.decimals)}
|
||||||
onChange={this.onChange.bind(this)}
|
onChange={this._onChange.bind(this)}
|
||||||
validate={this.validate.bind(this)}
|
validate={this._validate.bind(this)}
|
||||||
shouldCheckBalance={this.props.shouldCheckBalance}
|
shouldCheckBalance={this.props.shouldCheckBalance}
|
||||||
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
|
shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs}
|
||||||
onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
|
onVisitBalancesPageClick={this.props.onVisitBalancesPageClick}
|
||||||
@@ -45,14 +45,14 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onChange(isValid: boolean, amount?: BigNumber) {
|
private _onChange(isValid: boolean, amount?: BigNumber) {
|
||||||
let baseUnitAmount;
|
let baseUnitAmount;
|
||||||
if (!_.isUndefined(amount)) {
|
if (!_.isUndefined(amount)) {
|
||||||
baseUnitAmount = ZeroEx.toBaseUnitAmount(amount, this.props.token.decimals);
|
baseUnitAmount = ZeroEx.toBaseUnitAmount(amount, this.props.token.decimals);
|
||||||
}
|
}
|
||||||
this.props.onChange(isValid, baseUnitAmount);
|
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)) {
|
if (this.props.shouldCheckAllowance && amount.gt(this.props.tokenState.allowance)) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
|
@@ -52,9 +52,9 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState
|
|||||||
<Paper
|
<Paper
|
||||||
zDepth={1}
|
zDepth={1}
|
||||||
style={{cursor: 'pointer'}}
|
style={{cursor: 'pointer'}}
|
||||||
onMouseEnter={this.onToggleHover.bind(this, true)}
|
onMouseEnter={this._onToggleHover.bind(this, true)}
|
||||||
onMouseLeave={this.onToggleHover.bind(this, false)}
|
onMouseLeave={this._onToggleHover.bind(this, false)}
|
||||||
onClick={this.onAssetClicked.bind(this)}
|
onClick={this._onAssetClicked.bind(this)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="mx-auto pt2"
|
className="mx-auto pt2"
|
||||||
@@ -73,13 +73,13 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState
|
|||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
isOpen={this.state.isPickerOpen}
|
isOpen={this.state.isPickerOpen}
|
||||||
currentTokenAddress={this.props.assetToken.address}
|
currentTokenAddress={this.props.assetToken.address}
|
||||||
onTokenChosen={this.onTokenChosen.bind(this)}
|
onTokenChosen={this._onTokenChosen.bind(this)}
|
||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onTokenChosen(tokenAddress: string) {
|
private _onTokenChosen(tokenAddress: string) {
|
||||||
const assetToken: AssetToken = {
|
const assetToken: AssetToken = {
|
||||||
address: tokenAddress,
|
address: tokenAddress,
|
||||||
amount: this.props.assetToken.amount,
|
amount: this.props.assetToken.amount,
|
||||||
@@ -89,12 +89,12 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState
|
|||||||
isPickerOpen: false,
|
isPickerOpen: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onToggleHover(isHoveringIcon: boolean) {
|
private _onToggleHover(isHoveringIcon: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isHoveringIcon,
|
isHoveringIcon,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onAssetClicked() {
|
private _onAssetClicked() {
|
||||||
if (this.props.blockchainErr !== BlockchainErrs.NoError) {
|
if (this.props.blockchainErr !== BlockchainErrs.NoError) {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
return;
|
return;
|
||||||
|
@@ -36,7 +36,7 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
|
|||||||
shareLink: '',
|
shareLink: '',
|
||||||
};
|
};
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.setShareLinkAsync();
|
this._setShareLinkAsync();
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists,
|
const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists,
|
||||||
@@ -88,21 +88,21 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
|
|||||||
<div>
|
<div>
|
||||||
<i
|
<i
|
||||||
style={{cursor: 'pointer', fontSize: 29}}
|
style={{cursor: 'pointer', fontSize: 29}}
|
||||||
onClick={this.shareViaFacebook.bind(this)}
|
onClick={this._shareViaFacebook.bind(this)}
|
||||||
className="zmdi zmdi-facebook-box"
|
className="zmdi zmdi-facebook-box"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pl1" style={{position: 'relative', width: 28}}>
|
<div className="pl1" style={{position: 'relative', width: 28}}>
|
||||||
<i
|
<i
|
||||||
style={{cursor: 'pointer', fontSize: 32, position: 'absolute', top: -2, left: 8}}
|
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"
|
className="zmdi zmdi-email"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pl1">
|
<div className="pl1">
|
||||||
<i
|
<i
|
||||||
style={{cursor: 'pointer', fontSize: 29}}
|
style={{cursor: 'pointer', fontSize: 29}}
|
||||||
onClick={this.shareViaTwitterAsync.bind(this)}
|
onClick={this._shareViaTwitterAsync.bind(this)}
|
||||||
className="zmdi zmdi-twitter-box"
|
className="zmdi zmdi-twitter-box"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -111,32 +111,32 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private async shareViaTwitterAsync() {
|
private async _shareViaTwitterAsync() {
|
||||||
const tweetText = encodeURIComponent(`Fill my order using the 0x protocol: ${this.state.shareLink}`);
|
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');
|
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({
|
(window as any).FB.ui({
|
||||||
display: 'popup',
|
display: 'popup',
|
||||||
href: this.state.shareLink,
|
href: this.state.shareLink,
|
||||||
method: 'share',
|
method: 'share',
|
||||||
}, _.noop);
|
}, _.noop);
|
||||||
}
|
}
|
||||||
private async shareViaEmailAsync() {
|
private async _shareViaEmailAsync() {
|
||||||
const encodedSubject = encodeURIComponent('Let\'s trade using the 0x protocol');
|
const encodedSubject = encodeURIComponent('Let\'s trade using the 0x protocol');
|
||||||
const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol.
|
const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol.
|
||||||
You can see and fill it here: ${this.state.shareLink}`);
|
You can see and fill it here: ${this.state.shareLink}`);
|
||||||
const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`;
|
const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`;
|
||||||
window.open(mailToLink, '_blank');
|
window.open(mailToLink, '_blank');
|
||||||
}
|
}
|
||||||
private async setShareLinkAsync() {
|
private async _setShareLinkAsync() {
|
||||||
const shareLink = await this.generateShareLinkAsync();
|
const shareLink = await this._generateShareLinkAsync();
|
||||||
this.setState({
|
this.setState({
|
||||||
shareLink,
|
shareLink,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async generateShareLinkAsync(): Promise<string> {
|
private async _generateShareLinkAsync(): Promise<string> {
|
||||||
const longUrl = encodeURIComponent(this.getOrderUrl());
|
const longUrl = encodeURIComponent(this._getOrderUrl());
|
||||||
const bitlyRequestUrl =
|
const bitlyRequestUrl =
|
||||||
`${constants.URL_BITLY_API}/v3/shorten?access_token=${configs.BITLY_ACCESS_TOKEN}&longUrl=${longUrl}`;
|
`${constants.URL_BITLY_API}/v3/shorten?access_token=${configs.BITLY_ACCESS_TOKEN}&longUrl=${longUrl}`;
|
||||||
const response = await fetch(bitlyRequestUrl);
|
const response = await fetch(bitlyRequestUrl);
|
||||||
@@ -150,7 +150,7 @@ You can see and fill it here: ${this.state.shareLink}`);
|
|||||||
}
|
}
|
||||||
return (bodyObj).data.url;
|
return (bodyObj).data.url;
|
||||||
}
|
}
|
||||||
private getOrderUrl() {
|
private _getOrderUrl() {
|
||||||
const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists,
|
const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists,
|
||||||
this.props.sideToAssetToken, this.props.orderExpiryTimestamp, this.props.orderTakerAddress,
|
this.props.sideToAssetToken, this.props.orderExpiryTimestamp, this.props.orderTakerAddress,
|
||||||
this.props.orderMakerAddress, this.props.orderMakerFee, this.props.orderTakerFee,
|
this.props.orderMakerAddress, this.props.orderMakerFee, this.props.orderTakerFee,
|
||||||
|
@@ -70,9 +70,9 @@ interface PortalAllState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
||||||
private blockchain: Blockchain;
|
private _blockchain: Blockchain;
|
||||||
private sharedOrderIfExists: Order;
|
private _sharedOrderIfExists: Order;
|
||||||
private throttledScreenWidthUpdate: () => void;
|
private _throttledScreenWidthUpdate: () => void;
|
||||||
public static hasAlreadyDismissedWethNotice() {
|
public static hasAlreadyDismissedWethNotice() {
|
||||||
const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE);
|
const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE);
|
||||||
const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) &&
|
const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) &&
|
||||||
@@ -81,8 +81,8 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
}
|
}
|
||||||
constructor(props: PortalAllProps) {
|
constructor(props: PortalAllProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.sharedOrderIfExists = this.getSharedOrderIfExists();
|
this._sharedOrderIfExists = this._getSharedOrderIfExists();
|
||||||
this.throttledScreenWidthUpdate = _.throttle(this.updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||||
|
|
||||||
const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`);
|
const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`);
|
||||||
const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice();
|
const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice();
|
||||||
@@ -100,15 +100,15 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
window.addEventListener('resize', this.throttledScreenWidthUpdate);
|
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
public componentWillMount() {
|
public componentWillMount() {
|
||||||
this.blockchain = new Blockchain(this.props.dispatcher);
|
this._blockchain = new Blockchain(this.props.dispatcher);
|
||||||
}
|
}
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
this.blockchain.destroy();
|
this._blockchain.destroy();
|
||||||
window.removeEventListener('resize', this.throttledScreenWidthUpdate);
|
window.removeEventListener('resize', this._throttledScreenWidthUpdate);
|
||||||
// We re-set the entire redux state when the portal is unmounted so that when it is re-rendered
|
// 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
|
// 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
|
// 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) {
|
public componentWillReceiveProps(nextProps: PortalAllProps) {
|
||||||
if (nextProps.networkId !== this.state.prevNetworkId) {
|
if (nextProps.networkId !== this.state.prevNetworkId) {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
|
this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
|
||||||
this.setState({
|
this.setState({
|
||||||
prevNetworkId: nextProps.networkId,
|
prevNetworkId: nextProps.networkId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (nextProps.userAddress !== this.state.prevUserAddress) {
|
if (nextProps.userAddress !== this.state.prevUserAddress) {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress);
|
this._blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress);
|
||||||
if (!_.isEmpty(nextProps.userAddress) &&
|
if (!_.isEmpty(nextProps.userAddress) &&
|
||||||
nextProps.blockchainIsLoaded) {
|
nextProps.blockchainIsLoaded) {
|
||||||
const tokens = _.values(nextProps.tokenByAddress);
|
const tokens = _.values(nextProps.tokenByAddress);
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.updateBalanceAndAllowanceWithLoadingScreenAsync(tokens);
|
this._updateBalanceAndAllowanceWithLoadingScreenAsync(tokens);
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
prevUserAddress: nextProps.userAddress,
|
prevUserAddress: nextProps.userAddress,
|
||||||
@@ -138,7 +138,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
}
|
}
|
||||||
if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
|
if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
|
this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
|
||||||
}
|
}
|
||||||
if (nextProps.location.pathname !== this.state.prevPathname) {
|
if (nextProps.location.pathname !== this.state.prevPathname) {
|
||||||
const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`);
|
const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`);
|
||||||
@@ -206,23 +206,23 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
path={`${WebsitePaths.Portal}/weth`}
|
path={`${WebsitePaths.Portal}/weth`}
|
||||||
render={this.renderEthWrapper.bind(this)}
|
render={this._renderEthWrapper.bind(this)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={`${WebsitePaths.Portal}/fill`}
|
path={`${WebsitePaths.Portal}/fill`}
|
||||||
render={this.renderFillOrder.bind(this)}
|
render={this._renderFillOrder.bind(this)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={`${WebsitePaths.Portal}/balances`}
|
path={`${WebsitePaths.Portal}/balances`}
|
||||||
render={this.renderTokenBalances.bind(this)}
|
render={this._renderTokenBalances.bind(this)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={`${WebsitePaths.Portal}/trades`}
|
path={`${WebsitePaths.Portal}/trades`}
|
||||||
component={this.renderTradeHistory.bind(this)}
|
component={this._renderTradeHistory.bind(this)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={`${WebsitePaths.Home}`}
|
path={`${WebsitePaths.Home}`}
|
||||||
render={this.renderGenerateOrderForm.bind(this)}
|
render={this._renderGenerateOrderForm.bind(this)}
|
||||||
/>
|
/>
|
||||||
</Switch> :
|
</Switch> :
|
||||||
<Loading />
|
<Loading />
|
||||||
@@ -233,7 +233,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
}
|
}
|
||||||
</Paper>
|
</Paper>
|
||||||
<BlockchainErrDialog
|
<BlockchainErrDialog
|
||||||
blockchain={this.blockchain}
|
blockchain={this._blockchain}
|
||||||
blockchainErr={this.props.blockchainErr}
|
blockchainErr={this.props.blockchainErr}
|
||||||
isOpen={this.props.shouldBlockchainErrDialogBeOpen}
|
isOpen={this.props.shouldBlockchainErrDialogBeOpen}
|
||||||
userAddress={this.props.userAddress}
|
userAddress={this.props.userAddress}
|
||||||
@@ -242,11 +242,11 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
/>
|
/>
|
||||||
<WrappedEthSectionNoticeDialog
|
<WrappedEthSectionNoticeDialog
|
||||||
isOpen={this.state.isWethNoticeDialogOpen}
|
isOpen={this.state.isWethNoticeDialogOpen}
|
||||||
onToggleDialog={this.onWethNoticeAccepted.bind(this)}
|
onToggleDialog={this._onWethNoticeAccepted.bind(this)}
|
||||||
/>
|
/>
|
||||||
<PortalDisclaimerDialog
|
<PortalDisclaimerDialog
|
||||||
isOpen={this.state.isDisclaimerDialogOpen}
|
isOpen={this.state.isDisclaimerDialogOpen}
|
||||||
onToggleDialog={this.onPortalDisclaimerAccepted.bind(this)}
|
onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
|
||||||
/>
|
/>
|
||||||
<FlashMessage
|
<FlashMessage
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
@@ -257,11 +257,11 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderEthWrapper() {
|
private _renderEthWrapper() {
|
||||||
return (
|
return (
|
||||||
<EthWrappers
|
<EthWrappers
|
||||||
networkId={this.props.networkId}
|
networkId={this.props.networkId}
|
||||||
blockchain={this.blockchain}
|
blockchain={this._blockchain}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
tokenStateByAddress={this.props.tokenStateByAddress}
|
tokenStateByAddress={this.props.tokenStateByAddress}
|
||||||
@@ -270,7 +270,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderTradeHistory() {
|
private _renderTradeHistory() {
|
||||||
return (
|
return (
|
||||||
<TradeHistory
|
<TradeHistory
|
||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
@@ -279,10 +279,10 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderTokenBalances() {
|
private _renderTokenBalances() {
|
||||||
return (
|
return (
|
||||||
<TokenBalances
|
<TokenBalances
|
||||||
blockchain={this.blockchain}
|
blockchain={this._blockchain}
|
||||||
blockchainErr={this.props.blockchainErr}
|
blockchainErr={this.props.blockchainErr}
|
||||||
blockchainIsLoaded={this.props.blockchainIsLoaded}
|
blockchainIsLoaded={this.props.blockchainIsLoaded}
|
||||||
dispatcher={this.props.dispatcher}
|
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) ?
|
const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) ?
|
||||||
this.props.userSuppliedOrderCache :
|
this.props.userSuppliedOrderCache :
|
||||||
this.sharedOrderIfExists;
|
this._sharedOrderIfExists;
|
||||||
return (
|
return (
|
||||||
<FillOrder
|
<FillOrder
|
||||||
blockchain={this.blockchain}
|
blockchain={this._blockchain}
|
||||||
blockchainErr={this.props.blockchainErr}
|
blockchainErr={this.props.blockchainErr}
|
||||||
initialOrder={initialFillOrder}
|
initialOrder={initialFillOrder}
|
||||||
isOrderInUrl={!_.isUndefined(this.sharedOrderIfExists)}
|
isOrderInUrl={!_.isUndefined(this._sharedOrderIfExists)}
|
||||||
orderFillAmount={this.props.orderFillAmount}
|
orderFillAmount={this.props.orderFillAmount}
|
||||||
networkId={this.props.networkId}
|
networkId={this.props.networkId}
|
||||||
userAddress={this.props.userAddress}
|
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 (
|
return (
|
||||||
<GenerateOrderForm
|
<GenerateOrderForm
|
||||||
blockchain={this.blockchain}
|
blockchain={this._blockchain}
|
||||||
hashData={this.props.hashData}
|
hashData={this.props.hashData}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onPortalDisclaimerAccepted() {
|
private _onPortalDisclaimerAccepted() {
|
||||||
localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
|
localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
|
||||||
this.setState({
|
this.setState({
|
||||||
isDisclaimerDialogOpen: false,
|
isDisclaimerDialogOpen: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onWethNoticeAccepted() {
|
private _onWethNoticeAccepted() {
|
||||||
localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set');
|
localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set');
|
||||||
this.setState({
|
this.setState({
|
||||||
isWethNoticeDialogOpen: false,
|
isWethNoticeDialogOpen: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private getSharedOrderIfExists(): Order {
|
private _getSharedOrderIfExists(): Order {
|
||||||
const queryString = window.location.search;
|
const queryString = window.location.search;
|
||||||
if (queryString.length === 0) {
|
if (queryString.length === 0) {
|
||||||
return;
|
return;
|
||||||
@@ -362,13 +362,13 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
}
|
}
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
private updateScreenWidth() {
|
private _updateScreenWidth() {
|
||||||
const newScreenWidth = utils.getScreenWidth();
|
const newScreenWidth = utils.getScreenWidth();
|
||||||
this.props.dispatcher.updateScreenWidth(newScreenWidth);
|
this.props.dispatcher.updateScreenWidth(newScreenWidth);
|
||||||
}
|
}
|
||||||
private async updateBalanceAndAllowanceWithLoadingScreenAsync(tokens: Token[]) {
|
private async _updateBalanceAndAllowanceWithLoadingScreenAsync(tokens: Token[]) {
|
||||||
this.props.dispatcher.updateBlockchainIsLoaded(false);
|
this.props.dispatcher.updateBlockchainIsLoaded(false);
|
||||||
await this.blockchain.updateTokenBalancesAndAllowancesAsync(tokens);
|
await this._blockchain.updateTokenBalancesAndAllowancesAsync(tokens);
|
||||||
this.props.dispatcher.updateBlockchainIsLoaded(true);
|
this.props.dispatcher.updateBlockchainIsLoaded(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
|||||||
to={`${WebsitePaths.Portal}`}
|
to={`${WebsitePaths.Portal}`}
|
||||||
onClick={this.props.onClick.bind(this)}
|
onClick={this.props.onClick.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')}
|
{this._renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={this.props.menuItemStyle}
|
style={this.props.menuItemStyle}
|
||||||
@@ -31,7 +31,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
|||||||
to={`${WebsitePaths.Portal}/fill`}
|
to={`${WebsitePaths.Portal}/fill`}
|
||||||
onClick={this.props.onClick.bind(this)}
|
onClick={this.props.onClick.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')}
|
{this._renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={this.props.menuItemStyle}
|
style={this.props.menuItemStyle}
|
||||||
@@ -39,7 +39,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
|||||||
to={`${WebsitePaths.Portal}/balances`}
|
to={`${WebsitePaths.Portal}/balances`}
|
||||||
onClick={this.props.onClick.bind(this)}
|
onClick={this.props.onClick.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')}
|
{this._renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={this.props.menuItemStyle}
|
style={this.props.menuItemStyle}
|
||||||
@@ -47,7 +47,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
|||||||
to={`${WebsitePaths.Portal}/trades`}
|
to={`${WebsitePaths.Portal}/trades`}
|
||||||
onClick={this.props.onClick.bind(this)}
|
onClick={this.props.onClick.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')}
|
{this._renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
style={this.props.menuItemStyle}
|
style={this.props.menuItemStyle}
|
||||||
@@ -55,12 +55,12 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
|
|||||||
to={`${WebsitePaths.Portal}/weth`}
|
to={`${WebsitePaths.Portal}/weth`}
|
||||||
onClick={this.props.onClick.bind(this)}
|
onClick={this.props.onClick.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
|
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderMenuItemWithIcon(title: string, iconName: string) {
|
private _renderMenuItemWithIcon(title: string, iconName: string) {
|
||||||
return (
|
return (
|
||||||
<div className="flex" style={{fontWeight: 100}}>
|
<div className="flex" style={{fontWeight: 100}}>
|
||||||
<div className="pr1 pl2">
|
<div className="pr1 pl2">
|
||||||
|
@@ -39,28 +39,28 @@ export class SendButton extends React.Component<SendButtonProps, SendButtonState
|
|||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
disabled={this.state.isSending}
|
disabled={this.state.isSending}
|
||||||
label={this.state.isSending ? 'Sending...' : 'Send'}
|
label={this.state.isSending ? 'Sending...' : 'Send'}
|
||||||
onClick={this.toggleSendDialog.bind(this)}
|
onClick={this._toggleSendDialog.bind(this)}
|
||||||
/>
|
/>
|
||||||
<SendDialog
|
<SendDialog
|
||||||
isOpen={this.state.isSendDialogVisible}
|
isOpen={this.state.isSendDialogVisible}
|
||||||
onComplete={this.onSendAmountSelectedAsync.bind(this)}
|
onComplete={this._onSendAmountSelectedAsync.bind(this)}
|
||||||
onCancelled={this.toggleSendDialog.bind(this)}
|
onCancelled={this._toggleSendDialog.bind(this)}
|
||||||
token={this.props.token}
|
token={this.props.token}
|
||||||
tokenState={this.props.tokenState}
|
tokenState={this.props.tokenState}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private toggleSendDialog() {
|
private _toggleSendDialog() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSendDialogVisible: !this.state.isSendDialogVisible,
|
isSendDialogVisible: !this.state.isSendDialogVisible,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async onSendAmountSelectedAsync(recipient: string, value: BigNumber) {
|
private async _onSendAmountSelectedAsync(recipient: string, value: BigNumber) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSending: true,
|
isSending: true,
|
||||||
});
|
});
|
||||||
this.toggleSendDialog();
|
this._toggleSendDialog();
|
||||||
const token = this.props.token;
|
const token = this.props.token;
|
||||||
const tokenState = this.props.tokenState;
|
const tokenState = this.props.tokenState;
|
||||||
let balance = tokenState.balance;
|
let balance = tokenState.balance;
|
||||||
|
@@ -133,7 +133,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
key="errorOkBtn"
|
key="errorOkBtn"
|
||||||
label="Ok"
|
label="Ok"
|
||||||
primary={true}
|
primary={true}
|
||||||
onTouchTap={this.onErrorDialogToggle.bind(this, false)}
|
onTouchTap={this._onErrorDialogToggle.bind(this, false)}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
const dharmaDialogActions = [
|
const dharmaDialogActions = [
|
||||||
@@ -141,7 +141,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
key="dharmaCloseBtn"
|
key="dharmaCloseBtn"
|
||||||
label="Close"
|
label="Close"
|
||||||
primary={true}
|
primary={true}
|
||||||
onTouchTap={this.onDharmaDialogToggle.bind(this, false)}
|
onTouchTap={this._onDharmaDialogToggle.bind(this, false)}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
const isTestNetwork = this.props.networkId === constants.NETWORK_ID_TESTNET;
|
const isTestNetwork = this.props.networkId === constants.NETWORK_ID_TESTNET;
|
||||||
@@ -239,7 +239,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
labelReady="Request"
|
labelReady="Request"
|
||||||
labelLoading="Sending..."
|
labelLoading="Sending..."
|
||||||
labelComplete="Sent!"
|
labelComplete="Sent!"
|
||||||
onClickAsyncFn={this.faucetRequestAsync.bind(this, true)}
|
onClickAsyncFn={this._faucetRequestAsync.bind(this, true)}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
<RaisedButton
|
<RaisedButton
|
||||||
label="Request"
|
label="Request"
|
||||||
style={{width: '100%'}}
|
style={{width: '100%'}}
|
||||||
onTouchTap={this.onDharmaDialogToggle.bind(this)}
|
onTouchTap={this._onDharmaDialogToggle.bind(this)}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
mini={true}
|
mini={true}
|
||||||
zDepth={0}
|
zDepth={0}
|
||||||
onClick={this.onAddTokenClicked.bind(this)}
|
onClick={this._onAddTokenClicked.bind(this)}
|
||||||
>
|
>
|
||||||
<ContentAdd />
|
<ContentAdd />
|
||||||
</FloatingActionButton>
|
</FloatingActionButton>
|
||||||
@@ -275,7 +275,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
mini={true}
|
mini={true}
|
||||||
zDepth={0}
|
zDepth={0}
|
||||||
onClick={this.onRemoveTokenClicked.bind(this)}
|
onClick={this._onRemoveTokenClicked.bind(this)}
|
||||||
>
|
>
|
||||||
<ContentRemove />
|
<ContentRemove />
|
||||||
</FloatingActionButton>
|
</FloatingActionButton>
|
||||||
@@ -319,7 +319,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody displayRowCheckbox={false}>
|
<TableBody displayRowCheckbox={false}>
|
||||||
{this.renderTokenTableRows()}
|
{this._renderTokenTableRows()}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
<Dialog
|
<Dialog
|
||||||
@@ -327,9 +327,9 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
titleStyle={{fontWeight: 100}}
|
titleStyle={{fontWeight: 100}}
|
||||||
actions={errorDialogActions}
|
actions={errorDialogActions}
|
||||||
open={!_.isUndefined(this.state.errorType)}
|
open={!_.isUndefined(this.state.errorType)}
|
||||||
onRequestClose={this.onErrorDialogToggle.bind(this, false)}
|
onRequestClose={this._onErrorDialogToggle.bind(this, false)}
|
||||||
>
|
>
|
||||||
{this.renderErrorDialogBody()}
|
{this._renderErrorDialogBody()}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<Dialog
|
<Dialog
|
||||||
title="Request Dharma Loan"
|
title="Request Dharma Loan"
|
||||||
@@ -340,7 +340,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
actions={dharmaDialogActions}
|
actions={dharmaDialogActions}
|
||||||
open={this.state.isDharmaDialogVisible}
|
open={this.state.isDharmaDialogVisible}
|
||||||
>
|
>
|
||||||
{this.renderDharmaLoanFrame()}
|
{this._renderDharmaLoanFrame()}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<AssetPicker
|
<AssetPicker
|
||||||
userAddress={this.props.userAddress}
|
userAddress={this.props.userAddress}
|
||||||
@@ -349,14 +349,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
isOpen={this.state.isTokenPickerOpen}
|
isOpen={this.state.isTokenPickerOpen}
|
||||||
currentTokenAddress={''}
|
currentTokenAddress={''}
|
||||||
onTokenChosen={this.onAssetTokenPicked.bind(this)}
|
onTokenChosen={this._onAssetTokenPicked.bind(this)}
|
||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
tokenVisibility={this.state.isAddingToken ? TokenVisibility.UNTRACKED : TokenVisibility.TRACKED}
|
tokenVisibility={this.state.isAddingToken ? TokenVisibility.UNTRACKED : TokenVisibility.TRACKED}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderTokenTableRows() {
|
private _renderTokenTableRows() {
|
||||||
if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== BlockchainErrs.NoError) {
|
if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== BlockchainErrs.NoError) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -372,11 +372,11 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
);
|
);
|
||||||
const tableRows = _.map(
|
const tableRows = _.map(
|
||||||
trackedTokensStartingWithEtherToken,
|
trackedTokensStartingWithEtherToken,
|
||||||
this.renderTokenRow.bind(this, tokenColSpan, actionPaddingX),
|
this._renderTokenRow.bind(this, tokenColSpan, actionPaddingX),
|
||||||
);
|
);
|
||||||
return tableRows;
|
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 tokenState = this.props.tokenStateByAddress[token.address];
|
||||||
const tokenLink = utils.getEtherScanLinkIfExists(token.address, this.props.networkId,
|
const tokenLink = utils.getEtherScanLinkIfExists(token.address, this.props.networkId,
|
||||||
EtherscanLinkSuffixes.Address);
|
EtherscanLinkSuffixes.Address);
|
||||||
@@ -388,14 +388,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
colSpan={tokenColSpan}
|
colSpan={tokenColSpan}
|
||||||
>
|
>
|
||||||
{_.isUndefined(tokenLink) ?
|
{_.isUndefined(tokenLink) ?
|
||||||
this.renderTokenName(token) :
|
this._renderTokenName(token) :
|
||||||
<a href={tokenLink} target="_blank" style={{textDecoration: 'none'}}>
|
<a href={tokenLink} target="_blank" style={{textDecoration: 'none'}}>
|
||||||
{this.renderTokenName(token)}
|
{this._renderTokenName(token)}
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn style={{paddingRight: 3, paddingLeft: 3}}>
|
<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 &&
|
{this.state.isZRXSpinnerVisible && token.symbol === ZRX_TOKEN_SYMBOL &&
|
||||||
<span className="pl1">
|
<span className="pl1">
|
||||||
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
||||||
@@ -408,7 +408,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
token={token}
|
token={token}
|
||||||
tokenState={tokenState}
|
tokenState={tokenState}
|
||||||
onErrorOccurred={this.onErrorOccurred.bind(this)}
|
onErrorOccurred={this._onErrorOccurred.bind(this)}
|
||||||
userAddress={this.props.userAddress}
|
userAddress={this.props.userAddress}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
@@ -420,7 +420,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
labelReady="Mint"
|
labelReady="Mint"
|
||||||
labelLoading={<span style={{fontSize: 12}}>Minting...</span>}
|
labelLoading={<span style={{fontSize: 12}}>Minting...</span>}
|
||||||
labelComplete="Minted!"
|
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 &&
|
{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"
|
labelReady="Request"
|
||||||
labelLoading="Sending..."
|
labelLoading="Sending..."
|
||||||
labelComplete="Sent!"
|
labelComplete="Sent!"
|
||||||
onClickAsyncFn={this.faucetRequestAsync.bind(this, false)}
|
onClickAsyncFn={this._faucetRequestAsync.bind(this, false)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
@@ -441,14 +441,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
token={token}
|
token={token}
|
||||||
tokenState={tokenState}
|
tokenState={tokenState}
|
||||||
onError={this.onSendFailed.bind(this)}
|
onError={this._onSendFailed.bind(this)}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
}
|
}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onAssetTokenPicked(tokenAddress: string) {
|
private _onAssetTokenPicked(tokenAddress: string) {
|
||||||
if (_.isEmpty(tokenAddress)) {
|
if (_.isEmpty(tokenAddress)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isTokenPickerOpen: false,
|
isTokenPickerOpen: false,
|
||||||
@@ -477,16 +477,16 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
isTokenPickerOpen: false,
|
isTokenPickerOpen: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onSendFailed() {
|
private _onSendFailed() {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorType: BalanceErrs.sendFailed,
|
errorType: BalanceErrs.sendFailed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private renderAmount(amount: BigNumber, decimals: number) {
|
private _renderAmount(amount: BigNumber, decimals: number) {
|
||||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||||
return unitAmount.toNumber().toFixed(PRECISION);
|
return unitAmount.toNumber().toFixed(PRECISION);
|
||||||
}
|
}
|
||||||
private renderTokenName(token: Token) {
|
private _renderTokenName(token: Token) {
|
||||||
const tooltipId = `tooltip-${token.address}`;
|
const tooltipId = `tooltip-${token.address}`;
|
||||||
return (
|
return (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
@@ -502,7 +502,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderErrorDialogBody() {
|
private _renderErrorDialogBody() {
|
||||||
switch (this.state.errorType) {
|
switch (this.state.errorType) {
|
||||||
case BalanceErrs.incorrectNetworkForFaucet:
|
case BalanceErrs.incorrectNetworkForFaucet:
|
||||||
return (
|
return (
|
||||||
@@ -550,7 +550,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
throw utils.spawnSwitchErr('errorType', this.state.errorType);
|
throw utils.spawnSwitchErr('errorType', this.state.errorType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private renderDharmaLoanFrame() {
|
private _renderDharmaLoanFrame() {
|
||||||
if (utils.isUserOnMobile()) {
|
if (utils.isUserOnMobile()) {
|
||||||
return (
|
return (
|
||||||
<h4 style={{textAlign: 'center'}}>
|
<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({
|
this.setState({
|
||||||
errorType,
|
errorType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async onMintTestTokensAsync(token: Token): Promise<boolean> {
|
private async _onMintTestTokensAsync(token: Token): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await this.props.blockchain.mintTestTokensAsync(token);
|
await this.props.blockchain.mintTestTokensAsync(token);
|
||||||
const amount = ZeroEx.toUnitAmount(constants.MINT_AMOUNT, token.decimals);
|
const amount = ZeroEx.toUnitAmount(constants.MINT_AMOUNT, token.decimals);
|
||||||
@@ -597,7 +597,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> {
|
private async _faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> {
|
||||||
if (this.props.userAddress === '') {
|
if (this.props.userAddress === '') {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
return false;
|
return false;
|
||||||
@@ -646,23 +646,23 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
private onErrorDialogToggle(isOpen: boolean) {
|
private _onErrorDialogToggle(isOpen: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorType: undefined,
|
errorType: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onDharmaDialogToggle() {
|
private _onDharmaDialogToggle() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isDharmaDialogVisible: !this.state.isDharmaDialogVisible,
|
isDharmaDialogVisible: !this.state.isDharmaDialogVisible,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onAddTokenClicked() {
|
private _onAddTokenClicked() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isTokenPickerOpen: true,
|
isTokenPickerOpen: true,
|
||||||
isAddingToken: true,
|
isAddingToken: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onRemoveTokenClicked() {
|
private _onRemoveTokenClicked() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isTokenPickerOpen: true,
|
isTokenPickerOpen: true,
|
||||||
isAddingToken: false,
|
isAddingToken: false,
|
||||||
|
@@ -127,7 +127,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
<MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="Whitepaper" />
|
<MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="Whitepaper" />
|
||||||
</a>,
|
</a>,
|
||||||
];
|
];
|
||||||
const bottomBorderStyle = this.shouldDisplayBottomBar() ? styles.bottomBar : {};
|
const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
|
||||||
const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
|
const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
|
||||||
const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
|
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`;
|
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>
|
||||||
<div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} />
|
<div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} />
|
||||||
<div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} />
|
<div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} />
|
||||||
{!this.isViewingPortal() &&
|
{!this._isViewingPortal() &&
|
||||||
<div
|
<div
|
||||||
className={menuClasses}
|
className={menuClasses}
|
||||||
>
|
>
|
||||||
@@ -183,37 +183,37 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
}
|
}
|
||||||
{this.props.blockchainIsLoaded && !_.isEmpty(this.props.userAddress) &&
|
{this.props.blockchainIsLoaded && !_.isEmpty(this.props.userAddress) &&
|
||||||
<div className="col col-5">
|
<div className="col col-5">
|
||||||
{this.renderUser()}
|
{this._renderUser()}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{!this.isViewingPortal() &&
|
{!this._isViewingPortal() &&
|
||||||
<div
|
<div
|
||||||
className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}
|
className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}
|
||||||
>
|
>
|
||||||
<div style={menuIconStyle}>
|
<div style={menuIconStyle}>
|
||||||
<i
|
<i
|
||||||
className="zmdi zmdi-menu"
|
className="zmdi zmdi-menu"
|
||||||
onClick={this.onMenuButtonClick.bind(this)}
|
onClick={this._onMenuButtonClick.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{this.renderDrawer()}
|
{this._renderDrawer()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderDrawer() {
|
private _renderDrawer() {
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
open={this.state.isDrawerOpen}
|
open={this.state.isDrawerOpen}
|
||||||
docked={false}
|
docked={false}
|
||||||
openSecondary={true}
|
openSecondary={true}
|
||||||
onRequestChange={this.onMenuButtonClick.bind(this)}
|
onRequestChange={this._onMenuButtonClick.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderPortalMenu()}
|
{this._renderPortalMenu()}
|
||||||
{this.renderDocsMenu()}
|
{this._renderDocsMenu()}
|
||||||
{this.renderWiki()}
|
{this._renderWiki()}
|
||||||
<div className="pl1 py1 mt3" style={{backgroundColor: colors.lightGrey}}>Website</div>
|
<div className="pl1 py1 mt3" style={{backgroundColor: colors.lightGrey}}>Website</div>
|
||||||
<Link to={WebsitePaths.Home} className="text-decoration-none">
|
<Link to={WebsitePaths.Home} className="text-decoration-none">
|
||||||
<MenuItem className="py2">Home</MenuItem>
|
<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">
|
<Link to={`${WebsitePaths.Wiki}`} className="text-decoration-none">
|
||||||
<MenuItem className="py2">Wiki</MenuItem>
|
<MenuItem className="py2">Wiki</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
{!this.isViewing0xjsDocs() &&
|
{!this._isViewing0xjsDocs() &&
|
||||||
<Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
|
<Link to={WebsitePaths.ZeroExJs} className="text-decoration-none">
|
||||||
<MenuItem className="py2">0x.js Docs</MenuItem>
|
<MenuItem className="py2">0x.js Docs</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
{!this.isViewingConnectDocs() &&
|
{!this._isViewingConnectDocs() &&
|
||||||
<Link to={WebsitePaths.Connect} className="text-decoration-none">
|
<Link to={WebsitePaths.Connect} className="text-decoration-none">
|
||||||
<MenuItem className="py2">0x Connect Docs</MenuItem>
|
<MenuItem className="py2">0x Connect Docs</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
{!this.isViewingSmartContractsDocs() &&
|
{!this._isViewingSmartContractsDocs() &&
|
||||||
<Link to={WebsitePaths.SmartContracts} className="text-decoration-none">
|
<Link to={WebsitePaths.SmartContracts} className="text-decoration-none">
|
||||||
<MenuItem className="py2">Smart Contract Docs</MenuItem>
|
<MenuItem className="py2">Smart Contract Docs</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
{!this.isViewingPortal() &&
|
{!this._isViewingPortal() &&
|
||||||
<Link to={`${WebsitePaths.Portal}`} className="text-decoration-none">
|
<Link to={`${WebsitePaths.Portal}`} className="text-decoration-none">
|
||||||
<MenuItem className="py2">Portal DApp</MenuItem>
|
<MenuItem className="py2">Portal DApp</MenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -261,7 +261,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
<Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none">
|
<Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className="py2"
|
className="py2"
|
||||||
onTouchTap={this.onMenuButtonClick.bind(this)}
|
onTouchTap={this._onMenuButtonClick.bind(this)}
|
||||||
>
|
>
|
||||||
FAQ
|
FAQ
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@@ -269,8 +269,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderDocsMenu() {
|
private _renderDocsMenu() {
|
||||||
if (!this.isViewing0xjsDocs() && !this.isViewingSmartContractsDocs() && !this.isViewingConnectDocs()
|
if (!this._isViewing0xjsDocs() && !this._isViewingSmartContractsDocs() && !this._isViewingConnectDocs()
|
||||||
|| _.isUndefined(this.props.menu)) {
|
|| _.isUndefined(this.props.menu)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
topLevelMenu={this.props.menu}
|
topLevelMenu={this.props.menu}
|
||||||
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
|
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
|
||||||
shouldDisplaySectionHeaders={false}
|
shouldDisplaySectionHeaders={false}
|
||||||
onMenuItemClick={this.onMenuButtonClick.bind(this)}
|
onMenuItemClick={this._onMenuButtonClick.bind(this)}
|
||||||
selectedVersion={this.props.docsVersion}
|
selectedVersion={this.props.docsVersion}
|
||||||
docPath={this.props.docsInfo.websitePath}
|
docPath={this.props.docsInfo.websitePath}
|
||||||
versions={this.props.availableDocVersions}
|
versions={this.props.availableDocVersions}
|
||||||
@@ -291,8 +291,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderWiki() {
|
private _renderWiki() {
|
||||||
if (!this.isViewingWiki()) {
|
if (!this._isViewingWiki()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,13 +303,13 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
topLevelMenu={this.props.menuSubsectionsBySection}
|
topLevelMenu={this.props.menuSubsectionsBySection}
|
||||||
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
|
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
|
||||||
shouldDisplaySectionHeaders={false}
|
shouldDisplaySectionHeaders={false}
|
||||||
onMenuItemClick={this.onMenuButtonClick.bind(this)}
|
onMenuItemClick={this._onMenuButtonClick.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderPortalMenu() {
|
private _renderPortalMenu() {
|
||||||
if (!this.isViewingPortal()) {
|
if (!this._isViewingPortal()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,12 +318,12 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
<div className="pl1 py1" style={{backgroundColor: colors.lightGrey}}>Portal DApp</div>
|
<div className="pl1 py1" style={{backgroundColor: colors.lightGrey}}>Portal DApp</div>
|
||||||
<PortalMenu
|
<PortalMenu
|
||||||
menuItemStyle={{color: 'black'}}
|
menuItemStyle={{color: 'black'}}
|
||||||
onClick={this.onMenuButtonClick.bind(this)}
|
onClick={this._onMenuButtonClick.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderUser() {
|
private _renderUser() {
|
||||||
const userAddress = this.props.userAddress;
|
const userAddress = this.props.userAddress;
|
||||||
const identiconDiameter = 26;
|
const identiconDiameter = 26;
|
||||||
return (
|
return (
|
||||||
@@ -345,31 +345,31 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onMenuButtonClick() {
|
private _onMenuButtonClick() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isDrawerOpen: !this.state.isDrawerOpen,
|
isDrawerOpen: !this.state.isDrawerOpen,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private isViewingPortal() {
|
private _isViewingPortal() {
|
||||||
return _.includes(this.props.location.pathname, WebsitePaths.Portal);
|
return _.includes(this.props.location.pathname, WebsitePaths.Portal);
|
||||||
}
|
}
|
||||||
private isViewingFAQ() {
|
private _isViewingFAQ() {
|
||||||
return _.includes(this.props.location.pathname, WebsitePaths.FAQ);
|
return _.includes(this.props.location.pathname, WebsitePaths.FAQ);
|
||||||
}
|
}
|
||||||
private isViewing0xjsDocs() {
|
private _isViewing0xjsDocs() {
|
||||||
return _.includes(this.props.location.pathname, WebsitePaths.ZeroExJs);
|
return _.includes(this.props.location.pathname, WebsitePaths.ZeroExJs);
|
||||||
}
|
}
|
||||||
private isViewingConnectDocs() {
|
private _isViewingConnectDocs() {
|
||||||
return _.includes(this.props.location.pathname, WebsitePaths.Connect);
|
return _.includes(this.props.location.pathname, WebsitePaths.Connect);
|
||||||
}
|
}
|
||||||
private isViewingSmartContractsDocs() {
|
private _isViewingSmartContractsDocs() {
|
||||||
return _.includes(this.props.location.pathname, WebsitePaths.SmartContracts);
|
return _.includes(this.props.location.pathname, WebsitePaths.SmartContracts);
|
||||||
}
|
}
|
||||||
private isViewingWiki() {
|
private _isViewingWiki() {
|
||||||
return _.includes(this.props.location.pathname, WebsitePaths.Wiki);
|
return _.includes(this.props.location.pathname, WebsitePaths.Wiki);
|
||||||
}
|
}
|
||||||
private shouldDisplayBottomBar() {
|
private _shouldDisplayBottomBar() {
|
||||||
return this.isViewingWiki() || this.isViewing0xjsDocs() || this.isViewingFAQ() ||
|
return this._isViewingWiki() || this._isViewing0xjsDocs() || this._isViewingFAQ() ||
|
||||||
this.isViewingSmartContractsDocs() || this.isViewingConnectDocs();
|
this._isViewingSmartContractsDocs() || this._isViewingConnectDocs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,19 +20,19 @@ interface TradeHistoryState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> {
|
export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> {
|
||||||
private fillPollingIntervalId: number;
|
private _fillPollingIntervalId: number;
|
||||||
public constructor(props: TradeHistoryProps) {
|
public constructor(props: TradeHistoryProps) {
|
||||||
super(props);
|
super(props);
|
||||||
const sortedFills = this.getSortedFills();
|
const sortedFills = this._getSortedFills();
|
||||||
this.state = {
|
this.state = {
|
||||||
sortedFills,
|
sortedFills,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public componentWillMount() {
|
public componentWillMount() {
|
||||||
this.startPollingForFills();
|
this._startPollingForFills();
|
||||||
}
|
}
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
this.stopPollingForFills();
|
this._stopPollingForFills();
|
||||||
}
|
}
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
@@ -43,15 +43,15 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
|||||||
<h3>Trade history</h3>
|
<h3>Trade history</h3>
|
||||||
<Divider />
|
<Divider />
|
||||||
<div className="pt2" style={{height: 608, overflow: 'scroll'}}>
|
<div className="pt2" style={{height: 608, overflow: 'scroll'}}>
|
||||||
{this.renderTrades()}
|
{this._renderTrades()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderTrades() {
|
private _renderTrades() {
|
||||||
const numNonCustomFills = this.numFillsWithoutCustomERC20Tokens();
|
const numNonCustomFills = this._numFillsWithoutCustomERC20Tokens();
|
||||||
if (numNonCustomFills === 0) {
|
if (numNonCustomFills === 0) {
|
||||||
return this.renderEmptyNotice();
|
return this._renderEmptyNotice();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.map(this.state.sortedFills, (fill, index) => {
|
return _.map(this.state.sortedFills, (fill, index) => {
|
||||||
@@ -66,14 +66,14 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private renderEmptyNotice() {
|
private _renderEmptyNotice() {
|
||||||
return (
|
return (
|
||||||
<Paper className="mt1 p2 mx-auto center" style={{width: '80%'}}>
|
<Paper className="mt1 p2 mx-auto center" style={{width: '80%'}}>
|
||||||
No filled orders yet.
|
No filled orders yet.
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private numFillsWithoutCustomERC20Tokens() {
|
private _numFillsWithoutCustomERC20Tokens() {
|
||||||
let numNonCustomFills = 0;
|
let numNonCustomFills = 0;
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
_.each(this.state.sortedFills, fill => {
|
_.each(this.state.sortedFills, fill => {
|
||||||
@@ -93,9 +93,9 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
|||||||
});
|
});
|
||||||
return numNonCustomFills;
|
return numNonCustomFills;
|
||||||
}
|
}
|
||||||
private startPollingForFills() {
|
private _startPollingForFills() {
|
||||||
this.fillPollingIntervalId = window.setInterval(() => {
|
this._fillPollingIntervalId = window.setInterval(() => {
|
||||||
const sortedFills = this.getSortedFills();
|
const sortedFills = this._getSortedFills();
|
||||||
if (!utils.deepEqual(sortedFills, this.state.sortedFills)) {
|
if (!utils.deepEqual(sortedFills, this.state.sortedFills)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
sortedFills,
|
sortedFills,
|
||||||
@@ -103,10 +103,10 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor
|
|||||||
}
|
}
|
||||||
}, FILL_POLLING_INTERVAL);
|
}, FILL_POLLING_INTERVAL);
|
||||||
}
|
}
|
||||||
private stopPollingForFills() {
|
private _stopPollingForFills() {
|
||||||
clearInterval(this.fillPollingIntervalId);
|
clearInterval(this._fillPollingIntervalId);
|
||||||
}
|
}
|
||||||
private getSortedFills() {
|
private _getSortedFills() {
|
||||||
const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId);
|
const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId);
|
||||||
const fills = _.values(fillsByHash);
|
const fills = _.values(fillsByHash);
|
||||||
const sortedFills = _.sortBy(fills, [(fill: Fill) => fill.blockTimestamp * -1]);
|
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="clearfix">
|
||||||
<div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3">
|
<div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3">
|
||||||
{this.renderDate()}
|
{this._renderDate()}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col col-12 lg-col-6 md-col-6 lg-pl3 md-pl3"
|
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}
|
className={amountColClassNames}
|
||||||
style={amountColStyle}
|
style={amountColStyle}
|
||||||
>
|
>
|
||||||
{this.renderAmounts(makerToken, takerToken)}
|
{this._renderAmounts(makerToken, takerToken)}
|
||||||
</div>
|
</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="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}}>
|
<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>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderAmounts(makerToken: Token, takerToken: Token) {
|
private _renderAmounts(makerToken: Token, takerToken: Token) {
|
||||||
const fill = this.props.fill;
|
const fill = this.props.fill;
|
||||||
const filledTakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledTakerTokenAmount, takerToken.decimals);
|
const filledTakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledTakerTokenAmount, takerToken.decimals);
|
||||||
const filledMakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledMakerTokenAmount, 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}}
|
style={{color: colors.green400, fontSize: 16}}
|
||||||
>
|
>
|
||||||
<span>+{' '}</span>
|
<span>+{' '}</span>
|
||||||
{this.renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)}
|
{this._renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="pb1 inline-block"
|
className="pb1 inline-block"
|
||||||
style={{color: colors.red200, fontSize: 16}}
|
style={{color: colors.red200, fontSize: 16}}
|
||||||
>
|
>
|
||||||
<span>-{' '}</span>
|
<span>-{' '}</span>
|
||||||
{this.renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)}
|
{this._renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{color: colors.grey400, fontSize: 14}}>
|
<div style={{color: colors.grey400, fontSize: 14}}>
|
||||||
{exchangeRate.toFixed(PRECISION)} {givenToken.symbol}/{receiveToken.symbol}
|
{exchangeRate.toFixed(PRECISION)} {givenToken.symbol}/{receiveToken.symbol}
|
||||||
@@ -148,7 +148,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderDate() {
|
private _renderDate() {
|
||||||
const blockMoment = moment.unix(this.props.fill.blockTimestamp);
|
const blockMoment = moment.unix(this.props.fill.blockTimestamp);
|
||||||
if (!blockMoment.isValid()) {
|
if (!blockMoment.isValid()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -170,7 +170,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderAmount(amount: BigNumber, symbol: string, decimals: number) {
|
private _renderAmount(amount: BigNumber, symbol: string, decimals: number) {
|
||||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
|
@@ -42,14 +42,14 @@ export class Badge extends React.Component<BadgeProps, BadgeState> {
|
|||||||
<div
|
<div
|
||||||
className="p1 center"
|
className="p1 center"
|
||||||
style={badgeStyle}
|
style={badgeStyle}
|
||||||
onMouseOver={this.setHoverState.bind(this, true)}
|
onMouseOver={this._setHoverState.bind(this, true)}
|
||||||
onMouseOut={this.setHoverState.bind(this, false)}
|
onMouseOut={this._setHoverState.bind(this, false)}
|
||||||
>
|
>
|
||||||
{this.props.title}
|
{this.props.title}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setHoverState(isHovering: boolean) {
|
private _setHoverState(isHovering: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isHovering,
|
isHovering,
|
||||||
});
|
});
|
||||||
|
@@ -15,8 +15,8 @@ interface CopyIconState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
||||||
private copyTooltipTimeoutId: number;
|
private _copyTooltipTimeoutId: number;
|
||||||
private copyable: HTMLInputElement;
|
private _copyable: HTMLInputElement;
|
||||||
constructor(props: CopyIconProps) {
|
constructor(props: CopyIconProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -25,25 +25,25 @@ export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
|||||||
}
|
}
|
||||||
public componentDidUpdate() {
|
public componentDidUpdate() {
|
||||||
// Remove tooltip if hover away
|
// Remove tooltip if hover away
|
||||||
if (!this.state.isHovering && this.copyTooltipTimeoutId) {
|
if (!this.state.isHovering && this._copyTooltipTimeoutId) {
|
||||||
clearInterval(this.copyTooltipTimeoutId);
|
clearInterval(this._copyTooltipTimeoutId);
|
||||||
this.hideTooltip();
|
this._hideTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<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
|
<div
|
||||||
className="inline flex"
|
className="inline flex"
|
||||||
style={{cursor: 'pointer', color: colors.amber600}}
|
style={{cursor: 'pointer', color: colors.amber600}}
|
||||||
ref={this.setRefToProperty.bind(this)}
|
ref={this._setRefToProperty.bind(this)}
|
||||||
data-tip={true}
|
data-tip={true}
|
||||||
data-for="copy"
|
data-for="copy"
|
||||||
data-event="click"
|
data-event="click"
|
||||||
data-iscapture={true} // This let's the click event continue to propogate
|
data-iscapture={true} // This let's the click event continue to propogate
|
||||||
onMouseOver={this.setHoverState.bind(this, true)}
|
onMouseOver={this._setHoverState.bind(this, true)}
|
||||||
onMouseOut={this.setHoverState.bind(this, false)}
|
onMouseOut={this._setHoverState.bind(this, false)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<i style={{fontSize: 15}} className="zmdi zmdi-copy" />
|
<i style={{fontSize: 15}} className="zmdi zmdi-copy" />
|
||||||
@@ -57,25 +57,25 @@ export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setRefToProperty(el: HTMLInputElement) {
|
private _setRefToProperty(el: HTMLInputElement) {
|
||||||
this.copyable = el;
|
this._copyable = el;
|
||||||
}
|
}
|
||||||
private setHoverState(isHovering: boolean) {
|
private _setHoverState(isHovering: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isHovering,
|
isHovering,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onCopy() {
|
private _onCopy() {
|
||||||
if (this.copyTooltipTimeoutId) {
|
if (this._copyTooltipTimeoutId) {
|
||||||
clearInterval(this.copyTooltipTimeoutId);
|
clearInterval(this._copyTooltipTimeoutId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tooltipLifespanMs = 1000;
|
const tooltipLifespanMs = 1000;
|
||||||
this.copyTooltipTimeoutId = window.setTimeout(() => {
|
this._copyTooltipTimeoutId = window.setTimeout(() => {
|
||||||
this.hideTooltip();
|
this._hideTooltip();
|
||||||
}, tooltipLifespanMs);
|
}, tooltipLifespanMs);
|
||||||
}
|
}
|
||||||
private hideTooltip() {
|
private _hideTooltip() {
|
||||||
ReactTooltip.hide(ReactDOM.findDOMNode(this.copyable));
|
ReactTooltip.hide(ReactDOM.findDOMNode(this._copyable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,8 +28,8 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
|||||||
menuItemStyle: DEFAULT_STYLE,
|
menuItemStyle: DEFAULT_STYLE,
|
||||||
isNightVersion: false,
|
isNightVersion: false,
|
||||||
};
|
};
|
||||||
private isHovering: boolean;
|
private _isHovering: boolean;
|
||||||
private popoverCloseCheckIntervalId: number;
|
private _popoverCloseCheckIntervalId: number;
|
||||||
constructor(props: DropDownMenuItemProps) {
|
constructor(props: DropDownMenuItemProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -37,20 +37,20 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
this.popoverCloseCheckIntervalId = window.setInterval(() => {
|
this._popoverCloseCheckIntervalId = window.setInterval(() => {
|
||||||
this.checkIfShouldClosePopover();
|
this._checkIfShouldClosePopover();
|
||||||
}, CHECK_CLOSE_POPOVER_INTERVAL_MS);
|
}, CHECK_CLOSE_POPOVER_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
window.clearInterval(this.popoverCloseCheckIntervalId);
|
window.clearInterval(this._popoverCloseCheckIntervalId);
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const colorStyle = this.props.isNightVersion ? 'white' : this.props.style.color;
|
const colorStyle = this.props.isNightVersion ? 'white' : this.props.style.color;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{...this.props.style, color: colorStyle}}
|
style={{...this.props.style, color: colorStyle}}
|
||||||
onMouseEnter={this.onHover.bind(this)}
|
onMouseEnter={this._onHover.bind(this)}
|
||||||
onMouseLeave={this.onHoverOff.bind(this)}
|
onMouseLeave={this._onHoverOff.bind(this)}
|
||||||
>
|
>
|
||||||
<div className="flex relative">
|
<div className="flex relative">
|
||||||
<div style={{paddingRight: 10}}>
|
<div style={{paddingRight: 10}}>
|
||||||
@@ -65,12 +65,12 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
|||||||
anchorEl={this.state.anchorEl}
|
anchorEl={this.state.anchorEl}
|
||||||
anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}}
|
anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}}
|
||||||
targetOrigin={{horizontal: 'middle', vertical: 'top'}}
|
targetOrigin={{horizontal: 'middle', vertical: 'top'}}
|
||||||
onRequestClose={this.closePopover.bind(this)}
|
onRequestClose={this._closePopover.bind(this)}
|
||||||
useLayerForClickAway={false}
|
useLayerForClickAway={false}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
onMouseEnter={this.onHover.bind(this)}
|
onMouseEnter={this._onHover.bind(this)}
|
||||||
onMouseLeave={this.onHoverOff.bind(this)}
|
onMouseLeave={this._onHoverOff.bind(this)}
|
||||||
>
|
>
|
||||||
<Menu style={{color: colors.grey}}>
|
<Menu style={{color: colors.grey}}>
|
||||||
{this.props.subMenuItems}
|
{this.props.subMenuItems}
|
||||||
@@ -80,11 +80,11 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onHover(event: React.FormEvent<HTMLInputElement>) {
|
private _onHover(event: React.FormEvent<HTMLInputElement>) {
|
||||||
this.isHovering = true;
|
this._isHovering = true;
|
||||||
this.checkIfShouldOpenPopover(event);
|
this._checkIfShouldOpenPopover(event);
|
||||||
}
|
}
|
||||||
private checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>) {
|
private _checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>) {
|
||||||
if (this.state.isDropDownOpen) {
|
if (this.state.isDropDownOpen) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
@@ -94,16 +94,16 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro
|
|||||||
anchorEl: event.currentTarget,
|
anchorEl: event.currentTarget,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onHoverOff(event: React.FormEvent<HTMLInputElement>) {
|
private _onHoverOff(event: React.FormEvent<HTMLInputElement>) {
|
||||||
this.isHovering = false;
|
this._isHovering = false;
|
||||||
}
|
}
|
||||||
private checkIfShouldClosePopover() {
|
private _checkIfShouldClosePopover() {
|
||||||
if (!this.state.isDropDownOpen || this.isHovering) {
|
if (!this.state.isDropDownOpen || this._isHovering) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
this.closePopover();
|
this._closePopover();
|
||||||
}
|
}
|
||||||
private closePopover() {
|
private _closePopover() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isDropDownOpen: false,
|
isDropDownOpen: false,
|
||||||
});
|
});
|
||||||
|
@@ -26,7 +26,7 @@ export class FlashMessage extends React.Component<FlashMessageProps, FlashMessag
|
|||||||
open={true}
|
open={true}
|
||||||
message={this.props.flashMessage}
|
message={this.props.flashMessage}
|
||||||
autoHideDuration={this.props.showDurationMs}
|
autoHideDuration={this.props.showDurationMs}
|
||||||
onRequestClose={this.onClose.bind(this)}
|
onRequestClose={this._onClose.bind(this)}
|
||||||
bodyStyle={this.props.bodyStyle}
|
bodyStyle={this.props.bodyStyle}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -34,7 +34,7 @@ export class FlashMessage extends React.Component<FlashMessageProps, FlashMessag
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private onClose() {
|
private _onClose() {
|
||||||
this.props.dispatcher.hideFlashMessage();
|
this.props.dispatcher.hideFlashMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,8 +35,8 @@ export class LifeCycleRaisedButton extends
|
|||||||
backgroundColor: colors.white,
|
backgroundColor: colors.white,
|
||||||
labelColor: colors.darkGrey,
|
labelColor: colors.darkGrey,
|
||||||
};
|
};
|
||||||
private buttonTimeoutId: number;
|
private _buttonTimeoutId: number;
|
||||||
private didUnmount: boolean;
|
private _didUnmount: boolean;
|
||||||
constructor(props: LifeCycleRaisedButtonProps) {
|
constructor(props: LifeCycleRaisedButtonProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -44,8 +44,8 @@ export class LifeCycleRaisedButton extends
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
clearTimeout(this.buttonTimeoutId);
|
clearTimeout(this._buttonTimeoutId);
|
||||||
this.didUnmount = true;
|
this._didUnmount = true;
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
if (this.props.isHidden) {
|
if (this.props.isHidden) {
|
||||||
@@ -83,14 +83,14 @@ export class LifeCycleRaisedButton extends
|
|||||||
buttonState: ButtonState.LOADING,
|
buttonState: ButtonState.LOADING,
|
||||||
});
|
});
|
||||||
const didSucceed = await this.props.onClickAsyncFn();
|
const didSucceed = await this.props.onClickAsyncFn();
|
||||||
if (this.didUnmount) {
|
if (this._didUnmount) {
|
||||||
return; // noop since unmount called before async callback returned.
|
return; // noop since unmount called before async callback returned.
|
||||||
}
|
}
|
||||||
if (didSucceed) {
|
if (didSucceed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
buttonState: ButtonState.COMPLETE,
|
buttonState: ButtonState.COMPLETE,
|
||||||
});
|
});
|
||||||
this.buttonTimeoutId = window.setTimeout(() => {
|
this._buttonTimeoutId = window.setTimeout(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
buttonState: ButtonState.READY,
|
buttonState: ButtonState.READY,
|
||||||
});
|
});
|
||||||
|
@@ -35,15 +35,15 @@ export class MenuItem extends React.Component<MenuItemProps, MenuItemState> {
|
|||||||
onClick={this.props.onClick.bind(this)}
|
onClick={this.props.onClick.bind(this)}
|
||||||
className={`mx-auto ${this.props.className}`}
|
className={`mx-auto ${this.props.className}`}
|
||||||
style={menuItemStyles}
|
style={menuItemStyles}
|
||||||
onMouseEnter={this.onToggleHover.bind(this, true)}
|
onMouseEnter={this._onToggleHover.bind(this, true)}
|
||||||
onMouseLeave={this.onToggleHover.bind(this, false)}
|
onMouseLeave={this._onToggleHover.bind(this, false)}
|
||||||
>
|
>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onToggleHover(isHovering: boolean) {
|
private _onToggleHover(isHovering: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isHovering,
|
isHovering,
|
||||||
});
|
});
|
||||||
|
@@ -27,8 +27,8 @@ export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> {
|
|||||||
className="mx-auto pt4"
|
className="mx-auto pt4"
|
||||||
style={{cursor: 'pointer', height: 50, width: 37.5}}
|
style={{cursor: 'pointer', height: 50, width: 37.5}}
|
||||||
onClick={this.props.swapTokensFn}
|
onClick={this.props.swapTokensFn}
|
||||||
onMouseEnter={this.onToggleHover.bind(this, true)}
|
onMouseEnter={this._onToggleHover.bind(this, true)}
|
||||||
onMouseLeave={this.onToggleHover.bind(this, false)}
|
onMouseLeave={this._onToggleHover.bind(this, false)}
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
style={swapStyles}
|
style={swapStyles}
|
||||||
@@ -37,7 +37,7 @@ export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onToggleHover(isHovering: boolean) {
|
private _onToggleHover(isHovering: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isHovering,
|
isHovering,
|
||||||
});
|
});
|
||||||
|
@@ -42,13 +42,13 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt
|
|||||||
</div>
|
</div>
|
||||||
<div className="col col-2 center pt1">
|
<div className="col col-2 center pt1">
|
||||||
<div className="pb1">
|
<div className="pb1">
|
||||||
{this.renderAmount(this.props.takerAssetToken, this.props.takerToken)}
|
{this._renderAmount(this.props.takerAssetToken, this.props.takerToken)}
|
||||||
</div>
|
</div>
|
||||||
<div className="lg-p2 md-p2 sm-p1">
|
<div className="lg-p2 md-p2 sm-p1">
|
||||||
<img src="/images/trade_arrows.png" style={{width: 47}} />
|
<img src="/images/trade_arrows.png" style={{width: 47}} />
|
||||||
</div>
|
</div>
|
||||||
<div className="pt1">
|
<div className="pt1">
|
||||||
{this.renderAmount(this.props.makerAssetToken, this.props.makerToken)}
|
{this._renderAmount(this.props.makerAssetToken, this.props.makerToken)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col col-5 center">
|
<div className="col col-5 center">
|
||||||
@@ -65,7 +65,7 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderAmount(assetToken: AssetToken, token: Token) {
|
private _renderAmount(assetToken: AssetToken, token: Token) {
|
||||||
const unitAmount = ZeroEx.toUnitAmount(assetToken.amount, token.decimals);
|
const unitAmount = ZeroEx.toUnitAmount(assetToken.amount, token.decimals);
|
||||||
return (
|
return (
|
||||||
<div style={{fontSize: 13}}>
|
<div style={{fontSize: 13}}>
|
||||||
|
@@ -23,12 +23,12 @@ export class LazyComponent extends React.Component<LazyComponentProps, LazyCompo
|
|||||||
}
|
}
|
||||||
public componentWillMount() {
|
public componentWillMount() {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.loadComponentFireAndForgetAsync(this.props);
|
this._loadComponentFireAndForgetAsync(this.props);
|
||||||
}
|
}
|
||||||
public componentWillReceiveProps(nextProps: LazyComponentProps) {
|
public componentWillReceiveProps(nextProps: LazyComponentProps) {
|
||||||
if (nextProps.reactComponentPromise !== this.props.reactComponentPromise) {
|
if (nextProps.reactComponentPromise !== this.props.reactComponentPromise) {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.loadComponentFireAndForgetAsync(nextProps);
|
this._loadComponentFireAndForgetAsync(nextProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
@@ -36,7 +36,7 @@ export class LazyComponent extends React.Component<LazyComponentProps, LazyCompo
|
|||||||
null :
|
null :
|
||||||
React.createElement(this.state.component, this.props.reactComponentProps);
|
React.createElement(this.state.component, this.props.reactComponentProps);
|
||||||
}
|
}
|
||||||
private async loadComponentFireAndForgetAsync(props: LazyComponentProps) {
|
private async _loadComponentFireAndForgetAsync(props: LazyComponentProps) {
|
||||||
const component = await props.reactComponentPromise;
|
const component = await props.reactComponentPromise;
|
||||||
this.setState({
|
this.setState({
|
||||||
component,
|
component,
|
||||||
|
@@ -188,10 +188,10 @@ export class About extends React.Component<AboutProps, AboutState> {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pt3 md-px4 lg-px0">
|
<div className="pt3 md-px4 lg-px0">
|
||||||
<div className="clearfix pb3">
|
<div className="clearfix pb3">
|
||||||
{this.renderProfiles(teamRow1)}
|
{this._renderProfiles(teamRow1)}
|
||||||
</div>
|
</div>
|
||||||
<div className="clearfix">
|
<div className="clearfix">
|
||||||
{this.renderProfiles(teamRow2)}
|
{this._renderProfiles(teamRow2)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt3 pb2">
|
<div className="pt3 pb2">
|
||||||
@@ -202,7 +202,7 @@ export class About extends React.Component<AboutProps, AboutState> {
|
|||||||
Advisors:
|
Advisors:
|
||||||
</div>
|
</div>
|
||||||
<div className="clearfix">
|
<div className="clearfix">
|
||||||
{this.renderProfiles(advisors)}
|
{this._renderProfiles(advisors)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto py4 sm-px3" style={{maxWidth: 308}}>
|
<div className="mx-auto py4 sm-px3" style={{maxWidth: 308}}>
|
||||||
@@ -232,7 +232,7 @@ export class About extends React.Component<AboutProps, AboutState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderProfiles(profiles: ProfileInfo[]) {
|
private _renderProfiles(profiles: ProfileInfo[]) {
|
||||||
const numIndiv = profiles.length;
|
const numIndiv = profiles.length;
|
||||||
const colSize = utils.getColSize(numIndiv);
|
const colSize = utils.getColSize(numIndiv);
|
||||||
return _.map(profiles, profile => {
|
return _.map(profiles, profile => {
|
||||||
|
@@ -19,7 +19,7 @@ export class DocsInfo {
|
|||||||
public menu: DocsMenu;
|
public menu: DocsMenu;
|
||||||
public sections: SectionsMap;
|
public sections: SectionsMap;
|
||||||
public sectionNameToMarkdown: {[sectionName: string]: string};
|
public sectionNameToMarkdown: {[sectionName: string]: string};
|
||||||
private docsInfo: DocsInfoConfig;
|
private _docsInfo: DocsInfoConfig;
|
||||||
constructor(config: DocsInfoConfig) {
|
constructor(config: DocsInfoConfig) {
|
||||||
this.displayName = config.displayName;
|
this.displayName = config.displayName;
|
||||||
this.packageUrl = config.packageUrl;
|
this.packageUrl = config.packageUrl;
|
||||||
@@ -28,32 +28,32 @@ export class DocsInfo {
|
|||||||
this.docsJsonRoot = config.docsJsonRoot;
|
this.docsJsonRoot = config.docsJsonRoot;
|
||||||
this.sections = config.sections;
|
this.sections = config.sections;
|
||||||
this.sectionNameToMarkdown = config.sectionNameToMarkdown;
|
this.sectionNameToMarkdown = config.sectionNameToMarkdown;
|
||||||
this.docsInfo = config;
|
this._docsInfo = config;
|
||||||
}
|
}
|
||||||
public isPublicType(typeName: string): boolean {
|
public isPublicType(typeName: string): boolean {
|
||||||
if (_.isUndefined(this.docsInfo.publicTypes)) {
|
if (_.isUndefined(this._docsInfo.publicTypes)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const isPublic = _.includes(this.docsInfo.publicTypes, typeName);
|
const isPublic = _.includes(this._docsInfo.publicTypes, typeName);
|
||||||
return isPublic;
|
return isPublic;
|
||||||
}
|
}
|
||||||
public getModulePathsIfExists(sectionName: string): string[] {
|
public getModulePathsIfExists(sectionName: string): string[] {
|
||||||
const modulePathsIfExists = this.docsInfo.sectionNameToModulePath[sectionName];
|
const modulePathsIfExists = this._docsInfo.sectionNameToModulePath[sectionName];
|
||||||
return modulePathsIfExists;
|
return modulePathsIfExists;
|
||||||
}
|
}
|
||||||
public getMenu(selectedVersion?: string): {[section: string]: string[]} {
|
public getMenu(selectedVersion?: string): {[section: string]: string[]} {
|
||||||
if (_.isUndefined(selectedVersion) || _.isUndefined(this.docsInfo.menuSubsectionToVersionWhenIntroduced)) {
|
if (_.isUndefined(selectedVersion) || _.isUndefined(this._docsInfo.menuSubsectionToVersionWhenIntroduced)) {
|
||||||
return this.docsInfo.menu;
|
return this._docsInfo.menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalMenu = _.cloneDeep(this.docsInfo.menu);
|
const finalMenu = _.cloneDeep(this._docsInfo.menu);
|
||||||
if (_.isUndefined(finalMenu.contracts)) {
|
if (_.isUndefined(finalMenu.contracts)) {
|
||||||
return finalMenu;
|
return finalMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor to include more sections then simply the `contracts` section
|
// TODO: refactor to include more sections then simply the `contracts` section
|
||||||
finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => {
|
finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => {
|
||||||
const versionIntroducedIfExists = this.docsInfo.menuSubsectionToVersionWhenIntroduced[contractName];
|
const versionIntroducedIfExists = this._docsInfo.menuSubsectionToVersionWhenIntroduced[contractName];
|
||||||
if (!_.isUndefined(versionIntroducedIfExists)) {
|
if (!_.isUndefined(versionIntroducedIfExists)) {
|
||||||
const existsInSelectedVersion = compareVersions(selectedVersion,
|
const existsInSelectedVersion = compareVersions(selectedVersion,
|
||||||
versionIntroducedIfExists) >= 0;
|
versionIntroducedIfExists) >= 0;
|
||||||
@@ -104,9 +104,9 @@ export class DocsInfo {
|
|||||||
return typeDefinitionByName;
|
return typeDefinitionByName;
|
||||||
}
|
}
|
||||||
public isVisibleConstructor(sectionName: string): boolean {
|
public isVisibleConstructor(sectionName: string): boolean {
|
||||||
return _.includes(this.docsInfo.visibleConstructors, sectionName);
|
return _.includes(this._docsInfo.visibleConstructors, sectionName);
|
||||||
}
|
}
|
||||||
public convertToDocAgnosticFormat(docObj: DoxityDocObj|TypeDocNode): DocAgnosticFormat {
|
public convertToDocAgnosticFormat(docObj: DoxityDocObj|TypeDocNode): DocAgnosticFormat {
|
||||||
return this.docsInfo.convertToDocAgnosticFormatFn(docObj, this);
|
return this._docsInfo.convertToDocAgnosticFormatFn(docObj, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -93,7 +93,7 @@ export class Documentation extends
|
|||||||
const versions = findVersions(lastSegment);
|
const versions = findVersions(lastSegment);
|
||||||
const preferredVersionIfExists = versions.length > 0 ? versions[0] : undefined;
|
const preferredVersionIfExists = versions.length > 0 ? versions[0] : undefined;
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists);
|
this._fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists);
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat) ?
|
const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat) ?
|
||||||
@@ -157,7 +157,7 @@ export class Documentation extends
|
|||||||
{this.props.docsInfo.displayName}
|
{this.props.docsInfo.displayName}
|
||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
{this.renderDocumentation()}
|
{this._renderDocumentation()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -165,16 +165,16 @@ export class Documentation extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderDocumentation(): React.ReactNode {
|
private _renderDocumentation(): React.ReactNode {
|
||||||
const subMenus = _.values(this.props.docsInfo.getMenu());
|
const subMenus = _.values(this.props.docsInfo.getMenu());
|
||||||
const orderedSectionNames = _.flatten(subMenus);
|
const orderedSectionNames = _.flatten(subMenus);
|
||||||
|
|
||||||
const typeDefinitionByName = this.props.docsInfo.getTypeDefinitionsByName(this.state.docAgnosticFormat);
|
const typeDefinitionByName = this.props.docsInfo.getTypeDefinitionsByName(this.state.docAgnosticFormat);
|
||||||
const renderedSections = _.map(orderedSectionNames, this.renderSection.bind(this, typeDefinitionByName));
|
const renderedSections = _.map(orderedSectionNames, this._renderSection.bind(this, typeDefinitionByName));
|
||||||
|
|
||||||
return renderedSections;
|
return renderedSections;
|
||||||
}
|
}
|
||||||
private renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode {
|
private _renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode {
|
||||||
const markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdown[sectionName];
|
const markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdown[sectionName];
|
||||||
if (!_.isUndefined(markdownFileIfExists)) {
|
if (!_.isUndefined(markdownFileIfExists)) {
|
||||||
return (
|
return (
|
||||||
@@ -203,12 +203,12 @@ export class Documentation extends
|
|||||||
});
|
});
|
||||||
|
|
||||||
const sortedProperties = _.sortBy(docSection.properties, 'name');
|
const sortedProperties = _.sortBy(docSection.properties, 'name');
|
||||||
const propertyDefs = _.map(sortedProperties, this.renderProperty.bind(this));
|
const propertyDefs = _.map(sortedProperties, this._renderProperty.bind(this));
|
||||||
|
|
||||||
const sortedMethods = _.sortBy(docSection.methods, 'name');
|
const sortedMethods = _.sortBy(docSection.methods, 'name');
|
||||||
const methodDefs = _.map(sortedMethods, method => {
|
const methodDefs = _.map(sortedMethods, method => {
|
||||||
const isConstructor = false;
|
const isConstructor = false;
|
||||||
return this.renderMethodBlocks(method, sectionName, isConstructor, typeDefinitionByName);
|
return this._renderMethodBlocks(method, sectionName, isConstructor, typeDefinitionByName);
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedEvents = _.sortBy(docSection.events, 'name');
|
const sortedEvents = _.sortBy(docSection.events, 'name');
|
||||||
@@ -230,7 +230,7 @@ export class Documentation extends
|
|||||||
<div style={{marginRight: 7}}>
|
<div style={{marginRight: 7}}>
|
||||||
<SectionHeader sectionName={sectionName} />
|
<SectionHeader sectionName={sectionName} />
|
||||||
</div>
|
</div>
|
||||||
{this.renderNetworkBadgesIfExists(sectionName)}
|
{this._renderNetworkBadgesIfExists(sectionName)}
|
||||||
</div>
|
</div>
|
||||||
{docSection.comment &&
|
{docSection.comment &&
|
||||||
<Comment
|
<Comment
|
||||||
@@ -241,7 +241,7 @@ export class Documentation extends
|
|||||||
this.props.docsInfo.isVisibleConstructor(sectionName) &&
|
this.props.docsInfo.isVisibleConstructor(sectionName) &&
|
||||||
<div>
|
<div>
|
||||||
<h2 className="thin">Constructor</h2>
|
<h2 className="thin">Constructor</h2>
|
||||||
{this.renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)}
|
{this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{docSection.properties.length > 0 &&
|
{docSection.properties.length > 0 &&
|
||||||
@@ -270,7 +270,7 @@ export class Documentation extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderNetworkBadgesIfExists(sectionName: string) {
|
private _renderNetworkBadgesIfExists(sectionName: string) {
|
||||||
const networkToAddressByContractName = configs.CONTRACT_ADDRESS[this.props.docsVersion];
|
const networkToAddressByContractName = configs.CONTRACT_ADDRESS[this.props.docsVersion];
|
||||||
const badges = _.map(networkToAddressByContractName,
|
const badges = _.map(networkToAddressByContractName,
|
||||||
(addressByContractName: AddressByContractName, networkName: string) => {
|
(addressByContractName: AddressByContractName, networkName: string) => {
|
||||||
@@ -297,11 +297,11 @@ export class Documentation extends
|
|||||||
});
|
});
|
||||||
return badges;
|
return badges;
|
||||||
}
|
}
|
||||||
private renderConstructors(constructors: SolidityMethod[]|TypescriptMethod[],
|
private _renderConstructors(constructors: SolidityMethod[]|TypescriptMethod[],
|
||||||
sectionName: string,
|
sectionName: string,
|
||||||
typeDefinitionByName: TypeDefinitionByName): React.ReactNode {
|
typeDefinitionByName: TypeDefinitionByName): React.ReactNode {
|
||||||
const constructorDefs = _.map(constructors, constructor => {
|
const constructorDefs = _.map(constructors, constructor => {
|
||||||
return this.renderMethodBlocks(
|
return this._renderMethodBlocks(
|
||||||
constructor, sectionName, constructor.isConstructor, typeDefinitionByName,
|
constructor, sectionName, constructor.isConstructor, typeDefinitionByName,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -311,7 +311,7 @@ export class Documentation extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderProperty(property: Property): React.ReactNode {
|
private _renderProperty(property: Property): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`property-${property.name}-${property.type.name}`}
|
key={`property-${property.name}-${property.type.name}`}
|
||||||
@@ -337,8 +337,8 @@ export class Documentation extends
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderMethodBlocks(method: SolidityMethod|TypescriptMethod, sectionName: string,
|
private _renderMethodBlocks(method: SolidityMethod|TypescriptMethod, sectionName: string,
|
||||||
isConstructor: boolean, typeDefinitionByName: TypeDefinitionByName): React.ReactNode {
|
isConstructor: boolean, typeDefinitionByName: TypeDefinitionByName): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<MethodBlock
|
<MethodBlock
|
||||||
key={`method-${method.name}-${sectionName}`}
|
key={`method-${method.name}-${sectionName}`}
|
||||||
@@ -349,7 +349,7 @@ export class Documentation extends
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private scrollToHash(): void {
|
private _scrollToHash(): void {
|
||||||
const hashWithPrefix = this.props.location.hash;
|
const hashWithPrefix = this.props.location.hash;
|
||||||
let hash = hashWithPrefix.slice(1);
|
let hash = hashWithPrefix.slice(1);
|
||||||
if (_.isEmpty(hash)) {
|
if (_.isEmpty(hash)) {
|
||||||
@@ -358,7 +358,7 @@ export class Documentation extends
|
|||||||
|
|
||||||
scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'});
|
scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'});
|
||||||
}
|
}
|
||||||
private async fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> {
|
private async _fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> {
|
||||||
const versionToFileName = await docUtils.getVersionToFileNameAsync(this.props.docsInfo.docsJsonRoot);
|
const versionToFileName = await docUtils.getVersionToFileNameAsync(this.props.docsInfo.docsJsonRoot);
|
||||||
const versions = _.keys(versionToFileName);
|
const versions = _.keys(versionToFileName);
|
||||||
this.props.dispatcher.updateAvailableDocVersions(versions);
|
this.props.dispatcher.updateAvailableDocVersions(versions);
|
||||||
@@ -383,7 +383,7 @@ export class Documentation extends
|
|||||||
this.setState({
|
this.setState({
|
||||||
docAgnosticFormat,
|
docAgnosticFormat,
|
||||||
}, () => {
|
}, () => {
|
||||||
this.scrollToHash();
|
this._scrollToHash();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,8 +29,8 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event
|
|||||||
id={event.name}
|
id={event.name}
|
||||||
className="pb2"
|
className="pb2"
|
||||||
style={{overflow: 'hidden', width: '100%'}}
|
style={{overflow: 'hidden', width: '100%'}}
|
||||||
onMouseOver={this.setAnchorVisibility.bind(this, true)}
|
onMouseOver={this._setAnchorVisibility.bind(this, true)}
|
||||||
onMouseOut={this.setAnchorVisibility.bind(this, false)}
|
onMouseOut={this._setAnchorVisibility.bind(this, false)}
|
||||||
>
|
>
|
||||||
<AnchorTitle
|
<AnchorTitle
|
||||||
headerSize={HeaderSizes.H3}
|
headerSize={HeaderSizes.H3}
|
||||||
@@ -41,14 +41,14 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event
|
|||||||
<div style={{fontSize: 16}}>
|
<div style={{fontSize: 16}}>
|
||||||
<pre>
|
<pre>
|
||||||
<code className="hljs">
|
<code className="hljs">
|
||||||
{this.renderEventCode()}
|
{this._renderEventCode()}
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderEventCode() {
|
private _renderEventCode() {
|
||||||
const indexed = <span style={{color: colors.green}}> indexed</span>;
|
const indexed = <span style={{color: colors.green}}> indexed</span>;
|
||||||
const eventArgs = _.map(this.props.event.eventArgs, (eventArg: EventArg) => {
|
const eventArgs = _.map(this.props.event.eventArgs, (eventArg: EventArg) => {
|
||||||
const type = (
|
const type = (
|
||||||
@@ -76,7 +76,7 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setAnchorVisibility(shouldShowAnchor: boolean) {
|
private _setAnchorVisibility(shouldShowAnchor: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowAnchor,
|
shouldShowAnchor,
|
||||||
});
|
});
|
||||||
|
@@ -57,19 +57,19 @@ export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockSt
|
|||||||
id={method.name}
|
id={method.name}
|
||||||
style={{overflow: 'hidden', width: '100%'}}
|
style={{overflow: 'hidden', width: '100%'}}
|
||||||
className="pb4"
|
className="pb4"
|
||||||
onMouseOver={this.setAnchorVisibility.bind(this, true)}
|
onMouseOver={this._setAnchorVisibility.bind(this, true)}
|
||||||
onMouseOut={this.setAnchorVisibility.bind(this, false)}
|
onMouseOut={this._setAnchorVisibility.bind(this, false)}
|
||||||
>
|
>
|
||||||
{!method.isConstructor &&
|
{!method.isConstructor &&
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{(method as TypescriptMethod).isStatic &&
|
{(method as TypescriptMethod).isStatic &&
|
||||||
this.renderChip('Static')
|
this._renderChip('Static')
|
||||||
}
|
}
|
||||||
{(method as SolidityMethod).isConstant &&
|
{(method as SolidityMethod).isConstant &&
|
||||||
this.renderChip('Constant')
|
this._renderChip('Constant')
|
||||||
}
|
}
|
||||||
{(method as SolidityMethod).isPayable &&
|
{(method as SolidityMethod).isPayable &&
|
||||||
this.renderChip('Payable')
|
this._renderChip('Payable')
|
||||||
}
|
}
|
||||||
<AnchorTitle
|
<AnchorTitle
|
||||||
headerSize={HeaderSizes.H3}
|
headerSize={HeaderSizes.H3}
|
||||||
@@ -108,7 +108,7 @@ export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockSt
|
|||||||
>
|
>
|
||||||
ARGUMENTS
|
ARGUMENTS
|
||||||
</h4>
|
</h4>
|
||||||
{this.renderParameterDescriptions(method.parameters)}
|
{this._renderParameterDescriptions(method.parameters)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{method.returnComment &&
|
{method.returnComment &&
|
||||||
@@ -127,7 +127,7 @@ export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockSt
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderChip(text: string) {
|
private _renderChip(text: string) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="p1 mr1"
|
className="p1 mr1"
|
||||||
@@ -137,7 +137,7 @@ export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockSt
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderParameterDescriptions(parameters: Parameter[]) {
|
private _renderParameterDescriptions(parameters: Parameter[]) {
|
||||||
const descriptions = _.map(parameters, parameter => {
|
const descriptions = _.map(parameters, parameter => {
|
||||||
const isOptional = parameter.isOptional;
|
const isOptional = parameter.isOptional;
|
||||||
return (
|
return (
|
||||||
@@ -166,7 +166,7 @@ export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockSt
|
|||||||
});
|
});
|
||||||
return descriptions;
|
return descriptions;
|
||||||
}
|
}
|
||||||
private setAnchorVisibility(shouldShowAnchor: boolean) {
|
private _setAnchorVisibility(shouldShowAnchor: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowAnchor,
|
shouldShowAnchor,
|
||||||
});
|
});
|
||||||
|
@@ -107,8 +107,8 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef
|
|||||||
id={this.props.shouldAddId ? typeDefinitionAnchorId : ''}
|
id={this.props.shouldAddId ? typeDefinitionAnchorId : ''}
|
||||||
className="pb2"
|
className="pb2"
|
||||||
style={{overflow: 'hidden', width: '100%'}}
|
style={{overflow: 'hidden', width: '100%'}}
|
||||||
onMouseOver={this.setAnchorVisibility.bind(this, true)}
|
onMouseOver={this._setAnchorVisibility.bind(this, true)}
|
||||||
onMouseOut={this.setAnchorVisibility.bind(this, false)}
|
onMouseOut={this._setAnchorVisibility.bind(this, false)}
|
||||||
>
|
>
|
||||||
<AnchorTitle
|
<AnchorTitle
|
||||||
headerSize={HeaderSizes.H3}
|
headerSize={HeaderSizes.H3}
|
||||||
@@ -132,7 +132,7 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setAnchorVisibility(shouldShowAnchor: boolean) {
|
private _setAnchorVisibility(shouldShowAnchor: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowAnchor,
|
shouldShowAnchor,
|
||||||
});
|
});
|
||||||
|
@@ -459,26 +459,26 @@ export class FAQ extends React.Component<FAQProps, FAQState> {
|
|||||||
>
|
>
|
||||||
<h1 className="center" style={{...styles.thin}}>0x FAQ</h1>
|
<h1 className="center" style={{...styles.thin}}>0x FAQ</h1>
|
||||||
<div className="sm-px2 md-px2 lg-px0 pb4">
|
<div className="sm-px2 md-px2 lg-px0 pb4">
|
||||||
{this.renderSections()}
|
{this._renderSections()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderSections() {
|
private _renderSections() {
|
||||||
const renderedSections = _.map(sections, (section: FAQSection, i: number) => {
|
const renderedSections = _.map(sections, (section: FAQSection, i: number) => {
|
||||||
const isFirstSection = i === 0;
|
const isFirstSection = i === 0;
|
||||||
return (
|
return (
|
||||||
<div key={section.name}>
|
<div key={section.name}>
|
||||||
<h3>{section.name}</h3>
|
<h3>{section.name}</h3>
|
||||||
{this.renderQuestions(section.questions, isFirstSection)}
|
{this._renderQuestions(section.questions, isFirstSection)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return renderedSections;
|
return renderedSections;
|
||||||
}
|
}
|
||||||
private renderQuestions(questions: FAQQuestion[], isFirstSection: boolean) {
|
private _renderQuestions(questions: FAQQuestion[], isFirstSection: boolean) {
|
||||||
const renderedQuestions = _.map(questions, (question: FAQQuestion, i: number) => {
|
const renderedQuestions = _.map(questions, (question: FAQQuestion, i: number) => {
|
||||||
const isFirstQuestion = i === 0;
|
const isFirstQuestion = i === 0;
|
||||||
return (
|
return (
|
||||||
|
@@ -27,7 +27,7 @@ export class Question extends React.Component<QuestionProps, QuestionState> {
|
|||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
initiallyExpanded={this.props.shouldDisplayExpanded}
|
initiallyExpanded={this.props.shouldDisplayExpanded}
|
||||||
onExpandChange={this.onExchangeChange.bind(this)}
|
onExpandChange={this._onExchangeChange.bind(this)}
|
||||||
>
|
>
|
||||||
<CardHeader
|
<CardHeader
|
||||||
title={this.props.prompt}
|
title={this.props.prompt}
|
||||||
@@ -45,7 +45,7 @@ export class Question extends React.Component<QuestionProps, QuestionState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onExchangeChange() {
|
private _onExchangeChange() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isExpanded: !this.state.isExpanded,
|
isExpanded: !this.state.isExpanded,
|
||||||
});
|
});
|
||||||
|
@@ -138,20 +138,20 @@ interface LandingState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Landing extends React.Component<LandingProps, LandingState> {
|
export class Landing extends React.Component<LandingProps, LandingState> {
|
||||||
private throttledScreenWidthUpdate: () => void;
|
private _throttledScreenWidthUpdate: () => void;
|
||||||
constructor(props: LandingProps) {
|
constructor(props: LandingProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
screenWidth: utils.getScreenWidth(),
|
screenWidth: utils.getScreenWidth(),
|
||||||
};
|
};
|
||||||
this.throttledScreenWidthUpdate = _.throttle(this.updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
|
||||||
}
|
}
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
window.addEventListener('resize', this.throttledScreenWidthUpdate);
|
window.addEventListener('resize', this._throttledScreenWidthUpdate);
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
window.removeEventListener('resize', this.throttledScreenWidthUpdate);
|
window.removeEventListener('resize', this._throttledScreenWidthUpdate);
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
@@ -163,19 +163,19 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
isNightVersion={true}
|
isNightVersion={true}
|
||||||
style={{backgroundColor: colors.heroGrey, position: 'relative'}}
|
style={{backgroundColor: colors.heroGrey, position: 'relative'}}
|
||||||
/>
|
/>
|
||||||
{this.renderHero()}
|
{this._renderHero()}
|
||||||
{this.renderProjects()}
|
{this._renderProjects()}
|
||||||
{this.renderTokenizationSection()}
|
{this._renderTokenizationSection()}
|
||||||
{this.renderProtocolSection()}
|
{this._renderProtocolSection()}
|
||||||
{this.renderInfoBoxes()}
|
{this._renderInfoBoxes()}
|
||||||
{this.renderBuildingBlocksSection()}
|
{this._renderBuildingBlocksSection()}
|
||||||
{this.renderUseCases()}
|
{this._renderUseCases()}
|
||||||
{this.renderCallToAction()}
|
{this._renderCallToAction()}
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderHero() {
|
private _renderHero() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
const buttonLabelStyle: React.CSSProperties = {
|
const buttonLabelStyle: React.CSSProperties = {
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
@@ -259,7 +259,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderProjects() {
|
private _renderProjects() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
const isMediumScreen = this.state.screenWidth === ScreenWidths.Md;
|
const isMediumScreen = this.state.screenWidth === ScreenWidths.Md;
|
||||||
const projectList = _.map(projects, (project: Project, i: number) => {
|
const projectList = _.map(projects, (project: Project, i: number) => {
|
||||||
@@ -323,7 +323,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderTokenizationSection() {
|
private _renderTokenizationSection() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -332,7 +332,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
>
|
>
|
||||||
<div className="mx-auto max-width-4 py4 clearfix">
|
<div className="mx-auto max-width-4 py4 clearfix">
|
||||||
{isSmallScreen &&
|
{isSmallScreen &&
|
||||||
this.renderTokenCloud()
|
this._renderTokenCloud()
|
||||||
}
|
}
|
||||||
<div className="col lg-col-6 md-col-6 col-12">
|
<div className="col lg-col-6 md-col-6 col-12">
|
||||||
<div className="mx-auto" style={{maxWidth: 385, paddingTop: 7}}>
|
<div className="mx-auto" style={{maxWidth: 385, paddingTop: 7}}>
|
||||||
@@ -365,18 +365,18 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex pt1 sm-px3">
|
<div className="flex pt1 sm-px3">
|
||||||
{this.renderAssetTypes()}
|
{this._renderAssetTypes()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!isSmallScreen &&
|
{!isSmallScreen &&
|
||||||
this.renderTokenCloud()
|
this._renderTokenCloud()
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderProtocolSection() {
|
private _renderProtocolSection() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -462,7 +462,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderBuildingBlocksSection() {
|
private _renderBuildingBlocksSection() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
const descriptionStyle: React.CSSProperties = {
|
const descriptionStyle: React.CSSProperties = {
|
||||||
fontFamily: 'Roboto Mono',
|
fontFamily: 'Roboto Mono',
|
||||||
@@ -484,7 +484,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
>
|
>
|
||||||
<div className="mx-auto max-width-4 lg-pt4 md-pt4 lg-mb4 md-mb4 sm-mb2 clearfix">
|
<div className="mx-auto max-width-4 lg-pt4 md-pt4 lg-mb4 md-mb4 sm-mb2 clearfix">
|
||||||
{isSmallScreen &&
|
{isSmallScreen &&
|
||||||
this.renderBlockChipImage()
|
this._renderBlockChipImage()
|
||||||
}
|
}
|
||||||
<div
|
<div
|
||||||
className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-px3"
|
className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-px3"
|
||||||
@@ -528,13 +528,13 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!isSmallScreen &&
|
{!isSmallScreen &&
|
||||||
this.renderBlockChipImage()
|
this._renderBlockChipImage()
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderBlockChipImage() {
|
private _renderBlockChipImage() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
return (
|
return (
|
||||||
<div className="col lg-col-6 md-col-6 col-12 sm-center">
|
<div className="col lg-col-6 md-col-6 col-12 sm-center">
|
||||||
@@ -545,7 +545,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderTokenCloud() {
|
private _renderTokenCloud() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
return (
|
return (
|
||||||
<div className="col lg-col-6 md-col-6 col-12 center">
|
<div className="col lg-col-6 md-col-6 col-12 center">
|
||||||
@@ -556,7 +556,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderAssetTypes() {
|
private _renderAssetTypes() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
const assetTypes: AssetType[] = [
|
const assetTypes: AssetType[] = [
|
||||||
{
|
{
|
||||||
@@ -595,7 +595,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
});
|
});
|
||||||
return assets;
|
return assets;
|
||||||
}
|
}
|
||||||
private renderInfoBoxes() {
|
private _renderInfoBoxes() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
const boxStyle: React.CSSProperties = {
|
const boxStyle: React.CSSProperties = {
|
||||||
maxWidth: 252,
|
maxWidth: 252,
|
||||||
@@ -648,7 +648,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderUseCases() {
|
private _renderUseCases() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
|
|
||||||
const useCases: UseCase[] = [
|
const useCases: UseCase[] = [
|
||||||
@@ -759,7 +759,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderCallToAction() {
|
private _renderCallToAction() {
|
||||||
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm;
|
||||||
const buttonLabelStyle: React.CSSProperties = {
|
const buttonLabelStyle: React.CSSProperties = {
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
@@ -805,7 +805,7 @@ export class Landing extends React.Component<LandingProps, LandingState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private updateScreenWidth() {
|
private _updateScreenWidth() {
|
||||||
const newScreenWidth = utils.getScreenWidth();
|
const newScreenWidth = utils.getScreenWidth();
|
||||||
if (newScreenWidth !== this.state.screenWidth) {
|
if (newScreenWidth !== this.state.screenWidth) {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@@ -79,14 +79,14 @@ export class AnchorTitle extends React.Component<AnchorTitleProps, AnchorTitleSt
|
|||||||
className="zmdi zmdi-link"
|
className="zmdi zmdi-link"
|
||||||
onClick={utils.setUrlHash.bind(utils, this.props.id)}
|
onClick={utils.setUrlHash.bind(utils, this.props.id)}
|
||||||
style={{...styles.anchor, opacity}}
|
style={{...styles.anchor, opacity}}
|
||||||
onMouseOver={this.setHoverState.bind(this, true)}
|
onMouseOver={this._setHoverState.bind(this, true)}
|
||||||
onMouseOut={this.setHoverState.bind(this, false)}
|
onMouseOut={this._setHoverState.bind(this, false)}
|
||||||
/>
|
/>
|
||||||
</ScrollLink>
|
</ScrollLink>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setHoverState(isHovering: boolean) {
|
private _setHoverState(isHovering: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isHovering,
|
isHovering,
|
||||||
});
|
});
|
||||||
|
@@ -35,8 +35,8 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="pt2 pr3 md-pl2 sm-pl3 overflow-hidden"
|
className="pt2 pr3 md-pl2 sm-pl3 overflow-hidden"
|
||||||
onMouseOver={this.setAnchorVisibility.bind(this, true)}
|
onMouseOver={this._setAnchorVisibility.bind(this, true)}
|
||||||
onMouseOut={this.setAnchorVisibility.bind(this, false)}
|
onMouseOut={this._setAnchorVisibility.bind(this, false)}
|
||||||
>
|
>
|
||||||
<ScrollElement name={id}>
|
<ScrollElement name={id}>
|
||||||
<div className="clearfix">
|
<div className="clearfix">
|
||||||
@@ -69,7 +69,7 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setAnchorVisibility(shouldShowAnchor: boolean) {
|
private _setAnchorVisibility(shouldShowAnchor: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowAnchor,
|
shouldShowAnchor,
|
||||||
});
|
});
|
||||||
|
@@ -61,13 +61,13 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
|
|||||||
{finalSectionName.toUpperCase()}
|
{finalSectionName.toUpperCase()}
|
||||||
</div>
|
</div>
|
||||||
</ScrollLink>
|
</ScrollLink>
|
||||||
{this.renderMenuItems(menuItems)}
|
{this._renderMenuItems(menuItems)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div key={`section-${sectionName}`} >
|
<div key={`section-${sectionName}`} >
|
||||||
{this.renderMenuItems(menuItems)}
|
{this._renderMenuItems(menuItems)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderMenuItems(menuItemNames: string[]): React.ReactNode[] {
|
private _renderMenuItems(menuItemNames: string[]): React.ReactNode[] {
|
||||||
const menuItemStyles = this.props.shouldDisplaySectionHeaders ?
|
const menuItemStyles = this.props.shouldDisplaySectionHeaders ?
|
||||||
styles.menuItemWithHeaders :
|
styles.menuItemWithHeaders :
|
||||||
styles.menuItemWithoutHeaders;
|
styles.menuItemWithoutHeaders;
|
||||||
@@ -105,7 +105,7 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
|
|||||||
containerId={constants.DOCS_CONTAINER_ID}
|
containerId={constants.DOCS_CONTAINER_ID}
|
||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onTouchTap={this.onMenuItemClick.bind(this, menuItemName)}
|
onTouchTap={this._onMenuItemClick.bind(this, menuItemName)}
|
||||||
style={menuItemStyles}
|
style={menuItemStyles}
|
||||||
innerDivStyle={menuItemInnerDivStyles}
|
innerDivStyle={menuItemInnerDivStyles}
|
||||||
>
|
>
|
||||||
@@ -114,19 +114,19 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
|
|||||||
</span>
|
</span>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</ScrollLink>
|
</ScrollLink>
|
||||||
{this.renderMenuItemSubsections(menuItemName)}
|
{this._renderMenuItemSubsections(menuItemName)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return menuItems;
|
return menuItems;
|
||||||
}
|
}
|
||||||
private renderMenuItemSubsections(menuItemName: string): React.ReactNode {
|
private _renderMenuItemSubsections(menuItemName: string): React.ReactNode {
|
||||||
if (_.isUndefined(this.props.menuSubsectionsBySection[menuItemName])) {
|
if (_.isUndefined(this.props.menuSubsectionsBySection[menuItemName])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.renderMenuSubsectionsBySection(menuItemName, this.props.menuSubsectionsBySection[menuItemName]);
|
return this._renderMenuSubsectionsBySection(menuItemName, this.props.menuSubsectionsBySection[menuItemName]);
|
||||||
}
|
}
|
||||||
private renderMenuSubsectionsBySection(menuItemName: string, entityNames: string[]): React.ReactNode {
|
private _renderMenuSubsectionsBySection(menuItemName: string, entityNames: string[]): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<ul style={{margin: 0, listStyleType: 'none', paddingLeft: 0}} key={menuItemName}>
|
<ul style={{margin: 0, listStyleType: 'none', paddingLeft: 0}} key={menuItemName}>
|
||||||
{_.map(entityNames, entityName => {
|
{_.map(entityNames, entityName => {
|
||||||
@@ -138,10 +138,10 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
|
|||||||
offset={0}
|
offset={0}
|
||||||
duration={constants.DOCS_SCROLL_DURATION_MS}
|
duration={constants.DOCS_SCROLL_DURATION_MS}
|
||||||
containerId={constants.DOCS_CONTAINER_ID}
|
containerId={constants.DOCS_CONTAINER_ID}
|
||||||
onTouchTap={this.onMenuItemClick.bind(this, entityName)}
|
onTouchTap={this._onMenuItemClick.bind(this, entityName)}
|
||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onTouchTap={this.onMenuItemClick.bind(this, menuItemName)}
|
onTouchTap={this._onMenuItemClick.bind(this, menuItemName)}
|
||||||
style={{minHeight: 35}}
|
style={{minHeight: 35}}
|
||||||
innerDivStyle={{paddingLeft: 36, fontSize: 14, lineHeight: '35px'}}
|
innerDivStyle={{paddingLeft: 36, fontSize: 14, lineHeight: '35px'}}
|
||||||
>
|
>
|
||||||
@@ -154,7 +154,7 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
|
|||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private onMenuItemClick(menuItemName: string): void {
|
private _onMenuItemClick(menuItemName: string): void {
|
||||||
const id = utils.getIdFromName(menuItemName);
|
const id = utils.getIdFromName(menuItemName);
|
||||||
utils.setUrlHash(id);
|
utils.setUrlHash(id);
|
||||||
this.props.onMenuItemClick();
|
this.props.onMenuItemClick();
|
||||||
|
@@ -28,8 +28,8 @@ export class SectionHeader extends React.Component<SectionHeaderProps, SectionHe
|
|||||||
const id = utils.getIdFromName(sectionName);
|
const id = utils.getIdFromName(sectionName);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onMouseOver={this.setAnchorVisibility.bind(this, true)}
|
onMouseOver={this._setAnchorVisibility.bind(this, true)}
|
||||||
onMouseOut={this.setAnchorVisibility.bind(this, false)}
|
onMouseOut={this._setAnchorVisibility.bind(this, false)}
|
||||||
>
|
>
|
||||||
<ScrollElement name={id}>
|
<ScrollElement name={id}>
|
||||||
<AnchorTitle
|
<AnchorTitle
|
||||||
@@ -42,7 +42,7 @@ export class SectionHeader extends React.Component<SectionHeaderProps, SectionHe
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private setAnchorVisibility(shouldShowAnchor: boolean) {
|
private _setAnchorVisibility(shouldShowAnchor: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
shouldShowAnchor,
|
shouldShowAnchor,
|
||||||
});
|
});
|
||||||
|
@@ -18,14 +18,14 @@ export class VersionDropDown extends React.Component<VersionDropDownProps, Versi
|
|||||||
<DropDownMenu
|
<DropDownMenu
|
||||||
maxHeight={300}
|
maxHeight={300}
|
||||||
value={this.props.selectedVersion}
|
value={this.props.selectedVersion}
|
||||||
onChange={this.updateSelectedVersion.bind(this)}
|
onChange={this._updateSelectedVersion.bind(this)}
|
||||||
>
|
>
|
||||||
{this.renderDropDownItems()}
|
{this._renderDropDownItems()}
|
||||||
</DropDownMenu>
|
</DropDownMenu>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderDropDownItems() {
|
private _renderDropDownItems() {
|
||||||
const items = _.map(this.props.versions, version => {
|
const items = _.map(this.props.versions, version => {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@@ -37,7 +37,7 @@ export class VersionDropDown extends React.Component<VersionDropDownProps, Versi
|
|||||||
});
|
});
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
private updateSelectedVersion(e: any, index: number, value: string) {
|
private _updateSelectedVersion(e: any, index: number, value: string) {
|
||||||
window.location.href = `${this.props.docPath}/${value}${window.location.hash}`;
|
window.location.href = `${this.props.docPath}/${value}${window.location.hash}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,7 @@ const styles: Styles = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class Wiki extends React.Component<WikiProps, WikiState> {
|
export class Wiki extends React.Component<WikiProps, WikiState> {
|
||||||
private wikiBackoffTimeoutId: number;
|
private _wikiBackoffTimeoutId: number;
|
||||||
constructor(props: WikiProps) {
|
constructor(props: WikiProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -55,15 +55,15 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
}
|
}
|
||||||
public componentWillMount() {
|
public componentWillMount() {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.fetchArticlesBySectionAsync();
|
this._fetchArticlesBySectionAsync();
|
||||||
}
|
}
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
clearTimeout(this.wikiBackoffTimeoutId);
|
clearTimeout(this._wikiBackoffTimeoutId);
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const menuSubsectionsBySection = _.isUndefined(this.state.articlesBySection)
|
const menuSubsectionsBySection = _.isUndefined(this.state.articlesBySection)
|
||||||
? {}
|
? {}
|
||||||
: this.getMenuSubsectionsBySection(this.state.articlesBySection);
|
: this._getMenuSubsectionsBySection(this.state.articlesBySection);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<DocumentTitle title="0x Protocol Wiki"/>
|
<DocumentTitle title="0x Protocol Wiki"/>
|
||||||
@@ -117,7 +117,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
<div id="wiki">
|
<div id="wiki">
|
||||||
{this.renderWikiArticles()}
|
{this._renderWikiArticles()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,12 +126,12 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private renderWikiArticles(): React.ReactNode {
|
private _renderWikiArticles(): React.ReactNode {
|
||||||
const sectionNames = _.keys(this.state.articlesBySection);
|
const sectionNames = _.keys(this.state.articlesBySection);
|
||||||
const sections = _.map(sectionNames, sectionName => this.renderSection(sectionName));
|
const sections = _.map(sectionNames, sectionName => this._renderSection(sectionName));
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
private renderSection(sectionName: string) {
|
private _renderSection(sectionName: string) {
|
||||||
const articles = this.state.articlesBySection[sectionName];
|
const articles = this.state.articlesBySection[sectionName];
|
||||||
const renderedArticles = _.map(articles, (article: Article) => {
|
const renderedArticles = _.map(articles, (article: Article) => {
|
||||||
const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`;
|
const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`;
|
||||||
@@ -165,7 +165,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private scrollToHash(): void {
|
private _scrollToHash(): void {
|
||||||
const hashWithPrefix = this.props.location.hash;
|
const hashWithPrefix = this.props.location.hash;
|
||||||
let hash = hashWithPrefix.slice(1);
|
let hash = hashWithPrefix.slice(1);
|
||||||
if (_.isEmpty(hash)) {
|
if (_.isEmpty(hash)) {
|
||||||
@@ -174,14 +174,14 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
|
|
||||||
scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'});
|
scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'});
|
||||||
}
|
}
|
||||||
private async fetchArticlesBySectionAsync(): Promise<void> {
|
private async _fetchArticlesBySectionAsync(): Promise<void> {
|
||||||
const endpoint = `${configs.BACKEND_BASE_URL}${WebsitePaths.Wiki}`;
|
const endpoint = `${configs.BACKEND_BASE_URL}${WebsitePaths.Wiki}`;
|
||||||
const response = await fetch(endpoint);
|
const response = await fetch(endpoint);
|
||||||
if (response.status === constants.HTTP_NO_CONTENT_STATUS_CODE) {
|
if (response.status === constants.HTTP_NO_CONTENT_STATUS_CODE) {
|
||||||
// We need to backoff and try fetching again later
|
// We need to backoff and try fetching again later
|
||||||
this.wikiBackoffTimeoutId = window.setTimeout(() => {
|
this._wikiBackoffTimeoutId = window.setTimeout(() => {
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.fetchArticlesBySectionAsync();
|
this._fetchArticlesBySectionAsync();
|
||||||
}, WIKI_NOT_READY_BACKOUT_TIMEOUT_MS);
|
}, WIKI_NOT_READY_BACKOUT_TIMEOUT_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -195,10 +195,10 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
articlesBySection,
|
articlesBySection,
|
||||||
}, () => {
|
}, () => {
|
||||||
this.scrollToHash();
|
this._scrollToHash();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) {
|
private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) {
|
||||||
const sectionNames = _.keys(articlesBySection);
|
const sectionNames = _.keys(articlesBySection);
|
||||||
const menuSubsectionsBySection: {[section: string]: string[]} = {};
|
const menuSubsectionsBySection: {[section: string]: string[]} = {};
|
||||||
for (const sectionName of sectionNames) {
|
for (const sectionName of sectionNames) {
|
||||||
|
@@ -15,53 +15,53 @@ import {
|
|||||||
} from 'ts/types';
|
} from 'ts/types';
|
||||||
|
|
||||||
export class Dispatcher {
|
export class Dispatcher {
|
||||||
private dispatch: Dispatch<State>;
|
private _dispatch: Dispatch<State>;
|
||||||
constructor(dispatch: Dispatch<State>) {
|
constructor(dispatch: Dispatch<State>) {
|
||||||
this.dispatch = dispatch;
|
this._dispatch = dispatch;
|
||||||
}
|
}
|
||||||
// Portal
|
// Portal
|
||||||
public resetState() {
|
public resetState() {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
type: ActionTypes.ResetState,
|
type: ActionTypes.ResetState,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateNodeVersion(nodeVersion: string) {
|
public updateNodeVersion(nodeVersion: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: nodeVersion,
|
data: nodeVersion,
|
||||||
type: ActionTypes.UpdateNodeVersion,
|
type: ActionTypes.UpdateNodeVersion,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateScreenWidth(screenWidth: ScreenWidths) {
|
public updateScreenWidth(screenWidth: ScreenWidths) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: screenWidth,
|
data: screenWidth,
|
||||||
type: ActionTypes.UpdateScreenWidth,
|
type: ActionTypes.UpdateScreenWidth,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public swapAssetTokenSymbols() {
|
public swapAssetTokenSymbols() {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
type: ActionTypes.SwapAssetTokens,
|
type: ActionTypes.SwapAssetTokens,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateOrderSalt(salt: BigNumber) {
|
public updateOrderSalt(salt: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: salt,
|
data: salt,
|
||||||
type: ActionTypes.UpdateOrderSalt,
|
type: ActionTypes.UpdateOrderSalt,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateUserSuppliedOrderCache(order: Order) {
|
public updateUserSuppliedOrderCache(order: Order) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: order,
|
data: order,
|
||||||
type: ActionTypes.UpdateUserSuppliedOrderCache,
|
type: ActionTypes.UpdateUserSuppliedOrderCache,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateShouldBlockchainErrDialogBeOpen(shouldBeOpen: boolean) {
|
public updateShouldBlockchainErrDialogBeOpen(shouldBeOpen: boolean) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: shouldBeOpen,
|
data: shouldBeOpen,
|
||||||
type: ActionTypes.UpdateShouldBlockchainErrDialogBeOpen,
|
type: ActionTypes.UpdateShouldBlockchainErrDialogBeOpen,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateChosenAssetToken(side: Side, token: AssetToken) {
|
public updateChosenAssetToken(side: Side, token: AssetToken) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: {
|
data: {
|
||||||
side,
|
side,
|
||||||
token,
|
token,
|
||||||
@@ -70,7 +70,7 @@ export class Dispatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateChosenAssetTokenAddress(side: Side, address: string) {
|
public updateChosenAssetTokenAddress(side: Side, address: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: {
|
data: {
|
||||||
address,
|
address,
|
||||||
side,
|
side,
|
||||||
@@ -79,72 +79,72 @@ export class Dispatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateOrderTakerAddress(address: string) {
|
public updateOrderTakerAddress(address: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: address,
|
data: address,
|
||||||
type: ActionTypes.UpdateOrderTakerAddress,
|
type: ActionTypes.UpdateOrderTakerAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateUserAddress(address: string) {
|
public updateUserAddress(address: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: address,
|
data: address,
|
||||||
type: ActionTypes.UpdateUserAddress,
|
type: ActionTypes.UpdateUserAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateOrderExpiry(unixTimestampSec: BigNumber) {
|
public updateOrderExpiry(unixTimestampSec: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: unixTimestampSec,
|
data: unixTimestampSec,
|
||||||
type: ActionTypes.UpdateOrderExpiry,
|
type: ActionTypes.UpdateOrderExpiry,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public encounteredBlockchainError(err: BlockchainErrs) {
|
public encounteredBlockchainError(err: BlockchainErrs) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: err,
|
data: err,
|
||||||
type: ActionTypes.BlockchainErrEncountered,
|
type: ActionTypes.BlockchainErrEncountered,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateBlockchainIsLoaded(isLoaded: boolean) {
|
public updateBlockchainIsLoaded(isLoaded: boolean) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: isLoaded,
|
data: isLoaded,
|
||||||
type: ActionTypes.UpdateBlockchainIsLoaded,
|
type: ActionTypes.UpdateBlockchainIsLoaded,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public addTokenToTokenByAddress(token: Token) {
|
public addTokenToTokenByAddress(token: Token) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: token,
|
data: token,
|
||||||
type: ActionTypes.AddTokenToTokenByAddress,
|
type: ActionTypes.AddTokenToTokenByAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public removeTokenToTokenByAddress(token: Token) {
|
public removeTokenToTokenByAddress(token: Token) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: token,
|
data: token,
|
||||||
type: ActionTypes.RemoveTokenFromTokenByAddress,
|
type: ActionTypes.RemoveTokenFromTokenByAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public clearTokenByAddress() {
|
public clearTokenByAddress() {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
type: ActionTypes.ClearTokenByAddress,
|
type: ActionTypes.ClearTokenByAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateTokenByAddress(tokens: Token[]) {
|
public updateTokenByAddress(tokens: Token[]) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: tokens,
|
data: tokens,
|
||||||
type: ActionTypes.UpdateTokenByAddress,
|
type: ActionTypes.UpdateTokenByAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateTokenStateByAddress(tokenStateByAddress: TokenStateByAddress) {
|
public updateTokenStateByAddress(tokenStateByAddress: TokenStateByAddress) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: tokenStateByAddress,
|
data: tokenStateByAddress,
|
||||||
type: ActionTypes.UpdateTokenStateByAddress,
|
type: ActionTypes.UpdateTokenStateByAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public removeFromTokenStateByAddress(tokenAddress: string) {
|
public removeFromTokenStateByAddress(tokenAddress: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: tokenAddress,
|
data: tokenAddress,
|
||||||
type: ActionTypes.RemoveFromTokenStateByAddress,
|
type: ActionTypes.RemoveFromTokenStateByAddress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public replaceTokenAllowanceByAddress(address: string, allowance: BigNumber) {
|
public replaceTokenAllowanceByAddress(address: string, allowance: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: {
|
data: {
|
||||||
address,
|
address,
|
||||||
allowance,
|
allowance,
|
||||||
@@ -153,7 +153,7 @@ export class Dispatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public replaceTokenBalanceByAddress(address: string, balance: BigNumber) {
|
public replaceTokenBalanceByAddress(address: string, balance: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: {
|
data: {
|
||||||
address,
|
address,
|
||||||
balance,
|
balance,
|
||||||
@@ -162,7 +162,7 @@ export class Dispatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateTokenBalanceByAddress(address: string, balanceDelta: BigNumber) {
|
public updateTokenBalanceByAddress(address: string, balanceDelta: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: {
|
data: {
|
||||||
address,
|
address,
|
||||||
balanceDelta,
|
balanceDelta,
|
||||||
@@ -171,25 +171,25 @@ export class Dispatcher {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateSignatureData(signatureData: SignatureData) {
|
public updateSignatureData(signatureData: SignatureData) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: signatureData,
|
data: signatureData,
|
||||||
type: ActionTypes.UpdateOrderSignatureData,
|
type: ActionTypes.UpdateOrderSignatureData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateUserEtherBalance(balance: BigNumber) {
|
public updateUserEtherBalance(balance: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: balance,
|
data: balance,
|
||||||
type: ActionTypes.UpdateUserEtherBalance,
|
type: ActionTypes.UpdateUserEtherBalance,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateNetworkId(networkId: number) {
|
public updateNetworkId(networkId: number) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: networkId,
|
data: networkId,
|
||||||
type: ActionTypes.UpdateNetworkId,
|
type: ActionTypes.UpdateNetworkId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateOrderFillAmount(amount: BigNumber) {
|
public updateOrderFillAmount(amount: BigNumber) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: amount,
|
data: amount,
|
||||||
type: ActionTypes.UpdateOrderFillAmount,
|
type: ActionTypes.UpdateOrderFillAmount,
|
||||||
});
|
});
|
||||||
@@ -197,13 +197,13 @@ export class Dispatcher {
|
|||||||
|
|
||||||
// Docs
|
// Docs
|
||||||
public updateCurrentDocsVersion(version: string) {
|
public updateCurrentDocsVersion(version: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: version,
|
data: version,
|
||||||
type: ActionTypes.UpdateLibraryVersion,
|
type: ActionTypes.UpdateLibraryVersion,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateAvailableDocVersions(versions: string[]) {
|
public updateAvailableDocVersions(versions: string[]) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: versions,
|
data: versions,
|
||||||
type: ActionTypes.UpdateAvailableLibraryVersions,
|
type: ActionTypes.UpdateAvailableLibraryVersions,
|
||||||
});
|
});
|
||||||
@@ -211,24 +211,24 @@ export class Dispatcher {
|
|||||||
|
|
||||||
// Shared
|
// Shared
|
||||||
public showFlashMessage(msg: string|React.ReactNode) {
|
public showFlashMessage(msg: string|React.ReactNode) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
data: msg,
|
data: msg,
|
||||||
type: ActionTypes.ShowFlashMessage,
|
type: ActionTypes.ShowFlashMessage,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public hideFlashMessage() {
|
public hideFlashMessage() {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
type: ActionTypes.HideFlashMessage,
|
type: ActionTypes.HideFlashMessage,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateProviderType(providerType: ProviderType) {
|
public updateProviderType(providerType: ProviderType) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
type: ActionTypes.UpdateProviderType,
|
type: ActionTypes.UpdateProviderType,
|
||||||
data: providerType,
|
data: providerType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateInjectedProviderName(injectedProviderName: string) {
|
public updateInjectedProviderName(injectedProviderName: string) {
|
||||||
this.dispatch({
|
this._dispatch({
|
||||||
type: ActionTypes.UpdateInjectedProviderName,
|
type: ActionTypes.UpdateInjectedProviderName,
|
||||||
data: injectedProviderName,
|
data: injectedProviderName,
|
||||||
});
|
});
|
||||||
|
@@ -5,15 +5,15 @@ import {signatureDataSchema} from 'ts/schemas/signature_data_schema';
|
|||||||
import {tokenSchema} from 'ts/schemas/token_schema';
|
import {tokenSchema} from 'ts/schemas/token_schema';
|
||||||
|
|
||||||
export class SchemaValidator {
|
export class SchemaValidator {
|
||||||
private validator: Validator;
|
private _validator: Validator;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.validator = new Validator();
|
this._validator = new Validator();
|
||||||
this.validator.addSchema(signatureDataSchema as JSONSchema, signatureDataSchema.id);
|
this._validator.addSchema(signatureDataSchema as JSONSchema, signatureDataSchema.id);
|
||||||
this.validator.addSchema(tokenSchema as JSONSchema, tokenSchema.id);
|
this._validator.addSchema(tokenSchema as JSONSchema, tokenSchema.id);
|
||||||
this.validator.addSchema(orderTakerSchema as JSONSchema, orderTakerSchema.id);
|
this._validator.addSchema(orderTakerSchema as JSONSchema, orderTakerSchema.id);
|
||||||
this.validator.addSchema(orderSchema as JSONSchema, orderSchema.id);
|
this._validator.addSchema(orderSchema as JSONSchema, orderSchema.id);
|
||||||
}
|
}
|
||||||
public validate(instance: object, schema: Schema) {
|
public validate(instance: object, schema: Schema) {
|
||||||
return this.validator.validate(instance, schema);
|
return this._validator.validate(instance, schema);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,30 +5,30 @@ import {Dispatcher} from 'ts/redux/dispatcher';
|
|||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
export class Web3Wrapper {
|
export class Web3Wrapper {
|
||||||
private dispatcher: Dispatcher;
|
private _dispatcher: Dispatcher;
|
||||||
private web3: Web3;
|
private _web3: Web3;
|
||||||
private prevNetworkId: number;
|
private _prevNetworkId: number;
|
||||||
private shouldPollUserAddress: boolean;
|
private _shouldPollUserAddress: boolean;
|
||||||
private watchNetworkAndBalanceIntervalId: NodeJS.Timer;
|
private _watchNetworkAndBalanceIntervalId: NodeJS.Timer;
|
||||||
private prevUserEtherBalanceInEth: BigNumber;
|
private _prevUserEtherBalanceInEth: BigNumber;
|
||||||
private prevUserAddress: string;
|
private _prevUserAddress: string;
|
||||||
constructor(dispatcher: Dispatcher, provider: Web3.Provider, networkIdIfExists: number,
|
constructor(dispatcher: Dispatcher, provider: Web3.Provider, networkIdIfExists: number,
|
||||||
shouldPollUserAddress: boolean) {
|
shouldPollUserAddress: boolean) {
|
||||||
this.dispatcher = dispatcher;
|
this._dispatcher = dispatcher;
|
||||||
this.prevNetworkId = networkIdIfExists;
|
this._prevNetworkId = networkIdIfExists;
|
||||||
this.shouldPollUserAddress = shouldPollUserAddress;
|
this._shouldPollUserAddress = shouldPollUserAddress;
|
||||||
|
|
||||||
this.web3 = new Web3();
|
this._web3 = new Web3();
|
||||||
this.web3.setProvider(provider);
|
this._web3.setProvider(provider);
|
||||||
|
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.startEmittingNetworkConnectionAndUserBalanceStateAsync();
|
this._startEmittingNetworkConnectionAndUserBalanceStateAsync();
|
||||||
}
|
}
|
||||||
public isAddress(address: string) {
|
public isAddress(address: string) {
|
||||||
return this.web3.isAddress(address);
|
return this._web3.isAddress(address);
|
||||||
}
|
}
|
||||||
public async getAccountsAsync(): Promise<string[]> {
|
public async getAccountsAsync(): Promise<string[]> {
|
||||||
const addresses = await promisify<string[]>(this.web3.eth.getAccounts)();
|
const addresses = await promisify<string[]>(this._web3.eth.getAccounts)();
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
public async getFirstAccountIfExistsAsync() {
|
public async getFirstAccountIfExistsAsync() {
|
||||||
@@ -39,109 +39,109 @@ export class Web3Wrapper {
|
|||||||
return (addresses)[0];
|
return (addresses)[0];
|
||||||
}
|
}
|
||||||
public async getNodeVersionAsync(): Promise<string> {
|
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;
|
return nodeVersion;
|
||||||
}
|
}
|
||||||
public getProviderObj() {
|
public getProviderObj() {
|
||||||
return this.web3.currentProvider;
|
return this._web3.currentProvider;
|
||||||
}
|
}
|
||||||
public async getNetworkIdIfExists() {
|
public async getNetworkIdIfExists() {
|
||||||
try {
|
try {
|
||||||
const networkId = await this.getNetworkAsync();
|
const networkId = await this._getNetworkAsync();
|
||||||
return Number(networkId);
|
return Number(networkId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
||||||
const balanceInWei: BigNumber = await promisify<BigNumber>(this.web3.eth.getBalance)(owner);
|
const balanceInWei: BigNumber = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
|
||||||
const balanceEthOldBigNumber = this.web3.fromWei(balanceInWei, 'ether');
|
const balanceEthOldBigNumber = this._web3.fromWei(balanceInWei, 'ether');
|
||||||
const balanceEth = new BigNumber(balanceEthOldBigNumber);
|
const balanceEth = new BigNumber(balanceEthOldBigNumber);
|
||||||
return balanceEth;
|
return balanceEth;
|
||||||
}
|
}
|
||||||
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
|
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 accomodate poorly implemented clients
|
// Regex matches 0x0, 0x00, 0x in order to accomodate poorly implemented clients
|
||||||
const zeroHexAddressRegex = /^0[xX][0]*$/;
|
const zeroHexAddressRegex = /^0[xX][0]*$/;
|
||||||
const didFindCode = _.isNull(code.match(zeroHexAddressRegex));
|
const didFindCode = _.isNull(code.match(zeroHexAddressRegex));
|
||||||
return didFindCode;
|
return didFindCode;
|
||||||
}
|
}
|
||||||
public async signTransactionAsync(address: string, message: string): Promise<string> {
|
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;
|
return signData;
|
||||||
}
|
}
|
||||||
public async getBlockTimestampAsync(blockHash: string): Promise<number> {
|
public async getBlockTimestampAsync(blockHash: string): Promise<number> {
|
||||||
const {timestamp} = await promisify<Web3.BlockWithoutTransactionData>(this.web3.eth.getBlock)(blockHash);
|
const {timestamp} = await promisify<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockHash);
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.stopEmittingNetworkConnectionAndUserBalanceStateAsync();
|
this._stopEmittingNetworkConnectionAndUserBalanceStateAsync();
|
||||||
// HACK: stop() is only available on providerEngine instances
|
// HACK: stop() is only available on providerEngine instances
|
||||||
const provider = this.web3.currentProvider;
|
const provider = this._web3.currentProvider;
|
||||||
if (!_.isUndefined((provider as any).stop)) {
|
if (!_.isUndefined((provider as any).stop)) {
|
||||||
(provider as any).stop();
|
(provider as any).stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This should only be called from the LedgerConfigDialog
|
// This should only be called from the LedgerConfigDialog
|
||||||
public updatePrevUserAddress(userAddress: string) {
|
public updatePrevUserAddress(userAddress: string) {
|
||||||
this.prevUserAddress = userAddress;
|
this._prevUserAddress = userAddress;
|
||||||
}
|
}
|
||||||
private async getNetworkAsync() {
|
private async _getNetworkAsync() {
|
||||||
const networkId = await promisify(this.web3.version.getNetwork)();
|
const networkId = await promisify(this._web3.version.getNetwork)();
|
||||||
return networkId;
|
return networkId;
|
||||||
}
|
}
|
||||||
private async startEmittingNetworkConnectionAndUserBalanceStateAsync() {
|
private async _startEmittingNetworkConnectionAndUserBalanceStateAsync() {
|
||||||
if (!_.isUndefined(this.watchNetworkAndBalanceIntervalId)) {
|
if (!_.isUndefined(this._watchNetworkAndBalanceIntervalId)) {
|
||||||
return; // we are already emitting the state
|
return; // we are already emitting the state
|
||||||
}
|
}
|
||||||
|
|
||||||
let prevNodeVersion: string;
|
let prevNodeVersion: string;
|
||||||
this.prevUserEtherBalanceInEth = new BigNumber(0);
|
this._prevUserEtherBalanceInEth = new BigNumber(0);
|
||||||
this.dispatcher.updateNetworkId(this.prevNetworkId);
|
this._dispatcher.updateNetworkId(this._prevNetworkId);
|
||||||
this.watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
||||||
// Check for network state changes
|
// Check for network state changes
|
||||||
const currentNetworkId = await this.getNetworkIdIfExists();
|
const currentNetworkId = await this.getNetworkIdIfExists();
|
||||||
if (currentNetworkId !== this.prevNetworkId) {
|
if (currentNetworkId !== this._prevNetworkId) {
|
||||||
this.prevNetworkId = currentNetworkId;
|
this._prevNetworkId = currentNetworkId;
|
||||||
this.dispatcher.updateNetworkId(currentNetworkId);
|
this._dispatcher.updateNetworkId(currentNetworkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for node version changes
|
// Check for node version changes
|
||||||
const currentNodeVersion = await this.getNodeVersionAsync();
|
const currentNodeVersion = await this.getNodeVersionAsync();
|
||||||
if (currentNodeVersion !== prevNodeVersion) {
|
if (currentNodeVersion !== prevNodeVersion) {
|
||||||
prevNodeVersion = currentNodeVersion;
|
prevNodeVersion = currentNodeVersion;
|
||||||
this.dispatcher.updateNodeVersion(currentNodeVersion);
|
this._dispatcher.updateNodeVersion(currentNodeVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.shouldPollUserAddress) {
|
if (this._shouldPollUserAddress) {
|
||||||
const userAddressIfExists = await this.getFirstAccountIfExistsAsync();
|
const userAddressIfExists = await this.getFirstAccountIfExistsAsync();
|
||||||
// Update makerAddress on network change
|
// Update makerAddress on network change
|
||||||
if (this.prevUserAddress !== userAddressIfExists) {
|
if (this._prevUserAddress !== userAddressIfExists) {
|
||||||
this.prevUserAddress = userAddressIfExists;
|
this._prevUserAddress = userAddressIfExists;
|
||||||
this.dispatcher.updateUserAddress(userAddressIfExists);
|
this._dispatcher.updateUserAddress(userAddressIfExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for user ether balance changes
|
// Check for user ether balance changes
|
||||||
if (userAddressIfExists !== '') {
|
if (userAddressIfExists !== '') {
|
||||||
await this.updateUserEtherBalanceAsync(userAddressIfExists);
|
await this._updateUserEtherBalanceAsync(userAddressIfExists);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This logic is primarily for the Ledger, since we don't regularly poll for the address
|
// This logic is primarily for the Ledger, since we don't regularly poll for the address
|
||||||
// we simply update the balance for the last fetched address.
|
// we simply update the balance for the last fetched address.
|
||||||
if (!_.isEmpty(this.prevUserAddress)) {
|
if (!_.isEmpty(this._prevUserAddress)) {
|
||||||
await this.updateUserEtherBalanceAsync(this.prevUserAddress);
|
await this._updateUserEtherBalanceAsync(this._prevUserAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
private async updateUserEtherBalanceAsync(userAddress: string) {
|
private async _updateUserEtherBalanceAsync(userAddress: string) {
|
||||||
const balance = await this.getBalanceInEthAsync(userAddress);
|
const balance = await this.getBalanceInEthAsync(userAddress);
|
||||||
if (!balance.eq(this.prevUserEtherBalanceInEth)) {
|
if (!balance.eq(this._prevUserEtherBalanceInEth)) {
|
||||||
this.prevUserEtherBalanceInEth = balance;
|
this._prevUserEtherBalanceInEth = balance;
|
||||||
this.dispatcher.updateUserEtherBalance(balance);
|
this._dispatcher.updateUserEtherBalance(balance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private stopEmittingNetworkConnectionAndUserBalanceStateAsync() {
|
private _stopEmittingNetworkConnectionAndUserBalanceStateAsync() {
|
||||||
clearInterval(this.watchNetworkAndBalanceIntervalId);
|
clearInterval(this._watchNetworkAndBalanceIntervalId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user