Commit 72936322 authored by Jack Short's avatar Jack Short Committed by GitHub

feat: adding price impact modal (#6681)

parent 1bc6eb9a
...@@ -391,6 +391,7 @@ export enum ButtonEmphasis { ...@@ -391,6 +391,7 @@ export enum ButtonEmphasis {
low, low,
warning, warning,
destructive, destructive,
failure,
} }
interface BaseThemeButtonProps { interface BaseThemeButtonProps {
size: ButtonSize size: ButtonSize
...@@ -411,6 +412,8 @@ function pickThemeButtonBackgroundColor({ theme, emphasis }: { theme: DefaultThe ...@@ -411,6 +412,8 @@ function pickThemeButtonBackgroundColor({ theme, emphasis }: { theme: DefaultThe
return theme.accentWarningSoft return theme.accentWarningSoft
case ButtonEmphasis.destructive: case ButtonEmphasis.destructive:
return theme.accentCritical return theme.accentCritical
case ButtonEmphasis.failure:
return theme.accentFailureSoft
case ButtonEmphasis.medium: case ButtonEmphasis.medium:
default: default:
return theme.backgroundInteractive return theme.backgroundInteractive
...@@ -465,6 +468,8 @@ function pickThemeButtonTextColor({ theme, emphasis }: { theme: DefaultTheme; em ...@@ -465,6 +468,8 @@ function pickThemeButtonTextColor({ theme, emphasis }: { theme: DefaultTheme; em
return theme.accentWarning return theme.accentWarning
case ButtonEmphasis.destructive: case ButtonEmphasis.destructive:
return theme.accentTextDarkPrimary return theme.accentTextDarkPrimary
case ButtonEmphasis.failure:
return theme.accentFailure
case ButtonEmphasis.medium: case ButtonEmphasis.medium:
default: default:
return theme.textPrimary return theme.textPrimary
......
import { Trans } from '@lingui/macro'
import { formatPriceImpact } from '@uniswap/conedison/format'
import { Percent } from '@uniswap/sdk-core'
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
import { ColumnCenter } from 'components/Column'
import Row from 'components/Row'
import { AlertTriangle } from 'react-feather'
import styled from 'styled-components/macro'
import { CloseIcon, ThemedText } from 'theme'
import Modal from '../Modal'
const Wrapper = styled(ColumnCenter)`
padding: 16px 24px;
`
const IconContainer = styled.div`
padding: 32px 0px;
`
const WarningIcon = styled(AlertTriangle)`
color: ${({ theme }) => theme.accentCritical};
`
const ButtonContainer = styled(ColumnCenter)`
padding: 12px 0px 0px;
`
const StyledThemeButton = styled(ThemeButton)`
width: 100%;
`
interface PriceImpactModalProps {
priceImpact: Percent
onDismiss: () => void
onContinue: () => void
}
export default function PriceImpactModal({ priceImpact, onDismiss, onContinue }: PriceImpactModalProps) {
return (
<Modal isOpen onDismiss={onDismiss}>
<Wrapper gap="md">
<Row padding="8px 0px 4px">
<CloseIcon size={24} onClick={onDismiss} />
</Row>
<IconContainer>
<WarningIcon size={48} />
</IconContainer>
<ColumnCenter gap="sm">
<ThemedText.HeadlineSmall fontWeight={500}>
<Trans>Warning</Trans>
</ThemedText.HeadlineSmall>
<ThemedText.BodyPrimary lineHeight="24px" textAlign="center">
<Trans>
This transaction will result in a{' '}
<ThemedText.BodyPrimary lineHeight="24px" color="accentFailure" display="inline">
{formatPriceImpact(priceImpact)}
</ThemedText.BodyPrimary>{' '}
price impact on the market price of this pool. Do you wish to continue?
</Trans>
</ThemedText.BodyPrimary>
</ColumnCenter>
<ButtonContainer gap="md">
<StyledThemeButton size={ButtonSize.large} emphasis={ButtonEmphasis.failure} onClick={onContinue}>
<Trans>Continue</Trans>
</StyledThemeButton>
<StyledThemeButton size={ButtonSize.medium} emphasis={ButtonEmphasis.low} onClick={onDismiss}>
<Trans>Cancel</Trans>
</StyledThemeButton>
</ButtonContainer>
</Wrapper>
</Modal>
)
}
...@@ -39,7 +39,7 @@ export default function PriceImpactWarning({ priceImpact }: PriceImpactWarningPr ...@@ -39,7 +39,7 @@ export default function PriceImpactWarning({ priceImpact }: PriceImpactWarningPr
<Trans>Price impact warning</Trans> <Trans>Price impact warning</Trans>
</ThemedText.DeprecatedSubHeader> </ThemedText.DeprecatedSubHeader>
</RowFixed> </RowFixed>
<ThemedText.DeprecatedLabel textAlign="right" fontSize={14} color={theme.accentFailure}> <ThemedText.DeprecatedLabel textAlign="right" fontSize={14} color="accentFailure">
{formatPriceImpact(priceImpact)} {formatPriceImpact(priceImpact)}
</ThemedText.DeprecatedLabel> </ThemedText.DeprecatedLabel>
</RowBetween> </RowBetween>
......
...@@ -15,6 +15,7 @@ import { useWeb3React } from '@web3-react/core' ...@@ -15,6 +15,7 @@ import { useWeb3React } from '@web3-react/core'
import { useToggleAccountDrawer } from 'components/AccountDrawer' import { useToggleAccountDrawer } from 'components/AccountDrawer'
import { sendEvent } from 'components/analytics' import { sendEvent } from 'components/analytics'
import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert' import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
import PriceImpactModal from 'components/swap/PriceImpactModal'
import PriceImpactWarning from 'components/swap/PriceImpactWarning' import PriceImpactWarning from 'components/swap/PriceImpactWarning'
import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown' import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown'
import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal' import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal'
...@@ -190,6 +191,8 @@ export function Swap({ ...@@ -190,6 +191,8 @@ export function Swap({
}, [prefilledInputCurrency, prefilledOutputCurrency]) }, [prefilledInputCurrency, prefilledOutputCurrency])
const [dismissTokenWarning, setDismissTokenWarning] = useState<boolean>(false) const [dismissTokenWarning, setDismissTokenWarning] = useState<boolean>(false)
const [showPriceImpactModal, setShowPriceImpactModal] = useState<boolean>(false)
const urlLoadedTokens: Token[] = useMemo( const urlLoadedTokens: Token[] = useMemo(
() => [loadedInputCurrency, loadedOutputCurrency]?.filter((c): c is Token => c?.isToken ?? false) ?? [], () => [loadedInputCurrency, loadedOutputCurrency]?.filter((c): c is Token => c?.isToken ?? false) ?? [],
[loadedInputCurrency, loadedOutputCurrency] [loadedInputCurrency, loadedOutputCurrency]
...@@ -390,6 +393,15 @@ export function Swap({ ...@@ -390,6 +393,15 @@ export function Swap({
allowance.state === AllowanceState.ALLOWED ? allowance.permitSignature : undefined allowance.state === AllowanceState.ALLOWED ? allowance.permitSignature : undefined
) )
const handleContinueToReview = useCallback(() => {
setSwapState({
tradeToConfirm: trade,
swapError: undefined,
showConfirm: true,
txHash: undefined,
})
}, [trade])
const handleSwap = useCallback(() => { const handleSwap = useCallback(() => {
if (!swapCallback) { if (!swapCallback) {
return return
...@@ -500,7 +512,6 @@ export function Swap({ ...@@ -500,7 +512,6 @@ export function Swap({
[onCurrencyChange, onCurrencySelection, state] [onCurrencyChange, onCurrencySelection, state]
) )
const priceImpactTooHigh = priceImpactSeverity > 3
const showPriceImpactWarning = largerPriceImpact && priceImpactSeverity > 3 const showPriceImpactWarning = largerPriceImpact && priceImpactSeverity > 3
const prevTrade = usePrevious(trade) const prevTrade = usePrevious(trade)
...@@ -545,6 +556,16 @@ export function Swap({ ...@@ -545,6 +556,16 @@ export function Swap({
fiatValueOutput={fiatValueTradeOutput} fiatValueOutput={fiatValueTradeOutput}
/> />
)} )}
{showPriceImpactModal && showPriceImpactWarning && (
<PriceImpactModal
priceImpact={largerPriceImpact}
onDismiss={() => setShowPriceImpactModal(false)}
onContinue={() => {
setShowPriceImpactModal(false)
handleContinueToReview()
}}
/>
)}
<div style={{ display: 'relative' }}> <div style={{ display: 'relative' }}>
<SwapSection> <SwapSection>
...@@ -698,16 +719,11 @@ export function Swap({ ...@@ -698,16 +719,11 @@ export function Swap({
> >
<ButtonError <ButtonError
onClick={() => { onClick={() => {
setSwapState({ showPriceImpactWarning ? setShowPriceImpactModal(true) : handleContinueToReview()
tradeToConfirm: trade,
swapError: undefined,
showConfirm: true,
txHash: undefined,
})
}} }}
id="swap-button" id="swap-button"
data-testid="swap-button" data-testid="swap-button"
disabled={!isValid || routeIsSyncing || routeIsLoading || priceImpactTooHigh} disabled={!isValid || routeIsSyncing || routeIsLoading}
error={isValid && priceImpactSeverity > 2 && allowance.state === AllowanceState.ALLOWED} error={isValid && priceImpactSeverity > 2 && allowance.state === AllowanceState.ALLOWED}
> >
<Text fontSize={20} fontWeight={600}> <Text fontSize={20} fontWeight={600}>
...@@ -715,8 +731,6 @@ export function Swap({ ...@@ -715,8 +731,6 @@ export function Swap({
swapInputError swapInputError
) : routeIsSyncing || routeIsLoading ? ( ) : routeIsSyncing || routeIsLoading ? (
<Trans>Swap</Trans> <Trans>Swap</Trans>
) : priceImpactTooHigh ? (
<Trans>Price Impact Too High</Trans>
) : priceImpactSeverity > 2 ? ( ) : priceImpactSeverity > 2 ? (
<Trans>Swap Anyway</Trans> <Trans>Swap Anyway</Trans>
) : ( ) : (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment