feat: x rollout cleanup (#7582)
* feat: cleanup post x rollout * feat: remove feature flag * fix: remove more unused styled components * fix: delete deprecated value from redux store * fix: lint * fix: remove userOptedOutOfUniswapX * fix: migrate verion in edge case, add test
This commit is contained in:
parent
0f4ca592f2
commit
5ded55e061
@ -120,10 +120,7 @@ describe('Swap with fees', () => {
|
||||
describe('UniswapX swaps', () => {
|
||||
it('displays UniswapX fee in UI', () => {
|
||||
cy.visit('/swap', {
|
||||
featureFlags: [
|
||||
{ name: FeatureFlag.feesEnabled, value: true },
|
||||
{ name: FeatureFlag.uniswapXDefaultEnabled, value: true },
|
||||
],
|
||||
featureFlags: [{ name: FeatureFlag.feesEnabled, value: true }],
|
||||
})
|
||||
|
||||
// Intercept the trade quote
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ChainId, CurrencyAmount } from '@uniswap/sdk-core'
|
||||
import { CyHttpMessages } from 'cypress/types/net-stubbing'
|
||||
import { FeatureFlag } from 'featureFlags'
|
||||
|
||||
import { DAI, nativeOnChain, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
import { getTestSelector } from '../../utils'
|
||||
@ -45,9 +44,7 @@ function stubSwapTxReceipt() {
|
||||
describe('UniswapX Toggle', () => {
|
||||
beforeEach(() => {
|
||||
stubNonPriceQuoteWith(QuoteWhereUniswapXIsBetter)
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: true }],
|
||||
})
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
})
|
||||
|
||||
it('displays uniswapx ui when setting is on', () => {
|
||||
@ -69,9 +66,7 @@ describe('UniswapX Orders', () => {
|
||||
stubSwapTxReceipt()
|
||||
|
||||
cy.hardhat().then((hardhat) => hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 3e8)))
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: true }],
|
||||
})
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
})
|
||||
|
||||
it('can swap exact-in trades using uniswapX', () => {
|
||||
@ -159,9 +154,7 @@ describe('UniswapX Eth Input', () => {
|
||||
|
||||
stubSwapTxReceipt()
|
||||
|
||||
cy.visit(`/swap/?inputCurrency=ETH&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: true }],
|
||||
})
|
||||
cy.visit(`/swap/?inputCurrency=ETH&outputCurrency=${DAI.address}`)
|
||||
})
|
||||
|
||||
it('can swap using uniswapX with ETH as input', () => {
|
||||
@ -247,9 +240,7 @@ describe('UniswapX activity history', () => {
|
||||
cy.hardhat().then(async (hardhat) => {
|
||||
await hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 3e8))
|
||||
})
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: true }],
|
||||
})
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
})
|
||||
|
||||
it('can view UniswapX order status progress in activity', () => {
|
||||
|
@ -14,7 +14,6 @@ import { useMultichainUXFlag } from 'featureFlags/flags/multichainUx'
|
||||
import { useProgressIndicatorV2Flag } from 'featureFlags/flags/progressIndicatorV2'
|
||||
import { useQuickRouteMainnetFlag } from 'featureFlags/flags/quickRouteMainnet'
|
||||
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
|
||||
import { useUniswapXDefaultEnabledFlag } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useUniswapXSyntheticQuoteFlag } from 'featureFlags/flags/uniswapXUseSyntheticQuote'
|
||||
import { useFeesEnabledFlag } from 'featureFlags/flags/useFees'
|
||||
import { useUpdateAtom } from 'jotai/utils'
|
||||
@ -324,12 +323,6 @@ export default function FeatureFlagModal() {
|
||||
featureFlag={FeatureFlag.uniswapXSyntheticQuote}
|
||||
label="Force synthetic quotes for UniswapX"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variant={BaseVariant}
|
||||
value={useUniswapXDefaultEnabledFlag()}
|
||||
featureFlag={FeatureFlag.uniswapXDefaultEnabled}
|
||||
label="Enable UniswapX by default"
|
||||
/>
|
||||
</FeatureFlagGroup>
|
||||
<FeatureFlagGroup name="Info Site Migration">
|
||||
<FeatureFlagOption
|
||||
|
@ -20,7 +20,7 @@ const ReferenceElement = styled.div`
|
||||
height: inherit;
|
||||
`
|
||||
|
||||
export const Arrow = styled.div`
|
||||
const Arrow = styled.div`
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
z-index: 9998;
|
||||
|
@ -3,11 +3,8 @@ import Column from 'components/Column'
|
||||
import UniswapXBrandMark from 'components/Logo/UniswapXBrandMark'
|
||||
import { RowBetween, RowFixed } from 'components/Row'
|
||||
import Toggle from 'components/Toggle'
|
||||
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 { useRouterPreference } from 'state/user/hooks'
|
||||
import styled from 'styled-components'
|
||||
import { ExternalLink, ThemedText } from 'theme/components'
|
||||
|
||||
@ -22,12 +19,6 @@ const InlineLink = styled(ThemedText.BodySmall)`
|
||||
|
||||
export default function RouterPreferenceSettings() {
|
||||
const [routerPreference, setRouterPreference] = useRouterPreference()
|
||||
const dispatch = useAppDispatch()
|
||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
const isUniswapXOverrideEnabled = isUniswapXDefaultEnabled && !userOptedOutOfUniswapX
|
||||
|
||||
const uniswapXInEffect = routerPreference === RouterPreference.X || isUniswapXOverrideEnabled
|
||||
|
||||
return (
|
||||
<RowBetween gap="sm">
|
||||
@ -46,21 +37,9 @@ export default function RouterPreferenceSettings() {
|
||||
</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}
|
||||
isActive={routerPreference === RouterPreference.X}
|
||||
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)
|
||||
setRouterPreference(routerPreference === RouterPreference.X ? RouterPreference.API : RouterPreference.X)
|
||||
}}
|
||||
/>
|
||||
</RowBetween>
|
||||
|
@ -4,7 +4,6 @@ import { AlertTriangle } from 'react-feather'
|
||||
import styled, { css } from 'styled-components'
|
||||
import { Z_INDEX } from 'theme/zIndex'
|
||||
|
||||
import { useIsDarkMode } from '../../theme/components/ThemeToggle'
|
||||
import { AutoColumn } from '../Column'
|
||||
|
||||
export const PageWrapper = styled.div`
|
||||
@ -61,109 +60,6 @@ const SwapWrapperInner = styled.div`
|
||||
padding-top: 12px;
|
||||
`
|
||||
|
||||
export const UniswapPopoverContainer = styled.div`
|
||||
padding: 18px;
|
||||
color: ${({ theme }) => theme.neutral1};
|
||||
font-weight: 485;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
word-break: break-word;
|
||||
background: ${({ theme }) => theme.surface1};
|
||||
border-radius: 20px;
|
||||
border: 1px solid ${({ theme }) => theme.surface3};
|
||||
box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.9, theme.shadow1)};
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
`
|
||||
|
||||
const springDownKeyframes = `@keyframes spring-down {
|
||||
0% { transform: translateY(-80px); }
|
||||
25% { transform: translateY(4px); }
|
||||
50% { transform: translateY(-1px); }
|
||||
75% { transform: translateY(0px); }
|
||||
100% { transform: translateY(0px); }
|
||||
}`
|
||||
|
||||
const backUpKeyframes = `@keyframes back-up {
|
||||
0% { transform: translateY(0px); }
|
||||
100% { transform: translateY(-80px); }
|
||||
}`
|
||||
|
||||
export const UniswapXShine = (props: any) => {
|
||||
const isDarkMode = useIsDarkMode()
|
||||
return <UniswapXShineInner {...props} style={{ opacity: isDarkMode ? 0.15 : 0.05, ...props.style }} />
|
||||
}
|
||||
|
||||
const UniswapXShineInner = styled.div`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(130deg, transparent 20%, ${({ theme }) => theme.accent1}, transparent 80%);
|
||||
opacity: 0.15;
|
||||
`
|
||||
|
||||
// overflow hidden to hide the SwapMustacheShadow
|
||||
export const SwapOptInSmallContainer = styled.div<{ visible: boolean }>`
|
||||
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
|
||||
overflow: hidden;
|
||||
margin-top: -14px;
|
||||
transform: translateY(${({ visible }) => (visible ? 0 : -80)}px);
|
||||
transition: all ease 400ms;
|
||||
animation: ${({ visible }) => (visible ? `spring-down 900ms ease forwards` : 'back-up 200ms ease forwards')};
|
||||
|
||||
${springDownKeyframes}
|
||||
${backUpKeyframes}
|
||||
`
|
||||
|
||||
export const UniswapXOptInLargeContainerPositioner = styled.div`
|
||||
position: absolute;
|
||||
top: 211px;
|
||||
right: ${-320 - 15}px;
|
||||
width: 320px;
|
||||
align-items: center;
|
||||
min-height: 170px;
|
||||
display: flex;
|
||||
pointer-events: none;
|
||||
`
|
||||
|
||||
export const UniswapXOptInLargeContainer = styled.div<{ visible: boolean }>`
|
||||
opacity: ${({ visible }) => (visible ? 1 : 0)};
|
||||
transform: ${({ visible }) => `translateY(${visible ? 0 : -6}px)`};
|
||||
transition: all ease-in 300ms;
|
||||
transition-delay: ${({ visible }) => (visible ? '350ms' : '0')};
|
||||
pointer-events: ${({ visible }) => (visible ? 'auto' : 'none')};
|
||||
`
|
||||
|
||||
export const SwapMustache = styled.main`
|
||||
position: relative;
|
||||
background: ${({ theme }) => theme.surface1};
|
||||
border-radius: 16px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border: 1px solid ${({ theme }) => theme.surface3};
|
||||
border-top-width: 0;
|
||||
padding: 18px;
|
||||
padding-top: calc(12px + 18px);
|
||||
z-index: 0;
|
||||
transition: transform 250ms ease;
|
||||
`
|
||||
|
||||
export const SwapMustacheShadow = styled.main`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 16px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
box-shadow: 0 0 20px 20px ${({ theme }) => theme.surface2};
|
||||
background: red;
|
||||
`
|
||||
|
||||
export const ArrowWrapper = styled.div<{ clickable: boolean }>`
|
||||
border-radius: 12px;
|
||||
height: 40px;
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
|
||||
|
||||
export function useUniswapXDefaultEnabledFlag(): BaseVariant {
|
||||
return useBaseFlag(FeatureFlag.uniswapXDefaultEnabled)
|
||||
}
|
||||
|
||||
export function useUniswapXDefaultEnabled(): boolean {
|
||||
return useUniswapXDefaultEnabledFlag() === BaseVariant.Enabled
|
||||
}
|
@ -16,7 +16,6 @@ export enum FeatureFlag {
|
||||
infoTDP = 'info_tdp',
|
||||
infoPoolPage = 'info_pool_page',
|
||||
infoLiveViews = 'info_live_views',
|
||||
uniswapXDefaultEnabled = 'uniswapx_default_enabled',
|
||||
quickRouteMainnet = 'enable_quick_route_mainnet',
|
||||
progressIndicatorV2 = 'progress_indicator_v2',
|
||||
feesEnabled = 'fees_enabled',
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { SkipToken, skipToken } from '@reduxjs/toolkit/query/react'
|
||||
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useUniswapXSyntheticQuoteEnabled } from 'featureFlags/flags/uniswapXUseSyntheticQuote'
|
||||
import { useFeesEnabled } from 'featureFlags/flags/useFees'
|
||||
import { useMemo } from 'react'
|
||||
import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from 'state/routing/types'
|
||||
import { currencyAddressForSwapQuote } from 'state/routing/utils'
|
||||
import { useUserDisabledUniswapX, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
||||
|
||||
/**
|
||||
* Returns query arguments for the Routing API query or undefined if the
|
||||
@ -29,9 +27,6 @@ export function useRoutingAPIArguments({
|
||||
routerPreference: RouterPreference | typeof INTERNAL_ROUTER_PREFERENCE_PRICE
|
||||
}): GetQuoteArgs | SkipToken {
|
||||
const uniswapXForceSyntheticQuotes = useUniswapXSyntheticQuoteEnabled()
|
||||
const userDisabledUniswapX = useUserDisabledUniswapX()
|
||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
|
||||
const feesEnabled = useFeesEnabled()
|
||||
// Don't enable fee logic if this is a quote for pricing
|
||||
@ -56,23 +51,8 @@ export function useRoutingAPIArguments({
|
||||
tradeType,
|
||||
needsWrapIfUniswapX: tokenIn.isNative,
|
||||
uniswapXForceSyntheticQuotes,
|
||||
userDisabledUniswapX,
|
||||
userOptedOutOfUniswapX,
|
||||
isUniswapXDefaultEnabled,
|
||||
sendPortionEnabled,
|
||||
},
|
||||
[
|
||||
account,
|
||||
amount,
|
||||
routerPreference,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
tradeType,
|
||||
uniswapXForceSyntheticQuotes,
|
||||
userDisabledUniswapX,
|
||||
userOptedOutOfUniswapX,
|
||||
isUniswapXDefaultEnabled,
|
||||
sendPortionEnabled,
|
||||
]
|
||||
[account, amount, routerPreference, tokenIn, tokenOut, tradeType, uniswapXForceSyntheticQuotes, sendPortionEnabled]
|
||||
)
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ import ErrorBoundary from 'components/ErrorBoundary'
|
||||
import Loader from 'components/Icons/LoadingSpinner'
|
||||
import NavBar, { PageTabs } from 'components/NavBar'
|
||||
import { UK_BANNER_HEIGHT, UK_BANNER_HEIGHT_MD, UK_BANNER_HEIGHT_SM, UkBanner } from 'components/NavBar/UkBanner'
|
||||
import { FeatureFlag, useFeatureFlagsIsLoaded } from 'featureFlags'
|
||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useFeatureFlagsIsLoaded } from 'featureFlags'
|
||||
import { useAtom } from 'jotai'
|
||||
import { useBag } from 'nft/hooks/useBag'
|
||||
import { lazy, Suspense, useEffect, useLayoutEffect, useMemo, useState } from 'react'
|
||||
@ -14,9 +13,8 @@ import { Navigate, Route, Routes, useLocation, useSearchParams } from 'react-rou
|
||||
import { shouldDisableNFTRoutesAtom } from 'state/application/atoms'
|
||||
import { useAppSelector } from 'state/hooks'
|
||||
import { AppState } from 'state/reducer'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { useRouterPreference, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
||||
import { StatsigProvider, StatsigUser, useGate } from 'statsig-react'
|
||||
import { useRouterPreference } from 'state/user/hooks'
|
||||
import { StatsigProvider, StatsigUser } from 'statsig-react'
|
||||
import styled from 'styled-components'
|
||||
import DarkModeQueryParamReader from 'theme/components/DarkModeQueryParamReader'
|
||||
import { useIsDarkMode } from 'theme/components/ThemeToggle'
|
||||
@ -212,9 +210,6 @@ function UserPropertyUpdater() {
|
||||
const isDarkMode = useIsDarkMode()
|
||||
|
||||
const [routerPreference] = useRouterPreference()
|
||||
const userOptedOutOfUniswapX = useUserOptedOutOfUniswapX()
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
const { isLoading: isUniswapXDefaultLoading } = useGate(FeatureFlag.uniswapXDefaultEnabled)
|
||||
const rehydrated = useAppSelector((state) => state._persist.rehydrated)
|
||||
|
||||
useEffect(() => {
|
||||
@ -248,22 +243,8 @@ function UserPropertyUpdater() {
|
||||
}, [isDarkMode])
|
||||
|
||||
useEffect(() => {
|
||||
if (isUniswapXDefaultLoading || !rehydrated) return
|
||||
|
||||
// If we're not in the transition period to UniswapX opt-out, set the router preference to whatever is specified.
|
||||
if (!isUniswapXDefaultEnabled) {
|
||||
if (!rehydrated) return
|
||||
user.set(CustomUserProperties.ROUTER_PREFERENCE, routerPreference)
|
||||
return
|
||||
}
|
||||
|
||||
// In the transition period, override the stored API preference to UniswapX if the user hasn't opted out.
|
||||
if (routerPreference === RouterPreference.API && !userOptedOutOfUniswapX) {
|
||||
user.set(CustomUserProperties.ROUTER_PREFERENCE, RouterPreference.X)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, the user has opted out or their preference is UniswapX/client, so set the preference to whatever is specified.
|
||||
user.set(CustomUserProperties.ROUTER_PREFERENCE, routerPreference)
|
||||
}, [routerPreference, isUniswapXDefaultEnabled, userOptedOutOfUniswapX, isUniswapXDefaultLoading, rehydrated])
|
||||
}, [routerPreference, rehydrated])
|
||||
return null
|
||||
}
|
||||
|
@ -1,207 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { sendAnalyticsEvent, Trace } from 'analytics'
|
||||
import Column from 'components/Column'
|
||||
import UniswapXBrandMark from 'components/Logo/UniswapXBrandMark'
|
||||
import { Arrow } from 'components/Popover'
|
||||
import UniswapXRouterLabel from 'components/RouterLabel/UniswapXRouterLabel'
|
||||
import Row from 'components/Row'
|
||||
import {
|
||||
SwapMustache,
|
||||
SwapMustacheShadow,
|
||||
SwapOptInSmallContainer,
|
||||
UniswapPopoverContainer,
|
||||
UniswapXOptInLargeContainer,
|
||||
UniswapXOptInLargeContainerPositioner,
|
||||
UniswapXShine,
|
||||
} from 'components/swap/styled'
|
||||
import { formatCommonPropertiesForTrade } from 'lib/utils/analytics'
|
||||
import { PropsWithChildren, useRef, useState } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Text } from 'rebass'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { isClassicTrade } from 'state/routing/utils'
|
||||
import { SwapInfo } from 'state/swap/hooks'
|
||||
import { useRouterPreference, useUserDisabledUniswapX } from 'state/user/hooks'
|
||||
import { updateDisabledUniswapX } from 'state/user/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { ThemedText } from 'theme/components'
|
||||
|
||||
export const UniswapXOptIn = (props: { swapInfo: SwapInfo; isSmall: boolean }) => {
|
||||
const {
|
||||
trade: { trade },
|
||||
allowedSlippage,
|
||||
} = props.swapInfo
|
||||
const userDisabledUniswapX = useUserDisabledUniswapX()
|
||||
const isOnClassic = Boolean(trade && isClassicTrade(trade) && trade.isUniswapXBetter && !userDisabledUniswapX)
|
||||
const [hasEverShown, setHasEverShown] = useState(false)
|
||||
|
||||
if (isOnClassic && !hasEverShown) {
|
||||
setHasEverShown(true)
|
||||
}
|
||||
|
||||
// avoid some work if never needed to show
|
||||
if (!hasEverShown) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Trace
|
||||
shouldLogImpression
|
||||
name="UniswapX Opt In Impression"
|
||||
properties={trade ? formatCommonPropertiesForTrade(trade, allowedSlippage) : undefined}
|
||||
>
|
||||
<OptInContents isOnClassic={isOnClassic} {...props} />
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
||||
const OptInContents = ({
|
||||
swapInfo,
|
||||
isOnClassic,
|
||||
isSmall,
|
||||
}: {
|
||||
swapInfo: SwapInfo
|
||||
isOnClassic: boolean
|
||||
isSmall: boolean
|
||||
}) => {
|
||||
const {
|
||||
trade: { trade },
|
||||
allowedSlippage,
|
||||
} = swapInfo
|
||||
const [, setRouterPreference] = useRouterPreference()
|
||||
const dispatch = useAppDispatch()
|
||||
const [showYoureIn, setShowYoureIn] = useState(false)
|
||||
const isVisible = isOnClassic
|
||||
const location = useLocation()
|
||||
|
||||
const tryItNowElement = (
|
||||
<ThemedText.BodySecondary
|
||||
color="accent1"
|
||||
fontSize={14}
|
||||
fontWeight="500"
|
||||
onClick={() => {
|
||||
// slight delay before hiding
|
||||
setTimeout(() => {
|
||||
setShowYoureIn(true)
|
||||
setTimeout(() => {
|
||||
setShowYoureIn(false)
|
||||
}, 5000)
|
||||
}, 200)
|
||||
|
||||
if (!trade) return
|
||||
sendAnalyticsEvent('UniswapX Opt In Toggled', {
|
||||
...formatCommonPropertiesForTrade(trade, allowedSlippage),
|
||||
new_preference: RouterPreference.X,
|
||||
})
|
||||
setRouterPreference(RouterPreference.X)
|
||||
}}
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
Try it now
|
||||
</ThemedText.BodySecondary>
|
||||
)
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>()
|
||||
|
||||
if (isSmall || location.pathname.includes('/tokens/')) {
|
||||
return (
|
||||
<SwapOptInSmallContainer ref={containerRef as any} visible={isVisible}>
|
||||
<SwapMustache>
|
||||
<UniswapXShine />
|
||||
<SwapMustacheShadow />
|
||||
<Row justify="space-between" align="center" flexWrap="wrap">
|
||||
<Text fontSize={14} fontWeight={485} lineHeight="20px">
|
||||
<Trans>Try gas free swaps with the</Trans>
|
||||
<br />
|
||||
<UniswapXBrandMark fontWeight="bold" style={{ transform: `translateY(1px)`, margin: '0 2px' }} />{' '}
|
||||
<Trans>Beta</Trans>
|
||||
</Text>
|
||||
{tryItNowElement}
|
||||
</Row>
|
||||
</SwapMustache>
|
||||
</SwapOptInSmallContainer>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* first popover: intro */}
|
||||
<UniswapXOptInPopover shiny visible={isVisible && !showYoureIn}>
|
||||
<CloseIcon
|
||||
size={18}
|
||||
onClick={() => {
|
||||
if (!trade) return
|
||||
sendAnalyticsEvent('UniswapX Opt In Toggled', {
|
||||
...formatCommonPropertiesForTrade(trade, allowedSlippage),
|
||||
new_preference: RouterPreference.API,
|
||||
})
|
||||
setRouterPreference(RouterPreference.API)
|
||||
dispatch(updateDisabledUniswapX({ disabledUniswapX: true }))
|
||||
}}
|
||||
/>
|
||||
|
||||
<Column>
|
||||
<Text fontSize={14} fontWeight={485} lineHeight="20px">
|
||||
<Trans>Try the</Trans>{' '}
|
||||
<UniswapXBrandMark fontWeight="bold" style={{ transform: `translateY(2px)`, margin: '0 1px' }} />{' '}
|
||||
<Trans>Beta</Trans>
|
||||
<ul style={{ margin: '5px 0 12px 24px', lineHeight: '24px', padding: 0 }}>
|
||||
<li>
|
||||
<Trans>Gas free swaps</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>MEV protection</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans>Better prices and more liquidity</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
{tryItNowElement}
|
||||
</UniswapXOptInPopover>
|
||||
|
||||
{/* second popover: you're in! */}
|
||||
<UniswapXOptInPopover visible={showYoureIn}>
|
||||
<UniswapXRouterLabel disableTextGradient>
|
||||
<Text fontSize={14} fontWeight={535} lineHeight="20px">
|
||||
<Trans>You're in!</Trans>
|
||||
</Text>
|
||||
</UniswapXRouterLabel>
|
||||
|
||||
<ThemedText.BodySecondary style={{ marginTop: 8 }} fontSize={14}>
|
||||
<Trans>You can turn it off at anytime in settings</Trans>
|
||||
</ThemedText.BodySecondary>
|
||||
</UniswapXOptInPopover>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const UniswapXOptInPopover = (props: PropsWithChildren<{ visible: boolean; shiny?: boolean }>) => {
|
||||
return (
|
||||
// positioner ensures no matter the height of the inner content
|
||||
// it sits at the same position from the top of the swap area
|
||||
<UniswapXOptInLargeContainerPositioner>
|
||||
<UniswapXOptInLargeContainer visible={props.visible}>
|
||||
<Arrow className="arrow-right" style={{ position: 'absolute', bottom: '50%', left: -3.5, zIndex: 100 }} />
|
||||
<UniswapPopoverContainer>
|
||||
{props.shiny && <UniswapXShine style={{ zIndex: 0 }} />}
|
||||
{props.children}
|
||||
</UniswapPopoverContainer>
|
||||
</UniswapXOptInLargeContainer>
|
||||
</UniswapXOptInLargeContainerPositioner>
|
||||
)
|
||||
}
|
||||
|
||||
const CloseIcon = styled(X)`
|
||||
color: ${({ theme }) => theme.neutral3};
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 14px;
|
||||
`
|
@ -33,7 +33,6 @@ import { useConnectionReady } from 'connection/eagerlyConnect'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { asSupportedChain, isSupportedChain } from 'constants/chains'
|
||||
import { getSwapCurrencyId, TOKEN_SHORTHANDS } from 'constants/tokens'
|
||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useCurrency, useDefaultActiveTokens } from 'hooks/Tokens'
|
||||
import { useIsSwapUnsupported } from 'hooks/useIsSwapUnsupported'
|
||||
import { useMaxAmountIn } from 'hooks/useMaxAmountIn'
|
||||
@ -64,10 +63,8 @@ import { maxAmountSpend } from 'utils/maxAmountSpend'
|
||||
import { computeRealizedPriceImpact, warningSeverity } from 'utils/prices'
|
||||
import { didUserReject } from 'utils/swapErrorToUserReadableMessage'
|
||||
|
||||
import { useScreenSize } from '../../hooks/useScreenSize'
|
||||
import { useIsDarkMode } from '../../theme/components/ThemeToggle'
|
||||
import { OutputTaxTooltipBody } from './TaxTooltipBody'
|
||||
import { UniswapXOptIn } from './UniswapXOptIn'
|
||||
|
||||
export const ArrowContainer = styled.div`
|
||||
display: inline-flex;
|
||||
@ -597,9 +594,7 @@ export function Swap({
|
||||
const inputCurrency = currencies[Field.INPUT] ?? undefined
|
||||
const switchChain = useSwitchChain()
|
||||
const switchingChain = useAppSelector((state) => state.wallets.switchingChain)
|
||||
const showOptInSmall = !useScreenSize().navSearchInputVisible
|
||||
const isDark = useIsDarkMode()
|
||||
const isUniswapXDefaultEnabled = useUniswapXDefaultEnabled()
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<SwapTab>(SwapTab.Swap)
|
||||
|
||||
@ -832,7 +827,6 @@ export function Swap({
|
||||
)}
|
||||
</div>
|
||||
</AutoColumn>
|
||||
{!showOptInSmall && !isUniswapXDefaultEnabled && <UniswapXOptIn isSmall={false} swapInfo={swapInfo} />}
|
||||
</>
|
||||
)
|
||||
|
||||
@ -849,7 +843,6 @@ export function Swap({
|
||||
/>
|
||||
{/* todo: build Limit UI */}
|
||||
{currentTab === SwapTab.Swap ? swapElement : undefined}
|
||||
{showOptInSmall && !isUniswapXDefaultEnabled && <UniswapXOptIn isSmall swapInfo={swapInfo} />}
|
||||
</SwapWrapper>
|
||||
)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ const defaultState = {
|
||||
user: {},
|
||||
_persist: {
|
||||
rehydrated: true,
|
||||
version: 4,
|
||||
version: 5,
|
||||
},
|
||||
application: {
|
||||
chainId: null,
|
||||
|
@ -6,6 +6,7 @@ import { migration1 } from './migrations/1'
|
||||
import { migration2 } from './migrations/2'
|
||||
import { migration3 } from './migrations/3'
|
||||
import { migration4 } from './migrations/4'
|
||||
import { migration5 } from './migrations/5'
|
||||
import { legacyLocalStorageMigration } from './migrations/legacy'
|
||||
|
||||
/**
|
||||
@ -23,6 +24,7 @@ export const migrations: MigrationManifest = {
|
||||
2: migration2,
|
||||
3: migration3,
|
||||
4: migration4,
|
||||
5: migration5,
|
||||
}
|
||||
|
||||
// We use a custom migration function for the initial state, because redux-persist
|
||||
|
98
src/state/migrations/5.test.ts
Normal file
98
src/state/migrations/5.test.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { createMigrate } from 'redux-persist'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { SlippageTolerance } from 'state/user/types'
|
||||
|
||||
import { migration1 } from './1'
|
||||
import { migration2 } from './2'
|
||||
import { migration3 } from './3'
|
||||
import { migration4 } from './4'
|
||||
import { migration5, PersistAppStateV5 } from './5'
|
||||
|
||||
const previousState: PersistAppStateV5 = {
|
||||
user: {
|
||||
userRouterPreference: RouterPreference.API,
|
||||
optedOutOfUniswapX: false,
|
||||
disabledUniswapX: false,
|
||||
userLocale: null,
|
||||
userHideClosedPositions: false,
|
||||
userSlippageTolerance: SlippageTolerance.Auto,
|
||||
userSlippageToleranceHasBeenMigratedToAuto: true,
|
||||
userDeadline: 1800,
|
||||
tokens: {},
|
||||
pairs: {},
|
||||
timestamp: Date.now(),
|
||||
hideAndroidAnnouncementBanner: false,
|
||||
},
|
||||
_persist: {
|
||||
version: 4,
|
||||
rehydrated: true,
|
||||
},
|
||||
}
|
||||
|
||||
describe('migration to v5', () => {
|
||||
it('should migrate users who currently have `API` router preference', async () => {
|
||||
const migrator = createMigrate(
|
||||
{
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
3: migration3,
|
||||
4: migration4,
|
||||
5: migration5,
|
||||
},
|
||||
{ debug: false }
|
||||
)
|
||||
const result: any = await migrator(previousState, 5)
|
||||
expect(result?.user?.userRouterPreference).toEqual(RouterPreference.X)
|
||||
expect(result?.user?.disabledUniswapX).toBeUndefined()
|
||||
expect(result?.user?.optedOutOfUniswapX).toBeUndefined()
|
||||
expect(result?._persist.version).toEqual(5)
|
||||
})
|
||||
|
||||
it('should not migrate routerPreference if user disabled during rollout', async () => {
|
||||
const migrator = createMigrate(
|
||||
{
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
3: migration3,
|
||||
4: migration4,
|
||||
5: migration5,
|
||||
},
|
||||
{ debug: false }
|
||||
)
|
||||
const result: any = await migrator(
|
||||
{
|
||||
...previousState,
|
||||
user: {
|
||||
...previousState.user,
|
||||
optedOutOfUniswapX: true,
|
||||
},
|
||||
} as PersistAppStateV5,
|
||||
5
|
||||
)
|
||||
expect(result?.user?.userRouterPreference).toEqual(RouterPreference.API)
|
||||
expect(result?.user?.optedOutOfUniswapX).toBeUndefined()
|
||||
expect(result?._persist.version).toEqual(5)
|
||||
})
|
||||
|
||||
it('should not migrate user if user does not exist', async () => {
|
||||
const migrator = createMigrate(
|
||||
{
|
||||
1: migration1,
|
||||
2: migration2,
|
||||
3: migration3,
|
||||
4: migration4,
|
||||
5: migration5,
|
||||
},
|
||||
{ debug: false }
|
||||
)
|
||||
const result: any = await migrator(
|
||||
{
|
||||
...previousState,
|
||||
user: undefined,
|
||||
} as PersistAppStateV5,
|
||||
5
|
||||
)
|
||||
expect(result?.user).toBeUndefined()
|
||||
expect(result?._persist.version).toEqual(5)
|
||||
})
|
||||
})
|
43
src/state/migrations/5.ts
Normal file
43
src/state/migrations/5.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { PersistState } from 'redux-persist'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { UserState } from 'state/user/reducer'
|
||||
|
||||
export type PersistAppStateV5 = {
|
||||
_persist: PersistState
|
||||
} & { user?: UserState & { disabledUniswapX?: boolean; optedOutOfUniswapX?: boolean } }
|
||||
|
||||
/**
|
||||
* Migration to migrate users to UniswapX by default.
|
||||
*/
|
||||
export const migration5 = (state: PersistAppStateV5 | undefined) => {
|
||||
if (!state) return state
|
||||
// Remove a previously-persisted variable
|
||||
if (state?.user && 'disabledUniswapX' in state.user) {
|
||||
delete state.user['disabledUniswapX']
|
||||
}
|
||||
const userOptedOutOfUniswapX = state?.user?.optedOutOfUniswapX
|
||||
if (state?.user && 'optedOutOfUniswapX' in state.user) {
|
||||
delete state.user['optedOutOfUniswapX']
|
||||
}
|
||||
// If the the user has previously disabled UniswapX *during the opt-out rollout period*, we respect that preference.
|
||||
if (state?.user && !userOptedOutOfUniswapX) {
|
||||
return {
|
||||
...state,
|
||||
user: {
|
||||
...state.user,
|
||||
userRouterPreference: RouterPreference.X,
|
||||
},
|
||||
_persist: {
|
||||
...state._persist,
|
||||
version: 5,
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
_persist: {
|
||||
...state._persist,
|
||||
version: 5,
|
||||
},
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ export type AppState = ReturnType<typeof appReducer>
|
||||
|
||||
const persistConfig: PersistConfig<AppState> = {
|
||||
key: 'interface',
|
||||
version: 4, // see migrations.ts for more details about this version
|
||||
version: 5, // see migrations.ts for more details about this version
|
||||
storage: localForage.createInstance({
|
||||
name: 'redux',
|
||||
}),
|
||||
|
@ -89,8 +89,6 @@ interface ExpectedUserState {
|
||||
timestamp: number
|
||||
hideAndroidAnnouncementBanner: boolean
|
||||
showSurveyPopup?: boolean
|
||||
disabledUniswapX?: boolean
|
||||
optedOutOfUniswapX?: boolean
|
||||
originCountry?: string
|
||||
}
|
||||
|
||||
|
@ -63,9 +63,9 @@ function getRoutingAPIConfig(args: GetQuoteArgs): RoutingConfig {
|
||||
|
||||
if (
|
||||
// If the user has opted out of UniswapX during the opt-out transition period, we should respect that preference and only request classic quotes.
|
||||
(args.userOptedOutOfUniswapX && routerPreference !== RouterPreference.X) ||
|
||||
!isUniswapXSupportedChain(tokenInChainId) ||
|
||||
routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE
|
||||
routerPreference === RouterPreference.API ||
|
||||
routerPreference === INTERNAL_ROUTER_PREFERENCE_PRICE ||
|
||||
!isUniswapXSupportedChain(tokenInChainId)
|
||||
) {
|
||||
return [classic]
|
||||
}
|
||||
|
@ -43,11 +43,6 @@ export interface GetQuoteArgs {
|
||||
tradeType: TradeType
|
||||
needsWrapIfUniswapX: boolean
|
||||
uniswapXForceSyntheticQuotes: boolean
|
||||
// legacy field indicating the user disabled UniswapX during the opt-in period, or dismissed the UniswapX opt-in modal.
|
||||
userDisabledUniswapX: boolean
|
||||
// temporary field indicating the user disabled UniswapX during the transition to the opt-out model
|
||||
userOptedOutOfUniswapX: boolean
|
||||
isUniswapXDefaultEnabled: boolean
|
||||
sendPortionEnabled: boolean
|
||||
}
|
||||
|
||||
@ -197,7 +192,6 @@ export class ClassicTrade extends Trade<Currency, Currency, TradeType> {
|
||||
approveInfo: ApproveInfo
|
||||
gasUseEstimateUSD?: number // gas estimate for swaps
|
||||
blockNumber: string | null | undefined
|
||||
isUniswapXBetter: boolean | undefined
|
||||
requestId: string | undefined
|
||||
quoteMethod: QuoteMethod
|
||||
swapFee: SwapFeeInfo | undefined
|
||||
@ -205,7 +199,6 @@ export class ClassicTrade extends Trade<Currency, Currency, TradeType> {
|
||||
constructor({
|
||||
gasUseEstimateUSD,
|
||||
blockNumber,
|
||||
isUniswapXBetter,
|
||||
requestId,
|
||||
quoteMethod,
|
||||
approveInfo,
|
||||
@ -215,7 +208,6 @@ export class ClassicTrade extends Trade<Currency, Currency, TradeType> {
|
||||
gasUseEstimateUSD?: number
|
||||
totalGasUseEstimateUSD?: number
|
||||
blockNumber?: string | null
|
||||
isUniswapXBetter?: boolean
|
||||
requestId?: string
|
||||
quoteMethod: QuoteMethod
|
||||
approveInfo: ApproveInfo
|
||||
@ -240,7 +232,6 @@ export class ClassicTrade extends Trade<Currency, Currency, TradeType> {
|
||||
super(routes)
|
||||
this.blockNumber = blockNumber
|
||||
this.gasUseEstimateUSD = gasUseEstimateUSD
|
||||
this.isUniswapXBetter = isUniswapXBetter
|
||||
this.requestId = requestId
|
||||
this.quoteMethod = quoteMethod
|
||||
this.approveInfo = approveInfo
|
||||
|
@ -3,13 +3,12 @@ import { renderHook } from '@testing-library/react'
|
||||
import { CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
||||
import { AVERAGE_L1_BLOCK_TIME } from 'constants/chainInfo'
|
||||
import { USDC_MAINNET } from 'constants/tokens'
|
||||
import { useUniswapXDefaultEnabled } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useUniswapXSyntheticQuoteEnabled } from 'featureFlags/flags/uniswapXUseSyntheticQuote'
|
||||
import { useFeesEnabled } from 'featureFlags/flags/useFees'
|
||||
import useIsWindowVisible from 'hooks/useIsWindowVisible'
|
||||
import ms from 'ms'
|
||||
import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from 'state/routing/types'
|
||||
import { useRouterPreference, useUserDisabledUniswapX, useUserOptedOutOfUniswapX } from 'state/user/hooks'
|
||||
import { useRouterPreference } from 'state/user/hooks'
|
||||
import { ETH_MAINNET } from 'test-utils/constants'
|
||||
import { mocked } from 'test-utils/mocked'
|
||||
|
||||
@ -29,16 +28,12 @@ jest.mock('./slice', () => {
|
||||
})
|
||||
jest.mock('state/user/hooks')
|
||||
jest.mock('featureFlags/flags/uniswapXUseSyntheticQuote')
|
||||
jest.mock('featureFlags/flags/uniswapXDefault')
|
||||
jest.mock('featureFlags/flags/useFees')
|
||||
|
||||
beforeEach(() => {
|
||||
mocked(useIsWindowVisible).mockReturnValue(true)
|
||||
mocked(useRouterPreference).mockReturnValue([RouterPreference.API, () => undefined])
|
||||
mocked(useUniswapXSyntheticQuoteEnabled).mockReturnValue(false)
|
||||
mocked(useUserDisabledUniswapX).mockReturnValue(false)
|
||||
mocked(useUserOptedOutOfUniswapX).mockReturnValue(false)
|
||||
mocked(useUniswapXDefaultEnabled).mockReturnValue(false)
|
||||
mocked(useFeesEnabled).mockReturnValue(true)
|
||||
// @ts-ignore we dont use the response from this hook in useRoutingAPITrade so fine to mock as undefined
|
||||
mocked(useGetQuoteQuery).mockReturnValue(undefined)
|
||||
@ -66,9 +61,6 @@ const MOCK_ARGS: GetQuoteArgs = {
|
||||
tradeType: TradeType.EXACT_INPUT,
|
||||
needsWrapIfUniswapX: USDCAmount.currency.isNative,
|
||||
uniswapXForceSyntheticQuotes: false,
|
||||
userDisabledUniswapX: false,
|
||||
userOptedOutOfUniswapX: false,
|
||||
isUniswapXDefaultEnabled: false,
|
||||
sendPortionEnabled: true,
|
||||
}
|
||||
|
||||
|
@ -219,18 +219,14 @@ export async function transformQuoteToTrade(
|
||||
data: URAQuoteResponse,
|
||||
quoteMethod: QuoteMethod
|
||||
): Promise<TradeResult> {
|
||||
const { tradeType, needsWrapIfUniswapX, routerPreference, account, amount, isUniswapXDefaultEnabled } = args
|
||||
const { tradeType, needsWrapIfUniswapX, routerPreference, account, amount } = args
|
||||
|
||||
const showUniswapXTrade = data.routing === URAQuoteType.DUTCH_LIMIT && routerPreference === RouterPreference.X
|
||||
|
||||
const showUniswapXTrade =
|
||||
data.routing === URAQuoteType.DUTCH_LIMIT &&
|
||||
(routerPreference === RouterPreference.X || (isUniswapXDefaultEnabled && routerPreference === RouterPreference.API))
|
||||
const [currencyIn, currencyOut] = getTradeCurrencies(args, showUniswapXTrade)
|
||||
|
||||
const { gasUseEstimateUSD, blockNumber, routes, gasUseEstimate, swapFee } = getClassicTradeDetails(args, data)
|
||||
|
||||
// If the top-level URA quote type is DUTCH_LIMIT, then UniswapX is better for the user
|
||||
const isUniswapXBetter = data.routing === URAQuoteType.DUTCH_LIMIT
|
||||
|
||||
// Some sus javascript float math but it's ok because its just an estimate for display purposes
|
||||
const usdCostPerGas = gasUseEstimateUSD && gasUseEstimate ? gasUseEstimateUSD / gasUseEstimate : undefined
|
||||
|
||||
@ -267,15 +263,14 @@ export async function transformQuoteToTrade(
|
||||
gasUseEstimateUSD,
|
||||
approveInfo,
|
||||
blockNumber,
|
||||
isUniswapXBetter,
|
||||
requestId: data.quote.requestId,
|
||||
quoteMethod,
|
||||
swapFee,
|
||||
})
|
||||
|
||||
// During the opt-in period, only return UniswapX quotes if the user has turned on the setting,
|
||||
// even if it is the better quote.
|
||||
if (isUniswapXBetter && (routerPreference === RouterPreference.X || isUniswapXDefaultEnabled)) {
|
||||
// If the top-level URA quote type is DUTCH_LIMIT, then UniswapX is better for the user
|
||||
const isUniswapXBetter = data.routing === URAQuoteType.DUTCH_LIMIT
|
||||
if (isUniswapXBetter) {
|
||||
const orderInfo = toDutchOrderInfo(data.quote.orderInfo)
|
||||
const swapFee = getSwapFee(data.quote)
|
||||
const wrapInfo = await getWrapInfo(needsWrapIfUniswapX, account, currencyIn.chainId, amount, usdCostPerGas)
|
||||
|
@ -77,7 +77,7 @@ const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = {
|
||||
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D': true, // v2 router 02
|
||||
}
|
||||
|
||||
export type SwapInfo = {
|
||||
type SwapInfo = {
|
||||
currencies: { [field in Field]?: Currency }
|
||||
currencyBalances: { [field in Field]?: CurrencyAmount<Currency> }
|
||||
inputTax: Percent
|
||||
|
@ -5,13 +5,7 @@ import store from 'state'
|
||||
import { RouterPreference } from 'state/routing/types'
|
||||
import { renderHook } from 'test-utils/render'
|
||||
|
||||
import {
|
||||
deserializeToken,
|
||||
serializeToken,
|
||||
useRouterPreference,
|
||||
useUserDisabledUniswapX,
|
||||
useUserSlippageTolerance,
|
||||
} from './hooks'
|
||||
import { deserializeToken, serializeToken, useRouterPreference, useUserSlippageTolerance } from './hooks'
|
||||
import { updateUserSlippageTolerance } from './reducer'
|
||||
import { SlippageTolerance } from './types'
|
||||
|
||||
@ -81,12 +75,3 @@ describe('useRouterPreference', () => {
|
||||
expect(routerPreference).toBe(RouterPreference.X)
|
||||
})
|
||||
})
|
||||
|
||||
describe('useUserDisabledUniswapX', () => {
|
||||
it('returns `false` by default', () => {
|
||||
const {
|
||||
result: { current: disabledUniswapX },
|
||||
} = renderHook(() => useUserDisabledUniswapX())
|
||||
expect(disabledUniswapX).toBe(false)
|
||||
})
|
||||
})
|
||||
|
@ -217,14 +217,6 @@ export function useHideAndroidAnnouncementBanner(): [boolean, () => void] {
|
||||
return [hideAndroidAnnouncementBanner, toggleHideAndroidAnnouncementBanner]
|
||||
}
|
||||
|
||||
export function useUserDisabledUniswapX(): boolean {
|
||||
return useAppSelector((state) => state.user.disabledUniswapX) ?? false
|
||||
}
|
||||
|
||||
export function useUserOptedOutOfUniswapX(): boolean {
|
||||
return useAppSelector((state) => state.user.optedOutOfUniswapX) ?? false
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two tokens return the liquidity token that represents its liquidity shares
|
||||
* @param tokenA one of the two tokens
|
||||
|
@ -48,10 +48,6 @@ export interface UserState {
|
||||
|
||||
timestamp: number
|
||||
hideAndroidAnnouncementBanner: boolean
|
||||
// legacy field indicating the user disabled UniswapX during the opt-in period, or dismissed the UniswapX opt-in modal.
|
||||
disabledUniswapX?: boolean
|
||||
// temporary field indicating the user disabled UniswapX during the transition to the opt-out model
|
||||
optedOutOfUniswapX?: boolean
|
||||
// undefined means has not gone through A/B split yet
|
||||
showSurveyPopup?: boolean
|
||||
|
||||
@ -111,12 +107,6 @@ const userSlice = createSlice({
|
||||
updateHideAndroidAnnouncementBanner(state, action) {
|
||||
state.hideAndroidAnnouncementBanner = action.payload.hideAndroidAnnouncementBanner
|
||||
},
|
||||
updateDisabledUniswapX(state, action) {
|
||||
state.disabledUniswapX = action.payload.disabledUniswapX
|
||||
},
|
||||
updateOptedOutOfUniswapX(state, action) {
|
||||
state.optedOutOfUniswapX = action.payload.optedOutOfUniswapX
|
||||
},
|
||||
addSerializedToken(state, { payload: { serializedToken } }) {
|
||||
if (!state.tokens) {
|
||||
state.tokens = {}
|
||||
@ -153,7 +143,5 @@ export const {
|
||||
updateUserLocale,
|
||||
updateUserSlippageTolerance,
|
||||
updateHideAndroidAnnouncementBanner,
|
||||
updateDisabledUniswapX,
|
||||
updateOptedOutOfUniswapX,
|
||||
} = userSlice.actions
|
||||
export default userSlice.reducer
|
||||
|
Loading…
Reference in New Issue
Block a user