diff --git a/packages/widget/src/hooks/useRoutes.ts b/packages/widget/src/hooks/useRoutes.ts index bbc64d0dc..a5619530f 100644 --- a/packages/widget/src/hooks/useRoutes.ts +++ b/packages/widget/src/hooks/useRoutes.ts @@ -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 ? [] diff --git a/packages/widget/src/hooks/useSettingMonitor.ts b/packages/widget/src/hooks/useSettingMonitor.ts index ce43fe47c..cd16c437c 100644 --- a/packages/widget/src/hooks/useSettingMonitor.ts +++ b/packages/widget/src/hooks/useSettingMonitor.ts @@ -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 @@ -51,7 +58,7 @@ export const useSettingMonitor = () => { isRoutePriorityChanged || isGasPriceChanged - const isRouteSettingsWithWarnings = isSlippageOutsideRecommendedLimits + const isRouteSettingsWithWarnings = isSlippageNotRecommended const reset = () => { if (tools) { @@ -68,7 +75,9 @@ export const useSettingMonitor = () => { isBridgesChanged, isExchangesChanged, isSlippageChanged, + isSlippageNotRecommended, isSlippageOutsideRecommendedLimits, + isSlippageUnderRecommendedLimits, isRoutePriorityChanged, isGasPriceChanged, isCustomRouteSettings, diff --git a/packages/widget/src/i18n/en.json b/packages/widget/src/i18n/en.json index f7ab1c893..1b53f9fd2 100644 --- a/packages/widget/src/i18n/en.json +++ b/packages/widget/src/i18n/en.json @@ -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?", diff --git a/packages/widget/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx b/packages/widget/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx index 66ca86ab0..6db86376f 100644 --- a/packages/widget/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx +++ b/packages/widget/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx @@ -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]) @@ -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 = (event) => { - setFocused(undefined) + const handleInputFocus: FocusEventHandler = (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 ( {`${slippage}%`} + + {slippage ? `${slippage}%` : t('button.auto')} + } icon={} title={t('settings.slippage')} @@ -99,7 +113,7 @@ export const SlippageSettings: React.FC = () => { onClick={handleDefaultClick} disableRipple > - {defaultSlippage} + {t('button.auto')} { inputMode: 'decimal', }} onChange={handleInputUpdate} - onFocus={() => { - setFocused('input') - }} - onBlur={handleInputBlur} + onFocus={handleInputFocus} value={inputValue} autoComplete="off" + onBlur={() => setFocused(undefined)} /> - {isSlippageOutsideRecommendedLimits && ( + {isSlippageNotRecommended && ( { fontWeight: 400, }} > - {t('warning.message.slippageOutsideRecommendedLimits')} + {slippageWarningText} )} diff --git a/packages/widget/src/stores/settings/useSettingsStore.ts b/packages/widget/src/stores/settings/useSettingsStore.ts index 8b2f022d1..57d77e27c 100644 --- a/packages/widget/src/stores/settings/useSettingsStore.ts +++ b/packages/widget/src/stores/settings/useSettingsStore.ts @@ -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, diff --git a/packages/widget/src/types/widget.ts b/packages/widget/src/types/widget.ts index df3e17820..75419b03b 100644 --- a/packages/widget/src/types/widget.ts +++ b/packages/widget/src/types/widget.ts @@ -144,7 +144,7 @@ export interface CalculateFeeParams { toAddress?: string fromAmount?: bigint toAmount?: bigint - slippage: number + slippage?: number } export interface WidgetFeeConfig {