From 4b348e1e603ec45e1e4bf39533b4b204423cafa0 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 11:09:23 -0700 Subject: quoteState -> quoteRequestState --- packages/instant/src/components/instant_heading.tsx | 10 +++++----- packages/instant/src/containers/selected_asset_amount_input.ts | 6 +++--- .../instant/src/containers/selected_asset_instant_heading.ts | 4 ++-- packages/instant/src/redux/actions.ts | 4 ++-- packages/instant/src/redux/reducer.ts | 10 +++++----- 5 files changed, 17 insertions(+), 17 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index a36d35a93..9dd13299c 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -13,7 +13,7 @@ export interface InstantHeadingProps { selectedAssetAmount?: BigNumber; totalEthBaseAmount?: BigNumber; ethUsdPrice?: BigNumber; - quoteState: AsyncProcessState; + quoteRequestState: AsyncProcessState; } const Placeholder = () => ( @@ -42,8 +42,8 @@ const displayUsdAmount = ({ return format.ethBaseAmountInUsd(totalEthBaseAmount, ethUsdPrice, 2, ); }; -const loadingOrAmount = (quoteState: AsyncProcessState, amount: React.ReactNode): React.ReactNode => { - if (quoteState === AsyncProcessState.PENDING) { +const loadingOrAmount = (quoteRequestState: AsyncProcessState, amount: React.ReactNode): React.ReactNode => { + if (quoteRequestState === AsyncProcessState.PENDING) { return ( …loading @@ -73,11 +73,11 @@ export const InstantHeading: React.StatelessComponent = pro - {loadingOrAmount(props.quoteState, displaytotalEthBaseAmount(props))} + {loadingOrAmount(props.quoteRequestState, displaytotalEthBaseAmount(props))} - {loadingOrAmount(props.quoteState, displayUsdAmount(props))} + {loadingOrAmount(props.quoteRequestState, displayUsdAmount(props))} diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts index 0810b093a..aca6a09d4 100644 --- a/packages/instant/src/containers/selected_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_asset_amount_input.ts @@ -44,13 +44,13 @@ const updateBuyQuoteAsync = async ( const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, zrxDecimals); // mark quote as pending - dispatch(actions.updateBuyQuoteStatePending()); + dispatch(actions.updateBuyquoteRequestStatePending()); let newBuyQuote: BuyQuote | undefined; try { newBuyQuote = await assetBuyer.getBuyQuoteAsync(assetData, baseUnitValue); } catch (error) { - dispatch(actions.updateBuyQuoteStateFailure()); + dispatch(actions.updateBuyquoteRequestStateFailure()); errorUtil.errorFlasher.flashNewError(dispatch, error); return; } @@ -76,7 +76,7 @@ const mapDispatchToProps = ( if (!_.isUndefined(value) && !_.isUndefined(assetData)) { // even if it's debounced, give them the illusion it's loading - dispatch(actions.updateBuyQuoteStatePending()); + dispatch(actions.updateBuyquoteRequestStatePending()); // tslint:disable-next-line:no-floating-promises debouncedUpdateBuyQuoteAsync(dispatch, assetData, value); } diff --git a/packages/instant/src/containers/selected_asset_instant_heading.ts b/packages/instant/src/containers/selected_asset_instant_heading.ts index 0509db5da..43127582c 100644 --- a/packages/instant/src/containers/selected_asset_instant_heading.ts +++ b/packages/instant/src/containers/selected_asset_instant_heading.ts @@ -15,14 +15,14 @@ interface ConnectedState { selectedAssetAmount?: BigNumber; totalEthBaseAmount?: BigNumber; ethUsdPrice?: BigNumber; - quoteState: AsyncProcessState; + quoteRequestState: AsyncProcessState; } const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): ConnectedState => ({ selectedAssetAmount: state.selectedAssetAmount, totalEthBaseAmount: oc(state).latestBuyQuote.worstCaseQuoteInfo.totalEthAmount(), ethUsdPrice: state.ethUsdPrice, - quoteState: state.quoteState, + quoteRequestState: state.quoteRequestState, }); export const SelectedAssetInstantHeading: React.ComponentClass = connect(mapStateToProps)( diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 9c154c66f..b4aa4f4cb 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -38,8 +38,8 @@ export const actions = { updatebuyOrderState: (buyState: AsyncProcessState) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, buyState), updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote), - updateBuyQuoteStatePending: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING), - updateBuyQuoteStateFailure: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE), + updateBuyquoteRequestStatePending: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING), + updateBuyquoteRequestStateFailure: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE), setError: (error?: any) => createAction(ActionTypes.SET_ERROR, error), hideError: () => createAction(ActionTypes.HIDE_ERROR), clearError: () => createAction(ActionTypes.CLEAR_ERROR), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 05aa37420..d2256ef54 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -17,7 +17,7 @@ export interface State { buyOrderState: AsyncProcessState; ethUsdPrice?: BigNumber; latestBuyQuote?: BuyQuote; - quoteState: AsyncProcessState; + quoteRequestState: AsyncProcessState; latestError?: any; latestErrorDisplay: LatestErrorDisplay; } @@ -31,7 +31,7 @@ export const INITIAL_STATE: State = { latestBuyQuote: undefined, latestError: undefined, latestErrorDisplay: LatestErrorDisplay.Hidden, - quoteState: AsyncProcessState.NONE, + quoteRequestState: AsyncProcessState.NONE, }; export const reducer = (state: State = INITIAL_STATE, action: Action): State => { @@ -50,19 +50,19 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => return { ...state, latestBuyQuote: action.data, - quoteState: AsyncProcessState.SUCCESS, + quoteRequestState: AsyncProcessState.SUCCESS, }; case ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING: return { ...state, latestBuyQuote: undefined, - quoteState: AsyncProcessState.PENDING, + quoteRequestState: AsyncProcessState.PENDING, }; case ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE: return { ...state, latestBuyQuote: undefined, - quoteState: AsyncProcessState.FAILURE, + quoteRequestState: AsyncProcessState.FAILURE, }; case ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE: return { -- cgit From 12b6877aeb0a6bcddab4193b62cd10347b8c328b Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 13:31:11 -0700 Subject: Pulsating holder element showing, even if amount is empty --- .../instant/src/components/amount_placeholder.tsx | 29 ++++++ .../instant/src/components/animations/pulse.tsx | 15 +++ .../instant/src/components/instant_heading.tsx | 112 ++++++++++----------- packages/instant/src/components/ui/container.tsx | 2 + 4 files changed, 101 insertions(+), 57 deletions(-) create mode 100644 packages/instant/src/components/amount_placeholder.tsx create mode 100644 packages/instant/src/components/animations/pulse.tsx (limited to 'packages') diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx new file mode 100644 index 000000000..54639effb --- /dev/null +++ b/packages/instant/src/components/amount_placeholder.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Pulse } from './animations/pulse'; + +import { Text } from './ui'; + +export interface AmountPlaceholderProps { + pulsating: boolean; +} + +const PlainPlaceholder = () => ( + + — + +); + +export const AmountPlaceholder: React.StatelessComponent = props => { + if (props.pulsating) { + return ( + + + + ); + } else { + return ; + } +}; diff --git a/packages/instant/src/components/animations/pulse.tsx b/packages/instant/src/components/animations/pulse.tsx new file mode 100644 index 000000000..01d6ea070 --- /dev/null +++ b/packages/instant/src/components/animations/pulse.tsx @@ -0,0 +1,15 @@ +import { keyframes, styled } from '../../style/theme'; + +const pulsingKeyframes = keyframes` + 0%, 100% { + opacity: 0.2; + } + 50% { + opacity: 100; + } +`; +export const Pulse = styled.div` + animation-name: ${pulsingKeyframes} + animation-duration: 2s; + animation-iteration-count: infinite; +`; diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 9dd13299c..9ca4ce598 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -7,6 +7,7 @@ import { ColorOption } from '../style/theme'; import { AsyncProcessState } from '../types'; import { format } from '../util/format'; +import { AmountPlaceholder } from './amount_placeholder'; import { Container, Flex, Text } from './ui'; export interface InstantHeadingProps { @@ -16,70 +17,67 @@ export interface InstantHeadingProps { quoteRequestState: AsyncProcessState; } -const Placeholder = () => ( - - — - -); -const displaytotalEthBaseAmount = ({ - selectedAssetAmount, - totalEthBaseAmount, -}: InstantHeadingProps): React.ReactNode => { - if (_.isUndefined(selectedAssetAmount)) { - return '0 ETH'; +export class InstantHeading extends React.Component { + public render(): React.ReactNode { + const placeholderAmountToAlwaysShow = this._placeholderAmountToAlwaysShow(); + return ( + + + + I want to buy + + + + + + {placeholderAmountToAlwaysShow || this._ethAmount()} + {placeholderAmountToAlwaysShow || this._dollarAmount()} + + + + ); } - return format.ethBaseAmount(totalEthBaseAmount, 4, ); -}; -const displayUsdAmount = ({ - totalEthBaseAmount, - selectedAssetAmount, - ethUsdPrice, -}: InstantHeadingProps): React.ReactNode => { - if (_.isUndefined(selectedAssetAmount)) { - return '$0.00'; + private _placeholderAmountToAlwaysShow(): React.ReactNode | undefined { + if (this.props.quoteRequestState === AsyncProcessState.PENDING) { + return ; + } + if (_.isUndefined(this.props.selectedAssetAmount)) { + return ; + } + return undefined; } - return format.ethBaseAmountInUsd(totalEthBaseAmount, ethUsdPrice, 2, ); -}; -const loadingOrAmount = (quoteRequestState: AsyncProcessState, amount: React.ReactNode): React.ReactNode => { - if (quoteRequestState === AsyncProcessState.PENDING) { + private _ethAmount(): React.ReactNode { return ( - - …loading + + {format.ethBaseAmount(this.props.totalEthBaseAmount, 4, )} ); - } else { - return amount; } -}; -export const InstantHeading: React.StatelessComponent = props => ( - - - - I want to buy + private _dollarAmount(): React.ReactNode { + return ( + + {format.ethBaseAmountInUsd( + this.props.totalEthBaseAmount, + this.props.ethUsdPrice, + 2, + , + )} - - - - - - - {loadingOrAmount(props.quoteRequestState, displaytotalEthBaseAmount(props))} - - - - {loadingOrAmount(props.quoteRequestState, displayUsdAmount(props))} - - - - -); + ); + } +} diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 02b16e39f..5e2218c68 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -27,6 +27,7 @@ export interface ContainerProps { backgroundColor?: ColorOption; hasBoxShadow?: boolean; zIndex?: number; + opacity?: number; } const PlainContainer: React.StatelessComponent = ({ children, className }) => ( @@ -54,6 +55,7 @@ export const Container = styled(PlainContainer)` ${props => cssRuleIfExists(props, 'border-top')} ${props => cssRuleIfExists(props, 'border-bottom')} ${props => cssRuleIfExists(props, 'z-index')} + ${props => cssRuleIfExists(props, 'opacity')} ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')}; background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; -- cgit From 94ace00e0cfd550bccf33f85441ce1dad33f1348 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 13:38:04 -0700 Subject: fix camel casing of updateBuyOrderState --- packages/instant/src/containers/selected_asset_amount_input.ts | 2 +- packages/instant/src/containers/selected_asset_buy_button.ts | 6 +++--- packages/instant/src/redux/actions.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts index aca6a09d4..2a1e5e457 100644 --- a/packages/instant/src/containers/selected_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_asset_amount_input.ts @@ -72,7 +72,7 @@ const mapDispatchToProps = ( // invalidate the last buy quote. dispatch(actions.updateLatestBuyQuote(undefined)); // reset our buy state - dispatch(actions.updatebuyOrderState(AsyncProcessState.NONE)); + dispatch(actions.updateBuyOrderState(AsyncProcessState.NONE)); if (!_.isUndefined(value) && !_.isUndefined(assetData)) { // even if it's debounced, give them the illusion it's loading diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_button.ts index 4a8e31525..4d3315b1a 100644 --- a/packages/instant/src/containers/selected_asset_buy_button.ts +++ b/packages/instant/src/containers/selected_asset_buy_button.ts @@ -44,9 +44,9 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps): }); const mapDispatchToProps = (dispatch: Dispatch, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({ - onClick: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.PENDING)), - onBuySuccess: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.SUCCESS)), - onBuyFailure: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.FAILURE)), + onClick: buyQuote => dispatch(actions.updateBuyOrderState(AsyncProcessState.PENDING)), + onBuySuccess: buyQuote => dispatch(actions.updateBuyOrderState(AsyncProcessState.SUCCESS)), + onBuyFailure: buyQuote => dispatch(actions.updateBuyOrderState(AsyncProcessState.FAILURE)), }); export const SelectedAssetBuyButton: React.ComponentClass = connect( diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index b4aa4f4cb..016dc29dc 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -35,7 +35,7 @@ export enum ActionTypes { export const actions = { updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price), updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount), - updatebuyOrderState: (buyState: AsyncProcessState) => + updateBuyOrderState: (buyState: AsyncProcessState) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, buyState), updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote), updateBuyquoteRequestStatePending: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING), -- cgit From 9aa67538231cc4ff71fd0f8ebe4dc66b1bcc4937 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 13:42:59 -0700 Subject: Rename update function to set function since it doesnt take a parameter --- packages/instant/src/containers/selected_asset_amount_input.ts | 6 +++--- packages/instant/src/redux/actions.ts | 8 ++++---- packages/instant/src/redux/reducer.ts | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts index 2a1e5e457..e55c8b991 100644 --- a/packages/instant/src/containers/selected_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_asset_amount_input.ts @@ -44,13 +44,13 @@ const updateBuyQuoteAsync = async ( const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, zrxDecimals); // mark quote as pending - dispatch(actions.updateBuyquoteRequestStatePending()); + dispatch(actions.setQuoteRequestStatePending()); let newBuyQuote: BuyQuote | undefined; try { newBuyQuote = await assetBuyer.getBuyQuoteAsync(assetData, baseUnitValue); } catch (error) { - dispatch(actions.updateBuyquoteRequestStateFailure()); + dispatch(actions.setQuoteRequestStateFailure()); errorUtil.errorFlasher.flashNewError(dispatch, error); return; } @@ -76,7 +76,7 @@ const mapDispatchToProps = ( if (!_.isUndefined(value) && !_.isUndefined(assetData)) { // even if it's debounced, give them the illusion it's loading - dispatch(actions.updateBuyquoteRequestStatePending()); + dispatch(actions.setQuoteRequestStatePending()); // tslint:disable-next-line:no-floating-promises debouncedUpdateBuyQuoteAsync(dispatch, assetData, value); } diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 016dc29dc..e52a79e76 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -25,8 +25,8 @@ export enum ActionTypes { UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT', UPDATE_SELECTED_ASSET_BUY_STATE = 'UPDATE_SELECTED_ASSET_BUY_STATE', UPDATE_LATEST_BUY_QUOTE = 'UPDATE_LATEST_BUY_QUOTE', - UPDATE_BUY_QUOTE_STATE_PENDING = 'UPDATE_BUY_QUOTE_STATE_PENDING', - UPDATE_BUY_QUOTE_STATE_FAILURE = 'UPDATE_BUY_QUOTE_STATE_FAILURE', + SET_QUOTE_REQUEST_STATE_PENDING = 'SET_QUOTE_REQUEST_STATE_PENDING', + SET_QUOTE_REQUEST_STATE_FAILURE = 'SET_QUOTE_REQUEST_STATE_FAILURE', SET_ERROR = 'SET_ERROR', HIDE_ERROR = 'HIDE_ERROR', CLEAR_ERROR = 'CLEAR_ERROR', @@ -38,8 +38,8 @@ export const actions = { updateBuyOrderState: (buyState: AsyncProcessState) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, buyState), updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote), - updateBuyquoteRequestStatePending: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING), - updateBuyquoteRequestStateFailure: () => createAction(ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE), + setQuoteRequestStatePending: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING), + setQuoteRequestStateFailure: () => createAction(ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE), setError: (error?: any) => createAction(ActionTypes.SET_ERROR, error), hideError: () => createAction(ActionTypes.HIDE_ERROR), clearError: () => createAction(ActionTypes.CLEAR_ERROR), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index d2256ef54..6c278099f 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -52,13 +52,13 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => latestBuyQuote: action.data, quoteRequestState: AsyncProcessState.SUCCESS, }; - case ActionTypes.UPDATE_BUY_QUOTE_STATE_PENDING: + case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING: return { ...state, latestBuyQuote: undefined, quoteRequestState: AsyncProcessState.PENDING, }; - case ActionTypes.UPDATE_BUY_QUOTE_STATE_FAILURE: + case ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE: return { ...state, latestBuyQuote: undefined, -- cgit From b4af27dd4462a001904ac6d69e43aac9fd7bb69a Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 13:48:28 -0700 Subject: Moved LatestErrorDisplay to types file and gave generic name --- packages/instant/src/containers/latest_error.tsx | 5 +++-- packages/instant/src/redux/reducer.ts | 16 ++++++---------- packages/instant/src/types.ts | 4 ++++ 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx index 08ea418e7..413cf16ad 100644 --- a/packages/instant/src/containers/latest_error.tsx +++ b/packages/instant/src/containers/latest_error.tsx @@ -3,7 +3,8 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { SlidingError } from '../components/sliding_error'; -import { LatestErrorDisplay, State } from '../redux/reducer'; +import { State } from '../redux/reducer'; +import { DisplayStatus } from '../types'; import { errorUtil } from '../util/error'; export interface LatestErrorComponentProps { @@ -29,7 +30,7 @@ export interface LatestErrorProps {} const mapStateToProps = (state: State, _ownProps: LatestErrorProps): ConnectedState => ({ assetData: state.selectedAssetData, latestError: state.latestError, - slidingDirection: state.latestErrorDisplay === LatestErrorDisplay.Present ? 'up' : 'down', + slidingDirection: state.latestErrorDisplay === DisplayStatus.Present ? 'up' : 'down', }); export const LatestError = connect(mapStateToProps)(LatestErrorComponent); diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 6c278099f..2d50dd4b9 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -3,14 +3,10 @@ import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import { zrxAssetData } from '../constants'; -import { AsyncProcessState } from '../types'; +import { AsyncProcessState, DisplayStatus } from '../types'; import { Action, ActionTypes } from './actions'; -export enum LatestErrorDisplay { - Present, - Hidden, -} export interface State { selectedAssetData?: string; selectedAssetAmount?: BigNumber; @@ -19,7 +15,7 @@ export interface State { latestBuyQuote?: BuyQuote; quoteRequestState: AsyncProcessState; latestError?: any; - latestErrorDisplay: LatestErrorDisplay; + latestErrorDisplay: DisplayStatus; } export const INITIAL_STATE: State = { @@ -30,7 +26,7 @@ export const INITIAL_STATE: State = { ethUsdPrice: undefined, latestBuyQuote: undefined, latestError: undefined, - latestErrorDisplay: LatestErrorDisplay.Hidden, + latestErrorDisplay: DisplayStatus.Hidden, quoteRequestState: AsyncProcessState.NONE, }; @@ -73,18 +69,18 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => return { ...state, latestError: action.data, - latestErrorDisplay: LatestErrorDisplay.Present, + latestErrorDisplay: DisplayStatus.Present, }; case ActionTypes.HIDE_ERROR: return { ...state, - latestErrorDisplay: LatestErrorDisplay.Hidden, + latestErrorDisplay: DisplayStatus.Hidden, }; case ActionTypes.CLEAR_ERROR: return { ...state, latestError: undefined, - latestErrorDisplay: LatestErrorDisplay.Hidden, + latestErrorDisplay: DisplayStatus.Hidden, }; default: return state; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 8e3bb9b37..013ada27b 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -7,6 +7,10 @@ export enum AsyncProcessState { SUCCESS = 'Success', FAILURE = 'Failure', } +export enum DisplayStatus { + Present, + Hidden, +} export type FunctionType = (...args: any[]) => any; export type ActionCreatorsMapObject = ObjectMap; -- cgit From 8a6e0776640a7bec7eab1f91b3b611dc4cadd2f7 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 14:51:45 -0700 Subject: feat(instant): Indicate that order details section is loading by having pulsing placeholder --- .../instant/src/components/amount_placeholder.tsx | 17 +++++++----- .../instant/src/components/instant_heading.tsx | 13 +++++++--- packages/instant/src/components/order_details.tsx | 30 ++++++++++++++++++---- .../containers/latest_buy_quote_order_details.ts | 3 +++ 4 files changed, 47 insertions(+), 16 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx index 54639effb..23a00895a 100644 --- a/packages/instant/src/components/amount_placeholder.tsx +++ b/packages/instant/src/components/amount_placeholder.tsx @@ -6,24 +6,27 @@ import { Pulse } from './animations/pulse'; import { Text } from './ui'; -export interface AmountPlaceholderProps { - pulsating: boolean; +export interface PlainPlaceholder { + color: ColorOption; } - -const PlainPlaceholder = () => ( - +export const PlainPlaceholder: React.StatelessComponent = props => ( + ); +export interface AmountPlaceholderProps { + color: ColorOption; + pulsating: boolean; +} export const AmountPlaceholder: React.StatelessComponent = props => { if (props.pulsating) { return ( - + ); } else { - return ; + return ; } }; diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 9ca4ce598..6a4c850f2 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -17,6 +17,7 @@ export interface InstantHeadingProps { quoteRequestState: AsyncProcessState; } +const placeholderColor = ColorOption.white; export class InstantHeading extends React.Component { public render(): React.ReactNode { const placeholderAmountToAlwaysShow = this._placeholderAmountToAlwaysShow(); @@ -52,10 +53,10 @@ export class InstantHeading extends React.Component { private _placeholderAmountToAlwaysShow(): React.ReactNode | undefined { if (this.props.quoteRequestState === AsyncProcessState.PENDING) { - return ; + return ; } if (_.isUndefined(this.props.selectedAssetAmount)) { - return ; + return ; } return undefined; } @@ -63,7 +64,11 @@ export class InstantHeading extends React.Component { private _ethAmount(): React.ReactNode { return ( - {format.ethBaseAmount(this.props.totalEthBaseAmount, 4, )} + {format.ethBaseAmount( + this.props.totalEthBaseAmount, + 4, + , + )} ); } @@ -75,7 +80,7 @@ export class InstantHeading extends React.Component { this.props.totalEthBaseAmount, this.props.ethUsdPrice, 2, - , + , )} ); diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index ad4a87714..f48f27edb 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -7,11 +7,13 @@ import { oc } from 'ts-optchain'; import { ColorOption } from '../style/theme'; import { format } from '../util/format'; +import { AmountPlaceholder } from './amount_placeholder'; import { Container, Flex, Text } from './ui'; export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; ethUsdPrice?: BigNumber; + isLoading: boolean; } export class OrderDetails extends React.Component { @@ -39,13 +41,20 @@ export class OrderDetails extends React.Component { ethAmount={ethAssetPrice} ethUsdPrice={ethUsdPrice} isEthAmountInBaseUnits={false} + isLoading={this.props.isLoading} + /> + - ); @@ -58,6 +67,7 @@ export interface EthAmountRowProps { isEthAmountInBaseUnits?: boolean; ethUsdPrice?: BigNumber; shouldEmphasize?: boolean; + isLoading: boolean; } export const EthAmountRow: React.StatelessComponent = ({ @@ -66,15 +76,19 @@ export const EthAmountRow: React.StatelessComponent = ({ isEthAmountInBaseUnits, ethUsdPrice, shouldEmphasize, + isLoading, }) => { - const fontWeight = shouldEmphasize ? 700 : 400; + // TODO: put in private function const usdFormatter = isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd; - const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount; - const usdPriceSection = _.isUndefined(ethUsdPrice) ? null : ( + const shouldHideUsdPriceSection = _.isUndefined(ethUsdPrice) || _.isUndefined(ethAmount); + const usdPriceSection = shouldHideUsdPriceSection ? null : ( ({usdFormatter(ethAmount, ethUsdPrice)}) ); + + const fontWeight = shouldEmphasize ? 700 : 400; + const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount; return ( @@ -84,7 +98,13 @@ export const EthAmountRow: React.StatelessComponent = ({ {usdPriceSection} - {ethFormatter(ethAmount)} + {ethFormatter( + ethAmount, + 4, + + + , + )} diff --git a/packages/instant/src/containers/latest_buy_quote_order_details.ts b/packages/instant/src/containers/latest_buy_quote_order_details.ts index 597bf3088..092aaaf20 100644 --- a/packages/instant/src/containers/latest_buy_quote_order_details.ts +++ b/packages/instant/src/containers/latest_buy_quote_order_details.ts @@ -8,18 +8,21 @@ import { oc } from 'ts-optchain'; import { State } from '../redux/reducer'; import { OrderDetails } from '../components/order_details'; +import { AsyncProcessState } from '../types'; export interface LatestBuyQuoteOrderDetailsProps {} interface ConnectedState { buyQuoteInfo?: BuyQuoteInfo; ethUsdPrice?: BigNumber; + isLoading: boolean; } const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({ // use the worst case quote info buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(), ethUsdPrice: state.ethUsdPrice, + isLoading: state.quoteRequestState === AsyncProcessState.PENDING, }); export const LatestBuyQuoteOrderDetails: React.ComponentClass = connect( -- cgit From 8ff5e1926993979229783cfb03d38aabd6f2f3d3 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 15:27:34 -0700 Subject: Move USD section into helper function --- packages/instant/src/components/order_details.tsx | 88 +++++++++++------------ 1 file changed, 42 insertions(+), 46 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index f48f27edb..9a0dbc47a 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -15,7 +15,6 @@ export interface OrderDetailsProps { ethUsdPrice?: BigNumber; isLoading: boolean; } - export class OrderDetails extends React.Component { public render(): React.ReactNode { const { buyQuoteInfo, ethUsdPrice } = this.props; @@ -70,51 +69,48 @@ export interface EthAmountRowProps { isLoading: boolean; } -export const EthAmountRow: React.StatelessComponent = ({ - rowLabel, - ethAmount, - isEthAmountInBaseUnits, - ethUsdPrice, - shouldEmphasize, - isLoading, -}) => { - // TODO: put in private function - const usdFormatter = isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd; - const shouldHideUsdPriceSection = _.isUndefined(ethUsdPrice) || _.isUndefined(ethAmount); - const usdPriceSection = shouldHideUsdPriceSection ? null : ( - - ({usdFormatter(ethAmount, ethUsdPrice)}) - - ); +export class EthAmountRow extends React.Component { + public static defaultProps = { + shouldEmphasize: false, + isEthAmountInBaseUnits: true, + }; + public static displayName = 'EthAmountRow'; + public render(): React.ReactNode { + const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props; - const fontWeight = shouldEmphasize ? 700 : 400; - const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount; - return ( - - - - {rowLabel} - - - {usdPriceSection} + const fontWeight = shouldEmphasize ? 700 : 400; + const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount; + return ( + + - {ethFormatter( - ethAmount, - 4, - - - , - )} + {rowLabel} - - - - ); -}; - -EthAmountRow.defaultProps = { - shouldEmphasize: false, - isEthAmountInBaseUnits: true, -}; - -EthAmountRow.displayName = 'EthAmountRow'; + + {this._usdSection()} + + {ethFormatter( + ethAmount, + 4, + + + , + )} + + + + + ); + } + private _usdSection(): React.ReactNode { + const usdFormatter = this.props.isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd; + const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount); + return shouldHideUsdPriceSection ? null : ( + + + ({usdFormatter(this.props.ethAmount, this.props.ethUsdPrice)}) + + + ); + } +} -- cgit From a42347a776e2fa14fa898a354190f8b75bbe2fb2 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 15:28:24 -0700 Subject: Allow more than 1 class per file Felt silly that refactoring a component defined as a function to a class with a helper function caused a tslint violation --- packages/instant/tslint.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/tslint.json b/packages/instant/tslint.json index abe874a6d..08b76be97 100644 --- a/packages/instant/tslint.json +++ b/packages/instant/tslint.json @@ -2,6 +2,7 @@ "extends": ["@0x/tslint-config"], "rules": { "custom-no-magic-numbers": false, - "semicolon": [true, "always", "ignore-bound-class-methods"] + "semicolon": [true, "always", "ignore-bound-class-methods"], + "max-classes-per-file": false } } -- cgit From aa0e07b0581a645c3d2ea035d3acf28a74de0384 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 15:30:14 -0700 Subject: pulsating -> isPulsating --- packages/instant/src/components/amount_placeholder.tsx | 4 ++-- packages/instant/src/components/instant_heading.tsx | 8 ++++---- packages/instant/src/components/order_details.tsx | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx index 23a00895a..e27d0ba81 100644 --- a/packages/instant/src/components/amount_placeholder.tsx +++ b/packages/instant/src/components/amount_placeholder.tsx @@ -17,10 +17,10 @@ export const PlainPlaceholder: React.StatelessComponent = prop export interface AmountPlaceholderProps { color: ColorOption; - pulsating: boolean; + isPulsating: boolean; } export const AmountPlaceholder: React.StatelessComponent = props => { - if (props.pulsating) { + if (props.isPulsating) { return ( diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 6a4c850f2..e2ef2d668 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -53,10 +53,10 @@ export class InstantHeading extends React.Component { private _placeholderAmountToAlwaysShow(): React.ReactNode | undefined { if (this.props.quoteRequestState === AsyncProcessState.PENDING) { - return ; + return ; } if (_.isUndefined(this.props.selectedAssetAmount)) { - return ; + return ; } return undefined; } @@ -67,7 +67,7 @@ export class InstantHeading extends React.Component { {format.ethBaseAmount( this.props.totalEthBaseAmount, 4, - , + , )} ); @@ -80,7 +80,7 @@ export class InstantHeading extends React.Component { this.props.totalEthBaseAmount, this.props.ethUsdPrice, 2, - , + , )} ); diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 9a0dbc47a..a7971e1fd 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -93,7 +93,7 @@ export class EthAmountRow extends React.Component { ethAmount, 4, - + , )} -- cgit From ff1f0a967802529e5ee50a7ff52d67bae1252b51 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 15:31:18 -0700 Subject: undefined -> null to follow convention --- packages/instant/src/components/instant_heading.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index e2ef2d668..48cda7f88 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -51,14 +51,14 @@ export class InstantHeading extends React.Component { ); } - private _placeholderAmountToAlwaysShow(): React.ReactNode | undefined { + private _placeholderAmountToAlwaysShow(): React.ReactNode | null { if (this.props.quoteRequestState === AsyncProcessState.PENDING) { return ; } if (_.isUndefined(this.props.selectedAssetAmount)) { return ; } - return undefined; + return null; } private _ethAmount(): React.ReactNode { -- cgit From 1737411ab7478de4a394242c930fcc7189daae07 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 18 Oct 2018 17:16:28 -0700 Subject: Show order failed messaging when order fails --- .../instant/src/components/instant_heading.tsx | 70 +++++++++++++--------- .../containers/selected_asset_instant_heading.ts | 2 + 2 files changed, 45 insertions(+), 27 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index a36d35a93..6fc5a0963 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -14,6 +14,7 @@ export interface InstantHeadingProps { totalEthBaseAmount?: BigNumber; ethUsdPrice?: BigNumber; quoteState: AsyncProcessState; + buyOrderState: AsyncProcessState; } const Placeholder = () => ( @@ -54,32 +55,47 @@ const loadingOrAmount = (quoteState: AsyncProcessState, amount: React.ReactNode) } }; -export const InstantHeading: React.StatelessComponent = props => ( - - - - I want to buy - - - - - - - - {loadingOrAmount(props.quoteState, displaytotalEthBaseAmount(props))} - - - - {loadingOrAmount(props.quoteState, displayUsdAmount(props))} +const topText = (buyOrderState: AsyncProcessState): string => { + if (buyOrderState === AsyncProcessState.FAILURE) { + return 'Order failed'; + } + + return 'I want to buy'; +}; + +export const InstantHeading: React.StatelessComponent = props => { + return ( + + + + {topText(props.buyOrderState)} + + + + + + + {loadingOrAmount(props.quoteState, displaytotalEthBaseAmount(props))} + + + + {loadingOrAmount(props.quoteState, displayUsdAmount(props))} + + - - -); + + ); +}; diff --git a/packages/instant/src/containers/selected_asset_instant_heading.ts b/packages/instant/src/containers/selected_asset_instant_heading.ts index 0509db5da..743362151 100644 --- a/packages/instant/src/containers/selected_asset_instant_heading.ts +++ b/packages/instant/src/containers/selected_asset_instant_heading.ts @@ -16,6 +16,7 @@ interface ConnectedState { totalEthBaseAmount?: BigNumber; ethUsdPrice?: BigNumber; quoteState: AsyncProcessState; + buyOrderState: AsyncProcessState; } const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): ConnectedState => ({ @@ -23,6 +24,7 @@ const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): Connecte totalEthBaseAmount: oc(state).latestBuyQuote.worstCaseQuoteInfo.totalEthAmount(), ethUsdPrice: state.ethUsdPrice, quoteState: state.quoteState, + buyOrderState: state.buyOrderState, }); export const SelectedAssetInstantHeading: React.ComponentClass = connect(mapStateToProps)( -- cgit From 977e20edc3d94e2b95cf6e1e82eecdde2311eb7f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 13:27:16 +0100 Subject: style: make sure sideBar bottom padding is on scrollable content, not container --- packages/website/ts/pages/documentation/developers_page.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/pages/documentation/developers_page.tsx b/packages/website/ts/pages/documentation/developers_page.tsx index 30b79552f..401f65df3 100644 --- a/packages/website/ts/pages/documentation/developers_page.tsx +++ b/packages/website/ts/pages/documentation/developers_page.tsx @@ -72,7 +72,6 @@ const SidebarContainer = ` ${scrollableContainerStyles} padding-top: 27px; - padding-bottom: 100px; padding-left: ${SIDEBAR_PADDING}px; padding-right: ${SIDEBAR_PADDING}px; overflow: hidden; @@ -163,7 +162,9 @@ export class DevelopersPage extends React.Component - {this.props.screenWidth !== ScreenWidths.Sm && this.props.sidebar} + + {this.props.screenWidth !== ScreenWidths.Sm && this.props.sidebar} + Date: Fri, 19 Oct 2018 14:04:17 +0100 Subject: style: Switch out homepage image with improved one from Ben --- .../website/public/images/landing/0x_homepage.svg | 57 +++------------------- 1 file changed, 6 insertions(+), 51 deletions(-) (limited to 'packages') diff --git a/packages/website/public/images/landing/0x_homepage.svg b/packages/website/public/images/landing/0x_homepage.svg index 061ac8939..d2ccef8f4 100644 --- a/packages/website/public/images/landing/0x_homepage.svg +++ b/packages/website/public/images/landing/0x_homepage.svg @@ -1,24 +1,18 @@ - - - - - - - - - - + + + + + - @@ -56,7 +50,6 @@ - @@ -89,7 +82,6 @@ - @@ -116,7 +108,6 @@ - @@ -143,11 +134,10 @@ - - + @@ -170,7 +160,6 @@ - @@ -197,7 +186,6 @@ - @@ -224,7 +212,6 @@ - @@ -251,7 +238,6 @@ - @@ -277,109 +263,78 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit From 16ba01cd2e8b2af7bdeb6779e913ea4b6453dd78 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 14:05:37 +0100 Subject: chore: fix dropdown bug on Firefox and reduced duplicate code --- .../components/dropdowns/developers_drop_down.tsx | 46 +++++++++++----------- 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx index b279566e0..6e85c1499 100644 --- a/packages/website/ts/components/dropdowns/developers_drop_down.tsx +++ b/packages/website/ts/components/dropdowns/developers_drop_down.tsx @@ -89,26 +89,22 @@ export class DevelopersDropDown extends React.Component - - {this._renderTitle('Getting started')} - - - {this._renderLinkSection(gettingStartedKeyToLinkInfo1)} - - {this._renderLinkSection(gettingStartedKeyToLinkInfo2)} + + + {this._renderLinkSection(gettingStartedKeyToLinkInfo1, 'Getting started')} + {this._renderLinkSection(gettingStartedKeyToLinkInfo2)} - - - {this._renderTitle('Popular docs')} - {this._renderLinkSection(popularDocsToLinkInfos)} + + + {this._renderLinkSection(popularDocsToLinkInfos, 'Popular docs')} - {this._renderTitle('Useful links')} - {this._renderLinkSection(usefulLinksToLinkInfo)} + {this._renderLinkSection(usefulLinksToLinkInfo, 'Useful links')} @@ -127,16 +123,7 @@ export class DevelopersDropDown extends React.Component - - {title.toUpperCase()} - - - ); - } - private _renderLinkSection(links: ALink[]): React.ReactNode { + private _renderLinkSection(links: ALink[], title: string = ''): React.ReactNode { const numLinks = links.length; let i = 0; const renderLinks = _.map(links, (link: ALink) => { @@ -159,6 +146,17 @@ export class DevelopersDropDown extends React.Component ); }); - return {renderLinks}; + return ( + + + {!_.isEmpty(title) && ( + + {title.toUpperCase()} + + )} + + {renderLinks} + + ); } } -- cgit From 90ba8e0e8df2ccd2907adfcb143ed954b9d0b4c5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 17:09:13 +0100 Subject: Remove unused listeners --- packages/react-docs/src/components/doc_reference.tsx | 10 ---------- packages/website/ts/pages/wiki/wiki.tsx | 8 -------- 2 files changed, 18 deletions(-) (limited to 'packages') diff --git a/packages/react-docs/src/components/doc_reference.tsx b/packages/react-docs/src/components/doc_reference.tsx index 00b1286a4..85547576b 100644 --- a/packages/react-docs/src/components/doc_reference.tsx +++ b/packages/react-docs/src/components/doc_reference.tsx @@ -52,12 +52,6 @@ export interface DocReferenceProps { export interface DocReferenceState {} export class DocReference extends React.Component { - public componentDidMount(): void { - window.addEventListener('hashchange', this._onHashChanged.bind(this), false); - } - public componentWillUnmount(): void { - window.removeEventListener('hashchange', this._onHashChanged.bind(this), false); - } public componentDidUpdate(prevProps: DocReferenceProps, _prevState: DocReferenceState): void { if (!_.isEqual(prevProps.docAgnosticFormat, this.props.docAgnosticFormat)) { const hash = window.location.hash.slice(1); @@ -323,8 +317,4 @@ export class DocReference extends React.Component ); } - private _onHashChanged(_event: any): void { - const hash = window.location.hash.slice(1); - sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); - } } diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx index e62300ddf..a35404e33 100644 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ b/packages/website/ts/pages/wiki/wiki.tsx @@ -49,9 +49,6 @@ export class Wiki extends React.Component { isHoveringSidebar: false, }; } - public componentDidMount(): void { - window.addEventListener('hashchange', this._onHashChanged.bind(this), false); - } public componentWillMount(): void { // tslint:disable-next-line:no-floating-promises this._fetchArticlesBySectionAsync(); @@ -59,7 +56,6 @@ export class Wiki extends React.Component { public componentWillUnmount(): void { this._isUnmounted = true; clearTimeout(this._wikiBackoffTimeoutId); - window.removeEventListener('hashchange', this._onHashChanged.bind(this), false); } public render(): React.ReactNode { const sectionNameToLinks = _.isUndefined(this.state.articlesBySection) @@ -198,8 +194,4 @@ export class Wiki extends React.Component { } return sectionNameToLinks; } - private _onHashChanged(_event: any): void { - const hash = window.location.hash.slice(1); - sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); - } } -- cgit From d129c922edd8bc0319273488b23a5257d736502d Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 17:22:33 +0100 Subject: Use media module --- packages/website/ts/pages/documentation/developers_page.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/pages/documentation/developers_page.tsx b/packages/website/ts/pages/documentation/developers_page.tsx index 401f65df3..361dbc86e 100644 --- a/packages/website/ts/pages/documentation/developers_page.tsx +++ b/packages/website/ts/pages/documentation/developers_page.tsx @@ -6,6 +6,7 @@ import { DocsLogo } from 'ts/components/documentation/docs_logo'; import { DocsTopBar } from 'ts/components/documentation/docs_top_bar'; import { Container } from 'ts/components/ui/container'; import { Dispatcher } from 'ts/redux/dispatcher'; +import { media } from 'ts/style/media'; import { styled } from 'ts/style/theme'; import { BrowserType, OperatingSystemType, ScreenWidths } from 'ts/types'; import { Translate } from 'ts/utils/translate'; @@ -98,14 +99,14 @@ const MainContentContainer = padding-right: ${50 - SCROLLBAR_WIDTH}px; overflow: auto; } - @media (max-width: 40em) { + ${media.small` padding-left: 20px; padding-right: 20px; &:hover { padding-right: ${20 - SCROLLBAR_WIDTH}px; overflow: auto; } - } + `} `; export class DevelopersPage extends React.Component { -- cgit From 0de654bbd52f7d4702cec9f1a9a5a2cbb793181b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 17:40:55 +0100 Subject: fix: scroll lag on doc reference and wiki pages by using react-scroll `spy` and only updating the sidebar menu items whose active state had changed --- packages/react-shared/src/components/link.tsx | 16 ++- .../src/components/nested_sidebar_menu.tsx | 119 --------------------- packages/react-shared/src/index.ts | 1 - .../website/ts/components/nested_sidebar_menu.tsx | 92 ++++++++++++++++ .../website/ts/pages/documentation/doc_page.tsx | 2 +- .../website/ts/pages/documentation/docs_home.tsx | 3 +- packages/website/ts/pages/wiki/wiki.tsx | 2 +- 7 files changed, 111 insertions(+), 124 deletions(-) delete mode 100644 packages/react-shared/src/components/nested_sidebar_menu.tsx create mode 100644 packages/website/ts/components/nested_sidebar_menu.tsx (limited to 'packages') diff --git a/packages/react-shared/src/components/link.tsx b/packages/react-shared/src/components/link.tsx index 5a456109b..089e6e2ba 100644 --- a/packages/react-shared/src/components/link.tsx +++ b/packages/react-shared/src/components/link.tsx @@ -7,7 +7,7 @@ import * as validUrl from 'valid-url'; import { LinkType } from '../types'; import { constants } from '../utils/constants'; -interface LinkProps { +interface BaseLinkProps { to: string; shouldOpenInNewTab?: boolean; className?: string; @@ -18,6 +18,12 @@ interface LinkProps { fontColor?: string; } +interface ScrollLinkProps extends BaseLinkProps { + onActivityChanged?: (isActive: boolean) => void; +} + +type LinkProps = BaseLinkProps & ScrollLinkProps; + export interface LinkState {} /** @@ -103,11 +109,14 @@ export class Link extends React.Component { {this.props.children} @@ -119,6 +128,11 @@ export class Link extends React.Component { throw new Error(`Unrecognized LinkType: ${type}`); } } + private _onActivityChanged(isActive: boolean): void { + if (this.props.onActivityChanged) { + this.props.onActivityChanged(isActive); + } + } // HACK(fabio): For some reason, the react-scroll link decided to stop the propagation of click events. // We do however rely on these events being propagated in certain scenarios (e.g when the link // is within a dropdown we want to close upon being clicked). Because of this, we register the diff --git a/packages/react-shared/src/components/nested_sidebar_menu.tsx b/packages/react-shared/src/components/nested_sidebar_menu.tsx deleted file mode 100644 index 196c91af1..000000000 --- a/packages/react-shared/src/components/nested_sidebar_menu.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { ObjectMap } from '@0x/types'; -import * as _ from 'lodash'; -import MenuItem from 'material-ui/MenuItem'; -import * as React from 'react'; - -import { ALink, Styles } from '../types'; -import { colors } from '../utils/colors'; -import { utils } from '../utils/utils'; - -import { Link } from './link'; - -export interface NestedSidebarMenuProps { - sectionNameToLinks: ObjectMap; - sidebarHeader?: React.ReactNode; - shouldReformatMenuItemNames?: boolean; -} - -export interface NestedSidebarMenuState { - scrolledToId?: string; -} - -const styles: Styles = { - menuItem: { - minHeight: 0, - paddingLeft: 8, - borderRadius: 6, - }, - menuItemInnerDiv: { - color: colors.grey800, - fontSize: 14, - lineHeight: 2, - padding: 0, - whiteSpace: 'nowrap', - overflow: 'hidden', - textOverflow: 'ellipsis', - }, -}; - -export class NestedSidebarMenu extends React.Component { - public static defaultProps: Partial = { - shouldReformatMenuItemNames: true, - }; - private _urlIntervalCheckId: number | undefined = undefined; - constructor(props: NestedSidebarMenuProps) { - super(props); - this.state = {}; - } - public componentDidMount(): void { - this._urlIntervalCheckId = window.setInterval(() => { - const scrollId = location.hash.slice(1); - if (scrollId !== this.state.scrolledToId) { - this.setState({ - scrolledToId: scrollId, - }); - } - }, 200); - } - public componentWillUnmount(): void { - window.clearInterval(this._urlIntervalCheckId); - } - public render(): React.ReactNode { - const navigation = _.map(this.props.sectionNameToLinks, (links: ALink[], sectionName: string) => { - const finalSectionName = utils.convertCamelCaseToSpaces(sectionName); - // tslint:disable-next-line:no-unused-variable - return ( -
-
- {finalSectionName.toUpperCase()} -
- {this._renderMenuItems(links)} -
- ); - }); - return ( -
- {this.props.sidebarHeader} -
{navigation}
-
- ); - } - private _renderMenuItems(links: ALink[]): React.ReactNode[] { - const scrolledToId = this.state.scrolledToId; - const menuItems = _.map(links, link => { - const finalMenuItemName = this.props.shouldReformatMenuItemNames - ? utils.convertDashesToSpaces(link.title) - : link.title; - let menuItemStyle = styles.menuItem; - let menuItemInnerDivStyle = styles.menuItemInnerDiv; - const isScrolledTo = link.to === scrolledToId; - if (isScrolledTo) { - menuItemStyle = { - ...menuItemStyle, - backgroundColor: colors.lightLinkBlue, - }; - menuItemInnerDivStyle = { - ...menuItemInnerDivStyle, - color: colors.white, - fontWeight: 'bold', - }; - } - return ( -
- - - - {finalMenuItemName} - - - -
- ); - }); - return menuItems; - } -} diff --git a/packages/react-shared/src/index.ts b/packages/react-shared/src/index.ts index e33b09f19..a693f2a36 100644 --- a/packages/react-shared/src/index.ts +++ b/packages/react-shared/src/index.ts @@ -2,7 +2,6 @@ export { AnchorTitle } from './components/anchor_title'; export { MarkdownLinkBlock } from './components/markdown_link_block'; export { MarkdownCodeBlock } from './components/markdown_code_block'; export { MarkdownSection } from './components/markdown_section'; -export { NestedSidebarMenu } from './components/nested_sidebar_menu'; export { SectionHeader } from './components/section_header'; export { Link } from './components/link'; diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx new file mode 100644 index 000000000..7de91bf8c --- /dev/null +++ b/packages/website/ts/components/nested_sidebar_menu.tsx @@ -0,0 +1,92 @@ +import { ALink, colors, Link, utils as sharedUtils } from '@0x/react-shared'; +import { ObjectMap } from '@0x/types'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { Button } from 'ts/components/ui/button'; +import { Text } from 'ts/components/ui/text'; + +export interface NestedSidebarMenuProps { + sectionNameToLinks: ObjectMap; + sidebarHeader?: React.ReactNode; + shouldReformatMenuItemNames?: boolean; +} + +export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => { + const navigation = _.map(props.sectionNameToLinks, (links: ALink[], sectionName: string) => { + const finalSectionName = sharedUtils.convertCamelCaseToSpaces(sectionName); + const menuItems = _.map(links, (link, i) => { + const menuItemTitle = props.shouldReformatMenuItemNames + ? _.capitalize(sharedUtils.convertDashesToSpaces(link.title)) + : link.title; + const finalLink = { + ...link, + title: menuItemTitle, + }; + return ; + }); + // tslint:disable-next-line:no-unused-variable + return ( +
+
+ {finalSectionName.toUpperCase()} +
+ {menuItems} +
+ ); + }); + return ( +
+ {props.sidebarHeader} +
{navigation}
+
+ ); +}; + +export interface MenuItemProps { + link: ALink; +} + +export interface MenuItemState { + isActive: boolean; +} + +export class MenuItem extends React.Component { + constructor(props: MenuItemProps) { + super(props); + const isActive = window.location.hash.slice(1) === props.link.to; + this.state = { + isActive, + }; + } + public render(): React.ReactNode { + const isActive = this.state.isActive; + return ( + + + + ); + } + private _onActivityChanged(isActive: boolean): void { + this.setState({ + isActive, + }); + } +} diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx index 7157abfc9..28bf2dba1 100644 --- a/packages/website/ts/pages/documentation/doc_page.tsx +++ b/packages/website/ts/pages/documentation/doc_page.tsx @@ -6,13 +6,13 @@ import { SupportedDocJson, TypeDocUtils, } from '@0x/react-docs'; -import { NestedSidebarMenu } from '@0x/react-shared'; import findVersions = require('find-versions'); import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; import * as React from 'react'; import semverSort = require('semver-sort'); import { SidebarHeader } from 'ts/components/documentation/sidebar_header'; +import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu'; import { Container } from 'ts/components/ui/container'; import { DevelopersPage } from 'ts/pages/documentation/developers_page'; import { Dispatcher } from 'ts/redux/dispatcher'; diff --git a/packages/website/ts/pages/documentation/docs_home.tsx b/packages/website/ts/pages/documentation/docs_home.tsx index cf229cb3b..298b7ecf3 100644 --- a/packages/website/ts/pages/documentation/docs_home.tsx +++ b/packages/website/ts/pages/documentation/docs_home.tsx @@ -1,8 +1,9 @@ -import { ALink, colors, Link, NestedSidebarMenu } from '@0x/react-shared'; +import { ALink, colors, Link } from '@0x/react-shared'; import { ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; import { OverviewContent } from 'ts/components/documentation/overview_content'; +import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu'; import { Button } from 'ts/components/ui/button'; import { DevelopersPage } from 'ts/pages/documentation/developers_page'; import { Dispatcher } from 'ts/redux/dispatcher'; diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx index a35404e33..76df4f06f 100644 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ b/packages/website/ts/pages/wiki/wiki.tsx @@ -5,7 +5,6 @@ import { HeaderSizes, Link, MarkdownSection, - NestedSidebarMenu, utils as sharedUtils, } from '@0x/react-shared'; import { ObjectMap } from '@0x/types'; @@ -13,6 +12,7 @@ import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; import * as React from 'react'; import { SidebarHeader } from 'ts/components/documentation/sidebar_header'; +import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu'; import { Button } from 'ts/components/ui/button'; import { Container } from 'ts/components/ui/container'; import { DevelopersPage } from 'ts/pages/documentation/developers_page'; -- cgit From bce90318687b38c35af75cd78bf3ee69271b42ad Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 17:44:49 +0100 Subject: chore: use `colors` module --- packages/website/ts/components/nested_sidebar_menu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx index 7de91bf8c..f83833d69 100644 --- a/packages/website/ts/components/nested_sidebar_menu.tsx +++ b/packages/website/ts/components/nested_sidebar_menu.tsx @@ -70,7 +70,7 @@ export class MenuItem extends React.Component { borderRadius="4px" padding="0.4em 6px" width="100%" - backgroundColor={isActive ? colors.lightLinkBlue : 'rgb(245, 245, 245)'} + backgroundColor={isActive ? colors.lightLinkBlue : colors.grey100} fontSize="14px" textAlign="left" > -- cgit From 66465816ca049118d58ca34bada241fd146f2656 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 10:19:48 -0700 Subject: Getting rid of displayName, and rename usdSection -> _renderUsdSection --- packages/instant/src/components/order_details.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index a7971e1fd..704009d89 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -74,7 +74,6 @@ export class EthAmountRow extends React.Component { shouldEmphasize: false, isEthAmountInBaseUnits: true, }; - public static displayName = 'EthAmountRow'; public render(): React.ReactNode { const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props; @@ -87,7 +86,7 @@ export class EthAmountRow extends React.Component { {rowLabel} - {this._usdSection()} + {this._renderUsdSection()} {ethFormatter( ethAmount, @@ -102,7 +101,7 @@ export class EthAmountRow extends React.Component { ); } - private _usdSection(): React.ReactNode { + private _renderUsdSection(): React.ReactNode { const usdFormatter = this.props.isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd; const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount); return shouldHideUsdPriceSection ? null : ( -- cgit From 2f4e498a099ebbd8078139f90a054941e427de15 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 10:32:37 -0700 Subject: Refactor to make placeholder logic more straightforward --- packages/instant/src/components/instant_heading.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 48cda7f88..265c3e0a5 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -20,7 +20,6 @@ export interface InstantHeadingProps { const placeholderColor = ColorOption.white; export class InstantHeading extends React.Component { public render(): React.ReactNode { - const placeholderAmountToAlwaysShow = this._placeholderAmountToAlwaysShow(); return ( { - {placeholderAmountToAlwaysShow || this._ethAmount()} - {placeholderAmountToAlwaysShow || this._dollarAmount()} + + {this._placeholderOrAmount(this._ethAmount.bind(this))} + + {this._placeholderOrAmount(this._dollarAmount.bind(this))} ); } - private _placeholderAmountToAlwaysShow(): React.ReactNode | null { + private _placeholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode { if (this.props.quoteRequestState === AsyncProcessState.PENDING) { return ; } if (_.isUndefined(this.props.selectedAssetAmount)) { return ; } - return null; + return amountFunction(); } private _ethAmount(): React.ReactNode { -- cgit From 6588cf919ef70f54754b1428df51e967b817788a Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 10:34:44 -0700 Subject: dont export PlainPlaceholder --- packages/instant/src/components/amount_placeholder.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/amount_placeholder.tsx b/packages/instant/src/components/amount_placeholder.tsx index e27d0ba81..6ef8f0ac3 100644 --- a/packages/instant/src/components/amount_placeholder.tsx +++ b/packages/instant/src/components/amount_placeholder.tsx @@ -6,10 +6,10 @@ import { Pulse } from './animations/pulse'; import { Text } from './ui'; -export interface PlainPlaceholder { +interface PlainPlaceholder { color: ColorOption; } -export const PlainPlaceholder: React.StatelessComponent = props => ( +const PlainPlaceholder: React.StatelessComponent = props => ( -- cgit From ce4da870d79a589913d1660de8cf012b894357c6 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 19:38:12 +0100 Subject: chore: use Text --- packages/website/ts/components/nested_sidebar_menu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx index f83833d69..021e3f0e5 100644 --- a/packages/website/ts/components/nested_sidebar_menu.tsx +++ b/packages/website/ts/components/nested_sidebar_menu.tsx @@ -27,9 +27,9 @@ export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => { // tslint:disable-next-line:no-unused-variable return (
-
+ {finalSectionName.toUpperCase()} -
+ {menuItems}
); -- cgit From b49e5c76e485beead2554027a3ff8af101bce1d5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 19 Oct 2018 19:38:20 +0100 Subject: Use em for all --- packages/website/ts/components/nested_sidebar_menu.tsx | 2 +- packages/website/ts/pages/documentation/docs_home.tsx | 2 +- packages/website/ts/pages/wiki/wiki.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx index 021e3f0e5..db7d55261 100644 --- a/packages/website/ts/components/nested_sidebar_menu.tsx +++ b/packages/website/ts/components/nested_sidebar_menu.tsx @@ -68,7 +68,7 @@ export class MenuItem extends React.Component { > -
+ ); } private readonly _handleClick = async () => { @@ -43,10 +42,13 @@ export class BuyButton extends React.Component { this.props.onClick(this.props.buyQuote); let txnHash; try { - txnHash = await this.props.assetBuyer.executeBuyQuoteAsync(this.props.buyQuote); + txnHash = await this.props.assetBuyer.executeBuyQuoteAsync(this.props.buyQuote, { + gasLimit: 5000000, + }); await web3Wrapper.awaitTransactionSuccessAsync(txnHash); this.props.onBuySuccess(this.props.buyQuote, txnHash); - } catch { + } catch (e) { + console.log('error', e); this.props.onBuyFailure(this.props.buyQuote, txnHash); } }; diff --git a/packages/instant/src/components/retry_button.tsx b/packages/instant/src/components/retry_button.tsx new file mode 100644 index 000000000..5e36506d0 --- /dev/null +++ b/packages/instant/src/components/retry_button.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Button, Text } from './ui'; + +export interface RetryButtonProps { + onClick: () => void; +} + +export const RetryButton: React.StatelessComponent = props => { + return ( + + ); +}; diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_button.ts index 99f971321..a5fa0aa8e 100644 --- a/packages/instant/src/containers/selected_asset_buy_button.ts +++ b/packages/instant/src/containers/selected_asset_buy_button.ts @@ -1,3 +1,4 @@ +// TODO: Rename to SelectedAssetButton import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; import * as React from 'react'; @@ -8,45 +9,31 @@ import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; import { AsyncProcessState } from '../types'; -import { BuyButton } from '../components/buy_button'; +import { AssetButton } from '../components/asset_button'; +// TODO: rename export interface SelectedAssetBuyButtonProps {} interface ConnectedState { assetBuyer?: AssetBuyer; - text: string; + buyOrderState: AsyncProcessState; buyQuote?: BuyQuote; } interface ConnectedDispatch { - onClick: (buyQuote: BuyQuote) => void; + onBuyClick: (buyQuote: BuyQuote) => void; onBuySuccess: (buyQuote: BuyQuote) => void; onBuyFailure: (buyQuote: BuyQuote) => void; } -const textForState = (state: AsyncProcessState): string => { - switch (state) { - case AsyncProcessState.NONE: - return 'Buy'; - case AsyncProcessState.PENDING: - return '...Loading'; - case AsyncProcessState.SUCCESS: - return 'Success!'; - case AsyncProcessState.FAILURE: - return 'Failed'; - default: - return 'Buy'; - } -}; - const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps): ConnectedState => ({ assetBuyer: state.assetBuyer, - text: textForState(state.buyOrderState), + buyOrderState: state.buyOrderState, buyQuote: state.latestBuyQuote, }); const mapDispatchToProps = (dispatch: Dispatch, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({ - onClick: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.PENDING)), + onBuyClick: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.PENDING)), onBuySuccess: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.SUCCESS)), onBuyFailure: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.FAILURE)), }); @@ -54,4 +41,4 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: SelectedAssetB export const SelectedAssetBuyButton: React.ComponentClass = connect( mapStateToProps, mapDispatchToProps, -)(BuyButton); +)(AssetButton); -- cgit From 6c79a858dff2766917ee3a4b5d4f623b66dadd17 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 13:51:57 -0700 Subject: WIP: clear buy quote working --- packages/instant/src/components/asset_button.tsx | 10 +++------- packages/instant/src/containers/selected_asset_buy_button.ts | 2 ++ packages/instant/src/redux/actions.ts | 2 ++ packages/instant/src/redux/reducer.ts | 8 ++++++++ 4 files changed, 15 insertions(+), 7 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/asset_button.tsx b/packages/instant/src/components/asset_button.tsx index 84a27303d..4ae7a2704 100644 --- a/packages/instant/src/components/asset_button.tsx +++ b/packages/instant/src/components/asset_button.tsx @@ -9,6 +9,7 @@ import { BuyButton } from './buy_button'; import { RetryButton } from './retry_button'; import { Container } from './ui'; +// TODO: split into sepearte components? getting really big.. interface AssetButtonProps { assetBuyer?: AssetBuyer; buyQuote?: BuyQuote; @@ -16,6 +17,7 @@ interface AssetButtonProps { onBuyClick: (buyQuote: BuyQuote) => void; onBuySuccess: (buyQuote: BuyQuote) => void; onBuyFailure: (buyQuote: BuyQuote) => void; + onRetryClick: () => void; } export class AssetButton extends React.Component { @@ -30,13 +32,7 @@ export class AssetButton extends React.Component { // TODO: figure out why buyOrderState is undefined in beginning, get rid of default switch (this.props.buyOrderState) { case AsyncProcessState.FAILURE: - return ( - { - console.log('try again'); - }} - /> - ); + return ; case AsyncProcessState.SUCCESS: return
; default: diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_button.ts index a5fa0aa8e..41d196b03 100644 --- a/packages/instant/src/containers/selected_asset_buy_button.ts +++ b/packages/instant/src/containers/selected_asset_buy_button.ts @@ -24,6 +24,7 @@ interface ConnectedDispatch { onBuyClick: (buyQuote: BuyQuote) => void; onBuySuccess: (buyQuote: BuyQuote) => void; onBuyFailure: (buyQuote: BuyQuote) => void; + onRetryClick: () => void; } const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps): ConnectedState => ({ @@ -36,6 +37,7 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: SelectedAssetB onBuyClick: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.PENDING)), onBuySuccess: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.SUCCESS)), onBuyFailure: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.FAILURE)), + onRetryClick: () => dispatch(actions.clearBuyQuoteAndSelectedAssetAmount()), }); export const SelectedAssetBuyButton: React.ComponentClass = connect( diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index bc75ce66c..d6388d77e 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -31,6 +31,7 @@ export enum ActionTypes { SET_ERROR = 'SET_ERROR', HIDE_ERROR = 'HIDE_ERROR', CLEAR_ERROR = 'CLEAR_ERROR', + CLEAR_BUY_QUOTE_AND_SELECTED_ASSET_AMOUNT = 'CLEAR_BUY_QUOTE_AND_SELECTED_ASSET_AMOUNT', } export const actions = { @@ -45,4 +46,5 @@ export const actions = { setError: (error?: any) => createAction(ActionTypes.SET_ERROR, error), hideError: () => createAction(ActionTypes.HIDE_ERROR), clearError: () => createAction(ActionTypes.CLEAR_ERROR), + clearBuyQuoteAndSelectedAssetAmount: () => createAction(ActionTypes.CLEAR_BUY_QUOTE_AND_SELECTED_ASSET_AMOUNT), }; diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index 657bd0e40..10e56f152 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -99,6 +99,14 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State => ...state, selectedAsset: newSelectedAsset, }; + case ActionTypes.CLEAR_BUY_QUOTE_AND_SELECTED_ASSET_AMOUNT: + return { + ...state, + latestBuyQuote: undefined, + quoteState: AsyncProcessState.NONE, + buyOrderState: AsyncProcessState.NONE, + selectedAssetAmount: undefined, + }; default: return state; } -- cgit From d2766d7ced990efd5a91441b459f36e8a21f8513 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 14:49:38 -0700 Subject: Selected Asset button --- packages/instant/src/components/asset_button.tsx | 51 ---------------------- packages/instant/src/components/buy_button.tsx | 6 +-- .../src/components/zero_ex_instant_container.tsx | 6 ++- .../src/containers/selected_asset_button.tsx | 33 ++++++++++++++ .../src/containers/selected_asset_buy_button.ts | 10 +---- .../src/containers/selected_asset_retry_button.tsx | 27 ++++++++++++ 6 files changed, 68 insertions(+), 65 deletions(-) delete mode 100644 packages/instant/src/components/asset_button.tsx create mode 100644 packages/instant/src/containers/selected_asset_button.tsx create mode 100644 packages/instant/src/containers/selected_asset_retry_button.tsx (limited to 'packages') diff --git a/packages/instant/src/components/asset_button.tsx b/packages/instant/src/components/asset_button.tsx deleted file mode 100644 index 4ae7a2704..000000000 --- a/packages/instant/src/components/asset_button.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; -import * as React from 'react'; - -import { AsyncProcessState } from '../types'; - -// TODO: better name? - -import { BuyButton } from './buy_button'; -import { RetryButton } from './retry_button'; -import { Container } from './ui'; - -// TODO: split into sepearte components? getting really big.. -interface AssetButtonProps { - assetBuyer?: AssetBuyer; - buyQuote?: BuyQuote; - buyOrderState: AsyncProcessState; - onBuyClick: (buyQuote: BuyQuote) => void; - onBuySuccess: (buyQuote: BuyQuote) => void; - onBuyFailure: (buyQuote: BuyQuote) => void; - onRetryClick: () => void; -} - -export class AssetButton extends React.Component { - public render(): React.ReactNode { - return ( - - {this._renderButton()} - - ); - } - private _renderButton(): React.ReactNode { - // TODO: figure out why buyOrderState is undefined in beginning, get rid of default - switch (this.props.buyOrderState) { - case AsyncProcessState.FAILURE: - return ; - case AsyncProcessState.SUCCESS: - return
; - default: - return ( - - ); - } - } -} diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 4d2386620..5eef18aa3 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -6,7 +6,7 @@ import { ColorOption } from '../style/theme'; import { util } from '../util/util'; import { web3Wrapper } from '../util/web3_wrapper'; -import { Button, Container, Text } from './ui'; +import { Button, Text } from './ui'; export interface BuyButtonProps { buyQuote?: BuyQuote; @@ -14,7 +14,6 @@ export interface BuyButtonProps { onClick: (buyQuote: BuyQuote) => void; onBuySuccess: (buyQuote: BuyQuote, txnHash: string) => void; onBuyFailure: (buyQuote: BuyQuote, tnxHash?: string) => void; - text: string; } export class BuyButton extends React.Component { @@ -24,12 +23,11 @@ export class BuyButton extends React.Component { onBuyFailure: util.boundNoop, }; public render(): React.ReactNode { - // TODO: move container out const shouldDisableButton = _.isUndefined(this.props.buyQuote); return ( ); diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index cf918d890..088d0a93e 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details'; import { LatestError } from '../containers/latest_error'; -import { SelectedAssetBuyButton } from '../containers/selected_asset_buy_button'; +import { SelectedAssetButton } from '../containers/selected_asset_button'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; import { ColorOption } from '../style/theme'; @@ -26,7 +26,9 @@ export const ZeroExInstantContainer: React.StatelessComponent - + + + diff --git a/packages/instant/src/containers/selected_asset_button.tsx b/packages/instant/src/containers/selected_asset_button.tsx new file mode 100644 index 000000000..d6e7303dd --- /dev/null +++ b/packages/instant/src/containers/selected_asset_button.tsx @@ -0,0 +1,33 @@ +import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { State } from '../redux/reducer'; +import { AsyncProcessState } from '../types'; + +import { SelectedAssetBuyButton } from './selected_asset_buy_button'; +import { SelectedAssetRetryButton } from './selected_asset_retry_button'; + +interface ConnectedState { + buyOrderState: AsyncProcessState; +} +export interface SelectedAssetButtonProps {} +const mapStateToProps = (state: State, _ownProps: SelectedAssetButtonProps): ConnectedState => ({ + buyOrderState: state.buyOrderState, +}); + +const SelectedAssetButtonPresentationComponent: React.StatelessComponent<{ + buyOrderState: AsyncProcessState; +}> = props => { + if (props.buyOrderState === AsyncProcessState.FAILURE) { + return ; + } + + return ; +}; + +export const SelectedAssetButton: React.ComponentClass = connect(mapStateToProps)( + SelectedAssetButtonPresentationComponent, +); diff --git a/packages/instant/src/containers/selected_asset_buy_button.ts b/packages/instant/src/containers/selected_asset_buy_button.ts index 41d196b03..7306ec2ec 100644 --- a/packages/instant/src/containers/selected_asset_buy_button.ts +++ b/packages/instant/src/containers/selected_asset_buy_button.ts @@ -1,4 +1,3 @@ -// TODO: Rename to SelectedAssetButton import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; import * as React from 'react'; @@ -9,14 +8,12 @@ import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; import { AsyncProcessState } from '../types'; -import { AssetButton } from '../components/asset_button'; +import { BuyButton } from '../components/buy_button'; -// TODO: rename export interface SelectedAssetBuyButtonProps {} interface ConnectedState { assetBuyer?: AssetBuyer; - buyOrderState: AsyncProcessState; buyQuote?: BuyQuote; } @@ -24,12 +21,10 @@ interface ConnectedDispatch { onBuyClick: (buyQuote: BuyQuote) => void; onBuySuccess: (buyQuote: BuyQuote) => void; onBuyFailure: (buyQuote: BuyQuote) => void; - onRetryClick: () => void; } const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyButtonProps): ConnectedState => ({ assetBuyer: state.assetBuyer, - buyOrderState: state.buyOrderState, buyQuote: state.latestBuyQuote, }); @@ -37,10 +32,9 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: SelectedAssetB onBuyClick: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.PENDING)), onBuySuccess: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.SUCCESS)), onBuyFailure: buyQuote => dispatch(actions.updatebuyOrderState(AsyncProcessState.FAILURE)), - onRetryClick: () => dispatch(actions.clearBuyQuoteAndSelectedAssetAmount()), }); export const SelectedAssetBuyButton: React.ComponentClass = connect( mapStateToProps, mapDispatchToProps, -)(AssetButton); +)(BuyButton); diff --git a/packages/instant/src/containers/selected_asset_retry_button.tsx b/packages/instant/src/containers/selected_asset_retry_button.tsx new file mode 100644 index 000000000..f8963ca8e --- /dev/null +++ b/packages/instant/src/containers/selected_asset_retry_button.tsx @@ -0,0 +1,27 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { Action, actions } from '../redux/actions'; + +import { RetryButton } from '../components/retry_button'; +import { State } from '../redux/reducer'; + +export interface SelectedAssetRetryButtonProps {} + +interface ConnectedDispatch { + onClick: () => void; +} + +const mapDispatchToProps = ( + dispatch: Dispatch, + _ownProps: SelectedAssetRetryButtonProps, +): ConnectedDispatch => ({ + onClick: () => dispatch(actions.clearBuyQuoteAndSelectedAssetAmount()), +}); + +export const SelectedAssetRetryButton: React.ComponentClass = connect( + null, + mapDispatchToProps, +)(RetryButton); -- cgit From 092d010c2dcdeffa7c44c147d380255c33649679 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 15:57:11 -0700 Subject: Render failure icon --- .../instant/src/components/instant_heading.tsx | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 5d39e4048..7ae509e3a 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -9,6 +9,7 @@ import { format } from '../util/format'; import { AmountPlaceholder } from './amount_placeholder'; import { Container, Flex, Text } from './ui'; +import { Icon } from './ui/icon'; export interface InstantHeadingProps { selectedAssetAmount?: BigNumber; @@ -43,14 +44,34 @@ export class InstantHeading extends React.Component { - {this._placeholderOrAmount(this._ethAmount)} - {this._placeholderOrAmount(this._dollarAmount)} + {this._renderIconOrAmounts()} ); } + private _renderIconOrAmounts(): React.ReactNode { + const icon = this._renderIcon(); + if (icon) { + return icon; + } + + return ( + + {this._placeholderOrAmount(this._ethAmount)} + {this._placeholderOrAmount(this._dollarAmount)} + + ); + } + + private _renderIcon(): React.ReactNode { + if (this.props.buyOrderState === AsyncProcessState.FAILURE) { + return ; + } + return undefined; + } + private _renderTopText(): React.ReactNode { if (this.props.buyOrderState === AsyncProcessState.FAILURE) { return 'Order failed'; -- cgit From ac2d93ab2261e19f87870f4143806d62c1d1c619 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 16:06:42 -0700 Subject: Small refacotor of icons or amounts part --- packages/instant/src/components/instant_heading.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 7ae509e3a..856e4d43e 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -22,6 +22,7 @@ export interface InstantHeadingProps { const placeholderColor = ColorOption.white; export class InstantHeading extends React.Component { public render(): React.ReactNode { + const iconOrAmounts = this._renderIcon() || this._renderAmountsSection(); return ( { - {this._renderIconOrAmounts()} + {iconOrAmounts} ); } - private _renderIconOrAmounts(): React.ReactNode { - const icon = this._renderIcon(); - if (icon) { - return icon; - } - + private _renderAmountsSection(): React.ReactNode { return ( {this._placeholderOrAmount(this._ethAmount)} -- cgit From 51779fec38a32c0bbbc0209559f84aeda8a45d1a Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 16:11:01 -0700 Subject: linting --- packages/instant/src/components/buy_button.tsx | 1 - packages/instant/src/containers/selected_asset_button.tsx | 2 -- packages/instant/src/containers/selected_asset_retry_button.tsx | 1 - 3 files changed, 4 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 5eef18aa3..9a3ded699 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -46,7 +46,6 @@ export class BuyButton extends React.Component { await web3Wrapper.awaitTransactionSuccessAsync(txnHash); this.props.onBuySuccess(this.props.buyQuote, txnHash); } catch (e) { - console.log('error', e); this.props.onBuyFailure(this.props.buyQuote, txnHash); } }; diff --git a/packages/instant/src/containers/selected_asset_button.tsx b/packages/instant/src/containers/selected_asset_button.tsx index d6e7303dd..d84ae1a52 100644 --- a/packages/instant/src/containers/selected_asset_button.tsx +++ b/packages/instant/src/containers/selected_asset_button.tsx @@ -1,8 +1,6 @@ -import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; import * as _ from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; import { State } from '../redux/reducer'; import { AsyncProcessState } from '../types'; diff --git a/packages/instant/src/containers/selected_asset_retry_button.tsx b/packages/instant/src/containers/selected_asset_retry_button.tsx index f8963ca8e..66177551d 100644 --- a/packages/instant/src/containers/selected_asset_retry_button.tsx +++ b/packages/instant/src/containers/selected_asset_retry_button.tsx @@ -6,7 +6,6 @@ import { Dispatch } from 'redux'; import { Action, actions } from '../redux/actions'; import { RetryButton } from '../components/retry_button'; -import { State } from '../redux/reducer'; export interface SelectedAssetRetryButtonProps {} -- cgit From bf0a4bd91b6e6d15a468b0e75a3a5846c98b85ab Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 16:37:54 -0700 Subject: feat(instant): Add failure state and icon --- packages/instant/src/components/retry_button.tsx | 17 ++----------- .../instant/src/components/secondary_button.tsx | 28 ++++++++++++++++++++++ .../src/containers/selected_asset_button.tsx | 5 ++++ 3 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 packages/instant/src/components/secondary_button.tsx (limited to 'packages') diff --git a/packages/instant/src/components/retry_button.tsx b/packages/instant/src/components/retry_button.tsx index 5e36506d0..28547ce54 100644 --- a/packages/instant/src/components/retry_button.tsx +++ b/packages/instant/src/components/retry_button.tsx @@ -1,24 +1,11 @@ import * as React from 'react'; -import { ColorOption } from '../style/theme'; - -import { Button, Text } from './ui'; +import { SecondaryButton } from './secondary_button'; export interface RetryButtonProps { onClick: () => void; } export const RetryButton: React.StatelessComponent = props => { - return ( - - ); + return ; }; diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx new file mode 100644 index 000000000..e073f6061 --- /dev/null +++ b/packages/instant/src/components/secondary_button.tsx @@ -0,0 +1,28 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Button, ButtonProps } from './ui/button'; +import { Text } from './ui/text'; + +export interface SecondaryButtonProps extends ButtonProps { + text: string; +} + +export const SecondaryButton: React.StatelessComponent = props => { + const buttonProps = _.omit(props, 'text'); + return ( + + ); +}; diff --git a/packages/instant/src/containers/selected_asset_button.tsx b/packages/instant/src/containers/selected_asset_button.tsx index d84ae1a52..8c617804e 100644 --- a/packages/instant/src/containers/selected_asset_button.tsx +++ b/packages/instant/src/containers/selected_asset_button.tsx @@ -2,6 +2,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { connect } from 'react-redux'; +import { SecondaryButton } from '../components/secondary_button'; import { State } from '../redux/reducer'; import { AsyncProcessState } from '../types'; @@ -21,6 +22,10 @@ const SelectedAssetButtonPresentationComponent: React.StatelessComponent<{ }> = props => { if (props.buyOrderState === AsyncProcessState.FAILURE) { return ; + } else if (props.buyOrderState === AsyncProcessState.SUCCESS) { + return ; + } else if (props.buyOrderState === AsyncProcessState.PENDING) { + return ; } return ; -- cgit From a766d78706cb45336263388360584390fe0e62f2 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 19 Oct 2018 16:39:42 -0700 Subject: Remove hack fix --- packages/instant/src/components/buy_button.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 9a3ded699..2def34fd7 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -40,12 +40,10 @@ export class BuyButton extends React.Component { this.props.onClick(this.props.buyQuote); let txnHash; try { - txnHash = await this.props.assetBuyer.executeBuyQuoteAsync(this.props.buyQuote, { - gasLimit: 5000000, - }); + txnHash = await this.props.assetBuyer.executeBuyQuoteAsync(this.props.buyQuote); await web3Wrapper.awaitTransactionSuccessAsync(txnHash); this.props.onBuySuccess(this.props.buyQuote, txnHash); - } catch (e) { + } catch { this.props.onBuyFailure(this.props.buyQuote, txnHash); } }; -- cgit From 7e24c04c0bd45cae753aac818b1ec0a64bd85fa4 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sat, 20 Oct 2018 15:01:29 +0100 Subject: fix: Update address to ZRX token to newly deployed 'mintable' ZRX token on Kovan/Ropsten --- packages/website/ts/utils/fake_token_registry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/utils/fake_token_registry.ts b/packages/website/ts/utils/fake_token_registry.ts index 607dd2553..0d5b3486a 100644 --- a/packages/website/ts/utils/fake_token_registry.ts +++ b/packages/website/ts/utils/fake_token_registry.ts @@ -694,7 +694,7 @@ export const fakeTokenRegistry: { [networkId: string]: FakeTokenRegistryEntry[] ], '42': [ { - address: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', + address: '0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa', name: '0x Protocol Token', symbol: 'ZRX', decimals: 18, @@ -858,7 +858,7 @@ export const fakeTokenRegistry: { [networkId: string]: FakeTokenRegistryEntry[] decimals: 19, }, { - address: '0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d', + address: '0xff67881f8d12f372d91baae9752eb3631ff0ed00', name: '0x Protocol Token', symbol: 'ZRX', decimals: 18, -- cgit From b9dccf9da340e276ddf6f6dd35118cc6fb77026f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 19:20:36 +0200 Subject: chore: add whole number schema --- packages/json-schemas/schemas/whole_number_schema.json | 5 +++++ packages/json-schemas/src/schemas.ts | 2 ++ packages/json-schemas/tsconfig.json | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 packages/json-schemas/schemas/whole_number_schema.json (limited to 'packages') diff --git a/packages/json-schemas/schemas/whole_number_schema.json b/packages/json-schemas/schemas/whole_number_schema.json new file mode 100644 index 000000000..944ce820e --- /dev/null +++ b/packages/json-schemas/schemas/whole_number_schema.json @@ -0,0 +1,5 @@ +{ + "id": "/wholeNumberSchema", + "type": "string", + "pattern": "^\\d+$" +} diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index 8318df617..8ece5de75 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -34,6 +34,7 @@ import * as signedOrderSchema from '../schemas/signed_order_schema.json'; import * as signedOrdersSchema from '../schemas/signed_orders_schema.json'; import * as tokenSchema from '../schemas/token_schema.json'; import * as txDataSchema from '../schemas/tx_data_schema.json'; +import * as wholeNumberSchema from '../schemas/whole_number_schema.json'; import * as zeroExTransactionSchema from '../schemas/zero_ex_transaction_schema.json'; export const schemas = { @@ -74,4 +75,5 @@ export const schemas = { relayerApiOrdersResponseSchema, relayerApiAssetDataPairsSchema, zeroExTransactionSchema, + wholeNumberSchema, }; diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index 425dfcfe1..76d2cf240 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -43,6 +43,7 @@ "./schemas/js_number.json", "./schemas/zero_ex_transaction_schema.json", "./schemas/tx_data_schema.json", - "./schemas/index_filter_values_schema.json" + "./schemas/index_filter_values_schema.json", + "./schemas/wholeNumberSchema.json" ] } -- cgit From 632d7b6fc121444055c91e00ab616757ffebdf68 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 19:24:19 +0200 Subject: fix: improve schemas by enforcing that amounts that must be whole numbers (e.g Order asset amounts) no longer allow decimal numbers --- packages/json-schemas/schemas/order_cancel_schema.json | 2 +- .../schemas/order_fill_or_kill_requests_schema.json | 2 +- .../json-schemas/schemas/order_fill_requests_schema.json | 2 +- packages/json-schemas/schemas/order_schema.json | 12 ++++++------ .../schemas/relayer_api_asset_data_trade_info_schema.json | 4 ++-- .../schemas/relayer_api_order_config_payload_schema.json | 6 +++--- .../schemas/relayer_api_order_config_response_schema.json | 4 ++-- .../json-schemas/schemas/zero_ex_transaction_schema.json | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) (limited to 'packages') diff --git a/packages/json-schemas/schemas/order_cancel_schema.json b/packages/json-schemas/schemas/order_cancel_schema.json index 09d4068c6..8d0999941 100644 --- a/packages/json-schemas/schemas/order_cancel_schema.json +++ b/packages/json-schemas/schemas/order_cancel_schema.json @@ -4,7 +4,7 @@ "items": { "properties": { "order": { "$ref": "/orderSchema" }, - "takerTokenCancelAmount": { "$ref": "/numberSchema" } + "takerTokenCancelAmount": { "$ref": "/wholeNumberSchema" } }, "required": ["order", "takerTokenCancelAmount"], "type": "object" diff --git a/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json b/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json index c9549c72e..73bbf20bb 100644 --- a/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json +++ b/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json @@ -4,7 +4,7 @@ "items": { "properties": { "signedOrder": { "$ref": "/signedOrderSchema" }, - "fillTakerAmount": { "$ref": "/numberSchema" } + "fillTakerAmount": { "$ref": "/wholeNumberSchema" } }, "required": ["signedOrder", "fillTakerAmount"], "type": "object" diff --git a/packages/json-schemas/schemas/order_fill_requests_schema.json b/packages/json-schemas/schemas/order_fill_requests_schema.json index 98325653b..d06fb19a2 100644 --- a/packages/json-schemas/schemas/order_fill_requests_schema.json +++ b/packages/json-schemas/schemas/order_fill_requests_schema.json @@ -4,7 +4,7 @@ "items": { "properties": { "signedOrder": { "$ref": "/signedOrderSchema" }, - "takerTokenFillAmount": { "$ref": "/numberSchema" } + "takerTokenFillAmount": { "$ref": "/wholeNumberSchema" } }, "required": ["signedOrder", "takerTokenFillAmount"], "type": "object" diff --git a/packages/json-schemas/schemas/order_schema.json b/packages/json-schemas/schemas/order_schema.json index de2c8c7c2..c70b9e2dd 100644 --- a/packages/json-schemas/schemas/order_schema.json +++ b/packages/json-schemas/schemas/order_schema.json @@ -3,17 +3,17 @@ "properties": { "makerAddress": { "$ref": "/addressSchema" }, "takerAddress": { "$ref": "/addressSchema" }, - "makerFee": { "$ref": "/numberSchema" }, - "takerFee": { "$ref": "/numberSchema" }, + "makerFee": { "$ref": "/wholeNumberSchema" }, + "takerFee": { "$ref": "/wholeNumberSchema" }, "senderAddress": { "$ref": "/addressSchema" }, - "makerAssetAmount": { "$ref": "/numberSchema" }, - "takerAssetAmount": { "$ref": "/numberSchema" }, + "makerAssetAmount": { "$ref": "/wholeNumberSchema" }, + "takerAssetAmount": { "$ref": "/wholeNumberSchema" }, "makerAssetData": { "$ref": "/hexSchema" }, "takerAssetData": { "$ref": "/hexSchema" }, - "salt": { "$ref": "/numberSchema" }, + "salt": { "$ref": "/wholeNumberSchema" }, "exchangeAddress": { "$ref": "/addressSchema" }, "feeRecipientAddress": { "$ref": "/addressSchema" }, - "expirationTimeSeconds": { "$ref": "/numberSchema" } + "expirationTimeSeconds": { "$ref": "/wholeNumberSchema" } }, "required": [ "makerAddress", diff --git a/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json b/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json index 0ab9b444f..e0f274c5d 100644 --- a/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json +++ b/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json @@ -3,8 +3,8 @@ "type": "object", "properties": { "assetData": { "$ref": "/hexSchema" }, - "minAmount": { "$ref": "/numberSchema" }, - "maxAmount": { "$ref": "/numberSchema" }, + "minAmount": { "$ref": "/wholeNumberSchema" }, + "maxAmount": { "$ref": "/wholeNumberSchema" }, "precision": { "type": "number" } }, "required": ["assetData"] diff --git a/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json b/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json index bc95b61ef..f4583fc62 100644 --- a/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json +++ b/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json @@ -4,12 +4,12 @@ "properties": { "makerAddress": { "$ref": "/addressSchema" }, "takerAddress": { "$ref": "/addressSchema" }, - "makerAssetAmount": { "$ref": "/numberSchema" }, - "takerAssetAmount": { "$ref": "/numberSchema" }, + "makerAssetAmount": { "$ref": "/wholeNumberSchema" }, + "takerAssetAmount": { "$ref": "/wholeNumberSchema" }, "makerAssetData": { "$ref": "/hexSchema" }, "takerAssetData": { "$ref": "/hexSchema" }, "exchangeAddress": { "$ref": "/addressSchema" }, - "expirationTimeSeconds": { "$ref": "/numberSchema" } + "expirationTimeSeconds": { "$ref": "/wholeNumberSchema" } }, "required": [ "makerAddress", diff --git a/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json b/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json index 0742febdf..8193861e1 100644 --- a/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json +++ b/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json @@ -2,8 +2,8 @@ "id": "/relayerApiOrderConfigResponseSchema", "type": "object", "properties": { - "makerFee": { "$ref": "/numberSchema" }, - "takerFee": { "$ref": "/numberSchema" }, + "makerFee": { "$ref": "/wholeNumberSchema" }, + "takerFee": { "$ref": "/wholeNumberSchema" }, "feeRecipientAddress": { "$ref": "/addressSchema" }, "senderAddress": { "$ref": "/addressSchema" } }, diff --git a/packages/json-schemas/schemas/zero_ex_transaction_schema.json b/packages/json-schemas/schemas/zero_ex_transaction_schema.json index ad3b11583..0c714f14d 100644 --- a/packages/json-schemas/schemas/zero_ex_transaction_schema.json +++ b/packages/json-schemas/schemas/zero_ex_transaction_schema.json @@ -3,7 +3,7 @@ "properties": { "data": { "$ref": "/hexSchema" }, "signerAddress": { "$ref": "/addressSchema" }, - "salt": { "$ref": "/numberSchema" } + "salt": { "$ref": "/wholeNumberSchema" } }, "required": ["data", "salt", "signerAddress"], "type": "object" -- cgit From e0149618f306b9f3b9afc5001a9ef4840a1b5237 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 19:26:06 +0200 Subject: Add changelog --- packages/json-schemas/CHANGELOG.json | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'packages') diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index 8a88df6e2..3bd6552e3 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -1,4 +1,14 @@ [ + { + "version": "2.0.1", + "changes": [ + { + "note": + "Improve schemas by enforcing that amounts that must be whole numbers (e.g Order asset amounts) no longer allow decimal amounts", + "pr": 1173 + } + ] + }, { "version": "2.0.0", "changes": [ -- cgit From 528ae4376e5e605dac9666f2a5917803e942a1f9 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 19:27:42 +0200 Subject: revert unrelated change --- packages/website/ts/utils/fake_token_registry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/utils/fake_token_registry.ts b/packages/website/ts/utils/fake_token_registry.ts index 0d5b3486a..607dd2553 100644 --- a/packages/website/ts/utils/fake_token_registry.ts +++ b/packages/website/ts/utils/fake_token_registry.ts @@ -694,7 +694,7 @@ export const fakeTokenRegistry: { [networkId: string]: FakeTokenRegistryEntry[] ], '42': [ { - address: '0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa', + address: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', name: '0x Protocol Token', symbol: 'ZRX', decimals: 18, @@ -858,7 +858,7 @@ export const fakeTokenRegistry: { [networkId: string]: FakeTokenRegistryEntry[] decimals: 19, }, { - address: '0xff67881f8d12f372d91baae9752eb3631ff0ed00', + address: '0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d', name: '0x Protocol Token', symbol: 'ZRX', decimals: 18, -- cgit From 4dfbc6747e6f866f9fd76eecf75c6f0ad91dbe9f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 20:08:22 +0200 Subject: Fix links --- packages/website/md/docs/json_schemas/2/schemas.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'packages') diff --git a/packages/website/md/docs/json_schemas/2/schemas.md b/packages/website/md/docs/json_schemas/2/schemas.md index ec7cf6f15..c3d6bdbc3 100644 --- a/packages/website/md/docs/json_schemas/2/schemas.md +++ b/packages/website/md/docs/json_schemas/2/schemas.md @@ -1,8 +1,8 @@ Basic Schemas -* [Address type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/address.json) -* [Number type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/number.json) -* [Hex type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/hex.json) +* [Address type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/address_schema.json) +* [Number type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/number_schema.json) +* [Hex type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/hex_schema.json) * [JS number](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/js_number.json) 0x Protocol Schemas @@ -18,7 +18,7 @@ Basic Schemas * [BlockRange](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/block_range_schema.json) * [IndexFilter Values](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/index_filter_values_schema.json) * [OrderFillRequests](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_fill_requests_schema.json) -* [OrderCancellationRequests](https://github.com/0xProjet/0x-monorepo/blob/development/packages/json-schemas/schemas/order_cancel_schema.json) +* [OrderCancellationRequests](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_cancel_schema.json) * [OrderFillOrKillRequests](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json) * [SignedOrders](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/signed_orders_schema.json) * [Token](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/token_schema.json) @@ -34,7 +34,7 @@ Standard Relayer API Schemas * [Orders channel subscribe](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_schema.json) * [Orders channel update](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orders_channel_update_response_schema.json) * [Orderbook response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.json) -* [Asset pairs](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_pairs_schema.json) -* [Trade info](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_trade_info_schema.json) -* [Asset pairs response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_pairs_response_schema.json) +* [Asset pairs](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_data_pairs_schema.json) +* [Trade info](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json) +* [Asset pairs response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_data_pairs_response_schema.json) * [Fee recipients response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.json) -- cgit From 24b5b35a749bc985c3d0b73844a70a2fdb37d942 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 20:22:51 +0200 Subject: chore: link to schemas at a particular commit so it doesn't change when they are updated --- packages/website/md/docs/json_schemas/2/schemas.md | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'packages') diff --git a/packages/website/md/docs/json_schemas/2/schemas.md b/packages/website/md/docs/json_schemas/2/schemas.md index c3d6bdbc3..8ea6c8e85 100644 --- a/packages/website/md/docs/json_schemas/2/schemas.md +++ b/packages/website/md/docs/json_schemas/2/schemas.md @@ -1,40 +1,40 @@ Basic Schemas -* [Address type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/address_schema.json) -* [Number type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/number_schema.json) -* [Hex type](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/hex_schema.json) -* [JS number](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/js_number.json) +* [Address type](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/address_schema.json) +* [Number type](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/number_schema.json) +* [Hex type](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/hex_schema.json) +* [JS number](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/js_number.json) 0x Protocol Schemas -* [Order](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_schema.json) -* [SignedOrder](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/signed_order_schema.json) -* [OrderHash](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_hash_schema.json) -* [ECSignature](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/ec_signature_schema.json) +* [Order](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/order_schema.json) +* [SignedOrder](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/signed_order_schema.json) +* [OrderHash](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/order_hash_schema.json) +* [ECSignature](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/ec_signature_schema.json) 0x.js Schemas -* [BlockParam](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/block_param_schema.json) -* [BlockRange](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/block_range_schema.json) -* [IndexFilter Values](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/index_filter_values_schema.json) -* [OrderFillRequests](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_fill_requests_schema.json) -* [OrderCancellationRequests](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_cancel_schema.json) -* [OrderFillOrKillRequests](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json) -* [SignedOrders](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/signed_orders_schema.json) -* [Token](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/token_schema.json) -* [TxData](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/tx_data_schema.json) +* [BlockParam](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/block_param_schema.json) +* [BlockRange](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/block_range_schema.json) +* [IndexFilter Values](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/index_filter_values_schema.json) +* [OrderFillRequests](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/order_fill_requests_schema.json) +* [OrderCancellationRequests](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/order_cancel_schema.json) +* [OrderFillOrKillRequests](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json) +* [SignedOrders](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/signed_orders_schema.json) +* [Token](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/token_schema.json) +* [TxData](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/tx_data_schema.json) Standard Relayer API Schemas -* [Paginated collection](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/paginated_collection_schema.json) -* [Error response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_error_response_schema.json) -* [Order config payload](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json) -* [Order config response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json) -* [Orders channel subscribe payload](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_payload_schema.json) -* [Orders channel subscribe](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_schema.json) -* [Orders channel update](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orders_channel_update_response_schema.json) -* [Orderbook response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.json) -* [Asset pairs](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_data_pairs_schema.json) -* [Trade info](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json) -* [Asset pairs response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_asset_data_pairs_response_schema.json) -* [Fee recipients response](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.json) +* [Paginated collection](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/paginated_collection_schema.json) +* [Error response](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_error_response_schema.json) +* [Order config payload](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json) +* [Order config response](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json) +* [Orders channel subscribe payload](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_payload_schema.json) +* [Orders channel subscribe](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_schema.json) +* [Orders channel update](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_orders_channel_update_response_schema.json) +* [Orderbook response](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.json) +* [Asset pairs](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_asset_data_pairs_schema.json) +* [Trade info](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json) +* [Asset pairs response](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_asset_data_pairs_response_schema.json) +* [Fee recipients response](https://github.com/0xProject/0x-monorepo/blob/5ec4b27200297708298deca97603849a37b2f66a/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.json) -- cgit From 01f82ddf789f4f747816d6f766ffae9fb61e180e Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 20:24:38 +0200 Subject: chore: Add whole number to next json-schema doc md section --- packages/website/md/docs/json_schemas/3/schemas.md | 41 ++++++++++++++++++++++ .../ts/containers/json_schemas_documentation.ts | 17 ++++++--- 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 packages/website/md/docs/json_schemas/3/schemas.md (limited to 'packages') diff --git a/packages/website/md/docs/json_schemas/3/schemas.md b/packages/website/md/docs/json_schemas/3/schemas.md new file mode 100644 index 000000000..99aff7b5a --- /dev/null +++ b/packages/website/md/docs/json_schemas/3/schemas.md @@ -0,0 +1,41 @@ +Basic Schemas + +* [Address type](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/address_schema.json) +* [Number type](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/number_schema.json) +* [Whole number type](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/whole_number_schema.json) +* [Hex type](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/hex_schema.json) +* [JS number](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/js_number.json) + +0x Protocol Schemas + +* [Order](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/order_schema.json) +* [SignedOrder](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/signed_order_schema.json) +* [OrderHash](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/order_hash_schema.json) +* [ECSignature](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/ec_signature_schema.json) + +0x.js Schemas + +* [BlockParam](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/block_param_schema.json) +* [BlockRange](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/block_range_schema.json) +* [IndexFilter Values](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/index_filter_values_schema.json) +* [OrderFillRequests](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/order_fill_requests_schema.json) +* [OrderCancellationRequests](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/order_cancel_schema.json) +* [OrderFillOrKillRequests](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.json) +* [SignedOrders](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/signed_orders_schema.json) +* [Token](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/token_schema.json) +* [TxData](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/tx_data_schema.json) + +Standard Relayer API Schemas + +* [Paginated collection](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/paginated_collection_schema.json) +* [Error response](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_error_response_schema.json) +* [Order config payload](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_order_config_payload_schema.json) +* [Order config response](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_order_config_response_schema.json) +* [Orders channel subscribe payload](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_payload_schema.json) +* [Orders channel subscribe](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_orders_channel_subscribe_schema.json) +* [Orders channel update](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_orders_channel_update_response_schema.json) +* [Orderbook response](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.json) +* [Asset pairs](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_asset_data_pairs_schema.json) +* [Trade info](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_asset_data_trade_info_schema.json) +* [Asset pairs response](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_asset_data_pairs_response_schema.json) +* [Fee recipients response](https://github.com/0xProject/0x-monorepo/blob/528ae4376e5e605dac9666f2a5917803e942a1f9/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.json) diff --git a/packages/website/ts/containers/json_schemas_documentation.ts b/packages/website/ts/containers/json_schemas_documentation.ts index cb5918784..9c4bb8e26 100644 --- a/packages/website/ts/containers/json_schemas_documentation.ts +++ b/packages/website/ts/containers/json_schemas_documentation.ts @@ -15,8 +15,9 @@ const InstallationMarkdown1 = require('md/docs/json_schemas/1/installation'); const InstallationMarkdown3 = require('md/docs/json_schemas/3/installation'); const usageMarkdown1 = require('md/docs/json_schemas/1/usage'); const usageMarkdown3 = require('md/docs/json_schemas/3/usage'); -const SchemasMarkdownV1 = require('md/docs/json_schemas/1/schemas'); -const SchemasMarkdownV2 = require('md/docs/json_schemas/2/schemas'); +const SchemasMarkdown1 = require('md/docs/json_schemas/1/schemas'); +const SchemasMarkdown2 = require('md/docs/json_schemas/2/schemas'); +const SchemasMarkdown3 = require('md/docs/json_schemas/3/schemas'); /* tslint:enable:no-var-requires */ const markdownSections = { @@ -40,19 +41,25 @@ const docsInfoConfig: DocsInfoConfig = { '0.0.1': { [markdownSections.introduction]: IntroMarkdown1, [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.schemas]: SchemasMarkdownV1, + [markdownSections.schemas]: SchemasMarkdown1, [markdownSections.usage]: usageMarkdown1, }, '1.0.0': { [markdownSections.introduction]: IntroMarkdown1, [markdownSections.installation]: InstallationMarkdown1, - [markdownSections.schemas]: SchemasMarkdownV2, + [markdownSections.schemas]: SchemasMarkdown2, [markdownSections.usage]: usageMarkdown1, }, '2.0.0': { [markdownSections.introduction]: IntroMarkdown3, [markdownSections.installation]: InstallationMarkdown3, - [markdownSections.schemas]: SchemasMarkdownV2, + [markdownSections.schemas]: SchemasMarkdown2, + [markdownSections.usage]: usageMarkdown3, + }, + '2.0.1': { + [markdownSections.introduction]: IntroMarkdown3, + [markdownSections.installation]: InstallationMarkdown3, + [markdownSections.schemas]: SchemasMarkdown3, [markdownSections.usage]: usageMarkdown3, }, }, -- cgit From 39c7f3dc88d5e43399e055a2535ce2cddb560f4c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 20:30:53 +0200 Subject: chore: fix file name --- packages/json-schemas/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index 76d2cf240..7b14166c0 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -44,6 +44,6 @@ "./schemas/zero_ex_transaction_schema.json", "./schemas/tx_data_schema.json", "./schemas/index_filter_values_schema.json", - "./schemas/wholeNumberSchema.json" + "./schemas/whole_number_schema.json" ] } -- cgit From dbf75a43c37af31858dfca4026ab12f0491c520f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 21 Oct 2018 20:31:35 +0200 Subject: Add wholeNumberSchema test --- packages/json-schemas/test/schema_test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'packages') diff --git a/packages/json-schemas/test/schema_test.ts b/packages/json-schemas/test/schema_test.ts index 795261ef2..bfa2c5668 100644 --- a/packages/json-schemas/test/schema_test.ts +++ b/packages/json-schemas/test/schema_test.ts @@ -36,6 +36,7 @@ const { relayerApiOrdersChannelUpdateSchema, relayerApiOrdersResponseSchema, relayerApiOrderSchema, + wholeNumberSchema, } = schemas; describe('Schema', () => { @@ -73,6 +74,17 @@ describe('Schema', () => { validateAgainstSchema(testCases, numberSchema, shouldFail); }); }); + describe('#wholeNumberSchema', () => { + it('should validate valid numbers', () => { + const testCases = ['5', '42', '0']; + validateAgainstSchema(testCases, wholeNumberSchema); + }); + it('should fail for invalid numbers', () => { + const testCases = ['1.3', '0.2', '00.00', '.3', '1.', 'abacaba', 'и', '1..0']; + const shouldFail = true; + validateAgainstSchema(testCases, wholeNumberSchema, shouldFail); + }); + }); describe('#addressSchema', () => { it('should validate valid addresses', () => { const testCases = ['0x8b0292b11a196601ed2ce54b665cafeca0347d42', NULL_ADDRESS]; -- cgit From 2bb53d5b1df7cebaf6fd2e17640729f7401d7162 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 22 Oct 2018 10:56:11 -0700 Subject: fix(website): do not fetch balances for empty tokens --- packages/website/ts/components/portal/portal.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'packages') diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx index 2299881c4..94ab63ac6 100644 --- a/packages/website/ts/components/portal/portal.tsx +++ b/packages/website/ts/components/portal/portal.tsx @@ -210,12 +210,16 @@ export class Portal extends React.Component { isLoaded: false, }; } - this.setState({ - trackedTokenStateByAddress, - }); - // Fetch the actual balance/allowance. - // tslint:disable-next-line:no-floating-promises - this._fetchBalancesAndAllowancesAsync(newTokenAddresses); + this.setState( + { + trackedTokenStateByAddress, + }, + () => { + // Fetch the actual balance/allowance. + // tslint:disable-next-line:no-floating-promises + this._fetchBalancesAndAllowancesAsync(newTokenAddresses); + }, + ); } } public render(): React.ReactNode { @@ -644,6 +648,9 @@ export class Portal extends React.Component { } private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]): Promise { + if (_.isEmpty(tokenAddresses)) { + return; + } const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress; const balancesAndAllowances = await Promise.all( -- cgit From 1a3b1607b12cd75a1fc12ecd504dad61bef8d291 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 22 Oct 2018 10:56:39 -0700 Subject: fix(website): create correct subprovider for metamask --- packages/website/ts/blockchain.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index efb5aef23..62e16dd1d 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -163,7 +163,7 @@ export class Blockchain { const providerName = this._getNameGivenProvider(injectedWeb3.currentProvider); // Wrap Metamask in a compatability wrapper MetamaskSubprovider (to handle inconsistencies) const signerSubprovider = - providerName === Providers.Metamask + providerName === constants.PROVIDER_NAME_METAMASK ? new MetamaskSubprovider(injectedWeb3.currentProvider) : new SignerSubprovider(injectedWeb3.currentProvider); provider.addProvider(signerSubprovider); -- cgit From 15ed3b35df1103ac9b0b4104551ecff9559ddb9b Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 13:50:08 -0700 Subject: chore: change order of code to be clearer --- packages/instant/src/types.ts | 1 + packages/instant/src/util/asset.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 7323123c3..c340623ad 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -41,6 +41,7 @@ export interface ERC721Asset { assetData: string; metaData: ERC721AssetMetaData; } + export interface Asset { assetData: string; metaData: AssetMetaData; diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 4e3b2b946..bf6cd663d 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -16,10 +16,11 @@ export const assetUtils = { }; }, getMetaDataOrThrow: (assetData: string, metaDataMap: ObjectMap, network: Network): AssetMetaData => { - let mainnetAssetData: string | undefined = assetData; + let mainnetAssetData: string | undefined; if (network !== Network.Mainnet) { mainnetAssetData = assetUtils.getAssociatedAssetDataIfExists(assetData, network); } + mainnetAssetData = assetData; if (_.isUndefined(mainnetAssetData)) { throw new Error(ZeroExInstantError.AssetMetaDataNotAvailable); } -- cgit From 37c5165319d5962aedc683c105df446ce62cd72f Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 14:01:08 -0700 Subject: feat: add asset tests --- packages/instant/test/util/asset.test.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 packages/instant/test/util/asset.test.ts (limited to 'packages') diff --git a/packages/instant/test/util/asset.test.ts b/packages/instant/test/util/asset.test.ts new file mode 100644 index 000000000..9ca4a3d52 --- /dev/null +++ b/packages/instant/test/util/asset.test.ts @@ -0,0 +1,25 @@ +import { AssetProxyId } from '@0x/types'; + +import { Asset } from '../../src/types'; +import { assetUtils } from '../../src/util/asset'; + +const ZRX_ASSET_DATA = '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498'; +const ZRX_ASSET: Asset = { + assetData: ZRX_ASSET_DATA, + metaData: { + assetProxyId: AssetProxyId.ERC20, + symbol: 'zrx', + decimals: 18, + }, +}; + +describe('assetDataUtil', () => { + describe('bestNameForAsset', () => { + it('should return default string if assetData is undefined', () => { + expect(assetUtils.bestNameForAsset(undefined, 'xyz')).toEqual('xyz'); + }); + it('should return ZRX for ZRX assetData', () => { + expect(assetUtils.bestNameForAsset(ZRX_ASSET, 'mah default')).toEqual('ZRX'); + }); + }); +}); -- cgit From 48e4452a0442acb992c204ca1fbec36df1a75d6d Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 14:20:20 -0700 Subject: feat: add tests for assetUtils --- packages/instant/src/util/asset.ts | 3 +-- packages/instant/test/util/asset.test.ts | 36 +++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index bf6cd663d..4e3b2b946 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -16,11 +16,10 @@ export const assetUtils = { }; }, getMetaDataOrThrow: (assetData: string, metaDataMap: ObjectMap, network: Network): AssetMetaData => { - let mainnetAssetData: string | undefined; + let mainnetAssetData: string | undefined = assetData; if (network !== Network.Mainnet) { mainnetAssetData = assetUtils.getAssociatedAssetDataIfExists(assetData, network); } - mainnetAssetData = assetData; if (_.isUndefined(mainnetAssetData)) { throw new Error(ZeroExInstantError.AssetMetaDataNotAvailable); } diff --git a/packages/instant/test/util/asset.test.ts b/packages/instant/test/util/asset.test.ts index 9ca4a3d52..2c357d25c 100644 --- a/packages/instant/test/util/asset.test.ts +++ b/packages/instant/test/util/asset.test.ts @@ -1,16 +1,21 @@ -import { AssetProxyId } from '@0x/types'; +import { AssetData, AssetProxyId, ObjectMap } from '@0x/types'; -import { Asset } from '../../src/types'; +import { Asset, AssetMetaData, ERC20AssetMetaData, Network, ZeroExInstantError } from '../../src/types'; import { assetUtils } from '../../src/util/asset'; const ZRX_ASSET_DATA = '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498'; +const ZRX_ASSET_DATA_KOVAN = '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa'; +const ZRX_META_DATA: ERC20AssetMetaData = { + assetProxyId: AssetProxyId.ERC20, + symbol: 'zrx', + decimals: 18, +}; const ZRX_ASSET: Asset = { assetData: ZRX_ASSET_DATA, - metaData: { - assetProxyId: AssetProxyId.ERC20, - symbol: 'zrx', - decimals: 18, - }, + metaData: ZRX_META_DATA, +}; +const META_DATA_MAP: ObjectMap = { + [ZRX_ASSET_DATA]: ZRX_META_DATA, }; describe('assetDataUtil', () => { @@ -22,4 +27,21 @@ describe('assetDataUtil', () => { expect(assetUtils.bestNameForAsset(ZRX_ASSET, 'mah default')).toEqual('ZRX'); }); }); + describe('getMetaDataOrThrow', () => { + it('should return the metaData for the supplied mainnet asset data', () => { + expect(assetUtils.getMetaDataOrThrow(ZRX_ASSET_DATA, META_DATA_MAP, Network.Mainnet)).toEqual( + ZRX_META_DATA, + ); + }); + it('should return the metaData for the supplied non-mainnet asset data', () => { + expect(assetUtils.getMetaDataOrThrow(ZRX_ASSET_DATA_KOVAN, META_DATA_MAP, Network.Kovan)).toEqual( + ZRX_META_DATA, + ); + }); + it('should throw if the metaData for the asset is not available', () => { + expect(() => + assetUtils.getMetaDataOrThrow('asset data we dont have', META_DATA_MAP, Network.Mainnet), + ).toThrowError(ZeroExInstantError.AssetMetaDataNotAvailable); + }); + }); }); -- cgit From c5014af7fe7b06c01edfc677da48628d4972e298 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 15:27:35 -0700 Subject: chore: run linter --- packages/instant/test/util/asset.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/instant/test/util/asset.test.ts b/packages/instant/test/util/asset.test.ts index 2c357d25c..c7db7eba7 100644 --- a/packages/instant/test/util/asset.test.ts +++ b/packages/instant/test/util/asset.test.ts @@ -1,4 +1,4 @@ -import { AssetData, AssetProxyId, ObjectMap } from '@0x/types'; +import { AssetProxyId, ObjectMap } from '@0x/types'; import { Asset, AssetMetaData, ERC20AssetMetaData, Network, ZeroExInstantError } from '../../src/types'; import { assetUtils } from '../../src/util/asset'; -- cgit From 1ba207f1fef4338682b4cc7e45af8c073e63d263 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 22 Oct 2018 15:33:55 -0700 Subject: fix(website): asset-buyer usage documentation formatting --- packages/website/md/docs/asset_buyer/installation.md | 4 ++-- packages/website/md/docs/asset_buyer/usage.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'packages') diff --git a/packages/website/md/docs/asset_buyer/installation.md b/packages/website/md/docs/asset_buyer/installation.md index 76affaa09..3c0c95068 100644 --- a/packages/website/md/docs/asset_buyer/installation.md +++ b/packages/website/md/docs/asset_buyer/installation.md @@ -1,10 +1,10 @@ -**Install** +#### Install ```bash yarn add @0x/asset-buyer ``` -**Import** +#### Import ```javascript import { AssetBuyer } from '@0x/asset-buyer'; diff --git a/packages/website/md/docs/asset_buyer/usage.md b/packages/website/md/docs/asset_buyer/usage.md index 6462d938e..209c15062 100644 --- a/packages/website/md/docs/asset_buyer/usage.md +++ b/packages/website/md/docs/asset_buyer/usage.md @@ -1,4 +1,4 @@ -**Construction** +#### Construction Connecting to a standard relayer API compliant url: @@ -16,7 +16,7 @@ const orders = []; // get these from your own API, a relayer, a friend, from any const assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, orders); ``` -**Get a quote** +#### Get a quote A [BuyQuote](#types-BuyQuote) object contains enough information to display buy information to an end user @@ -30,7 +30,7 @@ console.log(quoteInfo.feeAmount); // a portion of the total ethAmount above that console.log(quoteInfo.ethPerAssetPrice); // the rate that this quote provides (e.g. 0.0035ETH / REP) ``` -**Perform a buy** +#### Perform a buy Pass the [BuyQuote](#types-BuyQuote) object from above back to the assetBuyer in order to initiate the buy transaction -- cgit From b75fe10c790a60c875914a2a79ae8c4761b78bb9 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 17 Oct 2018 00:49:48 -0700 Subject: feat(contract-wrappers): export ForwarderWrapperError and ContractWrapperError.SignatureRequestDenied --- packages/contract-wrappers/CHANGELOG.json | 8 ++++++++ packages/contract-wrappers/src/index.ts | 1 + packages/contract-wrappers/src/types.ts | 5 +++++ packages/contract-wrappers/src/utils/constants.ts | 1 + packages/contract-wrappers/src/utils/decorators.ts | 14 +++++++++++++- 5 files changed, 28 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index f66be3f0a..c3d986b4a 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -37,6 +37,14 @@ "note": "Removed ContractNotFound errors. Checking for this error was somewhat ineffecient. Relevant methods/functions now return the default error from web3-wrapper, which we feel provides enough information.", "pr": 1105 + }, + { + "note": "Add `ForwarderWrapperError` to public interface", + "pr": 1147 + }, + { + "note": "Add `ContractWrapperError.SignatureRequestDenied` to public interface", + "pr": 1147 } ], "timestamp": 1539871071 diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index a38bd122b..d66ff5c9c 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -39,6 +39,7 @@ export { TransactionEncoder } from './utils/transaction_encoder'; export { ContractWrappersError, + ForwarderWrapperError, IndexedFilterValues, BlockRange, ContractWrappersConfig, diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 60750179f..5a5bdd530 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -18,6 +18,10 @@ export enum ExchangeWrapperError { AssetDataMismatch = 'ASSET_DATA_MISMATCH', } +export enum ForwarderWrapperError { + CompleteFillFailed = 'COMPLETE_FILL_FAILED', +} + export enum ContractWrappersError { ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK', InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', @@ -30,6 +34,7 @@ export enum ContractWrappersError { SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT', ERC721OwnerNotFound = 'ERC_721_OWNER_NOT_FOUND', ERC721NoApproval = 'ERC_721_NO_APPROVAL', + SignatureRequestDenied = 'SIGNATURE_REQUEST_DENIED', } export enum InternalContractWrappersError { diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts index 9ff61f62a..b89438592 100644 --- a/packages/contract-wrappers/src/utils/constants.ts +++ b/packages/contract-wrappers/src/utils/constants.ts @@ -14,4 +14,5 @@ export const constants = { ZERO_AMOUNT: new BigNumber(0), ONE_AMOUNT: new BigNumber(1), ETHER_TOKEN_DECIMALS: 18, + METAMASK_DENIED_SIGNATURE_PATTERN: 'MetaMask Tx Signature: User denied transaction signature', }; diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts index e17246015..932b11785 100644 --- a/packages/contract-wrappers/src/utils/decorators.ts +++ b/packages/contract-wrappers/src/utils/decorators.ts @@ -29,6 +29,14 @@ const schemaErrorTransformer = (error: Error) => { return error; }; +const signatureRequestErrorTransformer = (error: Error) => { + if (_.includes(error.message, constants.METAMASK_DENIED_SIGNATURE_PATTERN)) { + const errMsg = ContractWrappersError.SignatureRequestDenied; + return new Error(errMsg); + } + return error; +}; + /** * Source: https://stackoverflow.com/a/29837695/3546986 */ @@ -87,7 +95,11 @@ const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => { }; // _.flow(f, g) = f ∘ g -const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer); +const zeroExErrorTransformer = _.flow( + schemaErrorTransformer, + contractCallErrorTransformer, + signatureRequestErrorTransformer, +); export const decorators = { asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer), -- cgit From 1f0c7f8fbeba90ac1f65c57ff58782051c751b3d Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Tue, 23 Oct 2018 12:08:16 -0400 Subject: feat(order_utils.py): ERC20 asset data encoding and decoding In addition to the ERC20 codec, also: Stopped ignoring type errors on 3rd party imports, by including interface stubs for them; Removed the unimplemented signature-utils module, which was just a stand-in when the python project support was first put in place. https://github.com/0xProject/0x-monorepo/pull/1144 --- packages/order-utils/test/asset_data_utils_test.ts | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 packages/order-utils/test/asset_data_utils_test.ts (limited to 'packages') diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts new file mode 100644 index 000000000..f8b850604 --- /dev/null +++ b/packages/order-utils/test/asset_data_utils_test.ts @@ -0,0 +1,31 @@ +import * as chai from 'chai'; + +import { ERC20AssetData } from '@0x/types'; + +import { assetDataUtils } from '../src/asset_data_utils'; + +import { chaiSetup } from './utils/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +const KNOWN_ENCODINGS = [ + { + address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', + assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48', + }, +]; + +const ERC20_ASSET_PROXY_ID = '0xf47261b0'; + +describe('assetDataUtils', () => { + it('should encode', () => { + const assetData = assetDataUtils.encodeERC20AssetData(KNOWN_ENCODINGS[0].address); + expect(assetData).to.equal(KNOWN_ENCODINGS[0].assetData); + }); + it('should decode', () => { + const assetData: ERC20AssetData = assetDataUtils.decodeERC20AssetData(KNOWN_ENCODINGS[0].assetData); + expect(assetData.tokenAddress).to.equal(KNOWN_ENCODINGS[0].address); + expect(assetData.assetProxyId).to.equal(ERC20_ASSET_PROXY_ID); + }); +}); -- cgit From e086c7b8e637fd57160273c69e27222ae8586a29 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 15 Oct 2018 17:52:51 -0700 Subject: Round up for Market Buys in Forwarding Contract. Includes new test cases + regression testing. --- .../extensions/Forwarder/MixinExchangeWrapper.sol | 12 +- packages/contracts/test/extensions/forwarder.ts | 267 ++++++++++++++++++++- packages/contracts/test/utils/forwarder_wrapper.ts | 9 +- 3 files changed, 280 insertions(+), 8 deletions(-) (limited to 'packages') diff --git a/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol b/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol index fea9a53c2..4991c0ea5 100644 --- a/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol +++ b/packages/contracts/contracts/extensions/Forwarder/MixinExchangeWrapper.sol @@ -155,8 +155,10 @@ contract MixinExchangeWrapper is uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount); // Convert the remaining amount of makerAsset to buy into remaining amount - // of takerAsset to sell, assuming entire amount can be sold in the current order - uint256 remainingTakerAssetFillAmount = getPartialAmountFloor( + // of takerAsset to sell, assuming entire amount can be sold in the current order. + // We round up because the exchange rate computed by fillOrder rounds in favor + // of the Maker. In this case we want to overestimate the amount of takerAsset. + uint256 remainingTakerAssetFillAmount = getPartialAmountCeil( orders[i].takerAssetAmount, orders[i].makerAssetAmount, remainingMakerAssetFillAmount @@ -224,7 +226,9 @@ contract MixinExchangeWrapper is // Convert the remaining amount of ZRX to buy into remaining amount // of WETH to sell, assuming entire amount can be sold in the current order. - uint256 remainingWethSellAmount = getPartialAmountFloor( + // We round up because the exchange rate computed by fillOrder rounds in favor + // of the Maker. In this case we want to overestimate the amount of takerAsset. + uint256 remainingWethSellAmount = getPartialAmountCeil( orders[i].takerAssetAmount, safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees remainingZrxBuyAmount @@ -233,7 +237,7 @@ contract MixinExchangeWrapper is // Attempt to sell the remaining amount of WETH. FillResults memory singleFillResult = fillOrderNoThrow( orders[i], - safeAdd(remainingWethSellAmount, 1), // we add 1 wei to the fill amount to make up for rounding errors + remainingWethSellAmount, signatures[i] ); diff --git a/packages/contracts/test/extensions/forwarder.ts b/packages/contracts/test/extensions/forwarder.ts index b76624fa9..0c4a06373 100644 --- a/packages/contracts/test/extensions/forwarder.ts +++ b/packages/contracts/test/extensions/forwarder.ts @@ -45,6 +45,7 @@ describe(ContractName.Forwarder, () => { let weth: DummyERC20TokenContract; let zrxToken: DummyERC20TokenContract; + let erc20TokenA: DummyERC20TokenContract; let erc721Token: DummyERC721TokenContract; let forwarderContract: ForwarderContract; let wethContract: WETH9Contract; @@ -77,7 +78,6 @@ describe(ContractName.Forwarder, () => { erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); const numDummyErc20ToDeploy = 3; - let erc20TokenA; [erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync( numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS, @@ -902,6 +902,271 @@ describe(ContractName.Forwarder, () => { ); expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); }); + it('Should buy slightly greater MakerAsset when exchange rate is rounded', async () => { + // The 0x Protocol contracts round the exchange rate in favor of the Maker. + // In this case, the taker must round up how much they're going to spend, which + // in turn increases the amount of MakerAsset being purchased. + // Example: + // The taker wants to buy 5 units of the MakerAsset at a rate of 3M/2T. + // For every 2 units of TakerAsset, the taker will receive 3 units of MakerAsset. + // To purchase 5 units, the taker must spend 10/3 = 3.33 units of TakerAssset. + // However, the Taker can only spend whole units. + // Spending floor(10/3) = 3 units will yield a profit of Floor(3*3/2) = Floor(4.5) = 4 units of MakerAsset. + // Spending ceil(10/3) = 4 units will yield a profit of Floor(4*3/2) = 6 units of MakerAsset. + // + // The forwarding contract will opt for the second option, which overbuys, to ensure the taker + // receives at least the amount of MakerAsset they requested. + // + // Construct test case using values from example above + orderWithoutFee = await orderFactory.newSignedOrderAsync({ + makerAssetAmount: new BigNumber('30'), + takerAssetAmount: new BigNumber('20'), + makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address), + takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + }); + const ordersWithoutFee = [orderWithoutFee]; + const feeOrders: SignedOrder[] = []; + const desiredMakerAssetFillAmount = new BigNumber('5'); + const makerAssetFillAmount = new BigNumber('6'); + const ethValue = new BigNumber('4'); + // Execute test case + tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( + ordersWithoutFee, + feeOrders, + desiredMakerAssetFillAmount, + { + value: ethValue, + from: takerAddress, + }, + ); + // Fetch end balances and construct expected outputs + const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); + const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const primaryTakerAssetFillAmount = ethValue; + const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); + // Validate test case + expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); + expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); + expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), + ); + expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), + ); + expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); + expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( + constants.ZERO_AMOUNT, + ); + expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX', async () => { + // See the test case above for a detailed description of this case. + // The difference here is that the MakerAsset is ZRX. We expect the same result as above, + // but this tests a different code path. + // + // Construct test case using values from example above + orderWithoutFee = await orderFactory.newSignedOrderAsync({ + makerAssetAmount: new BigNumber('30'), + takerAssetAmount: new BigNumber('20'), + makerAssetData: zrxAssetData, + takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + }); + const ordersWithoutFee = [orderWithoutFee]; + const feeOrders: SignedOrder[] = []; + const desiredMakerAssetFillAmount = new BigNumber('5'); + const makerAssetFillAmount = new BigNumber('6'); + const ethValue = new BigNumber('4'); + // Execute test case + tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( + ordersWithoutFee, + feeOrders, + desiredMakerAssetFillAmount, + { + value: ethValue, + from: takerAddress, + }, + ); + // Fetch end balances and construct expected outputs + const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); + const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const primaryTakerAssetFillAmount = ethValue; + const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); + // Validate test case + expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); + expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); + expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount), + ); + expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount), + ); + expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), + ); + expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); + expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => { + // Order taken from a transaction on mainnet that failed due to a rounding error. +- // tx=0x3d22b18fe2615c1903408b1b969744bcd117becc30205df18d5c5c54d27d1237 + orderWithoutFee = await orderFactory.newSignedOrderAsync({ + makerAssetAmount: new BigNumber('268166666666666666666'), + takerAssetAmount: new BigNumber('219090625878836371'), + makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address), + takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + }); + const ordersWithoutFee = [orderWithoutFee]; + const feeOrders: SignedOrder[] = []; + // The taker will receive more than the desired amount of makerAsset due to rounding + const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000'); + const ethValue = new BigNumber('4084971271824171'); + const makerAssetFillAmount = ethValue + .times(orderWithoutFee.makerAssetAmount) + .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); + // Execute test case + tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( + ordersWithoutFee, + feeOrders, + desiredMakerAssetFillAmount, + { + value: ethValue, + from: takerAddress, + }, + ); + // Fetch end balances and construct expected outputs + const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); + const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const primaryTakerAssetFillAmount = ethValue; + const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); + // Validate test case + expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); + expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); + expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), + ); + expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( + erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount), + ); + expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), + ); + expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); + expect(newBalances[forwarderContract.address][defaultMakerAssetAddress]).to.be.bignumber.equal( + constants.ZERO_AMOUNT, + ); + expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX (Regression Test)', async () => { + // Order taken from a transaction on mainnet that failed due to a rounding error. +- // tx=0x3d22b18fe2615c1903408b1b969744bcd117becc30205df18d5c5c54d27d1237 + orderWithoutFee = await orderFactory.newSignedOrderAsync({ + makerAssetAmount: new BigNumber('268166666666666666666'), + takerAssetAmount: new BigNumber('219090625878836371'), + makerAssetData: zrxAssetData, + takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + }); + const ordersWithoutFee = [orderWithoutFee]; + const feeOrders: SignedOrder[] = []; + // The taker will receive more than the desired amount of makerAsset due to rounding + const desiredMakerAssetFillAmount = new BigNumber('5000000000000000000'); + const ethValue = new BigNumber('4084971271824171'); + const makerAssetFillAmount = ethValue + .times(orderWithoutFee.makerAssetAmount) + .dividedToIntegerBy(orderWithoutFee.takerAssetAmount); + // Execute test case + tx = await forwarderWrapper.marketBuyOrdersWithEthAsync( + ordersWithoutFee, + feeOrders, + desiredMakerAssetFillAmount, + { + value: ethValue, + from: takerAddress, + }, + ); + // Fetch end balances and construct expected outputs + const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); + const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const primaryTakerAssetFillAmount = ethValue; + const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); + // Validate test case + expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount); + expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); + expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount), + ); + expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount), + ); + expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), + ); + expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); + expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('Should buy correct MakerAsset when exchange rate is NOT rounded, and MakerAsset is ZRX (Regression Test)', async () => { + // An extra unit of TakerAsset was sent to the exchange contract to account for rounding errors, in Forwarder v1. + // Specifically, the takerFillAmount was calculated using Floor(desiredMakerAmount * exchangeRate) + 1 + // We have since changed this to be Ceil(desiredMakerAmount * exchangeRate) + // These calculations produce different results when `desiredMakerAmount * exchangeRate` is an integer. + // + // This test verifies that `ceil` is sufficient: + // Let TakerAssetAmount = MakerAssetAmount * 2 + // -> exchangeRate = TakerAssetAmount / MakerAssetAmount = (2*MakerAssetAmount)/MakerAssetAmount = 2 + // .: desiredMakerAmount * exchangeRate is an integer. + // + // Construct test case using values from example above + orderWithoutFee = await orderFactory.newSignedOrderAsync({ + makerAssetAmount: new BigNumber('30'), + takerAssetAmount: new BigNumber('60'), + makerAssetData: zrxAssetData, + takerAssetData: assetDataUtils.encodeERC20AssetData(weth.address), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + }); + const ordersWithoutFee = [orderWithoutFee]; + const feeOrders: SignedOrder[] = []; + const makerAssetFillAmount = new BigNumber('5'); + const ethValue = new BigNumber('10'); + // Execute test case + tx = await forwarderWrapper.marketBuyOrdersWithEthAsync(ordersWithoutFee, feeOrders, makerAssetFillAmount, { + value: ethValue, + from: takerAddress, + }); + // Fetch end balances and construct expected outputs + const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(takerAddress); + const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(forwarderContract.address); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const primaryTakerAssetFillAmount = ethValue; + const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed)); + // Validate test case + expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent)); + expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][zrxToken.address].minus(makerAssetFillAmount), + ); + expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( + erc20Balances[takerAddress][zrxToken.address].plus(makerAssetFillAmount), + ); + expect(newBalances[makerAddress][weth.address]).to.be.bignumber.equal( + erc20Balances[makerAddress][weth.address].plus(primaryTakerAssetFillAmount), + ); + expect(newBalances[forwarderContract.address][weth.address]).to.be.bignumber.equal(constants.ZERO_AMOUNT); + expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT); + }); }); describe('marketBuyOrdersWithEth with extra fees', () => { it('should buy an asset and send fee to feeRecipient', async () => { diff --git a/packages/contracts/test/utils/forwarder_wrapper.ts b/packages/contracts/test/utils/forwarder_wrapper.ts index f1a64d47d..a0bfcfe1d 100644 --- a/packages/contracts/test/utils/forwarder_wrapper.ts +++ b/packages/contracts/test/utils/forwarder_wrapper.ts @@ -26,9 +26,12 @@ export class ForwarderWrapper { _.forEach(feeOrders, feeOrder => { const feeAvailable = feeOrder.makerAssetAmount.minus(feeOrder.takerFee); if (!remainingFeeAmount.isZero() && feeAvailable.gt(remainingFeeAmount)) { - wethAmount = wethAmount - .plus(feeOrder.takerAssetAmount.times(remainingFeeAmount).dividedToIntegerBy(feeAvailable)) - .plus(1); + wethAmount = wethAmount.plus( + feeOrder.takerAssetAmount + .times(remainingFeeAmount) + .dividedBy(feeAvailable) + .ceil(), + ); remainingFeeAmount = new BigNumber(0); } else if (!remainingFeeAmount.isZero()) { wethAmount = wethAmount.plus(feeOrder.takerAssetAmount); -- cgit From dcd428a4a299de0daf6bbfb8e8a7c15685b673cf Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 17 Oct 2018 09:54:41 -0700 Subject: feat(monorepo-scripts): add ForwarderWrapperError to IGNORED_EXCESSIVE_TYPES in docGenConfigs --- packages/monorepo-scripts/CHANGELOG.json | 4 ++++ packages/monorepo-scripts/src/doc_gen_configs.ts | 1 + 2 files changed, 5 insertions(+) (limited to 'packages') diff --git a/packages/monorepo-scripts/CHANGELOG.json b/packages/monorepo-scripts/CHANGELOG.json index 4797fd929..170a97a33 100644 --- a/packages/monorepo-scripts/CHANGELOG.json +++ b/packages/monorepo-scripts/CHANGELOG.json @@ -9,6 +9,10 @@ { "note": "Add AssetBuyerError to the IGNORED_EXCESSIVE_TYPES array", "pr": 1139 + }, + { + "note": "Add ForwarderError to the IGNORED_EXCESSIVE_TYPES array", + "pr": 1147 } ] }, diff --git a/packages/monorepo-scripts/src/doc_gen_configs.ts b/packages/monorepo-scripts/src/doc_gen_configs.ts index 0aaf5a6a5..7a14f8664 100644 --- a/packages/monorepo-scripts/src/doc_gen_configs.ts +++ b/packages/monorepo-scripts/src/doc_gen_configs.ts @@ -56,6 +56,7 @@ export const docGenConfigs: DocGenConfigs = { 'ContractWrappersError', 'OrderError', 'AssetBuyerError', + 'ForwarderWrapperError', ], // Some libraries only export types. In those cases, we cannot check if the exported types are part of the // "exported public interface". Thus we add them here and skip those checks. -- cgit From 117ee19370e56f3559b9b11b04becc5ad9c7d634 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 17 Oct 2018 10:03:46 -0700 Subject: feat(asset-buyer): throw SignatureRequestDenied and TransactionValueTooLow errors when executing buy --- packages/asset-buyer/CHANGELOG.json | 4 +++ packages/asset-buyer/src/asset_buyer.ts | 43 +++++++++++++++++++++------------ packages/asset-buyer/src/types.ts | 2 ++ 3 files changed, 33 insertions(+), 16 deletions(-) (limited to 'packages') diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index 5ebe2aa24..7ebcd8c2f 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -25,6 +25,10 @@ { "note": "Add missing types to public interface", "pr": 1139 + }, + { + "note": "Throw `SignatureRequestDenied` and `TransactionValueTooLow` errors when executing buy", + "pr": 1147 } ], "timestamp": 1539871071 diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts index 2fe8f6deb..2f9a3108e 100644 --- a/packages/asset-buyer/src/asset_buyer.ts +++ b/packages/asset-buyer/src/asset_buyer.ts @@ -1,4 +1,4 @@ -import { ContractWrappers } from '@0x/contract-wrappers'; +import { ContractWrappers, ContractWrappersError, ForwarderWrapperError } from '@0x/contract-wrappers'; import { schemas } from '@0x/json-schemas'; import { SignedOrder } from '@0x/order-utils'; import { ObjectMap } from '@0x/types'; @@ -210,21 +210,32 @@ export class AssetBuyer { throw new Error(AssetBuyerError.NoAddressAvailable); } } - // if no ethAmount is provided, default to the worst ethAmount from buyQuote - const txHash = await this._contractWrappers.forwarder.marketBuyOrdersWithEthAsync( - orders, - assetBuyAmount, - finalTakerAddress, - ethAmount || worstCaseQuoteInfo.totalEthAmount, - feeOrders, - feePercentage, - feeRecipient, - { - gasLimit, - gasPrice, - }, - ); - return txHash; + try { + // if no ethAmount is provided, default to the worst ethAmount from buyQuote + const txHash = await this._contractWrappers.forwarder.marketBuyOrdersWithEthAsync( + orders, + assetBuyAmount, + finalTakerAddress, + ethAmount || worstCaseQuoteInfo.totalEthAmount, + feeOrders, + feePercentage, + feeRecipient, + { + gasLimit, + gasPrice, + shouldValidate: true, + }, + ); + return txHash; + } catch (err) { + if (_.includes(err.message, ContractWrappersError.SignatureRequestDenied)) { + throw new Error(AssetBuyerError.SignatureRequestDenied); + } else if (_.includes(err.message, ForwarderWrapperError.CompleteFillFailed)) { + throw new Error(AssetBuyerError.TransactionValueTooLow); + } else { + throw err; + } + } } /** * Grab orders from the map, if there is a miss or it is time to refresh, fetch and process the orders diff --git a/packages/asset-buyer/src/types.ts b/packages/asset-buyer/src/types.ts index 0d8e732d7..f15e7e934 100644 --- a/packages/asset-buyer/src/types.ts +++ b/packages/asset-buyer/src/types.ts @@ -112,6 +112,8 @@ export enum AssetBuyerError { NoAddressAvailable = 'NO_ADDRESS_AVAILABLE', InvalidOrderProviderResponse = 'INVALID_ORDER_PROVIDER_RESPONSE', AssetUnavailable = 'ASSET_UNAVAILABLE', + SignatureRequestDenied = 'SIGNATURE_REQUEST_DENIED', + TransactionValueTooLow = 'TRANSACTION_VALUE_TOO_LOW', } export interface OrdersAndFillableAmounts { -- cgit From af2bf053bc9cfe80618109dc10a90515d780cd25 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Mon, 22 Oct 2018 22:23:32 -0700 Subject: feat(contract-wrappers): relax requirement for throwing `ContractWrappersError.SignatureRequestDenied` --- packages/contract-wrappers/src/utils/constants.ts | 2 +- packages/contract-wrappers/src/utils/decorators.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts index b89438592..c587ba526 100644 --- a/packages/contract-wrappers/src/utils/constants.ts +++ b/packages/contract-wrappers/src/utils/constants.ts @@ -14,5 +14,5 @@ export const constants = { ZERO_AMOUNT: new BigNumber(0), ONE_AMOUNT: new BigNumber(1), ETHER_TOKEN_DECIMALS: 18, - METAMASK_DENIED_SIGNATURE_PATTERN: 'MetaMask Tx Signature: User denied transaction signature', + USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature', }; diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts index 932b11785..a4207ae4c 100644 --- a/packages/contract-wrappers/src/utils/decorators.ts +++ b/packages/contract-wrappers/src/utils/decorators.ts @@ -30,7 +30,7 @@ const schemaErrorTransformer = (error: Error) => { }; const signatureRequestErrorTransformer = (error: Error) => { - if (_.includes(error.message, constants.METAMASK_DENIED_SIGNATURE_PATTERN)) { + if (_.includes(error.message, constants.USER_DENIED_SIGNATURE_PATTERN)) { const errMsg = ContractWrappersError.SignatureRequestDenied; return new Error(errMsg); } -- cgit From 56953320b30604b051c39374d0abff8456051fd7 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Tue, 23 Oct 2018 10:07:48 -0700 Subject: Run prettier and linter --- packages/contracts/test/extensions/forwarder.ts | 2 -- 1 file changed, 2 deletions(-) (limited to 'packages') diff --git a/packages/contracts/test/extensions/forwarder.ts b/packages/contracts/test/extensions/forwarder.ts index 0c4a06373..c006be0fe 100644 --- a/packages/contracts/test/extensions/forwarder.ts +++ b/packages/contracts/test/extensions/forwarder.ts @@ -1017,7 +1017,6 @@ describe(ContractName.Forwarder, () => { }); it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => { // Order taken from a transaction on mainnet that failed due to a rounding error. -- // tx=0x3d22b18fe2615c1903408b1b969744bcd117becc30205df18d5c5c54d27d1237 orderWithoutFee = await orderFactory.newSignedOrderAsync({ makerAssetAmount: new BigNumber('268166666666666666666'), takerAssetAmount: new BigNumber('219090625878836371'), @@ -1070,7 +1069,6 @@ describe(ContractName.Forwarder, () => { }); it('Should buy slightly greater MakerAsset when exchange rate is rounded, and MakerAsset is ZRX (Regression Test)', async () => { // Order taken from a transaction on mainnet that failed due to a rounding error. -- // tx=0x3d22b18fe2615c1903408b1b969744bcd117becc30205df18d5c5c54d27d1237 orderWithoutFee = await orderFactory.newSignedOrderAsync({ makerAssetAmount: new BigNumber('268166666666666666666'), takerAssetAmount: new BigNumber('219090625878836371'), -- cgit From 864f89c535cf68a9325f27eae7f49a088c481120 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 14:09:44 -0700 Subject: chore: incorportate pr feedback --- packages/instant/src/components/buy_button.tsx | 2 +- packages/instant/src/components/zero_ex_instant.tsx | 8 ++++---- packages/instant/src/constants.ts | 1 + packages/instant/src/index.umd.ts | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 3ef7c1f5c..adc32f071 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -24,7 +24,7 @@ export class BuyButton extends React.Component { onBuyFailure: util.boundNoop, }; public render(): React.ReactNode { - const shouldDisableButton = _.isUndefined(this.props.buyQuote); + const shouldDisableButton = _.isUndefined(this.props.buyQuote) || _.isUndefined(this.props.assetBuyer); return (