feat: Remove local routing setting (#7462)
* remove client side router preference * update e2e test * fix comment
This commit is contained in:
parent
e9fbf61375
commit
cfaf5d79c1
@ -9,7 +9,6 @@ describe('Swap settings', () => {
|
||||
cy.contains('Max. slippage').should('exist')
|
||||
cy.contains('Transaction deadline').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
cy.contains('Local routing').should('exist')
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.contains('Settings').should('not.exist')
|
||||
})
|
||||
@ -28,7 +27,6 @@ describe('Swap settings', () => {
|
||||
.within(() => {
|
||||
cy.contains('Max. slippage').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
cy.contains('Local routing').should('exist')
|
||||
cy.contains('Transaction deadline').should('exist')
|
||||
cy.get(getTestSelector('mobile-settings-close')).click()
|
||||
})
|
||||
|
@ -114,7 +114,7 @@ export function AddRemoveTabs({
|
||||
)}
|
||||
</AddRemoveTitleText>
|
||||
{children && <Box style={{ marginRight: '.5rem' }}>{children}</Box>}
|
||||
<SettingsTab autoSlippage={autoSlippage} chainId={chainId} showRoutingSettings={false} />
|
||||
<SettingsTab autoSlippage={autoSlippage} chainId={chainId} hideRoutingSettings />
|
||||
</RowBetween>
|
||||
</Tabs>
|
||||
)
|
||||
|
@ -13,8 +13,10 @@ export default function RouterLabel({ trade, color }: { trade: SubmittableTrade;
|
||||
</UniswapXRouterLabel>
|
||||
)
|
||||
}
|
||||
if (trade.quoteMethod === QuoteMethod.CLIENT_SIDE || trade.quoteMethod === QuoteMethod.CLIENT_SIDE_FALLBACK) {
|
||||
|
||||
if (trade.quoteMethod === QuoteMethod.CLIENT_SIDE_FALLBACK) {
|
||||
return <ThemedText.BodySmall color={color}>Uniswap Client</ThemedText.BodySmall>
|
||||
}
|
||||
|
||||
return <ThemedText.BodySmall color={color}>Uniswap API</ThemedText.BodySmall>
|
||||
}
|
||||
|
@ -24,18 +24,4 @@ describe('RouterPreferenceSettings', () => {
|
||||
expect(uniswapXToggle).toHaveAttribute('aria-selected', 'false')
|
||||
expect(store.getState().user.userRouterPreference).toEqual(RouterPreference.API)
|
||||
})
|
||||
it('toggles `Local Routing` router preference', () => {
|
||||
render(<RouterPreferenceSettings />)
|
||||
|
||||
const localRoutingToggle = screen.getByTestId('toggle-local-routing-button')
|
||||
|
||||
fireEvent.click(localRoutingToggle)
|
||||
expect(localRoutingToggle).toHaveAttribute('aria-selected', 'true')
|
||||
expect(store.getState().user.userRouterPreference).toEqual(RouterPreference.CLIENT)
|
||||
|
||||
fireEvent.click(localRoutingToggle)
|
||||
|
||||
expect(localRoutingToggle).toHaveAttribute('aria-selected', 'false')
|
||||
expect(store.getState().user.userRouterPreference).toEqual(RouterPreference.API)
|
||||
})
|
||||
})
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import Column from 'components/Column'
|
||||
import UniswapXBrandMark from 'components/Logo/UniswapXBrandMark'
|
||||
import { RowBetween, RowFixed } from 'components/Row'
|
||||
import Toggle from 'components/Toggle'
|
||||
import { isUniswapXSupportedChain } from 'constants/chains'
|
||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { useRouterPreference, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
||||
import { updateDisabledUniswapX, updateOptedOutOfUniswapX } from 'state/user/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { Divider, ExternalLink, ThemedText } from 'theme/components'
|
||||
import { ExternalLink, ThemedText } from 'theme/components'
|
||||
|
||||
const InlineLink = styled(ThemedText.BodySmall)`
|
||||
color: ${({ theme }) => theme.accent1};
|
||||
@ -23,81 +21,48 @@ const InlineLink = styled(ThemedText.BodySmall)`
|
||||
`
|
||||
|
||||
export default function RouterPreferenceSettings() {
|
||||
const { chainId } = useWeb3React()
|
||||
const [routerPreference, setRouterPreference] = useRouterPreference()
|
||||
const uniswapXEnabled = chainId && isUniswapXSupportedChain(chainId)
|
||||
const dispatch = useAppDispatch()
|
||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
const isUniswapXOverrideEnabled = isUniswapXDefaultEnabled && !userOptedOutOfUniswapX
|
||||
|
||||
const uniswapXInEffect =
|
||||
routerPreference === RouterPreference.X ||
|
||||
(routerPreference !== RouterPreference.CLIENT && isUniswapXOverrideEnabled)
|
||||
const uniswapXInEffect = routerPreference === RouterPreference.X || isUniswapXOverrideEnabled
|
||||
|
||||
return (
|
||||
<>
|
||||
{uniswapXEnabled && (
|
||||
<>
|
||||
<RowBetween gap="sm">
|
||||
<RowFixed>
|
||||
<Column gap="xs">
|
||||
<ThemedText.BodySecondary>
|
||||
<UniswapXBrandMark />
|
||||
</ThemedText.BodySecondary>
|
||||
<ThemedText.BodySmall color="neutral2">
|
||||
<Trans>When available, aggregates liquidity sources for better prices and gas free swaps.</Trans>{' '}
|
||||
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/17515415311501">
|
||||
<InlineLink>Learn more</InlineLink>
|
||||
</ExternalLink>
|
||||
</ThemedText.BodySmall>
|
||||
</Column>
|
||||
</RowFixed>
|
||||
<Toggle
|
||||
id="toggle-uniswap-x-button"
|
||||
// If UniswapX-by-default is enabled we need to render this as active even if routerPreference === RouterPreference.API
|
||||
// because we're going to default to the UniswapX quote.
|
||||
// If the user manually toggles it off, this doesn't apply.
|
||||
isActive={uniswapXInEffect}
|
||||
toggle={() => {
|
||||
if (uniswapXInEffect) {
|
||||
if (isUniswapXDefaultEnabled) {
|
||||
// We need to remember if a opts out of UniswapX, so we don't request UniswapX quotes.
|
||||
dispatch(updateOptedOutOfUniswapX({ optedOutOfUniswapX: true }))
|
||||
} else {
|
||||
// We need to remember if a user disables Uniswap X, so we don't show the opt-in flow again.
|
||||
dispatch(updateDisabledUniswapX({ disabledUniswapX: true }))
|
||||
}
|
||||
}
|
||||
setRouterPreference(uniswapXInEffect ? RouterPreference.API : RouterPreference.X)
|
||||
}}
|
||||
/>
|
||||
</RowBetween>
|
||||
<Divider />
|
||||
</>
|
||||
)}
|
||||
<RowBetween gap="sm">
|
||||
<RowFixed>
|
||||
<Column gap="xs">
|
||||
<ThemedText.BodySecondary>
|
||||
<Trans>Local routing</Trans>
|
||||
</ThemedText.BodySecondary>
|
||||
</Column>
|
||||
</RowFixed>
|
||||
<Toggle
|
||||
id="toggle-local-routing-button"
|
||||
isActive={routerPreference === RouterPreference.CLIENT}
|
||||
toggle={() =>
|
||||
setRouterPreference(
|
||||
routerPreference === RouterPreference.CLIENT
|
||||
? isUniswapXDefaultEnabled
|
||||
? RouterPreference.X
|
||||
: RouterPreference.API
|
||||
: RouterPreference.CLIENT
|
||||
)
|
||||
<RowBetween gap="sm">
|
||||
<RowFixed>
|
||||
<Column gap="xs">
|
||||
<ThemedText.BodySecondary>
|
||||
<UniswapXBrandMark />
|
||||
</ThemedText.BodySecondary>
|
||||
<ThemedText.BodySmall color="neutral2">
|
||||
<Trans>When available, aggregates liquidity sources for better prices and gas free swaps.</Trans>{' '}
|
||||
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/17515415311501">
|
||||
<InlineLink>Learn more</InlineLink>
|
||||
</ExternalLink>
|
||||
</ThemedText.BodySmall>
|
||||
</Column>
|
||||
</RowFixed>
|
||||
<Toggle
|
||||
id="toggle-uniswap-x-button"
|
||||
// If UniswapX-by-default is enabled we need to render this as active even if routerPreference === RouterPreference.API
|
||||
// because we're going to default to the UniswapX quote.
|
||||
// If the user manually toggles it off, this doesn't apply.
|
||||
isActive={uniswapXInEffect}
|
||||
toggle={() => {
|
||||
if (uniswapXInEffect) {
|
||||
if (isUniswapXDefaultEnabled) {
|
||||
// We need to remember if a opts out of UniswapX, so we don't request UniswapX quotes.
|
||||
dispatch(updateOptedOutOfUniswapX({ optedOutOfUniswapX: true }))
|
||||
} else {
|
||||
// We need to remember if a user disables Uniswap X, so we don't show the opt-in flow again.
|
||||
dispatch(updateDisabledUniswapX({ disabledUniswapX: true }))
|
||||
}
|
||||
}
|
||||
/>
|
||||
</RowBetween>
|
||||
</>
|
||||
setRouterPreference(uniswapXInEffect ? RouterPreference.API : RouterPreference.X)
|
||||
}}
|
||||
/>
|
||||
</RowBetween>
|
||||
)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { isSupportedChain } from 'constants/chains'
|
||||
import { isSupportedChain, isUniswapXSupportedChain } from 'constants/chains'
|
||||
import { mocked } from 'test-utils/mocked'
|
||||
import { fireEvent, render, screen, waitFor } from 'test-utils/render'
|
||||
|
||||
@ -14,25 +14,38 @@ describe('Settings Tab', () => {
|
||||
mocked(isSupportedChain).mockReturnValue(true)
|
||||
})
|
||||
|
||||
it('renders routing settings when showRoutingSettings is true', async () => {
|
||||
render(<SettingsTab showRoutingSettings={true} chainId={1} autoSlippage={slippage} />)
|
||||
it('renders routing settings when hideRoutingSettings is false', async () => {
|
||||
mocked(isUniswapXSupportedChain).mockReturnValue(true)
|
||||
render(<SettingsTab hideRoutingSettings={false} chainId={1} autoSlippage={slippage} />)
|
||||
|
||||
const settingsButton = screen.getByTestId('open-settings-dialog-button')
|
||||
fireEvent.click(settingsButton)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('toggle-local-routing-button')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('toggle-uniswap-x-button')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('does not render routing settings when showRoutingSettings is false', async () => {
|
||||
render(<SettingsTab showRoutingSettings={false} chainId={1} autoSlippage={slippage} />)
|
||||
it('does not render routing settings when hideRoutingSettings is true', async () => {
|
||||
render(<SettingsTab hideRoutingSettings chainId={1} autoSlippage={slippage} />)
|
||||
|
||||
const settingsButton = screen.getByTestId('open-settings-dialog-button')
|
||||
fireEvent.click(settingsButton)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('toggle-local-routing-button')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('toggle-uniswap-x-button')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('does not render routing settings when uniswapx is not enabled', async () => {
|
||||
mocked(isUniswapXSupportedChain).mockReturnValue(false)
|
||||
render(<SettingsTab hideRoutingSettings chainId={1} autoSlippage={slippage} />)
|
||||
|
||||
const settingsButton = screen.getByTestId('open-settings-dialog-button')
|
||||
fireEvent.click(settingsButton)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('toggle-uniswap-x-button')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ import { Scrim } from 'components/AccountDrawer'
|
||||
import AnimatedDropdown from 'components/AnimatedDropdown'
|
||||
import Column, { AutoColumn } from 'components/Column'
|
||||
import Row from 'components/Row'
|
||||
import { isSupportedChain, L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { isSupportedChain, isUniswapXSupportedChain, L2_CHAIN_IDS } from 'constants/chains'
|
||||
import useDisableScrolling from 'hooks/useDisableScrolling'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { Portal } from 'nft/components/common/Portal'
|
||||
@ -101,12 +101,12 @@ export default function SettingsTab({
|
||||
autoSlippage,
|
||||
chainId,
|
||||
trade,
|
||||
showRoutingSettings = true,
|
||||
hideRoutingSettings = false,
|
||||
}: {
|
||||
autoSlippage: Percent
|
||||
chainId?: number
|
||||
trade?: InterfaceTrade
|
||||
showRoutingSettings?: boolean
|
||||
hideRoutingSettings?: boolean
|
||||
}) {
|
||||
const { chainId: connectedChainId } = useWeb3React()
|
||||
const showDeadlineSettings = Boolean(chainId && !L2_CHAIN_IDS.includes(chainId))
|
||||
@ -124,6 +124,9 @@ export default function SettingsTab({
|
||||
useOnClickOutside(node, isOpenDesktop ? closeMenu : undefined)
|
||||
useDisableScrolling(isOpen)
|
||||
|
||||
const uniswapXEnabled = chainId && isUniswapXSupportedChain(chainId)
|
||||
const showRoutingSettings = Boolean(uniswapXEnabled && !hideRoutingSettings)
|
||||
|
||||
const isChainSupported = isSupportedChain(chainId)
|
||||
const Settings = useMemo(
|
||||
() => (
|
||||
|
@ -34,7 +34,7 @@ beforeEach(() => {
|
||||
|
||||
mocked(useIsWindowVisible).mockReturnValue(true)
|
||||
mocked(useAutoRouterSupported).mockReturnValue(true)
|
||||
mocked(useRouterPreference).mockReturnValue([RouterPreference.CLIENT, () => undefined])
|
||||
mocked(useRouterPreference).mockReturnValue([RouterPreference.API, () => undefined])
|
||||
})
|
||||
|
||||
describe('#useBestV3Trade ExactIn', () => {
|
||||
@ -49,7 +49,7 @@ describe('#useBestV3Trade ExactIn', () => {
|
||||
TradeType.EXACT_INPUT,
|
||||
USDCAmount,
|
||||
DAI,
|
||||
RouterPreference.CLIENT,
|
||||
RouterPreference.API,
|
||||
/* account = */ undefined,
|
||||
/* inputTax = */ undefined,
|
||||
/* outputTax = */ undefined
|
||||
@ -69,7 +69,7 @@ describe('#useDebouncedTrade ExactOut', () => {
|
||||
TradeType.EXACT_OUTPUT,
|
||||
DAIAmount,
|
||||
USDC_MAINNET,
|
||||
RouterPreference.CLIENT,
|
||||
RouterPreference.API,
|
||||
/* account = */ undefined,
|
||||
/* inputTax = */ undefined,
|
||||
/* outputTax = */ undefined
|
||||
|
@ -37,7 +37,7 @@ export function useDebouncedTrade(
|
||||
tradeType: TradeType,
|
||||
amountSpecified?: CurrencyAmount<Currency>,
|
||||
otherCurrency?: Currency,
|
||||
routerPreferenceOverride?: RouterPreference.API | RouterPreference.CLIENT,
|
||||
routerPreferenceOverride?: RouterPreference.API,
|
||||
account?: string,
|
||||
inputTax?: Percent,
|
||||
outputTax?: Percent
|
||||
@ -97,8 +97,7 @@ export function useDebouncedTrade(
|
||||
const skipBothFetches = !autoRouterSupported || !isWindowVisible || isWrap
|
||||
const skipRoutingFetch = skipBothFetches || isDebouncing
|
||||
|
||||
const skipPreviewTradeFetch =
|
||||
skipBothFetches || routerPreference === RouterPreference.CLIENT || isPreviewTradeDebouncing
|
||||
const skipPreviewTradeFetch = skipBothFetches || isPreviewTradeDebouncing
|
||||
|
||||
const previewTradeResult = usePreviewTrade(
|
||||
skipPreviewTradeFetch,
|
||||
|
@ -739,11 +739,7 @@ export default function MigrateV2Pair() {
|
||||
<ThemedText.DeprecatedMediumHeader>
|
||||
<Trans>Migrate V2 liquidity</Trans>
|
||||
</ThemedText.DeprecatedMediumHeader>
|
||||
<SettingsTab
|
||||
autoSlippage={DEFAULT_MIGRATE_SLIPPAGE_TOLERANCE}
|
||||
chainId={chainId}
|
||||
showRoutingSettings={false}
|
||||
/>
|
||||
<SettingsTab autoSlippage={DEFAULT_MIGRATE_SLIPPAGE_TOLERANCE} chainId={chainId} hideRoutingSettings />
|
||||
</AutoRow>
|
||||
|
||||
{!account ? (
|
||||
|
@ -13,7 +13,7 @@ const defaultState = {
|
||||
user: {},
|
||||
_persist: {
|
||||
rehydrated: true,
|
||||
version: 1,
|
||||
version: 2,
|
||||
},
|
||||
application: {
|
||||
chainId: null,
|
||||
|
@ -3,6 +3,7 @@ import { MigrationConfig } from 'redux-persist/es/createMigrate'
|
||||
|
||||
import { migration0 } from './migrations/0'
|
||||
import { migration1 } from './migrations/1'
|
||||
import { migration2 } from './migrations/2'
|
||||
import { legacyLocalStorageMigration } from './migrations/legacy'
|
||||
|
||||
/**
|
||||
@ -17,6 +18,7 @@ import { legacyLocalStorageMigration } from './migrations/legacy'
|
||||
export const migrations: MigrationManifest = {
|
||||
0: migration0,
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
}
|
||||
|
||||
// We use a custom migration function for the initial state, because redux-persist
|
||||
|
62
src/state/migrations/2.test.ts
Normal file
62
src/state/migrations/2.test.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { createMigrate } from 'redux-persist'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { SlippageTolerance } from 'state/user/types'
|
||||
|
||||
import { migration1 } from './1'
|
||||
import { migration2, PersistAppStateV2 } from './2'
|
||||
|
||||
const previousState: PersistAppStateV2 = {
|
||||
user: {
|
||||
userLocale: null,
|
||||
// @ts-ignore this is intentionally a string and not the `RouterPreference` enum because `client` is a deprecated option
|
||||
userRouterPreference: 'client',
|
||||
userHideClosedPositions: false,
|
||||
userSlippageTolerance: SlippageTolerance.Auto,
|
||||
userSlippageToleranceHasBeenMigratedToAuto: true,
|
||||
userDeadline: 1800,
|
||||
tokens: {},
|
||||
pairs: {},
|
||||
timestamp: Date.now(),
|
||||
hideBaseWalletBanner: false,
|
||||
},
|
||||
_persist: {
|
||||
version: 1,
|
||||
rehydrated: true,
|
||||
},
|
||||
}
|
||||
|
||||
describe('migration to v2', () => {
|
||||
it('should migrate users who currently have `client` router preference', async () => {
|
||||
const migrator = createMigrate(
|
||||
{
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
},
|
||||
{ debug: false }
|
||||
)
|
||||
const result: any = await migrator(previousState, 2)
|
||||
expect(result?.user?.userRouterPreference).toEqual(RouterPreference.API)
|
||||
expect(result?._persist.version).toEqual(2)
|
||||
})
|
||||
|
||||
it('should not migrate non-client router preference', async () => {
|
||||
const migrator = createMigrate(
|
||||
{
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
},
|
||||
{ debug: false }
|
||||
)
|
||||
const result: any = await migrator(
|
||||
{
|
||||
...previousState,
|
||||
user: {
|
||||
...previousState.user,
|
||||
userRouterPreference: RouterPreference.X,
|
||||
},
|
||||
} as PersistAppStateV2,
|
||||
2
|
||||
)
|
||||
expect(result?.user?.userRouterPreference).toEqual(RouterPreference.X)
|
||||
})
|
||||
})
|
29
src/state/migrations/2.ts
Normal file
29
src/state/migrations/2.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { PersistState } from 'redux-persist'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { UserState } from 'state/user/reducer'
|
||||
|
||||
export type PersistAppStateV2 = {
|
||||
_persist: PersistState
|
||||
} & { user?: UserState }
|
||||
|
||||
/**
|
||||
* Migration to move users who have local routing as their router preference to API
|
||||
* since forced local routing is now deprecated
|
||||
*/
|
||||
export const migration2 = (state: PersistAppStateV2 | undefined) => {
|
||||
// @ts-ignore this is intentionally a string and not the `RouterPreference` enum because `client` is a deprecated option
|
||||
if (state?.user && state.user?.userRouterPreference === 'client') {
|
||||
return {
|
||||
...state,
|
||||
user: {
|
||||
...state.user,
|
||||
userRouterPreference: RouterPreference.API,
|
||||
},
|
||||
_persist: {
|
||||
...state._persist,
|
||||
version: 2,
|
||||
},
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
@ -44,7 +44,7 @@ export type AppState = ReturnType<typeof appReducer>
|
||||
|
||||
const persistConfig: PersistConfig<AppState> = {
|
||||
key: 'interface',
|
||||
version: 1, // see migrations.ts for more details about this version
|
||||
version: 2, // see migrations.ts for more details about this version
|
||||
storage: localForage.createInstance({
|
||||
name: 'redux',
|
||||
}),
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
URAQuoteResponse,
|
||||
URAQuoteType,
|
||||
} from './types'
|
||||
import { isExactInput, shouldUseAPIRouter, transformRoutesToTrade } from './utils'
|
||||
import { isExactInput, transformRoutesToTrade } from './utils'
|
||||
|
||||
const UNISWAP_API_URL = process.env.REACT_APP_UNISWAP_API_URL
|
||||
if (UNISWAP_API_URL === undefined) {
|
||||
@ -121,73 +121,69 @@ export const routingApi = createApi({
|
||||
)
|
||||
},
|
||||
async queryFn(args, _api, _extraOptions, fetch) {
|
||||
let fellBack = false
|
||||
logSwapQuoteRequest(args.tokenInChainId, args.routerPreference, false)
|
||||
const quoteStartMark = performance.mark(`quote-fetch-start-${Date.now()}`)
|
||||
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,
|
||||
intent: args.routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE ? 'pricing' : undefined,
|
||||
configs: getRoutingAPIConfig(args),
|
||||
}
|
||||
|
||||
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 { errorCode?: string; detail?: string }
|
||||
// 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')
|
||||
) {
|
||||
sendAnalyticsEvent('No quote received from routing API', {
|
||||
requestBody,
|
||||
response,
|
||||
routerPreference: args.routerPreference,
|
||||
})
|
||||
return {
|
||||
data: { state: QuoteState.NOT_FOUND, latencyMs: getQuoteLatencyMeasure(quoteStartMark).duration },
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
throw response.error
|
||||
}
|
||||
}
|
||||
|
||||
const uraQuoteResponse = response.data as URAQuoteResponse
|
||||
const tradeResult = await transformRoutesToTrade(args, uraQuoteResponse, QuoteMethod.ROUTING_API)
|
||||
return { data: { ...tradeResult, latencyMs: getQuoteLatencyMeasure(quoteStartMark).duration } }
|
||||
} catch (error: any) {
|
||||
console.warn(
|
||||
`GetQuote failed on Unified Routing API, falling back to client: ${
|
||||
error?.message ?? error?.detail ?? error
|
||||
}`
|
||||
)
|
||||
}
|
||||
}
|
||||
try {
|
||||
const method = fellBack ? QuoteMethod.CLIENT_SIDE_FALLBACK : QuoteMethod.CLIENT_SIDE
|
||||
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,
|
||||
intent: args.routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE ? 'pricing' : undefined,
|
||||
configs: getRoutingAPIConfig(args),
|
||||
}
|
||||
|
||||
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 { errorCode?: string; detail?: string }
|
||||
// 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')
|
||||
) {
|
||||
sendAnalyticsEvent('No quote received from routing API', {
|
||||
requestBody,
|
||||
response,
|
||||
routerPreference: args.routerPreference,
|
||||
})
|
||||
return {
|
||||
data: { state: QuoteState.NOT_FOUND, latencyMs: getQuoteLatencyMeasure(quoteStartMark).duration },
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
throw response.error
|
||||
}
|
||||
}
|
||||
|
||||
const uraQuoteResponse = response.data as URAQuoteResponse
|
||||
const tradeResult = await transformRoutesToTrade(args, uraQuoteResponse, QuoteMethod.ROUTING_API)
|
||||
return { data: { ...tradeResult, latencyMs: getQuoteLatencyMeasure(quoteStartMark).duration } }
|
||||
} catch (error: any) {
|
||||
console.warn(
|
||||
`GetQuote failed on Unified Routing API, falling back to client: ${
|
||||
error?.message ?? error?.detail ?? error
|
||||
}`
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const { getRouter, getClientSideQuote } = await import('lib/hooks/routing/clientSideSmartOrderRouter')
|
||||
const router = getRouter(args.tokenInChainId)
|
||||
const quoteResult = await getClientSideQuote(args, router, CLIENT_PARAMS)
|
||||
if (quoteResult.state === QuoteState.SUCCESS) {
|
||||
const trade = await transformRoutesToTrade(args, quoteResult.data, method)
|
||||
const trade = await transformRoutesToTrade(args, quoteResult.data, QuoteMethod.CLIENT_SIDE_FALLBACK)
|
||||
return {
|
||||
data: { ...trade, latencyMs: getQuoteLatencyMeasure(quoteStartMark).duration },
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ export enum TradeState {
|
||||
export enum QuoteMethod {
|
||||
ROUTING_API = 'ROUTING_API',
|
||||
QUICK_ROUTE = 'QUICK_ROUTE',
|
||||
CLIENT_SIDE = 'CLIENT_SIDE',
|
||||
CLIENT_SIDE_FALLBACK = 'CLIENT_SIDE_FALLBACK', // If client-side was used after the routing-api call failed.
|
||||
}
|
||||
|
||||
@ -27,7 +26,6 @@ export const INTERNAL_ROUTER_PREFERENCE_PRICE = 'price' as const
|
||||
export enum RouterPreference {
|
||||
X = 'uniswapx',
|
||||
API = 'api',
|
||||
CLIENT = 'client',
|
||||
}
|
||||
|
||||
export interface GetQuoteArgs {
|
||||
|
@ -339,7 +339,3 @@ export function isSubmittableTrade(trade?: InterfaceTrade): trade is Submittable
|
||||
export function isUniswapXTrade(trade?: InterfaceTrade): trade is DutchOrderTrade {
|
||||
return trade?.fillType === TradeFillType.UniswapX
|
||||
}
|
||||
|
||||
export function shouldUseAPIRouter(args: GetQuoteArgs): boolean {
|
||||
return args.routerPreference !== RouterPreference.CLIENT
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ export const TEST_TRADE_EXACT_INPUT = new ClassicTrade({
|
||||
tradeType: TradeType.EXACT_INPUT,
|
||||
gasUseEstimateUSD: 1.0,
|
||||
approveInfo: { needsApprove: false },
|
||||
quoteMethod: QuoteMethod.CLIENT_SIDE,
|
||||
quoteMethod: QuoteMethod.CLIENT_SIDE_FALLBACK,
|
||||
inputTax: ZERO_PERCENT,
|
||||
outputTax: ZERO_PERCENT,
|
||||
})
|
||||
@ -80,7 +80,7 @@ export const TEST_TRADE_EXACT_OUTPUT = new ClassicTrade({
|
||||
],
|
||||
v2Routes: [],
|
||||
tradeType: TradeType.EXACT_OUTPUT,
|
||||
quoteMethod: QuoteMethod.CLIENT_SIDE,
|
||||
quoteMethod: QuoteMethod.CLIENT_SIDE_FALLBACK,
|
||||
approveInfo: { needsApprove: false },
|
||||
inputTax: ZERO_PERCENT,
|
||||
outputTax: ZERO_PERCENT,
|
||||
|
Loading…
Reference in New Issue
Block a user