parent
90f72e05b9
commit
dfe50b4bee
@ -2,7 +2,6 @@ import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'fe
|
|||||||
import { DetailsV2Variant, useDetailsV2Flag } from 'featureFlags/flags/nftDetails'
|
import { DetailsV2Variant, useDetailsV2Flag } from 'featureFlags/flags/nftDetails'
|
||||||
import { useRoutingAPIForPriceFlag } from 'featureFlags/flags/priceRoutingApi'
|
import { useRoutingAPIForPriceFlag } from 'featureFlags/flags/priceRoutingApi'
|
||||||
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
|
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
|
||||||
import { UnifiedRouterVariant, useRoutingAPIV2Flag } from 'featureFlags/flags/unifiedRouter'
|
|
||||||
import { useWalletConnectFallbackFlag } from 'featureFlags/flags/walletConnectPopover'
|
import { useWalletConnectFallbackFlag } from 'featureFlags/flags/walletConnectPopover'
|
||||||
import { useWalletConnectV2Flag } from 'featureFlags/flags/walletConnectV2'
|
import { useWalletConnectV2Flag } from 'featureFlags/flags/walletConnectV2'
|
||||||
import { useUpdateAtom } from 'jotai/utils'
|
import { useUpdateAtom } from 'jotai/utils'
|
||||||
@ -211,12 +210,6 @@ export default function FeatureFlagModal() {
|
|||||||
featureFlag={FeatureFlag.detailsV2}
|
featureFlag={FeatureFlag.detailsV2}
|
||||||
label="Use the new details page for nfts"
|
label="Use the new details page for nfts"
|
||||||
/>
|
/>
|
||||||
<FeatureFlagOption
|
|
||||||
variant={UnifiedRouterVariant}
|
|
||||||
value={useRoutingAPIV2Flag()}
|
|
||||||
featureFlag={FeatureFlag.uraEnabled}
|
|
||||||
label="Enable the Unified Routing API"
|
|
||||||
/>
|
|
||||||
<FeatureFlagOption
|
<FeatureFlagOption
|
||||||
variant={BaseVariant}
|
variant={BaseVariant}
|
||||||
value={useRoutingAPIForPriceFlag()}
|
value={useRoutingAPIForPriceFlag()}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
|
|
||||||
|
|
||||||
export function useRoutingAPIV2Flag(): BaseVariant {
|
|
||||||
return useBaseFlag(FeatureFlag.uraEnabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useRoutingAPIV2Enabled(): boolean {
|
|
||||||
return useRoutingAPIV2Flag() === BaseVariant.Enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
export { BaseVariant as UnifiedRouterVariant }
|
|
@ -10,7 +10,6 @@ export enum FeatureFlag {
|
|||||||
permit2 = 'permit2',
|
permit2 = 'permit2',
|
||||||
fiatOnRampButtonOnSwap = 'fiat_on_ramp_button_on_swap_page',
|
fiatOnRampButtonOnSwap = 'fiat_on_ramp_button_on_swap_page',
|
||||||
detailsV2 = 'details_v2',
|
detailsV2 = 'details_v2',
|
||||||
uraEnabled = 'ura_enabled',
|
|
||||||
debounceSwapQuote = 'debounce_swap_quote',
|
debounceSwapQuote = 'debounce_swap_quote',
|
||||||
nativeUsdcArbitrum = 'web_usdc_arbitrum',
|
nativeUsdcArbitrum = 'web_usdc_arbitrum',
|
||||||
routingAPIPrice = 'routing_api_price',
|
routingAPIPrice = 'routing_api_price',
|
||||||
|
@ -6,8 +6,7 @@ import { isTestEnv } from 'utils/env'
|
|||||||
import { updateVersion } from './global/actions'
|
import { updateVersion } from './global/actions'
|
||||||
import { sentryEnhancer } from './logging'
|
import { sentryEnhancer } from './logging'
|
||||||
import reducer from './reducer'
|
import reducer from './reducer'
|
||||||
import { routingApi } from './routing/slice'
|
import { routingApiV2 } from './routing/slice'
|
||||||
import { routingApiV2 } from './routing/v2Slice'
|
|
||||||
|
|
||||||
const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists']
|
const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists']
|
||||||
|
|
||||||
@ -21,10 +20,9 @@ const store = configureStore({
|
|||||||
// meta.arg and meta.baseQueryMeta are defaults. payload.trade is a nonserializable return value, but that's ok
|
// meta.arg and meta.baseQueryMeta are defaults. payload.trade is a nonserializable return value, but that's ok
|
||||||
// because we are not adding it into any persisted store that requires serialization (e.g. localStorage)
|
// because we are not adding it into any persisted store that requires serialization (e.g. localStorage)
|
||||||
ignoredActionPaths: ['meta.arg', 'meta.baseQueryMeta', 'payload.trade'],
|
ignoredActionPaths: ['meta.arg', 'meta.baseQueryMeta', 'payload.trade'],
|
||||||
ignoredPaths: [routingApi.reducerPath, routingApiV2.reducerPath],
|
ignoredPaths: [routingApiV2.reducerPath],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.concat(routingApi.middleware)
|
|
||||||
.concat(routingApiV2.middleware)
|
.concat(routingApiV2.middleware)
|
||||||
.concat(save({ states: PERSISTED_KEYS, debounce: 1000 })),
|
.concat(save({ states: PERSISTED_KEYS, debounce: 1000 })),
|
||||||
preloadedState: load({ states: PERSISTED_KEYS, disableWarnings: isTestEnv() }),
|
preloadedState: load({ states: PERSISTED_KEYS, disableWarnings: isTestEnv() }),
|
||||||
|
@ -7,8 +7,7 @@ import lists from './lists/reducer'
|
|||||||
import logs from './logs/slice'
|
import logs from './logs/slice'
|
||||||
import mint from './mint/reducer'
|
import mint from './mint/reducer'
|
||||||
import mintV3 from './mint/v3/reducer'
|
import mintV3 from './mint/v3/reducer'
|
||||||
import { routingApi } from './routing/slice'
|
import { routingApiV2 } from './routing/slice'
|
||||||
import { routingApiV2 } from './routing/v2Slice'
|
|
||||||
import transactions from './transactions/reducer'
|
import transactions from './transactions/reducer'
|
||||||
import user from './user/reducer'
|
import user from './user/reducer'
|
||||||
import wallets from './wallets/reducer'
|
import wallets from './wallets/reducer'
|
||||||
@ -25,6 +24,5 @@ export default {
|
|||||||
multicall: multicall.reducer,
|
multicall: multicall.reducer,
|
||||||
lists,
|
lists,
|
||||||
logs,
|
logs,
|
||||||
[routingApi.reducerPath]: routingApi.reducer,
|
|
||||||
[routingApiV2.reducerPath]: routingApiV2.reducer,
|
[routingApiV2.reducerPath]: routingApiV2.reducer,
|
||||||
}
|
}
|
||||||
|
@ -4,30 +4,11 @@ import { TradeType } from '@uniswap/sdk-core'
|
|||||||
import { ChainId } from '@uniswap/sdk-core'
|
import { ChainId } from '@uniswap/sdk-core'
|
||||||
import { getClientSideQuote } from 'lib/hooks/routing/clientSideSmartOrderRouter'
|
import { getClientSideQuote } from 'lib/hooks/routing/clientSideSmartOrderRouter'
|
||||||
import ms from 'ms.macro'
|
import ms from 'ms.macro'
|
||||||
import qs from 'qs'
|
|
||||||
import { trace } from 'tracing/trace'
|
import { trace } from 'tracing/trace'
|
||||||
|
|
||||||
import { QuoteData, QuoteMethod, TradeResult } from './types'
|
import { QuoteMethod, QuoteReponse, QuoteState, TradeResult } from './types'
|
||||||
import { getRouter, isExactInput, shouldUseAPIRouter, transformRoutesToTrade } from './utils'
|
import { getRouter, isExactInput, shouldUseAPIRouter, transformRoutesToTrade } from './utils'
|
||||||
|
|
||||||
export enum RouterPreference {
|
|
||||||
AUTO = 'auto',
|
|
||||||
API = 'api',
|
|
||||||
CLIENT = 'client',
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is excluded from `RouterPreference` enum because it's only used
|
|
||||||
// internally for token -> USDC trades to get a USD value.
|
|
||||||
export const INTERNAL_ROUTER_PREFERENCE_PRICE = 'price' as const
|
|
||||||
|
|
||||||
// routing API quote params: https://github.com/Uniswap/routing-api/blob/main/lib/handlers/quote/schema/quote-schema.ts
|
|
||||||
const API_QUERY_PARAMS = {
|
|
||||||
protocols: 'v2,v3,mixed',
|
|
||||||
}
|
|
||||||
const CLIENT_PARAMS = {
|
|
||||||
protocols: [Protocol.V2, Protocol.V3, Protocol.MIXED],
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GetQuoteArgs {
|
export interface GetQuoteArgs {
|
||||||
tokenInAddress: string
|
tokenInAddress: string
|
||||||
tokenInChainId: ChainId
|
tokenInChainId: ChainId
|
||||||
@ -43,21 +24,36 @@ export interface GetQuoteArgs {
|
|||||||
isRoutingAPIPrice?: boolean
|
isRoutingAPIPrice?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QuoteState {
|
export enum RouterPreference {
|
||||||
SUCCESS = 'Success',
|
AUTO = 'auto',
|
||||||
NOT_FOUND = 'Not found',
|
API = 'api',
|
||||||
|
CLIENT = 'client',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const routingApi = createApi({
|
// This is excluded from `RouterPreference` enum because it's only used
|
||||||
reducerPath: 'routingApi',
|
// internally for token -> USDC trades to get a USD value.
|
||||||
|
export const INTERNAL_ROUTER_PREFERENCE_PRICE = 'price' as const
|
||||||
|
|
||||||
|
const CLIENT_PARAMS = {
|
||||||
|
protocols: [Protocol.V2, Protocol.V3, Protocol.MIXED],
|
||||||
|
}
|
||||||
|
|
||||||
|
// routing API quote query params: https://github.com/Uniswap/routing-api/blob/main/lib/handlers/quote/schema/quote-schema.ts
|
||||||
|
const CLASSIC_SWAP_QUERY_PARAMS = {
|
||||||
|
...CLIENT_PARAMS,
|
||||||
|
routingType: 'CLASSIC',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const routingApiV2 = createApi({
|
||||||
|
reducerPath: 'routingApiV2',
|
||||||
baseQuery: fetchBaseQuery({
|
baseQuery: fetchBaseQuery({
|
||||||
baseUrl: 'https://api.uniswap.org/v1/',
|
baseUrl: 'https://api.uniswap.org/v2/',
|
||||||
}),
|
}),
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
getQuote: build.query<TradeResult, GetQuoteArgs>({
|
getQuote: build.query<TradeResult, GetQuoteArgs>({
|
||||||
async onQueryStarted(args: GetQuoteArgs, { queryFulfilled }) {
|
async onQueryStarted(args: GetQuoteArgs, { queryFulfilled }) {
|
||||||
trace(
|
trace(
|
||||||
'quote',
|
'quote-v2',
|
||||||
async ({ setTraceError, setTraceStatus }) => {
|
async ({ setTraceError, setTraceStatus }) => {
|
||||||
try {
|
try {
|
||||||
await queryFulfilled
|
await queryFulfilled
|
||||||
@ -83,28 +79,39 @@ export const routingApi = createApi({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
async queryFn(args, _api, _extraOptions, fetch) {
|
async queryFn(args: GetQuoteArgs, _api, _extraOptions, fetch) {
|
||||||
const fellBack = false
|
let fellBack = false
|
||||||
if (shouldUseAPIRouter(args)) {
|
if (shouldUseAPIRouter(args)) {
|
||||||
|
fellBack = true
|
||||||
try {
|
try {
|
||||||
const { tokenInAddress, tokenInChainId, tokenOutAddress, tokenOutChainId, amount, tradeType } = args
|
const { tokenInAddress, tokenInChainId, tokenOutAddress, tokenOutChainId, amount, tradeType } = args
|
||||||
const type = isExactInput(tradeType) ? 'exactIn' : 'exactOut'
|
const type = isExactInput(tradeType) ? 'EXACT_INPUT' : 'EXACT_OUTPUT'
|
||||||
const query = qs.stringify({
|
|
||||||
...API_QUERY_PARAMS,
|
const requestBody = {
|
||||||
tokenInAddress,
|
|
||||||
tokenInChainId,
|
tokenInChainId,
|
||||||
tokenOutAddress,
|
tokenIn: tokenInAddress,
|
||||||
tokenOutChainId,
|
tokenOutChainId,
|
||||||
|
tokenOut: tokenOutAddress,
|
||||||
amount,
|
amount,
|
||||||
type,
|
type,
|
||||||
|
configs: [CLASSIC_SWAP_QUERY_PARAMS],
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/quote',
|
||||||
|
body: JSON.stringify(requestBody),
|
||||||
})
|
})
|
||||||
const response = await fetch(`quote?${query}`)
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
try {
|
try {
|
||||||
// cast as any here because we do a runtime check on it being an object before indexing into .errorCode
|
// cast as any here because we do a runtime check on it being an object before indexing into .errorCode
|
||||||
const errorData = response.error.data as any
|
const errorData = response.error.data as any
|
||||||
// NO_ROUTE should be treated as a valid response to prevent retries.
|
// NO_ROUTE should be treated as a valid response to prevent retries.
|
||||||
if (typeof errorData === 'object' && errorData?.errorCode === 'NO_ROUTE') {
|
if (
|
||||||
|
typeof errorData === 'object' &&
|
||||||
|
(errorData?.errorCode === 'NO_ROUTE' || errorData?.detail === 'No quotes available')
|
||||||
|
) {
|
||||||
return { data: { state: QuoteState.NOT_FOUND } }
|
return { data: { state: QuoteState.NOT_FOUND } }
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@ -112,12 +119,13 @@ export const routingApi = createApi({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const quoteData = response.data as QuoteData
|
const quoteData = response.data as QuoteReponse
|
||||||
const tradeResult = transformRoutesToTrade(args, quoteData)
|
const tradeResult = transformRoutesToTrade(args, quoteData.quote)
|
||||||
|
|
||||||
return { data: { ...tradeResult, method: QuoteMethod.ROUTING_API } }
|
return { data: { ...tradeResult, method: QuoteMethod.ROUTING_API } }
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`GetQuote failed on routing API, falling back to client: ${error?.message ?? error?.detail ?? error}`
|
`GetQuote failed on API v2, falling back to client: ${error?.message ?? error?.detail ?? error}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,11 +144,8 @@ export const routingApi = createApi({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
keepUnusedDataFor: ms`10s`,
|
keepUnusedDataFor: ms`10s`,
|
||||||
extraOptions: {
|
|
||||||
maxRetries: 0,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const { useGetQuoteQuery } = routingApi
|
export const { useGetQuoteQuery } = routingApiV2
|
||||||
|
@ -76,7 +76,7 @@ export interface QuoteData {
|
|||||||
routeString: string
|
routeString: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QuoteDataV2 = {
|
export type QuoteReponse = {
|
||||||
routing: RouterPreference.API
|
routing: RouterPreference.API
|
||||||
quote: QuoteData
|
quote: QuoteData
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@ import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
|||||||
import { IMetric, MetricLoggerUnit, setGlobalMetric } from '@uniswap/smart-order-router'
|
import { IMetric, MetricLoggerUnit, setGlobalMetric } from '@uniswap/smart-order-router'
|
||||||
import { sendTiming } from 'components/analytics'
|
import { sendTiming } from 'components/analytics'
|
||||||
import { AVERAGE_L1_BLOCK_TIME } from 'constants/chainInfo'
|
import { AVERAGE_L1_BLOCK_TIME } from 'constants/chainInfo'
|
||||||
import { useRoutingAPIV2Enabled } from 'featureFlags/flags/unifiedRouter'
|
|
||||||
import { useRoutingAPIArguments } from 'lib/hooks/routing/useRoutingAPIArguments'
|
import { useRoutingAPIArguments } from 'lib/hooks/routing/useRoutingAPIArguments'
|
||||||
import ms from 'ms.macro'
|
import ms from 'ms.macro'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference, useGetQuoteQuery } from 'state/routing/slice'
|
import { INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from 'state/routing/slice'
|
||||||
import { useGetQuoteQuery as useGetQuoteQueryV2 } from 'state/routing/v2Slice'
|
import { useGetQuoteQuery as useGetQuoteQueryV2 } from 'state/routing/slice'
|
||||||
|
|
||||||
import { InterfaceTrade, QuoteMethod, QuoteState, TradeState } from './types'
|
import { InterfaceTrade, QuoteMethod, QuoteState, TradeState } from './types'
|
||||||
|
|
||||||
@ -48,34 +47,16 @@ export function useRoutingAPITrade<TTradeType extends TradeType>(
|
|||||||
routerPreference,
|
routerPreference,
|
||||||
})
|
})
|
||||||
|
|
||||||
const shouldUseRoutingApiV2 = useRoutingAPIV2Enabled()
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isError: isLegacyAPIError,
|
isError,
|
||||||
data: legacyAPITradeResult,
|
data: tradeResult,
|
||||||
currentData: currentLegacyAPITradeResult,
|
currentData: currentTradeResult,
|
||||||
} = useGetQuoteQuery(shouldUseRoutingApiV2 ? skipToken : queryArgs ?? skipToken, {
|
} = useGetQuoteQueryV2(queryArgs ?? skipToken, {
|
||||||
// Price-fetching is informational and costly, so it's done less frequently.
|
// Price-fetching is informational and costly, so it's done less frequently.
|
||||||
pollingInterval: routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE ? ms`1m` : AVERAGE_L1_BLOCK_TIME,
|
pollingInterval: routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE ? ms`1m` : AVERAGE_L1_BLOCK_TIME,
|
||||||
// If latest quote from cache was fetched > 2m ago, instantly repoll for another instead of waiting for next poll period
|
// If latest quote from cache was fetched > 2m ago, instantly repoll for another instead of waiting for next poll period
|
||||||
refetchOnMountOrArgChange: 2 * 60,
|
refetchOnMountOrArgChange: 2 * 60,
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
|
||||||
isError: isV2APIError,
|
|
||||||
data: v2TradeResult,
|
|
||||||
currentData: currentV2TradeResult,
|
|
||||||
} = useGetQuoteQueryV2(!shouldUseRoutingApiV2 ? skipToken : queryArgs ?? skipToken, {
|
|
||||||
// Price-fetching is informational and costly, so it's done less frequently.
|
|
||||||
pollingInterval: routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE ? ms`1m` : AVERAGE_L1_BLOCK_TIME,
|
|
||||||
// If latest quote from cache was fetched > 2m ago, instantly repoll for another instead of waiting for next poll period
|
|
||||||
refetchOnMountOrArgChange: 2 * 60,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [tradeResult, currentTradeResult, isError] = shouldUseRoutingApiV2
|
|
||||||
? [v2TradeResult, currentV2TradeResult, isV2APIError]
|
|
||||||
: [legacyAPITradeResult, currentLegacyAPITradeResult, isLegacyAPIError]
|
|
||||||
|
|
||||||
const isCurrent = currentTradeResult === tradeResult
|
const isCurrent = currentTradeResult === tradeResult
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
import { createApi, fetchBaseQuery, FetchBaseQueryError } from '@reduxjs/toolkit/query/react'
|
|
||||||
import { Protocol } from '@uniswap/router-sdk'
|
|
||||||
import { getClientSideQuote } from 'lib/hooks/routing/clientSideSmartOrderRouter'
|
|
||||||
import ms from 'ms.macro'
|
|
||||||
import { trace } from 'tracing/trace'
|
|
||||||
|
|
||||||
import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from './slice'
|
|
||||||
import { QuoteDataV2, QuoteMethod, QuoteState, TradeResult } from './types'
|
|
||||||
import { getRouter, isExactInput, shouldUseAPIRouter, transformRoutesToTrade } from './utils'
|
|
||||||
|
|
||||||
const CLIENT_PARAMS = {
|
|
||||||
protocols: [Protocol.V2, Protocol.V3, Protocol.MIXED],
|
|
||||||
}
|
|
||||||
|
|
||||||
// routing API quote query params: https://github.com/Uniswap/routing-api/blob/main/lib/handlers/quote/schema/quote-schema.ts
|
|
||||||
const CLASSIC_SWAP_QUERY_PARAMS = {
|
|
||||||
...CLIENT_PARAMS,
|
|
||||||
routingType: 'CLASSIC',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const routingApiV2 = createApi({
|
|
||||||
reducerPath: 'routingApiV2',
|
|
||||||
baseQuery: fetchBaseQuery({
|
|
||||||
baseUrl: 'https://api.uniswap.org/v2/',
|
|
||||||
}),
|
|
||||||
endpoints: (build) => ({
|
|
||||||
getQuote: build.query<TradeResult, GetQuoteArgs>({
|
|
||||||
async onQueryStarted(args: GetQuoteArgs, { queryFulfilled }) {
|
|
||||||
trace(
|
|
||||||
'quote-v2',
|
|
||||||
async ({ setTraceError, setTraceStatus }) => {
|
|
||||||
try {
|
|
||||||
await queryFulfilled
|
|
||||||
} catch (error: unknown) {
|
|
||||||
if (error && typeof error === 'object' && 'error' in error) {
|
|
||||||
const queryError = (error as Record<'error', FetchBaseQueryError>).error
|
|
||||||
if (typeof queryError.status === 'number') {
|
|
||||||
setTraceStatus(queryError.status)
|
|
||||||
}
|
|
||||||
setTraceError(queryError)
|
|
||||||
} else {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: {
|
|
||||||
...args,
|
|
||||||
isPrice: args.routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE,
|
|
||||||
isAutoRouter:
|
|
||||||
args.routerPreference === RouterPreference.AUTO || args.routerPreference === RouterPreference.API,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
async queryFn(args: GetQuoteArgs, _api, _extraOptions, fetch) {
|
|
||||||
let fellBack = false
|
|
||||||
if (shouldUseAPIRouter(args)) {
|
|
||||||
fellBack = true
|
|
||||||
try {
|
|
||||||
const { tokenInAddress, tokenInChainId, tokenOutAddress, tokenOutChainId, amount, tradeType } = args
|
|
||||||
const type = isExactInput(tradeType) ? 'EXACT_INPUT' : 'EXACT_OUTPUT'
|
|
||||||
|
|
||||||
const requestBody = {
|
|
||||||
tokenInChainId,
|
|
||||||
tokenIn: tokenInAddress,
|
|
||||||
tokenOutChainId,
|
|
||||||
tokenOut: tokenOutAddress,
|
|
||||||
amount,
|
|
||||||
type,
|
|
||||||
configs: [CLASSIC_SWAP_QUERY_PARAMS],
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch({
|
|
||||||
method: 'POST',
|
|
||||||
url: '/quote',
|
|
||||||
body: JSON.stringify(requestBody),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.error) {
|
|
||||||
try {
|
|
||||||
// cast as any here because we do a runtime check on it being an object before indexing into .errorCode
|
|
||||||
const errorData = response.error.data as any
|
|
||||||
// NO_ROUTE should be treated as a valid response to prevent retries.
|
|
||||||
if (
|
|
||||||
typeof errorData === 'object' &&
|
|
||||||
(errorData?.errorCode === 'NO_ROUTE' || errorData?.detail === 'No quotes available')
|
|
||||||
) {
|
|
||||||
return { data: { state: QuoteState.NOT_FOUND } }
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
throw response.error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const quoteData = response.data as QuoteDataV2
|
|
||||||
const tradeResult = transformRoutesToTrade(args, quoteData.quote)
|
|
||||||
|
|
||||||
return { data: { ...tradeResult, method: QuoteMethod.ROUTING_API } }
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn(
|
|
||||||
`GetQuote failed on API v2, falling back to client: ${error?.message ?? error?.detail ?? error}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const method = fellBack ? QuoteMethod.CLIENT_SIDE_FALLBACK : QuoteMethod.CLIENT_SIDE
|
|
||||||
const router = getRouter(args.tokenInChainId)
|
|
||||||
const quoteResult = await getClientSideQuote(args, router, CLIENT_PARAMS)
|
|
||||||
if (quoteResult.state === QuoteState.SUCCESS) {
|
|
||||||
return { data: { ...transformRoutesToTrade(args, quoteResult.data), method } }
|
|
||||||
} else {
|
|
||||||
return { data: quoteResult }
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn(`GetQuote failed on client: ${error}`)
|
|
||||||
return { error: { status: 'CUSTOM_ERROR', error: error?.detail ?? error?.message ?? error } }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
keepUnusedDataFor: ms`10s`,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
export const { useGetQuoteQuery } = routingApiV2
|
|
Loading…
Reference in New Issue
Block a user