diff --git a/app/scripts/controllers/swaps.js b/app/scripts/controllers/swaps.js index ced804a35..a464729c1 100644 --- a/app/scripts/controllers/swaps.js +++ b/app/scripts/controllers/swaps.js @@ -12,6 +12,7 @@ import { DEFAULT_ERC20_APPROVE_GAS, QUOTES_EXPIRED_ERROR, QUOTES_NOT_AVAILABLE_ERROR, + SWAPS_FETCH_ORDER_CONFLICT, } from '../../../ui/app/helpers/constants/swaps' import { fetchTradesInfo as defaultFetchTradesInfo, @@ -88,6 +89,8 @@ export default class SwapsController { this.pollCount = 0 this.getProviderConfig = getProviderConfig + this.indexOfNewestCallInFlight = 0 + this.ethersProvider = new ethers.providers.Web3Provider(provider) this._setupSwapsLivenessFetching() @@ -124,6 +127,10 @@ export default class SwapsController { if (!isPolledRequest) { this.setSwapsErrorKey('') } + + const indexOfCurrentCall = this.indexOfNewestCallInFlight + 1 + this.indexOfNewestCallInFlight = indexOfCurrentCall + let newQuotes = await this._fetchTradesInfo(fetchParams) newQuotes = mapValues(newQuotes, (quote) => ({ @@ -184,11 +191,18 @@ export default class SwapsController { } } + // If a newer call has been made, don't update state with old information + // Prevents timing conflicts between fetches + if (this.indexOfNewestCallInFlight !== indexOfCurrentCall) { + throw new Error(SWAPS_FETCH_ORDER_CONFLICT) + } + const { swapsState } = this.store.getState() let { selectedAggId } = swapsState if (!newQuotes[selectedAggId]) { selectedAggId = null } + this.store.updateState({ swapsState: { ...swapsState, diff --git a/ui/app/ducks/swaps/swaps.js b/ui/app/ducks/swaps/swaps.js index e6fbb71e7..ad45036d4 100644 --- a/ui/app/ducks/swaps/swaps.js +++ b/ui/app/ducks/swaps/swaps.js @@ -36,6 +36,7 @@ import { QUOTES_NOT_AVAILABLE_ERROR, ETH_SWAPS_TOKEN_OBJECT, SWAP_FAILED_ERROR, + SWAPS_FETCH_ORDER_CONFLICT, } from '../../helpers/constants/swaps' import { SWAP, SWAP_APPROVAL } from '../../helpers/constants/transactions' import { fetchBasicGasAndTimeEstimates, fetchGasEstimates, resetCustomGasState } from '../gas/gas.duck' @@ -399,6 +400,10 @@ export const fetchQuotesAndSetQuoteState = (history, inputValue, maxSlippage, me dispatch(setInitialGasEstimate(selectedAggId)) } } catch (e) { + // A newer swap request is running, so simply bail and let the newer request respond + if (e.message === SWAPS_FETCH_ORDER_CONFLICT) { + return + } dispatch(setSwapsErrorKey(ERROR_FETCHING_QUOTES)) } diff --git a/ui/app/helpers/constants/swaps.js b/ui/app/helpers/constants/swaps.js index f9ccc5a78..a20000a0c 100644 --- a/ui/app/helpers/constants/swaps.js +++ b/ui/app/helpers/constants/swaps.js @@ -14,6 +14,7 @@ export const SWAP_FAILED_ERROR = 'swap-failed-error' export const ERROR_FETCHING_QUOTES = 'error-fetching-quotes' export const QUOTES_NOT_AVAILABLE_ERROR = 'quotes-not-avilable' export const OFFLINE_FOR_MAINTENANCE = 'offline-for-maintenance' +export const SWAPS_FETCH_ORDER_CONFLICT = 'swaps-fetch-order-conflict' // A gas value for ERC20 approve calls that should be sufficient for all ERC20 approve implementations export const DEFAULT_ERC20_APPROVE_GAS = '0x1d4c0'