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 { ColorOption } from '../style/theme';
 | 
			
		||||
import { assetBuyer } from '../util/asset_buyer';
 | 
			
		||||
import { web3Wrapper } from '../util/web3_wrapper';
 | 
			
		||||
 | 
			
		||||
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(_);
 | 
			
		||||
 | 
			
		||||
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%">
 | 
			
		||||
                <Button width="100%" onClick={this._handleClick} isDisabled={shouldDisableButton}>
 | 
			
		||||
                    <Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
 | 
			
		||||
                Buy
 | 
			
		||||
                        {this.props.text}
 | 
			
		||||
                    </Text>
 | 
			
		||||
                </Button>
 | 
			
		||||
            </Container>
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
BuyButton.displayName = 'BuyButton';
 | 
			
		||||
    }
 | 
			
		||||
    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 { ethDecimals } from '../constants';
 | 
			
		||||
import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input';
 | 
			
		||||
import { ColorOption } from '../style/theme';
 | 
			
		||||
 | 
			
		||||
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 => (
 | 
			
		||||
    <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" />
 | 
			
		||||
                <Container display="inline-block" marginLeft="10px">
 | 
			
		||||
                    <Text fontSize="45px" fontColor={ColorOption.white} textTransform="uppercase">
 | 
			
		||||
                        rep
 | 
			
		||||
                        zrx
 | 
			
		||||
                    </Text>
 | 
			
		||||
                </Container>
 | 
			
		||||
            </Container>
 | 
			
		||||
            <Flex direction="column" justify="space-between">
 | 
			
		||||
                <Container marginBottom="5px">
 | 
			
		||||
                    <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}>
 | 
			
		||||
                        0 ETH
 | 
			
		||||
                        {displaytotalEthBaseAmount(props)}
 | 
			
		||||
                    </Text>
 | 
			
		||||
                </Container>
 | 
			
		||||
                <Text fontSize="16px" fontColor={ColorOption.white} opacity={0.7}>
 | 
			
		||||
                    $0.00
 | 
			
		||||
                    {displayUsdAmount(props)}
 | 
			
		||||
                </Text>
 | 
			
		||||
            </Flex>
 | 
			
		||||
        </Flex>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import * as React from 'react';
 | 
			
		||||
import { Provider } from 'react-redux';
 | 
			
		||||
 | 
			
		||||
import { asyncData } from '../redux/async_data';
 | 
			
		||||
import { store } from '../redux/store';
 | 
			
		||||
import { fonts } from '../style/fonts';
 | 
			
		||||
import { theme, ThemeProvider } from '../style/theme';
 | 
			
		||||
@@ -8,6 +9,7 @@ import { theme, ThemeProvider } from '../style/theme';
 | 
			
		||||
import { ZeroExInstantContainer } from './zero_ex_instant_container';
 | 
			
		||||
 | 
			
		||||
fonts.include();
 | 
			
		||||
asyncData.fetchAndDispatchToStore();
 | 
			
		||||
 | 
			
		||||
export interface ZeroExInstantProps {}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
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 { BuyButton } from './buy_button';
 | 
			
		||||
@@ -12,9 +15,9 @@ export interface ZeroExInstantContainerProps {}
 | 
			
		||||
export const ZeroExInstantContainer: React.StatelessComponent<ZeroExInstantContainerProps> = props => (
 | 
			
		||||
    <Container hasBoxShadow={true} width="350px" backgroundColor={ColorOption.white} borderRadius="3px">
 | 
			
		||||
        <Flex direction="column" justify="flex-start">
 | 
			
		||||
            <InstantHeading />
 | 
			
		||||
            <SelectedAssetInstantHeading />
 | 
			
		||||
            <OrderDetails />
 | 
			
		||||
            <BuyButton />
 | 
			
		||||
            <SelectedAssetBuyButton />
 | 
			
		||||
        </Flex>
 | 
			
		||||
    </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 * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { Action, ActionTypes } from '../types';
 | 
			
		||||
import { Action, ActionTypes, AsyncProcessState } from '../types';
 | 
			
		||||
 | 
			
		||||
export interface State {
 | 
			
		||||
    ethUsdPrice?: string;
 | 
			
		||||
    selectedAssetAmount?: BigNumber;
 | 
			
		||||
    selectedAssetBuyState: AsyncProcessState;
 | 
			
		||||
    ethUsdPrice?: BigNumber;
 | 
			
		||||
    latestBuyQuote?: BuyQuote;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const INITIAL_STATE: State = {
 | 
			
		||||
    ethUsdPrice: undefined,
 | 
			
		||||
    selectedAssetBuyState: AsyncProcessState.NONE,
 | 
			
		||||
    selectedAssetAmount: undefined,
 | 
			
		||||
    latestBuyQuote: undefined,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
                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:
 | 
			
		||||
            return state;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,16 @@
 | 
			
		||||
// Reusable
 | 
			
		||||
export enum AsyncProcessState {
 | 
			
		||||
    NONE,
 | 
			
		||||
    PENDING,
 | 
			
		||||
    SUCCESS,
 | 
			
		||||
    FAILURE,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum ActionTypes {
 | 
			
		||||
    UPDATE_ETH_USD_PRICE,
 | 
			
		||||
    UPDATE_SELECTED_ASSET_AMOUNT,
 | 
			
		||||
    UPDATE_SELECTED_ASSET_BUY_STATE,
 | 
			
		||||
    UPDATE_LATEST_BUY_QUOTE,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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