diff options
-rw-r--r-- | packages/json-schemas/package.json | 2 | ||||
-rw-r--r-- | packages/website/package.json | 1 | ||||
-rw-r--r-- | packages/website/ts/blockchain.ts | 321 | ||||
-rw-r--r-- | packages/website/ts/components/fill_order.tsx | 122 | ||||
-rw-r--r-- | packages/website/ts/globals.d.ts | 10 | ||||
-rw-r--r-- | packages/website/ts/types.ts | 19 | ||||
-rw-r--r-- | packages/website/ts/web3_wrapper.ts | 7 |
7 files changed, 233 insertions, 249 deletions
diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 9d207a923..87194d362 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -5,7 +5,7 @@ "main": "lib/src/index.js", "types": "lib/src/index.d.ts", "scripts": { - "lint": "tslint --project . 'src/*.ts' 'test/*.ts'", + "lint": "tslint --project . src/*.ts test/*.ts", "test": "run-s clean build run_mocha", "test:circleci": "yarn test", "run_mocha": "mocha lib/test/**/*_test.js", diff --git a/packages/website/package.json b/packages/website/package.json index f9951defb..f91b579bd 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -3,7 +3,6 @@ "version": "0.0.0", "description": "Website and 0x portal dapp", "scripts": { - "lint": "tslint --project . 'ts/*.ts'", "build": "NODE_ENV=production webpack; exit 0;", "clean": "shx rm -f public/bundle*", "dev": "webpack-dev-server --content-base public --https", diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index 7851ea8ff..b13c48a65 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -1,60 +1,59 @@ +import * as _ from 'lodash'; +import * as React from 'react'; import { - BlockParam, - DecodedLogEvent, + ZeroEx, + ZeroExError, ExchangeContractErrs, ExchangeContractEventArgs, ExchangeEvents, + SubscriptionOpts, IndexedFilterValues, - LogCancelContractEventArgs, + DecodedLogEvent, + BlockParam, LogFillContractEventArgs, - LogWithDecodedArgs, - Order, - SignedOrder, - SubscriptionOpts, + LogCancelContractEventArgs, Token as ZeroExToken, + LogWithDecodedArgs, TransactionReceiptWithDecodedLogs, - ZeroEx, - ZeroExError, + SignedOrder, + Order, } from '0x.js'; import BigNumber from 'bignumber.js'; -import compareVersions = require('compare-versions'); +import Web3 = require('web3'); import promisify = require('es6-promisify'); -import ethUtil = require('ethereumjs-util'); import findVersions = require('find-versions'); -import * as _ from 'lodash'; -import * as React from 'react'; +import compareVersions = require('compare-versions'); import contract = require('truffle-contract'); -import {TokenSendCompleted} from 'ts/components/flash_messages/token_send_completed'; +import ethUtil = require('ethereumjs-util'); +import ProviderEngine = require('web3-provider-engine'); +import FilterSubprovider = require('web3-provider-engine/subproviders/filters'); import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {tradeHistoryStorage} from 'ts/local_storage/trade_history_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; +import {TokenSendCompleted} from 'ts/components/flash_messages/token_send_completed'; +import {RedundantRPCSubprovider} from 'ts/subproviders/redundant_rpc_subprovider'; import {InjectedWeb3SubProvider} from 'ts/subproviders/injected_web3_subprovider'; import {ledgerWalletSubproviderFactory} from 'ts/subproviders/ledger_wallet_subprovider_factory'; -import {RedundantRPCSubprovider} from 'ts/subproviders/redundant_rpc_subprovider'; +import {Dispatcher} from 'ts/redux/dispatcher'; +import {utils} from 'ts/utils/utils'; +import {constants} from 'ts/utils/constants'; +import {configs} from 'ts/utils/configs'; import { - BlockchainCallErrs, BlockchainErrs, - ContractInstance, + Token, + SignatureData, + Side, ContractResponse, - EtherscanLinkSuffixes, - LedgerWalletSubprovider, + BlockchainCallErrs, + ContractInstance, ProviderType, - Side, - SignatureData, - Token, + LedgerWalletSubprovider, + EtherscanLinkSuffixes, TokenByAddress, TokenStateByAddress, } from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; import {Web3Wrapper} from 'ts/web3_wrapper'; -import Web3 = require('web3'); -import ProviderEngine = require('web3-provider-engine'); -import FilterSubprovider = require('web3-provider-engine/subproviders/filters'); - +import {errorReporter} from 'ts/utils/error_reporter'; +import {tradeHistoryStorage} from 'ts/local_storage/trade_history_storage'; +import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; import * as MintableArtifacts from '../contracts/Mintable.json'; const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 45730; @@ -73,116 +72,9 @@ export class Blockchain { private cachedProvider: Web3.Provider; private ledgerSubProvider: LedgerWalletSubprovider; private zrxPollIntervalId: number; - public static toHumanReadableErrorMsg(error: ZeroExError|ExchangeContractErrs, takerAddress: string): string { - const ZeroExErrorToHumanReadableError: {[error: string]: string} = { - [ZeroExError.TokenTransferProxyContractDoesNotExist]: 'Token transfer proxy contract does not exist', - [ZeroExError.TokenContractDoesNotExist]: 'Token contract does not exist', - [ZeroExError.ZRXContractDoesNotExist]: 'ZRX contract does not exist', - [ZeroExError.EtherTokenContractDoesNotExist]: 'Ether token contract does not exist', - [ZeroExError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist', - [ZeroExError.UnhandledError]: ' Unhandled error occured', - [ZeroExError.UserHasNoAssociatedAddress]: 'User has no addresses available', - [ZeroExError.InvalidSignature]: 'Order signature is not valid', - [ZeroExError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network', - [ZeroExError.InvalidJump]: 'Invalid jump occured while executing the transaction', - [ZeroExError.OutOfGas]: 'Transaction ran out of gas', - [ZeroExError.NoNetworkId]: 'No network id detected', - }; - const exchangeContractErrorToHumanReadableError: {[error: string]: string} = { - [ExchangeContractErrs.OrderFillExpired]: 'This order has expired', - [ExchangeContractErrs.OrderCancelExpired]: 'This order has expired', - [ExchangeContractErrs.OrderCancelAmountZero]: 'Order cancel amount can\'t be 0', - [ExchangeContractErrs.OrderAlreadyCancelledOrFilled]: - 'This order has already been completely filled or cancelled', - [ExchangeContractErrs.OrderFillAmountZero]: 'Order fill amount can\'t be 0', - [ExchangeContractErrs.OrderRemainingFillAmountZero]: - 'This order has already been completely filled or cancelled', - [ExchangeContractErrs.OrderFillRoundingError]: 'Rounding error will occur when filling this order', - [ExchangeContractErrs.InsufficientTakerBalance]: - 'Taker no longer has a sufficient balance to complete this order', - [ExchangeContractErrs.InsufficientTakerAllowance]: - 'Taker no longer has a sufficient allowance to complete this order', - [ExchangeContractErrs.InsufficientMakerBalance]: - 'Maker no longer has a sufficient balance to complete this order', - [ExchangeContractErrs.InsufficientMakerAllowance]: - 'Maker no longer has a sufficient allowance to complete this order', - [ExchangeContractErrs.InsufficientTakerFeeBalance]: 'Taker no longer has a sufficient balance to pay fees', - [ExchangeContractErrs.InsufficientTakerFeeAllowance]: - 'Taker no longer has a sufficient allowance to pay fees', - [ExchangeContractErrs.InsufficientMakerFeeBalance]: 'Maker no longer has a sufficient balance to pay fees', - [ExchangeContractErrs.InsufficientMakerFeeAllowance]: - 'Maker no longer has a sufficient allowance to pay fees', - [ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker]: - `This order can only be filled by ${takerAddress}`, - [ExchangeContractErrs.InsufficientRemainingFillAmount]: - 'Insufficient remaining fill amount', - }; - const humanReadableErrorMsg = exchangeContractErrorToHumanReadableError[error] || - ZeroExErrorToHumanReadableError[error]; - return humanReadableErrorMsg; - } - private static async getProviderAsync(injectedWeb3: Web3, networkIdIfExists: number): Promise<Web3.Provider> { - const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3); - const publicNodeUrlsIfExistsForNetworkId = constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists]; - const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId); - - let provider; - if (doesInjectedWeb3Exist && isPublicNodeAvailableForNetworkId) { - // We catch all requests involving a users account and send it to the injectedWeb3 - // instance. All other requests go to the public hosted node. - provider = new ProviderEngine(); - provider.addProvider(new InjectedWeb3SubProvider(injectedWeb3)); - provider.addProvider(new FilterSubprovider()); - provider.addProvider(new RedundantRPCSubprovider( - publicNodeUrlsIfExistsForNetworkId, - )); - provider.start(); - } else if (doesInjectedWeb3Exist) { - // Since no public node for this network, all requests go to injectedWeb3 instance - provider = injectedWeb3.currentProvider; - } else { - // If no injectedWeb3 instance, all requests fallback to our public hosted mainnet/testnet node - // We do this so that users can still browse the 0x Portal DApp even if they do not have web3 - // injected into their browser. - provider = new ProviderEngine(); - provider.addProvider(new FilterSubprovider()); - const networkId = configs.isMainnetEnabled ? - constants.MAINNET_NETWORK_ID : - constants.TESTNET_NETWORK_ID; - provider.addProvider(new RedundantRPCSubprovider( - constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], - )); - provider.start(); - } - - return provider; - } - private static getNameGivenProvider(provider: Web3.Provider): string { - if (!_.isUndefined((provider as any).isMetaMask)) { - return constants.METAMASK_PROVIDER_NAME; - } - - // HACK: We use the fact that Parity Signer's provider is an instance of their - // internal `Web3FrameProvider` class. - const isParitySigner = _.startsWith(provider.constructor.toString(), 'function Web3FrameProvider'); - if (isParitySigner) { - return constants.PARITY_SIGNER_PROVIDER_NAME; - } - - return constants.GENERIC_PROVIDER_NAME; - } - private static async onPageLoadAsync() { - if (document.readyState === 'complete') { - return; // Already loaded - } - return new Promise((resolve, reject) => { - window.onload = resolve; - }); - } constructor(dispatcher: Dispatcher, isSalePage: boolean = false) { this.dispatcher = dispatcher; this.userAddress = ''; - // tslint:disable-next-line:no-floating-promises this.onPageLoadInitFireAndForgetAsync(); } public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number) { @@ -265,8 +157,8 @@ export class Blockchain { this.web3Wrapper.destroy(); const shouldPollUserAddress = false; this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress); - this.zeroEx.setProvider(provider, this.networkId); - this.postInstantiationOrUpdatingProviderZeroEx(); + await this.zeroEx.setProviderAsync(provider); + await this.postInstantiationOrUpdatingProviderZeroExAsync(); break; } @@ -277,8 +169,8 @@ export class Blockchain { provider = this.cachedProvider; const shouldPollUserAddress = true; this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress); - this.zeroEx.setProvider(provider, this.networkId); - this.postInstantiationOrUpdatingProviderZeroEx(); + await this.zeroEx.setProviderAsync(provider); + await this.postInstantiationOrUpdatingProviderZeroExAsync(); delete this.ledgerSubProvider; delete this.cachedProvider; break; @@ -316,7 +208,7 @@ export class Blockchain { amountInBaseUnits, })); } - public portalOrderToSignedOrder(maker: string, takerIfExists: string, makerTokenAddress: string, + public portalOrderToSignedOrder(maker: string, taker: string, makerTokenAddress: string, takerTokenAddress: string, makerTokenAmount: BigNumber, takerTokenAmount: BigNumber, makerFee: BigNumber, takerFee: BigNumber, expirationUnixTimestampSec: BigNumber, @@ -324,7 +216,7 @@ export class Blockchain { signatureData: SignatureData, salt: BigNumber): SignedOrder { const ecSignature = signatureData; const exchangeContractAddress = this.getExchangeContractAddressIfExists(); - const taker = _.isEmpty(takerIfExists) ? constants.NULL_ADDRESS : takerIfExists; + taker = _.isEmpty(taker) ? constants.NULL_ADDRESS : taker; const signedOrder = { ecSignature, exchangeContractAddress, @@ -381,6 +273,51 @@ export class Blockchain { public getExchangeContractAddressIfExists() { return this.exchangeAddress; } + public toHumanReadableErrorMsg(error: ZeroExError|ExchangeContractErrs, takerAddress: string): string { + const ZeroExErrorToHumanReadableError: {[error: string]: string} = { + [ZeroExError.ContractDoesNotExist]: 'Contract does not exist', + [ZeroExError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist', + [ZeroExError.UnhandledError]: ' Unhandled error occured', + [ZeroExError.UserHasNoAssociatedAddress]: 'User has no addresses available', + [ZeroExError.InvalidSignature]: 'Order signature is not valid', + [ZeroExError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network', + [ZeroExError.InvalidJump]: 'Invalid jump occured while executing the transaction', + [ZeroExError.OutOfGas]: 'Transaction ran out of gas', + [ZeroExError.NoNetworkId]: 'No network id detected', + }; + const exchangeContractErrorToHumanReadableError: {[error: string]: string} = { + [ExchangeContractErrs.OrderFillExpired]: 'This order has expired', + [ExchangeContractErrs.OrderCancelExpired]: 'This order has expired', + [ExchangeContractErrs.OrderCancelAmountZero]: 'Order cancel amount can\'t be 0', + [ExchangeContractErrs.OrderAlreadyCancelledOrFilled]: + 'This order has already been completely filled or cancelled', + [ExchangeContractErrs.OrderFillAmountZero]: 'Order fill amount can\'t be 0', + [ExchangeContractErrs.OrderRemainingFillAmountZero]: + 'This order has already been completely filled or cancelled', + [ExchangeContractErrs.OrderFillRoundingError]: 'Rounding error will occur when filling this order', + [ExchangeContractErrs.InsufficientTakerBalance]: + 'Taker no longer has a sufficient balance to complete this order', + [ExchangeContractErrs.InsufficientTakerAllowance]: + 'Taker no longer has a sufficient allowance to complete this order', + [ExchangeContractErrs.InsufficientMakerBalance]: + 'Maker no longer has a sufficient balance to complete this order', + [ExchangeContractErrs.InsufficientMakerAllowance]: + 'Maker no longer has a sufficient allowance to complete this order', + [ExchangeContractErrs.InsufficientTakerFeeBalance]: 'Taker no longer has a sufficient balance to pay fees', + [ExchangeContractErrs.InsufficientTakerFeeAllowance]: + 'Taker no longer has a sufficient allowance to pay fees', + [ExchangeContractErrs.InsufficientMakerFeeBalance]: 'Maker no longer has a sufficient balance to pay fees', + [ExchangeContractErrs.InsufficientMakerFeeAllowance]: + 'Maker no longer has a sufficient allowance to pay fees', + [ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker]: + `This order can only be filled by ${takerAddress}`, + [ExchangeContractErrs.InsufficientRemainingFillAmount]: + 'Insufficient remaining fill amount', + }; + const humanReadableErrorMsg = exchangeContractErrorToHumanReadableError[error] || + ZeroExErrorToHumanReadableError[error]; + return humanReadableErrorMsg; + } public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber, takerAddress: string): Promise<void> { @@ -509,7 +446,6 @@ export class Blockchain { public destroy() { clearInterval(this.zrxPollIntervalId); this.web3Wrapper.destroy(); - // tslint:disable-next-line:no-floating-promises this.stopWatchingExchangeLogFillEventsAsync(); // fire and forget } private async showEtherScanLinkAndAwaitTransactionMinedAsync( @@ -549,7 +485,7 @@ export class Blockchain { // Start a subscription for new logs const exchangeAddress = this.getExchangeContractAddressIfExists(); - const subscriptionId = this.zeroEx.exchange.subscribe( + const subscriptionId = await this.zeroEx.exchange.subscribeAsync( ExchangeEvents.LogFill, indexFilterValues, async (err: Error, decodedLogEvent: DecodedLogEvent<LogFillContractEventArgs>) => { const decodedLog = decodedLogEvent.log; @@ -557,9 +493,7 @@ export class Blockchain { // Note: it's not entirely clear from the documentation which // errors will be thrown by `watch`. For now, let's log the error // to rollbar and stop watching when one occurs - // tslint:disable-next-line:no-floating-promises errorReporter.reportAsync(err); // fire and forget - // tslint:disable-next-line:no-floating-promises this.stopWatchingExchangeLogFillEventsAsync(); // fire and forget return; } else { @@ -595,7 +529,7 @@ export class Blockchain { } } private async convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { - const args = decodedLog.args; + const args = decodedLog.args as LogFillContractEventArgs; const blockTimestamp = await this.web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash); const fill = { filledTakerTokenAmount: args.filledTakerTokenAmount, @@ -614,7 +548,7 @@ export class Blockchain { return fill; } private doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { - const args = decodedLog.args; + const args = decodedLog.args as LogFillContractEventArgs; const isUserMakerOrTaker = args.maker === this.userAddress || args.taker === this.userAddress; return isUserMakerOrTaker; @@ -660,7 +594,7 @@ export class Blockchain { return tokenByAddress; } private async onPageLoadInitFireAndForgetAsync() { - await Blockchain.onPageLoadAsync(); // wait for page to load + await this.onPageLoadAsync(); // wait for page to load // Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in // order to properly instantiate the web3Wrapper. Since we must use the async call, we cannot @@ -678,34 +612,81 @@ export class Blockchain { } } - const provider = await Blockchain.getProviderAsync(injectedWeb3, networkId); - const zeroExConfig = { - networkId: this.networkId, - }; - this.zeroEx = new ZeroEx(provider, zeroExConfig); - this.updateProviderName(injectedWeb3); + const provider = await this.getProviderAsync(injectedWeb3, networkId); + this.zeroEx = new ZeroEx(provider); + await this.updateProviderName(injectedWeb3); const shouldPollUserAddress = true; this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, networkId, shouldPollUserAddress); - this.postInstantiationOrUpdatingProviderZeroEx(); + await this.postInstantiationOrUpdatingProviderZeroExAsync(); } // This method should always be run after instantiating or updating the provider // of the ZeroEx instance. - private postInstantiationOrUpdatingProviderZeroEx(): void { + private async postInstantiationOrUpdatingProviderZeroExAsync() { utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - this.exchangeAddress = this.zeroEx.exchange.getContractAddress(); + this.exchangeAddress = await this.zeroEx.exchange.getContractAddressAsync(); } - private updateProviderName(injectedWeb3: Web3): void { + private updateProviderName(injectedWeb3: Web3) { const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3); const providerName = doesInjectedWeb3Exist ? - Blockchain.getNameGivenProvider(injectedWeb3.currentProvider) : + this.getNameGivenProvider(injectedWeb3.currentProvider) : constants.PUBLIC_PROVIDER_NAME; this.dispatcher.updateInjectedProviderName(providerName); } // This is only ever called by the LedgerWallet subprovider in order to retrieve // the current networkId without this value going stale. - private getBlockchainNetworkId(): number { + private getBlockchainNetworkId() { return this.networkId; } + private async getProviderAsync(injectedWeb3: Web3, networkIdIfExists: number) { + const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3); + const publicNodeUrlsIfExistsForNetworkId = constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists]; + const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId); + + let provider; + if (doesInjectedWeb3Exist && isPublicNodeAvailableForNetworkId) { + // We catch all requests involving a users account and send it to the injectedWeb3 + // instance. All other requests go to the public hosted node. + provider = new ProviderEngine(); + provider.addProvider(new InjectedWeb3SubProvider(injectedWeb3)); + provider.addProvider(new FilterSubprovider()); + provider.addProvider(new RedundantRPCSubprovider( + publicNodeUrlsIfExistsForNetworkId, + )); + provider.start(); + } else if (doesInjectedWeb3Exist) { + // Since no public node for this network, all requests go to injectedWeb3 instance + provider = injectedWeb3.currentProvider; + } else { + // If no injectedWeb3 instance, all requests fallback to our public hosted mainnet/testnet node + // We do this so that users can still browse the 0x Portal DApp even if they do not have web3 + // injected into their browser. + provider = new ProviderEngine(); + provider.addProvider(new FilterSubprovider()); + const networkId = configs.isMainnetEnabled ? + constants.MAINNET_NETWORK_ID : + constants.TESTNET_NETWORK_ID; + provider.addProvider(new RedundantRPCSubprovider( + constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], + )); + provider.start(); + } + + return provider; + } + private getNameGivenProvider(provider: Web3.Provider): string { + if (!_.isUndefined((provider as any).isMetaMask)) { + return constants.METAMASK_PROVIDER_NAME; + } + + // HACK: We use the fact that Parity Signer's provider is an instance of their + // internal `Web3FrameProvider` class. + const isParitySigner = _.startsWith(provider.constructor.toString(), 'function Web3FrameProvider'); + if (isParitySigner) { + return constants.PARITY_SIGNER_PROVIDER_NAME; + } + + return constants.GENERIC_PROVIDER_NAME; + } private async fetchTokenInformationAsync() { utils.assert(!_.isUndefined(this.networkId), 'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node'); @@ -795,4 +776,12 @@ export class Blockchain { } } } -} // tslint:disable:max-file-line-count + private async onPageLoadAsync() { + if (document.readyState === 'complete') { + return; // Already loaded + } + return new Promise((resolve, reject) => { + window.onload = resolve; + }); + } +} diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx index 4077e4f8b..dc965283e 100644 --- a/packages/website/ts/components/fill_order.tsx +++ b/packages/website/ts/components/fill_order.tsx @@ -1,44 +1,44 @@ -import {Order as ZeroExOrder, ZeroEx} from '0x.js'; +import * as _ from 'lodash'; +import * as React from 'react'; import * as accounting from 'accounting'; +import {Link} from 'react-router-dom'; +import {ZeroEx, Order as ZeroExOrder} from '0x.js'; +import * as moment from 'moment'; import BigNumber from 'bignumber.js'; -import * as _ from 'lodash'; -import {Card, CardHeader, CardText} from 'material-ui/Card'; -import Divider from 'material-ui/Divider'; import Paper from 'material-ui/Paper'; -import RaisedButton from 'material-ui/RaisedButton'; +import {Card, CardText, CardHeader} from 'material-ui/Card'; +import Divider from 'material-ui/Divider'; import TextField from 'material-ui/TextField'; -import * as moment from 'moment'; -import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {Blockchain} from 'ts/blockchain'; -import {TrackTokenConfirmationDialog} from 'ts/components/dialogs/track_token_confirmation_dialog'; -import {FillOrderJSON} from 'ts/components/fill_order_json'; -import {FillWarningDialog} from 'ts/components/fill_warning_dialog'; -import {TokenAmountInput} from 'ts/components/inputs/token_amount_input'; -import {Alert} from 'ts/components/ui/alert'; -import {EthereumAddress} from 'ts/components/ui/ethereum_address'; -import {Identicon} from 'ts/components/ui/identicon'; -import {VisualOrder} from 'ts/components/visual_order'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {orderSchema} from 'ts/schemas/order_schema'; -import {SchemaValidator} from 'ts/schemas/validator'; +import RaisedButton from 'material-ui/RaisedButton'; +import {utils} from 'ts/utils/utils'; +import {constants} from 'ts/utils/constants'; import { - AlertTypes, - BlockchainErrs, - ContractResponse, - ExchangeContractErrs, - Order, - OrderToken, Side, - Token, TokenByAddress, TokenStateByAddress, + Order, + BlockchainErrs, + OrderToken, + Token, + ExchangeContractErrs, + AlertTypes, + ContractResponse, WebsitePaths, } from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import {Alert} from 'ts/components/ui/alert'; +import {Identicon} from 'ts/components/ui/identicon'; +import {EthereumAddress} from 'ts/components/ui/ethereum_address'; +import {TokenAmountInput} from 'ts/components/inputs/token_amount_input'; +import {FillWarningDialog} from 'ts/components/fill_warning_dialog'; +import {FillOrderJSON} from 'ts/components/fill_order_json'; +import {VisualOrder} from 'ts/components/visual_order'; +import {SchemaValidator} from 'ts/schemas/validator'; +import {orderSchema} from 'ts/schemas/order_schema'; +import {Dispatcher} from 'ts/redux/dispatcher'; +import {Blockchain} from 'ts/blockchain'; import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; +import {TrackTokenConfirmationDialog} from 'ts/components/dialogs/track_token_confirmation_dialog'; const CUSTOM_LIGHT_GRAY = '#BBBBBB'; @@ -76,31 +76,6 @@ interface FillOrderState { export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { private validator: SchemaValidator; - private static formatCurrencyAmount(amount: BigNumber, decimals: number): number { - const unitAmount = ZeroEx.toUnitAmount(amount, decimals); - const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000; - return roundedUnitAmount; - } - private static renderFillSuccessMsg() { - return ( - <div> - Order successfully filled. See the trade details in your{' '} - <Link - to={`${WebsitePaths.Portal}/trades`} - style={{color: 'white'}} - > - trade history - </Link> - </div> - ); - } - private static renderCancelSuccessMsg() { - return ( - <div> - Order successfully cancelled. - </div> - ); - } constructor(props: FillOrderProps) { super(props); this.state = { @@ -244,7 +219,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { let orderReceiveAmount = 0; if (!_.isUndefined(this.props.orderFillAmount)) { const orderReceiveAmountBigNumber = exchangeRate.mul(this.props.orderFillAmount); - orderReceiveAmount = FillOrder.formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); + orderReceiveAmount = this.formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); } const isUserMaker = !_.isUndefined(this.state.parsedOrder) && this.state.parsedOrder.maker.address === this.props.userAddress; @@ -324,7 +299,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { {this.state.didCancelOrderSucceed && <Alert type={AlertTypes.SUCCESS} - message={FillOrder.renderCancelSuccessMsg()} + message={this.renderCancelSuccessMsg()} /> } </div> : @@ -341,7 +316,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { {this.state.didFillOrderSucceed && <Alert type={AlertTypes.SUCCESS} - message={FillOrder.renderFillSuccessMsg()} + message={this.renderFillSuccessMsg()} /> } </div> @@ -350,6 +325,26 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { </div> ); } + private renderFillSuccessMsg() { + return ( + <div> + Order successfully filled. See the trade details in your{' '} + <Link + to={`${WebsitePaths.Portal}/trades`} + style={{color: 'white'}} + > + trade history + </Link> + </div> + ); + } + private renderCancelSuccessMsg() { + return ( + <div> + Order successfully cancelled. + </div> + ); + } private onFillOrderClick() { if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) { this.setState({ @@ -568,7 +563,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { await this.props.blockchain.validateFillOrderThrowIfInvalidAsync( signedOrder, takerFillAmount, this.props.userAddress); } catch (err) { - globalErrMsg = Blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); + globalErrMsg = this.props.blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); } } if (!_.isEmpty(globalErrMsg)) { @@ -657,7 +652,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { await this.props.blockchain.validateCancelOrderThrowIfInvalidAsync( signedOrder, availableTakerTokenAmount); } catch (err) { - globalErrMsg = Blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); + globalErrMsg = this.props.blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); } if (!_.isEmpty(globalErrMsg)) { this.setState({ @@ -694,6 +689,11 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { return; } } + private formatCurrencyAmount(amount: BigNumber, decimals: number): number { + const unitAmount = ZeroEx.toUnitAmount(amount, decimals); + const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000; + return roundedUnitAmount; + } private onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) { if (!didConfirmTokenTracking) { this.setState({ @@ -711,4 +711,4 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { tokensToTrack: [], }); } -} // tslint:disable:max-file-line-count +} diff --git a/packages/website/ts/globals.d.ts b/packages/website/ts/globals.d.ts index a7f1c1f18..ee449ecfd 100644 --- a/packages/website/ts/globals.d.ts +++ b/packages/website/ts/globals.d.ts @@ -126,7 +126,7 @@ declare function isMobile(): boolean; declare module 'is-mobile' { export = isMobile; } -// tslint:disable:max-classes-per-file + // web3-provider-engine declarations declare class Subprovider {} declare module 'web3-provider-engine/subproviders/subprovider' { @@ -148,9 +148,7 @@ declare module 'web3-provider-engine/subproviders/hooked-wallet' { declare interface Artifact { abi: any; - networks: { - [networkId: number]: { - address: string; - }; - }; + networks: {[networkId: number]: { + address: string; + }}; } diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index c1dcb35c5..2d0103499 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -1,5 +1,5 @@ -import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; +import BigNumber from 'bignumber.js'; // Utility function to create a K:V from a list of strings // Adapted from: https://basarat.gitbooks.io/typescript/content/docs/types/literal-types.html @@ -16,7 +16,7 @@ export enum GenerateOrderSteps { RemainingConfigs, SignTransaction, CopyAndShare, -} +}; export const Side = strEnum([ 'receive', @@ -45,11 +45,11 @@ export interface Token { decimals: number; isTracked: boolean; isRegistered: boolean; -} +}; export interface TokenByAddress { [address: string]: Token; -} +}; export interface TokenState { allowance: BigNumber; @@ -58,7 +58,7 @@ export interface TokenState { export interface TokenStateByAddress { [address: string]: TokenState; -} +}; export interface AssetToken { address?: string; @@ -67,14 +67,14 @@ export interface AssetToken { export interface SideToAssetToken { [side: string]: AssetToken; -} +}; export interface SignatureData { hash: string; r: string; s: string; v: number; -} +}; export interface HashData { depositAmount: BigNumber; @@ -138,7 +138,7 @@ export enum BalanceErrs { wethConversionFailed, sendFailed, allowanceSettingFailed, -} +}; export const ActionTypes = strEnum([ // Portal @@ -566,7 +566,7 @@ export interface TxParams { export interface PublicNodeUrlsByNetworkId { [networkId: number]: string[]; -} +}; export interface JSONRPCPayload { params: any[]; @@ -690,4 +690,3 @@ export enum WebsitePaths { Whitepaper = '/pdfs/0x_white_paper.pdf', SmartContracts = '/docs/contracts', } -// tslint:disable:max-file-line-count diff --git a/packages/website/ts/web3_wrapper.ts b/packages/website/ts/web3_wrapper.ts index c43436c7e..24279f5d2 100644 --- a/packages/website/ts/web3_wrapper.ts +++ b/packages/website/ts/web3_wrapper.ts @@ -1,8 +1,8 @@ +import * as _ from 'lodash'; +import Web3 = require('web3'); import BigNumber from 'bignumber.js'; import promisify = require('es6-promisify'); -import * as _ from 'lodash'; import {Dispatcher} from 'ts/redux/dispatcher'; -import Web3 = require('web3'); export class Web3Wrapper { private dispatcher: Dispatcher; @@ -21,7 +21,6 @@ export class Web3Wrapper { this.web3 = new Web3(); this.web3.setProvider(provider); - // tslint:disable-next-line:no-floating-promises this.startEmittingNetworkConnectionAndUserBalanceStateAsync(); } public isAddress(address: string) { @@ -36,7 +35,7 @@ export class Web3Wrapper { if (_.isEmpty(addresses)) { return ''; } - return (addresses)[0]; + return (addresses as string[])[0]; } public async getNodeVersionAsync() { const nodeVersion = await promisify(this.web3.version.getNode)(); |