aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/components/generate_order
diff options
context:
space:
mode:
authorHsuan Lee <boczeratul@gmail.com>2019-03-06 17:46:50 +0800
committerHsuan Lee <boczeratul@gmail.com>2019-03-06 17:46:50 +0800
commit35703539d0f2b4ddb3b11d0de8c9634af59ab71f (patch)
treeae3731221dbbb3a6fa40060a8d916cfd3f738289 /packages/website/ts/components/generate_order
parent92a1fde5b1ecd81b07cdb5bf0c9c1cd3544799db (diff)
downloaddexon-0x-contracts-stable.tar.gz
dexon-0x-contracts-stable.tar.zst
dexon-0x-contracts-stable.zip
Deploy @dexon-foundation/0x.jsstable
Diffstat (limited to 'packages/website/ts/components/generate_order')
-rw-r--r--packages/website/ts/components/generate_order/asset_picker.tsx284
-rw-r--r--packages/website/ts/components/generate_order/generate_order_form.tsx385
-rw-r--r--packages/website/ts/components/generate_order/new_token_form.tsx229
3 files changed, 0 insertions, 898 deletions
diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx
deleted file mode 100644
index d3f11f962..000000000
--- a/packages/website/ts/components/generate_order/asset_picker.tsx
+++ /dev/null
@@ -1,284 +0,0 @@
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import FlatButton from 'material-ui/FlatButton';
-import * as moment from 'moment';
-import * as React from 'react';
-import firstBy from 'thenby';
-
-import { Blockchain } from 'ts/blockchain';
-import { NewTokenForm } from 'ts/components/generate_order/new_token_form';
-import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation';
-import { TokenIcon } from 'ts/components/ui/token_icon';
-import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { DialogConfigs, Token, TokenByAddress, TokenVisibility } from 'ts/types';
-import { constants } from 'ts/utils/constants';
-import { utils } from 'ts/utils/utils';
-
-const TOKEN_ICON_DIMENSION = 100;
-const TILE_DIMENSION = 146;
-enum AssetViews {
- AssetPicker = 'ASSET_PICKER',
- NewTokenForm = 'NEW_TOKEN_FORM',
- ConfirmTrackToken = 'CONFIRM_TRACK_TOKEN',
-}
-
-interface AssetPickerProps {
- userAddress: string;
- blockchain: Blockchain;
- dispatcher: Dispatcher;
- networkId: number;
- isOpen: boolean;
- currentTokenAddress: string;
- onTokenChosen: (tokenAddress: string) => void;
- tokenByAddress: TokenByAddress;
- tokenVisibility?: TokenVisibility;
-}
-
-interface AssetPickerState {
- assetView: AssetViews;
- hoveredAddress: string | undefined;
- chosenTrackTokenAddress: string;
- isAddingTokenToTracked: boolean;
-}
-
-export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerState> {
- public static defaultProps: Partial<AssetPickerProps> = {
- tokenVisibility: TokenVisibility.All,
- };
- private readonly _dialogConfigsByAssetView: { [assetView: string]: DialogConfigs };
- constructor(props: AssetPickerProps) {
- super(props);
- this.state = {
- assetView: AssetViews.AssetPicker,
- hoveredAddress: undefined,
- chosenTrackTokenAddress: undefined,
- isAddingTokenToTracked: false,
- };
- this._dialogConfigsByAssetView = {
- [AssetViews.AssetPicker]: {
- title: 'Select token',
- isModal: false,
- actions: [],
- },
- [AssetViews.NewTokenForm]: {
- title: 'Add an ERC20 token',
- isModal: false,
- actions: [],
- },
- [AssetViews.ConfirmTrackToken]: {
- title: 'Tracking confirmation',
- isModal: true,
- actions: [
- <FlatButton
- key="noTracking"
- label="No"
- onClick={this._onTrackConfirmationRespondedAsync.bind(this, false)}
- />,
- <FlatButton
- key="yesTrack"
- label="Yes"
- onClick={this._onTrackConfirmationRespondedAsync.bind(this, true)}
- />,
- ],
- },
- };
- }
- public render(): React.ReactNode {
- const dialogConfigs: DialogConfigs = this._dialogConfigsByAssetView[this.state.assetView];
- return (
- <Dialog
- title={dialogConfigs.title}
- modal={dialogConfigs.isModal}
- open={this.props.isOpen}
- actions={dialogConfigs.actions}
- autoScrollBodyContent={true}
- onRequestClose={this._onCloseDialog.bind(this)}
- >
- {this.state.assetView === AssetViews.AssetPicker && this._renderAssetPicker()}
- {this.state.assetView === AssetViews.NewTokenForm && (
- <NewTokenForm
- blockchain={this.props.blockchain}
- onNewTokenSubmitted={this._onNewTokenSubmitted.bind(this)}
- tokenByAddress={this.props.tokenByAddress}
- />
- )}
- {this.state.assetView === AssetViews.ConfirmTrackToken && this._renderConfirmTrackToken()}
- </Dialog>
- );
- }
- private _renderConfirmTrackToken(): React.ReactNode {
- const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress];
- return (
- <TrackTokenConfirmation
- tokens={[token]}
- tokenByAddress={this.props.tokenByAddress}
- networkId={this.props.networkId}
- isAddingTokenToTracked={this.state.isAddingTokenToTracked}
- />
- );
- }
- private _renderAssetPicker(): React.ReactNode {
- return (
- <div
- className="flex flex-wrap"
- style={{
- maxWidth: 1000,
- maxHeight: 600,
- marginBottom: 10,
- }}
- >
- {this._renderGridTiles()}
- </div>
- );
- }
- private _renderGridTiles(): React.ReactNode {
- let isHovered;
- let tileStyles;
- const allTokens = _.values(this.props.tokenByAddress);
- // filter tokens based on visibility specified in props, do not show ZRX or ETHER as tracked or untracked
- const filteredTokens =
- this.props.tokenVisibility === TokenVisibility.All
- ? allTokens
- : _.filter(allTokens, token => {
- return (
- token.symbol !== constants.ZRX_TOKEN_SYMBOL &&
- token.symbol !== constants.ETHER_TOKEN_SYMBOL &&
- ((this.props.tokenVisibility === TokenVisibility.Tracked && utils.isTokenTracked(token)) ||
- (this.props.tokenVisibility === TokenVisibility.Untracked &&
- !utils.isTokenTracked(token)))
- );
- });
- // if we are showing tracked tokens, sort by date added, otherwise sort by symbol
- const sortKey = this.props.tokenVisibility === TokenVisibility.Tracked ? 'trackedTimestamp' : 'symbol';
- const sortedTokens = filteredTokens.sort(firstBy(sortKey));
- if (_.isEmpty(sortedTokens)) {
- return <div className="mx-auto p4 h2">No tokens to remove.</div>;
- }
- const gridTiles = _.map(sortedTokens, token => {
- const address = token.address;
- isHovered = this.state.hoveredAddress === address;
- tileStyles = {
- cursor: 'pointer',
- opacity: isHovered ? 0.6 : 1,
- };
- return (
- <div
- key={address}
- style={{
- width: TILE_DIMENSION,
- height: TILE_DIMENSION,
- ...tileStyles,
- }}
- className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto"
- onClick={this._onChooseToken.bind(this, address)}
- onMouseEnter={this._onToggleHover.bind(this, address, true)}
- onMouseLeave={this._onToggleHover.bind(this, address, false)}
- >
- <div className="p1">
- <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} />
- </div>
- <div className="center">{token.symbol}</div>
- </div>
- );
- });
- const otherTokenKey = 'otherToken';
- isHovered = this.state.hoveredAddress === otherTokenKey;
- tileStyles = {
- cursor: 'pointer',
- opacity: isHovered ? 0.6 : 1,
- };
- if (this.props.tokenVisibility !== TokenVisibility.Tracked) {
- gridTiles.push(
- <div
- key={otherTokenKey}
- style={{
- width: TILE_DIMENSION,
- height: TILE_DIMENSION,
- ...tileStyles,
- }}
- className="p2 flex sm-col-6 md-col-3 lg-col-3 flex-column items-center mx-auto"
- onClick={this._onCustomAssetChosen.bind(this)}
- onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)}
- onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)}
- >
- <div className="p1 center">
- <i
- style={{ fontSize: 105, paddingLeft: 1, paddingRight: 1 }}
- className="zmdi zmdi-plus-circle"
- />
- </div>
- <div className="center">Other ERC20 Token</div>
- </div>,
- );
- }
- return gridTiles;
- }
- private _onToggleHover(address: string, isHovered: boolean): void {
- const hoveredAddress = isHovered ? address : undefined;
- this.setState({
- hoveredAddress,
- });
- }
- private _onCloseDialog(): void {
- this.setState({
- assetView: AssetViews.AssetPicker,
- });
- this.props.onTokenChosen(this.props.currentTokenAddress);
- }
- private _onChooseToken(tokenAddress: string): void {
- const token = this.props.tokenByAddress[tokenAddress];
- if (utils.isTokenTracked(token)) {
- this.props.onTokenChosen(tokenAddress);
- } else {
- this.setState({
- assetView: AssetViews.ConfirmTrackToken,
- chosenTrackTokenAddress: tokenAddress,
- });
- }
- }
- private _onCustomAssetChosen(): void {
- this.setState({
- assetView: AssetViews.NewTokenForm,
- });
- }
- private _onNewTokenSubmitted(newToken: Token): void {
- trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newToken);
- this.props.dispatcher.addTokenToTokenByAddress(newToken);
- this.setState({
- assetView: AssetViews.AssetPicker,
- });
- this.props.onTokenChosen(newToken.address);
- }
- private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean): Promise<void> {
- const resetState: AssetPickerState = {
- ...this.state,
- isAddingTokenToTracked: false,
- assetView: AssetViews.AssetPicker,
- chosenTrackTokenAddress: undefined,
- };
- if (!didUserAcceptTracking) {
- this.setState(resetState);
- this._onCloseDialog();
- return;
- }
- this.setState({
- isAddingTokenToTracked: true,
- });
- const tokenAddress = this.state.chosenTrackTokenAddress;
- const token = this.props.tokenByAddress[tokenAddress];
- if (_.isUndefined(tokenAddress)) {
- this.setState(resetState);
- return;
- }
- const newTokenEntry = {
- ...token,
- trackedTimestamp: moment().unix(),
- };
- trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry);
-
- this.props.dispatcher.updateTokenByAddress([newTokenEntry]);
- this.setState(resetState);
- this.props.onTokenChosen(tokenAddress);
- }
-}
diff --git a/packages/website/ts/components/generate_order/generate_order_form.tsx b/packages/website/ts/components/generate_order/generate_order_form.tsx
deleted file mode 100644
index 0f70aa18f..000000000
--- a/packages/website/ts/components/generate_order/generate_order_form.tsx
+++ /dev/null
@@ -1,385 +0,0 @@
-import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils';
-import { colors } from '@0x/react-shared';
-import { Order as ZeroExOrder } from '@0x/types';
-import { BigNumber, logUtils } from '@0x/utils';
-import * as _ from 'lodash';
-import Dialog from 'material-ui/Dialog';
-import Divider from 'material-ui/Divider';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { ExpirationInput } from 'ts/components/inputs/expiration_input';
-import { HashInput } from 'ts/components/inputs/hash_input';
-import { IdenticonAddressInput } from 'ts/components/inputs/identicon_address_input';
-import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
-import { TokenInput } from 'ts/components/inputs/token_input';
-import { OrderJSON } from 'ts/components/order_json';
-import { Alert } from 'ts/components/ui/alert';
-import { HelpTooltip } from 'ts/components/ui/help_tooltip';
-import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
-import { SwapIcon } from 'ts/components/ui/swap_icon';
-import { Dispatcher } from 'ts/redux/dispatcher';
-import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
-import { validator } from 'ts/schemas/validator';
-import {
- AlertTypes,
- BlockchainErrs,
- HashData,
- PortalOrder,
- Side,
- SideToAssetToken,
- Token,
- TokenByAddress,
-} from 'ts/types';
-import { analytics } from 'ts/utils/analytics';
-import { constants } from 'ts/utils/constants';
-import { errorReporter } from 'ts/utils/error_reporter';
-import { utils } from 'ts/utils/utils';
-
-enum SigningState {
- Unsigned,
- Signing,
- Signed,
-}
-
-interface GenerateOrderFormProps {
- blockchain: Blockchain;
- blockchainErr: BlockchainErrs;
- blockchainIsLoaded: boolean;
- dispatcher: Dispatcher;
- hashData: HashData;
- orderExpiryTimestamp: BigNumber;
- networkId: number;
- userAddress: string;
- orderSignature: string;
- orderTakerAddress: string;
- orderSalt: BigNumber;
- sideToAssetToken: SideToAssetToken;
- tokenByAddress: TokenByAddress;
- lastForceTokenStateRefetch: number;
- isFullWidth?: boolean;
- shouldHideHeader?: boolean;
-}
-
-interface GenerateOrderFormState {
- globalErrMsg: string;
- shouldShowIncompleteErrs: boolean;
- signingState: SigningState;
-}
-
-export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> {
- public static defaultProps: Partial<GenerateOrderFormProps> = {
- isFullWidth: false,
- shouldHideHeader: false,
- };
- constructor(props: GenerateOrderFormProps) {
- super(props);
- this.state = {
- globalErrMsg: '',
- shouldShowIncompleteErrs: false,
- signingState: SigningState.Unsigned,
- };
- }
- public componentDidMount(): void {
- window.scrollTo(0, 0);
- }
- public render(): React.ReactNode {
- const dispatcher = this.props.dispatcher;
- const depositTokenAddress = this.props.sideToAssetToken[Side.Deposit].address;
- const depositToken = this.props.tokenByAddress[depositTokenAddress];
- const receiveTokenAddress = this.props.sideToAssetToken[Side.Receive].address;
- const receiveToken = this.props.tokenByAddress[receiveTokenAddress];
- const takerExplanation =
- 'If a taker is specified, only they are<br> \
- allowed to fill this order. If no taker is<br> \
- specified, anyone is able to fill it.';
- const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists();
- const initialTakerAddress =
- this.props.orderTakerAddress === constants.NULL_ADDRESS ? '' : this.props.orderTakerAddress;
- const rootClassName = this.props.isFullWidth ? 'clearfix mb2' : 'clearfix mb2 lg-px4 md-px4 sm-px2';
- return (
- <div className={rootClassName}>
- {!this.props.shouldHideHeader && (
- <div>
- <h3>Generate an order</h3>
- <Divider />
- </div>
- )}
- <div className="mx-auto" style={{ maxWidth: 580 }}>
- <div className="pt3">
- <div className="mx-auto clearfix">
- <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2">
- <TokenInput
- userAddress={this.props.userAddress}
- blockchain={this.props.blockchain}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- label="Selling"
- side={Side.Deposit}
- networkId={this.props.networkId}
- assetToken={this.props.sideToAssetToken[Side.Deposit]}
- updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)}
- tokenByAddress={this.props.tokenByAddress}
- />
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- label="Sell amount"
- token={depositToken}
- amount={this.props.sideToAssetToken[Side.Deposit].amount}
- onChange={this._onTokenAmountChange.bind(this, depositToken, Side.Deposit)}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={true}
- shouldCheckAllowance={true}
- />
- </div>
- <div className="lg-col md-col lg-col-2 md-col-2 sm-col sm-col-2 xs-hide">
- <div className="p1">
- <SwapIcon swapTokensFn={dispatcher.swapAssetTokenSymbols.bind(dispatcher)} />
- </div>
- </div>
- <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2">
- <TokenInput
- userAddress={this.props.userAddress}
- blockchain={this.props.blockchain}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- label="Buying"
- side={Side.Receive}
- networkId={this.props.networkId}
- assetToken={this.props.sideToAssetToken[Side.Receive]}
- updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)}
- tokenByAddress={this.props.tokenByAddress}
- />
- <TokenAmountInput
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- blockchain={this.props.blockchain}
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- label="Receive amount"
- token={receiveToken}
- amount={this.props.sideToAssetToken[Side.Receive].amount}
- onChange={this._onTokenAmountChange.bind(this, receiveToken, Side.Receive)}
- shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs}
- shouldCheckBalance={false}
- shouldCheckAllowance={false}
- />
- </div>
- </div>
- </div>
- <div className="pt1 sm-pb2 lg-px4 md-px4">
- <div className="lg-px3 md-px3">
- <div style={{ fontSize: 12, color: colors.grey }}>Expiration</div>
- <ExpirationInput
- orderExpiryTimestamp={this.props.orderExpiryTimestamp}
- updateOrderExpiry={dispatcher.updateOrderExpiry.bind(dispatcher)}
- />
- </div>
- </div>
- <div className="pt1 flex mx-auto">
- <IdenticonAddressInput
- label="Taker"
- initialAddress={initialTakerAddress}
- updateOrderAddress={this._updateOrderAddress.bind(this)}
- />
- <div className="pt3">
- <div className="pl1">
- <HelpTooltip explanation={takerExplanation} />
- </div>
- </div>
- </div>
- <div>
- <HashInput
- blockchain={this.props.blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- hashData={this.props.hashData}
- label="Order Hash"
- />
- </div>
- <div className="pt2">
- <div className="center">
- <LifeCycleRaisedButton
- labelReady="Sign hash"
- labelLoading="Signing..."
- labelComplete="Hash signed!"
- onClickAsyncFn={this._onSignClickedAsync.bind(this)}
- />
- </div>
- {this.state.globalErrMsg !== '' && (
- <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} />
- )}
- </div>
- </div>
- <Dialog
- title="Order JSON"
- titleStyle={{ fontWeight: 100 }}
- modal={false}
- open={this.state.signingState === SigningState.Signed}
- onRequestClose={this._onCloseOrderJSONDialog.bind(this)}
- >
- <OrderJSON
- exchangeContractIfExists={exchangeContractIfExists}
- orderExpiryTimestamp={this.props.orderExpiryTimestamp}
- orderSignature={this.props.orderSignature}
- orderTakerAddress={this.props.orderTakerAddress}
- orderMakerAddress={this.props.userAddress}
- orderSalt={this.props.orderSalt}
- orderMakerFee={this.props.hashData.makerFee}
- orderTakerFee={this.props.hashData.takerFee}
- orderFeeRecipient={this.props.hashData.feeRecipientAddress}
- sideToAssetToken={this.props.sideToAssetToken}
- tokenByAddress={this.props.tokenByAddress}
- />
- </Dialog>
- </div>
- );
- }
- private _onTokenAmountChange(token: Token, side: Side, _isValid: boolean, amount?: BigNumber): void {
- this.props.dispatcher.updateChosenAssetToken(side, {
- address: token.address,
- amount,
- });
- }
- private _onCloseOrderJSONDialog(): void {
- // Upon closing the order JSON dialog, we update the orderSalt stored in the Redux store
- // with a new value so that if a user signs the identical order again, the newly signed
- // orderHash will not collide with the previously generated orderHash.
- this.props.dispatcher.updateOrderSalt(generatePseudoRandomSalt());
- this.setState({
- signingState: SigningState.Unsigned,
- });
- }
- private async _onSignClickedAsync(): Promise<boolean> {
- if (this.props.blockchainErr !== BlockchainErrs.NoError) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- return false;
- }
-
- // Check if all required inputs were supplied
- 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(
- userAddressIfExists,
- debitToken.address,
- );
- const receiveToken = this.props.sideToAssetToken[Side.Receive];
- const receiveAmount = receiveToken.amount;
- if (
- !_.isUndefined(debitToken.amount) &&
- !_.isUndefined(receiveAmount) &&
- debitToken.amount.gt(0) &&
- receiveAmount.gt(0) &&
- this.props.userAddress !== '' &&
- debitBalance.gte(debitToken.amount) &&
- debitAllowance.gte(debitToken.amount)
- ) {
- const signedOrder = await this._signTransactionAsync();
- const doesSignedOrderExist = !_.isUndefined(signedOrder);
- if (doesSignedOrderExist) {
- analytics.trackOrderEvent('Sign Order Success', signedOrder);
- this.setState({
- globalErrMsg: '',
- shouldShowIncompleteErrs: false,
- });
- }
- return doesSignedOrderExist;
- } else {
- let globalErrMsg = 'You must fix the above errors in order to generate a valid order';
- if (this.props.userAddress === '') {
- globalErrMsg = 'You must enable wallet communication';
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- }
- analytics.track('Sign Order Failure', {
- makerTokenAmount: debitToken.amount.toString(),
- makerToken: this.props.tokenByAddress[debitToken.address].symbol,
- takerTokenAmount: receiveToken.amount.toString(),
- takerToken: this.props.tokenByAddress[receiveToken.address].symbol,
- });
- this.setState({
- globalErrMsg,
- shouldShowIncompleteErrs: true,
- });
- return false;
- }
- }
- private async _signTransactionAsync(): Promise<PortalOrder | undefined> {
- this.setState({
- signingState: SigningState.Signing,
- });
- const exchangeAddress = this.props.blockchain.getExchangeContractAddressIfExists();
- if (_.isUndefined(exchangeAddress)) {
- this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true);
- this.setState({
- signingState: SigningState.Unsigned,
- });
- return undefined;
- }
- const hashData = this.props.hashData;
-
- const makerAssetData = assetDataUtils.encodeERC20AssetData(hashData.depositTokenContractAddr);
- const takerAssetData = assetDataUtils.encodeERC20AssetData(hashData.receiveTokenContractAddr);
- const zeroExOrder: ZeroExOrder = {
- senderAddress: constants.NULL_ADDRESS,
- exchangeAddress,
- expirationTimeSeconds: hashData.orderExpiryTimestamp,
- feeRecipientAddress: hashData.feeRecipientAddress,
- makerAddress: hashData.orderMakerAddress,
- makerFee: hashData.makerFee,
- makerAssetData,
- makerAssetAmount: hashData.depositAmount,
- salt: hashData.orderSalt,
- takerAddress: hashData.orderTakerAddress,
- takerFee: hashData.takerFee,
- takerAssetData,
- takerAssetAmount: hashData.receiveAmount,
- };
- const orderHash = orderHashUtils.getOrderHashHex(zeroExOrder);
-
- let globalErrMsg = '';
- let order;
- try {
- const signature = await this.props.blockchain.signOrderHashAsync(orderHash);
- order = utils.generateOrder(
- exchangeAddress,
- this.props.sideToAssetToken,
- hashData.orderExpiryTimestamp,
- this.props.orderTakerAddress,
- this.props.userAddress,
- hashData.makerFee,
- hashData.takerFee,
- hashData.feeRecipientAddress,
- signature,
- this.props.tokenByAddress,
- hashData.orderSalt,
- );
- const validationResult = validator.validate(order, portalOrderSchema);
- if (validationResult.errors.length > 0) {
- globalErrMsg = 'Order signing failed. Please refresh and try again';
- logUtils.log(`Unexpected error occured: Order validation failed:
- ${validationResult.errors}`);
- }
- } catch (err) {
- const errMsg = `${err}`;
- if (utils.didUserDenyWeb3Request(errMsg)) {
- globalErrMsg = 'User denied sign request';
- } else {
- globalErrMsg = 'An unexpected error occured. Please try refreshing the page';
- logUtils.log(`Unexpected error occured: ${err}`);
- logUtils.log(err.stack);
- errorReporter.report(err);
- }
- }
- this.setState({
- signingState: globalErrMsg === '' ? SigningState.Signed : SigningState.Unsigned,
- globalErrMsg,
- });
- return order;
- }
- private _updateOrderAddress(address?: string): void {
- if (!_.isUndefined(address)) {
- const normalizedAddress = _.isEmpty(address) ? constants.NULL_ADDRESS : address;
- this.props.dispatcher.updateOrderTakerAddress(normalizedAddress);
- }
- }
-}
diff --git a/packages/website/ts/components/generate_order/new_token_form.tsx b/packages/website/ts/components/generate_order/new_token_form.tsx
deleted file mode 100644
index ce684d177..000000000
--- a/packages/website/ts/components/generate_order/new_token_form.tsx
+++ /dev/null
@@ -1,229 +0,0 @@
-import { colors } from '@0x/react-shared';
-import * as _ from 'lodash';
-import TextField from 'material-ui/TextField';
-import * as moment from 'moment';
-import * as React from 'react';
-import { Blockchain } from 'ts/blockchain';
-import { AddressInput } from 'ts/components/inputs/address_input';
-import { Alert } from 'ts/components/ui/alert';
-import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button';
-import { RequiredLabel } from 'ts/components/ui/required_label';
-import { AlertTypes, Token, TokenByAddress } from 'ts/types';
-
-interface NewTokenFormProps {
- blockchain: Blockchain;
- tokenByAddress: TokenByAddress;
- onNewTokenSubmitted: (token: Token) => void;
-}
-
-interface NewTokenFormState {
- globalErrMsg: string;
- name: string;
- nameErrText: string;
- symbol: string;
- symbolErrText: string;
- address: string;
- shouldShowAddressIncompleteErr: boolean;
- decimals: string;
- decimalsErrText: string;
-}
-
-export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFormState> {
- constructor(props: NewTokenFormProps) {
- super(props);
- this.state = {
- address: '',
- globalErrMsg: '',
- name: '',
- nameErrText: '',
- shouldShowAddressIncompleteErr: false,
- symbol: '',
- symbolErrText: '',
- decimals: '18',
- decimalsErrText: '',
- };
- }
- public render(): React.ReactNode {
- return (
- <div className="mx-auto pb2" style={{ width: 256 }}>
- <div>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText={<RequiredLabel label="Name" />}
- value={this.state.name}
- errorText={this.state.nameErrText}
- onChange={this._onTokenNameChanged.bind(this)}
- />
- </div>
- <div>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText={<RequiredLabel label="Symbol" />}
- value={this.state.symbol}
- errorText={this.state.symbolErrText}
- onChange={this._onTokenSymbolChanged.bind(this)}
- />
- </div>
- <div>
- <AddressInput
- isRequired={true}
- label="Contract address"
- initialAddress=""
- shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr}
- updateAddress={this._onTokenAddressChanged.bind(this)}
- />
- </div>
- <div>
- <TextField
- floatingLabelFixed={true}
- floatingLabelStyle={{ color: colors.grey }}
- floatingLabelText={<RequiredLabel label="Decimals" />}
- value={this.state.decimals}
- errorText={this.state.decimalsErrText}
- onChange={this._onTokenDecimalsChanged.bind(this)}
- />
- </div>
- <div className="pt2 mx-auto" style={{ width: 120 }}>
- <LifeCycleRaisedButton
- labelReady="Add"
- labelLoading="Adding..."
- labelComplete="Added!"
- onClickAsyncFn={this._onAddNewTokenClickAsync.bind(this)}
- />
- </div>
- {this.state.globalErrMsg !== '' && <Alert type={AlertTypes.Error} message={this.state.globalErrMsg} />}
- </div>
- );
- }
- private async _onAddNewTokenClickAsync(): Promise<void> {
- // Trigger validation of name and symbol
- this._onTokenNameChanged(undefined, this.state.name);
- this._onTokenSymbolChanged(undefined, this.state.symbol);
- this._onTokenDecimalsChanged(undefined, this.state.decimals);
-
- const isAddressIncomplete = this.state.address === '';
- let doesContractExist = false;
- if (!isAddressIncomplete) {
- doesContractExist = await this.props.blockchain.doesContractExistAtAddressAsync(this.state.address);
- }
-
- let hasBalanceAllowanceErr = false;
- if (doesContractExist) {
- try {
- await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync(this.state.address);
- } catch (err) {
- hasBalanceAllowanceErr = true;
- }
- }
-
- let globalErrMsg = '';
- if (
- this.state.nameErrText !== '' ||
- this.state.symbolErrText !== '' ||
- this.state.decimalsErrText !== '' ||
- isAddressIncomplete
- ) {
- globalErrMsg = 'Please fix the above issues';
- } else if (!doesContractExist) {
- globalErrMsg = 'No contract found at supplied address';
- } else if (hasBalanceAllowanceErr) {
- globalErrMsg = 'Unsuccessful call to `balanceOf` and/or `allowance` on supplied contract address';
- } else if (!isAddressIncomplete && !_.isUndefined(this.props.tokenByAddress[this.state.address])) {
- globalErrMsg = 'A token already exists with this address';
- }
-
- if (globalErrMsg !== '') {
- this.setState({
- globalErrMsg,
- shouldShowAddressIncompleteErr: isAddressIncomplete,
- });
- return;
- }
-
- const newToken: Token = {
- address: this.state.address,
- decimals: _.parseInt(this.state.decimals),
- iconUrl: undefined,
- name: this.state.name,
- symbol: this.state.symbol.toUpperCase(),
- trackedTimestamp: moment().unix(),
- isRegistered: false,
- };
- this.props.onNewTokenSubmitted(newToken);
- }
- private _onTokenNameChanged(_event: any, name: string): void {
- let nameErrText = '';
- const maxLength = 30;
- const tokens = _.values(this.props.tokenByAddress);
- const tokenWithNameIfExists = _.find(tokens, { name });
- const doesTokenWithNameExists = !_.isUndefined(tokenWithNameIfExists);
- if (name === '') {
- nameErrText = 'Name is required';
- } else if (!this._isValidName(name)) {
- nameErrText = 'Name should only contain letters, digits and spaces';
- } else if (name.length > maxLength) {
- nameErrText = `Max length is ${maxLength}`;
- } else if (doesTokenWithNameExists) {
- nameErrText = 'Token with this name already exists';
- }
-
- this.setState({
- name,
- nameErrText,
- });
- }
- private _onTokenSymbolChanged(_event: any, symbol: string): void {
- let symbolErrText = '';
- const maxLength = 5;
- const tokens = _.values(this.props.tokenByAddress);
- const doesTokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol }));
- if (symbol === '') {
- symbolErrText = 'Symbol is required';
- } else if (!this._isAlphanumeric(symbol)) {
- symbolErrText = 'Can only include alphanumeric characters';
- } else if (symbol.length > maxLength) {
- symbolErrText = `Max length is ${maxLength}`;
- } else if (doesTokenWithSymbolExists) {
- symbolErrText = 'Token with symbol already exists';
- }
-
- this.setState({
- symbol,
- symbolErrText,
- });
- }
- private _onTokenDecimalsChanged(_event: any, decimals: string): void {
- let decimalsErrText = '';
- const maxLength = 2;
- if (decimals === '') {
- decimalsErrText = 'Decimals is required';
- } else if (!this._isInteger(decimals)) {
- decimalsErrText = 'Must be an integer';
- } else if (decimals.length > maxLength) {
- decimalsErrText = `Max length is ${maxLength}`;
- }
-
- this.setState({
- decimals,
- decimalsErrText,
- });
- }
- private _onTokenAddressChanged(address?: string): void {
- if (!_.isUndefined(address)) {
- this.setState({
- address,
- });
- }
- }
- private _isValidName(input: string): boolean {
- return /^[a-z0-9 ]+$/i.test(input);
- }
- private _isInteger(input: string): boolean {
- return /^[0-9]+$/i.test(input);
- }
- private _isAlphanumeric(input: string): boolean {
- return /^[a-zA-Z0-9]+$/i.test(input);
- }
-}