feat: Move over features from zrx-buyer
This commit is contained in:
		@@ -1,19 +1,56 @@
 | 
				
			|||||||
 | 
					import { BuyQuote } from '@0xproject/asset-buyer';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
import * as React from 'react';
 | 
					import * as React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ColorOption } from '../style/theme';
 | 
					import { ColorOption } from '../style/theme';
 | 
				
			||||||
 | 
					import { assetBuyer } from '../util/asset_buyer';
 | 
				
			||||||
 | 
					import { web3Wrapper } from '../util/web3_wrapper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Button, Container, Text } from './ui';
 | 
					import { Button, Container, Text } from './ui';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface BuyButtonProps {}
 | 
					export interface BuyButtonProps {
 | 
				
			||||||
 | 
					    buyQuote?: BuyQuote;
 | 
				
			||||||
 | 
					    onClick: (buyQuote: BuyQuote) => void;
 | 
				
			||||||
 | 
					    onBuySuccess: (buyQuote: BuyQuote) => void;
 | 
				
			||||||
 | 
					    onBuyFailure: (buyQuote: BuyQuote) => void;
 | 
				
			||||||
 | 
					    text: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const BuyButton: React.StatelessComponent<BuyButtonProps> = props => (
 | 
					const boundNoop = _.noop.bind(_);
 | 
				
			||||||
    <Container padding="20px" width="100%">
 | 
					 | 
				
			||||||
        <Button width="100%">
 | 
					 | 
				
			||||||
            <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
 | 
					 | 
				
			||||||
                Buy
 | 
					 | 
				
			||||||
            </Text>
 | 
					 | 
				
			||||||
        </Button>
 | 
					 | 
				
			||||||
    </Container>
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
BuyButton.displayName = 'BuyButton';
 | 
					export class BuyButton extends React.Component<BuyButtonProps> {
 | 
				
			||||||
 | 
					    public static defaultProps = {
 | 
				
			||||||
 | 
					        onClick: boundNoop,
 | 
				
			||||||
 | 
					        onBuySuccess: boundNoop,
 | 
				
			||||||
 | 
					        onBuyFailure: boundNoop,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    public render(): React.ReactNode {
 | 
				
			||||||
 | 
					        const shouldDisableButton = _.isUndefined(this.props.buyQuote);
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <Container padding="20px" width="100%">
 | 
				
			||||||
 | 
					                <Button width="100%" onClick={this._handleClick} isDisabled={shouldDisableButton}>
 | 
				
			||||||
 | 
					                    <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
 | 
				
			||||||
 | 
					                        {this.props.text}
 | 
				
			||||||
 | 
					                    </Text>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </Container>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private readonly _handleClick = async () => {
 | 
				
			||||||
 | 
					        // The button is disabled when there is no buy quote anyway.
 | 
				
			||||||
 | 
					        if (_.isUndefined(this.props.buyQuote)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.props.onClick(this.props.buyQuote);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            const txnHash = await assetBuyer.executeBuyQuoteAsync(this.props.buyQuote, {
 | 
				
			||||||
 | 
					                // HACK: There is a calculation issue in asset-buyer. ETH is refunded anyway so just over-estimate.
 | 
				
			||||||
 | 
					                ethAmount: this.props.buyQuote.worstCaseQuoteInfo.totalEthAmount.mul(2),
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            await web3Wrapper.awaitTransactionSuccessAsync(txnHash);
 | 
				
			||||||
 | 
					        } catch {
 | 
				
			||||||
 | 
					            this.props.onBuyFailure(this.props.buyQuote);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.props.onBuySuccess(this.props.buyQuote);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,42 @@
 | 
				
			|||||||
 | 
					import { BigNumber } from '@0xproject/utils';
 | 
				
			||||||
 | 
					import { Web3Wrapper } from '@0xproject/web3-wrapper';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
import * as React from 'react';
 | 
					import * as React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ethDecimals } from '../constants';
 | 
				
			||||||
import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input';
 | 
					import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input';
 | 
				
			||||||
import { ColorOption } from '../style/theme';
 | 
					import { ColorOption } from '../style/theme';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Container, Flex, Text } from './ui';
 | 
					import { Container, Flex, Text } from './ui';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface InstantHeadingProps {}
 | 
					export interface InstantHeadingProps {
 | 
				
			||||||
 | 
					    selectedAssetAmount?: BigNumber;
 | 
				
			||||||
 | 
					    totalEthBaseAmount?: BigNumber;
 | 
				
			||||||
 | 
					    ethUsdPrice?: BigNumber;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const displaytotalEthBaseAmount = ({ selectedAssetAmount, totalEthBaseAmount }: InstantHeadingProps): string => {
 | 
				
			||||||
 | 
					    if (_.isUndefined(selectedAssetAmount)) {
 | 
				
			||||||
 | 
					        return '0 ETH';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (_.isUndefined(totalEthBaseAmount)) {
 | 
				
			||||||
 | 
					        return '...loading';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const ethUnitAmount = Web3Wrapper.toUnitAmount(totalEthBaseAmount, ethDecimals);
 | 
				
			||||||
 | 
					    const roundedAmount = ethUnitAmount.round(4);
 | 
				
			||||||
 | 
					    return `${roundedAmount} ETH`;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const displayUsdAmount = ({ totalEthBaseAmount, selectedAssetAmount, ethUsdPrice }: InstantHeadingProps): string => {
 | 
				
			||||||
 | 
					    if (_.isUndefined(selectedAssetAmount)) {
 | 
				
			||||||
 | 
					        return '$0.00';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (_.isUndefined(totalEthBaseAmount) || _.isUndefined(ethUsdPrice)) {
 | 
				
			||||||
 | 
					        return '...loading';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const ethUnitAmount = Web3Wrapper.toUnitAmount(totalEthBaseAmount, ethDecimals);
 | 
				
			||||||
 | 
					    return `$${ethUnitAmount.mul(ethUsdPrice).round(2)}`;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = props => (
 | 
					export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = props => (
 | 
				
			||||||
    <Container backgroundColor={ColorOption.primaryColor} padding="20px" width="100%" borderRadius="3px 3px 0px 0px">
 | 
					    <Container backgroundColor={ColorOption.primaryColor} padding="20px" width="100%" borderRadius="3px 3px 0px 0px">
 | 
				
			||||||
@@ -26,18 +57,18 @@ export const InstantHeading: React.StatelessComponent<InstantHeadingProps> = pro
 | 
				
			|||||||
                <SelectedAssetAmountInput fontSize="45px" />
 | 
					                <SelectedAssetAmountInput fontSize="45px" />
 | 
				
			||||||
                <Container display="inline-block" marginLeft="10px">
 | 
					                <Container display="inline-block" marginLeft="10px">
 | 
				
			||||||
                    <Text fontSize="45px" fontColor={ColorOption.white} textTransform="uppercase">
 | 
					                    <Text fontSize="45px" fontColor={ColorOption.white} textTransform="uppercase">
 | 
				
			||||||
                        rep
 | 
					                        zrx
 | 
				
			||||||
                    </Text>
 | 
					                    </Text>
 | 
				
			||||||
                </Container>
 | 
					                </Container>
 | 
				
			||||||
            </Container>
 | 
					            </Container>
 | 
				
			||||||
            <Flex direction="column" justify="space-between">
 | 
					            <Flex direction="column" justify="space-between">
 | 
				
			||||||
                <Container marginBottom="5px">
 | 
					                <Container marginBottom="5px">
 | 
				
			||||||
                    <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}>
 | 
					                    <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}>
 | 
				
			||||||
                        0 ETH
 | 
					                        {displaytotalEthBaseAmount(props)}
 | 
				
			||||||
                    </Text>
 | 
					                    </Text>
 | 
				
			||||||
                </Container>
 | 
					                </Container>
 | 
				
			||||||
                <Text fontSize="16px" fontColor={ColorOption.white} opacity={0.7}>
 | 
					                <Text fontSize="16px" fontColor={ColorOption.white} opacity={0.7}>
 | 
				
			||||||
                    $0.00
 | 
					                    {displayUsdAmount(props)}
 | 
				
			||||||
                </Text>
 | 
					                </Text>
 | 
				
			||||||
            </Flex>
 | 
					            </Flex>
 | 
				
			||||||
        </Flex>
 | 
					        </Flex>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import * as React from 'react';
 | 
					import * as React from 'react';
 | 
				
			||||||
import { Provider } from 'react-redux';
 | 
					import { Provider } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { asyncData } from '../redux/async_data';
 | 
				
			||||||
import { store } from '../redux/store';
 | 
					import { store } from '../redux/store';
 | 
				
			||||||
import { fonts } from '../style/fonts';
 | 
					import { fonts } from '../style/fonts';
 | 
				
			||||||
import { theme, ThemeProvider } from '../style/theme';
 | 
					import { theme, ThemeProvider } from '../style/theme';
 | 
				
			||||||
@@ -8,6 +9,7 @@ import { theme, ThemeProvider } from '../style/theme';
 | 
				
			|||||||
import { ZeroExInstantContainer } from './zero_ex_instant_container';
 | 
					import { ZeroExInstantContainer } from './zero_ex_instant_container';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fonts.include();
 | 
					fonts.include();
 | 
				
			||||||
 | 
					asyncData.fetchAndDispatchToStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ZeroExInstantProps {}
 | 
					export interface ZeroExInstantProps {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
import * as React from 'react';
 | 
					import * as React from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { SelectedAssetBuyButton } from '../containers/selected_asset_buy_button';
 | 
				
			||||||
 | 
					import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ColorOption } from '../style/theme';
 | 
					import { ColorOption } from '../style/theme';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { BuyButton } from './buy_button';
 | 
					import { BuyButton } from './buy_button';
 | 
				
			||||||
@@ -12,9 +15,9 @@ export interface ZeroExInstantContainerProps {}
 | 
				
			|||||||
export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantContainerProps> = props => (
 | 
					export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantContainerProps> = props => (
 | 
				
			||||||
    <Container hasBoxShadow={true} width="350px" backgroundColor={ColorOption.white} borderRadius="3px">
 | 
					    <Container hasBoxShadow={true} width="350px" backgroundColor={ColorOption.white} borderRadius="3px">
 | 
				
			||||||
        <Flex direction="column" justify="flex-start">
 | 
					        <Flex direction="column" justify="flex-start">
 | 
				
			||||||
            <InstantHeading />
 | 
					            <SelectedAssetInstantHeading />
 | 
				
			||||||
            <OrderDetails />
 | 
					            <OrderDetails />
 | 
				
			||||||
            <BuyButton />
 | 
					            <SelectedAssetBuyButton />
 | 
				
			||||||
        </Flex>
 | 
					        </Flex>
 | 
				
			||||||
    </Container>
 | 
					    </Container>
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								packages/instant/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								packages/instant/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					export const sraApiUrl = 'https://api.radarrelay.com/0x/v2/';
 | 
				
			||||||
 | 
					export const zrxContractAddress = '0xe41d2489571d322189246dafa5ebde1f4699f498';
 | 
				
			||||||
 | 
					export const zrxDecimals = 18;
 | 
				
			||||||
 | 
					export const ethDecimals = 18;
 | 
				
			||||||
@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					import { BigNumber } from '@0xproject/utils';
 | 
				
			||||||
 | 
					import { Web3Wrapper } from '@0xproject/web3-wrapper';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					import * as React from 'react';
 | 
				
			||||||
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					import { Dispatch } from 'redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { zrxContractAddress, zrxDecimals } from '../constants';
 | 
				
			||||||
 | 
					import { State } from '../redux/reducer';
 | 
				
			||||||
 | 
					import { ColorOption } from '../style/theme';
 | 
				
			||||||
 | 
					import { Action, ActionTypes, AsyncProcessState } from '../types';
 | 
				
			||||||
 | 
					import { assetBuyer } from '../util/asset_buyer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AmountInput } from '../components/amount_input';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface SelectedAssetAmountInputProps {
 | 
				
			||||||
 | 
					    fontColor?: ColorOption;
 | 
				
			||||||
 | 
					    fontSize?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ConnectedState {
 | 
				
			||||||
 | 
					    value?: BigNumber;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ConnectedDispatch {
 | 
				
			||||||
 | 
					    onChange?: (value?: BigNumber) => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mapStateToProps = (state: State, _ownProps: SelectedAssetAmountInputProps): ConnectedState => ({
 | 
				
			||||||
 | 
					    value: state.selectedAssetAmount,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mapDispatchToProps = (dispatch: Dispatch<Action>): ConnectedDispatch => ({
 | 
				
			||||||
 | 
					    onChange: async value => {
 | 
				
			||||||
 | 
					        // Update the input
 | 
				
			||||||
 | 
					        dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, data: value });
 | 
				
			||||||
 | 
					        // invalidate the last buy quote.
 | 
				
			||||||
 | 
					        dispatch({ type: ActionTypes.UPDATE_LATEST_BUY_QUOTE, data: undefined });
 | 
				
			||||||
 | 
					        // reset our buy state
 | 
				
			||||||
 | 
					        dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, data: AsyncProcessState.NONE });
 | 
				
			||||||
 | 
					        if (!_.isUndefined(value)) {
 | 
				
			||||||
 | 
					            // get a new buy quote.
 | 
				
			||||||
 | 
					            const baseUnitValue = Web3Wrapper.toBaseUnitAmount(value, zrxDecimals);
 | 
				
			||||||
 | 
					            const newBuyQuote = await assetBuyer.getBuyQuoteForERC20TokenAddressAsync(
 | 
				
			||||||
 | 
					                zrxContractAddress,
 | 
				
			||||||
 | 
					                baseUnitValue,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            // invalidate the last buy quote.
 | 
				
			||||||
 | 
					            dispatch({ type: ActionTypes.UPDATE_LATEST_BUY_QUOTE, data: newBuyQuote });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SelectedAssetAmountInput: React.ComponentClass<SelectedAssetAmountInputProps> = connect(
 | 
				
			||||||
 | 
					    mapStateToProps,
 | 
				
			||||||
 | 
					    mapDispatchToProps,
 | 
				
			||||||
 | 
					)(AmountInput);
 | 
				
			||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
import { BigNumber } from '@0xproject/utils';
 | 
					 | 
				
			||||||
import * as React from 'react';
 | 
					 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					 | 
				
			||||||
import { Dispatch } from 'redux';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { State } from '../redux/reducer';
 | 
					 | 
				
			||||||
import { ColorOption } from '../style/theme';
 | 
					 | 
				
			||||||
import { Action, ActionTypes } from '../types';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { AmountInput } from '../components/amount_input';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface SelectedAssetAmountInputProps {
 | 
					 | 
				
			||||||
    fontColor?: ColorOption;
 | 
					 | 
				
			||||||
    fontSize?: string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface ConnectedState {
 | 
					 | 
				
			||||||
    value?: BigNumber;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface ConnectedDispatch {
 | 
					 | 
				
			||||||
    onChange?: (value?: BigNumber) => void;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapStateToProps = (state: State, _ownProps: SelectedAssetAmountInputProps): ConnectedState => ({
 | 
					 | 
				
			||||||
    value: state.selectedAssetAmount,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapDispatchToProps = (dispatch: Dispatch<Action>): ConnectedDispatch => ({
 | 
					 | 
				
			||||||
    onChange: value => dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, data: value }),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const SelectedAssetAmountInput: React.ComponentClass<SelectedAssetAmountInputProps> = connect(
 | 
					 | 
				
			||||||
    mapStateToProps,
 | 
					 | 
				
			||||||
    mapDispatchToProps,
 | 
					 | 
				
			||||||
)(AmountInput);
 | 
					 | 
				
			||||||
							
								
								
									
										59
									
								
								packages/instant/src/containers/selected_asset_buy_button.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								packages/instant/src/containers/selected_asset_buy_button.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					import { BuyQuote } from '@0xproject/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 { Action, ActionTypes, AsyncProcessState } from '../types';
 | 
				
			||||||
 | 
					import { assetBuyer } from '../util/asset_buyer';
 | 
				
			||||||
 | 
					import { web3Wrapper } from '../util/web3_wrapper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { BuyButton } from '../components/buy_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface SelectedAssetBuyButtonProps {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ConnectedState {
 | 
				
			||||||
 | 
					    text: string;
 | 
				
			||||||
 | 
					    buyQuote?: BuyQuote;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ConnectedDispatch {
 | 
				
			||||||
 | 
					    onClick: (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 => ({
 | 
				
			||||||
 | 
					    text: textForState(state.selectedAssetBuyState),
 | 
				
			||||||
 | 
					    buyQuote: state.latestBuyQuote,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mapDispatchToProps = (dispatch: Dispatch<Action>, ownProps: SelectedAssetBuyButtonProps): ConnectedDispatch => ({
 | 
				
			||||||
 | 
					    onClick: buyQuote =>
 | 
				
			||||||
 | 
					        dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, data: AsyncProcessState.PENDING }),
 | 
				
			||||||
 | 
					    onBuySuccess: buyQuote =>
 | 
				
			||||||
 | 
					        dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, data: AsyncProcessState.SUCCESS }),
 | 
				
			||||||
 | 
					    onBuyFailure: buyQuote =>
 | 
				
			||||||
 | 
					        dispatch({ type: ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE, data: AsyncProcessState.FAILURE }),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SelectedAssetBuyButton: React.ComponentClass<SelectedAssetBuyButtonProps> = connect(
 | 
				
			||||||
 | 
					    mapStateToProps,
 | 
				
			||||||
 | 
					    mapDispatchToProps,
 | 
				
			||||||
 | 
					)(BuyButton);
 | 
				
			||||||
@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { BigNumber } from '@0xproject/utils';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					import * as React from 'react';
 | 
				
			||||||
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { State } from '../redux/reducer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { InstantHeading } from '../components/instant_heading';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface InstantHeadingProps {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ConnectedState {
 | 
				
			||||||
 | 
					    selectedAssetAmount?: BigNumber;
 | 
				
			||||||
 | 
					    totalEthBaseAmount?: BigNumber;
 | 
				
			||||||
 | 
					    ethUsdPrice?: BigNumber;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): ConnectedState => ({
 | 
				
			||||||
 | 
					    selectedAssetAmount: state.selectedAssetAmount,
 | 
				
			||||||
 | 
					    totalEthBaseAmount: _.get(state, 'latestBuyQuote.worstCaseQuoteInfo.totalEthAmount'),
 | 
				
			||||||
 | 
					    ethUsdPrice: state.ethUsdPrice,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const SelectedAssetInstantHeading: React.ComponentClass<InstantHeadingProps> = connect(mapStateToProps)(
 | 
				
			||||||
 | 
					    InstantHeading,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
							
								
								
									
										22
									
								
								packages/instant/src/redux/async_data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/instant/src/redux/async_data.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import { BigNumber } from '@0xproject/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ActionTypes } from '../types';
 | 
				
			||||||
 | 
					import { coinbaseApi } from '../util/coinbase_api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { store } from './store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const asyncData = {
 | 
				
			||||||
 | 
					    fetchAndDispatchToStore: async () => {
 | 
				
			||||||
 | 
					        let ethUsdPriceStr = '0';
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            ethUsdPriceStr = await coinbaseApi.getEthUsdPrice();
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            // ignore
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            store.dispatch({
 | 
				
			||||||
 | 
					                type: ActionTypes.UPDATE_ETH_USD_PRICE,
 | 
				
			||||||
 | 
					                data: new BigNumber(ethUsdPriceStr),
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -1,16 +1,21 @@
 | 
				
			|||||||
 | 
					import { BuyQuote } from '@0xproject/asset-buyer';
 | 
				
			||||||
import { BigNumber } from '@0xproject/utils';
 | 
					import { BigNumber } from '@0xproject/utils';
 | 
				
			||||||
import * as _ from 'lodash';
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Action, ActionTypes } from '../types';
 | 
					import { Action, ActionTypes, AsyncProcessState } from '../types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface State {
 | 
					export interface State {
 | 
				
			||||||
    ethUsdPrice?: string;
 | 
					 | 
				
			||||||
    selectedAssetAmount?: BigNumber;
 | 
					    selectedAssetAmount?: BigNumber;
 | 
				
			||||||
 | 
					    selectedAssetBuyState: AsyncProcessState;
 | 
				
			||||||
 | 
					    ethUsdPrice?: BigNumber;
 | 
				
			||||||
 | 
					    latestBuyQuote?: BuyQuote;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const INITIAL_STATE: State = {
 | 
					export const INITIAL_STATE: State = {
 | 
				
			||||||
    ethUsdPrice: undefined,
 | 
					    ethUsdPrice: undefined,
 | 
				
			||||||
 | 
					    selectedAssetBuyState: AsyncProcessState.NONE,
 | 
				
			||||||
    selectedAssetAmount: undefined,
 | 
					    selectedAssetAmount: undefined,
 | 
				
			||||||
 | 
					    latestBuyQuote: undefined,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const reducer = (state: State = INITIAL_STATE, action: Action): State => {
 | 
					export const reducer = (state: State = INITIAL_STATE, action: Action): State => {
 | 
				
			||||||
@@ -25,6 +30,16 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
 | 
				
			|||||||
                ...state,
 | 
					                ...state,
 | 
				
			||||||
                selectedAssetAmount: action.data,
 | 
					                selectedAssetAmount: action.data,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					        case ActionTypes.UPDATE_LATEST_BUY_QUOTE:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                ...state,
 | 
				
			||||||
 | 
					                latestBuyQuote: action.data,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        case ActionTypes.UPDATE_SELECTED_ASSET_BUY_STATE:
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                ...state,
 | 
				
			||||||
 | 
					                selectedAssetBuyState: action.data,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            return state;
 | 
					            return state;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,16 @@
 | 
				
			|||||||
 | 
					// Reusable
 | 
				
			||||||
 | 
					export enum AsyncProcessState {
 | 
				
			||||||
 | 
					    NONE,
 | 
				
			||||||
 | 
					    PENDING,
 | 
				
			||||||
 | 
					    SUCCESS,
 | 
				
			||||||
 | 
					    FAILURE,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum ActionTypes {
 | 
					export enum ActionTypes {
 | 
				
			||||||
    UPDATE_ETH_USD_PRICE,
 | 
					    UPDATE_ETH_USD_PRICE,
 | 
				
			||||||
    UPDATE_SELECTED_ASSET_AMOUNT,
 | 
					    UPDATE_SELECTED_ASSET_AMOUNT,
 | 
				
			||||||
 | 
					    UPDATE_SELECTED_ASSET_BUY_STATE,
 | 
				
			||||||
 | 
					    UPDATE_LATEST_BUY_QUOTE,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Action {
 | 
					export interface Action {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								packages/instant/src/util/asset_buyer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/instant/src/util/asset_buyer.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import { AssetBuyer } from '@0xproject/asset-buyer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { sraApiUrl } from '../constants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { getProvider } from './provider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const provider = getProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(provider, sraApiUrl, {
 | 
				
			||||||
 | 
					    expiryBufferSeconds: 300,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										8
									
								
								packages/instant/src/util/coinbase_api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								packages/instant/src/util/coinbase_api.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					const baseEndpoint = 'https://api.coinbase.com/v2';
 | 
				
			||||||
 | 
					export const coinbaseApi = {
 | 
				
			||||||
 | 
					    getEthUsdPrice: async (): Promise<string> => {
 | 
				
			||||||
 | 
					        const res = await fetch(`${baseEndpoint}/prices/ETH-USD/buy`);
 | 
				
			||||||
 | 
					        const resJson = await res.json();
 | 
				
			||||||
 | 
					        return resJson.data.amount;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										12
									
								
								packages/instant/src/util/provider.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/instant/src/util/provider.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import { Provider } from 'ethereum-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getProvider = (): Provider => {
 | 
				
			||||||
 | 
					    const injectedWeb3 = (window as any).web3 || undefined;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        // Use MetaMask/Mist provider
 | 
				
			||||||
 | 
					        return injectedWeb3.currentProvider;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					        // Throws when user doesn't have MetaMask/Mist running
 | 
				
			||||||
 | 
					        throw new Error(`No injected web3 found: ${err}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										5
									
								
								packages/instant/src/util/web3_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								packages/instant/src/util/web3_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import { Web3Wrapper } from '@0xproject/web3-wrapper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { getProvider } from './provider';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const web3Wrapper = new Web3Wrapper(getProvider());
 | 
				
			||||||
		Reference in New Issue
	
	Block a user