Skip to content

Commit

Permalink
feat: widget auto slippage mode (#349)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomiiide authored Feb 14, 2025
1 parent 6c9d22e commit 580ce06
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 32 deletions.
4 changes: 3 additions & 1 deletion packages/widget/src/hooks/useRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
}) => {
const fromAmount = parseUnits(fromTokenAmount, fromToken!.decimals)
const toAmount = parseUnits(toTokenAmount, toToken!.decimals)
const formattedSlippage = Number.parseFloat(slippage) / 100
const formattedSlippage = slippage
? Number.parseFloat(slippage) / 100
: defaultSlippage

const allowBridges = swapOnly
? []
Expand Down
13 changes: 11 additions & 2 deletions packages/widget/src/hooks/useSettingMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ export const useSettingMonitor = () => {
: slippage !== defaultConfigurableSettings.slippage

const isSlippageOutsideRecommendedLimits =
isSlippageChanged && Number(slippage) > 1
isSlippageChanged && slippage && Number(slippage) > 1

const isSlippageUnderRecommendedLimits =
isSlippageChanged && slippage && Number(slippage) < 0.1

const isSlippageNotRecommended = Boolean(
isSlippageOutsideRecommendedLimits || isSlippageUnderRecommendedLimits
)

const isRoutePriorityChanged = config.routePriority
? routePriority !== config.routePriority
Expand All @@ -51,7 +58,7 @@ export const useSettingMonitor = () => {
isRoutePriorityChanged ||
isGasPriceChanged

const isRouteSettingsWithWarnings = isSlippageOutsideRecommendedLimits
const isRouteSettingsWithWarnings = isSlippageNotRecommended

const reset = () => {
if (tools) {
Expand All @@ -68,7 +75,9 @@ export const useSettingMonitor = () => {
isBridgesChanged,
isExchangesChanged,
isSlippageChanged,
isSlippageNotRecommended,
isSlippageOutsideRecommendedLimits,
isSlippageUnderRecommendedLimits,
isRoutePriorityChanged,
isGasPriceChanged,
isCustomRouteSettings,
Expand Down
3 changes: 2 additions & 1 deletion packages/widget/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@
"insufficientGas": "You don't have enough gas to complete the transaction. You need to add at least:",
"rateChanged": "The exchange rate has changed. By continuing the transaction, you'll accept the new rate.",
"resetSettings": "This will reset your route priority, slippage, gas price, enabled bridges and exchanges.",
"slippageOutsideRecommendedLimits": "High slippage tolerance may result in unfavorable trade caused by front-running."
"slippageOutsideRecommendedLimits": "High slippage tolerance may result in unfavorable trade caused by front-running.",
"slippageUnderRecommendedLimits": "Low slippage tolerance may cause transaction delays or failures."
},
"title": {
"deleteActiveTransactions": "Delete all active transactions?",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,30 @@ import {
SlippageLimitsWarningContainer,
} from './SlippageSettings.style.js'

const DEFAULT_CUSTOM_INPUT_VALUE = '0.5'

export const SlippageSettings: React.FC = () => {
const { t } = useTranslation()
const { isSlippageOutsideRecommendedLimits, isSlippageChanged } =
useSettingMonitor()
const {
isSlippageNotRecommended,
isSlippageUnderRecommendedLimits,
isSlippageOutsideRecommendedLimits,
isSlippageChanged,
} = useSettingMonitor()
const { slippage } = useSettings(['slippage'])
const { setValue } = useSettingsActions()
const defaultValue = useRef(slippage)
const [focused, setFocused] = useState<'input' | 'button'>()

const customInputValue =
!slippage || slippage === defaultSlippage ? '' : slippage
!slippage || slippage === defaultSlippage
? DEFAULT_CUSTOM_INPUT_VALUE
: slippage

const [inputValue, setInputValue] = useState(customInputValue)

const handleDefaultClick = () => {
setValue('slippage', formatSlippage(defaultSlippage, defaultValue.current))
setValue('slippage', defaultSlippage)
}

const debouncedSetValue = useMemo(() => debounce(setValue, 500), [setValue])
Expand All @@ -41,43 +49,49 @@ export const SlippageSettings: React.FC = () => {
(event) => {
const { value } = event.target

setInputValue(formatSlippage(value, defaultValue.current, true))
const formattedValue = formatSlippage(value, defaultValue.current, true)

setInputValue(formattedValue)
debouncedSetValue(
'slippage',
formatSlippage(value || defaultSlippage, defaultValue.current, true)
formattedValue.length ? formattedValue : defaultSlippage
)
},
[debouncedSetValue]
)

const handleInputBlur: FocusEventHandler<HTMLInputElement> = (event) => {
setFocused(undefined)
const handleInputFocus: FocusEventHandler<HTMLInputElement> = (event) => {
setFocused('input')

const { value } = event.target

const formattedValue = formatSlippage(
value || defaultSlippage,
defaultValue.current
)
setInputValue(formattedValue === defaultSlippage ? '' : formattedValue)
const formattedValue = formatSlippage(value, defaultValue.current)
setInputValue(formattedValue)

setValue('slippage', formattedValue)
setValue(
'slippage',
formattedValue.length ? formattedValue : defaultSlippage
)
}

const badgeColor = isSlippageOutsideRecommendedLimits
const badgeColor = isSlippageNotRecommended
? 'warning'
: isSlippageChanged
? 'info'
: undefined

const slippageWarningText = isSlippageOutsideRecommendedLimits
? t('warning.message.slippageOutsideRecommendedLimits')
: isSlippageUnderRecommendedLimits
? t('warning.message.slippageUnderRecommendedLimits')
: ''

return (
<SettingCardExpandable
value={
<BadgedValue
badgeColor={badgeColor}
showBadge={!!badgeColor}
>{`${slippage}%`}</BadgedValue>
<BadgedValue badgeColor={badgeColor} showBadge={!!badgeColor}>
{slippage ? `${slippage}%` : t('button.auto')}
</BadgedValue>
}
icon={<Percent />}
title={t('settings.slippage')}
Expand All @@ -99,7 +113,7 @@ export const SlippageSettings: React.FC = () => {
onClick={handleDefaultClick}
disableRipple
>
{defaultSlippage}
{t('button.auto')}
</SlippageDefaultButton>
<SlippageCustomInput
selected={defaultSlippage !== slippage && focused !== 'button'}
Expand All @@ -108,15 +122,13 @@ export const SlippageSettings: React.FC = () => {
inputMode: 'decimal',
}}
onChange={handleInputUpdate}
onFocus={() => {
setFocused('input')
}}
onBlur={handleInputBlur}
onFocus={handleInputFocus}
value={inputValue}
autoComplete="off"
onBlur={() => setFocused(undefined)}
/>
</SettingsFieldSet>
{isSlippageOutsideRecommendedLimits && (
{isSlippageNotRecommended && (
<SlippageLimitsWarningContainer>
<WarningRounded color="warning" />
<Typography
Expand All @@ -125,7 +137,7 @@ export const SlippageSettings: React.FC = () => {
fontWeight: 400,
}}
>
{t('warning.message.slippageOutsideRecommendedLimits')}
{slippageWarningText}
</Typography>
</SlippageLimitsWarningContainer>
)}
Expand Down
2 changes: 1 addition & 1 deletion packages/widget/src/stores/settings/useSettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { SettingsProps, SettingsState } from './types.js'
import { SettingsToolTypes } from './types.js'
import { getStateValues } from './utils/getStateValues.js'

export const defaultSlippage = '0.5'
export const defaultSlippage = undefined

export const defaultConfigurableSettings: Pick<
SettingsState,
Expand Down
2 changes: 1 addition & 1 deletion packages/widget/src/types/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export interface CalculateFeeParams {
toAddress?: string
fromAmount?: bigint
toAmount?: bigint
slippage: number
slippage?: number
}

export interface WidgetFeeConfig {
Expand Down

0 comments on commit 580ce06

Please sign in to comment.