Skip to content

Commit

Permalink
Change MEV protection endpoint to KyberSwap RPC
Browse files Browse the repository at this point in the history
  • Loading branch information
tienkane committed Oct 14, 2024
1 parent eb33401 commit 383bbd4
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 106 deletions.
109 changes: 28 additions & 81 deletions src/components/SwapForm/AddMEVProtectionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { ChainId } from '@kyberswap/ks-sdk-core'
import { Trans, t } from '@lingui/macro'
import { darken } from 'polished'
import { useCallback, useState } from 'react'
import { useCallback } from 'react'
import { X } from 'react-feather'
import { useMedia } from 'react-use'
import { Text } from 'rebass'
import styled, { css } from 'styled-components'
import styled from 'styled-components'

import FlashBot from 'assets/images/flashbot.png'
import MEVBlocker from 'assets/images/mevblocker.png'
import { NotificationType } from 'components/Announcement/type'
import { ButtonEmpty, ButtonOutlined, ButtonPrimary } from 'components/Button'
import { ButtonOutlined, ButtonPrimary } from 'components/Button'
import Modal from 'components/Modal'
import Row, { RowBetween } from 'components/Row'
import { CONNECTION } from 'components/Web3Provider'
import { Z_INDEXS } from 'constants/styles'
import { useActiveWeb3React } from 'hooks'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import { useChangeNetwork } from 'hooks/web3/useChangeNetwork'
import { useNotify } from 'state/application/hooks'
Expand All @@ -34,71 +33,27 @@ const Wrapper = styled.div`
display: none;
}
`
const RPCOption = styled(ButtonEmpty)<{ selected: boolean }>`
color: ${({ theme }) => theme.primary};
background-color: ${({ theme }) => theme.tableHeader};
display: flex;
justify-content: start;
align-items: center;
height: 36px;
text-decoration: none;
gap: 4px;
transition: all 0.1s ease;
font-size: 14px;
font-weight: 500;
line-height: 20px;
padding: 8px;
& img {
width: 24px;
}
&:hover {
background-color: ${({ theme }) => darken(0.1, theme.buttonBlack)};
color: ${({ theme }) => theme.text} !important;
}
${({ theme, selected }) =>
selected &&
css`
background-color: ${theme.buttonBlack};
& > div {
color: ${theme.text};
}
`}
`

const rpcOptions: {
name: string
logo: string
rpc: string
}[] = [
{
name: 'Flashbots',
logo: FlashBot,
rpc: 'https://rpc.flashbots.net',
},
{
name: 'MEVBlocker',
logo: MEVBlocker,
rpc: 'https://rpc.mevblocker.io',
},
]
const KYBER_SWAP_RPC = 'https://ethereum.kyberengineering.io/'

