Skip to content

Commit

Permalink
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
Browse files Browse the repository at this point in the history
…to feat/auto-show-preview-after-approve
  • Loading branch information
viet-nv committed Feb 20, 2025
2 parents 93e8012 + 0e6eb83 commit a1ffaf0
Show file tree
Hide file tree
Showing 21 changed files with 313 additions and 285 deletions.
23 changes: 13 additions & 10 deletions src/components/SlippageControl/CustomSlippageInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { Flex, Text } from 'rebass'
import styled, { css } from 'styled-components'

import Tooltip from 'components/Tooltip'
import { DEFAULT_SLIPPAGES, MAX_DEGEN_SLIPPAGE_IN_BIPS, MAX_NORMAL_SLIPPAGE_IN_BIPS } from 'constants/index'
import { MAX_DEGEN_SLIPPAGE_IN_BIPS, MAX_NORMAL_SLIPPAGE_IN_BIPS } from 'constants/index'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import { useDefaultSlippageByPair } from 'state/swap/hooks'
import { useDegenModeManager } from 'state/user/hooks'
import { formatSlippage } from 'utils/slippage'

const parseSlippageInput = (str: string): number => Math.round(Number.parseFloat(str) * 100)
const getSlippageText = (rawSlippage: number) => {
const isCustom = !DEFAULT_SLIPPAGES.includes(rawSlippage)
const getSlippageText = (rawSlippage: number, options: number[]) => {
const isCustom = !options.includes(rawSlippage)
if (!isCustom) {
return ''
}
Expand Down Expand Up @@ -115,19 +116,21 @@ export type Props = {
rawSlippage: number
setRawSlippage: (value: number) => void
isWarning: boolean
defaultRawSlippage: number
options: number[]
}
const CustomSlippageInput: React.FC<Props> = ({ rawSlippage, setRawSlippage, isWarning, defaultRawSlippage }) => {
const CustomSlippageInput: React.FC<Props> = ({ options, rawSlippage, setRawSlippage, isWarning }) => {
const [tooltip, setTooltip] = useState('')
const inputRef = useRef<HTMLInputElement>(null)
const { mixpanelHandler } = useMixpanel()
const [isDegenMode] = useDegenModeManager()

const defaultRawSlippage = useDefaultSlippageByPair()

// rawSlippage = 10
// slippage shown to user: = 10 / 10_000 = 0.001 = 0.1%
const [rawText, setRawText] = useState(getSlippageText(rawSlippage))
const [rawText, setRawText] = useState(getSlippageText(rawSlippage, options))

const isCustomOptionActive = !DEFAULT_SLIPPAGES.includes(rawSlippage)
const isCustomOptionActive = !options.includes(rawSlippage)

const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setTooltip('')
Expand Down Expand Up @@ -165,16 +168,16 @@ const CustomSlippageInput: React.FC<Props> = ({ rawSlippage, setRawSlippage, isW

const handleCommitChange = () => {
setTooltip('')
setRawText(getSlippageText(rawSlippage))
setRawText(getSlippageText(rawSlippage, options))
mixpanelHandler(MIXPANEL_TYPE.SLIPPAGE_CHANGED, { new_slippage: Number(formatSlippage(rawSlippage, false)) })
}

useEffect(() => {
if (inputRef.current !== document.activeElement) {
setRawText(getSlippageText(rawSlippage))
setRawText(getSlippageText(rawSlippage, options))
setTooltip('')
}
}, [rawSlippage])
}, [rawSlippage, options])

return (
<Flex sx={{ flex: 1 }}>
Expand Down
15 changes: 11 additions & 4 deletions src/components/SlippageControl/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react'
import React, { useMemo } from 'react'
import { Flex } from 'rebass'
import styled, { css } from 'styled-components'

import CustomSlippageInput from 'components/SlippageControl/CustomSlippageInput'
import { DEFAULT_SLIPPAGES } from 'constants/index'
import { DEFAULT_SLIPPAGES, DEFAULT_SLIPPAGES_HIGH_VOTALITY } from 'constants/index'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useTheme from 'hooks/useTheme'
import { usePairCategory } from 'state/swap/hooks'

import { Props as CustomSlippageInputProps } from './CustomSlippageInput'

Expand Down Expand Up @@ -63,6 +64,12 @@ const SlippageControl: React.FC<Props> = props => {
const { rawSlippage, setRawSlippage, isWarning } = props
const theme = useTheme()
const { mixpanelHandler } = useMixpanel()
const cat = usePairCategory()
const options = useMemo(
() => (cat === 'highVolatilityPair' ? DEFAULT_SLIPPAGES_HIGH_VOTALITY : DEFAULT_SLIPPAGES),
[cat],
)

return (
<Flex
sx={{
Expand All @@ -75,7 +82,7 @@ const SlippageControl: React.FC<Props> = props => {
padding: '2px',
}}
>
{DEFAULT_SLIPPAGES.map(slp => (
{options.map(slp => (
<DefaultSlippageOption
key={slp}
onClick={() => {
Expand All @@ -89,7 +96,7 @@ const SlippageControl: React.FC<Props> = props => {
</DefaultSlippageOption>
))}

<CustomSlippageInput {...props} />
<CustomSlippageInput {...props} options={options} />
</Flex>
)
}
Expand Down
23 changes: 7 additions & 16 deletions src/components/SlippageWarningNote/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { Text } from 'rebass'
import styled from 'styled-components'

import WarningNote from 'components/WarningNote'
import { SLIPPAGE_STATUS, checkRangeSlippage } from 'utils/slippage'
import { PAIR_CATEGORY } from 'constants/index'
import { usePairCategory } from 'state/swap/hooks'
import { SLIPPAGE_STATUS, SLIPPAGE_WARNING_MESSAGES, checkRangeSlippage } from 'utils/slippage'

type Props = {
rawSlippage: number
isStablePairSwap: boolean
isCorrelatedPair: boolean
className?: string
}

Expand All @@ -31,24 +31,15 @@ const TextUnderlineTransparent = styled(Text)`
display: inline;
`

const SlippageWarningNote: FC<Props> = ({ className, rawSlippage, isStablePairSwap, isCorrelatedPair }) => {
const slippageStatus = checkRangeSlippage(rawSlippage, isStablePairSwap, isCorrelatedPair)
const SlippageWarningNote: FC<Props> = ({ className, rawSlippage }) => {
const cat = usePairCategory()
const slippageStatus = checkRangeSlippage(rawSlippage, cat)

if (slippageStatus === SLIPPAGE_STATUS.NORMAL) {
return null
}

let msg = 'setting might be high. You might want to adjust it to avoid potential front-running.'
if (slippageStatus === SLIPPAGE_STATUS.LOW) {
msg = 'is low. Your transaction may fail.'
}

if (isStablePairSwap)
msg =
'setting might be high compared to typical stable pair trades. Consider adjusting it to reduce the risk of front-running.'
if (isCorrelatedPair)
msg =
'setting might be high compared with other similar trades. You might want to adjust it to avoid potential front-running.'
const msg = (SLIPPAGE_WARNING_MESSAGES[slippageStatus] as Record<PAIR_CATEGORY, string>)[cat] || ''

const shortText = (
<div>
Expand Down
96 changes: 76 additions & 20 deletions src/components/SwapForm/SlippageSetting.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,76 @@
import { Trans, t } from '@lingui/macro'
import { ReactNode, useState } from 'react'
import { rgba } from 'polished'
import { ReactNode, useMemo, useState } from 'react'
import { Flex, Text } from 'rebass'
import styled from 'styled-components'
import styled, { keyframes } from 'styled-components'

import { ReactComponent as DropdownSVG } from 'assets/svg/down.svg'
import SlippageControl from 'components/SlippageControl'
import SlippageWarningNote from 'components/SlippageWarningNote'
import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
import { DEFAULT_SLIPPAGES, DEFAULT_SLIPPAGES_HIGH_VOTALITY, PAIR_CATEGORY } from 'constants/index'
import useTheme from 'hooks/useTheme'
import { useDefaultSlippageByPair, usePairCategory } from 'state/swap/hooks'
import { useDegenModeManager, useSlippageSettingByPage } from 'state/user/hooks'
import { ExternalLink } from 'theme'
import { checkWarningSlippage, formatSlippage, getDefaultSlippage } from 'utils/slippage'
import { checkWarningSlippage, formatSlippage } from 'utils/slippage'

const DropdownIcon = styled(DropdownSVG)`
transition: transform 300ms;
const highlight = keyframes`
0% {
box-shadow: 0 0 0 0 #31CB9E66;
}
70% {
box-shadow: 0 0 0 3px #31CB9E66;
}
100% {
box-shadow: 0 0 0 0 #31CB9E66;
}
`

//transition: transform 300ms;
const DropdownIcon = styled.div`
margin-left: 6px;
border-radius: 50%;
width: 12px;
height: 12px;
display: flex;
justify-content: center;
align-items: center;
padding: 2px;
transition: all 0.2s ease-in-out;
color: ${({ theme }) => theme.subText};
&[data-flip='true'] {
transform: rotate(180deg);
}
&[data-highlight='true'] {
background: ${({ theme }) => rgba(theme.primary, 0.6)};
animation: ${highlight} 2s infinite alternate ease-in-out;
}
`

type Props = {
isStablePairSwap: boolean
isCorrelatedPair: boolean
rightComponent?: ReactNode
tooltip?: ReactNode
}
const SlippageSetting = ({ isStablePairSwap, isCorrelatedPair, rightComponent, tooltip }: Props) => {
const SlippageSetting = ({ rightComponent, tooltip }: Props) => {
const theme = useTheme()
const [expanded, setExpanded] = useState(false)
const [isDegenMode] = useDegenModeManager()

const { rawSlippage, setRawSlippage, isSlippageControlPinned } = useSlippageSettingByPage()
const defaultRawSlippage = getDefaultSlippage(isStablePairSwap, isCorrelatedPair)

const isWarningSlippage = checkWarningSlippage(rawSlippage, isStablePairSwap, isCorrelatedPair)
const pairCategory = usePairCategory()
const defaultSlp = useDefaultSlippageByPair()
const isWarningSlippage = checkWarningSlippage(rawSlippage, pairCategory)

const options = useMemo(
() => (pairCategory === 'highVolatilityPair' ? DEFAULT_SLIPPAGES_HIGH_VOTALITY : DEFAULT_SLIPPAGES),
[pairCategory],
)

if (!isSlippageControlPinned) {
return null
}
Expand Down Expand Up @@ -109,9 +145,9 @@ const SlippageSetting = ({ isStablePairSwap, isCorrelatedPair, rightComponent, t
<MouseoverTooltip
text={
isWarningSlippage
? isStablePairSwap
? pairCategory === PAIR_CATEGORY.STABLE
? t`Your slippage setting might be high compared to typical stable pair trades. Consider adjusting it to reduce the risk of front-running.`
: isCorrelatedPair
: pairCategory === PAIR_CATEGORY.CORRELATED
? t`Your slippage setting might be high compared with other similar trades. You might want to adjust it to avoid potential front-running.`
: t`Your slippage setting might be high. You might want to adjust it to avoid potential front-running.`
: ''
Expand All @@ -121,7 +157,14 @@ const SlippageSetting = ({ isStablePairSwap, isCorrelatedPair, rightComponent, t
</MouseoverTooltip>
</Text>

<DropdownIcon data-flip={expanded} />
<DropdownIcon data-flip={expanded} data-highlight={!expanded && defaultSlp !== rawSlippage}>
<svg width="10" height="6" viewBox="0 0 6 4" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.70711 3.29289L5.29289 1.70711C5.92286 1.07714 5.47669 0 4.58579 0H1.41421C0.523309 0 0.0771406 1.07714 0.707105 1.70711L2.29289 3.29289C2.68342 3.68342 3.31658 3.68342 3.70711 3.29289Z"
fill="#FAFAFA"
/>
</svg>
</DropdownIcon>
</Flex>
</Flex>
{rightComponent}
Expand All @@ -140,19 +183,32 @@ const SlippageSetting = ({ isStablePairSwap, isCorrelatedPair, rightComponent, t
rawSlippage={rawSlippage}
setRawSlippage={setRawSlippage}
isWarning={isWarningSlippage}
defaultRawSlippage={defaultRawSlippage}
options={options}
/>
{isDegenMode && expanded && (
<Text fontSize="12px" fontWeight="500" color={theme.subText} padding="4px 6px" marginTop="-12px">
Maximum Slippage allow for Degen mode is 50%
</Text>
)}
{Math.abs(defaultSlp - rawSlippage) / defaultSlp > 0.2 && (
<Flex
fontSize={12}
color={theme.primary}
sx={{ gap: '4px', cursor: 'pointer' }}
alignItems="center"
marginTop="-12px"
paddingX="4px"
role="button"
onClick={() => setRawSlippage(defaultSlp)}
>
<MouseoverTooltip text="Dynamic entry based on trading pair." placement="bottom">
<Text sx={{ borderBottom: `1px dotted ${theme.primary}` }}>Suggestion</Text>
</MouseoverTooltip>
{(defaultSlp * 100) / 10_000}%
</Flex>
)}

<SlippageWarningNote
rawSlippage={rawSlippage}
isStablePairSwap={isStablePairSwap}
isCorrelatedPair={isCorrelatedPair}
/>
<SlippageWarningNote rawSlippage={rawSlippage} />
</Flex>
</Flex>
)
Expand Down
10 changes: 1 addition & 9 deletions src/components/SwapForm/SlippageSettingGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,9 @@ export const PriceAlertButton = styled.div`
`

export default function SlippageSettingGroup({
isStablePairSwap,
isCorrelatedPair,
isWrapOrUnwrap,
onOpenGasToken,
}: {
isStablePairSwap: boolean
isCorrelatedPair: boolean
isWrapOrUnwrap: boolean
onOpenGasToken?: () => void
}) {
Expand Down Expand Up @@ -106,11 +102,7 @@ export default function SlippageSettingGroup({
{rightButton}
</>
) : (
<SlippageSetting
isStablePairSwap={isStablePairSwap}
rightComponent={rightButton}
isCorrelatedPair={isCorrelatedPair}
/>
<SlippageSetting rightComponent={rightButton} />
)}
<AddMEVProtectionModal isOpen={showMevModal} onClose={onClose} />
</Flex>
Expand Down
7 changes: 7 additions & 0 deletions src/components/SwapForm/SwapActionButton/SwapOnlyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BuildRouteResult } from 'components/SwapForm/hooks/useBuildRoute'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useSwapCallbackV3 from 'hooks/useSwapCallbackV3'
import { Field } from 'state/swap/actions'
import { useUserSlippageTolerance } from 'state/user/hooks'
import { ChargeFeeBy, DetailedRouteSummary } from 'types/route'
import { toCurrencyAmount } from 'utils/currencyAmount'

Expand Down Expand Up @@ -112,6 +113,12 @@ const SwapOnlyButton: React.FC<Props> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [autoShowPreview, isApproved])

const [slippage] = useUserSlippageTolerance()
useEffect(() => {
if (Boolean(buildResult) && isProcessingSwap) handleClickSwapForNormalMode()
// eslint-disable-next-line
}, [slippage])

const handleClickSwapButton = () => {
mixpanelSwapInit()

Expand Down
2 changes: 0 additions & 2 deletions src/components/SwapForm/SwapFormContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ type SwapFormContextProps = {
routeSummary: DetailedRouteSummary | undefined
typedValue: string
recipient: string | null
isStablePairSwap: boolean
isCorrelatedPair: boolean
isAdvancedMode: boolean
}

Expand Down
Loading

0 comments on commit a1ffaf0

Please sign in to comment.