Use existing functions instead of writing our own
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user