Commit da36e638 authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: update max slippage state (#3268)

* fix: max slippage state

* chore: rename to useAllowedSlippage

* nit: maxSlippageInput name
parent fad55b8d
...@@ -4,9 +4,9 @@ import { useAtom } from 'jotai' ...@@ -4,9 +4,9 @@ import { useAtom } from 'jotai'
import Popover from 'lib/components/Popover' import Popover from 'lib/components/Popover'
import { TooltipHandlers, useTooltip } from 'lib/components/Tooltip' import { TooltipHandlers, useTooltip } from 'lib/components/Tooltip'
import { AlertTriangle, Check, Icon, LargeIcon, XOctagon } from 'lib/icons' import { AlertTriangle, Check, Icon, LargeIcon, XOctagon } from 'lib/icons'
import { MAX_VALID_SLIPPAGE, maxSlippageAtom, MIN_HIGH_SLIPPAGE } from 'lib/state/settings' import { autoSlippageAtom, MAX_VALID_SLIPPAGE, maxSlippageAtom, MIN_HIGH_SLIPPAGE } from 'lib/state/settings'
import styled, { Color, ThemedText } from 'lib/theme' import styled, { Color, ThemedText } from 'lib/theme'
import { memo, PropsWithChildren, ReactNode, useCallback, useEffect, useRef, useState } from 'react' import { memo, PropsWithChildren, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { BaseButton, TextButton } from '../../Button' import { BaseButton, TextButton } from '../../Button'
import Column from '../../Column' import Column from '../../Column'
...@@ -98,61 +98,69 @@ const Warning = memo(function Warning({ state, showTooltip }: { state: WarningSt ...@@ -98,61 +98,69 @@ const Warning = memo(function Warning({ state, showTooltip }: { state: WarningSt
}) })
export default function MaxSlippageSelect() { export default function MaxSlippageSelect() {
const [maxSlippage, setMaxSlippage] = useAtom(maxSlippageAtom)
const [custom, setCustom] = useState('')
const input = useRef<HTMLInputElement>(null) const input = useRef<HTMLInputElement>(null)
const focus = useCallback(() => input.current?.focus(), [input]) const focus = useCallback(() => input.current?.focus(), [input])
const [autoSlippage, setAutoSlippage] = useAtom(autoSlippageAtom)
const [maxSlippage, setMaxSlippage] = useAtom(maxSlippageAtom)
const maxSlippageInput = useMemo(() => maxSlippage?.toString() || '', [maxSlippage])
const [warning, setWarning] = useState(WarningState.NONE) const [warning, setWarning] = useState(WarningState.NONE)
const [showTooltip, setShowTooltip, tooltipProps] = useTooltip() const [showTooltip, setShowTooltip, tooltipProps] = useTooltip()
useEffect(() => setShowTooltip(true), [warning, setShowTooltip]) // enables the tooltip if a warning is set
const processInput = useCallback(() => { const processInput = useCallback(
const numerator = Math.floor(+custom * 100) (input: number | undefined) => {
if (numerator) { const numerator = input && Math.floor(input * 100)
const percent = new Percent(numerator, 10_000) if (numerator) {
if (percent.greaterThan(MAX_VALID_SLIPPAGE)) { const percent = new Percent(numerator, 10_000)
setWarning(WarningState.INVALID_SLIPPAGE) if (percent.greaterThan(MAX_VALID_SLIPPAGE)) {
setMaxSlippage('auto') setWarning(WarningState.INVALID_SLIPPAGE)
} else if (percent.greaterThan(MIN_HIGH_SLIPPAGE)) { setAutoSlippage(true)
setWarning(WarningState.HIGH_SLIPPAGE) setMaxSlippage(input)
setMaxSlippage(percent) } else if (percent.greaterThan(MIN_HIGH_SLIPPAGE)) {
setWarning(WarningState.HIGH_SLIPPAGE)
setAutoSlippage(false)
setMaxSlippage(input)
} else {
setWarning(WarningState.NONE)
setAutoSlippage(false)
setMaxSlippage(input)
}
} else { } else {
setWarning(WarningState.NONE) setAutoSlippage(true)
setMaxSlippage(percent) setMaxSlippage(undefined)
} }
} else { },
setMaxSlippage('auto') [setAutoSlippage, setMaxSlippage]
} )
}, [custom, setMaxSlippage])
useEffect(processInput, [processInput])
const onInputSelect = useCallback(() => { const onInputSelect = useCallback(() => {
focus() focus()
processInput() processInput(maxSlippage)
}, [focus, processInput]) }, [focus, maxSlippage, processInput])
useEffect(() => processInput(maxSlippage), [maxSlippage, processInput]) // processes any warnings on mount
useEffect(() => setShowTooltip(true), [warning, setShowTooltip]) // enables the tooltip if a warning is set
return ( return (
<Column gap={0.75}> <Column gap={0.75}>
<Label name={<Trans>Max slippage</Trans>} tooltip={tooltip} /> <Label name={<Trans>Max slippage</Trans>} tooltip={tooltip} />
<Row gap={0.5} grow="last"> <Row gap={0.5} grow="last">
<Option wrapper={Button} selected={maxSlippage === 'auto'} onSelect={() => setMaxSlippage('auto')}> <Option wrapper={Button} selected={autoSlippage} onSelect={() => setAutoSlippage(true)}>
<ThemedText.ButtonMedium> <ThemedText.ButtonMedium>
<Trans>Auto</Trans> <Trans>Auto</Trans>
</ThemedText.ButtonMedium> </ThemedText.ButtonMedium>
</Option> </Option>
<Option <Option
wrapper={Custom} wrapper={Custom}
selected={maxSlippage !== 'auto'} selected={!autoSlippage}
onSelect={onInputSelect} onSelect={onInputSelect}
icon={<Warning state={warning} showTooltip={showTooltip} />} icon={<Warning state={warning} showTooltip={showTooltip} />}
{...tooltipProps} {...tooltipProps}
> >
<Row color={warning === WarningState.INVALID_SLIPPAGE ? 'error' : undefined}> <Row color={warning === WarningState.INVALID_SLIPPAGE ? 'error' : undefined}>
<DecimalInput <DecimalInput
size={Math.max(custom.length, 3)} size={Math.max(maxSlippageInput.length, 3)}
value={custom} value={maxSlippageInput}
onChange={setCustom} onChange={(input) => processInput(+input)}
placeholder={placeholder} placeholder={placeholder}
ref={input} ref={input}
/> />
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { FeeOptions } from '@uniswap/v3-sdk' import { FeeOptions } from '@uniswap/v3-sdk'
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
import { atom } from 'jotai' import { atom } from 'jotai'
import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance' import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
import { maxSlippageAtom } from 'lib/state/settings'
import { feeOptionsAtom, Field, swapAtom } from 'lib/state/swap' import { feeOptionsAtom, Field, swapAtom } from 'lib/state/swap'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { ReactNode, useEffect, useMemo } from 'react' import { ReactNode, useEffect, useMemo } from 'react'
...@@ -13,6 +11,7 @@ import { InterfaceTrade, TradeState } from 'state/routing/types' ...@@ -13,6 +11,7 @@ import { InterfaceTrade, TradeState } from 'state/routing/types'
import { isAddress } from '../../../utils' import { isAddress } from '../../../utils'
import useActiveWeb3React from '../useActiveWeb3React' import useActiveWeb3React from '../useActiveWeb3React'
import useAllowedSlippage from '../useAllowedSlippage'
import { useBestTrade } from './useBestTrade' import { useBestTrade } from './useBestTrade'
interface SwapInfo { interface SwapInfo {
...@@ -90,16 +89,7 @@ function useComputeSwapInfo(): SwapInfo { ...@@ -90,16 +89,7 @@ function useComputeSwapInfo(): SwapInfo {
[trade.trade?.inputAmount, trade.trade?.outputAmount] [trade.trade?.inputAmount, trade.trade?.outputAmount]
) )
/* const allowedSlippage = useAllowedSlippage(trade.trade)
* If user has enabled 'auto' slippage, use the default best slippage calculated
* based on the trade. If user has entered custom slippage, use that instead.
*/
const autoSlippageTolerance = useAutoSlippageTolerance(trade.trade)
const maxSlippage = useAtomValue(maxSlippageAtom)
const allowedSlippage = useMemo(
() => (maxSlippage === 'auto' ? autoSlippageTolerance : maxSlippage),
[autoSlippageTolerance, maxSlippage]
)
const inputError = useMemo(() => { const inputError = useMemo(() => {
let inputError: ReactNode | undefined let inputError: ReactNode | undefined
......
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
import { useAtomValue } from 'jotai/utils'
import { autoSlippageAtom, maxSlippageAtom } from 'lib/state/settings'
import { InterfaceTrade } from 'state/routing/types'
export function toPercent(maxSlippage: number | undefined): Percent | undefined {
if (!maxSlippage) return undefined
const numerator = Math.floor(maxSlippage * 100)
return new Percent(numerator, 10_000)
}
/** Returns the user-inputted max slippage. */
export default function useMaxSlippage(trade: InterfaceTrade<Currency, Currency, TradeType> | undefined): Percent {
const autoSlippage = useAutoSlippageTolerance(trade)
const maxSlippage = toPercent(useAtomValue(maxSlippageAtom))
return useAtomValue(autoSlippageAtom) ? autoSlippage : maxSlippage ?? autoSlippage
}
...@@ -7,20 +7,23 @@ export const MAX_VALID_SLIPPAGE = new Percent(1, 2) ...@@ -7,20 +7,23 @@ export const MAX_VALID_SLIPPAGE = new Percent(1, 2)
export const MIN_HIGH_SLIPPAGE = new Percent(1, 100) export const MIN_HIGH_SLIPPAGE = new Percent(1, 100)
interface Settings { interface Settings {
maxSlippage: Percent | 'auto' // auto will cause slippage to resort to default calculation autoSlippage: boolean // if true, slippage will use the default calculation
maxSlippage: number | undefined // expressed as a percent
transactionTtl: number | undefined transactionTtl: number | undefined
mockTogglable: boolean mockTogglable: boolean
clientSideRouter: boolean // whether to use the client-side router or query the remote API clientSideRouter: boolean // whether to use the client-side router or query the remote API
} }
const initialSettings: Settings = { const initialSettings: Settings = {
maxSlippage: 'auto', autoSlippage: true,
maxSlippage: undefined,
transactionTtl: undefined, transactionTtl: undefined,
mockTogglable: true, mockTogglable: true,
clientSideRouter: false, clientSideRouter: false,
} }
export const settingsAtom = atomWithReset(initialSettings) export const settingsAtom = atomWithReset(initialSettings)
export const autoSlippageAtom = pickAtom(settingsAtom, 'autoSlippage')
export const maxSlippageAtom = pickAtom(settingsAtom, 'maxSlippage') export const maxSlippageAtom = pickAtom(settingsAtom, 'maxSlippage')
export const transactionTtlAtom = pickAtom(settingsAtom, 'transactionTtl') export const transactionTtlAtom = pickAtom(settingsAtom, 'transactionTtl')
export const mockTogglableAtom = pickAtom(settingsAtom, 'mockTogglable', setTogglable) export const mockTogglableAtom = pickAtom(settingsAtom, 'mockTogglable', setTogglable)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment