Compare commits

...

30 Commits

Author SHA1 Message Date
Ian Lapham
cccf149568 fix: update tick parsing to handle min/max prices (#1613)
* update tick parsing to handle min/max prices

* remove fee tier step
2021-05-17 20:19:15 -04:00
Justin Domingue
604ea49567 Revert "lazy load uncommon routes to reduce initial bundle size (#1597)" (#1611)
This reverts commit 4c0c6dfde6.
2021-05-17 11:24:31 -07:00
Justin Domingue
4c0c6dfde6 lazy load uncommon routes to reduce initial bundle size (#1597) 2021-05-17 11:03:49 -07:00
Noah Zinsmeister
a160bb8f02 Merge remote-tracking branch 'refs/remotes/origin/main' 2021-05-17 11:54:17 -04:00
Noah Zinsmeister
e86946b104 bump to sdk version that fixes mint slippage bug
closes #1573
2021-05-17 11:54:06 -04:00
Moody Salem
03108b981e update README.md 2021-05-17 10:14:35 -05:00
Moody Salem
ae27e245b4 replace the message when we fail to parse an error 2021-05-14 14:13:13 -05:00
Moody Salem
897f354202 chore: bump mathieudutour/github-tag-action to latest release version to fix generated changelogs
https://github.com/Uniswap/uniswap-interface/issues/1572
2021-05-14 10:56:57 -05:00
Moody Salem
4745052f0e fix: break words in swap error messages (fixes https://github.com/Uniswap/uniswap-interface/issues/1462) 2021-05-14 10:50:55 -05:00
Moody Salem
5bc5d6504e improve the text slightly 2021-05-14 08:45:17 -05:00
Moody Salem
7a0b85bf41 improvement: estimated amounts instead of minimum/maximums (#1570)
* estimated amounts instead of minimum/maximums

* missed a spot

* fix linting error
2021-05-14 07:15:53 -05:00
OMGspidertanx
534afb3278 fix: tweak element sizing/wraping in approve button (#1569) 2021-05-14 07:15:41 -05:00
Moody Salem
7d71af353e perf: debounce localStorage save 2021-05-14 07:10:25 -05:00
Moody Salem
af6098bfe5 feat: allow walletconnect on testnets (#1389)
* try walletconnect multinetwork

* clean up environment variables for multinetwork

* remove irrelevant config

* move some stuff around

Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
2021-05-13 17:46:30 -05:00
Moody Salem
fce29bb36f fix: division by 0 when computing the USDC value of tokens that do not have a v2 pair (fixes https://github.com/Uniswap/uniswap-interface/issues/1566) 2021-05-13 17:27:34 -05:00
Noah Zinsmeister
4517af39ba don't jump on mouse exit (#1565) 2021-05-13 17:06:25 -04:00
Noah Zinsmeister
b40163ce05 allow fee collection/liquidity removal in weth (#1553)
* add dummy flags for burn/collect as weth

* add toggles

* clean up toggle position

* only show weth toggle if collection is possible
2021-05-13 14:49:54 -04:00
Moody Salem
809902efec fixes https://github.com/Uniswap/uniswap-interface/issues/1386 2021-05-13 12:17:34 -05:00
Noah Zinsmeister
70be9894fa bump walletlink connector (#1563) 2021-05-13 12:35:17 -04:00
Moody Salem
698ad5bac9 bump v3 sdk 2021-05-13 11:21:07 -05:00
Moody Salem
cd37b7533d put the error reason in the message so we can differentiate between unrecognized errors 2021-05-13 11:16:37 -05:00
Justin Domingue
c0cd6a1c8d handle ape= query parameter (#1555)
* handle expert_mode= and ape= query parameters

* removed console log

* use useParsedQueryString

* only handle setting ape mode
2021-05-13 12:01:58 -04:00
Moody Salem
f6245d1093 retry more frequently, couple more error nits 2021-05-13 10:51:06 -05:00
Moody Salem
83c784f7c0 improve the error coverage 2021-05-13 10:51:06 -05:00
Moody Salem
3d95b1a33b fix access of undefined property 2021-05-13 09:37:04 -05:00
Moody Salem
5c96942922 fix: show better errors 2021-05-13 09:02:48 -05:00
Justin Domingue
d27c83b382 use styled-components/macro to display className in dev builds (#1541) 2021-05-13 09:15:13 -04:00
Moody Salem
b2f88965a9 handle errors better 2021-05-12 22:05:00 -05:00
Moody Salem
95db44e0fc add a little state to the automatic issue body 2021-05-12 18:20:16 -05:00
Moody Salem
7d45ff5ca8 fix 0 decimal tokens error 2021-05-12 17:29:02 -05:00
109 changed files with 1146 additions and 648 deletions

3
.env
View File

@@ -1,5 +1,4 @@
REACT_APP_CHAIN_ID="1"
REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847"
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
REACT_APP_WALLETCONNECT_BRIDGE_URL="https://uniswap.bridge.walletconnect.org"
# Because we use storybook which has its own babel-loader dependency @ 8.2.2, where react-scripts uses 8.1.0
SKIP_PREFLIGHT_CHECK=true

View File

@@ -1,5 +1,4 @@
REACT_APP_CHAIN_ID="1"
REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/099fc58e0de9451d80b18d7c74caa7c1"
REACT_APP_INFURA_KEY="099fc58e0de9451d80b18d7c74caa7c1"
REACT_APP_PORTIS_ID="c0e2bf01-4b08-4fd5-ac7b-8e26b58cd236"
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
REACT_APP_GOOGLE_ANALYTICS_ID="UA-128182339-4"

View File

@@ -19,7 +19,7 @@ jobs:
- name: Bump version and push tag
id: github_tag_action
uses: mathieudutour/github-tag-action@v4.5
uses: mathieudutour/github-tag-action@331898d5052eedac9b15fec867b5ba66ebf9b692
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
release_branches: .*
@@ -94,19 +94,13 @@ jobs:
The latest release is always accessible via our alias to the Cloudflare IPFS gateway at [app.uniswap.org](https://app.uniswap.org).
You can also access the Uniswap Interface directly from an IPFS gateway.
The Uniswap interface uses [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to store your settings.
**Beware** that other sites you access via the _same_ IPFS gateway can read and modify your settings on the Uniswap interface without your permission.
You can avoid this issue by using a subdomain IPFS gateway, or our alias to the latest release at [app.uniswap.org](https://app.uniswap.org).
The preferred URLs below are safe to use to access this specific release.
**BEWARE**: The Uniswap interface uses [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported.
**You should always use an IPFS gateway that enforces origin separation**, or our alias to the latest release at [app.uniswap.org](https://app.uniswap.org).
Your Uniswap settings are never remembered across different URLs.
Preferred URLs:
IPFS gateways:
- https://${{ steps.convert_cidv0.outputs.cidv1 }}.ipfs.dweb.link/
- https://${{ steps.convert_cidv0.outputs.cidv1 }}.ipfs.cf-ipfs.com/
- [ipfs://${{ steps.upload.outputs.hash }}/](ipfs://${{ steps.upload.outputs.hash }}/)
Other IPFS gateways:
- https://cloudflare-ipfs.com/ipfs/${{ steps.upload.outputs.hash }}/
- https://ipfs.infura.io/ipfs/${{ steps.upload.outputs.hash }}/
- https://ipfs.io/ipfs/${{ steps.upload.outputs.hash }}/
${{ needs.bump_version.outputs.changelog }}

View File

@@ -22,18 +22,12 @@ To access the Uniswap Interface, use an IPFS gateway link from the
[latest release](https://github.com/Uniswap/uniswap-interface/releases/latest),
or visit [app.uniswap.org](https://app.uniswap.org).
## Listing a token
Please see the
[@uniswap/default-token-list](https://github.com/uniswap/default-token-list)
repository.
## Development
### Install Dependencies
```bash
yarn
yarn install
```
### Run
@@ -42,26 +36,22 @@ yarn
yarn start
```
### Configuring the environment (optional)
To have the interface default to a different network when a wallet is not connected:
1. Make a copy of `.env` named `.env.local`
2. Change `REACT_APP_NETWORK_ID` to `"{YOUR_NETWORK_ID}"`
3. Change `REACT_APP_NETWORK_URL` to e.g. `"https://{YOUR_NETWORK_ID}.infura.io/v3/{YOUR_INFURA_KEY}"`
Note that the interface only works on testnets where both
[Uniswap V2](https://uniswap.org/docs/v2/smart-contracts/factory/) and
[multicall](https://github.com/makerdao/multicall) are deployed.
The interface will not work on other networks.
## Contributions
**Please open all pull requests against the `main` branch.**
CI checks will run against all PRs.
## Accessing Uniswap Interface V1
## Accessing Uniswap V2
The Uniswap Interface supports swapping against, and migrating or removing liquidity from Uniswap V1. However,
if you would like to use Uniswap V1, the Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for
Uniswap protocol V2.
- Swap on Uniswap V2: https://app.uniswap.org/#/swap?use=v2
- View V2 liquidity: https://app.uniswap.org/#/pool/v2
- Add V2 liquidity: https://app.uniswap.org/#/add/v2
- Migrate V2 liquidity to V3: https://app.uniswap.org/#/migrate/v2
## Accessing Uniswap V1
The Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
linked from the [v1.0.0 release](https://github.com/Uniswap/uniswap-interface/releases/tag/v1.0.0).

View File

@@ -0,0 +1,8 @@
const isDev = process.env.NODE_ENV !== 'production'
module.exports = {
styledComponents: {
fileName: isDev,
displayName: isDev,
},
}

View File

@@ -51,13 +51,13 @@
"@uniswap/v2-sdk": "^3.0.0-alpha.0",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "1.0.0",
"@uniswap/v3-sdk": "^3.0.0-alpha.1",
"@uniswap/v3-sdk": "^3.0.0-alpha.5",
"@web3-react/core": "^6.0.9",
"@web3-react/fortmatic-connector": "^6.0.9",
"@web3-react/injected-connector": "^6.0.7",
"@web3-react/portis-connector": "^6.0.9",
"@web3-react/walletconnect-connector": "^6.1.1",
"@web3-react/walletlink-connector": "^6.0.9",
"@web3-react/walletconnect-connector": "^6.2.0",
"@web3-react/walletlink-connector": "^6.2.0",
"ajv": "^6.12.3",
"cids": "^1.0.0",
"copy-to-clipboard": "^3.2.0",

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import useCopyClipboard from '../../hooks/useCopyClipboard'
import { LinkStyledButton } from '../../theme'

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { CheckCircle, Triangle } from 'react-feather'
import { useActiveWeb3React } from '../../hooks'

View File

@@ -1,7 +1,7 @@
import React from 'react'
import Badge, { BadgeVariant } from 'components/Badge'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { MouseoverTooltip } from '../../components/Tooltip'
import { useTranslation } from 'react-i18next'

View File

@@ -1,5 +1,5 @@
import { Story } from '@storybook/react/types-6-0'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import React from 'react'
import {
ButtonConfirmed,

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { darken } from 'polished'
import { RowBetween } from '../Row'

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { Box } from 'rebass/styled-components'
const Card = styled(Box)<{ width?: string; padding?: string; border?: string; borderRadius?: string }>`

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
const Column = styled.div`
display: flex;

View File

@@ -1,7 +1,7 @@
import { Pair } from '@uniswap/v2-sdk'
import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import React, { useState, useCallback } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { darken } from 'polished'
import { useCurrencyBalance } from '../../state/wallet/hooks'
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'

View File

@@ -1,6 +1,6 @@
import { ChainId, Currency } from '@uniswap/sdk-core'
import React, { useMemo } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import EthereumLogo from '../../assets/images/ethereum-logo.png'
import useHttpLocations from '../../hooks/useHttpLocations'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'

View File

@@ -1,6 +1,6 @@
import { Currency } from '@uniswap/sdk-core'
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import CurrencyLogo from '../CurrencyLogo'
const Wrapper = styled.div<{ margin: boolean; sizeraw: number }>`

View File

@@ -1,7 +1,8 @@
import React, { ErrorInfo } from 'react'
import store, { AppState } from '../../state'
import { ExternalLink, ThemedBackground, TYPE } from '../../theme'
import { AutoColumn } from '../Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import ReactGA from 'react-ga'
import { getUserAgent } from '../../utils/getUserAgent'
import { AutoRow } from '../Row'
@@ -114,26 +115,45 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
}
}
function getRelevantState(): null | keyof AppState {
const path = window.location.hash
if (!path.startsWith('#/')) {
return null
}
const pieces = path.substring(2).split(/[\/\\?]/)
switch (pieces[0]) {
case 'swap':
return 'swap'
case 'add':
if (pieces[1] === 'v2') return 'mint'
else return 'mintV3'
case 'remove':
if (pieces[1] === 'v2') return 'burn'
else return 'burnV3'
}
return null
}
function issueBody(error: Error): string {
if (!error) throw new Error('no error to report')
const relevantState = getRelevantState()
const deviceData = getUserAgent()
return `**Bug Description**
return `## URL
App crashed
**Steps to Reproduce**
1. Go to ...
2. Click on ...
...
**URL**
${window.location.href}
${
relevantState
? `## \`${relevantState}\` state
\`\`\`json
${JSON.stringify(store.getState()[relevantState], null, 2)}
\`\`\`
`
: ''
}
${
error.name &&
`**Error**
`## Error
\`\`\`
${error.name}${error.message && `: ${error.message}`}
@@ -142,7 +162,7 @@ ${error.name}${error.message && `: ${error.message}`}
}
${
error.stack &&
`**Stacktrace**
`## Stacktrace
\`\`\`
${error.stack}
@@ -151,9 +171,9 @@ ${error.stack}
}
${
deviceData &&
`**Device data**
`## Device data
\`\`\`json5
\`\`\`json
${JSON.stringify(deviceData, null, 2)}
\`\`\`
`

View File

@@ -6,7 +6,7 @@ import { DynamicSection } from 'pages/AddLiquidity/styled'
import { TYPE } from 'theme'
import { RowBetween } from 'components/Row'
import { ButtonRadioChecked } from 'components/Button'
import styled from 'styled-components'
import styled from 'styled-components/macro'
const ResponsiveText = styled(TYPE.label)`
${({ theme }) => theme.mediaWidth.upToSmall`

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AlertTriangle, X } from 'react-feather'
import { useURLWarningToggle, useURLWarningVisible } from '../../state/user/hooks'

View File

@@ -1,7 +1,7 @@
import { ChainId, CurrencyAmount, Token } from '@uniswap/sdk-core'
import React, { useMemo } from 'react'
import { X } from 'react-feather'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import tokenLogo from '../../assets/images/token-logo.png'
import { UNI } from '../../constants'
import { useTotalSupply } from '../../hooks/useTotalSupply'

View File

@@ -6,7 +6,7 @@ import { NavLink } from 'react-router-dom'
import { darken } from 'polished'
import { useTranslation } from 'react-i18next'
import { Moon, Sun } from 'react-feather'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Logo from '../../assets/svg/logo.svg'
import LogoDark from '../../assets/svg/logo_white.svg'

View File

@@ -1,6 +1,6 @@
import Tooltip from 'components/Tooltip'
import React, { useState } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
const TextWrapper = styled.span<{ margin: boolean; link?: boolean; fontSize?: string; adjustSize?: boolean }>`
cursor: auto;

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useRef } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks'
import Jazzicon from 'jazzicon'

View File

@@ -1,7 +1,7 @@
import { Story } from '@storybook/react/types-6-0'
import React from 'react'
// import Row, { RowFixed } from 'components/Row'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Component, { LineChartProps } from './'
import { dummyData } from './data'
// import { AutoColumn } from 'components/Column'

View File

@@ -3,7 +3,7 @@ import { createChart, IChartApi } from 'lightweight-charts'
import { darken } from 'polished'
import { RowBetween } from 'components/Row'
import Card from '../Card'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import useTheme from 'hooks/useTheme'
const Wrapper = styled(Card)`

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import useHttpLocations from '../../hooks/useHttpLocations'
import Logo from '../Logo'

View File

@@ -1,6 +1,6 @@
import { Story } from '@storybook/react/types-6-0'
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Component from './index'
const Wrapper = styled.div`

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { darken } from 'polished'
import { useTranslation } from 'react-i18next'
import { NavLink, Link as HistoryLink } from 'react-router-dom'

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { escapeRegExp } from '../../utils'
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`

View File

@@ -2,7 +2,7 @@ import { Placement } from '@popperjs/core'
import { transparentize } from 'polished'
import React, { useCallback, useState } from 'react'
import { usePopper } from 'react-popper'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import useInterval from '../../hooks/useInterval'
import Portal from '@reach/portal'

View File

@@ -3,7 +3,7 @@ import React, { useCallback, useMemo } from 'react'
import ReactGA from 'react-ga'
import { useDispatch } from 'react-redux'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AppDispatch } from '../../state'
import { useRemovePopup } from '../../state/application/hooks'
import { acceptListUpdate } from '../../state/lists/actions'

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useActivePopups } from '../../state/application/hooks'
import { AutoColumn } from '../Column'
import PopupItem from './PopupItem'

View File

@@ -2,7 +2,7 @@ import React from 'react'
import { Token } from '@uniswap/sdk-core'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { unwrappedToken } from '../../utils/wrappedCurrency'
import { ButtonEmpty } from '../Button'

View File

@@ -5,7 +5,7 @@ import { Pair } from '@uniswap/v2-sdk'
import { ChevronDown, ChevronUp } from 'react-feather'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks'

View File

@@ -6,7 +6,7 @@ import React, { useState } from 'react'
import { ChevronDown, ChevronUp } from 'react-feather'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks'

View File

@@ -1,7 +1,7 @@
import PositionListItem from 'components/PositionListItem'
import React from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { MEDIA_WIDTHS } from 'theme'
import { PositionDetails } from 'types/position'

View File

@@ -5,7 +5,7 @@ import DoubleCurrencyLogo from 'components/DoubleLogo'
import { usePool } from 'hooks/usePools'
import { useToken } from 'hooks/Tokens'
import { Link } from 'react-router-dom'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { HideSmall, MEDIA_WIDTHS, SmallOnly } from 'theme'
import { PositionDetails } from 'types/position'
import { WETH9, Price, Token, Percent } from '@uniswap/sdk-core'

View File

@@ -1,5 +1,5 @@
import React, { useContext } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AutoColumn } from '../Column'
import { ThemeContext } from 'styled-components'
import { TYPE } from '../../theme'

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useState } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Tooltip from '../Tooltip'
const QuestionWrapper = styled.div`

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { Box } from 'rebass/styled-components'
const Row = styled(Box)<{

View File

@@ -1,7 +1,7 @@
import React from 'react'
import { Text } from 'rebass'
import { ChainId, Currency, currencyEquals, Token, ETHER } from '@uniswap/sdk-core'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { SUGGESTED_BASES } from '../../constants'
import { AutoColumn } from '../Column'

View File

@@ -2,7 +2,7 @@ import { Currency, CurrencyAmount, currencyEquals, Token } from '@uniswap/sdk-co
import React, { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks'
import { useCombinedActiveList } from '../../state/lists/hooks'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'

View File

@@ -16,7 +16,7 @@ import { filterTokens, useSortedTokensByQuery } from './filtering'
import { useTokenComparator } from './sorting'
import { PaddedColumn, SearchInput, Separator } from './styleds'
import AutoSizer from 'react-virtualized-auto-sizer'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import useToggle from 'hooks/useToggle'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useTheme from 'hooks/useTheme'

View File

@@ -1,5 +1,5 @@
import React, { useState, useCallback } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import ReactGA from 'react-ga'
import { TYPE, CloseIcon } from 'theme'
import Card from 'components/Card'

View File

@@ -7,7 +7,7 @@ import { TYPE } from 'theme'
import ListLogo from 'components/ListLogo'
import useTheme from 'hooks/useTheme'
import { ButtonPrimary } from 'components/Button'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useIsUserAddedToken, useIsTokenActive } from 'hooks/Tokens'
import { CheckCircle } from 'react-feather'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'

View File

@@ -1,7 +1,7 @@
import { TokenList } from '@uniswap/token-lists/dist/types'
import React from 'react'
import { Token, Currency } from '@uniswap/sdk-core'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { TYPE, CloseIcon } from 'theme'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'

View File

@@ -4,7 +4,7 @@ import { RowBetween } from 'components/Row'
import { ArrowLeft } from 'react-feather'
import { Text } from 'rebass'
import { CloseIcon } from 'theme'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { Token } from '@uniswap/sdk-core'
import { ManageLists } from './ManageLists'
import ManageTokens from './ManageTokens'

View File

@@ -3,7 +3,7 @@ import { Settings, CheckCircle } from 'react-feather'
import ReactGA from 'react-ga'
import { usePopper } from 'react-popper'
import { useDispatch, useSelector } from 'react-redux'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useFetchListCallback } from '../../hooks/useFetchListCallback'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { TokenList } from '@uniswap/token-lists'

View File

@@ -4,7 +4,7 @@ import { PaddedColumn, Separator, SearchInput } from './styleds'
import Row, { RowBetween, RowFixed } from 'components/Row'
import { TYPE, ExternalLinkIcon, TrashIcon, ButtonText, ExternalLink } from 'theme'
import { useToken } from 'hooks/Tokens'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useUserAddedTokens, useRemoveUserAddedToken } from 'state/user/hooks'
import { Token } from '@uniswap/sdk-core'
import CurrencyLogo from 'components/CurrencyLogo'

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { RowFixed } from '../Row'
export const FilterWrapper = styled(RowFixed)`

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row'

View File

@@ -1,5 +1,5 @@
import React, { useCallback } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
const StyledRangeInput = styled.input<{ size: number }>`
-webkit-appearance: none; /* Hides the slider so that custom slider can be made */

View File

@@ -1,6 +1,6 @@
import { readableColor } from 'polished'
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { colors } from 'theme'
const Swatch = styled.div`

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { TYPE } from '../../theme'
const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean }>`

View File

@@ -1,5 +1,5 @@
import { Story } from '@storybook/react/types-6-0'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import React, { useState } from 'react'
import MultiToggle from './MultiToggle'

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
export const ToggleWrapper = styled.button<{ width?: string }>`
display: flex;

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
const ToggleElement = styled.span<{ isActive?: boolean; isOnSwitch?: boolean }>`
padding: 0.25rem 0.5rem;

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useState } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Popover, { PopoverProps } from '../Popover'
const TooltipContainer = styled.div`

View File

@@ -184,7 +184,12 @@ export function TransactionErrorContent({ message, onDismiss }: { message: strin
</RowBetween>
<AutoColumn style={{ marginTop: 20, padding: '2rem 0' }} gap="24px" justify="center">
<AlertTriangle color={theme.red1} style={{ strokeWidth: 1.5 }} size={64} />
<Text fontWeight={500} fontSize={16} color={theme.red1} style={{ textAlign: 'center', width: '85%' }}>
<Text
fontWeight={500}
fontSize={16}
color={theme.red1}
style={{ textAlign: 'center', width: '85%', wordBreak: 'break-word' }}
>
{message}
</Text>
</AutoColumn>

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { ExternalLink } from '../../theme'
const InfoCard = styled.button<{ active?: boolean }>`

View File

@@ -1,6 +1,6 @@
import { AbstractConnector } from '@web3-react/abstract-connector'
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Option from './Option'
import { SUPPORTED_WALLETS } from '../../constants'
import { injected } from '../../connectors'

View File

@@ -5,7 +5,7 @@ import { AutoRow } from 'components/Row'
import React, { useEffect, useState } from 'react'
import { isMobile } from 'react-device-detect'
import ReactGA from 'react-ga'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import MetamaskIcon from '../../assets/images/metamask.png'
import { ReactComponent as Close } from '../../assets/images/x.svg'
import { fortmatic, injected, portis } from '../../connectors'

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'
import { useWeb3React } from '@web3-react/core'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useTranslation } from 'react-i18next'
import { network } from '../../connectors'

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import Modal from '../Modal'
import { AutoColumn, ColumnCenter } from '../Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { DataCard, CardSection, Break } from '../earn/styled'
import { RowBetween } from '../Row'
import { TYPE, ExternalLink, CloseIcon, CustomLightSpinner, UniTokenAnimated } from '../../theme'

View File

@@ -3,7 +3,7 @@ import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { isAddress } from 'ethers/lib/utils'
import React, { useEffect, useState } from 'react'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import Circle from '../../assets/images/blue-loader.svg'
import tokenLogo from '../../assets/images/token-logo.png'
import { useActiveWeb3React } from '../../hooks'

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import Modal from '../Modal'
import { AutoColumn } from '../Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { RowBetween } from '../Row'
import { TYPE, CloseIcon } from '../../theme'
import { ButtonError } from '../Button'

View File

@@ -1,7 +1,7 @@
import React from 'react'
import { AutoColumn } from '../Column'
import { RowBetween } from '../Row'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { TYPE, StyledInternalLink } from '../../theme'
import DoubleCurrencyLogo from '../DoubleLogo'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'

View File

@@ -4,7 +4,7 @@ import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
import useTransactionDeadline from '../../hooks/useTransactionDeadline'
import Modal from '../Modal'
import { AutoColumn } from '../Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { RowBetween } from '../Row'
import { TYPE, CloseIcon } from '../../theme'
import { ButtonConfirmed, ButtonError } from '../Button'

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import Modal from '../Modal'
import { AutoColumn } from '../Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { RowBetween } from '../Row'
import { TYPE, CloseIcon } from '../../theme'
import { ButtonError } from '../Button'

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AutoColumn } from '../Column'
import uImage from '../../assets/images/big_unicorn.png'

View File

@@ -1,11 +1,10 @@
import { Percent, Currency, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import React, { useContext } from 'react'
import React, { useContext, useMemo } from 'react'
import { ThemeContext } from 'styled-components'
import { TYPE } from '../../theme'
import { computePriceImpactWithMaximumSlippage } from '../../utils/computePriceImpactWithMaximumSlippage'
import { computeRealizedLPFeeAmount } from '../../utils/prices'
import { computeRealizedLPFeePercent } from '../../utils/prices'
import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row'
import FormattedPriceImpact from './FormattedPriceImpact'
@@ -19,7 +18,14 @@ export interface AdvancedSwapDetailsProps {
export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDetailsProps) {
const theme = useContext(ThemeContext)
const realizedLPFee = computeRealizedLPFeeAmount(trade)
const { realizedLPFee, priceImpact } = useMemo(() => {
if (!trade) return { realizedLPFee: undefined, priceImpact: undefined }
const realizedLpFeePercent = computeRealizedLPFeePercent(trade)
const realizedLPFee = trade.inputAmount.multiply(realizedLpFeePercent)
const priceImpact = trade.priceImpact.subtract(realizedLpFeePercent)
return { priceImpact, realizedLPFee }
}, [trade])
return !trade ? null : (
<AutoColumn gap="8px">
@@ -30,7 +36,7 @@ export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDeta
</TYPE.black>
</RowFixed>
<TYPE.black textAlign="right" fontSize={12} color={theme.text1}>
{realizedLPFee ? `${realizedLPFee.toSignificant(4)} ${trade.inputAmount.currency.symbol}` : '-'}
{realizedLPFee ? `${realizedLPFee.toSignificant(4)} ${realizedLPFee.currency.symbol}` : '-'}
</TYPE.black>
</RowBetween>
@@ -48,11 +54,24 @@ export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDeta
<RowBetween>
<RowFixed>
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
Execution price vs. spot price
Price Impact
</TYPE.black>
</RowFixed>
<TYPE.black textAlign="right" fontSize={12} color={theme.text1}>
<FormattedPriceImpact priceImpact={computePriceImpactWithMaximumSlippage(trade, allowedSlippage)} />
<FormattedPriceImpact priceImpact={priceImpact} />
</TYPE.black>
</RowBetween>
<RowBetween>
<RowFixed>
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
{trade.tradeType === TradeType.EXACT_INPUT ? 'Minimum received' : 'Maximum sent'}
</TYPE.black>
</RowFixed>
<TYPE.black textAlign="right" fontSize={12} color={theme.text1}>
{trade.tradeType === TradeType.EXACT_INPUT
? `${trade.minimumAmountOut(allowedSlippage).toSignificant(6)} ${trade.outputAmount.currency.symbol}`
: `${trade.maximumAmountIn(allowedSlippage).toSignificant(6)} ${trade.inputAmount.currency.symbol}`}
</TYPE.black>
</RowBetween>

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { useLastTruthy } from '../../hooks/useLast'
import { AdvancedSwapDetails, AdvancedSwapDetailsProps } from './AdvancedSwapDetails'

View File

@@ -7,7 +7,7 @@ import useParsedQueryString from '../../hooks/useParsedQueryString'
import { DEFAULT_VERSION, Version } from '../../hooks/useToggledVersion'
import { HideSmall, TYPE, SmallOnly } from '../../theme'
import { ButtonPrimary } from '../Button'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { Zap } from 'react-feather'
const ResponsiveButton = styled(ButtonPrimary)`

View File

@@ -90,9 +90,9 @@ export default function ConfirmSwapModal({
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade])
// text to show while loading
const pendingText = `Swapping ${trade?.maximumAmountIn(allowedSlippage)?.toSignificant(6)} ${
const pendingText = `Swapping ${trade?.inputAmount?.toSignificant(6)} ${
trade?.inputAmount?.currency?.symbol
} for ${trade?.minimumAmountOut(allowedSlippage)?.toSignificant(6)} ${trade?.outputAmount?.currency?.symbol}`
} for ${trade?.outputAmount?.toSignificant(6)} ${trade?.outputAmount?.currency?.symbol}`
const confirmationContent = useCallback(
() =>

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import SettingsTab from '../Settings'
import { Percent } from '@uniswap/sdk-core'

View File

@@ -31,12 +31,10 @@ export const ArrowWrapper = styled.div`
margin-top: -18px;
margin-bottom: -18px;
left: calc(50% - 16px);
/* transform: rotate(90deg); */
display: flex;
justify-content: center;
align-items: center;
background-color: ${({ theme }) => theme.bg1};
/* border: 4px solid ${({ theme }) => theme.bg0}; */
z-index: 2;
`
@@ -53,15 +51,12 @@ export default function SwapModalHeader({
showAcceptChanges: boolean
onAcceptChanges: () => void
}) {
const maximumAmountIn = trade.maximumAmountIn(allowedSlippage)
const minimumAmountOut = trade.minimumAmountOut(allowedSlippage)
const theme = useContext(ThemeContext)
const [showInverted, setShowInverted] = useState<boolean>(false)
const fiatValueInput = useUSDCValue(maximumAmountIn)
const fiatValueOutput = useUSDCValue(minimumAmountOut)
const fiatValueInput = useUSDCValue(trade.inputAmount)
const fiatValueOutput = useUSDCValue(trade.outputAmount)
return (
<AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}>
@@ -86,7 +81,7 @@ export default function SwapModalHeader({
fontWeight={500}
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? theme.primary1 : ''}
>
{maximumAmountIn.toSignificant(6)}
{trade.inputAmount.toSignificant(6)}
</TruncatedText>
</RowFixed>
</RowBetween>
@@ -117,7 +112,7 @@ export default function SwapModalHeader({
</RowFixed>
<RowFixed gap={'0px'}>
<TruncatedText fontSize={24} fontWeight={500}>
{minimumAmountOut.toSignificant(6)}
{trade.outputAmount.toSignificant(6)}
</TruncatedText>
</RowFixed>
</RowBetween>
@@ -127,11 +122,7 @@ export default function SwapModalHeader({
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
{'Price:'}
</TYPE.body>
<TradePrice
price={trade.worstExecutionPrice(allowedSlippage)}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
<TradePrice price={trade.executionPrice} showInverted={showInverted} setShowInverted={setShowInverted} />
</RowBetween>
<LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}>
@@ -155,12 +146,12 @@ export default function SwapModalHeader({
</SwapShowAcceptChanges>
) : null}
{/* <AutoColumn justify="flex-start" gap="sm" style={{ padding: '.75rem 1rem' }}>
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '.75rem 1rem' }}>
{trade.tradeType === TradeType.EXACT_INPUT ? (
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
{`Output is estimated. You will receive at least `}
<b>
{minimumAmountOut.toSignificant(6)} {trade.outputAmount.currency.symbol}
{trade.minimumAmountOut(allowedSlippage).toSignificant(6)} {trade.outputAmount.currency.symbol}
</b>
{' or the transaction will revert.'}
</TYPE.italic>
@@ -168,12 +159,12 @@ export default function SwapModalHeader({
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
{`Input is estimated. You will sell at most `}
<b>
{maximumAmountIn.toSignificant(6)} {trade.inputAmount.currency.symbol}
{trade.maximumAmountIn(allowedSlippage).toSignificant(6)} {trade.inputAmount.currency.symbol}
</b>
{' or the transaction will revert.'}
</TYPE.italic>
)}
</AutoColumn> */}
</AutoColumn>
{recipient !== null ? (
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
<TYPE.main>

View File

@@ -1,5 +1,5 @@
import React, { useState } from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { TYPE, CloseIcon, ExternalLink } from 'theme'
import { ButtonEmpty } from 'components/Button'
import Modal from 'components/Modal'

View File

@@ -171,7 +171,7 @@ export function SwapCallbackError({ error }: { error: string }) {
<SwapCallbackErrorInnerAlertTriangle>
<AlertTriangle size={24} />
</SwapCallbackErrorInnerAlertTriangle>
<p>{error}</p>
<p style={{ wordBreak: 'break-word' }}>{error}</p>
</SwapCallbackErrorInner>
)
}

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react'
import Modal from '../Modal'
import { AutoColumn } from '../Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { RowBetween } from '../Row'
import { TYPE } from '../../theme'
import { X } from 'react-feather'

View File

@@ -1,40 +1,53 @@
import { Web3Provider } from '@ethersproject/providers'
import { ChainId } from '@uniswap/sdk-core'
import { InjectedConnector } from '@web3-react/injected-connector'
import { WalletConnectConnector } from '@web3-react/walletconnect-connector'
import { WalletLinkConnector } from '@web3-react/walletlink-connector'
import { PortisConnector } from '@web3-react/portis-connector'
import getLibrary from '../utils/getLibrary'
import { FortmaticConnector } from './Fortmatic'
import { NetworkConnector } from './NetworkConnector'
import UNISWAP_LOGO_URL from '../assets/svg/logo.svg'
const NETWORK_URL = process.env.REACT_APP_NETWORK_URL
const INFURA_KEY = process.env.REACT_APP_INFURA_KEY
const FORMATIC_KEY = process.env.REACT_APP_FORTMATIC_KEY
const PORTIS_ID = process.env.REACT_APP_PORTIS_ID
const WALLETCONNECT_BRIDGE_URL = process.env.REACT_APP_WALLETCONNECT_BRIDGE_URL
export const NETWORK_CHAIN_ID: number = parseInt(process.env.REACT_APP_CHAIN_ID ?? '1')
if (typeof NETWORK_URL === 'undefined') {
throw new Error(`REACT_APP_NETWORK_URL must be a defined environment variable`)
if (typeof INFURA_KEY === 'undefined') {
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
}
const NETWORK_URLS: {
[chainId in ChainId]: string
} = {
[ChainId.MAINNET]: `https://mainnet.infura.io/v3/${INFURA_KEY}`,
[ChainId.RINKEBY]: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
[ChainId.ROPSTEN]: `https://ropsten.infura.io/v3/${INFURA_KEY}`,
[ChainId.GÖRLI]: `https://goerli.infura.io/v3/${INFURA_KEY}`,
[ChainId.KOVAN]: `https://kovan.infura.io/v3/${INFURA_KEY}`,
}
const SUPPORTED_CHAIN_IDS = [ChainId.MAINNET, ChainId.RINKEBY, ChainId.ROPSTEN, ChainId.KOVAN, ChainId.GÖRLI]
export const network = new NetworkConnector({
urls: { [NETWORK_CHAIN_ID]: NETWORK_URL },
urls: NETWORK_URLS,
defaultChainId: ChainId.MAINNET,
})
let networkLibrary: Web3Provider | undefined
export function getNetworkLibrary(): Web3Provider {
return (networkLibrary = networkLibrary ?? new Web3Provider(network.provider as any))
return (networkLibrary = networkLibrary ?? getLibrary(network.provider))
}
export const injected = new InjectedConnector({
supportedChainIds: [1, 3, 4, 5, 42],
supportedChainIds: SUPPORTED_CHAIN_IDS,
})
// mainnet only
export const walletconnect = new WalletConnectConnector({
rpc: { 1: NETWORK_URL },
supportedChainIds: SUPPORTED_CHAIN_IDS,
infuraId: INFURA_KEY, // obviously a hack
bridge: WALLETCONNECT_BRIDGE_URL,
qrcode: true,
pollingInterval: 15000,
@@ -54,7 +67,7 @@ export const portis = new PortisConnector({
// mainnet only
export const walletlink = new WalletLinkConnector({
url: NETWORK_URL,
url: NETWORK_URLS[ChainId.MAINNET],
appName: 'Uniswap',
appLogoUrl: UNISWAP_LOGO_URL,
})

View File

@@ -0,0 +1,22 @@
import { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { AppDispatch } from 'state'
import { updateUserExpertMode } from '../state/user/actions'
import useParsedQueryString from './useParsedQueryString'
export default function ApeModeQueryParamReader(): null {
useApeModeQueryParamReader()
return null
}
function useApeModeQueryParamReader() {
const dispatch = useDispatch<AppDispatch>()
const { ape } = useParsedQueryString()
useEffect(() => {
if (typeof ape !== 'string') return
if (ape === '' || ape.toLowerCase() === 'true') {
dispatch(updateUserExpertMode({ userExpertMode: true }))
}
})
}

View File

@@ -3,7 +3,7 @@ import { ChainId } from '@uniswap/sdk-core'
import { TokenList } from '@uniswap/token-lists'
import { useCallback } from 'react'
import { useDispatch } from 'react-redux'
import { getNetworkLibrary, NETWORK_CHAIN_ID } from '../connectors'
import { getNetworkLibrary } from '../connectors'
import { AppDispatch } from '../state'
import { fetchTokenList } from '../state/lists/actions'
import getTokenList from '../utils/getTokenList'
@@ -15,13 +15,12 @@ export function useFetchListCallback(): (listUrl: string, sendDispatch?: boolean
const dispatch = useDispatch<AppDispatch>()
const ensResolver = useCallback(
(ensName: string) => {
async (ensName: string) => {
if (!library || chainId !== ChainId.MAINNET) {
if (NETWORK_CHAIN_ID === ChainId.MAINNET) {
const networkLibrary = getNetworkLibrary()
if (networkLibrary) {
return resolveENSContentHash(ensName, networkLibrary)
}
const networkLibrary = getNetworkLibrary()
const network = await networkLibrary.getNetwork()
if (networkLibrary && network.chainId === ChainId.MAINNET) {
return resolveENSContentHash(ensName, networkLibrary)
}
throw new Error('Could not construct mainnet ENS resolver')
}

View File

@@ -133,6 +133,49 @@ function useSwapCallArguments(
}, [account, allowedSlippage, chainId, deadline, library, recipient, routerContract, signatureData, trade])
}
/**
* This is hacking out the revert reason from the ethers provider thrown error however it can.
* This object seems to be undocumented by ethers.
* @param error an error from the ethers provider
*/
export function swapErrorToUserReadableMessage(error: any): string {
let reason: string | undefined
while (Boolean(error)) {
reason = error.reason ?? error.message ?? reason
error = error.error ?? error.data?.originalError
}
if (reason?.indexOf('execution reverted: ') === 0) reason = reason.substr('execution reverted: '.length)
switch (reason) {
case 'UniswapV2Router: EXPIRED':
return 'The transaction could not be sent because the deadline has passed. Please check that your transaction deadline is not too low.'
case 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT':
case 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT':
return 'This transaction will not succeed either due to price movement or fee on transfer. Try increasing your slippage tolerance.'
case 'TransferHelper: TRANSFER_FROM_FAILED':
return 'The input token cannot be transferred. There may be an issue with the input token.'
case 'UniswapV2: TRANSFER_FAILED':
return 'The output token cannot be transferred. There may be an issue with the output token.'
case 'UniswapV2: K':
return 'The Uniswap invariant x*y=k was not satisfied by the swap. This usually means one of the tokens you are swapping incorporates custom behavior on transfer.'
case 'Too little received':
case 'Too much requested':
case 'STF':
return 'This transaction will not succeed due to price movement. Try increasing your slippage tolerance. Note fee on transfer and rebase tokens are incompatible with Uniswap V3.'
case 'TF':
return 'The output token cannot be transferred. There may be an issue with the output token. Note fee on transfer and rebase tokens are incompatible with Uniswap V3.'
default:
if (reason?.indexOf('undefined is not an object') !== -1) {
console.error(error, reason)
return 'An error occurred when trying to execute this swap. You may need to increase your slippage tolerance. If that does not work, there may be an incompatibility with the token you are trading. Note fee on transfer and rebase tokens are incompatible with Uniswap V3.'
}
return `Unknown error${
reason ? `: "${reason}"` : ''
}. Try increasing your slippage tolerance. Note fee on transfer and rebase tokens are incompatible with Uniswap V3.`
}
}
// returns a function that will execute a swap, if the parameters are all valid
// and the user has approved the slippage adjusted input amount for the trade
export function useSwapCallback(
@@ -198,28 +241,7 @@ export function useSwapCallback(
})
.catch((callError) => {
console.debug('Call threw error', call, callError)
let errorMessage: string
switch (callError.reason) {
case 'UniswapV2Router: EXPIRED':
errorMessage =
'The transaction could not be sent because the deadline has passed. Please check that your transaction deadline is not too low.'
break
case 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT':
case 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT':
errorMessage =
'This transaction will not succeed either due to price movement or fee on transfer. Try increasing your slippage tolerance.'
break
case 'UniswapV2: TRANSFER_FAILED':
errorMessage = 'The token could not be transferred. There may be an issue with the token.'
break
case 'UniswapV2: K':
errorMessage =
'The Uniswap invariant x*y=k was not satisfied by the swap. This usually means one of the tokens you are swapping incorporates custom behavior on transfer.'
break
default:
return { call }
}
return { call, error: new Error(errorMessage) }
return { call, error: new Error(swapErrorToUserReadableMessage(callError)) }
})
})
})
@@ -259,8 +281,8 @@ export function useSwapCallback(
.then((response) => {
const inputSymbol = trade.inputAmount.currency.symbol
const outputSymbol = trade.outputAmount.currency.symbol
const inputAmount = trade.maximumAmountIn(allowedSlippage).toSignificant(4)
const outputAmount = trade.minimumAmountOut(allowedSlippage).toSignificant(4)
const inputAmount = trade.inputAmount.toSignificant(4)
const outputAmount = trade.outputAmount.toSignificant(4)
const base = `Swap ${inputAmount} ${inputSymbol} for ${outputAmount} ${outputSymbol}`
const withRecipient =
@@ -289,11 +311,12 @@ export function useSwapCallback(
} else {
// otherwise, the error was unexpected and we need to convey that
console.error(`Swap failed`, error, address, calldata, value)
throw new Error(`Swap failed: ${error.message}`)
throw new Error(`Swap failed: ${swapErrorToUserReadableMessage(error)}`)
}
})
},
error: null,
}
}, [trade, library, account, chainId, recipient, recipientAddressOrName, swapCalls, allowedSlippage, addTransaction])
}, [trade, library, account, chainId, recipient, recipientAddressOrName, swapCalls, addTransaction])
}

View File

@@ -56,7 +56,9 @@ export default function useUSDCPrice(currency?: Currency): Price<Currency, Token
const ethPairETHAmount = ethPair?.reserveOf(weth)
const ethPairETHUSDCValue: JSBI =
ethPairETHAmount && usdcEthPair ? usdcEthPair.priceOf(weth).quote(ethPairETHAmount).quotient : JSBI.BigInt(0)
ethPairETHAmount?.greaterThan(0) && usdcEthPair?.reserveOf(weth)?.greaterThan(0)
? usdcEthPair.priceOf(weth).quote(ethPairETHAmount).quotient
: JSBI.BigInt(0)
// all other tokens
// first try the usdc pair
@@ -81,6 +83,10 @@ export function useUSDCValue(currencyAmount: CurrencyAmount<Currency> | undefine
return useMemo(() => {
if (!price || !currencyAmount) return null
return price.quote(currencyAmount)
try {
return price.quote(currencyAmount)
} catch (error) {
return null
}
}, [currencyAmount, price])
}

View File

@@ -3,16 +3,18 @@ import { useEffect, useState } from 'react'
import { useV3NFTPositionManagerContract } from './useContract'
import { BigNumber } from '@ethersproject/bignumber'
import { Pool } from '@uniswap/v3-sdk'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { CurrencyAmount, Token, currencyEquals, ETHER, Ether } from '@uniswap/sdk-core'
import { useBlockNumber } from 'state/application/hooks'
import { unwrappedToken } from 'utils/wrappedCurrency'
const MAX_UINT128 = BigNumber.from(2).pow(128).sub(1)
// compute current + counterfactual fees for a v3 position
export function useV3PositionFees(
pool?: Pool,
tokenId?: BigNumber
): [CurrencyAmount<Token>, CurrencyAmount<Token>] | [undefined, undefined] {
tokenId?: BigNumber,
asWETH = false
): [CurrencyAmount<Token | Ether>, CurrencyAmount<Token | Ether>] | [undefined, undefined] {
const positionManager = useV3NFTPositionManagerContract(false)
const owner = useSingleCallResult(tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
@@ -43,8 +45,12 @@ export function useV3PositionFees(
if (pool && amounts) {
return [
CurrencyAmount.fromRawAmount(pool.token0, amounts[0].toString()),
CurrencyAmount.fromRawAmount(pool.token1, amounts[1].toString()),
!asWETH && currencyEquals(unwrappedToken(pool.token0), ETHER)
? CurrencyAmount.ether(amounts[0].toString())
: CurrencyAmount.fromRawAmount(pool.token0, amounts[0].toString()),
!asWETH && currencyEquals(unwrappedToken(pool.token1), ETHER)
? CurrencyAmount.ether(amounts[1].toString())
: CurrencyAmount.fromRawAmount(pool.token1, amounts[1].toString()),
]
} else {
return [undefined, undefined]

View File

@@ -2,7 +2,7 @@ import React from 'react'
import { Field } from '../../state/mint/v3/actions'
import { AutoColumn } from 'components/Column'
import Card from 'components/Card'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk'
import { PositionPreview } from 'components/PositionPreview'

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AutoColumn } from 'components/Column'
import CurrencyInputPanel from 'components/CurrencyInputPanel'
import { DarkGreyCard } from 'components/Card'

View File

@@ -1,6 +1,6 @@
import React, { Suspense } from 'react'
import { Route, Switch } from 'react-router-dom'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import GoogleAnalyticsReporter from '../components/analytics/GoogleAnalyticsReporter'
import AddressClaimModal from '../components/claim/AddressClaimModal'
import Header from '../components/Header'
@@ -29,6 +29,7 @@ import { RedirectDuplicateTokenIdsV2 } from './AddLiquidityV2/redirects'
import { PositionPage } from './Pool/PositionPage'
import AddLiquidity from './AddLiquidity'
import { ThemedBackground } from '../theme'
import ApeModeQueryParamReader from 'hooks/useApeModeQueryParamReader'
const AppWrapper = styled.div`
display: flex;
@@ -76,6 +77,7 @@ export default function App() {
<Suspense fallback={null}>
<Route component={GoogleAnalyticsReporter} />
<Route component={DarkModeQueryParamReader} />
<Route component={ApeModeQueryParamReader} />
<AppWrapper>
<HeaderWrapper>
<Header />

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
export const BodyWrapper = styled.div<{ margin?: string }>`
position: relative;

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useState } from 'react'
import { AutoColumn } from '../../components/Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { Link } from 'react-router-dom'
import JSBI from 'jsbi'
import { Token, CurrencyAmount } from '@uniswap/sdk-core'

View File

@@ -1,7 +1,7 @@
import JSBI from 'jsbi'
import React from 'react'
import { AutoColumn } from '../../components/Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { STAKING_REWARDS_INFO, useStakingInfo } from '../../state/stake/hooks'
import { TYPE, ExternalLink } from '../../theme'
import PoolCard from '../../components/earn/PoolCard'

View File

@@ -208,6 +208,7 @@ function V2PairMigration({
tickUpper,
amount0: token0Value.quotient,
amount1: token1Value.quotient,
useFullPrecision: false, // we don't want full precision as this is used to calculate slippage amounts
})
: undefined

View File

@@ -1,5 +1,5 @@
import React from 'react'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { useTranslation } from 'react-i18next'
import { ExternalLink } from '../../theme'

View File

@@ -1,14 +1,14 @@
import React, { SyntheticEvent, useCallback, useMemo, useRef, useState } from 'react'
import React, { useCallback, useMemo, useRef, useState } from 'react'
import { NonfungiblePositionManager, Pool, Position } from '@uniswap/v3-sdk'
import { PoolState, usePool } from 'hooks/usePools'
import { useToken } from 'hooks/Tokens'
import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
import { Link, RouteComponentProps } from 'react-router-dom'
import { unwrappedToken } from 'utils/wrappedCurrency'
import { unwrappedToken, wrappedCurrencyAmount } from 'utils/wrappedCurrency'
import { usePositionTokenURI } from '../../hooks/usePositionTokenURI'
import { LoadingRows } from './styleds'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { AutoColumn } from 'components/Column'
import { RowBetween, RowFixed } from 'components/Row'
import DoubleCurrencyLogo from 'components/DoubleLogo'
@@ -23,7 +23,7 @@ import { currencyId } from 'utils/currencyId'
import { formatTokenAmount } from 'utils/formatTokenAmount'
import { useV3PositionFees } from 'hooks/useV3PositionFees'
import { BigNumber } from '@ethersproject/bignumber'
import { Token, WETH9, Currency, CurrencyAmount, Percent, Fraction, Price, currencyEquals } from '@uniswap/sdk-core'
import { Token, Currency, CurrencyAmount, Percent, Fraction, Price, Ether } from '@uniswap/sdk-core'
import { useActiveWeb3React } from 'hooks'
import { useV3NFTPositionManagerContract } from 'hooks/useContract'
import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks'
@@ -38,6 +38,7 @@ import { useSingleCallResult } from 'state/multicall/hooks'
import RangeBadge from '../../components/Badge/RangeBadge'
import useUSDCPrice from 'hooks/useUSDCPrice'
import Loader from 'components/Loader'
import Toggle from 'components/Toggle'
const PageWrapper = styled.div`
min-width: 800px;
@@ -200,20 +201,11 @@ function getRatio(
}
}
function NFT({ image, height: targetHeight }: { image: string; height: number }) {
const [animate, setAnimate] = useState(false)
const canvasRef = useRef<HTMLCanvasElement>()
const imageRef = useRef<HTMLImageElement>()
const getSnapshot = (src: HTMLImageElement) => {
if (!canvasRef.current) return
const { current: canvas } = canvasRef
const context = canvas.getContext('2d')
if (!context) return
// snapshots a src img into a canvas
function getSnapshot(src: HTMLImageElement, canvas: HTMLCanvasElement, targetHeight: number) {
const context = canvas.getContext('2d')
if (context) {
let { width, height } = src
// src may be hidden and not have the target dimensions
@@ -231,15 +223,39 @@ function NFT({ image, height: targetHeight }: { image: string; height: number })
context.clearRect(0, 0, width, height)
context.drawImage(src, 0, 0, width, height)
}
}
const onLoad = (e: SyntheticEvent<HTMLImageElement>) => {
getSnapshot(e.target as HTMLImageElement)
}
function NFT({ image, height: targetHeight }: { image: string; height: number }) {
const [animate, setAnimate] = useState(false)
const canvasRef = useRef<HTMLCanvasElement>(null)
const imageRef = useRef<HTMLImageElement>(null)
return (
<NFTGrid onMouseEnter={() => setAnimate(true)} onMouseLeave={() => setAnimate(false)}>
<NFTCanvas ref={canvasRef as any} />
<NFTImage src={image} hidden={!animate} onLoad={onLoad} ref={imageRef as any} />
<NFTGrid
onMouseEnter={() => {
setAnimate(true)
}}
onMouseLeave={() => {
// snapshot the current frame so the transition to the canvas is smooth
if (imageRef.current && canvasRef.current) {
getSnapshot(imageRef.current, canvasRef.current, targetHeight)
}
setAnimate(false)
}}
>
<NFTCanvas ref={canvasRef} />
<NFTImage
ref={imageRef}
src={image}
hidden={!animate}
onLoad={() => {
// snapshot for the canvas
if (imageRef.current && canvasRef.current) {
getSnapshot(imageRef.current, canvasRef.current, targetHeight)
}
}}
/>
</NFTGrid>
)
}
@@ -269,8 +285,11 @@ export function PositionPage({
const currency0 = token0 ? unwrappedToken(token0) : undefined
const currency1 = token1 ? unwrappedToken(token1) : undefined
// flag for receiving WETH
const [receiveWETH, setReceiveWETH] = useState(false)
// construct Position from details returned
const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount)
const [poolState, pool] = usePool(token0 ?? undefined, token1 ?? undefined, feeAmount)
const position = useMemo(() => {
if (pool && liquidity && typeof tickLower === 'number' && typeof tickUpper === 'number') {
return new Position({ pool, liquidity: liquidity.toString(), tickLower, tickUpper })
@@ -304,7 +323,7 @@ export function PositionPage({
}, [inverted, pool, priceLower, priceUpper])
// fees
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails?.tokenId)
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails?.tokenId, receiveWETH)
const [collecting, setCollecting] = useState<boolean>(false)
const [collectMigrationHash, setCollectMigrationHash] = useState<string | null>(null)
@@ -320,12 +339,8 @@ export function PositionPage({
const { calldata, value } = NonfungiblePositionManager.collectCallParameters({
tokenId: tokenId.toString(),
expectedCurrencyOwed0: currencyEquals(feeValue0.currency, WETH9[chainId])
? CurrencyAmount.ether(feeValue0.quotient)
: feeValue0,
expectedCurrencyOwed1: currencyEquals(feeValue1.currency, WETH9[chainId])
? CurrencyAmount.ether(feeValue1.quotient)
: feeValue1,
expectedCurrencyOwed0: feeValue0,
expectedCurrencyOwed1: feeValue1,
recipient: account,
})
@@ -371,15 +386,23 @@ export function PositionPage({
const owner = useSingleCallResult(!!tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
const ownsNFT = owner === account || positionDetails?.operator === account
// usdc prices always in terms of tokens
const price0 = useUSDCPrice(token0 ?? undefined)
const price1 = useUSDCPrice(token1 ?? undefined)
const fiatValueOfFees: CurrencyAmount<Token> | null = useMemo(() => {
const fiatValueOfFees: CurrencyAmount<Token | Ether> | null = useMemo(() => {
if (!price0 || !price1 || !feeValue0 || !feeValue1) return null
const amount0 = price0.quote(feeValue0)
const amount1 = price1.quote(feeValue1)
// we wrap because it doesn't matter, the quote returns a USDC amount
const feeValue0Wrapped = wrappedCurrencyAmount(feeValue0, chainId)
const feeValue1Wrapped = wrappedCurrencyAmount(feeValue1, chainId)
if (!feeValue0Wrapped || !feeValue1Wrapped) return null
const amount0 = price0.quote(feeValue0Wrapped)
const amount1 = price1.quote(feeValue1Wrapped)
return amount0.add(amount1)
}, [price0, price1, feeValue0, feeValue1])
}, [price0, price1, feeValue0, feeValue1, chainId])
const fiatValueOfLiquidity: CurrencyAmount<Token> | null = useMemo(() => {
if (!price0 || !price1 || !position) return null
@@ -388,6 +411,9 @@ export function PositionPage({
return amount0.add(amount1)
}, [price0, price1, position])
const feeValueUpper = inverted ? feeValue0 : feeValue1
const feeValueLower = inverted ? feeValue1 : feeValue0
function modalHeader() {
return (
<AutoColumn gap={'md'} style={{ marginTop: '20px' }}>
@@ -395,33 +421,17 @@ export function PositionPage({
<AutoColumn gap="md">
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyQuote} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>
{inverted
? feeValue0
? formatTokenAmount(feeValue0, 4)
: '-'
: feeValue1
? formatTokenAmount(feeValue1, 4)
: '-'}
</TYPE.main>
<CurrencyLogo currency={feeValueUpper?.currency} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{feeValueUpper ? formatTokenAmount(feeValueUpper, 4) : '-'}</TYPE.main>
</RowFixed>
<TYPE.main>{currencyQuote?.symbol}</TYPE.main>
<TYPE.main>{feeValueUpper?.currency?.symbol}</TYPE.main>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyBase} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>
{inverted
? feeValue0
? formatTokenAmount(feeValue1, 4)
: '-'
: feeValue1
? formatTokenAmount(feeValue0, 4)
: '-'}
</TYPE.main>
<CurrencyLogo currency={feeValueLower?.currency} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{feeValueLower ? formatTokenAmount(feeValueLower, 4) : '-'}</TYPE.main>
</RowFixed>
<TYPE.main>{currencyBase?.symbol}</TYPE.main>
<TYPE.main>{feeValueLower?.currency?.symbol}</TYPE.main>
</RowBetween>
</AutoColumn>
</LightCard>
@@ -640,40 +650,44 @@ export function PositionPage({
<AutoColumn gap="md">
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyQuote} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{currencyQuote?.symbol}</TYPE.main>
<CurrencyLogo
currency={feeValueUpper?.currency}
size={'20px'}
style={{ marginRight: '0.5rem' }}
/>
<TYPE.main>{feeValueUpper?.currency?.symbol}</TYPE.main>
</RowFixed>
<RowFixed>
<TYPE.main>
{inverted
? feeValue0
? formatTokenAmount(feeValue0, 4)
: '-'
: feeValue1
? formatTokenAmount(feeValue1, 4)
: '-'}
</TYPE.main>
<TYPE.main>{feeValueUpper ? formatTokenAmount(feeValueUpper, 4) : '-'}</TYPE.main>
</RowFixed>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyBase} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{currencyBase?.symbol}</TYPE.main>
<CurrencyLogo
currency={feeValueLower?.currency}
size={'20px'}
style={{ marginRight: '0.5rem' }}
/>
<TYPE.main>{feeValueLower?.currency?.symbol}</TYPE.main>
</RowFixed>
<RowFixed>
<TYPE.main>
{inverted
? feeValue0
? formatTokenAmount(feeValue1, 4)
: '-'
: feeValue1
? formatTokenAmount(feeValue0, 4)
: '-'}
</TYPE.main>
<TYPE.main>{feeValueLower ? formatTokenAmount(feeValueLower, 4) : '-'}</TYPE.main>
</RowFixed>
</RowBetween>
</AutoColumn>
</LightCard>
{ownsNFT && (feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) && !collectMigrationHash ? (
<AutoColumn gap="md">
<RowBetween>
<TYPE.main>Collect as WETH</TYPE.main>
<Toggle
id="receive-as-weth"
isActive={receiveWETH}
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
/>
</RowBetween>
</AutoColumn>
) : null}
</AutoColumn>
</DarkCard>
</AutoColumn>

View File

@@ -21,12 +21,10 @@ import ReactGA from 'react-ga'
import { useActiveWeb3React } from 'hooks'
import { TransactionResponse } from '@ethersproject/providers'
import { useTransactionAdder } from 'state/transactions/hooks'
import { WETH9, CurrencyAmount, currencyEquals, Percent } from '@uniswap/sdk-core'
import { Percent } from '@uniswap/sdk-core'
import { TYPE } from 'theme'
import { Wrapper, SmallMaxButton, ResponsiveHeaderText } from './styled'
import Loader from 'components/Loader'
import { useToken } from 'hooks/Tokens'
import { unwrappedToken } from 'utils/wrappedCurrency'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { Break } from 'components/earn/styled'
import { NonfungiblePositionManager } from '@uniswap/v3-sdk'
@@ -34,6 +32,7 @@ import { calculateGasMargin } from 'utils'
import useTheme from 'hooks/useTheme'
import { AddRemoveTabs } from 'components/NavigationTabs'
import RangeBadge from 'components/Badge/RangeBadge'
import Toggle from 'components/Toggle'
export const UINT128MAX = BigNumber.from(2).pow(128).sub(1)
@@ -65,11 +64,8 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
const theme = useTheme()
const { account, chainId, library } = useActiveWeb3React()
// currencies from position
const token0 = useToken(position?.token0)
const token1 = useToken(position?.token1)
const currency0 = token0 ? unwrappedToken(token0) : undefined
const currency1 = token1 ? unwrappedToken(token1) : undefined
// flag for receiving WETH
const [receiveWETH, setReceiveWETH] = useState(false)
// burn state
const { percent } = useBurnV3State()
@@ -82,7 +78,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
feeValue1,
outOfRange,
error,
} = useDerivedV3BurnInfo(position)
} = useDerivedV3BurnInfo(position, receiveWETH)
const { onPercentSelect } = useBurnV3ActionHandlers()
const removed = position?.liquidity?.eq(0)
@@ -122,12 +118,8 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
slippageTolerance: allowedSlippage,
deadline: deadline.toString(),
collectOptions: {
expectedCurrencyOwed0: currencyEquals(liquidityValue0.currency, WETH9[chainId])
? CurrencyAmount.ether(feeValue0.quotient)
: feeValue0,
expectedCurrencyOwed1: currencyEquals(liquidityValue1.currency, WETH9[chainId])
? CurrencyAmount.ether(feeValue1.quotient)
: feeValue1,
expectedCurrencyOwed0: feeValue0,
expectedCurrencyOwed1: feeValue1,
recipient: account,
},
})
@@ -195,32 +187,32 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
}, [onPercentSelectForSlider, txnHash])
const pendingText = `Removing ${liquidityValue0?.toSignificant(6)} ${
currency0?.symbol
} and ${liquidityValue1?.toSignificant(6)} ${currency1?.symbol}`
liquidityValue0?.currency?.symbol
} and ${liquidityValue1?.toSignificant(6)} ${liquidityValue1?.currency?.symbol}`
function modalHeader() {
return (
<AutoColumn gap={'sm'} style={{ padding: '16px' }}>
<RowBetween align="flex-end">
<Text fontSize={16} fontWeight={500}>
{currency0?.symbol}:
Pooled {liquidityValue0?.currency?.symbol}:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue0?.currency} />
</RowFixed>
</RowBetween>
<RowBetween align="flex-end">
<Text fontSize={16} fontWeight={500}>
{currency1?.symbol}:
Pooled {liquidityValue1?.currency?.symbol}:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue1?.currency} />
</RowFixed>
</RowBetween>
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) ? (
@@ -230,24 +222,24 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
</TYPE.italic>
<RowBetween>
<Text fontSize={16} fontWeight={500}>
{currency0?.symbol} from fees:
{feeValue0?.currency?.symbol} Fees Earned:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue0?.currency} />
</RowFixed>
</RowBetween>
<RowBetween>
<Text fontSize={16} fontWeight={500}>
{currency1?.symbol} from fees:
{feeValue1?.currency?.symbol} Fees Earned:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue1?.currency} />
</RowFixed>
</RowBetween>
</>
@@ -287,8 +279,16 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
<AutoColumn gap="lg">
<RowBetween>
<RowFixed>
<DoubleCurrencyLogo currency0={currency1} currency1={currency0} size={20} margin={true} />
<TYPE.label ml="10px" fontSize="20px">{`${currency0?.symbol}/${currency1?.symbol}`}</TYPE.label>
<DoubleCurrencyLogo
currency0={feeValue0?.currency}
currency1={feeValue1?.currency}
size={20}
margin={true}
/>
<TYPE.label
ml="10px"
fontSize="20px"
>{`${feeValue0?.currency?.symbol}/${feeValue1?.currency?.symbol}`}</TYPE.label>
</RowFixed>
<RangeBadge removed={removed} inRange={!outOfRange} />
</RowBetween>
@@ -319,24 +319,24 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
<AutoColumn gap="md">
<RowBetween>
<Text fontSize={16} fontWeight={500}>
Pooled {currency0?.symbol}:
Pooled {liquidityValue0?.currency?.symbol}:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue0?.currency} />
</RowFixed>
</RowBetween>
<RowBetween>
<Text fontSize={16} fontWeight={500}>
Pooled {currency1?.symbol}:
Pooled {liquidityValue1?.currency?.symbol}:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue1?.currency} />
</RowFixed>
</RowBetween>
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) ? (
@@ -344,30 +344,40 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
<Break />
<RowBetween>
<Text fontSize={16} fontWeight={500}>
{currency0?.symbol} Fees Earned:
{feeValue0?.currency?.symbol} Fees Earned:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue0?.currency} />
</RowFixed>
</RowBetween>
<RowBetween>
<Text fontSize={16} fontWeight={500}>
{currency1?.symbol} Fees Earned:
{feeValue1?.currency?.symbol} Fees Earned:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue1?.currency} />
</RowFixed>
</RowBetween>
</>
) : null}
</AutoColumn>
</LightCard>
<RowBetween>
<TYPE.main>Collect as WETH</TYPE.main>
<Toggle
id="receive-as-weth"
isActive={receiveWETH}
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
/>
</RowBetween>
<div style={{ display: 'flex' }}>
<AutoColumn gap="12px" style={{ flex: '1' }}>
<ButtonConfirmed

View File

@@ -1,6 +1,6 @@
import { MaxButton } from 'pages/Pool/styleds'
import { Text } from 'rebass'
import styled from 'styled-components'
import styled from 'styled-components/macro'
export const Wrapper = styled.div`
position: relative;

View File

@@ -49,7 +49,6 @@ import {
import { useExpertModeManager, useUserSingleHopOnly } from '../../state/user/hooks'
import { HideSmall, LinkStyledButton, TYPE } from '../../theme'
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
import { computePriceImpactWithMaximumSlippage } from '../../utils/computePriceImpactWithMaximumSlippage'
import { getTradeVersion } from '../../utils/getTradeVersion'
import { isTradeBetter } from '../../utils/isTradeBetter'
import { maxAmountSpend } from '../../utils/maxAmountSpend'
@@ -132,10 +131,10 @@ export default function Swap({ history }: RouteComponentProps) {
[Field.OUTPUT]: parsedAmount,
}
: {
[Field.INPUT]: independentField === Field.INPUT ? parsedAmount : trade?.maximumAmountIn(allowedSlippage),
[Field.OUTPUT]: independentField === Field.OUTPUT ? parsedAmount : trade?.minimumAmountOut(allowedSlippage),
[Field.INPUT]: independentField === Field.INPUT ? parsedAmount : trade?.inputAmount,
[Field.OUTPUT]: independentField === Field.OUTPUT ? parsedAmount : trade?.outputAmount,
},
[allowedSlippage, independentField, parsedAmount, showWrap, trade]
[independentField, parsedAmount, showWrap, trade]
)
const fiatValueInput = useUSDCValue(parsedAmounts[Field.INPUT])
@@ -292,7 +291,7 @@ export default function Swap({ history }: RouteComponentProps) {
// warnings on the greater of fiat value price impact and execution price impact
const priceImpactSeverity = useMemo(() => {
const executionPriceImpact = trade ? computePriceImpactWithMaximumSlippage(trade, allowedSlippage) : undefined
const executionPriceImpact = trade?.priceImpact
return warningSeverity(
executionPriceImpact && priceImpact
? executionPriceImpact.greaterThan(priceImpact)
@@ -300,7 +299,7 @@ export default function Swap({ history }: RouteComponentProps) {
: priceImpact
: executionPriceImpact ?? priceImpact
)
}, [allowedSlippage, priceImpact, trade])
}, [priceImpact, trade])
// 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
@@ -475,7 +474,7 @@ export default function Swap({ history }: RouteComponentProps) {
{trade ? (
<RowFixed>
<TradePrice
price={trade.worstExecutionPrice(allowedSlippage)}
price={trade.executionPrice}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
@@ -526,12 +525,12 @@ export default function Swap({ history }: RouteComponentProps) {
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
}
>
<AutoRow justify="space-between">
<AutoRow justify="space-between" style={{ flexWrap: 'nowrap' }}>
<span style={{ display: 'flex', alignItems: 'center' }}>
<CurrencyLogo
currency={currencies[Field.INPUT]}
size={'20px'}
style={{ marginRight: '8px' }}
style={{ marginRight: '8px', flexShrink: 0 }}
/>
{/* we need to shorten this string on mobile */}
{approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
@@ -551,7 +550,7 @@ export default function Swap({ history }: RouteComponentProps) {
'. You only have to do this once per token.'
}
>
<HelpCircle size="20" color={'white'} />
<HelpCircle size="20" color={'white'} style={{ marginLeft: '8px' }} />
</MouseoverTooltip>
)}
</AutoRow>

View File

@@ -1,6 +1,6 @@
import React, { useState } from 'react'
import { AutoColumn } from '../../components/Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { RouteComponentProps } from 'react-router-dom'
import { ExternalLink, StyledInternalLink, TYPE } from '../../theme'

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { AutoColumn } from '../../components/Column'
import styled from 'styled-components'
import styled from 'styled-components/macro'
import { ExternalLink, TYPE } from '../../theme'
import { RowBetween, RowFixed } from '../../components/Row'
import { Link } from 'react-router-dom'

View File

@@ -1,4 +1,4 @@
import styled from 'styled-components'
import styled from 'styled-components/macro'
export const StandardPageWrapper = styled.div`
padding-top: 160px;

Some files were not shown because too many files have changed in this diff Show More