Merge pull request #444 from 0xProject/dedupWeb3Wrapper
Remove custom web3Wrapper from website
This commit is contained in:
commit
870ba445b8
@ -1,5 +1,9 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v0.2.1 _TBD_
|
||||||
|
|
||||||
|
* Add a `getProvider` method (#444)
|
||||||
|
|
||||||
## v0.2.0 _March 4, 2018_
|
## v0.2.0 _March 4, 2018_
|
||||||
|
|
||||||
* Ensure all returned user addresses are lowercase (#373)
|
* Ensure all returned user addresses are lowercase (#373)
|
||||||
|
@ -11,7 +11,7 @@ export class Web3Wrapper {
|
|||||||
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,
|
||||||
// so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x`
|
// so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x`
|
||||||
// We re-assign the send method so that Web3@1.0 providers work with 0x.js
|
// We re-assign the send method so that Web3@1.0 providers work with @0xproject/web3-wrapper
|
||||||
(provider as any).sendAsync = (provider as any).send;
|
(provider as any).sendAsync = (provider as any).send;
|
||||||
}
|
}
|
||||||
this._web3 = new Web3();
|
this._web3 = new Web3();
|
||||||
@ -22,6 +22,9 @@ export class Web3Wrapper {
|
|||||||
public getContractDefaults(): Partial<TxData> {
|
public getContractDefaults(): Partial<TxData> {
|
||||||
return this._defaults;
|
return this._defaults;
|
||||||
}
|
}
|
||||||
|
public getProvider(): Web3.Provider {
|
||||||
|
return this._web3.currentProvider;
|
||||||
|
}
|
||||||
public setProvider(provider: Web3.Provider) {
|
public setProvider(provider: Web3.Provider) {
|
||||||
this._web3.setProvider(provider);
|
this._web3.setProvider(provider);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"@0xproject/react-docs": "^0.0.1",
|
"@0xproject/react-docs": "^0.0.1",
|
||||||
"@0xproject/react-shared": "^0.0.1",
|
"@0xproject/react-shared": "^0.0.1",
|
||||||
"@0xproject/subproviders": "^0.7.0",
|
"@0xproject/subproviders": "^0.7.0",
|
||||||
|
"@0xproject/web3-wrapper": "^0.2.1",
|
||||||
"@0xproject/utils": "^0.4.1",
|
"@0xproject/utils": "^0.4.1",
|
||||||
"accounting": "^0.4.1",
|
"accounting": "^0.4.1",
|
||||||
"basscss": "^8.0.3",
|
"basscss": "^8.0.3",
|
||||||
|
@ -24,9 +24,11 @@ import {
|
|||||||
RedundantRPCSubprovider,
|
RedundantRPCSubprovider,
|
||||||
} from '@0xproject/subproviders';
|
} from '@0xproject/subproviders';
|
||||||
import { BigNumber, intervalUtils, promisify } from '@0xproject/utils';
|
import { BigNumber, intervalUtils, promisify } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import contract = require('truffle-contract');
|
import contract = require('truffle-contract');
|
||||||
|
import { BlockchainWatcher } from 'ts/blockchain_watcher';
|
||||||
import { TokenSendCompleted } from 'ts/components/flash_messages/token_send_completed';
|
import { TokenSendCompleted } from 'ts/components/flash_messages/token_send_completed';
|
||||||
import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted';
|
import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted';
|
||||||
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
|
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
|
||||||
@ -47,7 +49,6 @@ import { configs } from 'ts/utils/configs';
|
|||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
import { errorReporter } from 'ts/utils/error_reporter';
|
import { errorReporter } from 'ts/utils/error_reporter';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
import { Web3Wrapper } from 'ts/web3_wrapper';
|
|
||||||
import Web3 = require('web3');
|
import Web3 = require('web3');
|
||||||
import ProviderEngine = require('web3-provider-engine');
|
import ProviderEngine = require('web3-provider-engine');
|
||||||
import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
|
import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
|
||||||
@ -63,8 +64,8 @@ export class Blockchain {
|
|||||||
private _zeroEx: ZeroEx;
|
private _zeroEx: ZeroEx;
|
||||||
private _dispatcher: Dispatcher;
|
private _dispatcher: Dispatcher;
|
||||||
private _web3Wrapper?: Web3Wrapper;
|
private _web3Wrapper?: Web3Wrapper;
|
||||||
private _exchangeAddress: string;
|
private _blockchainWatcher?: BlockchainWatcher;
|
||||||
private _userAddress: string;
|
private _userAddressIfExists: string;
|
||||||
private _cachedProvider: Web3.Provider;
|
private _cachedProvider: Web3.Provider;
|
||||||
private _cachedProviderNetworkId: number;
|
private _cachedProviderNetworkId: number;
|
||||||
private _ledgerSubprovider: LedgerWalletSubprovider;
|
private _ledgerSubprovider: LedgerWalletSubprovider;
|
||||||
@ -115,7 +116,6 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
constructor(dispatcher: Dispatcher, isSalePage: boolean = false) {
|
constructor(dispatcher: Dispatcher, isSalePage: boolean = false) {
|
||||||
this._dispatcher = dispatcher;
|
this._dispatcher = dispatcher;
|
||||||
this._userAddress = '';
|
|
||||||
const defaultGasPrice = GWEI_IN_WEI * 30;
|
const defaultGasPrice = GWEI_IN_WEI * 30;
|
||||||
this._defaultGasPrice = new BigNumber(defaultGasPrice);
|
this._defaultGasPrice = new BigNumber(defaultGasPrice);
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
@ -137,8 +137,8 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string) {
|
public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string) {
|
||||||
if (this._userAddress !== newUserAddress) {
|
if (this._userAddressIfExists !== newUserAddress) {
|
||||||
this._userAddress = newUserAddress;
|
this._userAddressIfExists = newUserAddress;
|
||||||
await this.fetchTokenInformationAsync();
|
await this.fetchTokenInformationAsync();
|
||||||
await this._rehydrateStoreWithContractEvents();
|
await this._rehydrateStoreWithContractEvents();
|
||||||
}
|
}
|
||||||
@ -189,14 +189,14 @@ 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
|
||||||
if (_.isUndefined(this._cachedProvider)) {
|
if (_.isUndefined(this._cachedProvider)) {
|
||||||
this._cachedProvider = this._web3Wrapper.getProviderObj();
|
this._cachedProvider = this._web3Wrapper.getProvider();
|
||||||
this._cachedProviderNetworkId = this.networkId;
|
this._cachedProviderNetworkId = this.networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._web3Wrapper.destroy();
|
this._blockchainWatcher.destroy();
|
||||||
|
|
||||||
this._userAddress = '';
|
delete this._userAddressIfExists;
|
||||||
this._dispatcher.updateUserAddress(''); // Clear old userAddress
|
this._dispatcher.updateUserAddress(undefined); // Clear old userAddress
|
||||||
|
|
||||||
const provider = new ProviderEngine();
|
const provider = new ProviderEngine();
|
||||||
const ledgerWalletConfigs = {
|
const ledgerWalletConfigs = {
|
||||||
@ -211,10 +211,15 @@ export class Blockchain {
|
|||||||
this.networkId = networkId;
|
this.networkId = networkId;
|
||||||
this._dispatcher.updateNetworkId(this.networkId);
|
this._dispatcher.updateNetworkId(this.networkId);
|
||||||
const shouldPollUserAddress = false;
|
const shouldPollUserAddress = false;
|
||||||
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress);
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
|
this._blockchainWatcher = new BlockchainWatcher(
|
||||||
|
this._dispatcher,
|
||||||
|
this._web3Wrapper,
|
||||||
|
this.networkId,
|
||||||
|
shouldPollUserAddress,
|
||||||
|
);
|
||||||
this._zeroEx.setProvider(provider, this.networkId);
|
this._zeroEx.setProvider(provider, this.networkId);
|
||||||
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
this._blockchainWatcher.startEmittingNetworkConnectionAndUserBalanceState();
|
||||||
this._web3Wrapper.startEmittingNetworkConnectionAndUserBalanceState();
|
|
||||||
this._dispatcher.updateProviderType(ProviderType.Ledger);
|
this._dispatcher.updateProviderType(ProviderType.Ledger);
|
||||||
}
|
}
|
||||||
public async updateProviderToInjectedAsync() {
|
public async updateProviderToInjectedAsync() {
|
||||||
@ -224,21 +229,27 @@ export class Blockchain {
|
|||||||
return; // Going from injected to injected, so we noop
|
return; // Going from injected to injected, so we noop
|
||||||
}
|
}
|
||||||
|
|
||||||
this._web3Wrapper.destroy();
|
this._blockchainWatcher.destroy();
|
||||||
|
|
||||||
const provider = this._cachedProvider;
|
const provider = this._cachedProvider;
|
||||||
this.networkId = this._cachedProviderNetworkId;
|
this.networkId = this._cachedProviderNetworkId;
|
||||||
|
|
||||||
const shouldPollUserAddress = true;
|
const shouldPollUserAddress = true;
|
||||||
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress);
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
|
this._blockchainWatcher = new BlockchainWatcher(
|
||||||
|
this._dispatcher,
|
||||||
|
this._web3Wrapper,
|
||||||
|
this.networkId,
|
||||||
|
shouldPollUserAddress,
|
||||||
|
);
|
||||||
|
|
||||||
this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync();
|
const userAddresses = await this._web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
this._userAddressIfExists = userAddresses[0];
|
||||||
|
|
||||||
this._zeroEx.setProvider(provider, this.networkId);
|
this._zeroEx.setProvider(provider, this.networkId);
|
||||||
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
|
||||||
|
|
||||||
await this.fetchTokenInformationAsync();
|
await this.fetchTokenInformationAsync();
|
||||||
this._web3Wrapper.startEmittingNetworkConnectionAndUserBalanceState();
|
this._blockchainWatcher.startEmittingNetworkConnectionAndUserBalanceState();
|
||||||
this._dispatcher.updateProviderType(ProviderType.Injected);
|
this._dispatcher.updateProviderType(ProviderType.Injected);
|
||||||
delete this._ledgerSubprovider;
|
delete this._ledgerSubprovider;
|
||||||
delete this._cachedProvider;
|
delete this._cachedProvider;
|
||||||
@ -251,7 +262,7 @@ export class Blockchain {
|
|||||||
this._showFlashMessageIfLedger();
|
this._showFlashMessageIfLedger();
|
||||||
const txHash = await this._zeroEx.token.setProxyAllowanceAsync(
|
const txHash = await this._zeroEx.token.setProxyAllowanceAsync(
|
||||||
token.address,
|
token.address,
|
||||||
this._userAddress,
|
this._userAddressIfExists,
|
||||||
amountInBaseUnits,
|
amountInBaseUnits,
|
||||||
{
|
{
|
||||||
gasPrice: this._defaultGasPrice,
|
gasPrice: this._defaultGasPrice,
|
||||||
@ -260,10 +271,13 @@ export class Blockchain {
|
|||||||
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
}
|
}
|
||||||
public async transferAsync(token: Token, toAddress: string, amountInBaseUnits: BigNumber): Promise<void> {
|
public async transferAsync(token: Token, toAddress: string, amountInBaseUnits: BigNumber): Promise<void> {
|
||||||
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
this._showFlashMessageIfLedger();
|
this._showFlashMessageIfLedger();
|
||||||
const txHash = await this._zeroEx.token.transferAsync(
|
const txHash = await this._zeroEx.token.transferAsync(
|
||||||
token.address,
|
token.address,
|
||||||
this._userAddress,
|
this._userAddressIfExists,
|
||||||
toAddress,
|
toAddress,
|
||||||
amountInBaseUnits,
|
amountInBaseUnits,
|
||||||
{
|
{
|
||||||
@ -305,6 +319,7 @@ export class Blockchain {
|
|||||||
return zeroExSignedOrder;
|
return zeroExSignedOrder;
|
||||||
}
|
}
|
||||||
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> {
|
||||||
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
@ -314,7 +329,7 @@ export class Blockchain {
|
|||||||
signedOrder,
|
signedOrder,
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
this._userAddress,
|
this._userAddressIfExists,
|
||||||
{
|
{
|
||||||
gasPrice: this._defaultGasPrice,
|
gasPrice: this._defaultGasPrice,
|
||||||
},
|
},
|
||||||
@ -347,7 +362,7 @@ export class Blockchain {
|
|||||||
return unavailableTakerAmount;
|
return unavailableTakerAmount;
|
||||||
}
|
}
|
||||||
public getExchangeContractAddressIfExists() {
|
public getExchangeContractAddressIfExists() {
|
||||||
return this._exchangeAddress;
|
return this._zeroEx.exchange.getContractAddress();
|
||||||
}
|
}
|
||||||
public async validateFillOrderThrowIfInvalidAsync(
|
public async validateFillOrderThrowIfInvalidAsync(
|
||||||
signedOrder: SignedOrder,
|
signedOrder: SignedOrder,
|
||||||
@ -373,12 +388,15 @@ export class Blockchain {
|
|||||||
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._userAddressIfExists, token.address);
|
||||||
|
|
||||||
const newTokenBalancePromise = new Promise((resolve: (balance: BigNumber) => void, reject) => {
|
const newTokenBalancePromise = new Promise((resolve: (balance: BigNumber) => void, reject) => {
|
||||||
const tokenPollInterval = intervalUtils.setAsyncExcludingInterval(
|
const tokenPollInterval = intervalUtils.setAsyncExcludingInterval(
|
||||||
async () => {
|
async () => {
|
||||||
const [balance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address);
|
const [balance] = await this.getTokenBalanceAndAllowanceAsync(
|
||||||
|
this._userAddressIfExists,
|
||||||
|
token.address,
|
||||||
|
);
|
||||||
if (!balance.eq(currBalance)) {
|
if (!balance.eq(currBalance)) {
|
||||||
intervalUtils.clearAsyncExcludingInterval(tokenPollInterval);
|
intervalUtils.clearAsyncExcludingInterval(tokenPollInterval);
|
||||||
resolve(balance);
|
resolve(balance);
|
||||||
@ -397,7 +415,7 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
public async signOrderHashAsync(orderHash: string): Promise<ECSignature> {
|
public async signOrderHashAsync(orderHash: string): Promise<ECSignature> {
|
||||||
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._userAddressIfExists;
|
||||||
// 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)) {
|
||||||
@ -427,22 +445,27 @@ export class Blockchain {
|
|||||||
const mintableContract = await this._instantiateContractIfExistsAsync(MintableArtifacts, token.address);
|
const mintableContract = await this._instantiateContractIfExistsAsync(MintableArtifacts, token.address);
|
||||||
this._showFlashMessageIfLedger();
|
this._showFlashMessageIfLedger();
|
||||||
await mintableContract.mint(constants.MINT_AMOUNT, {
|
await mintableContract.mint(constants.MINT_AMOUNT, {
|
||||||
from: this._userAddress,
|
from: this._userAddressIfExists,
|
||||||
gasPrice: this._defaultGasPrice,
|
gasPrice: this._defaultGasPrice,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
|
||||||
const balance = await this._web3Wrapper.getBalanceInEthAsync(owner);
|
const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(owner);
|
||||||
return balance;
|
return balanceInWei;
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|
||||||
this._showFlashMessageIfLedger();
|
this._showFlashMessageIfLedger();
|
||||||
const txHash = await this._zeroEx.etherToken.depositAsync(etherTokenAddress, amount, this._userAddress, {
|
const txHash = await this._zeroEx.etherToken.depositAsync(
|
||||||
gasPrice: this._defaultGasPrice,
|
etherTokenAddress,
|
||||||
});
|
amount,
|
||||||
|
this._userAddressIfExists,
|
||||||
|
{
|
||||||
|
gasPrice: this._defaultGasPrice,
|
||||||
|
},
|
||||||
|
);
|
||||||
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> {
|
||||||
@ -450,9 +473,14 @@ export class Blockchain {
|
|||||||
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
this._showFlashMessageIfLedger();
|
this._showFlashMessageIfLedger();
|
||||||
const txHash = await this._zeroEx.etherToken.withdrawAsync(etherTokenAddress, amount, this._userAddress, {
|
const txHash = await this._zeroEx.etherToken.withdrawAsync(
|
||||||
gasPrice: this._defaultGasPrice,
|
etherTokenAddress,
|
||||||
});
|
amount,
|
||||||
|
this._userAddressIfExists,
|
||||||
|
{
|
||||||
|
gasPrice: this._defaultGasPrice,
|
||||||
|
},
|
||||||
|
);
|
||||||
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash);
|
||||||
}
|
}
|
||||||
public async doesContractExistAtAddressAsync(address: string) {
|
public async doesContractExistAtAddressAsync(address: string) {
|
||||||
@ -460,21 +488,29 @@ export class Blockchain {
|
|||||||
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);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
|
const tokenBalanceAndAllowance = await this.getTokenBalanceAndAllowanceAsync(
|
||||||
|
this._userAddressIfExists,
|
||||||
|
tokenAddress,
|
||||||
|
);
|
||||||
return tokenBalanceAndAllowance;
|
return tokenBalanceAndAllowance;
|
||||||
}
|
}
|
||||||
public async getTokenBalanceAndAllowanceAsync(ownerAddress: string, tokenAddress: string): Promise<BigNumber[]> {
|
public async getTokenBalanceAndAllowanceAsync(
|
||||||
|
ownerAddressIfExists: string,
|
||||||
|
tokenAddress: string,
|
||||||
|
): Promise<BigNumber[]> {
|
||||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
||||||
|
|
||||||
if (_.isEmpty(ownerAddress)) {
|
if (_.isUndefined(ownerAddressIfExists)) {
|
||||||
const zero = new BigNumber(0);
|
const zero = new BigNumber(0);
|
||||||
return [zero, zero];
|
return [zero, zero];
|
||||||
}
|
}
|
||||||
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, ownerAddressIfExists);
|
||||||
allowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress);
|
allowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddressIfExists);
|
||||||
}
|
}
|
||||||
return [balance, allowance];
|
return [balance, allowance];
|
||||||
}
|
}
|
||||||
@ -487,10 +523,10 @@ export class Blockchain {
|
|||||||
// 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._blockchainWatcher.updatePrevUserAddress(newUserAddress);
|
||||||
}
|
}
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this._web3Wrapper.destroy();
|
this._blockchainWatcher.destroy();
|
||||||
this._stopWatchingExchangeLogFillEvents();
|
this._stopWatchingExchangeLogFillEvents();
|
||||||
}
|
}
|
||||||
public async fetchTokenInformationAsync() {
|
public async fetchTokenInformationAsync() {
|
||||||
@ -503,7 +539,9 @@ export class Blockchain {
|
|||||||
|
|
||||||
const tokenRegistryTokensByAddress = await this._getTokenRegistryTokensByAddressAsync();
|
const tokenRegistryTokensByAddress = await this._getTokenRegistryTokensByAddressAsync();
|
||||||
|
|
||||||
const trackedTokensByAddress = trackedTokenStorage.getTrackedTokensByAddress(this._userAddress, this.networkId);
|
const trackedTokensByAddress = _.isUndefined(this._userAddressIfExists)
|
||||||
|
? {}
|
||||||
|
: trackedTokenStorage.getTrackedTokensByAddress(this._userAddressIfExists, this.networkId);
|
||||||
const tokenRegistryTokens = _.values(tokenRegistryTokensByAddress);
|
const tokenRegistryTokens = _.values(tokenRegistryTokensByAddress);
|
||||||
if (_.isEmpty(trackedTokensByAddress)) {
|
if (_.isEmpty(trackedTokensByAddress)) {
|
||||||
_.each(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => {
|
_.each(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => {
|
||||||
@ -511,9 +549,11 @@ export class Blockchain {
|
|||||||
token.isTracked = true;
|
token.isTracked = true;
|
||||||
trackedTokensByAddress[token.address] = token;
|
trackedTokensByAddress[token.address] = token;
|
||||||
});
|
});
|
||||||
_.each(trackedTokensByAddress, (token: Token, address: string) => {
|
if (!_.isUndefined(this._userAddressIfExists)) {
|
||||||
trackedTokenStorage.addTrackedTokenToUser(this._userAddress, this.networkId, token);
|
_.each(trackedTokensByAddress, (token: Token, address: string) => {
|
||||||
});
|
trackedTokenStorage.addTrackedTokenToUser(this._userAddressIfExists, 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
|
||||||
_.each(trackedTokensByAddress, (trackedToken: Token, address: string) => {
|
_.each(trackedTokensByAddress, (trackedToken: Token, address: string) => {
|
||||||
@ -539,7 +579,7 @@ export class Blockchain {
|
|||||||
address: mostPopularTradingPairTokens[1].address,
|
address: mostPopularTradingPairTokens[1].address,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this._dispatcher.batchDispatch(allTokensByAddress, this.networkId, this._userAddress, sideToAssetToken);
|
this._dispatcher.batchDispatch(allTokensByAddress, this.networkId, this._userAddressIfExists, sideToAssetToken);
|
||||||
|
|
||||||
this._dispatcher.updateBlockchainIsLoaded(true);
|
this._dispatcher.updateBlockchainIsLoaded(true);
|
||||||
}
|
}
|
||||||
@ -560,7 +600,7 @@ export class Blockchain {
|
|||||||
return receipt;
|
return receipt;
|
||||||
}
|
}
|
||||||
private _doesUserAddressExist(): boolean {
|
private _doesUserAddressExist(): boolean {
|
||||||
return this._userAddress !== '';
|
return !_.isUndefined(this._userAddressIfExists);
|
||||||
}
|
}
|
||||||
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
|
||||||
@ -605,16 +645,18 @@ export class Blockchain {
|
|||||||
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._userAddressIfExists, this.networkId, fill);
|
||||||
} else {
|
} else {
|
||||||
tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill);
|
tradeHistoryStorage.addFillToUser(this._userAddressIfExists, this.networkId, fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private async _fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) {
|
private async _fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) {
|
||||||
const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this._userAddress, this.networkId);
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
|
const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this._userAddressIfExists, this.networkId);
|
||||||
const blockRange: BlockRange = {
|
const blockRange: BlockRange = {
|
||||||
fromBlock,
|
fromBlock,
|
||||||
toBlock: 'latest' as BlockParam,
|
toBlock: 'latest' as BlockParam,
|
||||||
@ -630,7 +672,7 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
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._userAddressIfExists, this.networkId, fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async _convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
private async _convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||||
@ -654,10 +696,12 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
private _doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
private _doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) {
|
||||||
const args = decodedLog.args;
|
const args = decodedLog.args;
|
||||||
const isUserMakerOrTaker = args.maker === this._userAddress || args.taker === this._userAddress;
|
const isUserMakerOrTaker = args.maker === this._userAddressIfExists || args.taker === this._userAddressIfExists;
|
||||||
return isUserMakerOrTaker;
|
return isUserMakerOrTaker;
|
||||||
}
|
}
|
||||||
private _updateLatestFillsBlockIfNeeded(blockNumber: number) {
|
private _updateLatestFillsBlockIfNeeded(blockNumber: number) {
|
||||||
|
utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses);
|
||||||
|
|
||||||
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
|
||||||
@ -668,7 +712,7 @@ export class Blockchain {
|
|||||||
// TODO: Debug if this is a race condition, and apply a more precise fix
|
// TODO: Debug if this is a race condition, and apply a more precise fix
|
||||||
const blockNumberToSet =
|
const blockNumberToSet =
|
||||||
blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ? 0 : blockNumber - BLOCK_NUMBER_BACK_TRACK;
|
blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ? 0 : blockNumber - BLOCK_NUMBER_BACK_TRACK;
|
||||||
tradeHistoryStorage.setFillsLatestBlock(this._userAddress, this.networkId, blockNumberToSet);
|
tradeHistoryStorage.setFillsLatestBlock(this._userAddressIfExists, this.networkId, blockNumberToSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _stopWatchingExchangeLogFillEvents(): void {
|
private _stopWatchingExchangeLogFillEvents(): void {
|
||||||
@ -739,20 +783,21 @@ export class Blockchain {
|
|||||||
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, this.networkId, shouldPollUserAddress);
|
this._web3Wrapper = new Web3Wrapper(provider);
|
||||||
await this._postInstantiationOrUpdatingProviderZeroExAsync();
|
this._blockchainWatcher = new BlockchainWatcher(
|
||||||
this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync();
|
this._dispatcher,
|
||||||
this._dispatcher.updateUserAddress(this._userAddress);
|
this._web3Wrapper,
|
||||||
|
this.networkId,
|
||||||
|
shouldPollUserAddress,
|
||||||
|
);
|
||||||
|
|
||||||
|
const userAddresses = await this._web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
this._userAddressIfExists = userAddresses[0];
|
||||||
|
this._dispatcher.updateUserAddress(this._userAddressIfExists);
|
||||||
await this.fetchTokenInformationAsync();
|
await this.fetchTokenInformationAsync();
|
||||||
this._web3Wrapper.startEmittingNetworkConnectionAndUserBalanceState();
|
this._blockchainWatcher.startEmittingNetworkConnectionAndUserBalanceState();
|
||||||
await this._rehydrateStoreWithContractEvents();
|
await this._rehydrateStoreWithContractEvents();
|
||||||
}
|
}
|
||||||
// This method should always be run after instantiating or updating the provider
|
|
||||||
// of the ZeroEx instance.
|
|
||||||
private async _postInstantiationOrUpdatingProviderZeroExAsync() {
|
|
||||||
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
|
|
||||||
this._exchangeAddress = this._zeroEx.exchange.getContractAddress();
|
|
||||||
}
|
|
||||||
private _updateProviderName(injectedWeb3: Web3) {
|
private _updateProviderName(injectedWeb3: Web3) {
|
||||||
const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
|
||||||
const providerName = doesInjectedWeb3Exist
|
const providerName = doesInjectedWeb3Exist
|
||||||
@ -762,7 +807,7 @@ export class Blockchain {
|
|||||||
}
|
}
|
||||||
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.getProvider();
|
||||||
c.setProvider(providerObj);
|
c.setProvider(providerObj);
|
||||||
|
|
||||||
const artifactNetworkConfigs = artifact.networks[this.networkId];
|
const artifactNetworkConfigs = artifact.networks[this.networkId];
|
||||||
|
107
packages/website/ts/blockchain_watcher.ts
Normal file
107
packages/website/ts/blockchain_watcher.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { BigNumber, intervalUtils, promisify } from '@0xproject/utils';
|
||||||
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import { Dispatcher } from 'ts/redux/dispatcher';
|
||||||
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
|
export class BlockchainWatcher {
|
||||||
|
private _dispatcher: Dispatcher;
|
||||||
|
private _web3Wrapper: Web3Wrapper;
|
||||||
|
private _prevNetworkId: number;
|
||||||
|
private _shouldPollUserAddress: boolean;
|
||||||
|
private _watchNetworkAndBalanceIntervalId: NodeJS.Timer;
|
||||||
|
private _prevUserEtherBalanceInWei: BigNumber;
|
||||||
|
private _prevUserAddressIfExists: string;
|
||||||
|
constructor(
|
||||||
|
dispatcher: Dispatcher,
|
||||||
|
web3Wrapper: Web3Wrapper,
|
||||||
|
networkIdIfExists: number,
|
||||||
|
shouldPollUserAddress: boolean,
|
||||||
|
) {
|
||||||
|
this._dispatcher = dispatcher;
|
||||||
|
this._prevNetworkId = networkIdIfExists;
|
||||||
|
this._shouldPollUserAddress = shouldPollUserAddress;
|
||||||
|
this._web3Wrapper = web3Wrapper;
|
||||||
|
}
|
||||||
|
public destroy() {
|
||||||
|
this._stopEmittingNetworkConnectionAndUserBalanceStateAsync();
|
||||||
|
// HACK: stop() is only available on providerEngine instances
|
||||||
|
const provider = this._web3Wrapper.getProvider();
|
||||||
|
if (!_.isUndefined((provider as any).stop)) {
|
||||||
|
(provider as any).stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This should only be called from the LedgerConfigDialog
|
||||||
|
public updatePrevUserAddress(userAddress: string) {
|
||||||
|
this._prevUserAddressIfExists = userAddress;
|
||||||
|
}
|
||||||
|
public startEmittingNetworkConnectionAndUserBalanceState() {
|
||||||
|
if (!_.isUndefined(this._watchNetworkAndBalanceIntervalId)) {
|
||||||
|
return; // we are already emitting the state
|
||||||
|
}
|
||||||
|
|
||||||
|
let prevNodeVersion: string;
|
||||||
|
this._prevUserEtherBalanceInWei = new BigNumber(0);
|
||||||
|
this._dispatcher.updateNetworkId(this._prevNetworkId);
|
||||||
|
this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval(
|
||||||
|
async () => {
|
||||||
|
// Check for network state changes
|
||||||
|
let currentNetworkId;
|
||||||
|
try {
|
||||||
|
currentNetworkId = await this._web3Wrapper.getNetworkIdAsync();
|
||||||
|
} catch (err) {
|
||||||
|
// Noop
|
||||||
|
}
|
||||||
|
if (currentNetworkId !== this._prevNetworkId) {
|
||||||
|
this._prevNetworkId = currentNetworkId;
|
||||||
|
this._dispatcher.updateNetworkId(currentNetworkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for node version changes
|
||||||
|
const currentNodeVersion = await this._web3Wrapper.getNodeVersionAsync();
|
||||||
|
if (currentNodeVersion !== prevNodeVersion) {
|
||||||
|
prevNodeVersion = currentNodeVersion;
|
||||||
|
this._dispatcher.updateNodeVersion(currentNodeVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._shouldPollUserAddress) {
|
||||||
|
const addresses = await this._web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
const userAddressIfExists = addresses[0];
|
||||||
|
// Update makerAddress on network change
|
||||||
|
if (this._prevUserAddressIfExists !== userAddressIfExists) {
|
||||||
|
this._prevUserAddressIfExists = userAddressIfExists;
|
||||||
|
this._dispatcher.updateUserAddress(userAddressIfExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for user ether balance changes
|
||||||
|
if (!_.isUndefined(userAddressIfExists)) {
|
||||||
|
await this._updateUserWeiBalanceAsync(userAddressIfExists);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 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.
|
||||||
|
if (!_.isUndefined(this._prevUserAddressIfExists)) {
|
||||||
|
await this._updateUserWeiBalanceAsync(this._prevUserAddressIfExists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
5000,
|
||||||
|
(err: Error) => {
|
||||||
|
utils.consoleLog(`Watching network and balances failed: ${err.stack}`);
|
||||||
|
this._stopEmittingNetworkConnectionAndUserBalanceStateAsync();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private async _updateUserWeiBalanceAsync(userAddress: string) {
|
||||||
|
const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(userAddress);
|
||||||
|
if (!balanceInWei.eq(this._prevUserEtherBalanceInWei)) {
|
||||||
|
this._prevUserEtherBalanceInWei = balanceInWei;
|
||||||
|
this._dispatcher.updateUserWeiBalance(balanceInWei);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private _stopEmittingNetworkConnectionAndUserBalanceStateAsync() {
|
||||||
|
if (!_.isUndefined(this._watchNetworkAndBalanceIntervalId)) {
|
||||||
|
intervalUtils.clearAsyncExcludingInterval(this._watchNetworkAndBalanceIntervalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
|
import { ZeroEx } from '0x.js';
|
||||||
import { colors } from '@0xproject/react-shared';
|
import { colors } from '@0xproject/react-shared';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
import Dialog from 'material-ui/Dialog';
|
import Dialog from 'material-ui/Dialog';
|
||||||
import FlatButton from 'material-ui/FlatButton';
|
import FlatButton from 'material-ui/FlatButton';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
@ -7,6 +9,7 @@ import { Blockchain } from 'ts/blockchain';
|
|||||||
import { EthAmountInput } from 'ts/components/inputs/eth_amount_input';
|
import { EthAmountInput } from 'ts/components/inputs/eth_amount_input';
|
||||||
import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
|
import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
|
||||||
import { Side, Token } from 'ts/types';
|
import { Side, Token } from 'ts/types';
|
||||||
|
import { constants } from 'ts/utils/constants';
|
||||||
|
|
||||||
interface EthWethConversionDialogProps {
|
interface EthWethConversionDialogProps {
|
||||||
blockchain: Blockchain;
|
blockchain: Blockchain;
|
||||||
@ -17,7 +20,7 @@ interface EthWethConversionDialogProps {
|
|||||||
onCancelled: () => void;
|
onCancelled: () => void;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
token: Token;
|
token: Token;
|
||||||
etherBalance: BigNumber;
|
etherBalanceInWei: BigNumber;
|
||||||
lastForceTokenStateRefetch: number;
|
lastForceTokenStateRefetch: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +78,7 @@ export class EthWethConversionDialog extends React.Component<
|
|||||||
? '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.";
|
||||||
const isWrappedVersion = this.props.direction === Side.Receive;
|
const isWrappedVersion = this.props.direction === Side.Receive;
|
||||||
|
const etherBalanceInEth = ZeroEx.toUnitAmount(this.props.etherBalanceInWei, constants.DECIMAL_PLACES_ETH);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="pb2">{explanation}</div>
|
<div className="pb2">{explanation}</div>
|
||||||
@ -103,7 +107,7 @@ export class EthWethConversionDialog extends React.Component<
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EthAmountInput
|
<EthAmountInput
|
||||||
balance={this.props.etherBalance}
|
balance={etherBalanceInEth}
|
||||||
amount={this.state.value}
|
amount={this.state.value}
|
||||||
onChange={this._onValueChange.bind(this)}
|
onChange={this._onValueChange.bind(this)}
|
||||||
shouldCheckBalance={true}
|
shouldCheckBalance={true}
|
||||||
@ -182,8 +186,9 @@ export class EthWethConversionDialog extends React.Component<
|
|||||||
this.props.onCancelled();
|
this.props.onCancelled();
|
||||||
}
|
}
|
||||||
private async _fetchEthTokenBalanceAsync() {
|
private async _fetchEthTokenBalanceAsync() {
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
const [balance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
this.props.token.address,
|
this.props.token.address,
|
||||||
);
|
);
|
||||||
if (!this._isUnmounted) {
|
if (!this._isUnmounted) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ZeroEx } from '0x.js';
|
||||||
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
|
import { colors, constants as sharedConstants } from '@0xproject/react-shared';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -160,14 +161,15 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
}
|
}
|
||||||
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 balanceInWei = this.state.addressBalances[i];
|
||||||
const addressTooltipId = `address-${userAddress}`;
|
const addressTooltipId = `address-${userAddress}`;
|
||||||
const balanceTooltipId = `balance-${userAddress}`;
|
const balanceTooltipId = `balance-${userAddress}`;
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
||||||
// We specifically prefix kovan ETH.
|
// We specifically prefix kovan ETH.
|
||||||
// TODO: We should probably add prefixes for all networks
|
// TODO: We should probably add prefixes for all networks
|
||||||
const isKovanNetwork = networkName === 'Kovan';
|
const isKovanNetwork = networkName === 'Kovan';
|
||||||
const balanceString = `${balance.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`;
|
const balanceInEth = ZeroEx.toUnitAmount(balanceInWei, constants.DECIMAL_PLACES_ETH);
|
||||||
|
const balanceString = `${balanceInEth.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`;
|
||||||
return (
|
return (
|
||||||
<TableRow key={userAddress} style={{ height: 40 }}>
|
<TableRow key={userAddress} style={{ height: 40 }}>
|
||||||
<TableRowColumn colSpan={2}>
|
<TableRowColumn colSpan={2}>
|
||||||
@ -204,7 +206,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
this.props.blockchain.updateWeb3WrapperPrevUserAddress(selectedAddress);
|
this.props.blockchain.updateWeb3WrapperPrevUserAddress(selectedAddress);
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this.props.blockchain.fetchTokenInformationAsync();
|
this.props.blockchain.fetchTokenInformationAsync();
|
||||||
this.props.dispatcher.updateUserEtherBalance(selectAddressBalance);
|
this.props.dispatcher.updateUserWeiBalance(selectAddressBalance);
|
||||||
this.setState({
|
this.setState({
|
||||||
stepIndex: LedgerSteps.CONNECT,
|
stepIndex: LedgerSteps.CONNECT,
|
||||||
});
|
});
|
||||||
@ -233,8 +235,8 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
|
|||||||
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 balanceInWei = await this.props.blockchain.getBalanceInWeiAsync(address);
|
||||||
addressBalances.push(balance);
|
addressBalances.push(balanceInWei);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
utils.consoleLog(`Ledger error: ${JSON.stringify(err)}`);
|
utils.consoleLog(`Ledger error: ${JSON.stringify(err)}`);
|
||||||
|
@ -18,7 +18,7 @@ interface EthWethConversionButtonProps {
|
|||||||
ethToken: Token;
|
ethToken: Token;
|
||||||
dispatcher: Dispatcher;
|
dispatcher: Dispatcher;
|
||||||
blockchain: Blockchain;
|
blockchain: Blockchain;
|
||||||
userEtherBalance: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
isOutdatedWrappedEther: boolean;
|
isOutdatedWrappedEther: boolean;
|
||||||
onConversionSuccessful?: () => void;
|
onConversionSuccessful?: () => void;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
@ -74,7 +74,7 @@ export class EthWethConversionButton extends React.Component<
|
|||||||
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}
|
etherBalanceInWei={this.props.userEtherBalanceInWei}
|
||||||
token={this.props.ethToken}
|
token={this.props.ethToken}
|
||||||
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
|
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
|
||||||
/>
|
/>
|
||||||
|
@ -15,7 +15,6 @@ import { configs } from 'ts/utils/configs';
|
|||||||
import { constants } from 'ts/utils/constants';
|
import { constants } from 'ts/utils/constants';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
const PRECISION = 5;
|
|
||||||
const DATE_FORMAT = 'D/M/YY';
|
const DATE_FORMAT = 'D/M/YY';
|
||||||
const ICON_DIMENSION = 40;
|
const ICON_DIMENSION = 40;
|
||||||
const ETHER_ICON_PATH = '/images/ether.png';
|
const ETHER_ICON_PATH = '/images/ether.png';
|
||||||
@ -34,7 +33,7 @@ interface EthWrappersProps {
|
|||||||
dispatcher: Dispatcher;
|
dispatcher: Dispatcher;
|
||||||
tokenByAddress: TokenByAddress;
|
tokenByAddress: TokenByAddress;
|
||||||
userAddress: string;
|
userAddress: string;
|
||||||
userEtherBalance: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
lastForceTokenStateRefetch: number;
|
lastForceTokenStateRefetch: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +97,10 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
EtherscanLinkSuffixes.Address,
|
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);
|
||||||
|
const userEtherBalanceInEth = ZeroEx.toUnitAmount(
|
||||||
|
this.props.userEtherBalanceInWei,
|
||||||
|
constants.DECIMAL_PLACES_ETH,
|
||||||
|
);
|
||||||
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">
|
||||||
@ -144,7 +147,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</div>
|
</div>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn>
|
<TableRowColumn>
|
||||||
{this.props.userEtherBalance.toFixed(PRECISION)} ETH
|
{userEtherBalanceInEth.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} ETH
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn>
|
<TableRowColumn>
|
||||||
<EthWethConversionButton
|
<EthWethConversionButton
|
||||||
@ -157,7 +160,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
ethToken={etherToken}
|
ethToken={etherToken}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
blockchain={this.props.blockchain}
|
blockchain={this.props.blockchain}
|
||||||
userEtherBalance={this.props.userEtherBalance}
|
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@ -167,7 +170,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn>
|
<TableRowColumn>
|
||||||
{this.state.isWethStateLoaded ? (
|
{this.state.isWethStateLoaded ? (
|
||||||
`${wethBalance.toFixed(PRECISION)} WETH`
|
`${wethBalance.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} WETH`
|
||||||
) : (
|
) : (
|
||||||
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
||||||
)}
|
)}
|
||||||
@ -184,7 +187,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
ethToken={etherToken}
|
ethToken={etherToken}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
blockchain={this.props.blockchain}
|
blockchain={this.props.blockchain}
|
||||||
userEtherBalance={this.props.userEtherBalance}
|
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@ -267,7 +270,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETHIfExists.address];
|
const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETHIfExists.address];
|
||||||
const balanceInEthIfExists = isStateLoaded
|
const balanceInEthIfExists = isStateLoaded
|
||||||
? ZeroEx.toUnitAmount(outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH).toFixed(
|
? ZeroEx.toUnitAmount(outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH).toFixed(
|
||||||
PRECISION,
|
configs.AMOUNT_DISPLAY_PRECSION,
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind(
|
const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind(
|
||||||
@ -304,7 +307,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
ethToken={outdatedEtherToken}
|
ethToken={outdatedEtherToken}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
blockchain={this.props.blockchain}
|
blockchain={this.props.blockchain}
|
||||||
userEtherBalance={this.props.userEtherBalance}
|
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
|
||||||
onConversionSuccessful={onConversionSuccessful}
|
onConversionSuccessful={onConversionSuccessful}
|
||||||
/>
|
/>
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
@ -348,8 +351,9 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
[outdatedWETHAddress]: false,
|
[outdatedWETHAddress]: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
outdatedWETHAddress,
|
outdatedWETHAddress,
|
||||||
);
|
);
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -369,8 +373,9 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
private async _fetchWETHStateAsync() {
|
private async _fetchWETHStateAsync() {
|
||||||
const tokens = _.values(this.props.tokenByAddress);
|
const tokens = _.values(this.props.tokenByAddress);
|
||||||
const wethToken = _.find(tokens, token => token.symbol === 'WETH');
|
const wethToken = _.find(tokens, token => token.symbol === 'WETH');
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
const [wethBalance, wethAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [wethBalance, wethAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
wethToken.address,
|
wethToken.address,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -379,7 +384,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
|
||||||
for (const address of outdatedWETHAddresses) {
|
for (const address of outdatedWETHAddresses) {
|
||||||
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
address,
|
address,
|
||||||
);
|
);
|
||||||
outdatedWETHStateByAddress[address] = {
|
outdatedWETHStateByAddress[address] = {
|
||||||
@ -420,8 +425,9 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
|
|||||||
}
|
}
|
||||||
private async _refetchEthTokenStateAsync() {
|
private async _refetchEthTokenStateAsync() {
|
||||||
const etherToken = this._getEthToken();
|
const etherToken = this._getEthToken();
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
etherToken.address,
|
etherToken.address,
|
||||||
);
|
);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -237,8 +237,9 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, G
|
|||||||
|
|
||||||
// Check if all required inputs were supplied
|
// Check if all required inputs were supplied
|
||||||
const debitToken = this.props.sideToAssetToken[Side.Deposit];
|
const debitToken = this.props.sideToAssetToken[Side.Deposit];
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
const [debitBalance, debitAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [debitBalance, debitAllowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
debitToken.address,
|
debitToken.address,
|
||||||
);
|
);
|
||||||
const receiveAmount = this.props.sideToAssetToken[Side.Receive].amount;
|
const receiveAmount = this.props.sideToAssetToken[Side.Receive].amount;
|
||||||
|
@ -67,6 +67,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow
|
|||||||
private async _onToggleAllowanceAsync(): Promise<void> {
|
private async _onToggleAllowanceAsync(): Promise<void> {
|
||||||
if (this.props.userAddress === '') {
|
if (this.props.userAddress === '') {
|
||||||
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -109,8 +109,9 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
|
|||||||
this.setState({
|
this.setState({
|
||||||
isBalanceAndAllowanceLoaded: false,
|
isBalanceAndAllowanceLoaded: false,
|
||||||
});
|
});
|
||||||
|
const userAddressIfExists = _.isEmpty(userAddress) ? undefined : userAddress;
|
||||||
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
userAddress,
|
userAddressIfExists,
|
||||||
tokenAddress,
|
tokenAddress,
|
||||||
);
|
);
|
||||||
if (!this._isUnmounted) {
|
if (!this._isUnmounted) {
|
||||||
|
@ -46,7 +46,7 @@ export interface PortalAllProps {
|
|||||||
providerType: ProviderType;
|
providerType: ProviderType;
|
||||||
screenWidth: ScreenWidths;
|
screenWidth: ScreenWidths;
|
||||||
tokenByAddress: TokenByAddress;
|
tokenByAddress: TokenByAddress;
|
||||||
userEtherBalance: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
userAddress: string;
|
userAddress: string;
|
||||||
shouldBlockchainErrDialogBeOpen: boolean;
|
shouldBlockchainErrDialogBeOpen: boolean;
|
||||||
userSuppliedOrderCache: Order;
|
userSuppliedOrderCache: Order;
|
||||||
@ -121,8 +121,9 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (nextProps.userAddress !== this.state.prevUserAddress) {
|
if (nextProps.userAddress !== this.state.prevUserAddress) {
|
||||||
|
const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress;
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this._blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress);
|
this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress);
|
||||||
this.setState({
|
this.setState({
|
||||||
prevUserAddress: nextProps.userAddress,
|
prevUserAddress: nextProps.userAddress,
|
||||||
});
|
});
|
||||||
@ -279,7 +280,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
userAddress={this.props.userAddress}
|
userAddress={this.props.userAddress}
|
||||||
userEtherBalance={this.props.userEtherBalance}
|
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
|
||||||
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
|
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -306,7 +307,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
|
|||||||
tokenByAddress={this.props.tokenByAddress}
|
tokenByAddress={this.props.tokenByAddress}
|
||||||
trackedTokens={trackedTokens}
|
trackedTokens={trackedTokens}
|
||||||
userAddress={this.props.userAddress}
|
userAddress={this.props.userAddress}
|
||||||
userEtherBalance={this.props.userEtherBalance}
|
userEtherBalanceInWei={this.props.userEtherBalanceInWei}
|
||||||
networkId={this.props.networkId}
|
networkId={this.props.networkId}
|
||||||
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
|
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
|
||||||
/>
|
/>
|
||||||
|
@ -48,7 +48,6 @@ const ETHER_ICON_PATH = '/images/ether.png';
|
|||||||
const ETHER_TOKEN_SYMBOL = 'WETH';
|
const ETHER_TOKEN_SYMBOL = 'WETH';
|
||||||
const ZRX_TOKEN_SYMBOL = 'ZRX';
|
const ZRX_TOKEN_SYMBOL = 'ZRX';
|
||||||
|
|
||||||
const PRECISION = 5;
|
|
||||||
const ICON_DIMENSION = 40;
|
const ICON_DIMENSION = 40;
|
||||||
const ARTIFICIAL_FAUCET_REQUEST_DELAY = 1000;
|
const ARTIFICIAL_FAUCET_REQUEST_DELAY = 1000;
|
||||||
const TOKEN_TABLE_ROW_HEIGHT = 60;
|
const TOKEN_TABLE_ROW_HEIGHT = 60;
|
||||||
@ -79,7 +78,7 @@ interface TokenBalancesProps {
|
|||||||
tokenByAddress: TokenByAddress;
|
tokenByAddress: TokenByAddress;
|
||||||
trackedTokens: Token[];
|
trackedTokens: Token[];
|
||||||
userAddress: string;
|
userAddress: string;
|
||||||
userEtherBalance: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
networkId: number;
|
networkId: number;
|
||||||
lastForceTokenStateRefetch: number;
|
lastForceTokenStateRefetch: number;
|
||||||
}
|
}
|
||||||
@ -119,11 +118,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
this._isUnmounted = true;
|
this._isUnmounted = true;
|
||||||
}
|
}
|
||||||
public componentWillReceiveProps(nextProps: TokenBalancesProps) {
|
public componentWillReceiveProps(nextProps: TokenBalancesProps) {
|
||||||
if (nextProps.userEtherBalance !== this.props.userEtherBalance) {
|
if (nextProps.userEtherBalanceInWei !== this.props.userEtherBalanceInWei) {
|
||||||
if (this.state.isBalanceSpinnerVisible) {
|
if (this.state.isBalanceSpinnerVisible) {
|
||||||
const receivedAmount = nextProps.userEtherBalance.minus(this.props.userEtherBalance);
|
const receivedAmountInWei = nextProps.userEtherBalanceInWei.minus(this.props.userEtherBalanceInWei);
|
||||||
|
const receivedAmountInEth = ZeroEx.toUnitAmount(receivedAmountInWei, constants.DECIMAL_PLACES_ETH);
|
||||||
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
|
||||||
this.props.dispatcher.showFlashMessage(`Received ${receivedAmount.toString(10)} ${networkName} Ether`);
|
this.props.dispatcher.showFlashMessage(
|
||||||
|
`Received ${receivedAmountInEth.toString(10)} ${networkName} Ether`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
isBalanceSpinnerVisible: false,
|
isBalanceSpinnerVisible: false,
|
||||||
@ -205,6 +207,10 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
token balances in order to execute trades.<br> \
|
token balances in order to execute trades.<br> \
|
||||||
Toggling sets an allowance for the<br> \
|
Toggling sets an allowance for the<br> \
|
||||||
smart contract so you can start trading that token.';
|
smart contract so you can start trading that token.';
|
||||||
|
const userEtherBalanceInEth = ZeroEx.toUnitAmount(
|
||||||
|
this.props.userEtherBalanceInWei,
|
||||||
|
constants.DECIMAL_PLACES_ETH,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div className="lg-px4 md-px4 sm-px1 pb2">
|
<div className="lg-px4 md-px4 sm-px1 pb2">
|
||||||
<h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3>
|
<h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3>
|
||||||
@ -241,7 +247,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
<img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />
|
<img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />
|
||||||
</TableRowColumn>
|
</TableRowColumn>
|
||||||
<TableRowColumn>
|
<TableRowColumn>
|
||||||
{this.props.userEtherBalance.toFixed(PRECISION)} ETH
|
{userEtherBalanceInEth.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} ETH
|
||||||
{this.state.isBalanceSpinnerVisible && (
|
{this.state.isBalanceSpinnerVisible && (
|
||||||
<span className="pl1">
|
<span className="pl1">
|
||||||
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
|
||||||
@ -493,7 +499,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
}
|
}
|
||||||
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(configs.AMOUNT_DISPLAY_PRECSION);
|
||||||
}
|
}
|
||||||
private _renderTokenName(token: Token) {
|
private _renderTokenName(token: Token) {
|
||||||
const tooltipId = `tooltip-${token.address}`;
|
const tooltipId = `tooltip-${token.address}`;
|
||||||
@ -681,9 +687,10 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
}
|
}
|
||||||
private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]) {
|
private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]) {
|
||||||
const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
|
const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
for (const tokenAddress of tokenAddresses) {
|
for (const tokenAddress of tokenAddresses) {
|
||||||
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
tokenAddress,
|
tokenAddress,
|
||||||
);
|
);
|
||||||
trackedTokenStateByAddress[tokenAddress] = {
|
trackedTokenStateByAddress[tokenAddress] = {
|
||||||
@ -710,8 +717,9 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
|
|||||||
return trackedTokenStateByAddress;
|
return trackedTokenStateByAddress;
|
||||||
}
|
}
|
||||||
private async _refetchTokenStateAsync(tokenAddress: string) {
|
private async _refetchTokenStateAsync(tokenAddress: string) {
|
||||||
|
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
|
||||||
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
|
||||||
this.props.userAddress,
|
userAddressIfExists,
|
||||||
tokenAddress,
|
tokenAddress,
|
||||||
);
|
);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -9,8 +9,8 @@ import * as ReactTooltip from 'react-tooltip';
|
|||||||
import { EtherScanIcon } from 'ts/components/ui/etherscan_icon';
|
import { EtherScanIcon } from 'ts/components/ui/etherscan_icon';
|
||||||
import { Party } from 'ts/components/ui/party';
|
import { Party } from 'ts/components/ui/party';
|
||||||
import { Fill, Token, TokenByAddress } from 'ts/types';
|
import { Fill, Token, TokenByAddress } from 'ts/types';
|
||||||
|
import { configs } from 'ts/utils/configs';
|
||||||
|
|
||||||
const PRECISION = 5;
|
|
||||||
const IDENTICON_DIAMETER = 40;
|
const IDENTICON_DIAMETER = 40;
|
||||||
|
|
||||||
interface TradeHistoryItemProps {
|
interface TradeHistoryItemProps {
|
||||||
@ -131,7 +131,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
|||||||
{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(configs.AMOUNT_DISPLAY_PRECSION)} {givenToken.symbol}/{receiveToken.symbol}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -163,7 +163,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra
|
|||||||
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{unitAmount.toFixed(PRECISION)} {symbol}
|
{unitAmount.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {symbol}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,9 @@ import * as _ from 'lodash';
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Party } from 'ts/components/ui/party';
|
import { Party } from 'ts/components/ui/party';
|
||||||
import { AssetToken, Token, TokenByAddress } from 'ts/types';
|
import { AssetToken, Token, TokenByAddress } from 'ts/types';
|
||||||
|
import { configs } from 'ts/utils/configs';
|
||||||
import { utils } from 'ts/utils/utils';
|
import { utils } from 'ts/utils/utils';
|
||||||
|
|
||||||
const PRECISION = 5;
|
|
||||||
|
|
||||||
interface VisualOrderProps {
|
interface VisualOrderProps {
|
||||||
makerAssetToken: AssetToken;
|
makerAssetToken: AssetToken;
|
||||||
takerAssetToken: AssetToken;
|
takerAssetToken: AssetToken;
|
||||||
@ -67,7 +66,7 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt
|
|||||||
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 }}>
|
||||||
{unitAmount.toNumber().toFixed(PRECISION)} {token.symbol}
|
{unitAmount.toNumber().toFixed(configs.AMOUNT_DISPLAY_PRECSION)} {token.symbol}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ interface ConnectedState {
|
|||||||
providerType: ProviderType;
|
providerType: ProviderType;
|
||||||
tokenByAddress: TokenByAddress;
|
tokenByAddress: TokenByAddress;
|
||||||
lastForceTokenStateRefetch: number;
|
lastForceTokenStateRefetch: number;
|
||||||
userEtherBalance: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
screenWidth: ScreenWidths;
|
screenWidth: ScreenWidths;
|
||||||
shouldBlockchainErrDialogBeOpen: boolean;
|
shouldBlockchainErrDialogBeOpen: boolean;
|
||||||
userAddress: string;
|
userAddress: string;
|
||||||
@ -72,7 +72,7 @@ const mapStateToProps = (state: State, ownProps: PortalComponentAllProps): Conne
|
|||||||
tokenByAddress: state.tokenByAddress,
|
tokenByAddress: state.tokenByAddress,
|
||||||
lastForceTokenStateRefetch: state.lastForceTokenStateRefetch,
|
lastForceTokenStateRefetch: state.lastForceTokenStateRefetch,
|
||||||
userAddress: state.userAddress,
|
userAddress: state.userAddress,
|
||||||
userEtherBalance: state.userEtherBalance,
|
userEtherBalanceInWei: state.userEtherBalanceInWei,
|
||||||
userSuppliedOrderCache: state.userSuppliedOrderCache,
|
userSuppliedOrderCache: state.userSuppliedOrderCache,
|
||||||
flashMessage: state.flashMessage,
|
flashMessage: state.flashMessage,
|
||||||
translate: state.translate,
|
translate: state.translate,
|
||||||
|
@ -86,7 +86,7 @@ export class Dispatcher {
|
|||||||
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,
|
||||||
@ -125,14 +125,14 @@ export class Dispatcher {
|
|||||||
public batchDispatch(
|
public batchDispatch(
|
||||||
tokenByAddress: TokenByAddress,
|
tokenByAddress: TokenByAddress,
|
||||||
networkId: number,
|
networkId: number,
|
||||||
userAddress: string,
|
userAddressIfExists: string | undefined,
|
||||||
sideToAssetToken: SideToAssetToken,
|
sideToAssetToken: SideToAssetToken,
|
||||||
) {
|
) {
|
||||||
this._dispatch({
|
this._dispatch({
|
||||||
data: {
|
data: {
|
||||||
tokenByAddress,
|
tokenByAddress,
|
||||||
networkId,
|
networkId,
|
||||||
userAddress,
|
userAddressIfExists,
|
||||||
sideToAssetToken,
|
sideToAssetToken,
|
||||||
},
|
},
|
||||||
type: ActionTypes.BatchDispatch,
|
type: ActionTypes.BatchDispatch,
|
||||||
@ -155,7 +155,7 @@ export class Dispatcher {
|
|||||||
type: ActionTypes.UpdateOrderECSignature,
|
type: ActionTypes.UpdateOrderECSignature,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public updateUserEtherBalance(balance: BigNumber) {
|
public updateUserWeiBalance(balance: BigNumber) {
|
||||||
this._dispatch({
|
this._dispatch({
|
||||||
data: balance,
|
data: balance,
|
||||||
type: ActionTypes.UpdateUserEtherBalance,
|
type: ActionTypes.UpdateUserEtherBalance,
|
||||||
|
@ -38,7 +38,7 @@ export interface State {
|
|||||||
tokenByAddress: TokenByAddress;
|
tokenByAddress: TokenByAddress;
|
||||||
lastForceTokenStateRefetch: number;
|
lastForceTokenStateRefetch: number;
|
||||||
userAddress: string;
|
userAddress: string;
|
||||||
userEtherBalance: BigNumber;
|
userEtherBalanceInWei: BigNumber;
|
||||||
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
|
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
|
||||||
userSuppliedOrderCache: Order;
|
userSuppliedOrderCache: Order;
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ const INITIAL_STATE: State = {
|
|||||||
tokenByAddress: {},
|
tokenByAddress: {},
|
||||||
lastForceTokenStateRefetch: moment().unix(),
|
lastForceTokenStateRefetch: moment().unix(),
|
||||||
userAddress: '',
|
userAddress: '',
|
||||||
userEtherBalance: new BigNumber(0),
|
userEtherBalanceInWei: new BigNumber(0),
|
||||||
userSuppliedOrderCache: undefined,
|
userSuppliedOrderCache: undefined,
|
||||||
|
|
||||||
// Docs
|
// Docs
|
||||||
@ -138,7 +138,7 @@ export function reducer(state: State = INITIAL_STATE, action: Action) {
|
|||||||
case ActionTypes.UpdateUserEtherBalance: {
|
case ActionTypes.UpdateUserEtherBalance: {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
userEtherBalance: action.data,
|
userEtherBalanceInWei: action.data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,10 +184,11 @@ export function reducer(state: State = INITIAL_STATE, action: Action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ActionTypes.BatchDispatch: {
|
case ActionTypes.BatchDispatch: {
|
||||||
|
const userAddress = _.isUndefined(action.data.userAddressIfExists) ? '' : action.data.userAddressIfExists;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
networkId: action.data.networkId,
|
networkId: action.data.networkId,
|
||||||
userAddress: action.data.userAddress,
|
userAddress,
|
||||||
sideToAssetToken: action.data.sideToAssetToken,
|
sideToAssetToken: action.data.sideToAssetToken,
|
||||||
tokenByAddress: action.data.tokenByAddress,
|
tokenByAddress: action.data.tokenByAddress,
|
||||||
};
|
};
|
||||||
@ -284,9 +285,10 @@ export function reducer(state: State = INITIAL_STATE, action: Action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ActionTypes.UpdateUserAddress: {
|
case ActionTypes.UpdateUserAddress: {
|
||||||
|
const userAddress = _.isUndefined(action.data) ? '' : action.data;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
userAddress: action.data,
|
userAddress,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ const isDevelopment = _.includes(
|
|||||||
const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs';
|
const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs';
|
||||||
|
|
||||||
export const configs = {
|
export const configs = {
|
||||||
|
AMOUNT_DISPLAY_PRECSION: 5,
|
||||||
BACKEND_BASE_URL: 'https://website-api.0xproject.com',
|
BACKEND_BASE_URL: 'https://website-api.0xproject.com',
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208',
|
BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208',
|
||||||
|
@ -1,157 +0,0 @@
|
|||||||
import { BigNumber, intervalUtils, promisify } from '@0xproject/utils';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { Dispatcher } from 'ts/redux/dispatcher';
|
|
||||||
import { utils } from 'ts/utils/utils';
|
|
||||||
import * as Web3 from 'web3';
|
|
||||||
|
|
||||||
export class Web3Wrapper {
|
|
||||||
private _dispatcher: Dispatcher;
|
|
||||||
private _web3: Web3;
|
|
||||||
private _prevNetworkId: number;
|
|
||||||
private _shouldPollUserAddress: boolean;
|
|
||||||
private _watchNetworkAndBalanceIntervalId: NodeJS.Timer;
|
|
||||||
private _prevUserEtherBalanceInEth: BigNumber;
|
|
||||||
private _prevUserAddress: string;
|
|
||||||
constructor(
|
|
||||||
dispatcher: Dispatcher,
|
|
||||||
provider: Web3.Provider,
|
|
||||||
networkIdIfExists: number,
|
|
||||||
shouldPollUserAddress: boolean,
|
|
||||||
) {
|
|
||||||
this._dispatcher = dispatcher;
|
|
||||||
this._prevNetworkId = networkIdIfExists;
|
|
||||||
this._shouldPollUserAddress = shouldPollUserAddress;
|
|
||||||
|
|
||||||
this._web3 = new Web3();
|
|
||||||
this._web3.setProvider(provider);
|
|
||||||
}
|
|
||||||
public isAddress(address: string) {
|
|
||||||
return this._web3.isAddress(address);
|
|
||||||
}
|
|
||||||
public async getAccountsAsync(): Promise<string[]> {
|
|
||||||
const addresses = await promisify<string[]>(this._web3.eth.getAccounts)();
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
public async getFirstAccountIfExistsAsync() {
|
|
||||||
const addresses = await this.getAccountsAsync();
|
|
||||||
if (_.isEmpty(addresses)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return addresses[0];
|
|
||||||
}
|
|
||||||
public async getNodeVersionAsync(): Promise<string> {
|
|
||||||
const nodeVersion = await promisify<string>(this._web3.version.getNode)();
|
|
||||||
return nodeVersion;
|
|
||||||
}
|
|
||||||
public getProviderObj() {
|
|
||||||
return this._web3.currentProvider;
|
|
||||||
}
|
|
||||||
public async getNetworkIdIfExists() {
|
|
||||||
try {
|
|
||||||
const networkId = await this._getNetworkAsync();
|
|
||||||
return Number(networkId);
|
|
||||||
} catch (err) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
|
|
||||||
const balanceInWei: BigNumber = await promisify<BigNumber>(this._web3.eth.getBalance)(owner);
|
|
||||||
const balanceEthOldBigNumber = this._web3.fromWei(balanceInWei, 'ether');
|
|
||||||
const balanceEth = new BigNumber(balanceEthOldBigNumber);
|
|
||||||
return balanceEth;
|
|
||||||
}
|
|
||||||
public async doesContractExistAtAddressAsync(address: string): Promise<boolean> {
|
|
||||||
const code = await promisify<string>(this._web3.eth.getCode)(address);
|
|
||||||
// Regex matches 0x0, 0x00, 0x in order to accomodate poorly implemented clients
|
|
||||||
const zeroHexAddressRegex = /^0[xX][0]*$/;
|
|
||||||
const didFindCode = _.isNull(code.match(zeroHexAddressRegex));
|
|
||||||
return didFindCode;
|
|
||||||
}
|
|
||||||
public async signTransactionAsync(address: string, message: string): Promise<string> {
|
|
||||||
const signData = await promisify<string>(this._web3.eth.sign)(address, message);
|
|
||||||
return signData;
|
|
||||||
}
|
|
||||||
public async getBlockTimestampAsync(blockHash: string): Promise<number> {
|
|
||||||
const { timestamp } = await promisify<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockHash);
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
public destroy() {
|
|
||||||
this._stopEmittingNetworkConnectionAndUserBalanceStateAsync();
|
|
||||||
// HACK: stop() is only available on providerEngine instances
|
|
||||||
const provider = this._web3.currentProvider;
|
|
||||||
if (!_.isUndefined((provider as any).stop)) {
|
|
||||||
(provider as any).stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This should only be called from the LedgerConfigDialog
|
|
||||||
public updatePrevUserAddress(userAddress: string) {
|
|
||||||
this._prevUserAddress = userAddress;
|
|
||||||
}
|
|
||||||
public startEmittingNetworkConnectionAndUserBalanceState() {
|
|
||||||
if (!_.isUndefined(this._watchNetworkAndBalanceIntervalId)) {
|
|
||||||
return; // we are already emitting the state
|
|
||||||
}
|
|
||||||
|
|
||||||
let prevNodeVersion: string;
|
|
||||||
this._prevUserEtherBalanceInEth = new BigNumber(0);
|
|
||||||
this._dispatcher.updateNetworkId(this._prevNetworkId);
|
|
||||||
this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval(
|
|
||||||
async () => {
|
|
||||||
// Check for network state changes
|
|
||||||
const currentNetworkId = await this.getNetworkIdIfExists();
|
|
||||||
if (currentNetworkId !== this._prevNetworkId) {
|
|
||||||
this._prevNetworkId = currentNetworkId;
|
|
||||||
this._dispatcher.updateNetworkId(currentNetworkId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for node version changes
|
|
||||||
const currentNodeVersion = await this.getNodeVersionAsync();
|
|
||||||
if (currentNodeVersion !== prevNodeVersion) {
|
|
||||||
prevNodeVersion = currentNodeVersion;
|
|
||||||
this._dispatcher.updateNodeVersion(currentNodeVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._shouldPollUserAddress) {
|
|
||||||
const userAddressIfExists = await this.getFirstAccountIfExistsAsync();
|
|
||||||
// Update makerAddress on network change
|
|
||||||
if (this._prevUserAddress !== userAddressIfExists) {
|
|
||||||
this._prevUserAddress = userAddressIfExists;
|
|
||||||
this._dispatcher.updateUserAddress(userAddressIfExists);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for user ether balance changes
|
|
||||||
if (!_.isEmpty(userAddressIfExists)) {
|
|
||||||
await this._updateUserEtherBalanceAsync(userAddressIfExists);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 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.
|
|
||||||
if (!_.isEmpty(this._prevUserAddress)) {
|
|
||||||
await this._updateUserEtherBalanceAsync(this._prevUserAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
(err: Error) => {
|
|
||||||
utils.consoleLog(`Watching network and balances failed: ${err.stack}`);
|
|
||||||
this._stopEmittingNetworkConnectionAndUserBalanceStateAsync();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
private async _getNetworkAsync() {
|
|
||||||
const networkId = await promisify(this._web3.version.getNetwork)();
|
|
||||||
return networkId;
|
|
||||||
}
|
|
||||||
private async _updateUserEtherBalanceAsync(userAddress: string) {
|
|
||||||
const balance = await this.getBalanceInEthAsync(userAddress);
|
|
||||||
if (!balance.eq(this._prevUserEtherBalanceInEth)) {
|
|
||||||
this._prevUserEtherBalanceInEth = balance;
|
|
||||||
this._dispatcher.updateUserEtherBalance(balance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private _stopEmittingNetworkConnectionAndUserBalanceStateAsync() {
|
|
||||||
if (!_.isUndefined(this._watchNetworkAndBalanceIntervalId)) {
|
|
||||||
intervalUtils.clearAsyncExcludingInterval(this._watchNetworkAndBalanceIntervalId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user