Compare commits

...

41 Commits

Author SHA1 Message Date
Moody Salem
46911593e5 fix: removing and adding liquidity when the price of the pool is at the min/max price
fixes https://github.com/Uniswap/uniswap-interface/issues/1641
2021-05-18 19:17:05 -05:00
Justin Domingue
1ac36c7b6b fix: display pool shares < 10% (#1639)
* fix: display pool shares < 10%

* set bips to 1/10_000
2021-05-18 17:07:06 -05:00
Moody Salem
8e055df447 refactor: make the price computation in v2 add liquidity a little safer 2021-05-18 16:06:54 -05:00
Moody Salem
02ecd727eb fix: do not crash when user switches eth -> weth in add (#1637)
* fix: do not crash when user switches eth -> weth in add

* linting error
2021-05-18 16:52:34 -04:00
Moody Salem
adc8429bdc fix: working copy to clipboard button in walletconnect qr code modal (#1636)
fixes https://github.com/Uniswap/uniswap-interface/issues/1488
2021-05-18 15:22:53 -05:00
Moody Salem
458d34d96c give the check a name 2021-05-18 15:14:33 -05:00
Justin Domingue
6a4fa0c9bf fix: division by 0 error when both reserves are 0 (#1632)
* set pair to invalid if both reserves are 0

* consider reserve0/1=0 as no liquidity
2021-05-18 12:50:28 -07:00
Moody Salem
7fc9a655fc fix: improve rendering of fee dollar values 2021-05-18 14:35:02 -05:00
Moody Salem
8d3babd015 refactor: more separation by chain of addresses 2021-05-18 14:33:03 -05:00
Moody Salem
75ed4c5dae fix: missed a memo for fetching v2 pairs (#1635) 2021-05-18 14:21:06 -05:00
Justin Domingue
58dfadb13c handle custom token overflow (#1634) 2021-05-18 11:32:09 -07:00
Moody Salem
3d5f5f783c chore: check pr titles 2021-05-18 13:26:23 -05:00
jab416171
ecb7132843 Add etherscan links for the two tokens in the pool on the NFT page (#1593)
* Add etherscan links for the two tokens in the pool on the NFT page

* moving linked tokens to a function

added arrow to show that it's a link
added check for eth

* clean up impl

Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
2021-05-18 13:34:20 -04:00
Justin Domingue
980eb8a518 Leverage Trade api for USDC price with v2 & v3 support (#1610)
* calculate usdc price using trade exact out

* fix typo

* add support for non-mainnet

* use fromRawAmount instead of tryParseAmount
2021-05-18 10:07:37 -07:00
Noah Zinsmeister
a11e89c0e1 hide WETH toggle for non-WETH pairs (#1633)
* only show weth toggle for eth pairs

* revert unwrappedToken change
2021-05-18 12:58:42 -04:00
Moody Salem
3efe5268ae refactor: break down some constants files and move some stuff around 2021-05-18 10:31:22 -05:00
Moody Salem
3f43a8fbaf npx not needed 2021-05-18 09:28:30 -05:00
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
144 changed files with 1416 additions and 1292 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"

17
.github/workflows/check-pr-title.yaml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: "Check PR Title"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
check-pr-title:
name: Check PR Title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v3.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

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

@@ -4,7 +4,7 @@ import { createWeb3ReactRoot, Web3ReactProvider } from '@web3-react/core'
import React from 'react'
import { Provider as StoreProvider } from 'react-redux'
import { ThemeProvider as SCThemeProvider } from 'styled-components'
import { NetworkContextName } from '../src/constants'
import { NetworkContextName } from '../src/constants/misc'
import store from '../src/state'
import { FixedGlobalStyle, theme, ThemedGlobalStyle } from '../src/theme'
import getLibrary from '../src/utils/getLibrary'

View File

@@ -27,7 +27,7 @@ or visit [app.uniswap.org](https://app.uniswap.org).
### Install Dependencies
```bash
yarn
yarn install
```
### Run
@@ -36,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

@@ -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.6",
"@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",
@@ -116,10 +116,13 @@
"workbox-routing": "^6.1.0",
"workbox-strategies": "^6.1.0"
},
"resolutions": {
"@walletconnect/web3-provider": "1.4.2-rc.2"
},
"scripts": {
"compile-contract-types": "yarn compile-external-abi-types && yarn compile-v3-contract-types",
"compile-external-abi-types": "npx typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
"compile-v3-contract-types": "npx typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
"compile-external-abi-types": "typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
"compile-v3-contract-types": "typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
"build": "yarn compile-contract-types && react-scripts build",
"integration-test": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run'",
"postinstall": "yarn compile-contract-types",

View File

@@ -1,55 +0,0 @@
[
{
"inputs": [
{
"internalType": "address",
"name": "_factoryV1",
"type": "address"
},
{
"internalType": "address",
"name": "_router",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountTokenMin",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountETHMin",
"type": "uint256"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
}
],
"name": "migrate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]

View File

@@ -1,6 +0,0 @@
import { Interface } from '@ethersproject/abi'
import { abi as STAKING_REWARDS_ABI } from '@uniswap/liquidity-staker/build/StakingRewards.json'
const STAKING_REWARDS_INTERFACE = new Interface(STAKING_REWARDS_ABI)
export { STAKING_REWARDS_INTERFACE }

View File

@@ -2,10 +2,10 @@ import React from 'react'
import styled from 'styled-components/macro'
import { CheckCircle, Triangle } from 'react-feather'
import { useActiveWeb3React } from '../../hooks'
import { getEtherscanLink } from '../../utils'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink } from '../../theme'
import { useAllTransactions } from '../../state/transactions/hooks'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { RowFixed } from '../Row'
import Loader from '../Loader'
@@ -49,7 +49,11 @@ export default function Transaction({ hash }: { hash: string }) {
return (
<TransactionWrapper>
<TransactionState href={getEtherscanLink(chainId, hash, 'transaction')} pending={pending} success={success}>
<TransactionState
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
pending={pending}
success={success}
>
<RowFixed>
<TransactionStatusText>{summary ?? hash} </TransactionStatusText>
</RowFixed>

View File

@@ -1,17 +1,17 @@
import React, { useCallback, useContext } from 'react'
import { useDispatch } from 'react-redux'
import styled, { ThemeContext } from 'styled-components'
import { useActiveWeb3React } from '../../hooks'
import { SUPPORTED_WALLETS } from '../../constants/wallet'
import { useActiveWeb3React } from '../../hooks/web3'
import { AppDispatch } from '../../state'
import { clearAllTransactions } from '../../state/transactions/actions'
import { shortenAddress } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoRow } from '../Row'
import Copy from './Copy'
import Transaction from './Transaction'
import { SUPPORTED_WALLETS } from '../../constants'
import { ReactComponent as Close } from '../../assets/images/x.svg'
import { getEtherscanLink } from '../../utils'
import { injected, walletconnect, walletlink, fortmatic, portis } from '../../connectors'
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
@@ -354,7 +354,7 @@ export default function AccountDetails({
<AddressLink
hasENS={!!ENSName}
isENS={true}
href={chainId && getEtherscanLink(chainId, ENSName, 'address')}
href={chainId && getExplorerLink(chainId, ENSName, ExplorerDataType.ADDRESS)}
>
<LinkIcon size={16} />
<span style={{ marginLeft: '4px' }}>View on Etherscan</span>
@@ -376,7 +376,7 @@ export default function AccountDetails({
<AddressLink
hasENS={!!ENSName}
isENS={false}
href={getEtherscanLink(chainId, account, 'address')}
href={getExplorerLink(chainId, account, ExplorerDataType.ADDRESS)}
>
<LinkIcon size={16} />
<span style={{ marginLeft: '4px' }}>View on Etherscan</span>

View File

@@ -1,11 +1,11 @@
import React, { useContext, useCallback } from 'react'
import styled, { ThemeContext } from 'styled-components'
import useENS from '../../hooks/useENS'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink, TYPE } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn } from '../Column'
import { RowBetween } from '../Row'
import { getEtherscanLink } from '../../utils'
const InputPanel = styled.div`
${({ theme }) => theme.flexColumnNoWrap}
@@ -102,7 +102,10 @@ export default function AddressInputPanel({
Recipient
</TYPE.black>
{address && chainId && (
<ExternalLink href={getEtherscanLink(chainId, name ?? address, 'address')} style={{ fontSize: '14px' }}>
<ExternalLink
href={getExplorerLink(chainId, name ?? address, ExplorerDataType.ADDRESS)}
style={{ fontSize: '14px' }}
>
(View on Etherscan)
</ExternalLink>
)}

View File

@@ -1,6 +1,14 @@
import React, { ReactNode, useMemo } from 'react'
import { BLOCKED_ADDRESSES } from '../../constants'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
// SDN OFAC addresses
const BLOCKED_ADDRESSES: string[] = [
'0x7F367cC41522cE07553e823bf3be79A889DEbe1B',
'0xd882cFc20F52f2599D84b8e8D58C7FB62cfE344b',
'0x901bb9583b24D97e995513C6778dc6888AB6870e',
'0xA7e5d5A720f06526557c513402f2e6B5fA20b008',
'0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C',
]
export default function Blocklist({ children }: { children: ReactNode }) {
const { account } = useActiveWeb3React()

View File

@@ -12,7 +12,7 @@ import { RowBetween, RowFixed } from '../Row'
import { TYPE } from '../../theme'
import { Input as NumericalInput } from '../NumericalInput'
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTranslation } from 'react-i18next'
import useTheme from '../../hooks/useTheme'
import { Lock } from 'react-feather'

View File

@@ -1,6 +1,6 @@
import { Story } from '@storybook/react/types-6-0'
import React from 'react'
import { DAI, WBTC } from '../../constants'
import { DAI, WBTC } from '../../constants/tokens'
import Component, { DoubleCurrencyLogoProps } from './index'
export default {

View File

@@ -1,10 +1,10 @@
import React, { useState, useEffect } from 'react'
import React, { useEffect, useState } from 'react'
import styled, { keyframes } from 'styled-components'
import { TYPE, ExternalLink } from '../../theme'
import { useActiveWeb3React } from '../../hooks/web3'
import { useBlockNumber } from '../../state/application/hooks'
import { getEtherscanLink } from '../../utils'
import { useActiveWeb3React } from '../../hooks'
import { ExternalLink, TYPE } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
const StyledPolling = styled.div`
position: fixed;
@@ -91,7 +91,9 @@ export default function Polling() {
)
return (
<ExternalLink href={chainId && blockNumber ? getEtherscanLink(chainId, blockNumber.toString(), 'block') : ''}>
<ExternalLink
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
>
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
{blockNumber}

View File

@@ -3,9 +3,9 @@ import React, { useMemo } from 'react'
import { X } from 'react-feather'
import styled from 'styled-components/macro'
import tokenLogo from '../../assets/images/token-logo.png'
import { UNI } from '../../constants'
import { UNI } from '../../constants/tokens'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useMerkleDistributorContract } from '../../hooks/useContract'
import useCurrentBlockTimestamp from '../../hooks/useCurrentBlockTimestamp'
import { useTotalUniEarned } from '../../state/stake/hooks'

View File

@@ -11,7 +11,7 @@ import styled from 'styled-components/macro'
import Logo from '../../assets/svg/logo.svg'
import LogoDark from '../../assets/svg/logo_white.svg'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useDarkModeManager } from '../../state/user/hooks'
import { useETHBalances } from '../../state/wallet/hooks'
import { CardNoise } from '../earn/styled'

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useRef } from 'react'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import Jazzicon from 'jazzicon'
const StyledIdenticonContainer = styled.div`

View File

@@ -3,7 +3,7 @@ import { BookOpen, Code, Info, MessageCircle, PieChart } from 'react-feather'
import { Link } from 'react-router-dom'
import styled, { css } from 'styled-components'
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useToggleModal } from '../../state/application/hooks'

View File

@@ -1,5 +1,6 @@
import React, { useContext } from 'react'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn, ColumnCenter } from '../Column'
import styled, { ThemeContext } from 'styled-components'
@@ -8,7 +9,6 @@ import { TYPE, CloseIcon, CustomLightSpinner } from '../../theme'
import { ArrowUpCircle } from 'react-feather'
import Circle from '../../assets/images/blue-loader.svg'
import { getEtherscanLink } from '../../utils'
import { ExternalLink } from '../../theme/components'
const ConfirmOrLoadingWrapper = styled.div`
@@ -62,7 +62,10 @@ export function SubmittedView({
<AutoColumn gap="100px" justify={'center'}>
{children}
{chainId && hash && (
<ExternalLink href={getEtherscanLink(chainId, hash, 'transaction')} style={{ marginLeft: '4px' }}>
<ExternalLink
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
style={{ marginLeft: '4px' }}
>
<TYPE.subHeader>View transaction on Etherscan</TYPE.subHeader>
</ExternalLink>
)}

View File

@@ -4,7 +4,7 @@ import { X } from 'react-feather'
import styled, { keyframes } from 'styled-components'
import tokenLogo from '../../assets/images/token-logo.png'
import { ButtonPrimary } from '../../components/Button'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { ApplicationModal } from '../../state/application/actions'
import {
useModalOpen,

View File

@@ -1,10 +1,10 @@
import React, { useContext } from 'react'
import { AlertCircle, CheckCircle } from 'react-feather'
import styled, { ThemeContext } from 'styled-components'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { TYPE } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { getEtherscanLink } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn } from '../Column'
import { AutoRow } from '../Row'
@@ -33,7 +33,9 @@ export default function TransactionPopup({
<AutoColumn gap="8px">
<TYPE.body fontWeight={500}>{summary ?? 'Hash: ' + hash.slice(0, 8) + '...' + hash.slice(58, 65)}</TYPE.body>
{chainId && (
<ExternalLink href={getEtherscanLink(chainId, hash, 'transaction')}>View on Etherscan</ExternalLink>
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>
View on Etherscan
</ExternalLink>
)}
</AutoColumn>
</RowNoFlex>

View File

@@ -8,7 +8,7 @@ import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/wrappedCurrency'
@@ -24,7 +24,7 @@ import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
import { RowBetween, RowFixed, AutoRow } from '../Row'
import { Dots } from '../swap/styleds'
import { BIG_INT_ZERO } from '../../constants'
import { BIG_INT_ZERO } from '../../constants/misc'
import { FixedHeightRow } from '.'
const StyledPositionCard = styled(LightCard)<{ bgColor: any }>`

View File

@@ -9,7 +9,7 @@ import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { currencyId } from '../../utils/currencyId'
@@ -26,7 +26,7 @@ import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
import { RowBetween, RowFixed, AutoRow } from '../Row'
import { Dots } from '../swap/styleds'
import { BIG_INT_ZERO } from '../../constants'
import { BIG_INT_ZERO } from '../../constants/misc'
export const FixedHeightRow = styled(RowBetween)`
height: 24px;

View File

@@ -12,10 +12,10 @@ import { WETH9, Price, Token, Percent } from '@uniswap/sdk-core'
import { formatPrice } from 'utils/formatTokenAmount'
import Loader from 'components/Loader'
import { unwrappedToken } from 'utils/wrappedCurrency'
import { DAI, USDC, USDT, WBTC } from '../../constants'
import RangeBadge from 'components/Badge/RangeBadge'
import { RowFixed } from 'components/Row'
import HoverInlineText from 'components/HoverInlineText'
import { DAI, USDC, USDT, WBTC } from '../../constants/tokens'
const Row = styled(Link)`
align-items: center;

View File

@@ -2,7 +2,7 @@ import React from 'react'
import { Currency, Price, Token } from '@uniswap/sdk-core'
import StepCounter from 'components/InputStepCounter/InputStepCounter'
import { RowBetween } from 'components/Row'
import { useActiveWeb3React } from 'hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { wrappedCurrency } from 'utils/wrappedCurrency'
// currencyA is the base token

View File

@@ -1,7 +1,7 @@
import React from 'react'
import { Currency } from '@uniswap/sdk-core'
import { ToggleElement, ToggleWrapper } from 'components/Toggle/MultiToggle'
import { useActiveWeb3React } from 'hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { wrappedCurrency } from 'utils/wrappedCurrency'
// the order of displayed base currencies from left to right is always in sort order

View File

@@ -3,7 +3,7 @@ import { Text } from 'rebass'
import { ChainId, Currency, currencyEquals, Token, ETHER } from '@uniswap/sdk-core'
import styled from 'styled-components/macro'
import { SUGGESTED_BASES } from '../../constants'
import { SUGGESTED_BASES } from '../../constants/routing'
import { AutoColumn } from '../Column'
import QuestionHelper from '../QuestionHelper'
import { AutoRow } from '../Row'

View File

@@ -3,7 +3,7 @@ import React, { CSSProperties, MutableRefObject, useCallback, useMemo } from 're
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useCombinedActiveList } from '../../state/lists/hooks'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import { useCurrencyBalance } from '../../state/wallet/hooks'

View File

@@ -4,7 +4,7 @@ import ReactGA from 'react-ga'
import { useTranslation } from 'react-i18next'
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useAllTokens, useToken, useIsUserAddedToken, useSearchInactiveTokenLists } from '../../hooks/Tokens'
import { CloseIcon, TYPE, ButtonText, IconWrapper } from '../../theme'
import { isAddress } from '../../utils'

View File

@@ -13,10 +13,10 @@ import useTheme from 'hooks/useTheme'
import { ButtonPrimary } from 'components/Button'
import { SectionBreak } from 'components/swap/styleds'
import { useAddUserToken } from 'state/user/hooks'
import { getEtherscanLink } from 'utils'
import { useActiveWeb3React } from 'hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { ExternalLink } from '../../theme/components'
import ListLogo from 'components/ListLogo'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { PaddedColumn } from './styleds'
const Wrapper = styled.div`
@@ -93,7 +93,7 @@ export function ImportToken({ tokens, list, onBack, onDismiss, handleCurrencySel
</TYPE.darkGray>
</AutoColumn>
{chainId && (
<ExternalLink href={getEtherscanLink(chainId, token.address, 'address')}>
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
<AddressText fontSize={12}>{token.address}</AddressText>
</ExternalLink>
)}

View File

@@ -1,5 +1,6 @@
import React, { useRef, RefObject, useCallback, useState, useMemo } from 'react'
import Column from 'components/Column'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { PaddedColumn, Separator, SearchInput } from './styleds'
import Row, { RowBetween, RowFixed } from 'components/Row'
import { TYPE, ExternalLinkIcon, TrashIcon, ButtonText, ExternalLink } from 'theme'
@@ -8,8 +9,8 @@ import styled from 'styled-components/macro'
import { useUserAddedTokens, useRemoveUserAddedToken } from 'state/user/hooks'
import { Token } from '@uniswap/sdk-core'
import CurrencyLogo from 'components/CurrencyLogo'
import { getEtherscanLink, isAddress } from 'utils'
import { useActiveWeb3React } from 'hooks'
import { isAddress } from 'utils'
import { useActiveWeb3React } from 'hooks/web3'
import Card from 'components/Card'
import ImportRow from './ImportRow'
import useTheme from '../../hooks/useTheme'
@@ -20,7 +21,7 @@ const Wrapper = styled.div`
width: 100%;
height: calc(100% - 60px);
position: relative;
padding-bottom: 60px;
padding-bottom: 80px;
`
const Footer = styled.div`
@@ -78,7 +79,7 @@ export default function ManageTokens({
<RowBetween key={token.address} width="100%">
<RowFixed>
<CurrencyLogo currency={token} size={'20px'} />
<ExternalLink href={getEtherscanLink(chainId, token.address, 'address')}>
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
<TYPE.main ml={'10px'} fontWeight={600}>
{token.symbol}
</TYPE.main>
@@ -86,7 +87,7 @@ export default function ManageTokens({
</RowFixed>
<RowFixed>
<TrashIcon onClick={() => removeToken(chainId, token.address)} />
<ExternalLinkIcon href={getEtherscanLink(chainId, token.address, 'address')} />
<ExternalLinkIcon href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)} />
</RowFixed>
</RowBetween>
))
@@ -95,7 +96,7 @@ export default function ManageTokens({
return (
<Wrapper>
<Column style={{ width: '100%', flex: '1 1' }}>
<Column style={{ width: '100%', height: '100%', flex: '1 1' }}>
<PaddedColumn gap="14px">
<Row>
<SearchInput
@@ -121,7 +122,7 @@ export default function ManageTokens({
)}
</PaddedColumn>
<Separator />
<PaddedColumn gap="lg">
<PaddedColumn gap="lg" style={{ overflow: 'auto', marginBottom: '10px' }}>
<RowBetween>
<TYPE.main fontWeight={600}>
{userAddedTokens?.length} Custom {userAddedTokens.length === 1 ? 'Token' : 'Tokens'}

View File

@@ -1,6 +1,7 @@
import { ChainId, Currency } from '@uniswap/sdk-core'
import React, { useContext } from 'react'
import styled, { ThemeContext } from 'styled-components'
import { getExplorerLink, ExplorerDataType } from '../../utils/getExplorerLink'
import Modal from '../Modal'
import { ExternalLink } from '../../theme'
import { Text } from 'rebass'
@@ -11,8 +12,7 @@ import { ButtonPrimary, ButtonLight } from '../Button'
import { AutoColumn, ColumnCenter } from '../Column'
import Circle from '../../assets/images/blue-loader.svg'
import MetaMaskLogo from '../../assets/images/metamask.png'
import { getEtherscanLink } from '../../utils'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import useAddTokenToMetamask from 'hooks/useAddTokenToMetamask'
const Wrapper = styled.div`
@@ -113,7 +113,7 @@ export function TransactionSubmittedContent({
Transaction Submitted
</Text>
{chainId && hash && (
<ExternalLink href={getEtherscanLink(chainId, hash, 'transaction')}>
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>
<Text fontWeight={500} fontSize={14} color={theme.primary1}>
View on Etherscan
</Text>
@@ -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

@@ -6,7 +6,7 @@ import QuestionHelper from '../QuestionHelper'
import { TYPE } from '../../theme'
import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row'
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/index'
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc'
import { darken } from 'polished'
import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks'

View File

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

View File

@@ -10,7 +10,7 @@ import MetamaskIcon from '../../assets/images/metamask.png'
import { ReactComponent as Close } from '../../assets/images/x.svg'
import { fortmatic, injected, portis } from '../../connectors'
import { OVERLAY_READY } from '../../connectors/Fortmatic'
import { SUPPORTED_WALLETS } from '../../constants'
import { SUPPORTED_WALLETS } from '../../constants/wallet'
import usePrevious from '../../hooks/usePrevious'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useWalletModalToggle } from '../../state/application/hooks'

View File

@@ -4,8 +4,8 @@ import styled from 'styled-components/macro'
import { useTranslation } from 'react-i18next'
import { network } from '../../connectors'
import { useEagerConnect, useInactiveListener } from '../../hooks'
import { NetworkContextName } from '../../constants'
import { useEagerConnect, useInactiveListener } from '../../hooks/web3'
import { NetworkContextName } from '../../constants/misc'
import Loader from '../Loader'
const MessageWrapper = styled.div`

View File

@@ -10,7 +10,7 @@ import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
import PortisIcon from '../../assets/images/portisIcon.png'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
import { NetworkContextName } from '../../constants'
import { NetworkContextName } from '../../constants/misc'
import useENSName from '../../hooks/useENSName'
import { useHasSocks } from '../../hooks/useSocksBalance'
import { useWalletModalToggle } from '../../state/application/hooks'

View File

@@ -1,4 +1,5 @@
import React, { useState } from 'react'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import Modal from '../Modal'
import { AutoColumn, ColumnCenter } from '../Column'
import styled from 'styled-components/macro'
@@ -12,13 +13,13 @@ import Circle from '../../assets/images/blue-loader.svg'
import { Text } from 'rebass'
import AddressInputPanel from '../AddressInputPanel'
import useENS from '../../hooks/useENS'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { isAddress } from 'ethers/lib/utils'
import Confetti from '../Confetti'
import { CardNoise, CardBGImage, CardBGImageSmaller } from '../earn/styled'
import { useIsTransactionPending } from '../../state/transactions/hooks'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { getEtherscanLink, shortenAddress } from '../../utils'
import { shortenAddress } from '../../utils'
const ContentWrapper = styled(AutoColumn)`
width: 100%;
@@ -181,7 +182,7 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
<TYPE.subHeader color="black">Confirm this transaction in your wallet</TYPE.subHeader>
)}
{attempting && hash && !claimConfirmed && chainId && hash && (
<ExternalLink href={getEtherscanLink(chainId, hash, 'transaction')} style={{ zIndex: 99 }}>
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)} style={{ zIndex: 99 }}>
View transaction on Etherscan
</ExternalLink>
)}

View File

@@ -6,13 +6,13 @@ import { Text } from 'rebass'
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'
import { useActiveWeb3React } from '../../hooks/web3'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useToggleSelfClaimModal } from '../../state/application/hooks'
import { useClaimCallback, useUserClaimData, useUserUnclaimedAmount } from '../../state/claim/hooks'
import { useUserHasSubmittedClaim } from '../../state/transactions/hooks'
import { CloseIcon, CustomLightSpinner, ExternalLink, TYPE, UniTokenAnimated } from '../../theme'
import { getEtherscanLink } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ButtonPrimary } from '../Button'
import { AutoColumn, ColumnCenter } from '../Column'
import Confetti from '../Confetti'
@@ -196,7 +196,10 @@ export default function ClaimModal() {
<TYPE.subHeader color="black">Confirm this transaction in your wallet</TYPE.subHeader>
)}
{attempting && claimSubmitted && !claimConfirmed && chainId && claimTxn?.hash && (
<ExternalLink href={getEtherscanLink(chainId, claimTxn?.hash, 'transaction')} style={{ zIndex: 99 }}>
<ExternalLink
href={getExplorerLink(chainId, claimTxn?.hash, ExplorerDataType.TRANSACTION)}
style={{ zIndex: 99 }}
>
View transaction on Etherscan
</ExternalLink>
)}

View File

@@ -10,7 +10,7 @@ import { useStakingContract } from '../../hooks/useContract'
import { SubmittedView, LoadingView } from '../ModalViews'
import { TransactionResponse } from '@ethersproject/providers'
import { useTransactionAdder } from '../../state/transactions/hooks'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
const ContentWrapper = styled(AutoColumn)`
width: 100%;

View File

@@ -15,7 +15,7 @@ import { unwrappedToken } from '../../utils/wrappedCurrency'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useV2Pair } from '../../hooks/useV2Pairs'
import useUSDCPrice from '../../hooks/useUSDCPrice'
import { BIG_INT_SECONDS_IN_WEEK } from '../../constants'
import { BIG_INT_SECONDS_IN_WEEK } from '../../constants/misc'
const StatContainer = styled.div`
display: flex;

View File

@@ -1,5 +1,5 @@
import React, { useState, useCallback } from 'react'
import { V2_ROUTER_ADDRESS } from '../../constants'
import { V2_ROUTER_ADDRESS } from '../../constants/addresses'
import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
import useTransactionDeadline from '../../hooks/useTransactionDeadline'
import Modal from '../Modal'
@@ -12,7 +12,7 @@ import ProgressCircles from '../ProgressSteps'
import CurrencyInputPanel from '../CurrencyInputPanel'
import { Pair } from '@uniswap/v2-sdk'
import { Token, CurrencyAmount } from '@uniswap/sdk-core'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { usePairContract, useStakingContract } from '../../hooks/useContract'
import { useApproveCallback, ApprovalState } from '../../hooks/useApproveCallback'
@@ -83,7 +83,10 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
// approval data for stake
const deadline = useTransactionDeadline()
const { signatureData, gatherPermitSignature } = useV2LiquidityTokenPermit(parsedAmountWrapped, V2_ROUTER_ADDRESS)
const { signatureData, gatherPermitSignature } = useV2LiquidityTokenPermit(
parsedAmountWrapped,
chainId && V2_ROUTER_ADDRESS[chainId]
)
const [approval, approveCallback] = useApproveCallback(parsedAmount, stakingInfo.stakingRewardAddress)
const stakingContract = useStakingContract(stakingInfo.stakingRewardAddress)

View File

@@ -11,7 +11,7 @@ import { SubmittedView, LoadingView } from '../ModalViews'
import { TransactionResponse } from '@ethersproject/providers'
import { useTransactionAdder } from '../../state/transactions/hooks'
import FormattedCurrencyAmount from '../FormattedCurrencyAmount'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
const ContentWrapper = styled(AutoColumn)`
width: 100%;

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

@@ -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

@@ -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

@@ -7,11 +7,11 @@ import Card, { OutlineCard } from 'components/Card'
import { RowBetween, AutoRow } from 'components/Row'
import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import { useActiveWeb3React } from 'hooks'
import { getEtherscanLink } from 'utils'
import { useActiveWeb3React } from 'hooks/web3'
import { Currency, Token } from '@uniswap/sdk-core'
import { wrappedCurrency } from 'utils/wrappedCurrency'
import { useUnsupportedTokens } from '../../hooks/Tokens'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
const DetailsFooter = styled.div<{ show: boolean }>`
padding-top: calc(16px + 2rem);
@@ -78,7 +78,7 @@ export default function UnsupportedCurrencyFooter({
<TYPE.body fontWeight={500}>{token.symbol}</TYPE.body>
</AutoRow>
{chainId && (
<ExternalLink href={getEtherscanLink(chainId, token.address, 'address')}>
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
<AddressText>{token.address}</AddressText>
</ExternalLink>
)}

View File

@@ -1,5 +1,5 @@
import { Percent } from '@uniswap/sdk-core'
import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from '../../constants'
import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from '../../constants/misc'
/**
* Given the price impact, get user confirmation.

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

@@ -1,4 +1,5 @@
import React, { useState } from 'react'
import { UNI } from '../../constants/tokens'
import Modal from '../Modal'
import { AutoColumn } from '../Column'
@@ -7,13 +8,12 @@ import { RowBetween } from '../Row'
import { TYPE } from '../../theme'
import { X } from 'react-feather'
import { ButtonPrimary } from '../Button'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import AddressInputPanel from '../AddressInputPanel'
import { isAddress } from 'ethers/lib/utils'
import useENS from '../../hooks/useENS'
import { useDelegateCallback } from '../../state/governance/hooks'
import { useTokenBalance } from '../../state/wallet/hooks'
import { UNI } from '../../constants'
import { LoadingView, SubmittedView } from '../ModalViews'
import { formatTokenAmount } from 'utils/formatTokenAmount'

View File

@@ -1,5 +1,6 @@
import React, { useState, useContext } from 'react'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { getExplorerLink, ExplorerDataType } from '../../utils/getExplorerLink'
import Modal from '../Modal'
import { AutoColumn, ColumnCenter } from '../Column'
@@ -10,7 +11,6 @@ import { X, ArrowUpCircle } from 'react-feather'
import { ButtonPrimary } from '../Button'
import Circle from '../../assets/images/blue-loader.svg'
import { useVoteCallback, useUserVotes } from '../../state/governance/hooks'
import { getEtherscanLink } from '../../utils'
import { ExternalLink } from '../../theme/components'
import { formatTokenAmount } from 'utils/formatTokenAmount'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
@@ -133,7 +133,10 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo
<TYPE.largeHeader>Transaction Submitted</TYPE.largeHeader>
</AutoColumn>
{chainId && (
<ExternalLink href={getEtherscanLink(chainId, hash, 'transaction')} style={{ marginLeft: '4px' }}>
<ExternalLink
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
style={{ marginLeft: '4px' }}
>
<TYPE.subHeader>View transaction on Etherscan</TYPE.subHeader>
</ExternalLink>
)}

View File

@@ -1,40 +1,53 @@
import { ChainId } from '@uniswap/sdk-core'
import { Web3Provider } from '@ethersproject/providers'
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,32 @@
import { ChainId } from '@uniswap/sdk-core'
import { FACTORY_ADDRESS as V3_FACTORY_ADDRESS } from '@uniswap/v3-sdk'
import { constructSameAddressMap } from '../utils/constructSameAddressMap'
export const UNI_ADDRESS = constructSameAddressMap('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984')
export const MULTICALL2_ADDRESSES = constructSameAddressMap('0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696')
export const V2_ROUTER_ADDRESS = constructSameAddressMap('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D')
export const GOVERNANCE_ADDRESS = constructSameAddressMap('0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F')
export const TIMELOCK_ADDRESS = constructSameAddressMap('0x1a9C8182C09F50C8318d769245beA52c32BE35BC')
export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e',
}
export const ARGENT_WALLET_DETECTOR_ADDRESS: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: '0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8',
}
export const V3_CORE_FACTORY_ADDRESSES = constructSameAddressMap(V3_FACTORY_ADDRESS)
export const QUOTER_ADDRESSES = constructSameAddressMap('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6')
export const TICK_LENS_ADDRESSES = constructSameAddressMap('0xbfd8137f7d1516D3ea5cA83523914859ec47F573')
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES = constructSameAddressMap(
'0xC36442b4a4522E871399CD717aBDD847Ab11FE88'
)
export const ENS_REGISTRAR_ADDRESSES = {
[ChainId.MAINNET]: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
[ChainId.GÖRLI]: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
[ChainId.RINKEBY]: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
[ChainId.ROPSTEN]: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
}
export const SOCKS_CONTROLLER_ADDRESSES = {
[ChainId.MAINNET]: '0x65770b5283117639760beA3F867b69b3697a91dd',
}
export const SWAP_ROUTER_ADDRESSES = constructSameAddressMap('0xE592427A0AEce92De3Edee1F18E0157C05861564')
export const V3_MIGRATOR_ADDRESSES = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34')

View File

@@ -0,0 +1,37 @@
import { ChainId } from '@uniswap/sdk-core'
import { GOVERNANCE_ADDRESS, TIMELOCK_ADDRESS, UNI_ADDRESS } from './addresses'
export const COMMON_CONTRACT_NAMES: { [chainId in ChainId]?: { [address: string]: string } } = {
[ChainId.MAINNET]: {
[UNI_ADDRESS[ChainId.MAINNET]]: 'UNI',
[GOVERNANCE_ADDRESS[ChainId.MAINNET]]: 'Governance',
[TIMELOCK_ADDRESS[ChainId.MAINNET]]: 'Timelock',
},
[ChainId.RINKEBY]: {
[UNI_ADDRESS[ChainId.RINKEBY]]: 'Rinkeby UNI',
[GOVERNANCE_ADDRESS[ChainId.RINKEBY]]: 'Rinkeby Governance',
[TIMELOCK_ADDRESS[ChainId.RINKEBY]]: 'Rinkeby Timelock',
},
[ChainId.ROPSTEN]: {
[UNI_ADDRESS[ChainId.ROPSTEN]]: 'Ropsten UNI',
[GOVERNANCE_ADDRESS[ChainId.ROPSTEN]]: 'Ropsten Governance',
[TIMELOCK_ADDRESS[ChainId.ROPSTEN]]: 'Ropsten Timelock',
},
[ChainId.KOVAN]: {
[UNI_ADDRESS[ChainId.KOVAN]]: 'Kovan UNI',
[GOVERNANCE_ADDRESS[ChainId.KOVAN]]: 'Kovan Governance',
[TIMELOCK_ADDRESS[ChainId.KOVAN]]: 'Kovan Timelock',
},
[ChainId.GÖRLI]: {
[UNI_ADDRESS[ChainId.GÖRLI]]: 'Goerli UNI',
[GOVERNANCE_ADDRESS[ChainId.GÖRLI]]: 'Goerli Governance',
[TIMELOCK_ADDRESS[ChainId.GÖRLI]]: 'Goerli Timelock',
},
}
export const DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS = 13
// Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time
export const AVERAGE_BLOCK_TIME_IN_SECS: { [chainId in ChainId]?: number } = {
[ChainId.MAINNET]: DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS,
}

View File

@@ -1,279 +0,0 @@
import { ChainId, Percent, Token, WETH9 } from '@uniswap/sdk-core'
import { AbstractConnector } from '@web3-react/abstract-connector'
import JSBI from 'jsbi'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../connectors'
import INJECTED_ICON_URL from '../assets/images/arrow-right.svg'
import METAMASK_ICON_URL from '../assets/images/metamask.png'
import WALLETCONNECT_ICON_URL from '../assets/images/walletConnectIcon.svg'
import COINBASE_ICON_URL from '../assets/images/coinbaseWalletIcon.svg'
import FORTMATIC_ICON_URL from '../assets/images/fortmaticIcon.png'
import PORTIS_ICON_URL from '../assets/images/portisIcon.png'
export const MULTICALL2_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
[ChainId.ROPSTEN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
[ChainId.KOVAN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
[ChainId.RINKEBY]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
[ChainId.GÖRLI]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
}
export const V2_ROUTER_ADDRESS = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export { PRELOADED_PROPOSALS } from './proposals'
// a list of tokens by chain
type ChainTokenList = {
readonly [chainId in ChainId]: Token[]
}
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
export const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin')
export const USDC = new Token(ChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC', 'USD//C')
export const USDT = new Token(ChainId.MAINNET, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6, 'USDT', 'Tether USD')
export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 8, 'WBTC', 'Wrapped BTC')
export const FEI = new Token(ChainId.MAINNET, '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', 18, 'FEI', 'Fei USD')
export const TRIBE = new Token(ChainId.MAINNET, '0xc7283b66Eb1EB5FB86327f08e1B5816b0720212B', 18, 'TRIBE', 'Tribe')
export const FRAX = new Token(ChainId.MAINNET, '0x853d955aCEf822Db058eb8505911ED77F175b99e', 18, 'FRAX', 'Frax')
export const FXS = new Token(ChainId.MAINNET, '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', 18, 'FXS', 'Frax Share')
export const renBTC = new Token(ChainId.MAINNET, '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', 8, 'renBTC', 'renBTC')
export const UMA = new Token(
ChainId.MAINNET,
'0x04Fa0d235C4abf4BcF4787aF4CF447DE572eF828',
18,
'UMA',
'UMA Voting Token v1'
)
// Mirror Protocol compat.
export const UST = new Token(ChainId.MAINNET, '0xa47c8bf37f92abed4a126bda807a7b7498661acd', 18, 'UST', 'Wrapped UST')
export const MIR = new Token(ChainId.MAINNET, '0x09a3ecafa817268f77be1283176b946c4ff2e608', 18, 'MIR', 'Wrapped MIR')
// List of all mirror's assets addresses.
// Last pulled from : https://whitelist.mirror.finance/eth/tokenlists.json
// TODO: Generate this programaticaly ?
const mAssetsAdditionalBases: { [tokenAddress: string]: Token[] } = {
[UST.address]: [MIR],
[MIR.address]: [UST],
'0xd36932143F6eBDEDD872D5Fb0651f4B72Fd15a84': [MIR, UST], // mAAPL
'0x59A921Db27Dd6d4d974745B7FfC5c33932653442': [MIR, UST], // mGOOGL
'0x21cA39943E91d704678F5D00b6616650F066fD63': [MIR, UST], // mTSLA
'0xC8d674114bac90148d11D3C1d33C61835a0F9DCD': [MIR, UST], // mNFLX
'0x13B02c8dE71680e71F0820c996E4bE43c2F57d15': [MIR, UST], // mQQQ
'0xEdb0414627E6f1e3F082DE65cD4F9C693D78CCA9': [MIR, UST], // mTWTR
'0x41BbEDd7286dAab5910a1f15d12CBda839852BD7': [MIR, UST], // mMSFT
'0x0cae9e4d663793c2a2A0b211c1Cf4bBca2B9cAa7': [MIR, UST], // mAMZN
'0x56aA298a19C93c6801FDde870fA63EF75Cc0aF72': [MIR, UST], // mBABA
'0x1d350417d9787E000cc1b95d70E9536DcD91F373': [MIR, UST], // mIAU
'0x9d1555d8cB3C846Bb4f7D5B1B1080872c3166676': [MIR, UST], // mSLV
'0x31c63146a635EB7465e5853020b39713AC356991': [MIR, UST], // mUSO
'0xf72FCd9DCF0190923Fadd44811E240Ef4533fc86': [MIR, UST], // mVIXY
}
// Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time
export const AVERAGE_BLOCK_TIME_IN_SECS = 13
export const PROPOSAL_LENGTH_IN_BLOCKS = 40_320
export const PROPOSAL_LENGTH_IN_SECS = AVERAGE_BLOCK_TIME_IN_SECS * PROPOSAL_LENGTH_IN_BLOCKS
export const GOVERNANCE_ADDRESS = '0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F'
export const TIMELOCK_ADDRESS = '0x1a9C8182C09F50C8318d769245beA52c32BE35BC'
const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
export const UNI: { [chainId in ChainId]: Token } = {
[ChainId.MAINNET]: new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
[ChainId.RINKEBY]: new Token(ChainId.RINKEBY, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
[ChainId.ROPSTEN]: new Token(ChainId.ROPSTEN, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
[ChainId.GÖRLI]: new Token(ChainId.GÖRLI, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
[ChainId.KOVAN]: new Token(ChainId.KOVAN, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
}
export const COMMON_CONTRACT_NAMES: { [address: string]: string } = {
[UNI_ADDRESS]: 'UNI',
[GOVERNANCE_ADDRESS]: 'Governance',
[TIMELOCK_ADDRESS]: 'Timelock',
}
export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e',
}
const WETH_ONLY: ChainTokenList = {
[ChainId.MAINNET]: [WETH9[ChainId.MAINNET]],
[ChainId.ROPSTEN]: [WETH9[ChainId.ROPSTEN]],
[ChainId.RINKEBY]: [WETH9[ChainId.RINKEBY]],
[ChainId.GÖRLI]: [WETH9[ChainId.GÖRLI]],
[ChainId.KOVAN]: [WETH9[ChainId.KOVAN]],
}
// used to construct intermediary pairs for trading
export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
...WETH_ONLY,
[ChainId.MAINNET]: [...WETH_ONLY[ChainId.MAINNET], DAI, USDC, USDT, WBTC],
}
export const ADDITIONAL_BASES: { [chainId in ChainId]?: { [tokenAddress: string]: Token[] } } = {
[ChainId.MAINNET]: {
...mAssetsAdditionalBases,
'0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18': [UNI[ChainId.MAINNET]],
'0x561a4717537ff4AF5c687328c0f7E90a319705C0': [UNI[ChainId.MAINNET]],
'0xa6e3454fec677772dd771788a079355e43910638': [UMA],
[FEI.address]: [TRIBE],
[TRIBE.address]: [FEI],
[FRAX.address]: [FXS],
[FXS.address]: [FRAX],
[WBTC.address]: [renBTC],
[renBTC.address]: [WBTC],
},
}
/**
* Some tokens can only be swapped via certain pairs, so we override the list of bases that are considered for these
* tokens.
*/
export const CUSTOM_BASES: { [chainId in ChainId]?: { [tokenAddress: string]: Token[] } } = {
[ChainId.MAINNET]: {
[AMPL.address]: [DAI, WETH9[ChainId.MAINNET]],
},
}
// used for display in the default list when adding liquidity
export const SUGGESTED_BASES: Partial<ChainTokenList> = {
[ChainId.MAINNET]: [DAI, USDC, USDT, WBTC],
}
// used to construct the list of all pairs we consider by default in the frontend
export const BASES_TO_TRACK_LIQUIDITY_FOR: ChainTokenList = {
...WETH_ONLY,
[ChainId.MAINNET]: [...WETH_ONLY[ChainId.MAINNET], DAI, USDC, USDT, WBTC],
}
export const PINNED_PAIRS: { readonly [chainId in ChainId]?: [Token, Token][] } = {
[ChainId.MAINNET]: [
[
new Token(ChainId.MAINNET, '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', 8, 'cDAI', 'Compound Dai'),
new Token(ChainId.MAINNET, '0x39AA39c021dfbaE8faC545936693aC917d5E7563', 8, 'cUSDC', 'Compound USD Coin'),
],
[USDC, USDT],
[DAI, USDT],
],
}
export interface WalletInfo {
connector?: AbstractConnector
name: string
iconURL: string
description: string
href: string | null
color: string
primary?: true
mobile?: true
mobileOnly?: true
}
export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = {
INJECTED: {
connector: injected,
name: 'Injected',
iconURL: INJECTED_ICON_URL,
description: 'Injected web3 provider.',
href: null,
color: '#010101',
primary: true,
},
METAMASK: {
connector: injected,
name: 'MetaMask',
iconURL: METAMASK_ICON_URL,
description: 'Easy-to-use browser extension.',
href: null,
color: '#E8831D',
},
WALLET_CONNECT: {
connector: walletconnect,
name: 'WalletConnect',
iconURL: WALLETCONNECT_ICON_URL,
description: 'Connect to Trust Wallet, Rainbow Wallet and more...',
href: null,
color: '#4196FC',
mobile: true,
},
WALLET_LINK: {
connector: walletlink,
name: 'Coinbase Wallet',
iconURL: COINBASE_ICON_URL,
description: 'Use Coinbase Wallet app on mobile device',
href: null,
color: '#315CF5',
},
COINBASE_LINK: {
name: 'Open in Coinbase Wallet',
iconURL: COINBASE_ICON_URL,
description: 'Open in Coinbase Wallet app.',
href: 'https://go.cb-w.com/mtUDhEZPy1',
color: '#315CF5',
mobile: true,
mobileOnly: true,
},
FORTMATIC: {
connector: fortmatic,
name: 'Fortmatic',
iconURL: FORTMATIC_ICON_URL,
description: 'Login using Fortmatic hosted wallet',
href: null,
color: '#6748FF',
mobile: true,
},
Portis: {
connector: portis,
name: 'Portis',
iconURL: PORTIS_ICON_URL,
description: 'Login using Portis hosted wallet',
href: null,
color: '#4A6C9B',
mobile: true,
},
}
export const NetworkContextName = 'NETWORK'
// 30 minutes, denominated in seconds
export const DEFAULT_DEADLINE_FROM_NOW = 60 * 30
// used for rewards deadlines
export const BIG_INT_SECONDS_IN_WEEK = JSBI.BigInt(60 * 60 * 24 * 7)
export const BIG_INT_ZERO = JSBI.BigInt(0)
// one basis JSBI.BigInt
export const ONE_BIPS = new Percent(JSBI.BigInt(1), JSBI.BigInt(10))
export const BIPS_BASE = JSBI.BigInt(10000)
// used for warning states
export const ALLOWED_PRICE_IMPACT_LOW: Percent = new Percent(JSBI.BigInt(100), BIPS_BASE) // 1%
export const ALLOWED_PRICE_IMPACT_MEDIUM: Percent = new Percent(JSBI.BigInt(300), BIPS_BASE) // 3%
export const ALLOWED_PRICE_IMPACT_HIGH: Percent = new Percent(JSBI.BigInt(500), BIPS_BASE) // 5%
// if the price slippage exceeds this number, force the user to type 'confirm' to execute
export const PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN: Percent = new Percent(JSBI.BigInt(1000), BIPS_BASE) // 10%
// for non expert mode disable swaps above this
export const BLOCKED_PRICE_IMPACT_NON_EXPERT: Percent = new Percent(JSBI.BigInt(1500), BIPS_BASE) // 15%
// used to ensure the user doesn't send so much ETH so they end up with <.01
export const MIN_ETH: JSBI = JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(16)) // .01 ETH
export const BETTER_TRADE_LESS_HOPS_THRESHOLD = new Percent(JSBI.BigInt(50), JSBI.BigInt(10000))
export const ZERO_PERCENT = new Percent('0')
export const ONE_HUNDRED_PERCENT = new Percent('1')
// SDN OFAC addresses
export const BLOCKED_ADDRESSES: string[] = [
'0x7F367cC41522cE07553e823bf3be79A889DEbe1B',
'0xd882cFc20F52f2599D84b8e8D58C7FB62cfE344b',
'0x901bb9583b24D97e995513C6778dc6888AB6870e',
'0xA7e5d5A720f06526557c513402f2e6B5fA20b008',
'0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C',
]
export const ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS = '0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8'
export const V1_MIGRATOR_ADDRESS = '0x16D4F26C15f3658ec65B1126ff27DD3dF2a2996b'

33
src/constants/misc.ts Normal file
View File

@@ -0,0 +1,33 @@
import { Percent } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export const NetworkContextName = 'NETWORK'
// 30 minutes, denominated in seconds
export const DEFAULT_DEADLINE_FROM_NOW = 60 * 30
// used for rewards deadlines
export const BIG_INT_SECONDS_IN_WEEK = JSBI.BigInt(60 * 60 * 24 * 7)
export const BIG_INT_ZERO = JSBI.BigInt(0)
// one basis JSBI.BigInt
export const ONE_BIPS = new Percent(JSBI.BigInt(1), JSBI.BigInt(10000))
export const BIPS_BASE = JSBI.BigInt(10000)
// used for warning states
export const ALLOWED_PRICE_IMPACT_LOW: Percent = new Percent(JSBI.BigInt(100), BIPS_BASE) // 1%
export const ALLOWED_PRICE_IMPACT_MEDIUM: Percent = new Percent(JSBI.BigInt(300), BIPS_BASE) // 3%
export const ALLOWED_PRICE_IMPACT_HIGH: Percent = new Percent(JSBI.BigInt(500), BIPS_BASE) // 5%
// if the price slippage exceeds this number, force the user to type 'confirm' to execute
export const PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN: Percent = new Percent(JSBI.BigInt(1000), BIPS_BASE) // 10%
// for non expert mode disable swaps above this
export const BLOCKED_PRICE_IMPACT_NON_EXPERT: Percent = new Percent(JSBI.BigInt(1500), BIPS_BASE) // 15%
// used to ensure the user doesn't send so much ETH so they end up with <.01
export const MIN_ETH: JSBI = JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(16)) // .01 ETH
export const BETTER_TRADE_LESS_HOPS_THRESHOLD = new Percent(JSBI.BigInt(50), JSBI.BigInt(10000))
export const ZERO_PERCENT = new Percent('0')
export const ONE_HUNDRED_PERCENT = new Percent('1')

View File

@@ -1,4 +1,6 @@
import { UNISWAP_GRANTS } from './uniswap_grants'
import { UNISWAP_GRANTS_PROPOSAL_DESCRIPTION } from './uniswap_grants_proposal_description'
// Proposals are 0-indexed
export const PRELOADED_PROPOSALS = new Map([[2, UNISWAP_GRANTS]])
export const PROPOSAL_DESCRIPTION_TEXT: { [proposalId: number]: string } = {
[2]: UNISWAP_GRANTS_PROPOSAL_DESCRIPTION,
}

View File

@@ -1,4 +1,4 @@
export const UNISWAP_GRANTS = `# Uniswap Grants Program v0.1
export const UNISWAP_GRANTS_PROPOSAL_DESCRIPTION = `# Uniswap Grants Program v0.1
*co-authored with [Ken Ng](https://twitter.com/nkennethk?lang=en)*

81
src/constants/routing.ts Normal file
View File

@@ -0,0 +1,81 @@
// a list of tokens by chain
import { ChainId, Token, WETH9 } from '@uniswap/sdk-core'
import { AMPL, DAI, FEI, FRAX, FXS, MIR, renBTC, TRIBE, UMA, UNI, USDC, USDT, UST, WBTC } from './tokens'
type ChainTokenList = {
readonly [chainId in ChainId]: Token[]
}
// List of all mirror's assets addresses.
// Last pulled from : https://whitelist.mirror.finance/eth/tokenlists.json
// TODO: Generate this programmatically ?
const mAssetsAdditionalBases: { [tokenAddress: string]: Token[] } = {
[UST.address]: [MIR],
[MIR.address]: [UST],
'0xd36932143F6eBDEDD872D5Fb0651f4B72Fd15a84': [MIR, UST], // mAAPL
'0x59A921Db27Dd6d4d974745B7FfC5c33932653442': [MIR, UST], // mGOOGL
'0x21cA39943E91d704678F5D00b6616650F066fD63': [MIR, UST], // mTSLA
'0xC8d674114bac90148d11D3C1d33C61835a0F9DCD': [MIR, UST], // mNFLX
'0x13B02c8dE71680e71F0820c996E4bE43c2F57d15': [MIR, UST], // mQQQ
'0xEdb0414627E6f1e3F082DE65cD4F9C693D78CCA9': [MIR, UST], // mTWTR
'0x41BbEDd7286dAab5910a1f15d12CBda839852BD7': [MIR, UST], // mMSFT
'0x0cae9e4d663793c2a2A0b211c1Cf4bBca2B9cAa7': [MIR, UST], // mAMZN
'0x56aA298a19C93c6801FDde870fA63EF75Cc0aF72': [MIR, UST], // mBABA
'0x1d350417d9787E000cc1b95d70E9536DcD91F373': [MIR, UST], // mIAU
'0x9d1555d8cB3C846Bb4f7D5B1B1080872c3166676': [MIR, UST], // mSLV
'0x31c63146a635EB7465e5853020b39713AC356991': [MIR, UST], // mUSO
'0xf72FCd9DCF0190923Fadd44811E240Ef4533fc86': [MIR, UST], // mVIXY
}
const WETH_ONLY: ChainTokenList = {
[ChainId.MAINNET]: [WETH9[ChainId.MAINNET]],
[ChainId.ROPSTEN]: [WETH9[ChainId.ROPSTEN]],
[ChainId.RINKEBY]: [WETH9[ChainId.RINKEBY]],
[ChainId.GÖRLI]: [WETH9[ChainId.GÖRLI]],
[ChainId.KOVAN]: [WETH9[ChainId.KOVAN]],
}
// used to construct intermediary pairs for trading
export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
...WETH_ONLY,
[ChainId.MAINNET]: [...WETH_ONLY[ChainId.MAINNET], DAI, USDC, USDT, WBTC],
}
export const ADDITIONAL_BASES: { [chainId in ChainId]?: { [tokenAddress: string]: Token[] } } = {
[ChainId.MAINNET]: {
...mAssetsAdditionalBases,
'0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18': [UNI[ChainId.MAINNET]],
'0x561a4717537ff4AF5c687328c0f7E90a319705C0': [UNI[ChainId.MAINNET]],
'0xa6e3454fec677772dd771788a079355e43910638': [UMA],
[FEI.address]: [TRIBE],
[TRIBE.address]: [FEI],
[FRAX.address]: [FXS],
[FXS.address]: [FRAX],
[WBTC.address]: [renBTC],
[renBTC.address]: [WBTC],
},
}
/**
* Some tokens can only be swapped via certain pairs, so we override the list of bases that are considered for these
* tokens.
*/
export const CUSTOM_BASES: { [chainId in ChainId]?: { [tokenAddress: string]: Token[] } } = {
[ChainId.MAINNET]: {
[AMPL.address]: [DAI, WETH9[ChainId.MAINNET]],
},
}
// used for display in the default list when adding liquidity
export const SUGGESTED_BASES: Partial<ChainTokenList> = {
[ChainId.MAINNET]: [DAI, USDC, USDT, WBTC],
}
// used to construct the list of all pairs we consider by default in the frontend
export const BASES_TO_TRACK_LIQUIDITY_FOR: ChainTokenList = {
...WETH_ONLY,
[ChainId.MAINNET]: [...WETH_ONLY[ChainId.MAINNET], DAI, USDC, USDT, WBTC],
}
export const PINNED_PAIRS: { readonly [chainId in ChainId]?: [Token, Token][] } = {
[ChainId.MAINNET]: [
[
new Token(ChainId.MAINNET, '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', 8, 'cDAI', 'Compound Dai'),
new Token(ChainId.MAINNET, '0x39AA39c021dfbaE8faC545936693aC917d5E7563', 8, 'cUSDC', 'Compound USD Coin'),
],
[USDC, USDT],
[DAI, USDT],
],
}

30
src/constants/tokens.ts Normal file
View File

@@ -0,0 +1,30 @@
import { ChainId, Token } from '@uniswap/sdk-core'
import { UNI_ADDRESS } from './addresses'
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
export const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin')
export const USDC = new Token(ChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC', 'USD//C')
export const USDT = new Token(ChainId.MAINNET, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6, 'USDT', 'Tether USD')
export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 8, 'WBTC', 'Wrapped BTC')
export const FEI = new Token(ChainId.MAINNET, '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', 18, 'FEI', 'Fei USD')
export const TRIBE = new Token(ChainId.MAINNET, '0xc7283b66Eb1EB5FB86327f08e1B5816b0720212B', 18, 'TRIBE', 'Tribe')
export const FRAX = new Token(ChainId.MAINNET, '0x853d955aCEf822Db058eb8505911ED77F175b99e', 18, 'FRAX', 'Frax')
export const FXS = new Token(ChainId.MAINNET, '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', 18, 'FXS', 'Frax Share')
export const renBTC = new Token(ChainId.MAINNET, '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', 8, 'renBTC', 'renBTC')
export const UMA = new Token(
ChainId.MAINNET,
'0x04Fa0d235C4abf4BcF4787aF4CF447DE572eF828',
18,
'UMA',
'UMA Voting Token v1'
)
// Mirror Protocol compat.
export const UST = new Token(ChainId.MAINNET, '0xa47c8bf37f92abed4a126bda807a7b7498661acd', 18, 'UST', 'Wrapped UST')
export const MIR = new Token(ChainId.MAINNET, '0x09a3ecafa817268f77be1283176b946c4ff2e608', 18, 'MIR', 'Wrapped MIR')
export const UNI: { [chainId in ChainId]: Token } = {
[ChainId.MAINNET]: new Token(ChainId.MAINNET, UNI_ADDRESS[ChainId.MAINNET], 18, 'UNI', 'Uniswap'),
[ChainId.RINKEBY]: new Token(ChainId.RINKEBY, UNI_ADDRESS[ChainId.RINKEBY], 18, 'UNI', 'Uniswap'),
[ChainId.ROPSTEN]: new Token(ChainId.ROPSTEN, UNI_ADDRESS[ChainId.ROPSTEN], 18, 'UNI', 'Uniswap'),
[ChainId.GÖRLI]: new Token(ChainId.GÖRLI, UNI_ADDRESS[ChainId.GÖRLI], 18, 'UNI', 'Uniswap'),
[ChainId.KOVAN]: new Token(ChainId.KOVAN, UNI_ADDRESS[ChainId.KOVAN], 18, 'UNI', 'Uniswap'),
}

View File

@@ -1,26 +0,0 @@
import { ChainId } from '@uniswap/sdk-core'
import { FACTORY_ADDRESS } from '@uniswap/v3-sdk'
function constructSameAddressMap(address: string): { [chainId in ChainId]: string } {
return {
[ChainId.MAINNET]: address,
[ChainId.ROPSTEN]: address,
[ChainId.KOVAN]: address,
[ChainId.RINKEBY]: address,
[ChainId.GÖRLI]: address,
}
}
export const V3_CORE_FACTORY_ADDRESSES = constructSameAddressMap(FACTORY_ADDRESS)
export const QUOTER_ADDRESSES = constructSameAddressMap('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6')
export const TICK_LENS_ADDRESSES = constructSameAddressMap('0xbfd8137f7d1516D3ea5cA83523914859ec47F573')
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES = constructSameAddressMap(
'0xC36442b4a4522E871399CD717aBDD847Ab11FE88'
)
export const SWAP_ROUTER_ADDRESSES = constructSameAddressMap('0xE592427A0AEce92De3Edee1F18E0157C05861564')
export const V3_MIGRATOR_ADDRESSES = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34')

84
src/constants/wallet.ts Normal file
View File

@@ -0,0 +1,84 @@
import { AbstractConnector } from '@web3-react/abstract-connector'
import INJECTED_ICON_URL from '../assets/images/arrow-right.svg'
import COINBASE_ICON_URL from '../assets/images/coinbaseWalletIcon.svg'
import FORTMATIC_ICON_URL from '../assets/images/fortmaticIcon.png'
import METAMASK_ICON_URL from '../assets/images/metamask.png'
import PORTIS_ICON_URL from '../assets/images/portisIcon.png'
import WALLETCONNECT_ICON_URL from '../assets/images/walletConnectIcon.svg'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../connectors'
export interface WalletInfo {
connector?: AbstractConnector
name: string
iconURL: string
description: string
href: string | null
color: string
primary?: true
mobile?: true
mobileOnly?: true
}
export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = {
INJECTED: {
connector: injected,
name: 'Injected',
iconURL: INJECTED_ICON_URL,
description: 'Injected web3 provider.',
href: null,
color: '#010101',
primary: true,
},
METAMASK: {
connector: injected,
name: 'MetaMask',
iconURL: METAMASK_ICON_URL,
description: 'Easy-to-use browser extension.',
href: null,
color: '#E8831D',
},
WALLET_CONNECT: {
connector: walletconnect,
name: 'WalletConnect',
iconURL: WALLETCONNECT_ICON_URL,
description: 'Connect to Trust Wallet, Rainbow Wallet and more...',
href: null,
color: '#4196FC',
mobile: true,
},
WALLET_LINK: {
connector: walletlink,
name: 'Coinbase Wallet',
iconURL: COINBASE_ICON_URL,
description: 'Use Coinbase Wallet app on mobile device',
href: null,
color: '#315CF5',
},
COINBASE_LINK: {
name: 'Open in Coinbase Wallet',
iconURL: COINBASE_ICON_URL,
description: 'Open in Coinbase Wallet app.',
href: 'https://go.cb-w.com/mtUDhEZPy1',
color: '#315CF5',
mobile: true,
mobileOnly: true,
},
FORTMATIC: {
connector: fortmatic,
name: 'Fortmatic',
iconURL: FORTMATIC_ICON_URL,
description: 'Login using Fortmatic hosted wallet',
href: null,
color: '#6748FF',
mobile: true,
},
Portis: {
connector: portis,
name: 'Portis',
iconURL: PORTIS_ICON_URL,
description: 'Login using Portis hosted wallet',
href: null,
color: '#4A6C9B',
mobile: true,
},
}

View File

@@ -10,7 +10,7 @@ import { useUserAddedTokens } from '../state/user/hooks'
import { isAddress } from '../utils'
import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/hooks'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useBytes32TokenContract, useTokenContract } from './useContract'
// reduce token map into standard address <-> Token mapping, optionally include user added tokens

View File

@@ -2,7 +2,7 @@ import { getTokenLogoURL } from './../components/CurrencyLogo/index'
import { wrappedCurrency } from 'utils/wrappedCurrency'
import { Currency, Token } from '@uniswap/sdk-core'
import { useCallback, useState } from 'react'
import { useActiveWeb3React } from 'hooks'
import { useActiveWeb3React } from 'hooks/web3'
export default function useAddTokenToMetamask(
currencyToAdd: Currency | undefined

View File

@@ -1,9 +1,9 @@
import { Currency, Token } from '@uniswap/sdk-core'
import flatMap from 'lodash.flatmap'
import { useMemo } from 'react'
import { ADDITIONAL_BASES, BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES } from '../constants'
import { ADDITIONAL_BASES, BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES } from '../constants/routing'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
export function useAllCurrencyCombinations(currencyA?: Currency, currencyB?: Currency): [Token, Token][] {
const { chainId } = useActiveWeb3React()

View File

@@ -3,7 +3,7 @@ import { Pool, Route } from '@uniswap/v3-sdk'
import { useMemo } from 'react'
import { useUserSingleHopOnly } from '../state/user/hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useV3SwapPools } from './useV3SwapPools'
function computeAllRoutes(

View File

@@ -1,7 +1,7 @@
import { Token } from '@uniswap/sdk-core'
import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
import { nearestUsableTick, TickMath } from '@uniswap/v3-sdk/dist/'
import { ZERO_ADDRESS } from '../constants'
import { ZERO_ADDRESS } from '../constants/misc'
import { useEffect, useMemo, useState } from 'react'
import { Result, useSingleCallResult, useSingleContractMultipleData } from 'state/multicall/hooks'
import { useTickLens, useV3Factory } from './useContract'

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

@@ -4,12 +4,11 @@ import { CurrencyAmount, ChainId, Percent, Currency, TradeType } from '@uniswap/
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { useCallback, useMemo } from 'react'
import { V2_ROUTER_ADDRESS } from '../constants'
import { SWAP_ROUTER_ADDRESSES } from '../constants/v3'
import { SWAP_ROUTER_ADDRESSES, V2_ROUTER_ADDRESS } from '../constants/addresses'
import { useTransactionAdder, useHasPendingApproval } from '../state/transactions/hooks'
import { calculateGasMargin } from '../utils'
import { calculateGasMargin } from '../utils/calculateGasMargin'
import { useTokenContract } from './useContract'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useTokenAllowance } from './useTokenAllowance'
export enum ApprovalState {
@@ -104,13 +103,19 @@ export function useApproveCallbackFromTrade(
allowedSlippage: Percent
) {
const { chainId } = useActiveWeb3React()
const swapRouterAddress = SWAP_ROUTER_ADDRESSES[chainId as ChainId]
const v3SwapRouterAddress = SWAP_ROUTER_ADDRESSES[chainId as ChainId]
const amountToApprove = useMemo(
() => (trade && trade.inputAmount.currency.isToken ? trade.maximumAmountIn(allowedSlippage) : undefined),
[trade, allowedSlippage]
)
return useApproveCallback(
amountToApprove,
trade instanceof V2Trade ? V2_ROUTER_ADDRESS : trade instanceof V3Trade ? swapRouterAddress : undefined
chainId
? trade instanceof V2Trade
? V2_ROUTER_ADDRESS[chainId]
: trade instanceof V3Trade
? v3SwapRouterAddress
: undefined
: undefined
)
}

View File

@@ -17,7 +17,6 @@ import ENS_PUBLIC_RESOLVER_ABI from 'abis/ens-public-resolver.json'
import ENS_ABI from 'abis/ens-registrar.json'
import ERC20_ABI from 'abis/erc20.json'
import ERC20_BYTES32_ABI from 'abis/erc20_bytes32.json'
import MIGRATOR_ABI from 'abis/migrator.json'
import MULTICALL_ABI from 'abis/multicall2.json'
import { Unisocks } from 'abis/types/Unisocks'
import UNISOCKS_ABI from 'abis/unisocks.json'
@@ -25,91 +24,75 @@ import WETH_ABI from 'abis/weth.json'
import EIP_2612 from 'abis/eip_2612.json'
import {
ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS,
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
QUOTER_ADDRESSES,
TICK_LENS_ADDRESSES,
V3_CORE_FACTORY_ADDRESSES,
V3_MIGRATOR_ADDRESSES,
ARGENT_WALLET_DETECTOR_ADDRESS,
GOVERNANCE_ADDRESS,
MERKLE_DISTRIBUTOR_ADDRESS,
V1_MIGRATOR_ADDRESS,
UNI,
MULTICALL2_ADDRESSES,
V2_ROUTER_ADDRESS,
} from 'constants/index'
ENS_REGISTRAR_ADDRESSES,
SOCKS_CONTROLLER_ADDRESSES,
} from 'constants/addresses'
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import {
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
V3_CORE_FACTORY_ADDRESSES,
TICK_LENS_ADDRESSES,
V3_MIGRATOR_ADDRESSES,
QUOTER_ADDRESSES,
} from 'constants/v3'
import { useMemo } from 'react'
import { Quoter, TickLens, UniswapV3Factory, UniswapV3Pool } from 'types/v3'
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
import { V3Migrator } from 'types/v3/V3Migrator'
import { getContract } from 'utils'
import { Multicall2 } from '../abis/types'
import { useActiveWeb3React } from './index'
import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Multicall2, Weth } from '../abis/types'
import { UNI } from '../constants/tokens'
import { useActiveWeb3React } from './web3'
// returns null on errors
export function useContract(address: string | undefined, ABI: any, withSignerIfPossible = true): Contract | null {
const { library, account } = useActiveWeb3React()
export function useContract<T extends Contract = Contract>(
addressOrAddressMap: string | { [chainId in ChainId]?: string } | undefined,
ABI: any,
withSignerIfPossible = true
): T | null {
const { library, account, chainId } = useActiveWeb3React()
return useMemo(() => {
if (!address || !ABI || !library) return null
if (!addressOrAddressMap || !ABI || !library || !chainId) return null
let address: string | undefined
if (typeof addressOrAddressMap === 'string') address = addressOrAddressMap
else address = addressOrAddressMap[chainId]
if (!address) return null
try {
return getContract(address, ABI, library, withSignerIfPossible && account ? account : undefined)
} catch (error) {
console.error('Failed to get contract', error)
return null
}
}, [address, ABI, library, withSignerIfPossible, account])
}, [addressOrAddressMap, ABI, library, chainId, withSignerIfPossible, account]) as T
}
export function useV1MigratorContract(): Contract | null {
return useContract(V1_MIGRATOR_ADDRESS, MIGRATOR_ABI, true)
export function useV2MigratorContract() {
return useContract<V3Migrator>(V3_MIGRATOR_ADDRESSES, V2MigratorABI, true)
}
export function useV2MigratorContract(): V3Migrator | null {
export function useTokenContract(tokenAddress?: string, withSignerIfPossible?: boolean) {
return useContract<Erc20>(tokenAddress, ERC20_ABI, withSignerIfPossible)
}
export function useWETHContract(withSignerIfPossible?: boolean) {
const { chainId } = useActiveWeb3React()
return useContract(chainId && V3_MIGRATOR_ADDRESSES[chainId], V2MigratorABI, true) as V3Migrator | null
return useContract<Weth>(chainId ? WETH9[chainId]?.address : undefined, WETH_ABI, withSignerIfPossible)
}
export function useTokenContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null {
return useContract(tokenAddress, ERC20_ABI, withSignerIfPossible)
export function useArgentWalletDetectorContract() {
return useContract<ArgentWalletDetector>(ARGENT_WALLET_DETECTOR_ADDRESS, ARGENT_WALLET_DETECTOR_ABI, false)
}
export function useWETHContract(withSignerIfPossible?: boolean): Contract | null {
const { chainId } = useActiveWeb3React()
const address = chainId && chainId in WETH9 ? WETH9[chainId].address : undefined
return useContract(address, WETH_ABI, withSignerIfPossible)
export function useENSRegistrarContract(withSignerIfPossible?: boolean) {
return useContract<EnsRegistrar>(ENS_REGISTRAR_ADDRESSES, ENS_ABI, withSignerIfPossible)
}
export function useArgentWalletDetectorContract(): Contract | null {
const { chainId } = useActiveWeb3React()
return useContract(
chainId === ChainId.MAINNET ? ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS : undefined,
ARGENT_WALLET_DETECTOR_ABI,
false
)
}
export function useENSRegistrarContract(withSignerIfPossible?: boolean): Contract | null {
const { chainId } = useActiveWeb3React()
let address: string | undefined
if (chainId) {
switch (chainId) {
case ChainId.MAINNET:
case ChainId.GÖRLI:
case ChainId.ROPSTEN:
case ChainId.RINKEBY:
address = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'
break
}
}
return useContract(address, ENS_ABI, withSignerIfPossible)
}
export function useENSResolverContract(address: string | undefined, withSignerIfPossible?: boolean): Contract | null {
return useContract(address, ENS_PUBLIC_RESOLVER_ABI, withSignerIfPossible)
export function useENSResolverContract(address: string | undefined, withSignerIfPossible?: boolean) {
return useContract<EnsPublicResolver>(address, ENS_PUBLIC_RESOLVER_ABI, withSignerIfPossible)
}
export function useBytes32TokenContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null {
@@ -128,61 +111,51 @@ export function useV2RouterContract(): Contract | null {
return useContract(V2_ROUTER_ADDRESS, IUniswapV2Router02ABI, true)
}
export function useMulticall2Contract(): Multicall2 | null {
const { chainId } = useActiveWeb3React()
return useContract(chainId && MULTICALL2_ADDRESSES[chainId], MULTICALL_ABI, false) as Multicall2
export function useMulticall2Contract() {
return useContract<Multicall2>(MULTICALL2_ADDRESSES, MULTICALL_ABI, false) as Multicall2
}
export function useMerkleDistributorContract(): Contract | null {
const { chainId } = useActiveWeb3React()
return useContract(chainId ? MERKLE_DISTRIBUTOR_ADDRESS[chainId] : undefined, MERKLE_DISTRIBUTOR_ABI, true)
export function useMerkleDistributorContract() {
return useContract(MERKLE_DISTRIBUTOR_ADDRESS, MERKLE_DISTRIBUTOR_ABI, true)
}
export function useGovernanceContract(): Contract | null {
export function useGovernanceContract() {
return useContract(GOVERNANCE_ADDRESS, GOVERNANCE_ABI, true)
}
export function useUniContract(): Contract | null {
export function useUniContract() {
const { chainId } = useActiveWeb3React()
return useContract(chainId ? UNI[chainId].address : undefined, UNI_ABI, true)
return useContract(chainId ? UNI[chainId]?.address : undefined, UNI_ABI, true)
}
export function useStakingContract(stakingAddress?: string, withSignerIfPossible?: boolean): Contract | null {
export function useStakingContract(stakingAddress?: string, withSignerIfPossible?: boolean) {
return useContract(stakingAddress, STAKING_REWARDS_ABI, withSignerIfPossible)
}
export function useSocksController(): Unisocks | null {
const { chainId } = useActiveWeb3React()
return useContract(
chainId === ChainId.MAINNET ? '0x65770b5283117639760beA3F867b69b3697a91dd' : undefined,
UNISOCKS_ABI,
false
) as Unisocks | null
return useContract<Unisocks>(SOCKS_CONTROLLER_ADDRESSES, UNISOCKS_ABI, false)
}
export function useV3NFTPositionManagerContract(withSignerIfPossible?: boolean): NonfungiblePositionManager | null {
const { chainId } = useActiveWeb3React()
const address = chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
return useContract(address, NFTPositionManagerABI, withSignerIfPossible) as NonfungiblePositionManager | null
return useContract<NonfungiblePositionManager>(
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
NFTPositionManagerABI,
withSignerIfPossible
)
}
export function useV3Factory(): UniswapV3Factory | null {
const { chainId } = useActiveWeb3React()
const address = chainId ? V3_CORE_FACTORY_ADDRESSES[chainId] : undefined
return useContract(address, V3FactoryABI) as UniswapV3Factory | null
export function useV3Factory() {
return useContract<UniswapV3Factory>(V3_CORE_FACTORY_ADDRESSES, V3FactoryABI) as UniswapV3Factory | null
}
export function useV3Pool(address: string | undefined): UniswapV3Pool | null {
return useContract(address, V3PoolABI) as UniswapV3Pool | null
export function useV3Pool(address: string | undefined) {
return useContract<UniswapV3Pool>(address, V3PoolABI)
}
export function useV3Quoter(): Quoter | null {
const { chainId } = useActiveWeb3React()
return useContract(chainId ? QUOTER_ADDRESSES[chainId] : undefined, QuoterABI) as Quoter | null
export function useV3Quoter() {
return useContract<Quoter>(QUOTER_ADDRESSES, QuoterABI)
}
export function useTickLens(): TickLens | null {
const { chainId } = useActiveWeb3React()
const address = chainId ? TICK_LENS_ADDRESSES[chainId] : undefined
return useContract(address, TickLensABI) as TickLens | null
return useContract<TickLens>(TICK_LENS_ADDRESSES, TickLensABI)
}

View File

@@ -4,10 +4,10 @@ import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { splitSignature } from 'ethers/lib/utils'
import { useMemo, useState } from 'react'
import { UNI, USDC, DAI } from '../constants'
import { SWAP_ROUTER_ADDRESSES } from '../constants/v3'
import { SWAP_ROUTER_ADDRESSES } from '../constants/addresses'
import { DAI, UNI, USDC } from '../constants/tokens'
import { useSingleCallResult } from '../state/multicall/hooks'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useEIP2612Contract } from './useContract'
import useIsArgentWallet from './useIsArgentWallet'
import useTransactionDeadline from './useTransactionDeadline'

View File

@@ -3,25 +3,24 @@ 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'
import resolveENSContentHash from '../utils/resolveENSContentHash'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
export function useFetchListCallback(): (listUrl: string, sendDispatch?: boolean) => Promise<TokenList> {
const { chainId, library } = useActiveWeb3React()
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

@@ -1,5 +1,5 @@
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useArgentWalletDetectorContract } from './useContract'
export default function useIsArgentWallet(): boolean {

View File

@@ -1,12 +1,12 @@
import { computePoolAddress } from '@uniswap/v3-sdk'
import { V3_CORE_FACTORY_ADDRESSES } from '../constants/addresses'
import { IUniswapV3PoolStateInterface } from '../types/v3/IUniswapV3PoolState'
import { Token, Currency } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useMultipleContractSingleData } from '../state/multicall/hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { Pool, FeeAmount } from '@uniswap/v3-sdk'
import { V3_CORE_FACTORY_ADDRESSES } from 'constants/v3'
import { abi as IUniswapV3PoolStateABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/pool/IUniswapV3PoolState.sol/IUniswapV3PoolState.json'
import { Interface } from '@ethersproject/abi'

View File

@@ -1,7 +1,7 @@
import JSBI from 'jsbi'
import { useMemo } from 'react'
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useSocksController } from './useContract'
export default function useSocksBalance(): JSBI | undefined {

View File

@@ -3,12 +3,13 @@ import { Router, Trade as V2Trade } from '@uniswap/v2-sdk'
import { SwapRouter, Trade as V3Trade } from '@uniswap/v3-sdk'
import { ChainId, Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { SWAP_ROUTER_ADDRESSES } from '../constants/v3'
import { SWAP_ROUTER_ADDRESSES } from '../constants/addresses'
import { calculateGasMargin } from '../utils/calculateGasMargin'
import { getTradeVersion } from '../utils/getTradeVersion'
import { useTransactionAdder } from '../state/transactions/hooks'
import { calculateGasMargin, isAddress, shortenAddress } from '../utils'
import { isAddress, shortenAddress } from '../utils'
import isZero from '../utils/isZero'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useV2RouterContract } from './useContract'
import { SignatureData } from './useERC20Permit'
import useTransactionDeadline from './useTransactionDeadline'
@@ -153,16 +154,26 @@ export function swapErrorToUserReadableMessage(error: any): string {
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 token could not be transferred. There may be an issue with the token.'
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.'
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:
return 'Unknown error. Please join the Discord to get help.'
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.`
}
}
@@ -271,8 +282,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 =
@@ -302,13 +313,11 @@ export function useSwapCallback(
// otherwise, the error was unexpected and we need to convey that
console.error(`Swap failed`, error, address, calldata, value)
throw new Error(
`Swap failed: ${'reason' in error ? swapErrorToUserReadableMessage(error) : 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

@@ -1,19 +0,0 @@
import { useActiveWeb3React } from '.'
import { useState, useEffect } from 'react'
export function useTimestampFromBlock(block: number | undefined): number | undefined {
const { library } = useActiveWeb3React()
const [timestamp, setTimestamp] = useState<number>()
useEffect(() => {
async function fetchTimestamp() {
if (block) {
const blockData = await library?.getBlock(block)
blockData && setTimestamp(blockData.timestamp)
}
}
if (!timestamp) {
fetchTimestamp()
}
}, [block, library, timestamp])
return timestamp
}

View File

@@ -1,10 +1,13 @@
import { ChainId, Currency, CurrencyAmount, currencyEquals, Price, Token, WETH9 } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
import { ChainId, Currency, CurrencyAmount, Price, Token } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { USDC } from '../constants'
import { PairState, useV2Pairs } from './useV2Pairs'
import { useActiveWeb3React } from '../hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { USDC } from '../constants/tokens'
import { useV2TradeExactOut } from './useV2Trade'
import { useBestV3TradeExactOut, V3TradeState } from './useBestV3Trade'
import { useActiveWeb3React } from './web3'
// USDC amount used when calculating spot price for a given currency.
// The amount is large enough to filter low liquidity pairs.
const usdcCurrencyAmount = CurrencyAmount.fromRawAmount(USDC, 10_000e6)
/**
* Returns the price in USDC of the input currency
@@ -12,23 +15,15 @@ import { wrappedCurrency } from '../utils/wrappedCurrency'
*/
export default function useUSDCPrice(currency?: Currency): Price<Currency, Token> | undefined {
const { chainId } = useActiveWeb3React()
const wrapped = wrappedCurrency(currency, chainId)
const weth = WETH9[chainId as ChainId]
const tokenPairs: [Currency | undefined, Currency | undefined][] = useMemo(
() => [
[chainId && wrapped && currencyEquals(weth, wrapped) ? undefined : currency, chainId ? weth : undefined],
[wrapped?.equals(USDC) ? undefined : wrapped, chainId === ChainId.MAINNET ? USDC : undefined],
[chainId ? weth : undefined, chainId === ChainId.MAINNET ? USDC : undefined],
],
[chainId, currency, weth, wrapped]
)
const [[ethPairState, ethPair], [usdcPairState, usdcPair], [usdcEthPairState, usdcEthPair]] = useV2Pairs(tokenPairs)
const v2USDCTrade = useV2TradeExactOut(currency, chainId === ChainId.MAINNET ? usdcCurrencyAmount : undefined)
const v3USDCTrade = useBestV3TradeExactOut(currency, chainId === ChainId.MAINNET ? usdcCurrencyAmount : undefined)
return useMemo(() => {
if (!currency || !wrapped || !chainId) {
if (!currency || !chainId) {
return undefined
}
// return some fake price data for non-mainnet
if (chainId !== ChainId.MAINNET) {
const fakeUSDC = new Token(chainId, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'fUSDC', 'Fake USDC')
@@ -40,40 +35,17 @@ export default function useUSDCPrice(currency?: Currency): Price<Currency, Token
)
}
// handle weth/eth
if (wrapped.equals(weth)) {
if (usdcPair) {
const price = usdcPair.priceOf(weth)
return new Price(currency, USDC, price.denominator, price.numerator)
} else {
return undefined
}
}
// handle usdc
if (wrapped.equals(USDC)) {
return new Price(USDC, USDC, '1', '1')
// use v2 price if available, v3 as fallback
if (v2USDCTrade) {
const { numerator, denominator } = v2USDCTrade.route.midPrice
return new Price(currency, USDC, denominator, numerator)
} else if (v3USDCTrade.state === V3TradeState.VALID && v3USDCTrade.trade) {
const { numerator, denominator } = v3USDCTrade.trade.route.midPrice
return new Price(currency, USDC, denominator, numerator)
}
const ethPairETHAmount = ethPair?.reserveOf(weth)
const ethPairETHUSDCValue: JSBI =
ethPairETHAmount && usdcEthPair ? usdcEthPair.priceOf(weth).quote(ethPairETHAmount).quotient : JSBI.BigInt(0)
// all other tokens
// first try the usdc pair
if (usdcPairState === PairState.EXISTS && usdcPair && usdcPair.reserveOf(USDC).greaterThan(ethPairETHUSDCValue)) {
const price = usdcPair.priceOf(wrapped)
return new Price(currency, USDC, price.denominator, price.numerator)
}
if (ethPairState === PairState.EXISTS && ethPair && usdcEthPairState === PairState.EXISTS && usdcEthPair) {
if (usdcEthPair.reserveOf(USDC).greaterThan('0') && ethPair.reserveOf(weth).greaterThan('0')) {
const ethUsdcPrice = usdcEthPair.priceOf(USDC)
const currencyEthPrice = ethPair.priceOf(weth)
const usdcPrice = ethUsdcPrice.multiply(currencyEthPrice).invert()
return new Price(currency, USDC, usdcPrice.denominator, usdcPrice.numerator)
}
}
return undefined
}, [chainId, currency, ethPair, ethPairState, usdcEthPair, usdcEthPairState, usdcPair, usdcPairState, weth, wrapped])
}, [chainId, currency, v2USDCTrade, v3USDCTrade])
}
export function useUSDCValue(currencyAmount: CurrencyAmount<Currency> | undefined | null) {
@@ -81,6 +53,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

@@ -2,7 +2,7 @@ import { Pair } from '@uniswap/v2-sdk'
import { useMemo } from 'react'
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
import { Interface } from '@ethersproject/abi'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useMultipleContractSingleData } from '../state/multicall/hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
@@ -61,5 +61,6 @@ export function useV2Pairs(currencies: [Currency | undefined, Currency | undefin
}
export function useV2Pair(tokenA?: Currency, tokenB?: Currency): [PairState, Pair | null] {
return useV2Pairs([[tokenA, tokenB]])[0]
const inputs: [[Currency | undefined, Currency | undefined]] = useMemo(() => [[tokenA, tokenB]], [tokenA, tokenB])
return useV2Pairs(inputs)[0]
}

View File

@@ -3,7 +3,7 @@ import { Pair, Trade } from '@uniswap/v2-sdk'
import { useMemo } from 'react'
import { useUserSingleHopOnly } from 'state/user/hooks'
import { isTradeBetter } from 'utils/isTradeBetter'
import { BETTER_TRADE_LESS_HOPS_THRESHOLD } from '../constants'
import { BETTER_TRADE_LESS_HOPS_THRESHOLD } from '../constants/misc'
import { useAllCurrencyCombinations } from './useAllCurrencyCombinations'
import { PairState, useV2Pairs } from './useV2Pairs'

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

@@ -3,7 +3,7 @@ import { useMemo } from 'react'
import { tryParseAmount } from '../state/swap/hooks'
import { useTransactionAdder } from '../state/transactions/hooks'
import { useCurrencyBalance } from '../state/wallet/hooks'
import { useActiveWeb3React } from './index'
import { useActiveWeb3React } from './web3'
import { useWETHContract } from './useContract'
export enum WrapType {

View File

@@ -5,7 +5,7 @@ import { Web3ReactContextInterface } from '@web3-react/core/dist/types'
import { useEffect, useState } from 'react'
import { isMobile } from 'react-device-detect'
import { injected } from '../connectors'
import { NetworkContextName } from '../constants'
import { NetworkContextName } from '../constants/misc'
export function useActiveWeb3React(): Web3ReactContextInterface<Web3Provider> & { chainId?: ChainId } {
const context = useWeb3ReactCore<Web3Provider>()

View File

@@ -7,7 +7,7 @@ import ReactGA from 'react-ga'
import { Provider } from 'react-redux'
import { HashRouter } from 'react-router-dom'
import Blocklist from './components/Blocklist'
import { NetworkContextName } from './constants'
import { NetworkContextName } from './constants/misc'
import './i18n'
import App from './pages/App'
import store from './state'

View File

@@ -4,7 +4,7 @@ import { Text } from 'rebass'
import { ThemeContext } from 'styled-components'
import { AutoColumn } from '../../components/Column'
import { AutoRow } from '../../components/Row'
import { ONE_BIPS } from '../../constants'
import { ONE_BIPS } from '../../constants/misc'
import { Field } from '../../state/mint/v3/actions'
import { TYPE } from '../../theme'

View File

@@ -1,10 +1,11 @@
import React, { useCallback, useContext, useMemo, useState, useEffect } from 'react'
import React, { useCallback, useContext, useMemo, useState } from 'react'
import { TransactionResponse } from '@ethersproject/providers'
import { Currency, CurrencyAmount, currencyEquals, Percent } from '@uniswap/sdk-core'
import { WETH9 } from '@uniswap/sdk-core'
import { AlertTriangle, AlertCircle } from 'react-feather'
import ReactGA from 'react-ga'
import { ZERO_PERCENT } from '../../constants'
import { ZERO_PERCENT } from '../../constants/misc'
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from '../../constants/addresses'
import { useV3NFTPositionManagerContract } from '../../hooks/useContract'
import { RouteComponentProps } from 'react-router-dom'
import { Text } from 'rebass'
@@ -17,8 +18,9 @@ import CurrencyInputPanel from '../../components/CurrencyInputPanel'
import { RowBetween, RowFixed } from '../../components/Row'
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
import { useUSDCValue } from '../../hooks/useUSDCPrice'
import { calculateGasMargin } from '../../utils/calculateGasMargin'
import Review from './Review'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useCurrency } from '../../hooks/Tokens'
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
import useTransactionDeadline from '../../hooks/useTransactionDeadline'
@@ -42,7 +44,6 @@ import {
useV3DerivedMintInfo,
} from 'state/mint/v3/hooks'
import { FeeAmount, NonfungiblePositionManager } from '@uniswap/v3-sdk'
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from 'constants/v3'
import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
import { useDerivedPositionInfo } from 'hooks/useDerivedPositionInfo'
import { PositionPreview } from 'components/PositionPreview'
@@ -50,7 +51,6 @@ import FeeSelector from 'components/FeeSelector'
import RangeSelector from 'components/RangeSelector'
import RateToggle from 'components/RateToggle'
import { BigNumber } from '@ethersproject/bignumber'
import { calculateGasMargin } from 'utils'
import { AddRemoveTabs } from 'components/NavigationTabs'
import HoverInlineText from 'components/HoverInlineText'
@@ -88,7 +88,7 @@ export default function AddLiquidity({
const currencyB = useCurrency(currencyIdB)
// keep track for UI display purposes of user selected base currency
const [baseCurrency, setBaseCurrency] = useState(currencyA)
const baseCurrency = currencyA
const quoteCurrency = useMemo(
() =>
currencyA && currencyB && baseCurrency
@@ -99,14 +99,6 @@ export default function AddLiquidity({
[currencyA, currencyB, baseCurrency]
)
// url params are the source truth, so we have to do this
useEffect(() => {
setBaseCurrency(currencyA)
return () => {
setBaseCurrency(undefined)
}
}, [currencyA, currencyB])
// mint state
const { independentField, typedValue, startPriceTypedValue } = useV3MintState()

View File

@@ -1,4 +1,4 @@
import { useActiveWeb3React } from 'hooks'
import { useActiveWeb3React } from 'hooks/web3'
import React from 'react'
import { Redirect, RouteComponentProps } from 'react-router-dom'
import AddLiquidity from './index'

View File

@@ -4,7 +4,7 @@ import { Text } from 'rebass'
import { ThemeContext } from 'styled-components'
import { AutoColumn } from '../../components/Column'
import { AutoRow } from '../../components/Row'
import { ONE_BIPS } from '../../constants'
import { ONE_BIPS } from '../../constants/misc'
import { Field } from '../../state/mint/actions'
import { TYPE } from '../../theme'

View File

@@ -17,10 +17,10 @@ import { AddRemoveTabs } from '../../components/NavigationTabs'
import { MinimalPositionCard } from '../../components/PositionCard'
import Row, { RowBetween, RowFlat } from '../../components/Row'
import { V2_ROUTER_ADDRESS, ZERO_PERCENT } from '../../constants'
import { ZERO_PERCENT } from '../../constants/misc'
import { useV2RouterContract } from '../../hooks/useContract'
import { PairState } from '../../hooks/useV2Pairs'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useCurrency } from '../../hooks/Tokens'
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
@@ -32,7 +32,8 @@ import { useDerivedMintInfo, useMintActionHandlers, useMintState } from '../../s
import { useTransactionAdder } from '../../state/transactions/hooks'
import { useIsExpertMode, useUserSlippageToleranceWithDefault } from '../../state/user/hooks'
import { TYPE } from '../../theme'
import { calculateGasMargin, calculateSlippageAmount } from '../../utils'
import { calculateGasMargin } from '../../utils/calculateGasMargin'
import { calculateSlippageAmount } from '../../utils/calculateSlippageAmount'
import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { wrappedCurrency } from '../../utils/wrappedCurrency'
import AppBody from '../AppBody'
@@ -122,14 +123,14 @@ export default function AddLiquidity({
{}
)
const router = useV2RouterContract()
// check whether the user has approved the router on the tokens
const [approvalA, approveACallback] = useApproveCallback(parsedAmounts[Field.CURRENCY_A], V2_ROUTER_ADDRESS)
const [approvalB, approveBCallback] = useApproveCallback(parsedAmounts[Field.CURRENCY_B], V2_ROUTER_ADDRESS)
const [approvalA, approveACallback] = useApproveCallback(parsedAmounts[Field.CURRENCY_A], router?.address)
const [approvalB, approveBCallback] = useApproveCallback(parsedAmounts[Field.CURRENCY_B], router?.address)
const addTransaction = useTransactionAdder()
const router = useV2RouterContract()
async function onAdd() {
if (!chainId || !library || !account || !router) return

View File

@@ -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

@@ -18,7 +18,7 @@ import { useStakingInfo } from '../../state/stake/hooks'
import UnstakingModal from '../../components/earn/UnstakingModal'
import ClaimRewardModal from '../../components/earn/ClaimRewardModal'
import { useTokenBalance } from '../../state/wallet/hooks'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useColor } from '../../hooks/useColor'
import { CountUp } from 'use-count-up'
@@ -28,7 +28,7 @@ import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useV2Pair } from '../../hooks/useV2Pairs'
import usePrevious from '../../hooks/usePrevious'
import useUSDCPrice from '../../hooks/useUSDCPrice'
import { BIG_INT_ZERO, BIG_INT_SECONDS_IN_WEEK } from '../../constants'
import { BIG_INT_ZERO, BIG_INT_SECONDS_IN_WEEK } from '../../constants/misc'
const PageWrapper = styled(AutoColumn)`
max-width: 640px;

View File

@@ -9,8 +9,8 @@ import { RowBetween } from '../../components/Row'
import { CardSection, DataCard, CardNoise, CardBGImage } from '../../components/earn/styled'
import { Countdown } from './Countdown'
import Loader from '../../components/Loader'
import { useActiveWeb3React } from '../../hooks'
import { BIG_INT_ZERO } from '../../constants'
import { useActiveWeb3React } from '../../hooks/web3'
import { BIG_INT_ZERO } from '../../constants/misc'
import { OutlineCard } from '../../components/Card'
const PageWrapper = styled(AutoColumn)`

View File

@@ -10,15 +10,16 @@ import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useToken } from '../../hooks/Tokens'
import { usePairContract, useV2MigratorContract } from '../../hooks/useContract'
import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks'
import { useTokenBalance } from '../../state/wallet/hooks'
import { BackArrow, ExternalLink, TYPE } from '../../theme'
import { calculateGasMargin, getEtherscanLink, isAddress } from '../../utils'
import { isAddress } from '../../utils'
import { calculateGasMargin } from '../../utils/calculateGasMargin'
import { getExplorerLink, ExplorerDataType } from '../../utils/getExplorerLink'
import { BodyWrapper } from '../AppBody'
import { V3_MIGRATOR_ADDRESSES } from 'constants/v3'
import { PoolState, usePool } from 'hooks/usePools'
import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk'
import { BlueCard, DarkGreyCard, LightCard, YellowCard } from 'components/Card'
@@ -208,6 +209,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
@@ -253,9 +255,8 @@ function V2PairMigration({
const migrator = useV2MigratorContract()
// approvals
const migratorAddress = chainId && V3_MIGRATOR_ADDRESSES[chainId]
const [approval, approveManually] = useApproveCallback(pairBalance, migratorAddress)
const { signatureData, gatherPermitSignature } = useV2LiquidityTokenPermit(pairBalance, migratorAddress)
const [approval, approveManually] = useApproveCallback(pairBalance, migrator?.address)
const { signatureData, gatherPermitSignature } = useV2LiquidityTokenPermit(pairBalance, migrator?.address)
const approve = useCallback(async () => {
if (isNotUniswap) {
@@ -395,8 +396,8 @@ function V2PairMigration({
<TYPE.body my={9} style={{ fontWeight: 400 }}>
This tool will safely migrate your {isNotUniswap ? 'SushiSwap' : 'V2'} liquidity to V3. The process is
completely trustless thanks to the{' '}
{chainId && migratorAddress && (
<ExternalLink href={getEtherscanLink(chainId, migratorAddress, 'address')}>
{chainId && migrator && (
<ExternalLink href={getExplorerLink(chainId, migrator.address, ExplorerDataType.ADDRESS)}>
<TYPE.blue display="inline">Uniswap migration contract</TYPE.blue>
</ExternalLink>
)}

View File

@@ -5,7 +5,7 @@ import { ThemeContext } from 'styled-components'
import { AutoColumn } from '../../components/Column'
import { AutoRow } from '../../components/Row'
import { Text } from 'rebass'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalancesWithLoadingIndicator } from '../../state/wallet/hooks'
import { BackArrow, StyledInternalLink, TYPE } from '../../theme'
import { LightCard } from '../../components/Card'

View File

@@ -1,12 +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 { calculateGasMargin } from '../../utils/calculateGasMargin'
import { getExplorerLink, ExplorerDataType } from '../../utils/getExplorerLink'
import { LoadingRows } from './styleds'
import styled from 'styled-components/macro'
import { AutoColumn } from 'components/Column'
@@ -14,7 +16,6 @@ import { RowBetween, RowFixed } from 'components/Row'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { ExternalLink, HideExtraSmall, TYPE } from 'theme'
import Badge from 'components/Badge'
import { calculateGasMargin, getEtherscanLink } from 'utils'
import { ButtonConfirmed, ButtonPrimary, ButtonGray } from 'components/Button'
import { DarkCard, LightCard } from 'components/Card'
import CurrencyLogo from 'components/CurrencyLogo'
@@ -23,8 +24,18 @@ 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 { useActiveWeb3React } from 'hooks'
import {
Token,
Currency,
CurrencyAmount,
Percent,
Fraction,
Price,
Ether,
currencyEquals,
ETHER,
} from '@uniswap/sdk-core'
import { useActiveWeb3React } from 'hooks/web3'
import { useV3NFTPositionManagerContract } from 'hooks/useContract'
import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks'
import ReactGA from 'react-ga'
@@ -38,6 +49,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;
@@ -172,6 +184,28 @@ function CurrentPriceCard({
)
}
function LinkedCurrency({ chainId, currency }: { chainId?: number; currency?: Currency }) {
const address = (currency as Token)?.address
if (typeof chainId === 'number' && address) {
return (
<ExternalLink href={getExplorerLink(chainId, address, ExplorerDataType.ADDRESS)}>
<RowFixed>
<CurrencyLogo currency={currency} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{currency?.symbol} </TYPE.main>
</RowFixed>
</ExternalLink>
)
}
return (
<RowFixed>
<CurrencyLogo currency={currency} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{currency?.symbol}</TYPE.main>
</RowFixed>
)
}
function getRatio(
lower: Price<Currency, Currency>,
current: Price<Currency, Currency>,
@@ -200,20 +234,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 +256,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 +318,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 +356,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 +372,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 +419,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 +444,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 +454,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>
@@ -525,7 +568,7 @@ export function PositionPage({
<NFT image={metadata.result.image} height={400} />
</div>
{typeof chainId === 'number' && owner && !ownsNFT ? (
<ExternalLink href={getEtherscanLink(chainId, owner, 'address')}>Owner</ExternalLink>
<ExternalLink href={getExplorerLink(chainId, owner, ExplorerDataType.ADDRESS)}>Owner</ExternalLink>
) : null}
</DarkCard>
) : (
@@ -547,7 +590,7 @@ export function PositionPage({
<Label>Liquidity</Label>
{fiatValueOfLiquidity?.greaterThan(new Fraction(1, 100)) ? (
<TYPE.largeHeader fontSize="36px" fontWeight={500}>
${fiatValueOfLiquidity.toFixed(2)}
${fiatValueOfLiquidity.toFixed(2, { groupSeparator: ',' })}
</TYPE.largeHeader>
) : (
<TYPE.largeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
@@ -558,10 +601,7 @@ export function PositionPage({
<LightCard padding="12px 16px">
<AutoColumn gap="md">
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyQuote} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{currencyQuote?.symbol}</TYPE.main>
</RowFixed>
<LinkedCurrency chainId={chainId} currency={currencyQuote} />
<RowFixed>
<TYPE.main>
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
@@ -574,10 +614,7 @@ export function PositionPage({
</RowFixed>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyBase} size={'20px'} style={{ marginRight: '0.5rem' }} />
<TYPE.main>{currencyBase?.symbol}</TYPE.main>
</RowFixed>
<LinkedCurrency chainId={chainId} currency={currencyBase} />
<RowFixed>
<TYPE.main>
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
@@ -603,7 +640,7 @@ export function PositionPage({
<Label>Unclaimed fees</Label>
{fiatValueOfFees?.greaterThan(new Fraction(1, 100)) ? (
<TYPE.largeHeader color={theme.green1} fontSize="36px" fontWeight={500}>
${fiatValueOfFees.toFixed(2)}
${fiatValueOfFees.toFixed(2, { groupSeparator: ',' })}
</TYPE.largeHeader>
) : (
<TYPE.largeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
@@ -640,40 +677,49 @@ 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)) &&
currency0 &&
currency1 &&
(currencyEquals(currency0, ETHER) || currencyEquals(currency1, ETHER)) &&
!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

@@ -5,7 +5,7 @@ import { FlyoutAlignment, NewMenu } from 'components/Menu'
import { SwapPoolTabs } from 'components/NavigationTabs'
import PositionList from 'components/PositionList'
import { RowBetween, RowFixed } from 'components/Row'
import { useActiveWeb3React } from 'hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { useV3Positions } from 'hooks/useV3Positions'
import { BookOpen, ChevronDown, Download, Inbox, PlusCircle, ChevronsRight, Layers } from 'react-feather'
import { useTranslation } from 'react-i18next'

View File

@@ -14,13 +14,13 @@ import { ChevronsRight } from 'react-feather'
import { AutoColumn } from '../../components/Column'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { useV2Pairs } from '../../hooks/useV2Pairs'
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
import { Dots } from '../../components/swap/styleds'
import { CardSection, DataCard, CardNoise, CardBGImage } from '../../components/earn/styled'
import { useStakingInfo } from '../../state/stake/hooks'
import { BIG_INT_ZERO } from '../../constants'
import { BIG_INT_ZERO } from '../../constants/misc'
import { Pair } from '@uniswap/v2-sdk'
const PageWrapper = styled(AutoColumn)`

View File

@@ -12,7 +12,7 @@ import { MinimalPositionCard } from '../../components/PositionCard'
import Row from '../../components/Row'
import CurrencySearchModal from '../../components/SearchModal/CurrencySearchModal'
import { PairState, useV2Pair } from '../../hooks/useV2Pairs'
import { useActiveWeb3React } from '../../hooks'
import { useActiveWeb3React } from '../../hooks/web3'
import { usePairAdder } from '../../state/user/hooks'
import { useTokenBalance } from '../../state/wallet/hooks'
import { StyledInternalLink } from '../../theme'

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