fix: update max slippage state (#3268)
* fix: max slippage state * chore: rename to useAllowedSlippage * nit: maxSlippageInput name
This commit is contained in:
parent
fad55b8dbc
commit
da36e638c2
@ -4,9 +4,9 @@ import { useAtom } from 'jotai'
|
||||
import Popover from 'lib/components/Popover'
|
||||
import { TooltipHandlers, useTooltip } from 'lib/components/Tooltip'
|
||||
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 { 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 Column from '../../Column'
|
||||
@ -98,61 +98,69 @@ const Warning = memo(function Warning({ state, showTooltip }: { state: WarningSt
|
||||
})
|
||||
|
||||
export default function MaxSlippageSelect() {
|
||||
const [maxSlippage, setMaxSlippage] = useAtom(maxSlippageAtom)
|
||||
|
||||
const [custom, setCustom] = useState('')
|
||||
const input = useRef<HTMLInputElement>(null)
|
||||
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 [showTooltip, setShowTooltip, tooltipProps] = useTooltip()
|
||||
useEffect(() => setShowTooltip(true), [warning, setShowTooltip]) // enables the tooltip if a warning is set
|
||||
|
||||
const processInput = useCallback(() => {
|
||||
const numerator = Math.floor(+custom * 100)
|
||||
if (numerator) {
|
||||
const percent = new Percent(numerator, 10_000)
|
||||
if (percent.greaterThan(MAX_VALID_SLIPPAGE)) {
|
||||
setWarning(WarningState.INVALID_SLIPPAGE)
|
||||
setMaxSlippage('auto')
|
||||
} else if (percent.greaterThan(MIN_HIGH_SLIPPAGE)) {
|
||||
setWarning(WarningState.HIGH_SLIPPAGE)
|
||||
setMaxSlippage(percent)
|
||||
const processInput = useCallback(
|
||||
(input: number | undefined) => {
|
||||
const numerator = input && Math.floor(input * 100)
|
||||
if (numerator) {
|
||||
const percent = new Percent(numerator, 10_000)
|
||||
if (percent.greaterThan(MAX_VALID_SLIPPAGE)) {
|
||||
setWarning(WarningState.INVALID_SLIPPAGE)
|
||||
setAutoSlippage(true)
|
||||
setMaxSlippage(input)
|
||||
} else if (percent.greaterThan(MIN_HIGH_SLIPPAGE)) {
|
||||
setWarning(WarningState.HIGH_SLIPPAGE)
|
||||
setAutoSlippage(false)
|
||||
setMaxSlippage(input)
|
||||
} else {
|
||||
setWarning(WarningState.NONE)
|
||||
setAutoSlippage(false)
|
||||
setMaxSlippage(input)
|
||||
}
|
||||
} else {
|
||||
setWarning(WarningState.NONE)
|
||||
setMaxSlippage(percent)
|
||||
setAutoSlippage(true)
|
||||
setMaxSlippage(undefined)
|
||||
}
|
||||
} else {
|
||||
setMaxSlippage('auto')
|
||||
}
|
||||
}, [custom, setMaxSlippage])
|
||||
useEffect(processInput, [processInput])
|
||||
},
|
||||
[setAutoSlippage, setMaxSlippage]
|
||||
)
|
||||
const onInputSelect = useCallback(() => {
|
||||
focus()
|
||||
processInput()
|
||||
}, [focus, processInput])
|
||||
processInput(maxSlippage)
|
||||
}, [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 (
|
||||
<Column gap={0.75}>
|
||||
<Label name={<Trans>Max slippage</Trans>} tooltip={tooltip} />
|
||||
<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>
|
||||
<Trans>Auto</Trans>
|
||||
</ThemedText.ButtonMedium>
|
||||
</Option>
|
||||
<Option
|
||||
wrapper={Custom}
|
||||
selected={maxSlippage !== 'auto'}
|
||||
selected={!autoSlippage}
|
||||
onSelect={onInputSelect}
|
||||
icon={<Warning state={warning} showTooltip={showTooltip} />}
|
||||
{...tooltipProps}
|
||||
>
|
||||
<Row color={warning === WarningState.INVALID_SLIPPAGE ? 'error' : undefined}>
|
||||
<DecimalInput
|
||||
size={Math.max(custom.length, 3)}
|
||||
value={custom}
|
||||
onChange={setCustom}
|
||||
size={Math.max(maxSlippageInput.length, 3)}
|
||||
value={maxSlippageInput}
|
||||
onChange={(input) => processInput(+input)}
|
||||
placeholder={placeholder}
|
||||
ref={input}
|
||||
/>
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { FeeOptions } from '@uniswap/v3-sdk'
|
||||
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
|
||||
import { atom } from 'jotai'
|
||||
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
|
||||
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
|
||||
import { maxSlippageAtom } from 'lib/state/settings'
|
||||
import { feeOptionsAtom, Field, swapAtom } from 'lib/state/swap'
|
||||
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
||||
import { ReactNode, useEffect, useMemo } from 'react'
|
||||
@ -13,6 +11,7 @@ import { InterfaceTrade, TradeState } from 'state/routing/types'
|
||||
|
||||
import { isAddress } from '../../../utils'
|
||||
import useActiveWeb3React from '../useActiveWeb3React'
|
||||
import useAllowedSlippage from '../useAllowedSlippage'
|
||||
import { useBestTrade } from './useBestTrade'
|
||||
|
||||
interface SwapInfo {
|
||||
@ -90,16 +89,7 @@ function useComputeSwapInfo(): SwapInfo {
|
||||
[trade.trade?.inputAmount, trade.trade?.outputAmount]
|
||||
)
|
||||
|
||||
/*
|
||||
* 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 allowedSlippage = useAllowedSlippage(trade.trade)
|
||||
|
||||
const inputError = useMemo(() => {
|
||||
let inputError: ReactNode | undefined
|
||||
|
18
src/lib/hooks/useAllowedSlippage.ts
Normal file
18
src/lib/hooks/useAllowedSlippage.ts
Normal file
@ -0,0 +1,18 @@
|
||||
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)
|
||||
export const MIN_HIGH_SLIPPAGE = new Percent(1, 100)
|
||||
|
||||
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
|
||||
mockTogglable: boolean
|
||||
clientSideRouter: boolean // whether to use the client-side router or query the remote API
|
||||
}
|
||||
|
||||
const initialSettings: Settings = {
|
||||
maxSlippage: 'auto',
|
||||
autoSlippage: true,
|
||||
maxSlippage: undefined,
|
||||
transactionTtl: undefined,
|
||||
mockTogglable: true,
|
||||
clientSideRouter: false,
|
||||
}
|
||||
|
||||
export const settingsAtom = atomWithReset(initialSettings)
|
||||
export const autoSlippageAtom = pickAtom(settingsAtom, 'autoSlippage')
|
||||
export const maxSlippageAtom = pickAtom(settingsAtom, 'maxSlippage')
|
||||
export const transactionTtlAtom = pickAtom(settingsAtom, 'transactionTtl')
|
||||
export const mockTogglableAtom = pickAtom(settingsAtom, 'mockTogglable', setTogglable)
|
||||
|
Loading…
Reference in New Issue
Block a user