Use existing functions instead of writing our own

This commit is contained in:
Steve Klebanoff
2018-11-09 10:40:47 -08:00
parent df91d34315
commit 2e8f74abce
7 changed files with 28 additions and 94 deletions

View File

@@ -99,13 +99,13 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
}
// tslint:disable-next-line:no-floating-promises
// asyncData.fetchAccountInfoAndDispatchToStore(this._store);
this._accountUpdateHeartbeat = generateAccountHeartbeater(this._store);
this._accountUpdateHeartbeat = generateAccountHeartbeater(this._store, true);
this._accountUpdateHeartbeat.start(ACCOUNT_UPDATE_INTERVAL_TIME_MS);
this._buyQuoteHeartbeat = generateBuyQuoteHeartbeater(this._store);
this._buyQuoteHeartbeat = generateBuyQuoteHeartbeater(this._store, false);
this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS);
asyncData.fetchCurrentBuyQuoteAndDispatchToStore(this._store, true);
// warm up the gas price estimator cache just in case we can't
// grab the gas price estimate when submitting the transaction

View File

@@ -11,7 +11,6 @@ import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { ColorOption } from '../style/theme';
import { AffiliateInfo, ERC20Asset, OrderProcessState } from '../types';
import { updateBuyQuoteOrFlashErrorAsync } from '../util/buy_quote_fetcher';
import { buyQuoteUpdater } from '../util/buy_quote_updater';
export interface SelectedERC20AssetAmountInputProps {
@@ -68,10 +67,9 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP
};
};
// TODO: change to set pending to true
const debouncedUpdateBuyQuoteAsync = _.debounce(buyQuoteUpdater.updateBuyQuoteAsync.bind(buyQuoteUpdater), 200, {
trailing: true,
});
}) as typeof buyQuoteUpdater.updateBuyQuoteAsync;
const mapDispatchToProps = (
dispatch: Dispatch<Action>,
@@ -89,7 +87,7 @@ const mapDispatchToProps = (
// 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, affiliateInfo);
debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, true, affiliateInfo);
}
},
});

View File

@@ -74,7 +74,7 @@ export const asyncData = {
return;
}
},
fetchCurrentBuyQuoteAndDispatchToStore: async (store: Store) => {
fetchCurrentBuyQuoteAndDispatchToStore: async (store: Store, setPending: boolean) => {
const { providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = store.getState();
const assetBuyer = providerState.assetBuyer;
if (
@@ -87,6 +87,7 @@ export const asyncData = {
store.dispatch,
selectedAsset as ERC20Asset,
selectedAssetAmount,
setPending,
affiliateInfo,
);
}

View File

@@ -1,75 +0,0 @@
// TODO: rename file and export object
// TODO: delete this
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import { Dispatch } from 'redux';
import { oc } from 'ts-optchain';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { AffiliateInfo, ERC20Asset } from '../types';
import { assetUtils } from '../util/asset';
import { errorFlasher } from './error_flasher';
export const updateBuyQuoteOrFlashErrorAsync = async (
assetBuyer: AssetBuyer,
asset: ERC20Asset,
assetAmount: BigNumber,
dispatch: Dispatch<Action>,
affiliateInfo?: AffiliateInfo,
) => {
// get a new buy quote.
const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals);
const feePercentage = oc(affiliateInfo).feePercentage();
let newBuyQuote: BuyQuote | undefined;
try {
newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
} catch (error) {
dispatch(actions.setQuoteRequestStateFailure());
let errorMessage;
if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
errorMessage = `Not enough ${assetName} available`;
} else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
errorMessage = 'Not enough ZRX available';
} else if (
error.message === AssetBuyerError.StandardRelayerApiError ||
error.message.startsWith(AssetBuyerError.AssetUnavailable)
) {
const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
errorMessage = `${assetName} is currently unavailable`;
}
if (!_.isUndefined(errorMessage)) {
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
} else {
throw error;
}
return;
}
// We have a successful new buy quote
errorFlasher.clearError(dispatch);
// invalidate the last buy quote.
dispatch(actions.updateLatestBuyQuote(newBuyQuote));
};
export const updateBuyQuoteOrFlashErrorAsyncForState = async (state: State, dispatch: Dispatch<Action>) => {
const { selectedAsset, selectedAssetAmount, affiliateInfo } = state;
const assetBuyer = state.providerState.assetBuyer;
if (selectedAsset && selectedAssetAmount && selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20) {
// TODO: maybe dont do in the case of an error showing
updateBuyQuoteOrFlashErrorAsync(
assetBuyer,
selectedAsset as ERC20Asset, // TODO: better way to do this?
selectedAssetAmount,
dispatch,
affiliateInfo,
);
}
};

View File

@@ -1,4 +1,5 @@
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
@@ -6,6 +7,7 @@ import { Dispatch } from 'redux';
import { oc } from 'ts-optchain';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { AffiliateInfo, ERC20Asset } from '../types';
import { assetUtils } from '../util/asset';
import { errorFlasher } from '../util/error_flasher';
@@ -16,12 +18,15 @@ export const buyQuoteUpdater = {
dispatch: Dispatch<Action>,
asset: ERC20Asset,
assetAmount: BigNumber,
setPending = true,
affiliateInfo?: AffiliateInfo,
): Promise<void> => {
// get a new buy quote.
const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals);
// mark quote as pending
dispatch(actions.setQuoteRequestStatePending());
if (setPending) {
// mark quote as pending
dispatch(actions.setQuoteRequestStatePending());
}
const feePercentage = oc(affiliateInfo).feePercentage();
let newBuyQuote: BuyQuote | undefined;
try {

View File

@@ -4,18 +4,24 @@ type HeartbeatableFunction = () => Promise<void>;
export class Heartbeater {
private _intervalId?: number;
private _hasPendingRequest: boolean;
private _performImmediatelyOnStart: boolean;
private _performFunction: HeartbeatableFunction;
public constructor(_performingFunctionAsync: HeartbeatableFunction) {
this._performFunction = _performingFunctionAsync;
public constructor(performingFunctionAsync: HeartbeatableFunction, performImmediatelyOnStart: boolean) {
this._performFunction = performingFunctionAsync;
this._hasPendingRequest = false;
this._performImmediatelyOnStart = performImmediatelyOnStart;
}
public start(intervalTimeMs: number): void {
if (!_.isUndefined(this._intervalId)) {
throw new Error('Heartbeat is running, please stop before restarting');
}
this._trackAndPerformAsync();
if (this._performImmediatelyOnStart) {
this._trackAndPerformAsync();
}
this._intervalId = window.setInterval(this._trackAndPerformAsync.bind(this), intervalTimeMs);
}

View File

@@ -1,17 +1,16 @@
import { asyncData } from '../redux/async_data';
import { Store } from '../redux/store';
import { updateBuyQuoteOrFlashErrorAsyncForState } from './buy_quote_fetcher';
import { Heartbeater } from './heartbeater';
export const generateAccountHeartbeater = (store: Store): Heartbeater => {
export const generateAccountHeartbeater = (store: Store, performImmediatelyOnStart: boolean): Heartbeater => {
return new Heartbeater(async () => {
await asyncData.fetchAccountInfoAndDispatchToStore(store, { setLoading: false });
});
}, performImmediatelyOnStart);
};
export const generateBuyQuoteHeartbeater = (store: Store): Heartbeater => {
export const generateBuyQuoteHeartbeater = (store: Store, performImmediatelyOnStart: boolean): Heartbeater => {
return new Heartbeater(async () => {
await updateBuyQuoteOrFlashErrorAsyncForState(store.getState(), store.dispatch);
});
await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store, false);
}, performImmediatelyOnStart);
};