Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
Merge branch 'master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
anxolin committed Jan 22, 2022
2 parents 56fbeb1 + 3760095 commit b3c8e1b
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 32 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"dist"
],
"private": true,
"version": "1.9.0",
"version": "1.9.2",
"engines": {
"node": ">=14.0.0"
},
Expand Down
66 changes: 36 additions & 30 deletions src/custom/pages/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ import TermsAndConditions from 'pages/TermsAndConditions'
import About from 'pages/About'
import Profile from 'pages/Profile'
import Faq from 'pages/Faq'
import NotFound from 'pages/NotFound'
import CowRunner from '@src/custom/pages/games/CowRunner'
import MevSlicer from '@src/custom/pages/games/MevSlicer'
import NotFound from 'pages/error/NotFound'
import CowRunner from 'pages/games/CowRunner'
import MevSlicer from 'pages/games/MevSlicer'
import AnySwapAffectedUsers from 'pages/error/AnySwapAffectedUsers'
import * as Sentry from '@sentry/react'
import { Integrations } from '@sentry/tracing'
import { version } from '@src/../package.json'
import { environmentName } from 'utils/environments'
import { useFilterEmptyQueryParams } from 'hooks/useFilterEmptyQueryParams'
import RedirectAnySwapAffectedUsers from 'pages/error/AnySwapAffectedUsers/RedirectAnySwapAffectedUsers'

