mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-10-22 19:26:13 +02:00
Fetch swap quote refresh time from API (#10069)
This commit is contained in:
parent
6c637bba9c
commit
88525ec392
@ -17,6 +17,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
fetchTradesInfo as defaultFetchTradesInfo,
|
fetchTradesInfo as defaultFetchTradesInfo,
|
||||||
fetchSwapsFeatureLiveness as defaultFetchSwapsFeatureLiveness,
|
fetchSwapsFeatureLiveness as defaultFetchSwapsFeatureLiveness,
|
||||||
|
fetchSwapsQuoteRefreshTime as defaultFetchSwapsQuoteRefreshTime,
|
||||||
} from '../../../ui/app/pages/swaps/swaps.util'
|
} from '../../../ui/app/pages/swaps/swaps.util'
|
||||||
|
|
||||||
const METASWAP_ADDRESS = '0x881d40237659c251811cec9c364ef91dc08d300c'
|
const METASWAP_ADDRESS = '0x881d40237659c251811cec9c364ef91dc08d300c'
|
||||||
@ -28,6 +29,14 @@ const MAX_GAS_LIMIT = 2500000
|
|||||||
// 3 seems to be an appropriate balance of giving users the time they need when MetaMask is not left idle, and turning polling off when it is.
|
// 3 seems to be an appropriate balance of giving users the time they need when MetaMask is not left idle, and turning polling off when it is.
|
||||||
const POLL_COUNT_LIMIT = 3
|
const POLL_COUNT_LIMIT = 3
|
||||||
|
|
||||||
|
// If for any reason the MetaSwap API fails to provide a refresh time,
|
||||||
|
// provide a reasonable fallback to avoid further errors
|
||||||
|
const FALLBACK_QUOTE_REFRESH_TIME = 60000
|
||||||
|
|
||||||
|
// This is the amount of time to wait, after successfully fetching quotes
|
||||||
|
// and their gas estimates, before fetching for new quotes
|
||||||
|
const QUOTE_POLLING_DIFFERENCE_INTERVAL = 10 * 1000
|
||||||
|
|
||||||
function calculateGasEstimateWithRefund(
|
function calculateGasEstimateWithRefund(
|
||||||
maxGas = MAX_GAS_LIMIT,
|
maxGas = MAX_GAS_LIMIT,
|
||||||
estimatedRefund = 0,
|
estimatedRefund = 0,
|
||||||
@ -42,9 +51,6 @@ function calculateGasEstimateWithRefund(
|
|||||||
return gasEstimateWithRefund
|
return gasEstimateWithRefund
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the amount of time to wait, after successfully fetching quotes and their gas estimates, before fetching for new quotes
|
|
||||||
const QUOTE_POLLING_INTERVAL = 50 * 1000
|
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
swapsState: {
|
swapsState: {
|
||||||
quotes: {},
|
quotes: {},
|
||||||
@ -61,6 +67,7 @@ const initialState = {
|
|||||||
topAggId: null,
|
topAggId: null,
|
||||||
routeState: '',
|
routeState: '',
|
||||||
swapsFeatureIsLive: false,
|
swapsFeatureIsLive: false,
|
||||||
|
swapsQuoteRefreshTime: FALLBACK_QUOTE_REFRESH_TIME,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +80,7 @@ export default class SwapsController {
|
|||||||
tokenRatesStore,
|
tokenRatesStore,
|
||||||
fetchTradesInfo = defaultFetchTradesInfo,
|
fetchTradesInfo = defaultFetchTradesInfo,
|
||||||
fetchSwapsFeatureLiveness = defaultFetchSwapsFeatureLiveness,
|
fetchSwapsFeatureLiveness = defaultFetchSwapsFeatureLiveness,
|
||||||
|
fetchSwapsQuoteRefreshTime = defaultFetchSwapsQuoteRefreshTime,
|
||||||
}) {
|
}) {
|
||||||
this.store = new ObservableStore({
|
this.store = new ObservableStore({
|
||||||
swapsState: { ...initialState.swapsState },
|
swapsState: { ...initialState.swapsState },
|
||||||
@ -80,6 +88,7 @@ export default class SwapsController {
|
|||||||
|
|
||||||
this._fetchTradesInfo = fetchTradesInfo
|
this._fetchTradesInfo = fetchTradesInfo
|
||||||
this._fetchSwapsFeatureLiveness = fetchSwapsFeatureLiveness
|
this._fetchSwapsFeatureLiveness = fetchSwapsFeatureLiveness
|
||||||
|
this._fetchSwapsQuoteRefreshTime = fetchSwapsQuoteRefreshTime
|
||||||
|
|
||||||
this.getBufferedGasLimit = getBufferedGasLimit
|
this.getBufferedGasLimit = getBufferedGasLimit
|
||||||
this.tokenRatesStore = tokenRatesStore
|
this.tokenRatesStore = tokenRatesStore
|
||||||
@ -101,11 +110,31 @@ export default class SwapsController {
|
|||||||
this._setupSwapsLivenessFetching()
|
this._setupSwapsLivenessFetching()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the refresh rate for quote updates from the MetaSwap API
|
||||||
|
async _setSwapsQuoteRefreshTime() {
|
||||||
|
// Default to fallback time unless API returns valid response
|
||||||
|
let swapsQuoteRefreshTime = FALLBACK_QUOTE_REFRESH_TIME
|
||||||
|
try {
|
||||||
|
swapsQuoteRefreshTime = await this._fetchSwapsQuoteRefreshTime()
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Request for swaps quote refresh time failed: ', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { swapsState } = this.store.getState()
|
||||||
|
this.store.updateState({
|
||||||
|
swapsState: { ...swapsState, swapsQuoteRefreshTime },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Once quotes are fetched, we poll for new ones to keep the quotes up to date. Market and aggregator contract conditions can change fast enough
|
// Once quotes are fetched, we poll for new ones to keep the quotes up to date. Market and aggregator contract conditions can change fast enough
|
||||||
// that quotes will no longer be available after 1 or 2 minutes. When fetchAndSetQuotes is first called it, receives fetch that parameters are stored in
|
// that quotes will no longer be available after 1 or 2 minutes. When fetchAndSetQuotes is first called it, receives fetch that parameters are stored in
|
||||||
// state. These stored parameters are used on subsequent calls made during polling.
|
// state. These stored parameters are used on subsequent calls made during polling.
|
||||||
// Note: we stop polling after 3 requests, until new quotes are explicitly asked for. The logic that enforces that maximum is in the body of fetchAndSetQuotes
|
// Note: we stop polling after 3 requests, until new quotes are explicitly asked for. The logic that enforces that maximum is in the body of fetchAndSetQuotes
|
||||||
pollForNewQuotes() {
|
pollForNewQuotes() {
|
||||||
|
const {
|
||||||
|
swapsState: { swapsQuoteRefreshTime },
|
||||||
|
} = this.store.getState()
|
||||||
|
|
||||||
this.pollingTimeout = setTimeout(() => {
|
this.pollingTimeout = setTimeout(() => {
|
||||||
const { swapsState } = this.store.getState()
|
const { swapsState } = this.store.getState()
|
||||||
this.fetchAndSetQuotes(
|
this.fetchAndSetQuotes(
|
||||||
@ -113,7 +142,7 @@ export default class SwapsController {
|
|||||||
swapsState.fetchParams?.metaData,
|
swapsState.fetchParams?.metaData,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}, QUOTE_POLLING_INTERVAL)
|
}, swapsQuoteRefreshTime - QUOTE_POLLING_DIFFERENCE_INTERVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
stopPollingForQuotes() {
|
stopPollingForQuotes() {
|
||||||
@ -128,7 +157,6 @@ export default class SwapsController {
|
|||||||
if (!fetchParams) {
|
if (!fetchParams) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every time we get a new request that is not from the polling, we reset the poll count so we can poll for up to three more sets of quotes with these new params.
|
// Every time we get a new request that is not from the polling, we reset the poll count so we can poll for up to three more sets of quotes with these new params.
|
||||||
if (!isPolledRequest) {
|
if (!isPolledRequest) {
|
||||||
this.pollCount = 0
|
this.pollCount = 0
|
||||||
@ -144,7 +172,10 @@ export default class SwapsController {
|
|||||||
const indexOfCurrentCall = this.indexOfNewestCallInFlight + 1
|
const indexOfCurrentCall = this.indexOfNewestCallInFlight + 1
|
||||||
this.indexOfNewestCallInFlight = indexOfCurrentCall
|
this.indexOfNewestCallInFlight = indexOfCurrentCall
|
||||||
|
|
||||||
let newQuotes = await this._fetchTradesInfo(fetchParams)
|
let [newQuotes] = await Promise.all([
|
||||||
|
this._fetchTradesInfo(fetchParams),
|
||||||
|
this._setSwapsQuoteRefreshTime(),
|
||||||
|
])
|
||||||
|
|
||||||
newQuotes = mapValues(newQuotes, (quote) => ({
|
newQuotes = mapValues(newQuotes, (quote) => ({
|
||||||
...quote,
|
...quote,
|
||||||
@ -422,6 +453,7 @@ export default class SwapsController {
|
|||||||
tokens: swapsState.tokens,
|
tokens: swapsState.tokens,
|
||||||
fetchParams: swapsState.fetchParams,
|
fetchParams: swapsState.fetchParams,
|
||||||
swapsFeatureIsLive: swapsState.swapsFeatureIsLive,
|
swapsFeatureIsLive: swapsState.swapsFeatureIsLive,
|
||||||
|
swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
clearTimeout(this.pollingTimeout)
|
clearTimeout(this.pollingTimeout)
|
||||||
@ -435,6 +467,7 @@ export default class SwapsController {
|
|||||||
...initialState.swapsState,
|
...initialState.swapsState,
|
||||||
tokens: swapsState.tokens,
|
tokens: swapsState.tokens,
|
||||||
swapsFeatureIsLive: swapsState.swapsFeatureIsLive,
|
swapsFeatureIsLive: swapsState.swapsFeatureIsLive,
|
||||||
|
swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
clearTimeout(this.pollingTimeout)
|
clearTimeout(this.pollingTimeout)
|
||||||
|
@ -121,12 +121,14 @@ const EMPTY_INIT_STATE = {
|
|||||||
topAggId: null,
|
topAggId: null,
|
||||||
routeState: '',
|
routeState: '',
|
||||||
swapsFeatureIsLive: false,
|
swapsFeatureIsLive: false,
|
||||||
|
swapsQuoteRefreshTime: 60000,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const sandbox = sinon.createSandbox()
|
const sandbox = sinon.createSandbox()
|
||||||
const fetchTradesInfoStub = sandbox.stub()
|
const fetchTradesInfoStub = sandbox.stub()
|
||||||
const fetchSwapsFeatureLivenessStub = sandbox.stub()
|
const fetchSwapsFeatureLivenessStub = sandbox.stub()
|
||||||
|
const fetchSwapsQuoteRefreshTimeStub = sandbox.stub()
|
||||||
|
|
||||||
describe('SwapsController', function () {
|
describe('SwapsController', function () {
|
||||||
let provider
|
let provider
|
||||||
@ -140,6 +142,7 @@ describe('SwapsController', function () {
|
|||||||
tokenRatesStore: MOCK_TOKEN_RATES_STORE,
|
tokenRatesStore: MOCK_TOKEN_RATES_STORE,
|
||||||
fetchTradesInfo: fetchTradesInfoStub,
|
fetchTradesInfo: fetchTradesInfoStub,
|
||||||
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
|
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
|
||||||
|
fetchSwapsQuoteRefreshTime: fetchSwapsQuoteRefreshTimeStub,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,9 +642,9 @@ describe('SwapsController', function () {
|
|||||||
const quotes = await swapsController.fetchAndSetQuotes(undefined)
|
const quotes = await swapsController.fetchAndSetQuotes(undefined)
|
||||||
assert.strictEqual(quotes, null)
|
assert.strictEqual(quotes, null)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls fetchTradesInfo with the given fetchParams and returns the correct quotes', async function () {
|
it('calls fetchTradesInfo with the given fetchParams and returns the correct quotes', async function () {
|
||||||
fetchTradesInfoStub.resolves(getMockQuotes())
|
fetchTradesInfoStub.resolves(getMockQuotes())
|
||||||
|
fetchSwapsQuoteRefreshTimeStub.resolves(getMockQuoteRefreshTime())
|
||||||
|
|
||||||
// Make it so approval is not required
|
// Make it so approval is not required
|
||||||
sandbox
|
sandbox
|
||||||
@ -682,9 +685,9 @@ describe('SwapsController', function () {
|
|||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('performs the allowance check', async function () {
|
it('performs the allowance check', async function () {
|
||||||
fetchTradesInfoStub.resolves(getMockQuotes())
|
fetchTradesInfoStub.resolves(getMockQuotes())
|
||||||
|
fetchSwapsQuoteRefreshTimeStub.resolves(getMockQuoteRefreshTime())
|
||||||
|
|
||||||
// Make it so approval is not required
|
// Make it so approval is not required
|
||||||
const allowanceStub = sandbox
|
const allowanceStub = sandbox
|
||||||
@ -707,6 +710,7 @@ describe('SwapsController', function () {
|
|||||||
|
|
||||||
it('gets the gas limit if approval is required', async function () {
|
it('gets the gas limit if approval is required', async function () {
|
||||||
fetchTradesInfoStub.resolves(MOCK_QUOTES_APPROVAL_REQUIRED)
|
fetchTradesInfoStub.resolves(MOCK_QUOTES_APPROVAL_REQUIRED)
|
||||||
|
fetchSwapsQuoteRefreshTimeStub.resolves(getMockQuoteRefreshTime())
|
||||||
|
|
||||||
// Ensure approval is required
|
// Ensure approval is required
|
||||||
sandbox
|
sandbox
|
||||||
@ -732,6 +736,7 @@ describe('SwapsController', function () {
|
|||||||
|
|
||||||
it('marks the best quote', async function () {
|
it('marks the best quote', async function () {
|
||||||
fetchTradesInfoStub.resolves(getMockQuotes())
|
fetchTradesInfoStub.resolves(getMockQuotes())
|
||||||
|
fetchSwapsQuoteRefreshTimeStub.resolves(getMockQuoteRefreshTime())
|
||||||
|
|
||||||
// Make it so approval is not required
|
// Make it so approval is not required
|
||||||
sandbox
|
sandbox
|
||||||
@ -762,6 +767,7 @@ describe('SwapsController', function () {
|
|||||||
}
|
}
|
||||||
const quotes = { ...getMockQuotes(), [bestAggId]: bestQuote }
|
const quotes = { ...getMockQuotes(), [bestAggId]: bestQuote }
|
||||||
fetchTradesInfoStub.resolves(quotes)
|
fetchTradesInfoStub.resolves(quotes)
|
||||||
|
fetchSwapsQuoteRefreshTimeStub.resolves(getMockQuoteRefreshTime())
|
||||||
|
|
||||||
// Make it so approval is not required
|
// Make it so approval is not required
|
||||||
sandbox
|
sandbox
|
||||||
@ -779,6 +785,7 @@ describe('SwapsController', function () {
|
|||||||
|
|
||||||
it('does not mark as best quote if no conversion rate exists for destination token', async function () {
|
it('does not mark as best quote if no conversion rate exists for destination token', async function () {
|
||||||
fetchTradesInfoStub.resolves(getMockQuotes())
|
fetchTradesInfoStub.resolves(getMockQuotes())
|
||||||
|
fetchSwapsQuoteRefreshTimeStub.resolves(getMockQuoteRefreshTime())
|
||||||
|
|
||||||
// Make it so approval is not required
|
// Make it so approval is not required
|
||||||
sandbox
|
sandbox
|
||||||
@ -805,6 +812,7 @@ describe('SwapsController', function () {
|
|||||||
assert.deepStrictEqual(swapsState, {
|
assert.deepStrictEqual(swapsState, {
|
||||||
...EMPTY_INIT_STATE.swapsState,
|
...EMPTY_INIT_STATE.swapsState,
|
||||||
tokens: old.tokens,
|
tokens: old.tokens,
|
||||||
|
swapsQuoteRefreshTime: old.swapsQuoteRefreshTime,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -850,8 +858,14 @@ describe('SwapsController', function () {
|
|||||||
const tokens = 'test'
|
const tokens = 'test'
|
||||||
const fetchParams = 'test'
|
const fetchParams = 'test'
|
||||||
const swapsFeatureIsLive = false
|
const swapsFeatureIsLive = false
|
||||||
|
const swapsQuoteRefreshTime = 0
|
||||||
swapsController.store.updateState({
|
swapsController.store.updateState({
|
||||||
swapsState: { tokens, fetchParams, swapsFeatureIsLive },
|
swapsState: {
|
||||||
|
tokens,
|
||||||
|
fetchParams,
|
||||||
|
swapsFeatureIsLive,
|
||||||
|
swapsQuoteRefreshTime,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
swapsController.resetPostFetchState()
|
swapsController.resetPostFetchState()
|
||||||
@ -862,6 +876,7 @@ describe('SwapsController', function () {
|
|||||||
tokens,
|
tokens,
|
||||||
fetchParams,
|
fetchParams,
|
||||||
swapsFeatureIsLive,
|
swapsFeatureIsLive,
|
||||||
|
swapsQuoteRefreshTime,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -1615,3 +1630,7 @@ function getTopQuoteAndSavingsBaseExpectedResults() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMockQuoteRefreshTime() {
|
||||||
|
return 45000
|
||||||
|
}
|
||||||
|
@ -224,6 +224,9 @@ const getSwapsState = (state) => state.metamask.swapsState
|
|||||||
export const getSwapsFeatureLiveness = (state) =>
|
export const getSwapsFeatureLiveness = (state) =>
|
||||||
state.metamask.swapsState.swapsFeatureIsLive
|
state.metamask.swapsState.swapsFeatureIsLive
|
||||||
|
|
||||||
|
export const getSwapsQuoteRefreshTime = (state) =>
|
||||||
|
state.metamask.swapsState.swapsQuoteRefreshTime
|
||||||
|
|
||||||
export const getBackgroundSwapRouteState = (state) =>
|
export const getBackgroundSwapRouteState = (state) =>
|
||||||
state.metamask.swapsState.routeState
|
state.metamask.swapsState.routeState
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { useState, useEffect, useContext, useRef } from 'react'
|
import React, { useState, useEffect, useContext, useRef } from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { Duration } from 'luxon'
|
import { Duration } from 'luxon'
|
||||||
import { I18nContext } from '../../../contexts/i18n'
|
import { I18nContext } from '../../../contexts/i18n'
|
||||||
import InfoTooltip from '../../../components/ui/info-tooltip'
|
import InfoTooltip from '../../../components/ui/info-tooltip'
|
||||||
|
import { getSwapsQuoteRefreshTime } from '../../../ducks/swaps/swaps'
|
||||||
const TIMER_BASE = 60000
|
|
||||||
|
|
||||||
// Return the mm:ss start time of the countdown timer.
|
// Return the mm:ss start time of the countdown timer.
|
||||||
// If time has elapsed between `timeStarted` the time current time,
|
// If time has elapsed between `timeStarted` the time current time,
|
||||||
@ -31,7 +31,7 @@ function timeBelowWarningTime(timer, warningTime) {
|
|||||||
export default function CountdownTimer({
|
export default function CountdownTimer({
|
||||||
timeStarted,
|
timeStarted,
|
||||||
timeOnly,
|
timeOnly,
|
||||||
timerBase = TIMER_BASE,
|
timerBase,
|
||||||
warningTime,
|
warningTime,
|
||||||
labelKey,
|
labelKey,
|
||||||
infoTooltipLabelKey,
|
infoTooltipLabelKey,
|
||||||
@ -40,9 +40,12 @@ export default function CountdownTimer({
|
|||||||
const intervalRef = useRef()
|
const intervalRef = useRef()
|
||||||
const initialTimeStartedRef = useRef()
|
const initialTimeStartedRef = useRef()
|
||||||
|
|
||||||
|
const swapsQuoteRefreshTime = useSelector(getSwapsQuoteRefreshTime)
|
||||||
|
const timerStart = Number(timerBase) || swapsQuoteRefreshTime
|
||||||
|
|
||||||
const [currentTime, setCurrentTime] = useState(() => Date.now())
|
const [currentTime, setCurrentTime] = useState(() => Date.now())
|
||||||
const [timer, setTimer] = useState(() =>
|
const [timer, setTimer] = useState(() =>
|
||||||
getNewTimer(currentTime, timeStarted, timerBase),
|
getNewTimer(currentTime, timeStarted, timerStart),
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -67,14 +70,14 @@ export default function CountdownTimer({
|
|||||||
initialTimeStartedRef.current = timeStarted
|
initialTimeStartedRef.current = timeStarted
|
||||||
const newCurrentTime = Date.now()
|
const newCurrentTime = Date.now()
|
||||||
setCurrentTime(newCurrentTime)
|
setCurrentTime(newCurrentTime)
|
||||||
setTimer(getNewTimer(newCurrentTime, timeStarted, timerBase))
|
setTimer(getNewTimer(newCurrentTime, timeStarted, timerStart))
|
||||||
|
|
||||||
clearInterval(intervalRef.current)
|
clearInterval(intervalRef.current)
|
||||||
intervalRef.current = setInterval(() => {
|
intervalRef.current = setInterval(() => {
|
||||||
setTimer(decreaseTimerByOne)
|
setTimer(decreaseTimerByOne)
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
}, [timeStarted, timer, timerBase])
|
}, [timeStarted, timer, timerStart])
|
||||||
|
|
||||||
const formattedTimer = Duration.fromMillis(timer).toFormat('m:ss')
|
const formattedTimer = Duration.fromMillis(timer).toFormat('m:ss')
|
||||||
let time
|
let time
|
||||||
|
@ -24,20 +24,24 @@ const TOKEN_TRANSFER_LOG_TOPIC_HASH =
|
|||||||
|
|
||||||
const CACHE_REFRESH_ONE_HOUR = 3600000
|
const CACHE_REFRESH_ONE_HOUR = 3600000
|
||||||
|
|
||||||
|
const METASWAP_API_HOST = 'https://api.metaswap.codefi.network'
|
||||||
|
|
||||||
const getBaseApi = function (type) {
|
const getBaseApi = function (type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'trade':
|
case 'trade':
|
||||||
return `https://api.metaswap.codefi.network/trades?`
|
return `${METASWAP_API_HOST}/trades?`
|
||||||
case 'tokens':
|
case 'tokens':
|
||||||
return `https://api.metaswap.codefi.network/tokens`
|
return `${METASWAP_API_HOST}/tokens`
|
||||||
case 'topAssets':
|
case 'topAssets':
|
||||||
return `https://api.metaswap.codefi.network/topAssets`
|
return `${METASWAP_API_HOST}/topAssets`
|
||||||
case 'featureFlag':
|
case 'featureFlag':
|
||||||
return `https://api.metaswap.codefi.network/featureFlag`
|
return `${METASWAP_API_HOST}/featureFlag`
|
||||||
case 'aggregatorMetadata':
|
case 'aggregatorMetadata':
|
||||||
return `https://api.metaswap.codefi.network/aggregatorMetadata`
|
return `${METASWAP_API_HOST}/aggregatorMetadata`
|
||||||
case 'gasPrices':
|
case 'gasPrices':
|
||||||
return `https://api.metaswap.codefi.network/gasPrices`
|
return `${METASWAP_API_HOST}/gasPrices`
|
||||||
|
case 'refreshTime':
|
||||||
|
return `${METASWAP_API_HOST}/quoteRefreshRate`
|
||||||
default:
|
default:
|
||||||
throw new Error('getBaseApi requires an api call type')
|
throw new Error('getBaseApi requires an api call type')
|
||||||
}
|
}
|
||||||
@ -328,6 +332,23 @@ export async function fetchSwapsFeatureLiveness() {
|
|||||||
return status?.active
|
return status?.active
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchSwapsQuoteRefreshTime() {
|
||||||
|
const response = await fetchWithCache(
|
||||||
|
getBaseApi('refreshTime'),
|
||||||
|
{ method: 'GET' },
|
||||||
|
{ cacheRefreshTime: 600000 },
|
||||||
|
)
|
||||||
|
|
||||||
|
// We presently use milliseconds in the UI
|
||||||
|
if (typeof response?.seconds === 'number' && response.seconds > 0) {
|
||||||
|
return response.seconds * 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`MetaMask - refreshTime provided invalid response: ${response}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchTokenPrice(address) {
|
export async function fetchTokenPrice(address) {
|
||||||
const query = `contract_addresses=${address}&vs_currencies=eth`
|
const query = `contract_addresses=${address}&vs_currencies=eth`
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
signAndSendTransactions,
|
signAndSendTransactions,
|
||||||
getBackgroundSwapRouteState,
|
getBackgroundSwapRouteState,
|
||||||
swapsQuoteSelected,
|
swapsQuoteSelected,
|
||||||
|
getSwapsQuoteRefreshTime,
|
||||||
} from '../../../ducks/swaps/swaps'
|
} from '../../../ducks/swaps/swaps'
|
||||||
import {
|
import {
|
||||||
conversionRateSelector,
|
conversionRateSelector,
|
||||||
@ -114,6 +115,7 @@ export default function ViewQuote() {
|
|||||||
const topQuote = useSelector(getTopQuote)
|
const topQuote = useSelector(getTopQuote)
|
||||||
const usedQuote = selectedQuote || topQuote
|
const usedQuote = selectedQuote || topQuote
|
||||||
const tradeValue = usedQuote?.trade?.value ?? '0x0'
|
const tradeValue = usedQuote?.trade?.value ?? '0x0'
|
||||||
|
const swapsQuoteRefreshTime = useSelector(getSwapsQuoteRefreshTime)
|
||||||
|
|
||||||
const { isBestQuote } = usedQuote
|
const { isBestQuote } = usedQuote
|
||||||
|
|
||||||
@ -265,14 +267,23 @@ export default function ViewQuote() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentTime = Date.now()
|
const currentTime = Date.now()
|
||||||
const timeSinceLastFetched = currentTime - quotesLastFetched
|
const timeSinceLastFetched = currentTime - quotesLastFetched
|
||||||
if (timeSinceLastFetched > 60000 && !dispatchedSafeRefetch) {
|
if (
|
||||||
|
timeSinceLastFetched > swapsQuoteRefreshTime &&
|
||||||
|
!dispatchedSafeRefetch
|
||||||
|
) {
|
||||||
setDispatchedSafeRefetch(true)
|
setDispatchedSafeRefetch(true)
|
||||||
dispatch(safeRefetchQuotes())
|
dispatch(safeRefetchQuotes())
|
||||||
} else if (timeSinceLastFetched > 60000) {
|
} else if (timeSinceLastFetched > swapsQuoteRefreshTime) {
|
||||||
dispatch(setSwapsErrorKey(QUOTES_EXPIRED_ERROR))
|
dispatch(setSwapsErrorKey(QUOTES_EXPIRED_ERROR))
|
||||||
history.push(SWAPS_ERROR_ROUTE)
|
history.push(SWAPS_ERROR_ROUTE)
|
||||||
}
|
}
|
||||||
}, [quotesLastFetched, dispatchedSafeRefetch, dispatch, history])
|
}, [
|
||||||
|
quotesLastFetched,
|
||||||
|
dispatchedSafeRefetch,
|
||||||
|
dispatch,
|
||||||
|
history,
|
||||||
|
swapsQuoteRefreshTime,
|
||||||
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!originalApproveAmount && approveAmount) {
|
if (!originalApproveAmount && approveAmount) {
|
||||||
|
Loading…
Reference in New Issue
Block a user