removed buyer and adding in asset-swapper

This commit is contained in:
David Sun 2019-11-12 16:30:13 -05:00 committed by Jacob Evans
parent c3c8ee7292
commit 64d25e6522
No known key found for this signature in database
GPG Key ID: 2036DA2ADDFB0842
18 changed files with 172 additions and 164 deletions

View File

@ -44,7 +44,7 @@
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
"dependencies": {
"@0x/assert": "^2.2.0-beta.2",
"@0x/asset-buyer": "6.1.8",
"@0x/asset-swapper": "^2.1.0-beta.2",
"@0x/json-schemas": "^4.1.0-beta.2",
"@0x/order-utils": "^8.5.0-beta.3",
"@0x/subproviders": "^5.1.0-beta.2",

View File

@ -16,12 +16,12 @@ export const ONE_SECOND_MS = 1000;
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
export const GIT_SHA = process.env.GIT_SHA;
export const NODE_ENV = process.env.NODE_ENV;
export const ERC20_BUY_QUOTE_SLIPPAGE_PERCENTAGE = 0.2;
export const ERC721_BUY_QUOTE_SLIPPAGE_PERCENTAGE = 0;
export const ERC20_SWAP_QUOTE_SLIPPAGE_PERCENTAGE = 0.2;
export const ERC721_SWAP_QUOTE_SLIPPAGE_PERCENTAGE = 0;
export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION;
export const DEFAULT_UNKOWN_ASSET_NAME = '???';
export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5;
export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15;
export const SWAP_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15;
export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.multipliedBy(6);
export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
export const MAGIC_TRIGGER_ERROR_INPUT = '0€';

View File

@ -28,7 +28,7 @@ interface ConnectedState extends BuyOrderProgressOrPaymentMethodProps {}
export interface ConnectedBuyOrderProgressOrPaymentMethodProps {}
const mapStateToProps = (state: State, _ownProps: ConnectedBuyOrderProgressOrPaymentMethodProps): ConnectedState => ({
orderProcessState: state.buyOrderState.processState,
orderProcessState: state.swapOrderState.processState,
});
export const ConnectedBuyOrderProgressOrPaymentMethod: React.ComponentClass<
ConnectedBuyOrderProgressOrPaymentMethodProps

View File

@ -16,7 +16,7 @@ type DispatchProperties = 'onBaseCurrencySwitchEth' | 'onBaseCurrencySwitchUsd';
interface ConnectedState extends Omit<OrderDetailsProps, DispatchProperties> {}
const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({
// use the worst case quote info
buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(),
buyQuoteInfo: oc(state).latestSwapQuote.worstCaseQuoteInfo(),
selectedAssetUnitAmount: state.selectedAssetUnitAmount,
ethUsdPrice: state.ethUsdPrice,
isLoading: state.quoteRequestState === AsyncProcessState.Pending,

View File

@ -5,9 +5,9 @@ import { State } from '../redux/reducer';
import { OrderState } from '../types';
interface ConnectedState {
buyOrderState: OrderState;
swapOrderState: OrderState;
}
const mapStateToProps = (state: State, _ownProps: {}): ConnectedState => ({
buyOrderState: state.buyOrderState,
swapOrderState: state.swapOrderState,
});
export const SelectedAssetBuyOrderProgress = connect(mapStateToProps)(BuyOrderProgress);

View File

@ -19,16 +19,16 @@ interface ConnectedState {
totalEthBaseUnitAmount?: BigNumber;
ethUsdPrice?: BigNumber;
quoteRequestState: AsyncProcessState;
buyOrderState: OrderState;
swapOrderState: OrderState;
}
const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): ConnectedState => ({
selectedAsset: state.selectedAsset,
selectedAssetUnitAmount: state.selectedAssetUnitAmount,
totalEthBaseUnitAmount: oc(state).latestBuyQuote.worstCaseQuoteInfo.totalEthAmount(),
totalEthBaseUnitAmount: oc(state).latestSwapQuote.worstCaseQuoteInfo.totalTakerAssetAmount(),
ethUsdPrice: state.ethUsdPrice,
quoteRequestState: state.quoteRequestState,
buyOrderState: state.buyOrderState,
swapOrderState: state.swapOrderState,
});
export const SelectedAssetInstantHeading: React.ComponentClass<InstantHeadingProps> = connect(mapStateToProps)(

View File

@ -1,4 +1,4 @@
import { AssetBuyer } from '@0x/asset-buyer';
import { SwapQuoter } from '@0x/asset-swapper';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
@ -11,7 +11,7 @@ import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { ColorOption } from '../style/theme';
import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState, QuoteFetchOrigin } from '../types';
import { buyQuoteUpdater } from '../util/buy_quote_updater';
import { swapQuoteUpdater } from '../util/swap_quote_updater';
export interface SelectedERC20AssetAmountInputProps {
fontColor?: ColorOption;
@ -20,7 +20,7 @@ export interface SelectedERC20AssetAmountInputProps {
}
interface ConnectedState {
assetBuyer: AssetBuyer;
swapQuoter: SwapQuoter;
value?: BigNumber;
asset?: ERC20Asset;
isInputDisabled: boolean;
@ -30,8 +30,8 @@ interface ConnectedState {
}
interface ConnectedDispatch {
updateBuyQuote: (
assetBuyer: AssetBuyer,
updateSwapQuote: (
swapQuoter: SwapQuoter,
value?: BigNumber,
asset?: ERC20Asset,
affiliateInfo?: AffiliateInfo,
@ -43,7 +43,7 @@ type ConnectedProps = Omit<ERC20AssetAmountInputProps, keyof SelectedERC20AssetA
type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps;
const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => {
const processState = state.buyOrderState.processState;
const processState = state.swapOrderState.processState;
const isInputEnabled = processState === OrderProcessState.None || processState === OrderProcessState.Failure;
const isInputDisabled = !isInputEnabled;
const selectedAsset =
@ -56,9 +56,9 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP
? isInputEnabled || processState === OrderProcessState.Success
: false;
const assetBuyer = state.providerState.assetBuyer;
const swapQuoter = state.providerState.swapQuoter;
return {
assetBuyer,
swapQuoter,
value: state.selectedAssetUnitAmount,
asset: selectedAsset,
isInputDisabled,
@ -68,27 +68,27 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP
};
};
const debouncedUpdateBuyQuoteAsync = _.debounce(buyQuoteUpdater.updateBuyQuoteAsync.bind(buyQuoteUpdater), 200, {
const debouncedUpdateSwapQuoteAsync = _.debounce(swapQuoteUpdater.updateSwapQuoteAsync.bind(swapQuoteUpdater), 200, {
trailing: true,
}) as typeof buyQuoteUpdater.updateBuyQuoteAsync;
}) as typeof swapQuoteUpdater.updateSwapQuoteAsync;
const mapDispatchToProps = (
dispatch: Dispatch<Action>,
_ownProps: SelectedERC20AssetAmountInputProps,
): ConnectedDispatch => ({
updateBuyQuote: (assetBuyer, value, asset, affiliateInfo) => {
updateSwapQuote: (swapQuoter, value, asset, affiliateInfo) => {
// Update the input
dispatch(actions.updateSelectedAssetAmount(value));
// invalidate the last buy quote.
dispatch(actions.updateLatestBuyQuote(undefined));
// reset our buy state
dispatch(actions.setBuyOrderStateNone());
// invalidate the last swap quote.
dispatch(actions.updateLatestSwapQuote(undefined));
// reset our swap state
dispatch(actions.setSwapOrderStateNone());
if (value !== undefined && value.isGreaterThan(0) && asset !== undefined) {
// even if it's debounced, give them the illusion it's loading
dispatch(actions.setQuoteRequestStatePending());
// tslint:disable-next-line:no-floating-promises
debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, QuoteFetchOrigin.Manual, {
debouncedUpdateSwapQuoteAsync(swapQuoter, dispatch, asset, value, QuoteFetchOrigin.Manual, {
setPending: true,
dispatchErrors: true,
affiliateInfo,
@ -107,7 +107,7 @@ const mergeProps = (
asset: connectedState.asset,
value: connectedState.value,
onChange: (value, asset) => {
connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset, connectedState.affiliateInfo);
connectedDispatch.updateSwapQuote(connectedState.swapQuoter, value, asset, connectedState.affiliateInfo);
},
isInputDisabled: connectedState.isInputDisabled,
numberOfAssetsAvailable: connectedState.numberOfAssetsAvailable,

View File

@ -1,4 +1,4 @@
import { BuyQuote } from '@0x/asset-buyer';
import { MarketBuySwapQuote } from '@0x/asset-swapper';
import { BigNumber } from '@0x/utils';
import { ActionsUnion, AddressAndEthBalanceInWei, Asset, BaseCurrency, StandardSlidingPanelContent } from '../types';
@ -26,12 +26,12 @@ export enum ActionTypes {
UpdateAccountEthBalance = 'UPDATE_ACCOUNT_ETH_BALANCE',
UpdateEthUsdPrice = 'UPDATE_ETH_USD_PRICE',
UpdateSelectedAssetUnitAmount = 'UPDATE_SELECTED_ASSET_UNIT_AMOUNT',
SetBuyOrderStateNone = 'SET_BUY_ORDER_STATE_NONE',
SetBuyOrderStateValidating = 'SET_BUY_ORDER_STATE_VALIDATING',
SetBuyOrderStateProcessing = 'SET_BUY_ORDER_STATE_PROCESSING',
SetBuyOrderStateFailure = 'SET_BUY_ORDER_STATE_FAILURE',
SetBuyOrderStateSuccess = 'SET_BUY_ORDER_STATE_SUCCESS',
UpdateLatestBuyQuote = 'UPDATE_LATEST_BUY_QUOTE',
SetSwapOrderStateNone = 'SET_SWAP_ORDER_STATE_NONE',
SetSwapOrderStateValidating = 'SET_SWAP_ORDER_STATE_VALIDATING',
SetSwapOrderStateProcessing = 'SET_SWAP_ORDER_STATE_PROCESSING',
SetSwapOrderStateFailure = 'SET_SWAP_ORDER_STATE_FAILURE',
SetSwapOrderStateSuccess = 'SET_SWAP_ORDER_STATE_SUCCESS',
UpdateLatestSwapQuote = 'UPDATE_LATEST_SWAP_QUOTE',
UpdateSelectedAsset = 'UPDATE_SELECTED_ASSET',
SetAvailableAssets = 'SET_AVAILABLE_ASSETS',
SetQuoteRequestStatePending = 'SET_QUOTE_REQUEST_STATE_PENDING',
@ -53,13 +53,13 @@ export const actions = {
createAction(ActionTypes.UpdateAccountEthBalance, addressAndBalance),
updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UpdateEthUsdPrice, price),
updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UpdateSelectedAssetUnitAmount, amount),
setBuyOrderStateNone: () => createAction(ActionTypes.SetBuyOrderStateNone),
setBuyOrderStateValidating: () => createAction(ActionTypes.SetBuyOrderStateValidating),
setBuyOrderStateProcessing: (txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
createAction(ActionTypes.SetBuyOrderStateProcessing, { txHash, startTimeUnix, expectedEndTimeUnix }),
setBuyOrderStateFailure: (txHash: string) => createAction(ActionTypes.SetBuyOrderStateFailure, txHash),
setBuyOrderStateSuccess: (txHash: string) => createAction(ActionTypes.SetBuyOrderStateSuccess, txHash),
updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UpdateLatestBuyQuote, buyQuote),
setSwapOrderStateNone: () => createAction(ActionTypes.SetSwapOrderStateNone),
setSwapOrderStateValidating: () => createAction(ActionTypes.SetSwapOrderStateValidating),
setSwapOrderStateProcessing: (txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
createAction(ActionTypes.SetSwapOrderStateProcessing, { txHash, startTimeUnix, expectedEndTimeUnix }),
setSwapOrderStateFailure: (txHash: string) => createAction(ActionTypes.SetSwapOrderStateFailure, txHash),
setSwapOrderStateSuccess: (txHash: string) => createAction(ActionTypes.SetSwapOrderStateSuccess, txHash),
updateLatestSwapQuote: (swapQuote?: MarketBuySwapQuote) => createAction(ActionTypes.UpdateLatestSwapQuote, swapQuote),
updateSelectedAsset: (asset: Asset) => createAction(ActionTypes.UpdateSelectedAsset, asset),
setAvailableAssets: (availableAssets: Asset[]) => createAction(ActionTypes.SetAvailableAssets, availableAssets),
setQuoteRequestStatePending: () => createAction(ActionTypes.SetQuoteRequestStatePending),

View File

@ -6,10 +6,10 @@ import { BIG_NUMBER_ZERO } from '../constants';
import { AccountState, BaseCurrency, OrderProcessState, ProviderState, QuoteFetchOrigin } from '../types';
import { analytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { buyQuoteUpdater } from '../util/buy_quote_updater';
import { coinbaseApi } from '../util/coinbase_api';
import { errorFlasher } from '../util/error_flasher';
import { errorReporter } from '../util/error_reporter';
import { swapQuoteUpdater } from '../util/swap_quote_updater';
import { actions } from './actions';
import { State } from './reducer';
@ -30,9 +30,11 @@ export const asyncData = {
},
fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => {
const { providerState, assetMetaDataMap, network } = state;
const assetBuyer = providerState.assetBuyer;
const swapQuoter = providerState.swapQuoter;
try {
const assetDatas = await assetBuyer.getAvailableAssetDatasAsync();
// TODO(dave4506)
const wethAssetData = '';
const assetDatas = await swapQuoter.getAvailableMakerAssetDatasAsync(wethAssetData);
const deduplicatedAssetDatas = _.uniq(assetDatas);
const assets = assetUtils.createAssetsFromAssetDatas(deduplicatedAssetDatas, assetMetaDataMap, network);
dispatch(actions.setAvailableAssets(assets));
@ -87,22 +89,22 @@ export const asyncData = {
return;
}
},
fetchCurrentBuyQuoteAndDispatchToStore: async (
fetchCurrentSwapQuoteAndDispatchToStore: async (
state: State,
dispatch: Dispatch,
fetchOrigin: QuoteFetchOrigin,
options: { updateSilently: boolean },
) => {
const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
const assetBuyer = providerState.assetBuyer;
const { swapOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state;
const swapQuoter = providerState.swapQuoter;
if (
selectedAssetUnitAmount !== undefined &&
selectedAsset !== undefined &&
selectedAssetUnitAmount.isGreaterThan(BIG_NUMBER_ZERO) &&
buyOrderState.processState === OrderProcessState.None
swapOrderState.processState === OrderProcessState.None
) {
await buyQuoteUpdater.updateBuyQuoteAsync(
assetBuyer,
await swapQuoteUpdater.updateSwapQuoteAsync(
swapQuoter,
dispatch,
selectedAsset,
selectedAssetUnitAmount,

View File

@ -1,4 +1,4 @@
import { BuyQuote } from '@0x/asset-buyer';
import { MarketBuySwapQuote } from '@0x/asset-swapper';
import { AssetProxyId, ObjectMap } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
@ -30,7 +30,7 @@ import { Action, ActionTypes } from './actions';
export interface DefaultState {
network: Network;
assetMetaDataMap: ObjectMap<AssetMetaData>;
buyOrderState: OrderState;
swapOrderState: OrderState;
latestErrorDisplayStatus: DisplayStatus;
quoteRequestState: AsyncProcessState;
standardSlidingPanelSettings: StandardSlidingPanelSettings;
@ -48,7 +48,7 @@ interface OptionalState {
availableAssets: Asset[];
selectedAssetUnitAmount: BigNumber;
ethUsdPrice: BigNumber;
latestBuyQuote: BuyQuote;
latestSwapQuote: MarketBuySwapQuote;
latestErrorMessage: string;
affiliateInfo: AffiliateInfo;
walletDisplayName: string;
@ -60,7 +60,7 @@ export type State = DefaultState & PropsDerivedState & Partial<OptionalState>;
export const DEFAULT_STATE: DefaultState = {
network: Network.Mainnet,
assetMetaDataMap,
buyOrderState: { processState: OrderProcessState.None },
swapOrderState: { processState: OrderProcessState.None },
latestErrorDisplayStatus: DisplayStatus.Hidden,
quoteRequestState: AsyncProcessState.None,
standardSlidingPanelSettings: {
@ -115,14 +115,14 @@ export const createReducer = (initialState: State) => {
...state,
selectedAssetUnitAmount: action.data,
};
case ActionTypes.UpdateLatestBuyQuote:
const newBuyQuoteIfExists = action.data;
case ActionTypes.UpdateLatestSwapQuote:
const newSwapQuoteIfExists = action.data;
const shouldUpdate =
newBuyQuoteIfExists === undefined || doesBuyQuoteMatchState(newBuyQuoteIfExists, state);
newSwapQuoteIfExists === undefined || doesSwapQuoteMatchState(newSwapQuoteIfExists, state);
if (shouldUpdate) {
return {
...state,
latestBuyQuote: newBuyQuoteIfExists,
latestSwapQuote: newSwapQuoteIfExists,
quoteRequestState: AsyncProcessState.Success,
};
} else {
@ -131,31 +131,31 @@ export const createReducer = (initialState: State) => {
case ActionTypes.SetQuoteRequestStatePending:
return {
...state,
latestBuyQuote: undefined,
latestSwapQuote: undefined,
quoteRequestState: AsyncProcessState.Pending,
};
case ActionTypes.SetQuoteRequestStateFailure:
return {
...state,
latestBuyQuote: undefined,
latestSwapQuote: undefined,
quoteRequestState: AsyncProcessState.Failure,
};
case ActionTypes.SetBuyOrderStateNone:
case ActionTypes.SetSwapOrderStateNone:
return {
...state,
buyOrderState: { processState: OrderProcessState.None },
swapOrderState: { processState: OrderProcessState.None },
};
case ActionTypes.SetBuyOrderStateValidating:
case ActionTypes.SetSwapOrderStateValidating:
return {
...state,
buyOrderState: { processState: OrderProcessState.Validating },
swapOrderState: { processState: OrderProcessState.Validating },
};
case ActionTypes.SetBuyOrderStateProcessing:
case ActionTypes.SetSwapOrderStateProcessing:
const processingData = action.data;
const { startTimeUnix, expectedEndTimeUnix } = processingData;
return {
...state,
buyOrderState: {
swapOrderState: {
processState: OrderProcessState.Processing,
txHash: processingData.txHash,
progress: {
@ -164,14 +164,14 @@ export const createReducer = (initialState: State) => {
},
},
};
case ActionTypes.SetBuyOrderStateFailure:
case ActionTypes.SetSwapOrderStateFailure:
const failureTxHash = action.data;
if ('txHash' in state.buyOrderState) {
if (state.buyOrderState.txHash === failureTxHash) {
const { txHash, progress } = state.buyOrderState;
if ('txHash' in state.swapOrderState) {
if (state.swapOrderState.txHash === failureTxHash) {
const { txHash, progress } = state.swapOrderState;
return {
...state,
buyOrderState: {
swapOrderState: {
processState: OrderProcessState.Failure,
txHash,
progress,
@ -180,14 +180,14 @@ export const createReducer = (initialState: State) => {
}
}
return state;
case ActionTypes.SetBuyOrderStateSuccess:
case ActionTypes.SetSwapOrderStateSuccess:
const successTxHash = action.data;
if ('txHash' in state.buyOrderState) {
if (state.buyOrderState.txHash === successTxHash) {
const { txHash, progress } = state.buyOrderState;
if ('txHash' in state.swapOrderState) {
if (state.swapOrderState.txHash === successTxHash) {
const { txHash, progress } = state.swapOrderState;
return {
...state,
buyOrderState: {
swapOrderState: {
processState: OrderProcessState.Success,
txHash,
progress,
@ -221,9 +221,9 @@ export const createReducer = (initialState: State) => {
case ActionTypes.ResetAmount:
return {
...state,
latestBuyQuote: undefined,
latestSwapQuote: undefined,
quoteRequestState: AsyncProcessState.None,
buyOrderState: { processState: OrderProcessState.None },
swapOrderState: { processState: OrderProcessState.None },
selectedAssetUnitAmount: undefined,
};
case ActionTypes.SetAvailableAssets:
@ -271,18 +271,18 @@ const reduceStateWithAccount = (state: State, account: Account) => {
};
};
const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => {
const doesSwapQuoteMatchState = (swapQuote: MarketBuySwapQuote , state: State): boolean => {
const selectedAssetIfExists = state.selectedAsset;
const selectedAssetUnitAmountIfExists = state.selectedAssetUnitAmount;
// if no selectedAsset or selectedAssetAmount exists on the current state, return false
if (selectedAssetIfExists === undefined || selectedAssetUnitAmountIfExists === undefined) {
return false;
}
// if buyQuote's assetData does not match that of the current selected asset, return false
if (selectedAssetIfExists.assetData !== buyQuote.assetData) {
// if swapQuote's assetData does not match that of the current selected asset, return false
if (selectedAssetIfExists.assetData !== swapQuote.makerAssetData) {
return false;
}
// if ERC20 and buyQuote's assetBuyAmount does not match selectedAssetAmount, return false
// if ERC20 and swapQuote's makerAssetFillAmount does not match selectedAssetAmount, return false
// if ERC721, return true
const selectedAssetMetaData = selectedAssetIfExists.metaData;
if (selectedAssetMetaData.assetProxyId === AssetProxyId.ERC20) {
@ -290,7 +290,7 @@ const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => {
selectedAssetUnitAmountIfExists,
selectedAssetMetaData.decimals,
);
const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(buyQuote.assetBuyAmount);
const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(swapQuote.makerAssetFillAmount);
return doesAssetAmountMatch;
} else {
return true;

View File

@ -1,4 +1,4 @@
import { AssetBuyer, BigNumber } from '@0x/asset-buyer';
import { BigNumber, SwapQuoteConsumer, SwapQuoter } from '@0x/asset-swapper';
import { AssetProxyId, ObjectMap, SignedOrder } from '@0x/types';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { SupportedProvider, ZeroExProvider } from 'ethereum-types';
@ -110,7 +110,8 @@ export interface ProviderState {
name: string;
displayName: string;
provider: ZeroExProvider;
assetBuyer: AssetBuyer;
swapQuoter: SwapQuoter;
swapQuoteConsumer: SwapQuoteConsumer;
web3Wrapper: Web3Wrapper;
account: Account;
}

View File

@ -1,4 +1,4 @@
import { BuyQuote } from '@0x/asset-buyer';
import { MarketBuySwapQuote, SwapQuote } from '@0x/asset-swapper';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
@ -82,20 +82,17 @@ function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: Ev
};
}
const buyQuoteEventProperties = (buyQuote: BuyQuote) => {
const assetBuyAmount = buyQuote.assetBuyAmount.toString();
const assetEthAmount = buyQuote.worstCaseQuoteInfo.assetEthAmount.toString();
const feeEthAmount = buyQuote.worstCaseQuoteInfo.feeEthAmount.toString();
const totalEthAmount = buyQuote.worstCaseQuoteInfo.totalEthAmount.toString();
const feePercentage = buyQuote.feePercentage !== undefined ? buyQuote.feePercentage.toString() : 0;
const hasFeeOrders = !_.isEmpty(buyQuote.feeOrders) ? 'true' : 'false';
const swapQuoteEventProperties = (swapQuote: MarketBuySwapQuote) => {
const assetBuyAmount = swapQuote.makerAssetFillAmount.toString();
const assetEthAmount = swapQuote.worstCaseQuoteInfo.takerAssetAmount.toString();
const feeEthAmount = swapQuote.worstCaseQuoteInfo.protocolFeeInEthAmount.plus(swapQuote.worstCaseQuoteInfo.feeTakerAssetAmount).toString();
const totalEthAmount = swapQuote.worstCaseQuoteInfo.totalTakerAssetAmount.toString();
// const feePercentage = swapQuote.feePercentage !== undefined ? buyQuote.feePercentage.toString() : 0;
return {
assetBuyAmount,
assetEthAmount,
feeEthAmount,
totalEthAmount,
feePercentage,
hasFeeOrders,
};
};
@ -182,35 +179,35 @@ export const analytics = {
trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PaymentMethodDropdownOpened),
trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PaymentMethodOpenedEtherscan),
trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PaymentMethodCopiedAddress),
trackBuyNotEnoughEth: (buyQuote: BuyQuote) =>
trackingEventFnWithPayload(EventNames.BuyNotEnoughEth)(buyQuoteEventProperties(buyQuote)),
trackBuyStarted: (buyQuote: BuyQuote) =>
trackingEventFnWithPayload(EventNames.BuyStarted)(buyQuoteEventProperties(buyQuote)),
trackBuySignatureDenied: (buyQuote: BuyQuote) =>
trackingEventFnWithPayload(EventNames.BuySignatureDenied)(buyQuoteEventProperties(buyQuote)),
trackBuySimulationFailed: (buyQuote: BuyQuote) =>
trackingEventFnWithPayload(EventNames.BuySimulationFailed)(buyQuoteEventProperties(buyQuote)),
trackBuyUnknownError: (buyQuote: BuyQuote, errorMessage: string) =>
trackBuyNotEnoughEth: (swapQuote: MarketBuySwapQuote) =>
trackingEventFnWithPayload(EventNames.BuyNotEnoughEth)(swapQuoteEventProperties(swapQuote)),
trackBuyStarted: (swapQuote: MarketBuySwapQuote) =>
trackingEventFnWithPayload(EventNames.BuyStarted)(swapQuoteEventProperties(swapQuote)),
trackBuySignatureDenied: (swapQuote: MarketBuySwapQuote) =>
trackingEventFnWithPayload(EventNames.BuySignatureDenied)(swapQuoteEventProperties(swapQuote)),
trackBuySimulationFailed: (swapQuote: MarketBuySwapQuote) =>
trackingEventFnWithPayload(EventNames.BuySimulationFailed)(swapQuoteEventProperties(swapQuote)),
trackBuyUnknownError: (swapQuote: MarketBuySwapQuote, errorMessage: string) =>
trackingEventFnWithPayload(EventNames.BuyUnknownError)({
...buyQuoteEventProperties(buyQuote),
...swapQuoteEventProperties(swapQuote),
errorMessage,
}),
trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackBuyTxSubmitted: (swapQuote: MarketBuySwapQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackingEventFnWithPayload(EventNames.BuyTxSubmitted)({
...buyQuoteEventProperties(buyQuote),
...swapQuoteEventProperties(swapQuote),
txHash,
expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
}),
trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackBuyTxSucceeded: (swapQuote: MarketBuySwapQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackingEventFnWithPayload(EventNames.BuyTxSucceeded)({
...buyQuoteEventProperties(buyQuote),
...swapQuoteEventProperties(swapQuote),
txHash,
expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
actualTxTimeMs: new Date().getTime() - startTimeUnix,
}),
trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackBuyTxFailed: (swapQuote: MarketBuySwapQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) =>
trackingEventFnWithPayload(EventNames.BuyTxFailed)({
...buyQuoteEventProperties(buyQuote),
...swapQuoteEventProperties(swapQuote),
txHash,
expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix,
actualTxTimeMs: new Date().getTime() - startTimeUnix,
@ -232,9 +229,9 @@ export const analytics = {
trackingEventFnWithPayload(EventNames.TokenSelectorSearched)({ searchText }),
trackTransactionViewed: (orderProcesState: OrderProcessState) =>
trackingEventFnWithPayload(EventNames.TransactionViewed)({ orderState: orderProcesState }),
trackQuoteFetched: (buyQuote: BuyQuote, fetchOrigin: QuoteFetchOrigin) =>
trackQuoteFetched: (swapQuote: MarketBuySwapQuote, fetchOrigin: QuoteFetchOrigin) =>
trackingEventFnWithPayload(EventNames.QuoteFetched)({
...buyQuoteEventProperties(buyQuote),
...swapQuoteEventProperties(swapQuote),
fetchOrigin,
}),
trackQuoteError: (errorMessage: string, assetBuyAmount: BigNumber, fetchOrigin: QuoteFetchOrigin) => {

View File

@ -1,4 +1,4 @@
import { AssetBuyerError, InsufficientAssetLiquidityError } from '@0x/asset-buyer';
import { InsufficientAssetLiquidityError, SwapQuoterError } from '@0x/asset-swapper';
import { AssetProxyId, ObjectMap } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
@ -109,8 +109,8 @@ export const assetUtils = {
);
return _.compact(erc20sOrUndefined);
},
assetBuyerErrorMessage: (asset: Asset, error: Error): string | undefined => {
if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
swapQuoterErrorMessage: (asset: Asset, error: Error): string | undefined => {
if (error.message === SwapQuoterError.InsufficientAssetLiquidity) {
const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
if (
error instanceof InsufficientAssetLiquidityError &&
@ -131,11 +131,9 @@ export const assetUtils = {
}
return `Not enough ${assetName} available`;
} else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
return 'Not enough ZRX available';
} else if (
error.message === AssetBuyerError.StandardRelayerApiError ||
error.message.startsWith(AssetBuyerError.AssetUnavailable)
error.message === SwapQuoterError.StandardRelayerApiError ||
error.message.startsWith(SwapQuoterError.AssetUnavailable)
) {
const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
return `${assetName} is currently unavailable`;

View File

@ -1,17 +0,0 @@
import { AssetBuyer, AssetBuyerOpts } from '@0x/asset-buyer';
import { SupportedProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { Network, OrderSource } from '../types';
export const assetBuyerFactory = {
getAssetBuyer: (supportedProvider: SupportedProvider, orderSource: OrderSource, network: Network): AssetBuyer => {
const assetBuyerOptions: Partial<AssetBuyerOpts> = {
networkId: network,
};
const assetBuyer = _.isString(orderSource)
? AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(supportedProvider, orderSource, assetBuyerOptions)
: AssetBuyer.getAssetBuyerForProvidedOrders(supportedProvider, orderSource, assetBuyerOptions);
return assetBuyer;
},
};

View File

@ -0,0 +1,23 @@
import { SwapQuoteConsumer, SwapQuoter, SwapQuoteConsumerOpts, SwapQuoterOpts } from '@0x/asset-swapper';
import { SupportedProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { Network, OrderSource } from '../types';
export const assetSwapperFactory = {
getSwapQuoter: (supportedProvider: SupportedProvider, orderSource: OrderSource, network: Network): SwapQuoter => {
const swapQuoterOpts: Partial<SwapQuoterOpts> = {
chainId: network,
};
const swapQuoter = _.isString(orderSource)
? SwapQuoter.getSwapQuoterForStandardRelayerAPIUrl(supportedProvider, orderSource, swapQuoterOpts)
: SwapQuoter.getSwapQuoterForProvidedOrders(supportedProvider, orderSource, swapQuoterOpts);
return swapQuoter;
},
getSwapQuoteConsumer: (supportedProvider: SupportedProvider, network: Network): SwapQuoteConsumer => {
const swapQuoteConsumerOptions: Partial<SwapQuoterOpts> = {
chainId: network,
};
return new SwapQuoteConsumer(supportedProvider, swapQuoteConsumerOptions );
},
};

View File

@ -15,10 +15,10 @@ export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): He
}, shouldPerformImmediatelyOnStart);
};
export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
export const generateSwapQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
const { store, shouldPerformImmediatelyOnStart } = options;
return new Heartbeater(async () => {
await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(
await asyncData.fetchCurrentSwapQuoteAndDispatchToStore(
store.getState(),
store.dispatch,
QuoteFetchOrigin.Heartbeat,

View File

@ -7,7 +7,7 @@ import { LOADING_ACCOUNT, NO_ACCOUNT } from '../constants';
import { Maybe, Network, OrderSource, ProviderState } from '../types';
import { envUtil } from '../util/env';
import { assetBuyerFactory } from './asset_buyer_factory';
import { assetSwapperFactory } from './asset_swapper_factory';
import { providerFactory } from './provider_factory';
export const providerStateFactory = {
@ -48,7 +48,8 @@ export const providerStateFactory = {
displayName: walletDisplayName || envUtil.getProviderDisplayName(provider),
provider,
web3Wrapper: new Web3Wrapper(provider),
assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network),
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, network),
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, network),
account: LOADING_ACCOUNT,
};
return providerState;
@ -65,7 +66,8 @@ export const providerStateFactory = {
displayName: walletDisplayName || envUtil.getProviderDisplayName(injectedProviderIfExists),
provider: injectedProviderIfExists,
web3Wrapper: new Web3Wrapper(injectedProviderIfExists),
assetBuyer: assetBuyerFactory.getAssetBuyer(injectedProviderIfExists, orderSource, network),
swapQuoter: assetSwapperFactory.getSwapQuoter(injectedProviderIfExists, orderSource, network),
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(injectedProviderIfExists, network),
account: LOADING_ACCOUNT,
};
return providerState;
@ -84,7 +86,8 @@ export const providerStateFactory = {
displayName: walletDisplayName || envUtil.getProviderDisplayName(provider),
provider,
web3Wrapper: new Web3Wrapper(provider),
assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network),
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, network),
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, network),
account: NO_ACCOUNT,
};
return providerState;

View File

@ -1,4 +1,4 @@
import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
import { SwapQuote, SwapQuoter } from '@0x/asset-swapper';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
@ -6,17 +6,17 @@ import * as _ from 'lodash';
import { Dispatch } from 'redux';
import { oc } from 'ts-optchain';
import { ERC20_BUY_QUOTE_SLIPPAGE_PERCENTAGE, ERC721_BUY_QUOTE_SLIPPAGE_PERCENTAGE } from '../constants';
import { ERC20_SWAP_QUOTE_SLIPPAGE_PERCENTAGE, ERC721_SWAP_QUOTE_SLIPPAGE_PERCENTAGE } from '../constants';
import { Action, actions } from '../redux/actions';
import { AffiliateInfo, Asset, QuoteFetchOrigin } from '../types';
import { analytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { errorFlasher } from '../util/error_flasher';
import { errorReporter } from '../util/error_reporter';
import { analytics } from './analytics';
import { assetUtils } from './asset';
import { errorFlasher } from './error_flasher';
import { errorReporter } from './error_reporter';
export const buyQuoteUpdater = {
updateBuyQuoteAsync: async (
assetBuyer: AssetBuyer,
export const swapQuoteUpdater = {
updateSwapQuoteAsync: async (
swapQuoter: SwapQuoter,
dispatch: Dispatch<Action>,
asset: Asset,
assetUnitAmount: BigNumber,
@ -27,7 +27,7 @@ export const buyQuoteUpdater = {
affiliateInfo?: AffiliateInfo;
},
): Promise<void> => {
// get a new buy quote.
// get a new swap quote.
const baseUnitValue =
asset.metaData.assetProxyId === AssetProxyId.ERC20
? Web3Wrapper.toBaseUnitAmount(assetUnitAmount, asset.metaData.decimals)
@ -36,19 +36,20 @@ export const buyQuoteUpdater = {
// mark quote as pending
dispatch(actions.setQuoteRequestStatePending());
}
// TODO(dave4506) expose wethAssetData + feePercentage utils
const wethAssetData = '';
const feePercentage = oc(options.affiliateInfo).feePercentage();
let newBuyQuote: BuyQuote | undefined;
let newSwapQuote: SwapQuote | undefined;
const slippagePercentage =
asset.metaData.assetProxyId === AssetProxyId.ERC20
? ERC20_BUY_QUOTE_SLIPPAGE_PERCENTAGE
: ERC721_BUY_QUOTE_SLIPPAGE_PERCENTAGE;
? ERC20_SWAP_QUOTE_SLIPPAGE_PERCENTAGE
: ERC721_SWAP_QUOTE_SLIPPAGE_PERCENTAGE;
try {
newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, {
feePercentage,
newSwapQuote = await swapQuoter.getMarketBuySwapQuoteAsync(wethAssetData, asset.assetData, assetUnitAmount, {
slippagePercentage,
});
} catch (error) {
const errorMessage = assetUtils.assetBuyerErrorMessage(asset, error);
const errorMessage = assetUtils.swapQuoterErrorMessage(asset, error);
errorReporter.report(error);
analytics.trackQuoteError(error.message ? error.message : 'other', baseUnitValue, fetchOrigin);
@ -59,10 +60,10 @@ export const buyQuoteUpdater = {
}
return;
}
// We have a successful new buy quote
// We have a successful new swap quote
errorFlasher.clearError(dispatch);
// invalidate the last buy quote.
dispatch(actions.updateLatestBuyQuote(newBuyQuote));
analytics.trackQuoteFetched(newBuyQuote, fetchOrigin);
// invalidate the last swap quote.
dispatch(actions.updateLatestSwapQuote(newSwapQuote));
analytics.trackQuoteFetched(newSwapQuote, fetchOrigin);
},
};