const SENTRY_DSN = process.env.REACT_APP_SENTRY_DSN
const SENTRY_TRACES_SAMPLE_RATE = process.env.REACT_APP_SENTRY_TRACES_SAMPLE_RATE
Expand Down Expand Up @@ -66,32 +68,36 @@ export default function App() {
useFilterEmptyQueryParams()

return (
<Wrapper>
<Switch>
<Route exact strict path="/swap" component={Swap} />
<Route exact strict path="/swap/:outputCurrency" component={RedirectToSwap} />
<Route exact strict path="/send" component={RedirectPathToSwapOnly} />
<Route exact strict path="/claim" component={Claim} />
<Route exact strict path="/about" component={About} />
<Route exact strict path="/profile" component={Profile} />
<Route exact strict path="/faq" component={Faq} />
<Route exact strict path="/play/cow-runner" component={CowRunner} />
<Route exact strict path="/play/mev-slicer" component={MevSlicer} />
<Route exact strict path="/privacy-policy" component={PrivacyPolicy} />
<Route exact strict path="/cookie-policy" component={CookiePolicy} />
<Route exact strict path="/terms-and-conditions" component={TermsAndConditions} />
<Route exact strict path="/chat" component={createRedirectExternal('https://chat.cowswap.exchange')} />
<Route exact strict path="/docs" component={createRedirectExternal('https://docs.cow.fi')} />
<Route
exact
strict
path="/stats"
component={createRedirectExternal('https://dune.xyz/gnosis.protocol/Gnosis-Protocol-V2')}
/>
<Route exact strict path="/twitter" component={createRedirectExternal('https://twitter.com/MEVprotection')} />
<Route exact strict path="/" component={RedirectPathToSwapOnly} />
<Route component={NotFound} />
</Switch>
</Wrapper>
<>
<RedirectAnySwapAffectedUsers />
<Wrapper>
<Switch>
<Route exact strict path="/swap" component={Swap} />
<Route exact strict path="/swap/:outputCurrency" component={RedirectToSwap} />
<Route exact strict path="/send" component={RedirectPathToSwapOnly} />
<Route exact strict path="/claim" component={Claim} />
<Route exact strict path="/about" component={About} />
<Route exact strict path="/profile" component={Profile} />
<Route exact strict path="/faq" component={Faq} />
<Route exact strict path="/play/cow-runner" component={CowRunner} />
<Route exact strict path="/play/mev-slicer" component={MevSlicer} />
<Route exact strict path="/anyswap-affected-users" component={AnySwapAffectedUsers} />
<Route exact strict path="/privacy-policy" component={PrivacyPolicy} />
<Route exact strict path="/cookie-policy" component={CookiePolicy} />
<Route exact strict path="/terms-and-conditions" component={TermsAndConditions} />
<Route exact strict path="/chat" component={createRedirectExternal('https://chat.cowswap.exchange')} />
<Route exact strict path="/docs" component={createRedirectExternal('https://docs.cow.fi')} />
<Route
exact
strict
path="/stats"
component={createRedirectExternal('https://dune.xyz/gnosis.protocol/Gnosis-Protocol-V2')}
/>
<Route exact strict path="/twitter" component={createRedirectExternal('https://twitter.com/MEVprotection')} />
<Route exact strict path="/" component={RedirectPathToSwapOnly} />
<Route component={NotFound} />
</Switch>
</Wrapper>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useEffect } from 'react'
import { useHistory, useLocation } from 'react-router-dom'

import useIsAnySwapAffectedUser from './useIsAnySwapAffectedUser'

const WARNING_PAGE = '/anyswap-affected-users'

export default function RedirectAnySwapAffectedUsers() {
const history = useHistory()
const { pathname } = useLocation()

// Detect if the user is affected by the hack
const isAnySwapAffectedUser = useIsAnySwapAffectedUser()

useEffect(() => {
if (isAnySwapAffectedUser && location.pathname !== WARNING_PAGE) {
// Redirect to warning page
history.push(WARNING_PAGE)
}
}, [isAnySwapAffectedUser, history, pathname])

return null
}
96 changes: 96 additions & 0 deletions src/custom/pages/error/AnySwapAffectedUsers/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import styled from 'styled-components/macro'
import Page, { Title, Content, GdocsListStyle } from 'components/Page'
import { ButtonPrimary } from 'custom/components/Button'
import cow404IMG from 'assets/cow-swap/cow-404.png'
import { ExternalLink as ExternalLinkTheme } from 'theme'

const ExternalLink = styled(ExternalLinkTheme)``

const Wrapper = styled(Page)`
${GdocsListStyle}
min-height: auto;
padding-bottom: 32px;
${({ theme }) => theme.mediaWidth.upToSmall`
padding-bottom: 24px;
`}
${Title} {
margin-bottom: 50px;
font-size: 26px;
${({ theme }) => theme.mediaWidth.upToSmall`
font-size: 18px;
text-align: center;
`}
}
${Content} {
margin-bottom: 0;
pre {
display: inline;
}
}
${ExternalLink} {
text-decoration: underline;
font-weight: 800;
color: ${({ theme }) => theme.primary1};
}
`

const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
${ButtonPrimary} {
width: 196px;
padding: 9px;
color: ${({ theme }) => theme.primaryText1};
&:hover {
${({ theme }) => theme.buttonPrimary.background}
}
}
h2 {
margin: 36px 0 32px;
}
img {
max-width: 506px;
}
p {
text-align: left;
}
${({ theme }) => theme.mediaWidth.upToSmall`
img {
max-width: 287px;
}
h2 {
font-size: 16px;
text-align: center;
}
`}
`

export default function AnySwapAffectedUsers() {
return (
<Wrapper>
<Title>Your account is affected by AnySwap Hack</Title>
<Content>
<Container>
<img src={cow404IMG} alt="CowSwap 404 not found" />
<h2>Read how to prevent loosing funds</h2>
</Container>
<p>
Your user has given an allowance to <pre>AnyswapV4Router</pre> which is affected by a critical vulnerability.
</p>
<p>In order to protect your funds, you will need to remove the approval on this contract.</p>
<p>
Please read more in this{' '}
<ExternalLink href="https://cointelegraph.com/news/multichain-asks-users-to-revoke-approvals-amid-critical-vulnerability">
link
</ExternalLink>
.
</p>
</Content>
</Wrapper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useMultipleContractSingleData } from 'state/multicall/hooks'
import { WETH9_EXTENDED as WETH } from 'constants/tokens'
import { Interface } from '@ethersproject/abi'
import ERC20_ABI from 'abis/erc20.json'
import { Erc20Interface } from '@src/abis/types/Erc20'
import { ChainId } from '@uniswap/sdk'
import { useActiveWeb3React } from 'hooks/web3'
import { useMemo } from 'react'
import { ZERO_ADDRESS } from '@src/constants/misc'
import { BigNumber } from '@ethersproject/bignumber'

const WETH_ADDRESS = WETH[ChainId.MAINNET].address
const PERI_ADDRESS = '0x5d30aD9C6374Bf925D0A75454fa327AACf778492'
const MATIC_ADDRESS = '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0'
const WBNB_ADDRESS = '0x418d75f65a02b3d53b2418fb8e1fe493759c7605'

const AFFECTED_TOKENS = [WETH_ADDRESS, PERI_ADDRESS, MATIC_ADDRESS, WBNB_ADDRESS] // relevant tokens for the check

const ERC20_INTERFACE = new Interface(ERC20_ABI) as Erc20Interface
const ANYSWAP_V4_CONTRACT = '0x6b7a87899490EcE95443e979cA9485CBE7E71522'

// Uncomment to test logic: 0xC92...522 is mainnet VaultRelayer address. Use it with one account that has given some WETH allowance to it
// const ANYSWAP_V4_CONTRACT = '0xC92E8bdf79f0507f65a392b0ab4667716BFE0110' //'0x6b7a87899490EcE95443e979cA9485CBE7E71522'

const BLOCKS_PER_FETCH = 120 // 30min. It would actually suffice to check once, but we check every 120 blocks

export default function useIsAnySwapAffectedUser() {
const { chainId, account } = useActiveWeb3React()
const result = useMultipleContractSingleData(
AFFECTED_TOKENS,
ERC20_INTERFACE,
'allowance',
[account || ZERO_ADDRESS, ANYSWAP_V4_CONTRACT],
{ blocksPerFetch: BLOCKS_PER_FETCH }
)

const isAffected = useMemo(() => {
// The error affects Mainnet
if (chainId !== ChainId.MAINNET) {
return false
}

// Check if any of the tokens has allowance in the router contract
const hasAllowance = result.some(({ result, loading, error, valid }) => {
const allowance = valid && !loading && !error && result ? (result[0] as BigNumber) : undefined
return allowance ? !allowance.isZero() : false
})

return hasAllowance
}, [chainId, result])

return isAffected
}
2 changes: 1 addition & 1 deletion src/state/multicall/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const NEVER_RELOAD: ListenerOptions = {
}

// the lowest level call for subscribing to contract data
function useCallsData(
export function useCallsData(
calls: (Call | undefined)[],
{ blocksPerFetch }: ListenerOptions = { blocksPerFetch: 1 }
): CallResult[] {
Expand Down

0 comments on commit b3c8e1b

Please sign in to comment.