export default function AddMEVProtectionModal({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) {
const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`)
const [selectedRpc, setSelectedRpc] = useState(rpcOptions[0].name)
const { addNewNetwork } = useChangeNetwork()
const selectedOption = rpcOptions.find(option => option.name === selectedRpc)
const notify = useNotify()
const { mixpanelHandler } = useMixpanel()
const { walletKey } = useActiveWeb3React()
const notify = useNotify()

const onAdd = useCallback(() => {
if (!selectedOption) return
const addingOption = selectedOption
mixpanelHandler(MIXPANEL_TYPE.MEV_ADD_CLICK_MODAL, { type: addingOption.name })
const name = addingOption.name
if (!walletKey || walletKey !== CONNECTION.METAMASK_RDNS) {
onClose?.()
return
}

const name = 'KyberSwap'
mixpanelHandler(MIXPANEL_TYPE.MEV_ADD_CLICK_MODAL, { type: name })
addNewNetwork(
ChainId.MAINNET,
addingOption.rpc,
KYBER_SWAP_RPC,
{
name,
title: t`Failed to switch to ${name} RPC Endpoint`,
Expand All @@ -111,14 +66,15 @@ export default function AddMEVProtectionModal({ isOpen, onClose }: { isOpen: boo
summary: t`You have successfully turned on MEV Protection Mode. All transactions on Ethereum will go through the custom RPC endpoint unless you change it`,
})
onClose?.()
mixpanelHandler(MIXPANEL_TYPE.MEV_ADD_RESULT, { type: addingOption.name, result: 'success' })
mixpanelHandler(MIXPANEL_TYPE.MEV_ADD_RESULT, { type: name, result: 'success' })
},
(error: Error) => {
const message = friendlyError(error)
mixpanelHandler(MIXPANEL_TYPE.MEV_ADD_RESULT, { type: addingOption.name, result: 'fail', reason: message })
mixpanelHandler(MIXPANEL_TYPE.MEV_ADD_RESULT, { type: name, result: 'fail', reason: message })
onClose?.()
},
)
}, [addNewNetwork, notify, onClose, selectedOption, mixpanelHandler])
}, [walletKey, onClose, mixpanelHandler, addNewNetwork, notify])

return (
<Modal
Expand All @@ -142,37 +98,28 @@ export default function AddMEVProtectionModal({ isOpen, onClose }: { isOpen: boo
<ExternalLink href="https://docs.kyberswap.com/getting-started/foundational-topics/decentralized-finance/maximal-extractable-value-mev">
MEV
</ExternalLink>{' '}
Protection safeguards you from front-running attacks on Ethereum. We suggest you employing the{' '}
Protection safeguards you from front-running attacks on Ethereum. We recommend using{' '}
<ExternalLink href="https://docs.kyberswap.com/getting-started/foundational-topics/decentralized-technologies/rpc">
RPC endpoint
KyberSwap&apos;s RPC endpoint
</ExternalLink>{' '}
of reliable third-parties such as{' '}
<ExternalLink href="https://docs.flashbots.net/flashbots-protect/overview">Flashbots</ExternalLink> or{' '}
<ExternalLink href="https://mevblocker.io/#faq">MEVBlocker</ExternalLink>.
- powered by Blink to protect your transactions from front-running attacks and ensure a better trading
experience.
<br />
<br />
Note that adding the RPC endpoint automatically is only available via the MetaMask wallet. If you would
like to add the RPC endpoint to your wallet manually, please refer to this{' '}
Note that adding the RPC endpoint automatically is only available via the MetaMask wallet. If you are
using another wallet or would like to add the RPC endpoint to your wallet manually, please refer to this{' '}
<ExternalLink href="https://docs.kyberswap.com/getting-started/quickstart/faq#how-to-change-rpc-in-metamask">
guide
</ExternalLink>
.
. Please make sure you understand how it works and use at your own caution.
</Trans>
</Text>
</Row>
<Row gap="16px" flexDirection={upToExtraSmall ? 'column' : 'row'}>
{rpcOptions.map(({ name, logo }) => (
<RPCOption selected={selectedRpc === name} key={name} onClick={() => setSelectedRpc(name)}>
<img src={logo} />
{name}
</RPCOption>
))}
</Row>
<Row gap="16px" flexDirection={upToExtraSmall ? 'column' : 'row'}>
<ButtonOutlined onClick={onClose}>
<Trans>No, go back</Trans>
</ButtonOutlined>
<ButtonPrimary onClick={onAdd} disabled={!selectedOption}>
<ButtonPrimary onClick={onAdd}>
<Trans>Yes</Trans>
</ButtonPrimary>
</Row>
Expand Down
8 changes: 6 additions & 2 deletions src/components/SwapForm/SlippageSettingGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { ChainId } from '@kyberswap/ks-sdk-core'
import { Trans } from '@lingui/macro'
import { rgba } from 'polished'
import { useCallback, useState } from 'react'
import { isMobile, isTablet } from 'react-device-detect'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
import styled from 'styled-components'

import { ReactComponent as DropdownSVG } from 'assets/svg/down.svg'
import { Shield } from 'components/Icons'
import InfoHelper from 'components/InfoHelper'
import SlippageSetting from 'components/SwapForm/SlippageSetting'
import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
import { APP_PATHS } from 'constants/index'
Expand All @@ -19,13 +21,14 @@ import { MEDIA_WIDTHS } from 'theme'

import AddMEVProtectionModal from './AddMEVProtectionModal'

const PriceAlertButton = styled.div`
export const PriceAlertButton = styled.div`
background: ${({ theme }) => rgba(theme.subText, 0.2)};
border-radius: 24px;
display: flex;
align-items: center;
gap: 4px;
padding: 4px 6px;
font-size: 12px;
cursor: pointer;
user-select: none;
font-weight: 500;
Expand Down Expand Up @@ -62,11 +65,12 @@ export default function SlippageSettingGroup({
const { isSlippageControlPinned } = useSlippageSettingByPage()
const isPartnerSwap = window.location.pathname.startsWith(APP_PATHS.PARTNER_SWAP)
let rightButton =
chainId === ChainId.MAINNET && active && !isPartnerSwap ? (
chainId === ChainId.MAINNET && active && !isPartnerSwap && !isMobile && !isTablet ? (
<PriceAlertButton onClick={addMevProtectionHandler}>
<Shield size={14} color={theme.subText} />
<Text color={theme.subText} style={{ whiteSpace: 'nowrap' }}>
{upToXXSmall ? <Trans>MEV Protection</Trans> : <Trans>Add MEV Protection</Trans>}
<InfoHelper size={14} text="Add MEV Protection to safeguard you from front-running attacks." />
</Text>
</PriceAlertButton>
) : null
Expand Down
72 changes: 59 additions & 13 deletions src/components/SwapForm/SwapModal/SwapDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
import { Currency, CurrencyAmount, Price } from '@kyberswap/ks-sdk-core'
import { ChainId, Currency, CurrencyAmount, Price } from '@kyberswap/ks-sdk-core'
import { Trans } from '@lingui/macro'
import { rgba } from 'polished'
import { useState } from 'react'
import { useCallback, useState } from 'react'
import { isMobile, isTablet } from 'react-device-detect'
import { ExternalLink as ExternalLinkIcon, Repeat } from 'react-feather'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
import { BuildRouteData } from 'services/route/types/buildRoute'

import { TruncatedText } from 'components'
import { AutoColumn } from 'components/Column'
import CopyHelper from 'components/Copy'
import Divider from 'components/Divider'
import { Shield } from 'components/Icons'
import InfoHelper from 'components/InfoHelper'
import { RowBetween, RowFixed } from 'components/Row'
import AddMEVProtectionModal from 'components/SwapForm/AddMEVProtectionModal'
import { PriceAlertButton } from 'components/SwapForm/SlippageSettingGroup'
import { useSwapFormContext } from 'components/SwapForm/SwapFormContext'
import ValueWithLoadingSkeleton from 'components/SwapForm/SwapModal/SwapDetails/ValueWithLoadingSkeleton'
import { TooltipTextOfSwapFee } from 'components/SwapForm/TradeSummary'
import useCheckStablePairSwap from 'components/SwapForm/hooks/useCheckStablePairSwap'
import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
import { StyledBalanceMaxMini } from 'components/swapv2/styleds'
import { useActiveWeb3React } from 'hooks'
import { APP_PATHS } from 'constants/index'
import { useActiveWeb3React, useWeb3React } from 'hooks'
import useENS from 'hooks/useENS'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useTheme from 'hooks/useTheme'
import { useCheckCorrelatedPair } from 'state/swap/hooks'
import { usePaymentToken } from 'state/user/hooks'
import { ExternalLink, TYPE } from 'theme'
import { usePaymentToken, useSlippageSettingByPage } from 'state/user/hooks'
import { ExternalLink, MEDIA_WIDTHS, TYPE } from 'theme'
import { DetailedRouteSummary } from 'types/route'
import { formattedNum, shortenAddress } from 'utils'
import { calculateFeeFromBuildData } from 'utils/fee'
import { checkPriceImpact, formatPriceImpact } from 'utils/prices'
import { checkWarningSlippage, formatSlippage } from 'utils/slippage'
import { SLIPPAGE_STATUS, checkRangeSlippage, checkWarningSlippage, formatSlippage } from 'utils/slippage'

interface ExecutionPriceProps {
executionPrice?: Price<Currency, Currency>
Expand Down Expand Up @@ -73,7 +81,9 @@ export default function SwapDetails({
buildData,
}: Props) {
const { chainId, networkInfo, account } = useActiveWeb3React()
const { active } = useWeb3React()
const [showInverted, setShowInverted] = useState<boolean>(false)
const [showMevModal, setShowMevModal] = useState(false)
const theme = useTheme()
const { slippage, routeSummary } = useSwapFormContext()

Expand Down Expand Up @@ -116,8 +126,41 @@ export default function SwapDetails({
const { address: recipientAddress } = useENS(recipientAddressOrName)
const recipient = recipientAddressOrName === null || recipientAddressOrName === '' ? account : recipientAddress

const { mixpanelHandler } = useMixpanel()

const addMevProtectionHandler = useCallback(() => {
setShowMevModal(true)
mixpanelHandler(MIXPANEL_TYPE.MEV_CLICK_ADD_MEV)
}, [mixpanelHandler])

const onClose = useCallback(() => {
setShowMevModal(false)
}, [])

const { rawSlippage } = useSlippageSettingByPage()
const slippageStatus = checkRangeSlippage(rawSlippage, isStablePair, isCorrelated)
const upToXXSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToXXSmall}px)`)
const isPartnerSwap = window.location.pathname.startsWith(APP_PATHS.PARTNER_SWAP)
const addMevButton =
chainId === ChainId.MAINNET &&
active &&
!isPartnerSwap &&
slippageStatus === SLIPPAGE_STATUS.HIGH &&
!isMobile &&
!isTablet ? (
<PriceAlertButton onClick={addMevProtectionHandler}>
<Shield size={14} color={theme.subText} />
<Text color={theme.subText} style={{ whiteSpace: 'nowrap' }}>
{upToXXSmall ? <Trans>MEV Protection</Trans> : <Trans>Add MEV Protection</Trans>}
<InfoHelper size={14} text="Add MEV Protection to safeguard you from front-running attacks." />
</Text>
</PriceAlertButton>
) : null

return (
<>
<AddMEVProtectionModal isOpen={showMevModal} onClose={onClose} />

<AutoColumn
gap="0.5rem"
style={{ padding: '12px 16px', border: `1px solid ${theme.border}`, borderRadius: '16px' }}
Expand Down Expand Up @@ -345,7 +388,7 @@ export default function SwapDetails({
</RowBetween>
)}

<RowBetween height="20px" style={{ gap: '16px' }}>
<RowBetween height={addMevButton !== null ? '45px' : '20px'} style={{ gap: '16px' }} align="flex-start">
<RowFixed>
<TextDashed fontSize={12} fontWeight={400} color={theme.subText}>
<MouseoverTooltip
Expand All @@ -366,12 +409,15 @@ export default function SwapDetails({
</TextDashed>
</RowFixed>

<TYPE.black
fontSize={12}
color={checkWarningSlippage(slippage, isStablePair, isCorrelated) ? theme.warning : undefined}
>
{formatSlippage(slippage)}
</TYPE.black>
<Flex flexDirection={'column'} alignItems={'flex-end'} sx={{ gap: '6px' }}>
<TYPE.black
fontSize={12}
color={checkWarningSlippage(slippage, isStablePair, isCorrelated) ? theme.warning : undefined}
>
{formatSlippage(slippage)}
</TYPE.black>
{addMevButton}
</Flex>
</RowBetween>

<Divider />
Expand Down
Loading

0 comments on commit 383bbd4

Please sign in to comment.