diff --git a/src/custom/components/TransactionSettings/TransactionSettingsMod.tsx b/src/custom/components/TransactionSettings/TransactionSettingsMod.tsx index a6ea97c5a0..7dc4302d7d 100644 --- a/src/custom/components/TransactionSettings/TransactionSettingsMod.tsx +++ b/src/custom/components/TransactionSettings/TransactionSettingsMod.tsx @@ -5,7 +5,7 @@ import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc' import useActiveWeb3React from 'hooks/useActiveWeb3React' // import ms from 'ms.macro' import { darken } from 'polished' -import { useContext, useState } from 'react' +import { useCallback, useContext, useState } from 'react' import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks' import styled, { ThemeContext } from 'styled-components/macro' @@ -16,7 +16,17 @@ import { RowBetween, RowFixed } from 'components/Row' import ReactGA from 'react-ga4' // MOD imports -import { INPUT_OUTPUT_EXPLANATION, MINIMUM_ORDER_VALID_TO_TIME_SECONDS } from 'constants/index' +import { + INPUT_OUTPUT_EXPLANATION, + MINIMUM_ORDER_VALID_TO_TIME_SECONDS, + MIN_SLIPPAGE_BPS, + MAX_SLIPPAGE_BPS, + LOW_SLIPPAGE_BPS, + HIGH_SLIPPAGE_BPS, + DEFAULT_SLIPPAGE_BPS, +} from 'constants/index' +import ReactGA from 'react-ga4' +import { debounce } from 'utils/misc' const MAX_DEADLINE_MINUTES = 180 // 3h @@ -95,6 +105,14 @@ const SlippageEmojiContainer = styled.span` `} ` +const reportAnalytics = debounce((actionName: string, slippageBps: number) => { + ReactGA.event({ + category: 'Order Slippage Tolerance', + action: actionName, + value: slippageBps, + }) +}, 2000) + export interface TransactionSettingsProps { placeholderSlippage: Percent // varies according to the context in which the settings dialog is placed } @@ -116,29 +134,37 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction const [deadlineInput, setDeadlineInput] = useState('') const [deadlineError, setDeadlineError] = useState(false) - function parseSlippageInput(value: string) { - // populate what the user typed and clear the error - setSlippageInput(value) - setSlippageError(false) + const parseSlippageInput = useCallback( + (value: string) => { + // populate what the user typed and clear the error + setSlippageInput(value) + setSlippageError(false) - if (value.length === 0) { - setUserSlippageTolerance('auto') - } else { - const parsed = Math.floor(Number.parseFloat(value) * 100) - - if (!Number.isInteger(parsed) || parsed < 0 || parsed > 5000) { + if (value.length === 0) { + reportAnalytics('Set Default Slippage Tolerance', DEFAULT_SLIPPAGE_BPS) setUserSlippageTolerance('auto') - if (value !== '.') { - setSlippageError(SlippageError.InvalidInput) - } } else { - setUserSlippageTolerance(new Percent(parsed, 10_000)) + const parsed = Math.floor(Number.parseFloat(value) * 100) + + if (!Number.isInteger(parsed) || parsed < MIN_SLIPPAGE_BPS || parsed > MAX_SLIPPAGE_BPS) { + reportAnalytics('Set Default Slippage Tolerance', DEFAULT_SLIPPAGE_BPS) + setUserSlippageTolerance('auto') + if (value !== '.') { + setSlippageError(SlippageError.InvalidInput) + } + } else { + reportAnalytics('Set Custom Slippage Tolerance', parsed) + setUserSlippageTolerance(new Percent(parsed, 10_000)) + } } - } - } + }, + [setUserSlippageTolerance] + ) - const tooLow = userSlippageTolerance !== 'auto' && userSlippageTolerance.lessThan(new Percent(5, 10_000)) - const tooHigh = userSlippageTolerance !== 'auto' && userSlippageTolerance.greaterThan(new Percent(1, 100)) + const tooLow = + userSlippageTolerance !== 'auto' && userSlippageTolerance.lessThan(new Percent(LOW_SLIPPAGE_BPS, 10_000)) + const tooHigh = + userSlippageTolerance !== 'auto' && userSlippageTolerance.greaterThan(new Percent(HIGH_SLIPPAGE_BPS, 10_000)) function parseCustomDeadline(value: string) { // populate what the user typed and clear the error diff --git a/src/custom/constants/index.ts b/src/custom/constants/index.ts index ae9c2ff492..76dabc3fa7 100644 --- a/src/custom/constants/index.ts +++ b/src/custom/constants/index.ts @@ -6,7 +6,12 @@ import { WalletInfo, SUPPORTED_WALLETS as SUPPORTED_WALLETS_UNISWAP } from 'cons import { SupportedChainId as ChainId } from 'constants/chains' import { getAppDataHash } from './appDataHash' -export const INITIAL_ALLOWED_SLIPPAGE_PERCENT = new Percent('5', '1000') // 0.5% +export const DEFAULT_SLIPPAGE_BPS = 50 // 0.5% +export const MAX_SLIPPAGE_BPS = 5000 // 50% +export const MIN_SLIPPAGE_BPS = 0 // 0% +export const HIGH_SLIPPAGE_BPS = 100 // 1% +export const LOW_SLIPPAGE_BPS = 5 // 0.05% +export const INITIAL_ALLOWED_SLIPPAGE_PERCENT = new Percent(DEFAULT_SLIPPAGE_BPS, 10_000) // 0.5% export const RADIX_DECIMAL = 10 export const RADIX_HEX = 16 diff --git a/src/custom/utils/misc.ts b/src/custom/utils/misc.ts index 27b354e38c..65c223027a 100644 --- a/src/custom/utils/misc.ts +++ b/src/custom/utils/misc.ts @@ -16,6 +16,16 @@ export function withTimeout(promise: Promise, ms: number, context?: string return Promise.race([promise, failOnTimeout]) } +export function debounce any>(func: F, wait = 200) { + let timeout: NodeJS.Timeout + const debounced = (...args: any) => { + clearTimeout(timeout) + timeout = setTimeout(() => func(args), wait) + } + + return debounced +} + export function isPromiseFulfilled( promiseResult: PromiseSettledResult ): promiseResult is PromiseFulfilledResult {