diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx
index e4444493ab..ec2f55b1da 100644
--- a/src/components/Button/index.tsx
+++ b/src/components/Button/index.tsx
@@ -244,6 +244,9 @@ const ButtonErrorStyle = styled(Base)`
&:disabled {
opacity: 50%;
cursor: auto;
+ box-shadow: none;
+ background-color: ${({ theme }) => theme.red1};
+ border: 1px solid ${({ theme }) => theme.red1};
}
`
diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx
index 3298d2866a..a61352e7ca 100644
--- a/src/components/Header/index.tsx
+++ b/src/components/Header/index.tsx
@@ -17,6 +17,7 @@ import { useTokenBalanceTreatingWETHasETH } from '../../state/wallet/hooks'
import { ExternalLink, StyledInternalLink } from '../../theme'
import { YellowCard } from '../Card'
import { AutoColumn } from '../Column'
+import Settings from '../Settings'
import Menu from '../Menu'
import Row, { RowBetween } from '../Row'
@@ -31,15 +32,12 @@ const HeaderFrame = styled.div`
width: 100%;
top: 0;
position: absolute;
-
- pointer-events: none;
-
+ z-index: 2;
${({ theme }) => theme.mediaWidth.upToExtraSmall`
padding: 12px 0 0 0;
width: calc(100%);
position: relative;
`};
- z-index: 2;
`
const HeaderElement = styled.div`
@@ -130,6 +128,12 @@ const NETWORK_LABELS: { [chainId in ChainId]: string | null } = {
[ChainId.KOVAN]: 'Kovan'
}
+const BalanceWrapper = styled.div`
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ display: none;
+ `};
+`
+
export default function Header() {
const { account, chainId } = useActiveWeb3React()
@@ -174,16 +178,17 @@ export default function Header() {
{!isMobile && NETWORK_LABELS[chainId] && {NETWORK_LABELS[chainId]}}
- {account && userEthBalance ? (
-
- {userEthBalance?.toSignificant(4)} ETH
-
- ) : null}
+
+ {account && userEthBalance ? (
+
+ {userEthBalance?.toSignificant(4)} ETH
+
+ ) : null}
+
-
-
-
+
+
diff --git a/src/components/Settings/index.tsx b/src/components/Settings/index.tsx
new file mode 100644
index 0000000000..cd9b2f4880
--- /dev/null
+++ b/src/components/Settings/index.tsx
@@ -0,0 +1,253 @@
+import React, { useRef, useEffect, useContext, useState } from 'react'
+import { Settings, X } from 'react-feather'
+import styled from 'styled-components'
+
+import {
+ useUserSlippageTolerance,
+ useExpertModeManager,
+ useUserDeadline,
+ useDarkModeManager
+} from '../../state/user/hooks'
+import SlippageTabs from '../SlippageTabs'
+import { RowFixed, RowBetween } from '../Row'
+import { TYPE } from '../../theme'
+import QuestionHelper from '../QuestionHelper'
+import Toggle from '../Toggle'
+import { ThemeContext } from 'styled-components'
+import { AutoColumn } from '../Column'
+import { ButtonError } from '../Button'
+import { useSettingsMenuOpen, useToggleSettingsMenu } from '../../state/application/hooks'
+import { Text } from 'rebass'
+import Modal from '../Modal'
+
+const StyledMenuIcon = styled(Settings)`
+ height: 20px;
+ width: 20px;
+
+ > * {
+ stroke: ${({ theme }) => theme.text1};
+ }
+`
+
+const StyledCloseIcon = styled(X)`
+ height: 20px;
+ width: 20px;
+ :hover {
+ cursor: pointer;
+ }
+
+ > * {
+ stroke: ${({ theme }) => theme.text1};
+ }
+`
+
+const StyledMenuButton = styled.button`
+ position: relative;
+ width: 100%;
+ height: 100%;
+ border: none;
+ background-color: transparent;
+ margin: 0;
+ padding: 0;
+ height: 35px;
+ background-color: ${({ theme }) => theme.bg3};
+
+ padding: 0.15rem 0.5rem;
+ border-radius: 0.5rem;
+
+ :hover,
+ :focus {
+ cursor: pointer;
+ outline: none;
+ background-color: ${({ theme }) => theme.bg4};
+ }
+
+ svg {
+ margin-top: 2px;
+ }
+`
+const EmojiWrapper = styled.div`
+ position: absolute;
+ bottom: -6px;
+ right: 0px;
+ font-size: 14px;
+`
+
+const StyledMenu = styled.div`
+ margin-left: 0.5rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ border: none;
+ text-align: left;
+`
+
+const MenuFlyout = styled.span`
+ min-width: 20.125rem;
+ background-color: ${({ theme }) => theme.bg1};
+ box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
+ 0px 24px 32px rgba(0, 0, 0, 0.01);
+ border-radius: 0.5rem;
+ display: flex;
+ flex-direction: column;
+ font-size: 1rem;
+ position: absolute;
+ top: 3rem;
+ right: 0rem;
+ z-index: 100;
+
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ min-width: 18.125rem;
+ right: -46px;
+ `};
+`
+
+const Break = styled.div`
+ width: 100%;
+ height: 1px;
+ background-color: ${({ theme }) => theme.bg3};
+`
+
+const ModalContentWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 2rem 0;
+ background-color: ${({ theme }) => theme.bg2};
+ border-radius: 20px;
+`
+
+export default function SettingsTab() {
+ const node = useRef()
+ const open = useSettingsMenuOpen()
+ const toggle = useToggleSettingsMenu()
+
+ const theme = useContext(ThemeContext)
+ const [userSlippageTolerance, setUserslippageTolerance] = useUserSlippageTolerance()
+
+ const [deadline, setDeadline] = useUserDeadline()
+
+ const [expertMode, toggleExpertMode] = useExpertModeManager()
+
+ const [darkMode, toggleDarkMode] = useDarkModeManager()
+
+ // show confirmation view before turning on
+ const [showConfirmation, setShowConfirmation] = useState(false)
+
+ useEffect(() => {
+ const handleClickOutside = e => {
+ if (node.current?.contains(e.target) ?? false) {
+ return
+ }
+ toggle()
+ }
+
+ if (open) {
+ document.addEventListener('mousedown', handleClickOutside)
+ } else {
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+ }, [open, toggle])
+
+ return (
+
+ setShowConfirmation(false)}>
+
+
+
+
+
+ Are you sure?
+
+ setShowConfirmation(false)} />
+
+
+
+
+ Expert mode turns off the confirm transaction prompt and allows high slippage trades that often result
+ in bad rates and lost funds.
+
+
+ ONLY USE THIS MODE IF YOU KNOW WHAT YOU ARE DOING.
+
+ {
+ if (window.prompt(`Please type the word "confirm" to enable expert mode.`) === 'confirm') {
+ toggleExpertMode()
+ setShowConfirmation(false)
+ }
+ }}
+ >
+
+ Turn On Expert Mode
+
+
+
+
+
+
+
+
+ {expertMode && (
+
+
+ 🧙
+
+
+ )}
+
+ {open && (
+
+
+
+ Transaction Settings
+
+
+
+ Interface Settings
+
+
+
+
+ Toggle Expert Mode
+
+
+
+ {
+ toggleExpertMode()
+ setShowConfirmation(false)
+ }
+ : () => setShowConfirmation(true)
+ }
+ />
+
+
+
+
+ Toggle Dark Mode
+
+
+
+
+
+
+ )}
+
+ )
+}
diff --git a/src/components/SlippageTabs/index.tsx b/src/components/SlippageTabs/index.tsx
index e9c159bb91..554a40898d 100644
--- a/src/components/SlippageTabs/index.tsx
+++ b/src/components/SlippageTabs/index.tsx
@@ -78,10 +78,6 @@ const OptionCustom = styled(FancyButton)<{ active?: boolean; warning?: boolean }
}
`
-const SlippageSelector = styled.div`
- padding: 0 20px;
-`
-
export interface SlippageTabsProps {
rawSlippage: number
setRawSlippage: (rawSlippage: number) => void
@@ -146,15 +142,14 @@ export default function SlippageTabs({ rawSlippage, setRawSlippage, deadline, se
}
return (
- <>
-
-
- Set slippage tolerance
-
-
-
-
-
+
+
+
+
+ Slippage tolerance
+
+
+
)}
-
+
-
+
- Deadline
+ Transaction deadline
-
+
- >
+
)
}
diff --git a/src/components/Toggle/index.tsx b/src/components/Toggle/index.tsx
new file mode 100644
index 0000000000..992ffb6e86
--- /dev/null
+++ b/src/components/Toggle/index.tsx
@@ -0,0 +1,41 @@
+import React from 'react'
+import styled from 'styled-components'
+
+const ToggleElement = styled.span<{ isActive?: boolean; isOnSwitch?: boolean }>`
+ padding: 0.25rem 0.5rem;
+ border-radius: 14px;
+ background: ${({ theme, isActive, isOnSwitch }) => (isActive ? (isOnSwitch ? theme.primary1 : theme.text4) : 'none')};
+ color: ${({ theme, isActive, isOnSwitch }) => (isActive ? (isOnSwitch ? theme.white : theme.text2) : theme.text3)};
+ font-size: 0.825rem;
+ font-weight: 400;
+`
+
+const StyledToggle = styled.a<{ isActive?: boolean; activeElement?: boolean }>`
+ border-radius: 16px;
+ border: 1px solid ${({ theme, isActive }) => (isActive ? theme.primary5 : theme.text4)};
+ display: flex;
+ width: fit-content;
+ cursor: pointer;
+ text-decoration: none;
+ :hover {
+ text-decoration: none;
+ }
+`
+
+export interface ToggleProps {
+ isActive: boolean
+ toggle: () => void
+}
+
+export default function Toggle({ isActive, toggle }: ToggleProps) {
+ return (
+
+
+ On
+
+
+ Off
+
+
+ )
+}
diff --git a/src/components/swap/AdvancedSwapDetails.tsx b/src/components/swap/AdvancedSwapDetails.tsx
index 81f74c304f..ef916bea49 100644
--- a/src/components/swap/AdvancedSwapDetails.tsx
+++ b/src/components/swap/AdvancedSwapDetails.tsx
@@ -10,10 +10,10 @@ import { AutoColumn } from '../Column'
import { SectionBreak } from './styleds'
import QuestionHelper from '../QuestionHelper'
import { RowBetween, RowFixed } from '../Row'
-import SlippageTabs, { SlippageTabsProps } from '../SlippageTabs'
import FormattedPriceImpact from './FormattedPriceImpact'
import TokenLogo from '../TokenLogo'
import flatMap from 'lodash.flatmap'
+import { useUserSlippageTolerance } from '../../state/user/hooks'
function TradeSummary({ trade, allowedSlippage }: { trade: Trade; allowedSlippage: number }) {
const theme = useContext(ThemeContext)
@@ -61,20 +61,20 @@ function TradeSummary({ trade, allowedSlippage }: { trade: Trade; allowedSlippag
-
-
>
)
}
-export interface AdvancedSwapDetailsProps extends SlippageTabsProps {
+export interface AdvancedSwapDetailsProps {
trade?: Trade
onDismiss: () => void
}
-export function AdvancedSwapDetails({ trade, onDismiss, ...slippageTabProps }: AdvancedSwapDetailsProps) {
+export function AdvancedSwapDetails({ trade, onDismiss }: AdvancedSwapDetailsProps) {
const theme = useContext(ThemeContext)
+ const [allowedSlippage] = useUserSlippageTolerance()
+
return (
@@ -85,13 +85,9 @@ export function AdvancedSwapDetails({ trade, onDismiss, ...slippageTabProps }: A
-
-
- {trade && }
-
-
-
+ {trade && }
+ {trade?.route?.path?.length > 2 && }
{trade?.route?.path?.length > 2 && (
diff --git a/src/components/swap/PriceSlippageWarningCard.tsx b/src/components/swap/PriceSlippageWarningCard.tsx
deleted file mode 100644
index 1ee5889aee..0000000000
--- a/src/components/swap/PriceSlippageWarningCard.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Percent } from '@uniswap/sdk'
-import React, { useContext } from 'react'
-import { Text } from 'rebass'
-import { ThemeContext } from 'styled-components'
-import { YellowCard } from '../Card'
-import { AutoColumn } from '../Column'
-import { RowBetween, RowFixed } from '../Row'
-
-export function PriceSlippageWarningCard({ priceSlippage }: { priceSlippage: Percent }) {
- const theme = useContext(ThemeContext)
- return (
-
-
-
-
-
- ⚠️
- {' '}
-
- Price Warning
-
-
-
-
- This trade will move the price by ~{priceSlippage.toFixed(2)}%.
-
-
-
- )
-}
diff --git a/src/components/swap/styleds.ts b/src/components/swap/styleds.ts
index 70d0288258..dee886278c 100644
--- a/src/components/swap/styleds.ts
+++ b/src/components/swap/styleds.ts
@@ -45,9 +45,15 @@ export const BottomGrouping = styled.div`
position: relative;
`
-export const ErrorText = styled(Text)<{ severity?: 0 | 1 | 2 | 3 }>`
+export const ErrorText = styled(Text)<{ severity?: 0 | 1 | 2 | 3 | 4 }>`
color: ${({ theme, severity }) =>
- severity === 3 ? theme.red1 : severity === 2 ? theme.yellow2 : severity === 1 ? theme.text1 : theme.green1};
+ severity === 3 || severity === 4
+ ? theme.red1
+ : severity === 2
+ ? theme.yellow2
+ : severity === 1
+ ? theme.text1
+ : theme.green1};
`
export const InputGroup = styled(AutoColumn)`
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 48b548b923..b2e47d7393 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -153,6 +153,8 @@ export const BIPS_BASE = JSBI.BigInt(10000)
export const ALLOWED_PRICE_IMPACT_LOW: Percent = new Percent(JSBI.BigInt(100), BIPS_BASE) // 1%
export const ALLOWED_PRICE_IMPACT_MEDIUM: Percent = new Percent(JSBI.BigInt(500), BIPS_BASE) // 5%
export const ALLOWED_PRICE_IMPACT_HIGH: Percent = new Percent(JSBI.BigInt(1000), BIPS_BASE) // 10%
+// for non expert mode disable swaps above this
+export const BLOCKED_PRICE_IMPACT_NON_EXPERT: Percent = new Percent(JSBI.BigInt(5000), BIPS_BASE) // 50%
// if the price slippage exceeds this number, force the user to type 'confirm' to execute
export const PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN: Percent = new Percent(JSBI.BigInt(2500), BIPS_BASE) // 25%
diff --git a/src/hooks/useSwapCallback.ts b/src/hooks/useSwapCallback.ts
index b68efccf04..e5bbc8b410 100644
--- a/src/hooks/useSwapCallback.ts
+++ b/src/hooks/useSwapCallback.ts
@@ -60,8 +60,8 @@ function getSwapType(trade: Trade | undefined): SwapType | undefined {
// and the user has approved the slippage adjusted input amount for the trade
export function useSwapCallback(
trade?: Trade, // trade to execute, required
- allowedSlippage: number = INITIAL_ALLOWED_SLIPPAGE, // in bips, optional
- deadline: number = DEFAULT_DEADLINE_FROM_NOW, // in seconds from now, optional
+ allowedSlippage: number = INITIAL_ALLOWED_SLIPPAGE, // in bips
+ deadline: number = DEFAULT_DEADLINE_FROM_NOW, // in seconds from now
to?: string // recipient of output, optional
): null | (() => Promise) {
const { account, chainId, library } = useActiveWeb3React()
diff --git a/src/pages/AddLiquidity/index.tsx b/src/pages/AddLiquidity/index.tsx
index 5cbb92021e..064628290e 100644
--- a/src/pages/AddLiquidity/index.tsx
+++ b/src/pages/AddLiquidity/index.tsx
@@ -17,7 +17,7 @@ import Row, { AutoRow, RowBetween, RowFixed, RowFlat } from '../../components/Ro
import TokenLogo from '../../components/TokenLogo'
-import { ROUTER_ADDRESS, MIN_ETH, ONE_BIPS, DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE } from '../../constants'
+import { ROUTER_ADDRESS, MIN_ETH, ONE_BIPS } from '../../constants'
import { useActiveWeb3React } from '../../hooks'
import { useTransactionAdder } from '../../state/transactions/hooks'
@@ -34,7 +34,7 @@ import {
import { Field } from '../../state/mint/actions'
import { useApproveCallback, ApprovalState } from '../../hooks/useApproveCallback'
import { useWalletModalToggle } from '../../state/application/hooks'
-import AdvancedSwapDetailsDropdown from '../../components/swap/AdvancedSwapDetailsDropdown'
+import { useUserSlippageTolerance, useUserDeadline, useIsExpertMode } from '../../state/user/hooks'
export default function AddLiquidity({ match: { params } }: RouteComponentProps<{ tokens: string }>) {
useDefaultsFromURLMatchParams(params)
@@ -45,6 +45,8 @@ export default function AddLiquidity({ match: { params } }: RouteComponentProps<
// toggle wallet when disconnected
const toggleWalletModal = useWalletModalToggle()
+ const expertMode = useIsExpertMode()
+
// mint state
const { independentField, typedValue, otherTypedValue } = useMintState()
const {
@@ -64,14 +66,13 @@ export default function AddLiquidity({ match: { params } }: RouteComponentProps<
const isValid = !error
// modal and loading
- const [showAdvanced, setShowAdvanced] = useState(false) // toggling slippage, deadline, etc. on and off
- const [showConfirm, setShowConfirm] = useState(false) // show confirmation modal
- const [attemptingTxn, setAttemptingTxn] = useState(false) // waiting for user confirmaion/rejection
- const [txHash, setTxHash] = useState('')
+ const [showConfirm, setShowConfirm] = useState(false)
+ const [attemptingTxn, setAttemptingTxn] = useState(false) // clicked confirm
- // tx parameters
- const [deadline, setDeadline] = useState(DEFAULT_DEADLINE_FROM_NOW)
- const [allowedSlippage, setAllowedSlippage] = useState(INITIAL_ALLOWED_SLIPPAGE)
+ // txn values
+ const [deadline] = useUserDeadline() // custom from users settings
+ const [allowedSlippage] = useUserSlippageTolerance() // custom from users
+ const [txHash, setTxHash] = useState('')
// get formatted amounts
const formattedAmounts = {
@@ -427,7 +428,7 @@ export default function AddLiquidity({ match: { params } }: RouteComponentProps<
)}
{
- setShowConfirm(true)
+ expertMode ? onAdd() : setShowConfirm(true)
}}
disabled={!isValid || approvalA !== ApprovalState.APPROVED || approvalB !== ApprovalState.APPROVED}
error={!isValid && !!parsedAmounts[Field.TOKEN_A] && !!parsedAmounts[Field.TOKEN_B]}
@@ -442,17 +443,6 @@ export default function AddLiquidity({ match: { params } }: RouteComponentProps<
- {isValid && !!parsedAmounts[Field.TOKEN_A] && !!parsedAmounts[Field.TOKEN_B] ? (
-
- ) : null}
-
{pair && !noLiquidity ? (
diff --git a/src/pages/RemoveLiquidity/index.tsx b/src/pages/RemoveLiquidity/index.tsx
index 57da1ba2f7..8b0c458fa5 100644
--- a/src/pages/RemoveLiquidity/index.tsx
+++ b/src/pages/RemoveLiquidity/index.tsx
@@ -18,7 +18,7 @@ import Row, { RowBetween, RowFixed } from '../../components/Row'
import Slider from '../../components/Slider'
import TokenLogo from '../../components/TokenLogo'
-import { ROUTER_ADDRESS, DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE } from '../../constants'
+import { ROUTER_ADDRESS } from '../../constants'
import { useActiveWeb3React } from '../../hooks'
import { usePairContract } from '../../hooks/useContract'
@@ -31,9 +31,9 @@ import { useApproveCallback, ApprovalState } from '../../hooks/useApproveCallbac
import { Dots } from '../../components/swap/styleds'
import { useDefaultsFromURLMatchParams, useBurnActionHandlers } from '../../state/burn/hooks'
import { useDerivedBurnInfo, useBurnState } from '../../state/burn/hooks'
-import AdvancedSwapDetailsDropdown from '../../components/swap/AdvancedSwapDetailsDropdown'
import { Field } from '../../state/burn/actions'
import { useWalletModalToggle } from '../../state/application/hooks'
+import { useUserDeadline, useUserSlippageTolerance } from '../../state/user/hooks'
import { BigNumber } from '@ethersproject/bignumber'
export default function RemoveLiquidity({ match: { params } }: RouteComponentProps<{ tokens: string }>) {
@@ -52,15 +52,14 @@ export default function RemoveLiquidity({ match: { params } }: RouteComponentPro
const isValid = !error
// modal and loading
- const [showDetailed, setShowDetailed] = useState(false) // toggling detailed view
- const [showAdvanced, setShowAdvanced] = useState(false) // toggling slippage, deadline, etc. on and off
- const [showConfirm, setShowConfirm] = useState(false) // show confirmation modal
- const [attemptingTxn, setAttemptingTxn] = useState(false) // waiting for user confirmaion/rejection
- const [txHash, setTxHash] = useState('')
+ const [showConfirm, setShowConfirm] = useState(false)
+ const [showDetailed, setShowDetailed] = useState(false)
+ const [attemptingTxn, setAttemptingTxn] = useState(false) // clicked confirm
- // tx parameters
- const [deadline, setDeadline] = useState(DEFAULT_DEADLINE_FROM_NOW)
- const [allowedSlippage, setAllowedSlippage] = useState(INITIAL_ALLOWED_SLIPPAGE)
+ // txn values
+ const [txHash, setTxHash] = useState('')
+ const [deadline] = useUserDeadline()
+ const [allowedSlippage] = useUserSlippageTolerance()
const formattedAmounts = {
[Field.LIQUIDITY_PERCENT]: parsedAmounts[Field.LIQUIDITY_PERCENT].equalTo('0')
@@ -592,17 +591,6 @@ export default function RemoveLiquidity({ match: { params } }: RouteComponentPro
- {isValid ? (
-
- ) : null}
-
{pair ? (
diff --git a/src/pages/Send/index.tsx b/src/pages/Send/index.tsx
index e73352e449..56aada6c53 100644
--- a/src/pages/Send/index.tsx
+++ b/src/pages/Send/index.tsx
@@ -22,19 +22,14 @@ import { TransferModalHeader } from '../../components/swap/TransferModalHeader'
import BetterTradeLink from '../../components/swap/BetterTradeLink'
import TokenLogo from '../../components/TokenLogo'
import { TokenWarningCards } from '../../components/TokenWarningCard'
-import {
- DEFAULT_DEADLINE_FROM_NOW,
- INITIAL_ALLOWED_SLIPPAGE,
- MIN_ETH,
- BETTER_TRADE_LINK_THRESHOLD
-} from '../../constants'
+import { INITIAL_ALLOWED_SLIPPAGE, MIN_ETH, BETTER_TRADE_LINK_THRESHOLD } from '../../constants'
import { getTradeVersion, isTradeBetter } from '../../data/V1'
import { useActiveWeb3React } from '../../hooks'
import { useApproveCallbackFromTrade, ApprovalState } from '../../hooks/useApproveCallback'
import { useSendCallback } from '../../hooks/useSendCallback'
import { useSwapCallback } from '../../hooks/useSwapCallback'
+import { useWalletModalToggle, useToggleSettingsMenu } from '../../state/application/hooks'
import useToggledVersion, { Version } from '../../hooks/useToggledVersion'
-import { useWalletModalToggle } from '../../state/application/hooks'
import { Field } from '../../state/swap/actions'
import {
useDefaultsFromURLSearch,
@@ -46,7 +41,8 @@ import { useAllTokenBalancesTreatingWETHasETH } from '../../state/wallet/hooks'
import { CursorPointer, TYPE } from '../../theme'
import { computeSlippageAdjustedAmounts, computeTradePriceBreakdown, warningSeverity } from '../../utils/prices'
import AppBody from '../AppBody'
-import { PriceSlippageWarningCard } from '../../components/swap/PriceSlippageWarningCard'
+import { useUserSlippageTolerance, useUserDeadline, useExpertModeManager } from '../../state/user/hooks'
+import { ClickableText } from '../Pool/styleds'
export default function Send() {
useDefaultsFromURLSearch()
@@ -59,6 +55,10 @@ export default function Send() {
// toggle wallet when disconnected
const toggleWalletModal = useWalletModalToggle()
+ // for expert mode
+ const toggleSettings = useToggleSettingsMenu()
+ const [expertMode] = useExpertModeManager()
+
// sending state
const [sendingWithSwap, setSendingWithSwap] = useState(false)
const [recipient, setRecipient] = useState('')
@@ -102,10 +102,8 @@ export default function Send() {
const [showConfirm, setShowConfirm] = useState(false) // show confirmation modal
const [attemptingTxn, setAttemptingTxn] = useState(false) // waiting for user confirmaion/rejection
const [txHash, setTxHash] = useState('')
-
- // tx parameters
- const [deadline, setDeadline] = useState(DEFAULT_DEADLINE_FROM_NOW)
- const [allowedSlippage, setAllowedSlippage] = useState(INITIAL_ALLOWED_SLIPPAGE)
+ const [deadline] = useUserDeadline() // custom from user settings
+ const [allowedSlippage] = useUserSlippageTolerance() // custom from user settings
const route = bestTrade?.route
const userHasSpecifiedInputOutput =
@@ -223,7 +221,8 @@ export default function Send() {
((sendingWithSwap && isSwapValid) || (!sendingWithSwap && isSendValid)) &&
(approval === ApprovalState.NOT_APPROVED ||
approval === ApprovalState.PENDING ||
- (approvalSubmitted && approval === ApprovalState.APPROVED))
+ (approvalSubmitted && approval === ApprovalState.APPROVED)) &&
+ !(severity > 3 && !expertMode)
function modalHeader() {
if (!sendingWithSwap) {
@@ -487,6 +486,20 @@ export default function Send() {
+ {allowedSlippage !== INITIAL_ALLOWED_SLIPPAGE && (
+
+
+
+ Slippage Tolerance
+
+
+
+
+ {allowedSlippage ? allowedSlippage / 100 : '-'}%
+
+
+
+ )}
{bestTrade && severity > 1 && (
{
- setShowConfirm(true)
+ expertMode ? (sendingWithSwap ? onSwap() : onSend()) : setShowConfirm(true)
}}
width="48%"
id="send-button"
@@ -544,23 +557,28 @@ export default function Send() {
error={sendingWithSwap && isSwapValid && severity > 2}
>
- {`Send${severity > 2 ? ' Anyway' : ''}`}
+ {severity > 3 && !expertMode ? `Price Impact High` : `Send${severity > 2 ? ' Anyway' : ''}`}
) : (
{
- setShowConfirm(true)
+ expertMode ? (sendingWithSwap ? onSwap() : onSend()) : setShowConfirm(true)
}}
id="send-button"
- disabled={(sendingWithSwap && !isSwapValid) || (!sendingWithSwap && !isSendValid)}
+ disabled={
+ (sendingWithSwap && !isSwapValid) ||
+ (!sendingWithSwap && !isSendValid) ||
+ (severity > 3 && !expertMode && sendingWithSwap)
+ }
error={sendingWithSwap && isSwapValid && severity > 2}
>
{(sendingWithSwap ? swapError : null) ||
sendAmountError ||
recipientError ||
+ (severity > 3 && !expertMode && `Price Impact Too High`) ||
`Send${severity > 2 ? ' Anyway' : ''}`}
@@ -571,21 +589,7 @@ export default function Send() {
{bestTrade && (
-
- )}
-
- {priceImpactWithoutFee && severity > 2 && (
-
-
-
+
)}
>
)
diff --git a/src/pages/Swap/index.tsx b/src/pages/Swap/index.tsx
index 9f329f67b8..17f67efea2 100644
--- a/src/pages/Swap/index.tsx
+++ b/src/pages/Swap/index.tsx
@@ -20,18 +20,15 @@ import SwapModalHeader from '../../components/swap/SwapModalHeader'
import TradePrice from '../../components/swap/TradePrice'
import BetterTradeLink from '../../components/swap/BetterTradeLink'
import { TokenWarningCards } from '../../components/TokenWarningCard'
-import {
- DEFAULT_DEADLINE_FROM_NOW,
- INITIAL_ALLOWED_SLIPPAGE,
- MIN_ETH,
- BETTER_TRADE_LINK_THRESHOLD
-} from '../../constants'
-import { getTradeVersion, isTradeBetter } from '../../data/V1'
import { useActiveWeb3React } from '../../hooks'
import { useApproveCallbackFromTrade, ApprovalState } from '../../hooks/useApproveCallback'
import { useSwapCallback } from '../../hooks/useSwapCallback'
+import { useWalletModalToggle, useToggleSettingsMenu } from '../../state/application/hooks'
+import { useExpertModeManager, useUserSlippageTolerance, useUserDeadline } from '../../state/user/hooks'
+
+import { INITIAL_ALLOWED_SLIPPAGE, MIN_ETH, BETTER_TRADE_LINK_THRESHOLD } from '../../constants'
+import { getTradeVersion, isTradeBetter } from '../../data/V1'
import useToggledVersion, { Version } from '../../hooks/useToggledVersion'
-import { useWalletModalToggle } from '../../state/application/hooks'
import { Field } from '../../state/swap/actions'
import {
useDefaultsFromURLSearch,
@@ -42,7 +39,7 @@ import {
import { CursorPointer, TYPE } from '../../theme'
import { computeSlippageAdjustedAmounts, computeTradePriceBreakdown, warningSeverity } from '../../utils/prices'
import AppBody from '../AppBody'
-import { PriceSlippageWarningCard } from '../../components/swap/PriceSlippageWarningCard'
+import { ClickableText } from '../Pool/styleds'
export default function Swap() {
useDefaultsFromURLSearch()
@@ -53,6 +50,14 @@ export default function Swap() {
// toggle wallet when disconnected
const toggleWalletModal = useWalletModalToggle()
+ // for expert mode
+ const toggleSettings = useToggleSettingsMenu()
+ const [expertMode] = useExpertModeManager()
+
+ // get custom setting values for user
+ const [deadline] = useUserDeadline()
+ const [allowedSlippage] = useUserSlippageTolerance()
+
// swap state
const { independentField, typedValue } = useSwapState()
const { bestTrade: bestTradeV2, tokenBalances, parsedAmount, tokens, error, v1Trade } = useDerivedSwapInfo()
@@ -84,10 +89,6 @@ export default function Swap() {
const [attemptingTxn, setAttemptingTxn] = useState(false) // waiting for user confirmaion/rejection
const [txHash, setTxHash] = useState('')
- // tx parameters
- const [deadline, setDeadline] = useState(DEFAULT_DEADLINE_FROM_NOW)
- const [allowedSlippage, setAllowedSlippage] = useState(INITIAL_ALLOWED_SLIPPAGE)
-
const formattedAmounts = {
[independentField]: typedValue,
[dependentField]: parsedAmounts[dependentField] ? parsedAmounts[dependentField].toSignificant(6) : ''
@@ -107,13 +108,6 @@ export default function Swap() {
// check if user has gone through approval process, used to show two step buttons, reset on token change
const [approvalSubmitted, setApprovalSubmitted] = useState(false)
- // show approve flow when: no error on inputs, not approved or pending, or approved in current session
- const showApproveFlow =
- !error &&
- (approval === ApprovalState.NOT_APPROVED ||
- approval === ApprovalState.PENDING ||
- (approvalSubmitted && approval === ApprovalState.APPROVED))
-
// mark when a user has submitted an approval, reset onTokenSelection for input field
useEffect(() => {
if (approval === ApprovalState.PENDING) {
@@ -146,7 +140,6 @@ export default function Swap() {
if (priceImpactWithoutFee && !confirmPriceImpactWithoutFee(priceImpactWithoutFee)) {
return
}
-
setAttemptingTxn(true)
swapCallback()
.then(hash => {
@@ -178,6 +171,15 @@ export default function Swap() {
// warnings on slippage
const priceImpactSeverity = warningSeverity(priceImpactWithoutFee)
+ // show approve flow when: no error on inputs, not approved or pending, or approved in current session
+ // never show if price impact is above threshold in non expert mode
+ const showApproveFlow =
+ !error &&
+ (approval === ApprovalState.NOT_APPROVED ||
+ approval === ApprovalState.PENDING ||
+ (approvalSubmitted && approval === ApprovalState.APPROVED)) &&
+ !(priceImpactSeverity > 3 && !expertMode)
+
function modalHeader() {
return (
+ {allowedSlippage !== INITIAL_ALLOWED_SLIPPAGE && (
+
+
+ Slippage Tolerance
+
+
+ {allowedSlippage ? allowedSlippage / 100 : '-'}%
+
+
+ )}
+
{bestTrade && priceImpactSeverity > 1 && (
{
- setShowConfirm(true)
+ expertMode ? onSwap() : setShowConfirm(true)
}}
width="48%"
id="swap-button"
- disabled={!isValid || approval !== ApprovalState.APPROVED}
+ disabled={!isValid || approval !== ApprovalState.APPROVED || (priceImpactSeverity > 3 && !expertMode)}
error={isValid && priceImpactSeverity > 2}
>
- {`Swap${priceImpactSeverity > 2 ? ' Anyway' : ''}`}
+ {priceImpactSeverity > 3 && !expertMode
+ ? `Price Impact High`
+ : `Swap${priceImpactSeverity > 2 ? ' Anyway' : ''}`}
) : (
{
- setShowConfirm(true)
+ expertMode ? onSwap() : setShowConfirm(true)
}}
id="swap-button"
- disabled={!isValid}
+ disabled={!isValid || (priceImpactSeverity > 3 && !expertMode)}
error={isValid && priceImpactSeverity > 2}
>
- {error ?? `Swap${priceImpactSeverity > 2 ? ' Anyway' : ''}`}
+ {error
+ ? error
+ : priceImpactSeverity > 3 && !expertMode
+ ? `Price Impact Too High`
+ : `Swap${priceImpactSeverity > 2 ? ' Anyway' : ''}`}
)}
@@ -367,21 +386,7 @@ export default function Swap() {
{bestTrade && (
-
- )}
-
- {priceImpactWithoutFee && priceImpactSeverity > 2 && (
-
-
-
+
)}
>
)
diff --git a/src/state/application/actions.ts b/src/state/application/actions.ts
index 140eb25279..c098b015c6 100644
--- a/src/state/application/actions.ts
+++ b/src/state/application/actions.ts
@@ -23,5 +23,6 @@ export type PopupContent =
export const updateBlockNumber = createAction<{ chainId: number; blockNumber: number }>('updateBlockNumber')
export const toggleWalletModal = createAction('toggleWalletModal')
+export const toggleSettingsMenu = createAction('toggleSettingsMenu')
export const addPopup = createAction<{ key?: string; content: PopupContent }>('addPopup')
export const removePopup = createAction<{ key: string }>('removePopup')
diff --git a/src/state/application/hooks.ts b/src/state/application/hooks.ts
index 4caf1f90fd..b996d2c57a 100644
--- a/src/state/application/hooks.ts
+++ b/src/state/application/hooks.ts
@@ -1,6 +1,6 @@
import { useCallback, useMemo } from 'react'
import { useActiveWeb3React } from '../../hooks'
-import { addPopup, PopupContent, removePopup, toggleWalletModal } from './actions'
+import { addPopup, PopupContent, removePopup, toggleWalletModal, toggleSettingsMenu } from './actions'
import { useSelector, useDispatch } from 'react-redux'
import { AppState } from '../index'
@@ -19,6 +19,15 @@ export function useWalletModalToggle(): () => void {
return useCallback(() => dispatch(toggleWalletModal()), [dispatch])
}
+export function useSettingsMenuOpen(): boolean {
+ return useSelector((state: AppState) => state.application.settingsMenuOpen)
+}
+
+export function useToggleSettingsMenu(): () => void {
+ const dispatch = useDispatch()
+ return useCallback(() => dispatch(toggleSettingsMenu()), [dispatch])
+}
+
// returns a function that allows adding a popup
export function useAddPopup(): (content: PopupContent, key?: string) => void {
const dispatch = useDispatch()
diff --git a/src/state/application/reducer.ts b/src/state/application/reducer.ts
index b15fde46d1..203243d908 100644
--- a/src/state/application/reducer.ts
+++ b/src/state/application/reducer.ts
@@ -1,5 +1,12 @@
import { createReducer, nanoid } from '@reduxjs/toolkit'
-import { addPopup, PopupContent, removePopup, toggleWalletModal, updateBlockNumber } from './actions'
+import {
+ addPopup,
+ PopupContent,
+ removePopup,
+ toggleWalletModal,
+ toggleSettingsMenu,
+ updateBlockNumber
+} from './actions'
type PopupList = Array<{ key: string; show: boolean; content: PopupContent }>
@@ -7,12 +14,14 @@ interface ApplicationState {
blockNumber: { [chainId: number]: number }
popupList: PopupList
walletModalOpen: boolean
+ settingsMenuOpen: boolean
}
const initialState: ApplicationState = {
blockNumber: {},
popupList: [],
- walletModalOpen: false
+ walletModalOpen: false,
+ settingsMenuOpen: false
}
export default createReducer(initialState, builder =>
@@ -28,6 +37,9 @@ export default createReducer(initialState, builder =>
.addCase(toggleWalletModal, state => {
state.walletModalOpen = !state.walletModalOpen
})
+ .addCase(toggleSettingsMenu, state => {
+ state.settingsMenuOpen = !state.settingsMenuOpen
+ })
.addCase(addPopup, (state, { payload: { content, key } }) => {
if (key && state.popupList.some(popup => popup.key === key)) return
state.popupList.push({
diff --git a/src/state/swap/hooks.ts b/src/state/swap/hooks.ts
index 86f5113943..57d7fe93a9 100644
--- a/src/state/swap/hooks.ts
+++ b/src/state/swap/hooks.ts
@@ -1,3 +1,4 @@
+import { Version } from './../../hooks/useToggledVersion'
import { parseUnits } from '@ethersproject/units'
import { ChainId, JSBI, Token, TokenAmount, Trade, WETH } from '@uniswap/sdk'
import { ParsedQs } from 'qs'
@@ -13,6 +14,9 @@ import { AppDispatch, AppState } from '../index'
import { useTokenBalancesTreatWETHAsETH } from '../wallet/hooks'
import { Field, replaceSwapState, selectToken, switchTokens, typeInput } from './actions'
import { SwapState } from './reducer'
+import useToggledVersion from '../../hooks/useToggledVersion'
+import { useUserSlippageTolerance } from '../user/hooks'
+import { computeSlippageAdjustedAmounts } from '../../utils/prices'
export function useSwapState(): AppState['swap'] {
return useSelector(state => state.swap)
@@ -83,6 +87,8 @@ export function useDerivedSwapInfo(): {
} {
const { account } = useActiveWeb3React()
+ const toggledVersion = useToggledVersion()
+
const {
independentField,
typedValue,
@@ -132,12 +138,29 @@ export function useDerivedSwapInfo(): {
error = error ?? 'Select a token'
}
- // this check is incorrect, it should check against the maximum amount in
- // rather than the estimated amount in
- // const [balanceIn, amountIn] = [tokenBalances[Field.INPUT], parsedAmounts[Field.INPUT]]
- // if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) {
- // error = 'Insufficient ' + amountIn.token.symbol + ' balance'
- // }
+ const [allowedSlippage] = useUserSlippageTolerance()
+
+ const slippageAdjustedAmounts =
+ bestTrade && allowedSlippage && computeSlippageAdjustedAmounts(bestTrade, allowedSlippage)
+
+ const slippageAdjustedAmountsV1 =
+ v1Trade && allowedSlippage && computeSlippageAdjustedAmounts(v1Trade, allowedSlippage)
+
+ // compare input balance to MAx input based on version
+ const [balanceIn, amountIn] = [
+ tokenBalances[Field.INPUT],
+ toggledVersion === Version.v1
+ ? slippageAdjustedAmountsV1
+ ? slippageAdjustedAmountsV1[Field.INPUT]
+ : null
+ : slippageAdjustedAmounts
+ ? slippageAdjustedAmounts[Field.INPUT]
+ : null
+ ]
+
+ if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) {
+ error = 'Insufficient ' + amountIn.token.symbol + ' balance'
+ }
return {
tokens,
diff --git a/src/state/user/actions.ts b/src/state/user/actions.ts
index 30d87ef374..2765408d61 100644
--- a/src/state/user/actions.ts
+++ b/src/state/user/actions.ts
@@ -16,6 +16,11 @@ export interface SerializedPair {
export const updateVersion = createAction('updateVersion')
export const updateMatchesDarkMode = createAction<{ matchesDarkMode: boolean }>('updateMatchesDarkMode')
export const updateUserDarkMode = createAction<{ userDarkMode: boolean }>('updateUserDarkMode')
+export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('updateUserExpertMode')
+export const updateUserSlippageTolerance = createAction<{ userSlippageTolerance: number }>(
+ 'updateUserSlippageTolerance'
+)
+export const updateUserDeadline = createAction<{ userDeadline: number }>('updateUserDeadline')
export const addSerializedToken = createAction<{ serializedToken: SerializedToken }>('addSerializedToken')
export const removeSerializedToken = createAction<{ chainId: number; address: string }>('removeSerializedToken')
export const addSerializedPair = createAction<{ serializedPair: SerializedPair }>('addSerializedPair')
diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx
index 08477662a3..82ae18d323 100644
--- a/src/state/user/hooks.tsx
+++ b/src/state/user/hooks.tsx
@@ -13,7 +13,10 @@ import {
removeSerializedToken,
SerializedPair,
SerializedToken,
- updateUserDarkMode
+ updateUserDarkMode,
+ updateUserExpertMode,
+ updateUserSlippageTolerance,
+ updateUserDeadline
} from './actions'
import { BASES_TO_TRACK_LIQUIDITY_FOR, DUMMY_PAIRS_TO_PIN } from '../../constants'
@@ -63,6 +66,54 @@ export function useDarkModeManager(): [boolean, () => void] {
return [darkMode, toggleSetDarkMode]
}
+export function useIsExpertMode(): boolean {
+ const userExpertMode = useSelector(state => state.user.userExpertMode)
+ return userExpertMode
+}
+
+export function useExpertModeManager(): [boolean, () => void] {
+ const dispatch = useDispatch()
+ const expertMode = useIsExpertMode()
+
+ const toggleSetExpertMode = useCallback(() => {
+ dispatch(updateUserExpertMode({ userExpertMode: !expertMode }))
+ }, [expertMode, dispatch])
+
+ return [expertMode, toggleSetExpertMode]
+}
+
+export function useUserSlippageTolerance(): [number, (slippage: number) => void] {
+ const dispatch = useDispatch()
+ const userSlippageTolerance = useSelector(state => {
+ return state.user.userSlippageTolerance
+ })
+
+ const setUserSlippageTolerance = useCallback(
+ (userSlippageTolerance: number) => {
+ dispatch(updateUserSlippageTolerance({ userSlippageTolerance }))
+ },
+ [dispatch]
+ )
+
+ return [userSlippageTolerance, setUserSlippageTolerance]
+}
+
+export function useUserDeadline(): [number, (slippage: number) => void] {
+ const dispatch = useDispatch()
+ const userDeadline = useSelector(state => {
+ return state.user.userDeadline
+ })
+
+ const setUserDeadline = useCallback(
+ (userDeadline: number) => {
+ dispatch(updateUserDeadline({ userDeadline }))
+ },
+ [dispatch]
+ )
+
+ return [userDeadline, setUserDeadline]
+}
+
export function useAddUserToken(): (token: Token) => void {
const dispatch = useDispatch()
return useCallback(
diff --git a/src/state/user/reducer.ts b/src/state/user/reducer.ts
index 5d34848e2a..a1adef6c50 100644
--- a/src/state/user/reducer.ts
+++ b/src/state/user/reducer.ts
@@ -1,5 +1,5 @@
+import { INITIAL_ALLOWED_SLIPPAGE, DEFAULT_DEADLINE_FROM_NOW } from './../../constants/index'
import { createReducer } from '@reduxjs/toolkit'
-import { ChainId, WETH } from '@uniswap/sdk'
import {
addSerializedPair,
addSerializedToken,
@@ -10,7 +10,10 @@ import {
SerializedToken,
updateMatchesDarkMode,
updateUserDarkMode,
- updateVersion
+ updateVersion,
+ updateUserExpertMode,
+ updateUserSlippageTolerance,
+ updateUserDeadline
} from './actions'
const currentTimestamp = () => new Date().getTime()
@@ -21,6 +24,14 @@ interface UserState {
userDarkMode: boolean | null // the user's choice for dark mode or light mode
matchesDarkMode: boolean // whether the dark mode media query matches
+ userExpertMode: boolean
+
+ // user defined slippage tolerance in bips, used in all txns
+ userSlippageTolerance: number
+
+ // deadline set by user in minutes, used in all txns
+ userDeadline: number
+
tokens: {
[chainId: number]: {
[address: string]: SerializedToken
@@ -50,13 +61,13 @@ function pairKey(token0Address: string, token1Address: string) {
const initialState: UserState = {
lastVersion: '',
-
userDarkMode: null,
matchesDarkMode: false,
-
+ userExpertMode: false,
+ userSlippageTolerance: INITIAL_ALLOWED_SLIPPAGE,
+ userDeadline: DEFAULT_DEADLINE_FROM_NOW,
tokens: {},
pairs: {},
-
timestamp: currentTimestamp()
}
@@ -68,12 +79,14 @@ export default createReducer(initialState, builder =>
if (GIT_COMMIT_HASH && state.lastVersion !== GIT_COMMIT_HASH) {
state.lastVersion = GIT_COMMIT_HASH
- // Wed May 20, 2020 @ ~9pm central
- if (state.timestamp < 1590027589111) {
- // this should remove the user added token from 'eth' for mainnet
- if (state.tokens[ChainId.MAINNET]) {
- delete state.tokens[ChainId.MAINNET][WETH[ChainId.MAINNET].address]
- }
+ // slippage isnt being tracked in local storage, reset to default
+ if (typeof state.userSlippageTolerance !== 'number') {
+ state.userSlippageTolerance = INITIAL_ALLOWED_SLIPPAGE
+ }
+
+ // deadline isnt being tracked in local storage, reset to default
+ if (typeof state.userDeadline !== 'number') {
+ state.userDeadline = DEFAULT_DEADLINE_FROM_NOW
}
}
state.timestamp = currentTimestamp()
@@ -86,6 +99,18 @@ export default createReducer(initialState, builder =>
state.matchesDarkMode = action.payload.matchesDarkMode
state.timestamp = currentTimestamp()
})
+ .addCase(updateUserExpertMode, (state, action) => {
+ state.userExpertMode = action.payload.userExpertMode
+ state.timestamp = currentTimestamp()
+ })
+ .addCase(updateUserSlippageTolerance, (state, action) => {
+ state.userSlippageTolerance = action.payload.userSlippageTolerance
+ state.timestamp = currentTimestamp()
+ })
+ .addCase(updateUserDeadline, (state, action) => {
+ state.userDeadline = action.payload.userDeadline
+ state.timestamp = currentTimestamp()
+ })
.addCase(addSerializedToken, (state, { payload: { serializedToken } }) => {
state.tokens[serializedToken.chainId] = state.tokens[serializedToken.chainId] || {}
state.tokens[serializedToken.chainId][serializedToken.address] = serializedToken
diff --git a/src/utils/prices.ts b/src/utils/prices.ts
index 524179caa5..0431d6dfd1 100644
--- a/src/utils/prices.ts
+++ b/src/utils/prices.ts
@@ -1,3 +1,4 @@
+import { BLOCKED_PRICE_IMPACT_NON_EXPERT } from './../constants/index'
import { Fraction, JSBI, Percent, TokenAmount, Trade } from '@uniswap/sdk'
import { ALLOWED_PRICE_IMPACT_HIGH, ALLOWED_PRICE_IMPACT_LOW, ALLOWED_PRICE_IMPACT_MEDIUM } from '../constants'
import { Field } from '../state/swap/actions'
@@ -51,7 +52,8 @@ export function computeSlippageAdjustedAmounts(
}
}
-export function warningSeverity(priceImpact: Percent): 0 | 1 | 2 | 3 {
+export function warningSeverity(priceImpact: Percent): 0 | 1 | 2 | 3 | 4 {
+ if (!priceImpact?.lessThan(BLOCKED_PRICE_IMPACT_NON_EXPERT)) return 4
if (!priceImpact?.lessThan(ALLOWED_PRICE_IMPACT_HIGH)) return 3
if (!priceImpact?.lessThan(ALLOWED_PRICE_IMPACT_MEDIUM)) return 2
if (!priceImpact?.lessThan(ALLOWED_PRICE_IMPACT_LOW)) return 1