diff options
Diffstat (limited to 'packages')
-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, 249 insertions, 233 deletions
diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 87194d362..9d207a923 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 f91b579bd..f9951defb 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -3,6 +3,7 @@ "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 b13c48a65..7851ea8ff 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -1,59 +1,60 @@ -import * as _ from 'lodash'; -import * as React from 'react'; import { - ZeroEx, - ZeroExError, + BlockParam, + DecodedLogEvent, ExchangeContractErrs, ExchangeContractEventArgs, ExchangeEvents, - SubscriptionOpts, IndexedFilterValues, - DecodedLogEvent, - BlockParam, - LogFillContractEventArgs, LogCancelContractEventArgs, - Token as ZeroExToken, + LogFillContractEventArgs, LogWithDecodedArgs, - TransactionReceiptWithDecodedLogs, - SignedOrder, Order, + SignedOrder, + SubscriptionOpts, + Token as ZeroExToken, + TransactionReceiptWithDecodedLogs, + ZeroEx, + ZeroExError, } from '0x.js'; import BigNumber from 'bignumber.js'; -import Web3 = require('web3'); +import compareVersions = require('compare-versions'); import promisify = require('es6-promisify'); +import ethUtil = require('ethereumjs-util'); import findVersions = require('find-versions'); -import compareVersions = require('compare-versions'); +import * as _ from 'lodash'; +import * as React from 'react'; import contract = require('truffle-contract'); -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 {TokenSendCompleted} from 'ts/components/flash_messages/token_send_completed'; -import {RedundantRPCSubprovider} from 'ts/subproviders/redundant_rpc_subprovider'; +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 {InjectedWeb3SubProvider} from 'ts/subproviders/injected_web3_subprovider'; import {ledgerWalletSubproviderFactory} from 'ts/subproviders/ledger_wallet_subprovider_factory'; -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 {RedundantRPCSubprovider} from 'ts/subproviders/redundant_rpc_subprovider'; import { - BlockchainErrs, - Token, - SignatureData, - Side, - ContractResponse, BlockchainCallErrs, + BlockchainErrs, ContractInstance, - ProviderType, - LedgerWalletSubprovider, + ContractResponse, EtherscanLinkSuffixes, + LedgerWalletSubprovider, + ProviderType, + Side, + SignatureData, + Token, TokenByAddress, TokenStateByAddress, } from 'ts/types'; -import {Web3Wrapper} from 'ts/web3_wrapper'; +import {configs} from 'ts/utils/configs'; +import {constants} from 'ts/utils/constants'; 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 {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 * as MintableArtifacts from '../contracts/Mintable.json'; const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 45730; @@ -72,9 +73,116 @@ 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) { @@ -157,8 +265,8 @@ export class Blockchain { this.web3Wrapper.destroy(); const shouldPollUserAddress = false; this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress); - await this.zeroEx.setProviderAsync(provider); - await this.postInstantiationOrUpdatingProviderZeroExAsync(); + this.zeroEx.setProvider(provider, this.networkId); + this.postInstantiationOrUpdatingProviderZeroEx(); break; } @@ -169,8 +277,8 @@ export class Blockchain { provider = this.cachedProvider; const shouldPollUserAddress = true; this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress); - await this.zeroEx.setProviderAsync(provider); - await this.postInstantiationOrUpdatingProviderZeroExAsync(); + this.zeroEx.setProvider(provider, this.networkId); + this.postInstantiationOrUpdatingProviderZeroEx(); delete this.ledgerSubProvider; delete this.cachedProvider; break; @@ -208,7 +316,7 @@ export class Blockchain { amountInBaseUnits, })); } - public portalOrderToSignedOrder(maker: string, taker: string, makerTokenAddress: string, + public portalOrderToSignedOrder(maker: string, takerIfExists: string, makerTokenAddress: string, takerTokenAddress: string, makerTokenAmount: BigNumber, takerTokenAmount: BigNumber, makerFee: BigNumber, takerFee: BigNumber, expirationUnixTimestampSec: BigNumber, @@ -216,7 +324,7 @@ export class Blockchain { signatureData: SignatureData, salt: BigNumber): SignedOrder { const ecSignature = signatureData; const exchangeContractAddress = this.getExchangeContractAddressIfExists(); - taker = _.isEmpty(taker) ? constants.NULL_ADDRESS : taker; + const taker = _.isEmpty(takerIfExists) ? constants.NULL_ADDRESS : takerIfExists; const signedOrder = { ecSignature, exchangeContractAddress, @@ -273,51 +381,6 @@ 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> { @@ -446,6 +509,7 @@ 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( @@ -485,7 +549,7 @@ export class Blockchain { // Start a subscription for new logs const exchangeAddress = this.getExchangeContractAddressIfExists(); - const subscriptionId = await this.zeroEx.exchange.subscribeAsync( + const subscriptionId = this.zeroEx.exchange.subscribe( ExchangeEvents.LogFill, indexFilterValues, async (err: Error, decodedLogEvent: DecodedLogEvent<LogFillContractEventArgs>) => { const decodedLog = decodedLogEvent.log; @@ -493,7 +557,9 @@ 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 { @@ -529,7 +595,7 @@ export class Blockchain { } } private async convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { - const args = decodedLog.args as LogFillContractEventArgs; + const args = decodedLog.args; const blockTimestamp = await this.web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash); const fill = { filledTakerTokenAmount: args.filledTakerTokenAmount, @@ -548,7 +614,7 @@ export class Blockchain { return fill; } private doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { - const args = decodedLog.args as LogFillContractEventArgs; + const args = decodedLog.args; const isUserMakerOrTaker = args.maker === this.userAddress || args.taker === this.userAddress; return isUserMakerOrTaker; @@ -594,7 +660,7 @@ export class Blockchain { return tokenByAddress; } private async onPageLoadInitFireAndForgetAsync() { - await this.onPageLoadAsync(); // wait for page to load + await Blockchain.onPageLoadAsync(); // wait for page to load // Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in // order to properly instantiate the web3Wrapper. Since we must use the async call, we cannot @@ -612,81 +678,34 @@ export class Blockchain { } } - const provider = await this.getProviderAsync(injectedWeb3, networkId); - this.zeroEx = new ZeroEx(provider); - await this.updateProviderName(injectedWeb3); + const provider = await Blockchain.getProviderAsync(injectedWeb3, networkId); + const zeroExConfig = { + networkId: this.networkId, + }; + this.zeroEx = new ZeroEx(provider, zeroExConfig); + this.updateProviderName(injectedWeb3); const shouldPollUserAddress = true; this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, networkId, shouldPollUserAddress); - await this.postInstantiationOrUpdatingProviderZeroExAsync(); + this.postInstantiationOrUpdatingProviderZeroEx(); } // This method should always be run after instantiating or updating the provider // of the ZeroEx instance. - private async postInstantiationOrUpdatingProviderZeroExAsync() { + private postInstantiationOrUpdatingProviderZeroEx(): void { utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - this.exchangeAddress = await this.zeroEx.exchange.getContractAddressAsync(); + this.exchangeAddress = this.zeroEx.exchange.getContractAddress(); } - private updateProviderName(injectedWeb3: Web3) { + private updateProviderName(injectedWeb3: Web3): void { const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3); const providerName = doesInjectedWeb3Exist ? - this.getNameGivenProvider(injectedWeb3.currentProvider) : + Blockchain.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() { + private getBlockchainNetworkId(): number { 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'); @@ -776,12 +795,4 @@ export class Blockchain { } } } - private async onPageLoadAsync() { - if (document.readyState === 'complete') { - return; // Already loaded - } - return new Promise((resolve, reject) => { - window.onload = resolve; - }); - } -} +} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx index dc965283e..4077e4f8b 100644 --- a/packages/website/ts/components/fill_order.tsx +++ b/packages/website/ts/components/fill_order.tsx @@ -1,44 +1,44 @@ -import * as _ from 'lodash'; -import * as React from 'react'; +import {Order as ZeroExOrder, ZeroEx} from '0x.js'; 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 Paper from 'material-ui/Paper'; -import {Card, CardText, CardHeader} from 'material-ui/Card'; +import * as _ from 'lodash'; +import {Card, CardHeader, CardText} from 'material-ui/Card'; import Divider from 'material-ui/Divider'; -import TextField from 'material-ui/TextField'; +import Paper from 'material-ui/Paper'; import RaisedButton from 'material-ui/RaisedButton'; -import {utils} from 'ts/utils/utils'; -import {constants} from 'ts/utils/constants'; +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 { - Side, - TokenByAddress, - TokenStateByAddress, - Order, + AlertTypes, BlockchainErrs, + ContractResponse, + ExchangeContractErrs, + Order, OrderToken, + Side, Token, - ExchangeContractErrs, - AlertTypes, - ContractResponse, + TokenByAddress, + TokenStateByAddress, WebsitePaths, } from 'ts/types'; -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 {constants} from 'ts/utils/constants'; import {errorReporter} from 'ts/utils/error_reporter'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {TrackTokenConfirmationDialog} from 'ts/components/dialogs/track_token_confirmation_dialog'; +import {utils} from 'ts/utils/utils'; const CUSTOM_LIGHT_GRAY = '#BBBBBB'; @@ -76,6 +76,31 @@ 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 = { @@ -219,7 +244,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { let orderReceiveAmount = 0; if (!_.isUndefined(this.props.orderFillAmount)) { const orderReceiveAmountBigNumber = exchangeRate.mul(this.props.orderFillAmount); - orderReceiveAmount = this.formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); + orderReceiveAmount = FillOrder.formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); } const isUserMaker = !_.isUndefined(this.state.parsedOrder) && this.state.parsedOrder.maker.address === this.props.userAddress; @@ -299,7 +324,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { {this.state.didCancelOrderSucceed && <Alert type={AlertTypes.SUCCESS} - message={this.renderCancelSuccessMsg()} + message={FillOrder.renderCancelSuccessMsg()} /> } </div> : @@ -316,7 +341,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { {this.state.didFillOrderSucceed && <Alert type={AlertTypes.SUCCESS} - message={this.renderFillSuccessMsg()} + message={FillOrder.renderFillSuccessMsg()} /> } </div> @@ -325,26 +350,6 @@ 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({ @@ -563,7 +568,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { await this.props.blockchain.validateFillOrderThrowIfInvalidAsync( signedOrder, takerFillAmount, this.props.userAddress); } catch (err) { - globalErrMsg = this.props.blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); + globalErrMsg = Blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); } } if (!_.isEmpty(globalErrMsg)) { @@ -652,7 +657,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { await this.props.blockchain.validateCancelOrderThrowIfInvalidAsync( signedOrder, availableTakerTokenAmount); } catch (err) { - globalErrMsg = this.props.blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); + globalErrMsg = Blockchain.toHumanReadableErrorMsg(err.message, parsedOrder.taker.address); } if (!_.isEmpty(globalErrMsg)) { this.setState({ @@ -689,11 +694,6 @@ 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 ee449ecfd..a7f1c1f18 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,7 +148,9 @@ 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 2d0103499..c1dcb35c5 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -1,5 +1,5 @@ -import * as _ from 'lodash'; import BigNumber from 'bignumber.js'; +import * as _ from 'lodash'; // 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,3 +690,4 @@ 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 24279f5d2..c43436c7e 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,6 +21,7 @@ export class Web3Wrapper { this.web3 = new Web3(); this.web3.setProvider(provider); + // tslint:disable-next-line:no-floating-promises this.startEmittingNetworkConnectionAndUserBalanceStateAsync(); } public isAddress(address: string) { @@ -35,7 +36,7 @@ export class Web3Wrapper { if (_.isEmpty(addresses)) { return ''; } - return (addresses as string[])[0]; + return (addresses)[0]; } public async getNodeVersionAsync() { const nodeVersion = await promisify(this.web3.version.getNode)(); |