Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bc5d6504e | ||
|
|
7a0b85bf41 | ||
|
|
534afb3278 | ||
|
|
7d71af353e | ||
|
|
af6098bfe5 | ||
|
|
fce29bb36f | ||
|
|
4517af39ba | ||
|
|
b40163ce05 | ||
|
|
809902efec | ||
|
|
70be9894fa | ||
|
|
698ad5bac9 | ||
|
|
cd37b7533d | ||
|
|
c0cd6a1c8d | ||
|
|
f6245d1093 | ||
|
|
83c784f7c0 | ||
|
|
3d95b1a33b |
3
.env
3
.env
@@ -1,5 +1,4 @@
|
|||||||
REACT_APP_CHAIN_ID="1"
|
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||||
REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847"
|
|
||||||
REACT_APP_WALLETCONNECT_BRIDGE_URL="https://uniswap.bridge.walletconnect.org"
|
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
|
# 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
|
SKIP_PREFLIGHT_CHECK=true
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
REACT_APP_CHAIN_ID="1"
|
REACT_APP_INFURA_KEY="099fc58e0de9451d80b18d7c74caa7c1"
|
||||||
REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/099fc58e0de9451d80b18d7c74caa7c1"
|
|
||||||
REACT_APP_PORTIS_ID="c0e2bf01-4b08-4fd5-ac7b-8e26b58cd236"
|
REACT_APP_PORTIS_ID="c0e2bf01-4b08-4fd5-ac7b-8e26b58cd236"
|
||||||
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
|
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
|
||||||
REACT_APP_GOOGLE_ANALYTICS_ID="UA-128182339-4"
|
REACT_APP_GOOGLE_ANALYTICS_ID="UA-128182339-4"
|
||||||
|
|||||||
14
.github/workflows/release.yaml
vendored
14
.github/workflows/release.yaml
vendored
@@ -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).
|
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.
|
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**: 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.
|
||||||
**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 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).
|
||||||
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).
|
Your Uniswap settings are never remembered across different URLs.
|
||||||
The preferred URLs below are safe to use to access this specific release.
|
|
||||||
|
|
||||||
Preferred URLs:
|
IPFS gateways:
|
||||||
- https://${{ steps.convert_cidv0.outputs.cidv1 }}.ipfs.dweb.link/
|
- https://${{ steps.convert_cidv0.outputs.cidv1 }}.ipfs.dweb.link/
|
||||||
- https://${{ steps.convert_cidv0.outputs.cidv1 }}.ipfs.cf-ipfs.com/
|
- https://${{ steps.convert_cidv0.outputs.cidv1 }}.ipfs.cf-ipfs.com/
|
||||||
- [ipfs://${{ steps.upload.outputs.hash }}/](ipfs://${{ steps.upload.outputs.hash }}/)
|
- [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 }}
|
${{ needs.bump_version.outputs.changelog }}
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -27,7 +27,7 @@ or visit [app.uniswap.org](https://app.uniswap.org).
|
|||||||
### Install Dependencies
|
### Install Dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn
|
yarn install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run
|
### Run
|
||||||
@@ -36,19 +36,6 @@ yarn
|
|||||||
yarn start
|
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
|
## Contributions
|
||||||
|
|
||||||
**Please open all pull requests against the `main` branch.**
|
**Please open all pull requests against the `main` branch.**
|
||||||
|
|||||||
@@ -51,13 +51,13 @@
|
|||||||
"@uniswap/v2-sdk": "^3.0.0-alpha.0",
|
"@uniswap/v2-sdk": "^3.0.0-alpha.0",
|
||||||
"@uniswap/v3-core": "1.0.0",
|
"@uniswap/v3-core": "1.0.0",
|
||||||
"@uniswap/v3-periphery": "1.0.0",
|
"@uniswap/v3-periphery": "1.0.0",
|
||||||
"@uniswap/v3-sdk": "^3.0.0-alpha.1",
|
"@uniswap/v3-sdk": "^3.0.0-alpha.4",
|
||||||
"@web3-react/core": "^6.0.9",
|
"@web3-react/core": "^6.0.9",
|
||||||
"@web3-react/fortmatic-connector": "^6.0.9",
|
"@web3-react/fortmatic-connector": "^6.0.9",
|
||||||
"@web3-react/injected-connector": "^6.0.7",
|
"@web3-react/injected-connector": "^6.0.7",
|
||||||
"@web3-react/portis-connector": "^6.0.9",
|
"@web3-react/portis-connector": "^6.0.9",
|
||||||
"@web3-react/walletconnect-connector": "^6.1.1",
|
"@web3-react/walletconnect-connector": "^6.2.0",
|
||||||
"@web3-react/walletlink-connector": "^6.0.9",
|
"@web3-react/walletlink-connector": "^6.2.0",
|
||||||
"ajv": "^6.12.3",
|
"ajv": "^6.12.3",
|
||||||
"cids": "^1.0.0",
|
"cids": "^1.0.0",
|
||||||
"copy-to-clipboard": "^3.2.0",
|
"copy-to-clipboard": "^3.2.0",
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { Percent, Currency, TradeType } from '@uniswap/sdk-core'
|
import { Percent, Currency, TradeType } from '@uniswap/sdk-core'
|
||||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||||
import { Trade as V3Trade } from '@uniswap/v3-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 { ThemeContext } from 'styled-components'
|
||||||
import { TYPE } from '../../theme'
|
import { TYPE } from '../../theme'
|
||||||
import { computePriceImpactWithMaximumSlippage } from '../../utils/computePriceImpactWithMaximumSlippage'
|
import { computeRealizedLPFeePercent } from '../../utils/prices'
|
||||||
import { computeRealizedLPFeeAmount } from '../../utils/prices'
|
|
||||||
import { AutoColumn } from '../Column'
|
import { AutoColumn } from '../Column'
|
||||||
import { RowBetween, RowFixed } from '../Row'
|
import { RowBetween, RowFixed } from '../Row'
|
||||||
import FormattedPriceImpact from './FormattedPriceImpact'
|
import FormattedPriceImpact from './FormattedPriceImpact'
|
||||||
@@ -19,7 +18,14 @@ export interface AdvancedSwapDetailsProps {
|
|||||||
export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDetailsProps) {
|
export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDetailsProps) {
|
||||||
const theme = useContext(ThemeContext)
|
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 : (
|
return !trade ? null : (
|
||||||
<AutoColumn gap="8px">
|
<AutoColumn gap="8px">
|
||||||
@@ -30,7 +36,7 @@ export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDeta
|
|||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<TYPE.black textAlign="right" fontSize={12} color={theme.text1}>
|
<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>
|
</TYPE.black>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
|
||||||
@@ -48,11 +54,24 @@ export function AdvancedSwapDetails({ trade, allowedSlippage }: AdvancedSwapDeta
|
|||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
|
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
|
||||||
Execution price vs. spot price
|
Price Impact
|
||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<TYPE.black textAlign="right" fontSize={12} color={theme.text1}>
|
<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>
|
</TYPE.black>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ export default function ConfirmSwapModal({
|
|||||||
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade])
|
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade])
|
||||||
|
|
||||||
// text to show while loading
|
// text to show while loading
|
||||||
const pendingText = `Swapping ${trade?.maximumAmountIn(allowedSlippage)?.toSignificant(6)} ${
|
const pendingText = `Swapping ${trade?.inputAmount?.toSignificant(6)} ${
|
||||||
trade?.inputAmount?.currency?.symbol
|
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(
|
const confirmationContent = useCallback(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -31,12 +31,10 @@ export const ArrowWrapper = styled.div`
|
|||||||
margin-top: -18px;
|
margin-top: -18px;
|
||||||
margin-bottom: -18px;
|
margin-bottom: -18px;
|
||||||
left: calc(50% - 16px);
|
left: calc(50% - 16px);
|
||||||
/* transform: rotate(90deg); */
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: ${({ theme }) => theme.bg1};
|
background-color: ${({ theme }) => theme.bg1};
|
||||||
/* border: 4px solid ${({ theme }) => theme.bg0}; */
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -53,15 +51,12 @@ export default function SwapModalHeader({
|
|||||||
showAcceptChanges: boolean
|
showAcceptChanges: boolean
|
||||||
onAcceptChanges: () => void
|
onAcceptChanges: () => void
|
||||||
}) {
|
}) {
|
||||||
const maximumAmountIn = trade.maximumAmountIn(allowedSlippage)
|
|
||||||
const minimumAmountOut = trade.minimumAmountOut(allowedSlippage)
|
|
||||||
|
|
||||||
const theme = useContext(ThemeContext)
|
const theme = useContext(ThemeContext)
|
||||||
|
|
||||||
const [showInverted, setShowInverted] = useState<boolean>(false)
|
const [showInverted, setShowInverted] = useState<boolean>(false)
|
||||||
|
|
||||||
const fiatValueInput = useUSDCValue(maximumAmountIn)
|
const fiatValueInput = useUSDCValue(trade.inputAmount)
|
||||||
const fiatValueOutput = useUSDCValue(minimumAmountOut)
|
const fiatValueOutput = useUSDCValue(trade.outputAmount)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}>
|
<AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}>
|
||||||
@@ -86,7 +81,7 @@ export default function SwapModalHeader({
|
|||||||
fontWeight={500}
|
fontWeight={500}
|
||||||
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? theme.primary1 : ''}
|
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? theme.primary1 : ''}
|
||||||
>
|
>
|
||||||
{maximumAmountIn.toSignificant(6)}
|
{trade.inputAmount.toSignificant(6)}
|
||||||
</TruncatedText>
|
</TruncatedText>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
@@ -117,7 +112,7 @@ export default function SwapModalHeader({
|
|||||||
</RowFixed>
|
</RowFixed>
|
||||||
<RowFixed gap={'0px'}>
|
<RowFixed gap={'0px'}>
|
||||||
<TruncatedText fontSize={24} fontWeight={500}>
|
<TruncatedText fontSize={24} fontWeight={500}>
|
||||||
{minimumAmountOut.toSignificant(6)}
|
{trade.outputAmount.toSignificant(6)}
|
||||||
</TruncatedText>
|
</TruncatedText>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
@@ -127,11 +122,7 @@ export default function SwapModalHeader({
|
|||||||
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
|
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
|
||||||
{'Price:'}
|
{'Price:'}
|
||||||
</TYPE.body>
|
</TYPE.body>
|
||||||
<TradePrice
|
<TradePrice price={trade.executionPrice} showInverted={showInverted} setShowInverted={setShowInverted} />
|
||||||
price={trade.worstExecutionPrice(allowedSlippage)}
|
|
||||||
showInverted={showInverted}
|
|
||||||
setShowInverted={setShowInverted}
|
|
||||||
/>
|
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
|
||||||
<LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}>
|
<LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}>
|
||||||
@@ -155,12 +146,12 @@ export default function SwapModalHeader({
|
|||||||
</SwapShowAcceptChanges>
|
</SwapShowAcceptChanges>
|
||||||
) : null}
|
) : 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 ? (
|
{trade.tradeType === TradeType.EXACT_INPUT ? (
|
||||||
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||||
{`Output is estimated. You will receive at least `}
|
{`Output is estimated. You will receive at least `}
|
||||||
<b>
|
<b>
|
||||||
{minimumAmountOut.toSignificant(6)} {trade.outputAmount.currency.symbol}
|
{trade.minimumAmountOut(allowedSlippage).toSignificant(6)} {trade.outputAmount.currency.symbol}
|
||||||
</b>
|
</b>
|
||||||
{' or the transaction will revert.'}
|
{' or the transaction will revert.'}
|
||||||
</TYPE.italic>
|
</TYPE.italic>
|
||||||
@@ -168,12 +159,12 @@ export default function SwapModalHeader({
|
|||||||
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||||
{`Input is estimated. You will sell at most `}
|
{`Input is estimated. You will sell at most `}
|
||||||
<b>
|
<b>
|
||||||
{maximumAmountIn.toSignificant(6)} {trade.inputAmount.currency.symbol}
|
{trade.maximumAmountIn(allowedSlippage).toSignificant(6)} {trade.inputAmount.currency.symbol}
|
||||||
</b>
|
</b>
|
||||||
{' or the transaction will revert.'}
|
{' or the transaction will revert.'}
|
||||||
</TYPE.italic>
|
</TYPE.italic>
|
||||||
)}
|
)}
|
||||||
</AutoColumn> */}
|
</AutoColumn>
|
||||||
{recipient !== null ? (
|
{recipient !== null ? (
|
||||||
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
|
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
|
||||||
<TYPE.main>
|
<TYPE.main>
|
||||||
|
|||||||
@@ -1,40 +1,53 @@
|
|||||||
import { Web3Provider } from '@ethersproject/providers'
|
import { Web3Provider } from '@ethersproject/providers'
|
||||||
|
import { ChainId } from '@uniswap/sdk-core'
|
||||||
import { InjectedConnector } from '@web3-react/injected-connector'
|
import { InjectedConnector } from '@web3-react/injected-connector'
|
||||||
import { WalletConnectConnector } from '@web3-react/walletconnect-connector'
|
import { WalletConnectConnector } from '@web3-react/walletconnect-connector'
|
||||||
import { WalletLinkConnector } from '@web3-react/walletlink-connector'
|
import { WalletLinkConnector } from '@web3-react/walletlink-connector'
|
||||||
import { PortisConnector } from '@web3-react/portis-connector'
|
import { PortisConnector } from '@web3-react/portis-connector'
|
||||||
|
import getLibrary from '../utils/getLibrary'
|
||||||
|
|
||||||
import { FortmaticConnector } from './Fortmatic'
|
import { FortmaticConnector } from './Fortmatic'
|
||||||
import { NetworkConnector } from './NetworkConnector'
|
import { NetworkConnector } from './NetworkConnector'
|
||||||
import UNISWAP_LOGO_URL from '../assets/svg/logo.svg'
|
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 FORMATIC_KEY = process.env.REACT_APP_FORTMATIC_KEY
|
||||||
const PORTIS_ID = process.env.REACT_APP_PORTIS_ID
|
const PORTIS_ID = process.env.REACT_APP_PORTIS_ID
|
||||||
const WALLETCONNECT_BRIDGE_URL = process.env.REACT_APP_WALLETCONNECT_BRIDGE_URL
|
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 INFURA_KEY === 'undefined') {
|
||||||
|
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
|
||||||
if (typeof NETWORK_URL === 'undefined') {
|
|
||||||
throw new Error(`REACT_APP_NETWORK_URL 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({
|
export const network = new NetworkConnector({
|
||||||
urls: { [NETWORK_CHAIN_ID]: NETWORK_URL },
|
urls: NETWORK_URLS,
|
||||||
|
defaultChainId: ChainId.MAINNET,
|
||||||
})
|
})
|
||||||
|
|
||||||
let networkLibrary: Web3Provider | undefined
|
let networkLibrary: Web3Provider | undefined
|
||||||
export function getNetworkLibrary(): Web3Provider {
|
export function getNetworkLibrary(): Web3Provider {
|
||||||
return (networkLibrary = networkLibrary ?? new Web3Provider(network.provider as any))
|
return (networkLibrary = networkLibrary ?? getLibrary(network.provider))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const injected = new InjectedConnector({
|
export const injected = new InjectedConnector({
|
||||||
supportedChainIds: [1, 3, 4, 5, 42],
|
supportedChainIds: SUPPORTED_CHAIN_IDS,
|
||||||
})
|
})
|
||||||
|
|
||||||
// mainnet only
|
|
||||||
export const walletconnect = new WalletConnectConnector({
|
export const walletconnect = new WalletConnectConnector({
|
||||||
rpc: { 1: NETWORK_URL },
|
supportedChainIds: SUPPORTED_CHAIN_IDS,
|
||||||
|
infuraId: INFURA_KEY, // obviously a hack
|
||||||
bridge: WALLETCONNECT_BRIDGE_URL,
|
bridge: WALLETCONNECT_BRIDGE_URL,
|
||||||
qrcode: true,
|
qrcode: true,
|
||||||
pollingInterval: 15000,
|
pollingInterval: 15000,
|
||||||
@@ -54,7 +67,7 @@ export const portis = new PortisConnector({
|
|||||||
|
|
||||||
// mainnet only
|
// mainnet only
|
||||||
export const walletlink = new WalletLinkConnector({
|
export const walletlink = new WalletLinkConnector({
|
||||||
url: NETWORK_URL,
|
url: NETWORK_URLS[ChainId.MAINNET],
|
||||||
appName: 'Uniswap',
|
appName: 'Uniswap',
|
||||||
appLogoUrl: UNISWAP_LOGO_URL,
|
appLogoUrl: UNISWAP_LOGO_URL,
|
||||||
})
|
})
|
||||||
|
|||||||
22
src/hooks/useApeModeQueryParamReader.ts
Normal file
22
src/hooks/useApeModeQueryParamReader.ts
Normal 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 }))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { ChainId } from '@uniswap/sdk-core'
|
|||||||
import { TokenList } from '@uniswap/token-lists'
|
import { TokenList } from '@uniswap/token-lists'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch } from 'react-redux'
|
||||||
import { getNetworkLibrary, NETWORK_CHAIN_ID } from '../connectors'
|
import { getNetworkLibrary } from '../connectors'
|
||||||
import { AppDispatch } from '../state'
|
import { AppDispatch } from '../state'
|
||||||
import { fetchTokenList } from '../state/lists/actions'
|
import { fetchTokenList } from '../state/lists/actions'
|
||||||
import getTokenList from '../utils/getTokenList'
|
import getTokenList from '../utils/getTokenList'
|
||||||
@@ -15,13 +15,12 @@ export function useFetchListCallback(): (listUrl: string, sendDispatch?: boolean
|
|||||||
const dispatch = useDispatch<AppDispatch>()
|
const dispatch = useDispatch<AppDispatch>()
|
||||||
|
|
||||||
const ensResolver = useCallback(
|
const ensResolver = useCallback(
|
||||||
(ensName: string) => {
|
async (ensName: string) => {
|
||||||
if (!library || chainId !== ChainId.MAINNET) {
|
if (!library || chainId !== ChainId.MAINNET) {
|
||||||
if (NETWORK_CHAIN_ID === ChainId.MAINNET) {
|
const networkLibrary = getNetworkLibrary()
|
||||||
const networkLibrary = getNetworkLibrary()
|
const network = await networkLibrary.getNetwork()
|
||||||
if (networkLibrary) {
|
if (networkLibrary && network.chainId === ChainId.MAINNET) {
|
||||||
return resolveENSContentHash(ensName, networkLibrary)
|
return resolveENSContentHash(ensName, networkLibrary)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new Error('Could not construct mainnet ENS resolver')
|
throw new Error('Could not construct mainnet ENS resolver')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export function swapErrorToUserReadableMessage(error: any): string {
|
|||||||
let reason: string | undefined
|
let reason: string | undefined
|
||||||
while (Boolean(error)) {
|
while (Boolean(error)) {
|
||||||
reason = error.reason ?? error.message ?? reason
|
reason = error.reason ?? error.message ?? reason
|
||||||
error = error.error ?? error.data.originalError
|
error = error.error ?? error.data?.originalError
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason?.indexOf('execution reverted: ') === 0) reason = reason.substr('execution reverted: '.length)
|
if (reason?.indexOf('execution reverted: ') === 0) reason = reason.substr('execution reverted: '.length)
|
||||||
@@ -153,16 +153,20 @@ export function swapErrorToUserReadableMessage(error: any): string {
|
|||||||
case 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT':
|
case 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT':
|
||||||
case 'UniswapV2Router: EXCESSIVE_INPUT_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.'
|
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':
|
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':
|
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.'
|
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 little received':
|
||||||
case 'Too much requested':
|
case 'Too much requested':
|
||||||
case 'STF':
|
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:
|
default:
|
||||||
return 'Unknown error. Please join the Discord to get help.'
|
return `Unknown error${reason ? `: "${reason}"` : ''}. Please join the Discord to get help.`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,8 +275,8 @@ export function useSwapCallback(
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
const inputSymbol = trade.inputAmount.currency.symbol
|
const inputSymbol = trade.inputAmount.currency.symbol
|
||||||
const outputSymbol = trade.outputAmount.currency.symbol
|
const outputSymbol = trade.outputAmount.currency.symbol
|
||||||
const inputAmount = trade.maximumAmountIn(allowedSlippage).toSignificant(4)
|
const inputAmount = trade.inputAmount.toSignificant(4)
|
||||||
const outputAmount = trade.minimumAmountOut(allowedSlippage).toSignificant(4)
|
const outputAmount = trade.outputAmount.toSignificant(4)
|
||||||
|
|
||||||
const base = `Swap ${inputAmount} ${inputSymbol} for ${outputAmount} ${outputSymbol}`
|
const base = `Swap ${inputAmount} ${inputSymbol} for ${outputAmount} ${outputSymbol}`
|
||||||
const withRecipient =
|
const withRecipient =
|
||||||
@@ -302,13 +306,11 @@ export function useSwapCallback(
|
|||||||
// otherwise, the error was unexpected and we need to convey that
|
// otherwise, the error was unexpected and we need to convey that
|
||||||
console.error(`Swap failed`, error, address, calldata, value)
|
console.error(`Swap failed`, error, address, calldata, value)
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(`Swap failed: ${swapErrorToUserReadableMessage(error)}`)
|
||||||
`Swap failed: ${'reason' in error ? swapErrorToUserReadableMessage(error) : error.message}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
error: null,
|
error: null,
|
||||||
}
|
}
|
||||||
}, [trade, library, account, chainId, recipient, recipientAddressOrName, swapCalls, allowedSlippage, addTransaction])
|
}, [trade, library, account, chainId, recipient, recipientAddressOrName, swapCalls, addTransaction])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ export default function useUSDCPrice(currency?: Currency): Price<Currency, Token
|
|||||||
|
|
||||||
const ethPairETHAmount = ethPair?.reserveOf(weth)
|
const ethPairETHAmount = ethPair?.reserveOf(weth)
|
||||||
const ethPairETHUSDCValue: JSBI =
|
const ethPairETHUSDCValue: JSBI =
|
||||||
ethPairETHAmount && usdcEthPair ? usdcEthPair.priceOf(weth).quote(ethPairETHAmount).quotient : JSBI.BigInt(0)
|
ethPairETHAmount?.greaterThan(0) && usdcEthPair?.reserveOf(weth)?.greaterThan(0)
|
||||||
|
? usdcEthPair.priceOf(weth).quote(ethPairETHAmount).quotient
|
||||||
|
: JSBI.BigInt(0)
|
||||||
|
|
||||||
// all other tokens
|
// all other tokens
|
||||||
// first try the usdc pair
|
// first try the usdc pair
|
||||||
@@ -81,6 +83,10 @@ export function useUSDCValue(currencyAmount: CurrencyAmount<Currency> | undefine
|
|||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!price || !currencyAmount) return null
|
if (!price || !currencyAmount) return null
|
||||||
return price.quote(currencyAmount)
|
try {
|
||||||
|
return price.quote(currencyAmount)
|
||||||
|
} catch (error) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}, [currencyAmount, price])
|
}, [currencyAmount, price])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,18 @@ import { useEffect, useState } from 'react'
|
|||||||
import { useV3NFTPositionManagerContract } from './useContract'
|
import { useV3NFTPositionManagerContract } from './useContract'
|
||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { Pool } from '@uniswap/v3-sdk'
|
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 { useBlockNumber } from 'state/application/hooks'
|
||||||
|
import { unwrappedToken } from 'utils/wrappedCurrency'
|
||||||
|
|
||||||
const MAX_UINT128 = BigNumber.from(2).pow(128).sub(1)
|
const MAX_UINT128 = BigNumber.from(2).pow(128).sub(1)
|
||||||
|
|
||||||
// compute current + counterfactual fees for a v3 position
|
// compute current + counterfactual fees for a v3 position
|
||||||
export function useV3PositionFees(
|
export function useV3PositionFees(
|
||||||
pool?: Pool,
|
pool?: Pool,
|
||||||
tokenId?: BigNumber
|
tokenId?: BigNumber,
|
||||||
): [CurrencyAmount<Token>, CurrencyAmount<Token>] | [undefined, undefined] {
|
asWETH = false
|
||||||
|
): [CurrencyAmount<Token | Ether>, CurrencyAmount<Token | Ether>] | [undefined, undefined] {
|
||||||
const positionManager = useV3NFTPositionManagerContract(false)
|
const positionManager = useV3NFTPositionManagerContract(false)
|
||||||
const owner = useSingleCallResult(tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
|
const owner = useSingleCallResult(tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
|
||||||
|
|
||||||
@@ -43,8 +45,12 @@ export function useV3PositionFees(
|
|||||||
|
|
||||||
if (pool && amounts) {
|
if (pool && amounts) {
|
||||||
return [
|
return [
|
||||||
CurrencyAmount.fromRawAmount(pool.token0, amounts[0].toString()),
|
!asWETH && currencyEquals(unwrappedToken(pool.token0), ETHER)
|
||||||
CurrencyAmount.fromRawAmount(pool.token1, amounts[1].toString()),
|
? 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 {
|
} else {
|
||||||
return [undefined, undefined]
|
return [undefined, undefined]
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { RedirectDuplicateTokenIdsV2 } from './AddLiquidityV2/redirects'
|
|||||||
import { PositionPage } from './Pool/PositionPage'
|
import { PositionPage } from './Pool/PositionPage'
|
||||||
import AddLiquidity from './AddLiquidity'
|
import AddLiquidity from './AddLiquidity'
|
||||||
import { ThemedBackground } from '../theme'
|
import { ThemedBackground } from '../theme'
|
||||||
|
import ApeModeQueryParamReader from 'hooks/useApeModeQueryParamReader'
|
||||||
|
|
||||||
const AppWrapper = styled.div`
|
const AppWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -76,6 +77,7 @@ export default function App() {
|
|||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<Route component={GoogleAnalyticsReporter} />
|
<Route component={GoogleAnalyticsReporter} />
|
||||||
<Route component={DarkModeQueryParamReader} />
|
<Route component={DarkModeQueryParamReader} />
|
||||||
|
<Route component={ApeModeQueryParamReader} />
|
||||||
<AppWrapper>
|
<AppWrapper>
|
||||||
<HeaderWrapper>
|
<HeaderWrapper>
|
||||||
<Header />
|
<Header />
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
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 { NonfungiblePositionManager, Pool, Position } from '@uniswap/v3-sdk'
|
||||||
|
|
||||||
import { PoolState, usePool } from 'hooks/usePools'
|
import { PoolState, usePool } from 'hooks/usePools'
|
||||||
import { useToken } from 'hooks/Tokens'
|
import { useToken } from 'hooks/Tokens'
|
||||||
import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
|
import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
|
||||||
import { Link, RouteComponentProps } from 'react-router-dom'
|
import { Link, RouteComponentProps } from 'react-router-dom'
|
||||||
import { unwrappedToken } from 'utils/wrappedCurrency'
|
import { unwrappedToken, wrappedCurrencyAmount } from 'utils/wrappedCurrency'
|
||||||
import { usePositionTokenURI } from '../../hooks/usePositionTokenURI'
|
import { usePositionTokenURI } from '../../hooks/usePositionTokenURI'
|
||||||
import { LoadingRows } from './styleds'
|
import { LoadingRows } from './styleds'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
@@ -23,7 +23,7 @@ import { currencyId } from 'utils/currencyId'
|
|||||||
import { formatTokenAmount } from 'utils/formatTokenAmount'
|
import { formatTokenAmount } from 'utils/formatTokenAmount'
|
||||||
import { useV3PositionFees } from 'hooks/useV3PositionFees'
|
import { useV3PositionFees } from 'hooks/useV3PositionFees'
|
||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { Token, WETH9, Currency, CurrencyAmount, Percent, Fraction, Price, currencyEquals } from '@uniswap/sdk-core'
|
import { Token, Currency, CurrencyAmount, Percent, Fraction, Price, Ether } from '@uniswap/sdk-core'
|
||||||
import { useActiveWeb3React } from 'hooks'
|
import { useActiveWeb3React } from 'hooks'
|
||||||
import { useV3NFTPositionManagerContract } from 'hooks/useContract'
|
import { useV3NFTPositionManagerContract } from 'hooks/useContract'
|
||||||
import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks'
|
import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks'
|
||||||
@@ -38,6 +38,7 @@ import { useSingleCallResult } from 'state/multicall/hooks'
|
|||||||
import RangeBadge from '../../components/Badge/RangeBadge'
|
import RangeBadge from '../../components/Badge/RangeBadge'
|
||||||
import useUSDCPrice from 'hooks/useUSDCPrice'
|
import useUSDCPrice from 'hooks/useUSDCPrice'
|
||||||
import Loader from 'components/Loader'
|
import Loader from 'components/Loader'
|
||||||
|
import Toggle from 'components/Toggle'
|
||||||
|
|
||||||
const PageWrapper = styled.div`
|
const PageWrapper = styled.div`
|
||||||
min-width: 800px;
|
min-width: 800px;
|
||||||
@@ -200,20 +201,11 @@ function getRatio(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function NFT({ image, height: targetHeight }: { image: string; height: number }) {
|
// snapshots a src img into a canvas
|
||||||
const [animate, setAnimate] = useState(false)
|
function getSnapshot(src: HTMLImageElement, canvas: HTMLCanvasElement, targetHeight: number) {
|
||||||
|
const context = canvas.getContext('2d')
|
||||||
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
|
|
||||||
|
|
||||||
|
if (context) {
|
||||||
let { width, height } = src
|
let { width, height } = src
|
||||||
|
|
||||||
// src may be hidden and not have the target dimensions
|
// src may be hidden and not have the target dimensions
|
||||||
@@ -231,15 +223,39 @@ function NFT({ image, height: targetHeight }: { image: string; height: number })
|
|||||||
context.clearRect(0, 0, width, height)
|
context.clearRect(0, 0, width, height)
|
||||||
context.drawImage(src, 0, 0, width, height)
|
context.drawImage(src, 0, 0, width, height)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onLoad = (e: SyntheticEvent<HTMLImageElement>) => {
|
function NFT({ image, height: targetHeight }: { image: string; height: number }) {
|
||||||
getSnapshot(e.target as HTMLImageElement)
|
const [animate, setAnimate] = useState(false)
|
||||||
}
|
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||||
|
const imageRef = useRef<HTMLImageElement>(null)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NFTGrid onMouseEnter={() => setAnimate(true)} onMouseLeave={() => setAnimate(false)}>
|
<NFTGrid
|
||||||
<NFTCanvas ref={canvasRef as any} />
|
onMouseEnter={() => {
|
||||||
<NFTImage src={image} hidden={!animate} onLoad={onLoad} ref={imageRef as any} />
|
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>
|
</NFTGrid>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -269,8 +285,11 @@ export function PositionPage({
|
|||||||
const currency0 = token0 ? unwrappedToken(token0) : undefined
|
const currency0 = token0 ? unwrappedToken(token0) : undefined
|
||||||
const currency1 = token1 ? unwrappedToken(token1) : undefined
|
const currency1 = token1 ? unwrappedToken(token1) : undefined
|
||||||
|
|
||||||
|
// flag for receiving WETH
|
||||||
|
const [receiveWETH, setReceiveWETH] = useState(false)
|
||||||
|
|
||||||
// construct Position from details returned
|
// 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(() => {
|
const position = useMemo(() => {
|
||||||
if (pool && liquidity && typeof tickLower === 'number' && typeof tickUpper === 'number') {
|
if (pool && liquidity && typeof tickLower === 'number' && typeof tickUpper === 'number') {
|
||||||
return new Position({ pool, liquidity: liquidity.toString(), tickLower, tickUpper })
|
return new Position({ pool, liquidity: liquidity.toString(), tickLower, tickUpper })
|
||||||
@@ -304,7 +323,7 @@ export function PositionPage({
|
|||||||
}, [inverted, pool, priceLower, priceUpper])
|
}, [inverted, pool, priceLower, priceUpper])
|
||||||
|
|
||||||
// fees
|
// 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 [collecting, setCollecting] = useState<boolean>(false)
|
||||||
const [collectMigrationHash, setCollectMigrationHash] = useState<string | null>(null)
|
const [collectMigrationHash, setCollectMigrationHash] = useState<string | null>(null)
|
||||||
@@ -320,12 +339,8 @@ export function PositionPage({
|
|||||||
|
|
||||||
const { calldata, value } = NonfungiblePositionManager.collectCallParameters({
|
const { calldata, value } = NonfungiblePositionManager.collectCallParameters({
|
||||||
tokenId: tokenId.toString(),
|
tokenId: tokenId.toString(),
|
||||||
expectedCurrencyOwed0: currencyEquals(feeValue0.currency, WETH9[chainId])
|
expectedCurrencyOwed0: feeValue0,
|
||||||
? CurrencyAmount.ether(feeValue0.quotient)
|
expectedCurrencyOwed1: feeValue1,
|
||||||
: feeValue0,
|
|
||||||
expectedCurrencyOwed1: currencyEquals(feeValue1.currency, WETH9[chainId])
|
|
||||||
? CurrencyAmount.ether(feeValue1.quotient)
|
|
||||||
: feeValue1,
|
|
||||||
recipient: account,
|
recipient: account,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -371,15 +386,23 @@ export function PositionPage({
|
|||||||
const owner = useSingleCallResult(!!tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
|
const owner = useSingleCallResult(!!tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
|
||||||
const ownsNFT = owner === account || positionDetails?.operator === account
|
const ownsNFT = owner === account || positionDetails?.operator === account
|
||||||
|
|
||||||
|
// usdc prices always in terms of tokens
|
||||||
const price0 = useUSDCPrice(token0 ?? undefined)
|
const price0 = useUSDCPrice(token0 ?? undefined)
|
||||||
const price1 = useUSDCPrice(token1 ?? 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
|
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)
|
return amount0.add(amount1)
|
||||||
}, [price0, price1, feeValue0, feeValue1])
|
}, [price0, price1, feeValue0, feeValue1, chainId])
|
||||||
|
|
||||||
const fiatValueOfLiquidity: CurrencyAmount<Token> | null = useMemo(() => {
|
const fiatValueOfLiquidity: CurrencyAmount<Token> | null = useMemo(() => {
|
||||||
if (!price0 || !price1 || !position) return null
|
if (!price0 || !price1 || !position) return null
|
||||||
@@ -388,6 +411,9 @@ export function PositionPage({
|
|||||||
return amount0.add(amount1)
|
return amount0.add(amount1)
|
||||||
}, [price0, price1, position])
|
}, [price0, price1, position])
|
||||||
|
|
||||||
|
const feeValueUpper = inverted ? feeValue0 : feeValue1
|
||||||
|
const feeValueLower = inverted ? feeValue1 : feeValue0
|
||||||
|
|
||||||
function modalHeader() {
|
function modalHeader() {
|
||||||
return (
|
return (
|
||||||
<AutoColumn gap={'md'} style={{ marginTop: '20px' }}>
|
<AutoColumn gap={'md'} style={{ marginTop: '20px' }}>
|
||||||
@@ -395,33 +421,17 @@ export function PositionPage({
|
|||||||
<AutoColumn gap="md">
|
<AutoColumn gap="md">
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<CurrencyLogo currency={currencyQuote} size={'20px'} style={{ marginRight: '0.5rem' }} />
|
<CurrencyLogo currency={feeValueUpper?.currency} size={'20px'} style={{ marginRight: '0.5rem' }} />
|
||||||
<TYPE.main>
|
<TYPE.main>{feeValueUpper ? formatTokenAmount(feeValueUpper, 4) : '-'}</TYPE.main>
|
||||||
{inverted
|
|
||||||
? feeValue0
|
|
||||||
? formatTokenAmount(feeValue0, 4)
|
|
||||||
: '-'
|
|
||||||
: feeValue1
|
|
||||||
? formatTokenAmount(feeValue1, 4)
|
|
||||||
: '-'}
|
|
||||||
</TYPE.main>
|
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<TYPE.main>{currencyQuote?.symbol}</TYPE.main>
|
<TYPE.main>{feeValueUpper?.currency?.symbol}</TYPE.main>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<CurrencyLogo currency={currencyBase} size={'20px'} style={{ marginRight: '0.5rem' }} />
|
<CurrencyLogo currency={feeValueLower?.currency} size={'20px'} style={{ marginRight: '0.5rem' }} />
|
||||||
<TYPE.main>
|
<TYPE.main>{feeValueLower ? formatTokenAmount(feeValueLower, 4) : '-'}</TYPE.main>
|
||||||
{inverted
|
|
||||||
? feeValue0
|
|
||||||
? formatTokenAmount(feeValue1, 4)
|
|
||||||
: '-'
|
|
||||||
: feeValue1
|
|
||||||
? formatTokenAmount(feeValue0, 4)
|
|
||||||
: '-'}
|
|
||||||
</TYPE.main>
|
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<TYPE.main>{currencyBase?.symbol}</TYPE.main>
|
<TYPE.main>{feeValueLower?.currency?.symbol}</TYPE.main>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</LightCard>
|
</LightCard>
|
||||||
@@ -640,40 +650,44 @@ export function PositionPage({
|
|||||||
<AutoColumn gap="md">
|
<AutoColumn gap="md">
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<CurrencyLogo currency={currencyQuote} size={'20px'} style={{ marginRight: '0.5rem' }} />
|
<CurrencyLogo
|
||||||
<TYPE.main>{currencyQuote?.symbol}</TYPE.main>
|
currency={feeValueUpper?.currency}
|
||||||
|
size={'20px'}
|
||||||
|
style={{ marginRight: '0.5rem' }}
|
||||||
|
/>
|
||||||
|
<TYPE.main>{feeValueUpper?.currency?.symbol}</TYPE.main>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<TYPE.main>
|
<TYPE.main>{feeValueUpper ? formatTokenAmount(feeValueUpper, 4) : '-'}</TYPE.main>
|
||||||
{inverted
|
|
||||||
? feeValue0
|
|
||||||
? formatTokenAmount(feeValue0, 4)
|
|
||||||
: '-'
|
|
||||||
: feeValue1
|
|
||||||
? formatTokenAmount(feeValue1, 4)
|
|
||||||
: '-'}
|
|
||||||
</TYPE.main>
|
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<CurrencyLogo currency={currencyBase} size={'20px'} style={{ marginRight: '0.5rem' }} />
|
<CurrencyLogo
|
||||||
<TYPE.main>{currencyBase?.symbol}</TYPE.main>
|
currency={feeValueLower?.currency}
|
||||||
|
size={'20px'}
|
||||||
|
style={{ marginRight: '0.5rem' }}
|
||||||
|
/>
|
||||||
|
<TYPE.main>{feeValueLower?.currency?.symbol}</TYPE.main>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<TYPE.main>
|
<TYPE.main>{feeValueLower ? formatTokenAmount(feeValueLower, 4) : '-'}</TYPE.main>
|
||||||
{inverted
|
|
||||||
? feeValue0
|
|
||||||
? formatTokenAmount(feeValue1, 4)
|
|
||||||
: '-'
|
|
||||||
: feeValue1
|
|
||||||
? formatTokenAmount(feeValue0, 4)
|
|
||||||
: '-'}
|
|
||||||
</TYPE.main>
|
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</LightCard>
|
</LightCard>
|
||||||
|
{ownsNFT && (feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) && !collectMigrationHash ? (
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween>
|
||||||
|
<TYPE.main>Collect as WETH</TYPE.main>
|
||||||
|
<Toggle
|
||||||
|
id="receive-as-weth"
|
||||||
|
isActive={receiveWETH}
|
||||||
|
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
|
||||||
|
/>
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>
|
||||||
|
) : null}
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</DarkCard>
|
</DarkCard>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ import ReactGA from 'react-ga'
|
|||||||
import { useActiveWeb3React } from 'hooks'
|
import { useActiveWeb3React } from 'hooks'
|
||||||
import { TransactionResponse } from '@ethersproject/providers'
|
import { TransactionResponse } from '@ethersproject/providers'
|
||||||
import { useTransactionAdder } from 'state/transactions/hooks'
|
import { useTransactionAdder } from 'state/transactions/hooks'
|
||||||
import { WETH9, CurrencyAmount, currencyEquals, Percent } from '@uniswap/sdk-core'
|
import { Percent } from '@uniswap/sdk-core'
|
||||||
import { TYPE } from 'theme'
|
import { TYPE } from 'theme'
|
||||||
import { Wrapper, SmallMaxButton, ResponsiveHeaderText } from './styled'
|
import { Wrapper, SmallMaxButton, ResponsiveHeaderText } from './styled'
|
||||||
import Loader from 'components/Loader'
|
import Loader from 'components/Loader'
|
||||||
import { useToken } from 'hooks/Tokens'
|
|
||||||
import { unwrappedToken } from 'utils/wrappedCurrency'
|
|
||||||
import DoubleCurrencyLogo from 'components/DoubleLogo'
|
import DoubleCurrencyLogo from 'components/DoubleLogo'
|
||||||
import { Break } from 'components/earn/styled'
|
import { Break } from 'components/earn/styled'
|
||||||
import { NonfungiblePositionManager } from '@uniswap/v3-sdk'
|
import { NonfungiblePositionManager } from '@uniswap/v3-sdk'
|
||||||
@@ -34,6 +32,7 @@ import { calculateGasMargin } from 'utils'
|
|||||||
import useTheme from 'hooks/useTheme'
|
import useTheme from 'hooks/useTheme'
|
||||||
import { AddRemoveTabs } from 'components/NavigationTabs'
|
import { AddRemoveTabs } from 'components/NavigationTabs'
|
||||||
import RangeBadge from 'components/Badge/RangeBadge'
|
import RangeBadge from 'components/Badge/RangeBadge'
|
||||||
|
import Toggle from 'components/Toggle'
|
||||||
|
|
||||||
export const UINT128MAX = BigNumber.from(2).pow(128).sub(1)
|
export const UINT128MAX = BigNumber.from(2).pow(128).sub(1)
|
||||||
|
|
||||||
@@ -65,11 +64,8 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const { account, chainId, library } = useActiveWeb3React()
|
const { account, chainId, library } = useActiveWeb3React()
|
||||||
|
|
||||||
// currencies from position
|
// flag for receiving WETH
|
||||||
const token0 = useToken(position?.token0)
|
const [receiveWETH, setReceiveWETH] = useState(false)
|
||||||
const token1 = useToken(position?.token1)
|
|
||||||
const currency0 = token0 ? unwrappedToken(token0) : undefined
|
|
||||||
const currency1 = token1 ? unwrappedToken(token1) : undefined
|
|
||||||
|
|
||||||
// burn state
|
// burn state
|
||||||
const { percent } = useBurnV3State()
|
const { percent } = useBurnV3State()
|
||||||
@@ -82,7 +78,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
feeValue1,
|
feeValue1,
|
||||||
outOfRange,
|
outOfRange,
|
||||||
error,
|
error,
|
||||||
} = useDerivedV3BurnInfo(position)
|
} = useDerivedV3BurnInfo(position, receiveWETH)
|
||||||
const { onPercentSelect } = useBurnV3ActionHandlers()
|
const { onPercentSelect } = useBurnV3ActionHandlers()
|
||||||
|
|
||||||
const removed = position?.liquidity?.eq(0)
|
const removed = position?.liquidity?.eq(0)
|
||||||
@@ -122,12 +118,8 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
slippageTolerance: allowedSlippage,
|
slippageTolerance: allowedSlippage,
|
||||||
deadline: deadline.toString(),
|
deadline: deadline.toString(),
|
||||||
collectOptions: {
|
collectOptions: {
|
||||||
expectedCurrencyOwed0: currencyEquals(liquidityValue0.currency, WETH9[chainId])
|
expectedCurrencyOwed0: feeValue0,
|
||||||
? CurrencyAmount.ether(feeValue0.quotient)
|
expectedCurrencyOwed1: feeValue1,
|
||||||
: feeValue0,
|
|
||||||
expectedCurrencyOwed1: currencyEquals(liquidityValue1.currency, WETH9[chainId])
|
|
||||||
? CurrencyAmount.ether(feeValue1.quotient)
|
|
||||||
: feeValue1,
|
|
||||||
recipient: account,
|
recipient: account,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -195,32 +187,32 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
}, [onPercentSelectForSlider, txnHash])
|
}, [onPercentSelectForSlider, txnHash])
|
||||||
|
|
||||||
const pendingText = `Removing ${liquidityValue0?.toSignificant(6)} ${
|
const pendingText = `Removing ${liquidityValue0?.toSignificant(6)} ${
|
||||||
currency0?.symbol
|
liquidityValue0?.currency?.symbol
|
||||||
} and ${liquidityValue1?.toSignificant(6)} ${currency1?.symbol}`
|
} and ${liquidityValue1?.toSignificant(6)} ${liquidityValue1?.currency?.symbol}`
|
||||||
|
|
||||||
function modalHeader() {
|
function modalHeader() {
|
||||||
return (
|
return (
|
||||||
<AutoColumn gap={'sm'} style={{ padding: '16px' }}>
|
<AutoColumn gap={'sm'} style={{ padding: '16px' }}>
|
||||||
<RowBetween align="flex-end">
|
<RowBetween align="flex-end">
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
{currency0?.symbol}:
|
Pooled {liquidityValue0?.currency?.symbol}:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
|
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue0?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<RowBetween align="flex-end">
|
<RowBetween align="flex-end">
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
{currency1?.symbol}:
|
Pooled {liquidityValue1?.currency?.symbol}:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
|
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue1?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) ? (
|
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) ? (
|
||||||
@@ -230,24 +222,24 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
</TYPE.italic>
|
</TYPE.italic>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
{currency0?.symbol} from fees:
|
{feeValue0?.currency?.symbol} Fees Earned:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
|
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue0?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
{currency1?.symbol} from fees:
|
{feeValue1?.currency?.symbol} Fees Earned:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
|
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue1?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
</>
|
</>
|
||||||
@@ -287,8 +279,16 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
<AutoColumn gap="lg">
|
<AutoColumn gap="lg">
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<DoubleCurrencyLogo currency0={currency1} currency1={currency0} size={20} margin={true} />
|
<DoubleCurrencyLogo
|
||||||
<TYPE.label ml="10px" fontSize="20px">{`${currency0?.symbol}/${currency1?.symbol}`}</TYPE.label>
|
currency0={feeValue0?.currency}
|
||||||
|
currency1={feeValue1?.currency}
|
||||||
|
size={20}
|
||||||
|
margin={true}
|
||||||
|
/>
|
||||||
|
<TYPE.label
|
||||||
|
ml="10px"
|
||||||
|
fontSize="20px"
|
||||||
|
>{`${feeValue0?.currency?.symbol}/${feeValue1?.currency?.symbol}`}</TYPE.label>
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<RangeBadge removed={removed} inRange={!outOfRange} />
|
<RangeBadge removed={removed} inRange={!outOfRange} />
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
@@ -319,24 +319,24 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
<AutoColumn gap="md">
|
<AutoColumn gap="md">
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
Pooled {currency0?.symbol}:
|
Pooled {liquidityValue0?.currency?.symbol}:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
|
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue0?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
Pooled {currency1?.symbol}:
|
Pooled {liquidityValue1?.currency?.symbol}:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
|
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue1?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) ? (
|
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) ? (
|
||||||
@@ -344,30 +344,40 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
<Break />
|
<Break />
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
{currency0?.symbol} Fees Earned:
|
{feeValue0?.currency?.symbol} Fees Earned:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
|
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue0?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text fontSize={16} fontWeight={500}>
|
<Text fontSize={16} fontWeight={500}>
|
||||||
{currency1?.symbol} Fees Earned:
|
{feeValue1?.currency?.symbol} Fees Earned:
|
||||||
</Text>
|
</Text>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||||
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
|
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
|
||||||
</Text>
|
</Text>
|
||||||
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
|
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue1?.currency} />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</LightCard>
|
</LightCard>
|
||||||
|
|
||||||
|
<RowBetween>
|
||||||
|
<TYPE.main>Collect as WETH</TYPE.main>
|
||||||
|
<Toggle
|
||||||
|
id="receive-as-weth"
|
||||||
|
isActive={receiveWETH}
|
||||||
|
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
|
||||||
|
/>
|
||||||
|
</RowBetween>
|
||||||
|
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
<AutoColumn gap="12px" style={{ flex: '1' }}>
|
<AutoColumn gap="12px" style={{ flex: '1' }}>
|
||||||
<ButtonConfirmed
|
<ButtonConfirmed
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import {
|
|||||||
import { useExpertModeManager, useUserSingleHopOnly } from '../../state/user/hooks'
|
import { useExpertModeManager, useUserSingleHopOnly } from '../../state/user/hooks'
|
||||||
import { HideSmall, LinkStyledButton, TYPE } from '../../theme'
|
import { HideSmall, LinkStyledButton, TYPE } from '../../theme'
|
||||||
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
|
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
|
||||||
import { computePriceImpactWithMaximumSlippage } from '../../utils/computePriceImpactWithMaximumSlippage'
|
|
||||||
import { getTradeVersion } from '../../utils/getTradeVersion'
|
import { getTradeVersion } from '../../utils/getTradeVersion'
|
||||||
import { isTradeBetter } from '../../utils/isTradeBetter'
|
import { isTradeBetter } from '../../utils/isTradeBetter'
|
||||||
import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
||||||
@@ -132,10 +131,10 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
[Field.OUTPUT]: parsedAmount,
|
[Field.OUTPUT]: parsedAmount,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
[Field.INPUT]: independentField === Field.INPUT ? parsedAmount : trade?.maximumAmountIn(allowedSlippage),
|
[Field.INPUT]: independentField === Field.INPUT ? parsedAmount : trade?.inputAmount,
|
||||||
[Field.OUTPUT]: independentField === Field.OUTPUT ? parsedAmount : trade?.minimumAmountOut(allowedSlippage),
|
[Field.OUTPUT]: independentField === Field.OUTPUT ? parsedAmount : trade?.outputAmount,
|
||||||
},
|
},
|
||||||
[allowedSlippage, independentField, parsedAmount, showWrap, trade]
|
[independentField, parsedAmount, showWrap, trade]
|
||||||
)
|
)
|
||||||
|
|
||||||
const fiatValueInput = useUSDCValue(parsedAmounts[Field.INPUT])
|
const fiatValueInput = useUSDCValue(parsedAmounts[Field.INPUT])
|
||||||
@@ -292,7 +291,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
|
|
||||||
// warnings on the greater of fiat value price impact and execution price impact
|
// warnings on the greater of fiat value price impact and execution price impact
|
||||||
const priceImpactSeverity = useMemo(() => {
|
const priceImpactSeverity = useMemo(() => {
|
||||||
const executionPriceImpact = trade ? computePriceImpactWithMaximumSlippage(trade, allowedSlippage) : undefined
|
const executionPriceImpact = trade?.priceImpact
|
||||||
return warningSeverity(
|
return warningSeverity(
|
||||||
executionPriceImpact && priceImpact
|
executionPriceImpact && priceImpact
|
||||||
? executionPriceImpact.greaterThan(priceImpact)
|
? executionPriceImpact.greaterThan(priceImpact)
|
||||||
@@ -300,7 +299,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
: priceImpact
|
: priceImpact
|
||||||
: executionPriceImpact ?? priceImpact
|
: executionPriceImpact ?? priceImpact
|
||||||
)
|
)
|
||||||
}, [allowedSlippage, priceImpact, trade])
|
}, [priceImpact, trade])
|
||||||
|
|
||||||
// show approve flow when: no error on inputs, not approved or pending, or approved in current session
|
// show approve flow when: no error on inputs, not approved or pending, or approved in current session
|
||||||
// never show if price impact is above threshold in non expert mode
|
// never show if price impact is above threshold in non expert mode
|
||||||
@@ -475,7 +474,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
{trade ? (
|
{trade ? (
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<TradePrice
|
<TradePrice
|
||||||
price={trade.worstExecutionPrice(allowedSlippage)}
|
price={trade.executionPrice}
|
||||||
showInverted={showInverted}
|
showInverted={showInverted}
|
||||||
setShowInverted={setShowInverted}
|
setShowInverted={setShowInverted}
|
||||||
/>
|
/>
|
||||||
@@ -526,12 +525,12 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
|
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<AutoRow justify="space-between">
|
<AutoRow justify="space-between" style={{ flexWrap: 'nowrap' }}>
|
||||||
<span style={{ display: 'flex', alignItems: 'center' }}>
|
<span style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<CurrencyLogo
|
<CurrencyLogo
|
||||||
currency={currencies[Field.INPUT]}
|
currency={currencies[Field.INPUT]}
|
||||||
size={'20px'}
|
size={'20px'}
|
||||||
style={{ marginRight: '8px' }}
|
style={{ marginRight: '8px', flexShrink: 0 }}
|
||||||
/>
|
/>
|
||||||
{/* we need to shorten this string on mobile */}
|
{/* we need to shorten this string on mobile */}
|
||||||
{approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
|
{approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
|
||||||
@@ -551,7 +550,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
'. You only have to do this once per token.'
|
'. You only have to do this once per token.'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<HelpCircle size="20" color={'white'} />
|
<HelpCircle size="20" color={'white'} style={{ marginLeft: '8px' }} />
|
||||||
</MouseoverTooltip>
|
</MouseoverTooltip>
|
||||||
)}
|
)}
|
||||||
</AutoRow>
|
</AutoRow>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Token, CurrencyAmount, Percent } from '@uniswap/sdk-core'
|
import { Token, CurrencyAmount, Percent, Ether, currencyEquals, ETHER } from '@uniswap/sdk-core'
|
||||||
import { Position } from '@uniswap/v3-sdk'
|
import { Position } from '@uniswap/v3-sdk'
|
||||||
import { usePool } from 'hooks/usePools'
|
import { usePool } from 'hooks/usePools'
|
||||||
import { useActiveWeb3React } from 'hooks'
|
import { useActiveWeb3React } from 'hooks'
|
||||||
@@ -10,20 +10,22 @@ import { PositionDetails } from 'types/position'
|
|||||||
|
|
||||||
import { AppDispatch, AppState } from '../../index'
|
import { AppDispatch, AppState } from '../../index'
|
||||||
import { selectPercent } from './actions'
|
import { selectPercent } from './actions'
|
||||||
|
import { unwrappedToken } from 'utils/wrappedCurrency'
|
||||||
|
|
||||||
export function useBurnV3State(): AppState['burnV3'] {
|
export function useBurnV3State(): AppState['burnV3'] {
|
||||||
return useSelector<AppState, AppState['burnV3']>((state) => state.burnV3)
|
return useSelector<AppState, AppState['burnV3']>((state) => state.burnV3)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useDerivedV3BurnInfo(
|
export function useDerivedV3BurnInfo(
|
||||||
position?: PositionDetails
|
position?: PositionDetails,
|
||||||
|
asWETH = false
|
||||||
): {
|
): {
|
||||||
position?: Position
|
position?: Position
|
||||||
liquidityPercentage?: Percent
|
liquidityPercentage?: Percent
|
||||||
liquidityValue0?: CurrencyAmount<Token>
|
liquidityValue0?: CurrencyAmount<Token | Ether>
|
||||||
liquidityValue1?: CurrencyAmount<Token>
|
liquidityValue1?: CurrencyAmount<Token | Ether>
|
||||||
feeValue0?: CurrencyAmount<Token>
|
feeValue0?: CurrencyAmount<Token | Ether>
|
||||||
feeValue1?: CurrencyAmount<Token>
|
feeValue1?: CurrencyAmount<Token | Ether>
|
||||||
outOfRange: boolean
|
outOfRange: boolean
|
||||||
error?: string
|
error?: string
|
||||||
} {
|
} {
|
||||||
@@ -50,20 +52,27 @@ export function useDerivedV3BurnInfo(
|
|||||||
|
|
||||||
const liquidityPercentage = new Percent(percent, 100)
|
const liquidityPercentage = new Percent(percent, 100)
|
||||||
|
|
||||||
const liquidityValue0 =
|
const discountedAmount0 = positionSDK
|
||||||
positionSDK &&
|
? liquidityPercentage.multiply(positionSDK.amount0.quotient).quotient
|
||||||
CurrencyAmount.fromRawAmount(
|
: undefined
|
||||||
positionSDK.amount0.currency,
|
const discountedAmount1 = positionSDK
|
||||||
liquidityPercentage.multiply(positionSDK.amount0.quotient).quotient
|
? liquidityPercentage.multiply(positionSDK.amount1.quotient).quotient
|
||||||
)
|
: undefined
|
||||||
const liquidityValue1 =
|
|
||||||
positionSDK &&
|
|
||||||
CurrencyAmount.fromRawAmount(
|
|
||||||
positionSDK.amount1.currency,
|
|
||||||
liquidityPercentage.multiply(positionSDK.amount1.quotient).quotient
|
|
||||||
)
|
|
||||||
|
|
||||||
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, position?.tokenId)
|
const liquidityValue0 =
|
||||||
|
token0 && discountedAmount0
|
||||||
|
? currencyEquals(unwrappedToken(token0), ETHER) && !asWETH
|
||||||
|
? CurrencyAmount.ether(discountedAmount0)
|
||||||
|
: CurrencyAmount.fromRawAmount(token0, discountedAmount0)
|
||||||
|
: undefined
|
||||||
|
const liquidityValue1 =
|
||||||
|
token1 && discountedAmount1
|
||||||
|
? currencyEquals(unwrappedToken(token1), ETHER) && !asWETH
|
||||||
|
? CurrencyAmount.ether(discountedAmount1)
|
||||||
|
: CurrencyAmount.fromRawAmount(token1, discountedAmount1)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, position?.tokenId, asWETH)
|
||||||
|
|
||||||
const outOfRange =
|
const outOfRange =
|
||||||
pool && position ? pool.tickCurrent < position.tickLower || pool.tickCurrent > position.tickUpper : false
|
pool && position ? pool.tickCurrent < position.tickLower || pool.tickCurrent > position.tickUpper : false
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const store = configureStore({
|
|||||||
multicall,
|
multicall,
|
||||||
lists,
|
lists,
|
||||||
},
|
},
|
||||||
middleware: [...getDefaultMiddleware({ thunk: false }), save({ states: PERSISTED_KEYS })],
|
middleware: [...getDefaultMiddleware({ thunk: false }), save({ states: PERSISTED_KEYS, debounce: 1000 })],
|
||||||
preloadedState: load({ states: PERSISTED_KEYS }),
|
preloadedState: load({ states: PERSISTED_KEYS }),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -164,8 +164,8 @@ export default function Updater(): null {
|
|||||||
cancellations: chunkedCalls.map((chunk, index) => {
|
cancellations: chunkedCalls.map((chunk, index) => {
|
||||||
const { cancel, promise } = retry(() => fetchChunk(multicall2Contract, chunk, latestBlockNumber), {
|
const { cancel, promise } = retry(() => fetchChunk(multicall2Contract, chunk, latestBlockNumber), {
|
||||||
n: Infinity,
|
n: Infinity,
|
||||||
minWait: 2500,
|
minWait: 1000,
|
||||||
maxWait: 3500,
|
maxWait: 2500,
|
||||||
})
|
})
|
||||||
promise
|
promise
|
||||||
.then(({ results: returnData, blockNumber: fetchBlockNumber }) => {
|
.then(({ results: returnData, blockNumber: fetchBlockNumber }) => {
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import { computePriceImpact, Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
|
||||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
|
||||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
|
||||||
|
|
||||||
export function computePriceImpactWithMaximumSlippage(
|
|
||||||
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType>,
|
|
||||||
allowedSlippage: Percent
|
|
||||||
): Percent {
|
|
||||||
return computePriceImpact(
|
|
||||||
trade.route.midPrice,
|
|
||||||
trade.maximumAmountIn(allowedSlippage),
|
|
||||||
trade.minimumAmountOut(allowedSlippage)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -22,15 +22,15 @@ export function computeRealizedLPFeePercent(
|
|||||||
// for each hop in our trade, take away the x*y=k price impact from 0.3% fees
|
// for each hop in our trade, take away the x*y=k price impact from 0.3% fees
|
||||||
// e.g. for 3 tokens/2 hops: 1 - ((1 - .03) * (1-.03))
|
// e.g. for 3 tokens/2 hops: 1 - ((1 - .03) * (1-.03))
|
||||||
percent = ONE_HUNDRED_PERCENT.subtract(
|
percent = ONE_HUNDRED_PERCENT.subtract(
|
||||||
trade.route.pairs.reduce<Fraction>(
|
trade.route.pairs.reduce<Percent>(
|
||||||
(currentFee: Fraction): Fraction => currentFee.multiply(INPUT_FRACTION_AFTER_FEE),
|
(currentFee: Percent): Percent => currentFee.multiply(INPUT_FRACTION_AFTER_FEE),
|
||||||
ONE_HUNDRED_PERCENT
|
ONE_HUNDRED_PERCENT
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
percent = ONE_HUNDRED_PERCENT.subtract(
|
percent = ONE_HUNDRED_PERCENT.subtract(
|
||||||
trade.route.pools.reduce<Fraction>(
|
trade.route.pools.reduce<Percent>(
|
||||||
(currentFee: Fraction, pool): Fraction =>
|
(currentFee: Percent, pool): Percent =>
|
||||||
currentFee.multiply(ONE_HUNDRED_PERCENT.subtract(new Fraction(pool.fee, 1_000_000))),
|
currentFee.multiply(ONE_HUNDRED_PERCENT.subtract(new Fraction(pool.fee, 1_000_000))),
|
||||||
ONE_HUNDRED_PERCENT
|
ONE_HUNDRED_PERCENT
|
||||||
)
|
)
|
||||||
@@ -44,14 +44,11 @@ export function computeRealizedLPFeePercent(
|
|||||||
export function computeRealizedLPFeeAmount(
|
export function computeRealizedLPFeeAmount(
|
||||||
trade?: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType> | null
|
trade?: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType> | null
|
||||||
): CurrencyAmount<Currency> | undefined {
|
): CurrencyAmount<Currency> | undefined {
|
||||||
if (trade instanceof V2Trade || trade instanceof V3Trade) {
|
if (trade) {
|
||||||
const realizedLPFee = computeRealizedLPFeePercent(trade)
|
const realizedLPFee = computeRealizedLPFeePercent(trade)
|
||||||
|
|
||||||
// the amount of the input that accrues to LPs
|
// the amount of the input that accrues to LPs
|
||||||
return CurrencyAmount.fromRawAmount(
|
return CurrencyAmount.fromRawAmount(trade.inputAmount.currency, trade.inputAmount.multiply(realizedLPFee).quotient)
|
||||||
trade.inputAmount.currency,
|
|
||||||
trade.inputAmount.asFraction.multiply(realizedLPFee).quotient
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
|
|||||||
72
yarn.lock
72
yarn.lock
@@ -2452,7 +2452,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b"
|
resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b"
|
||||||
integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==
|
integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==
|
||||||
|
|
||||||
"@metamask/safe-event-emitter@^2.0.0":
|
"@metamask/safe-event-emitter@2.0.0", "@metamask/safe-event-emitter@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c"
|
resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c"
|
||||||
integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==
|
integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==
|
||||||
@@ -4478,10 +4478,10 @@
|
|||||||
"@uniswap/v3-core" "1.0.0"
|
"@uniswap/v3-core" "1.0.0"
|
||||||
base64-sol "1.0.1"
|
base64-sol "1.0.1"
|
||||||
|
|
||||||
"@uniswap/v3-sdk@^3.0.0-alpha.1":
|
"@uniswap/v3-sdk@^3.0.0-alpha.4":
|
||||||
version "3.0.0-alpha.1"
|
version "3.0.0-alpha.4"
|
||||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.0.0-alpha.1.tgz#33fcd4b1587d323c6afde3bb546ad0bb1c77e492"
|
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.0.0-alpha.4.tgz#e8bf26291fd74e36a5a3d9b88f1809a7aceb7d3a"
|
||||||
integrity sha512-3+rVWwGlryEX/Nu7qevBrScTjZ4791fSfmLDz+U5ofWQL/edhZkjgTY1I/fkndUSI8FKWRppRAdzqcnmbpqqlQ==
|
integrity sha512-BcEH8eHt+b6eaaiLDlzbFox2NquP1H7KgrgmNjAlU/et+vC4azdfNN6SsRlTFzhioPOwHlAKAAZJLq+yzboDOQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ethersproject/abi" "^5.0.12"
|
"@ethersproject/abi" "^5.0.12"
|
||||||
"@ethersproject/solidity" "^5.0.9"
|
"@ethersproject/solidity" "^5.0.9"
|
||||||
@@ -4582,7 +4582,7 @@
|
|||||||
js-sha3 "0.8.0"
|
js-sha3 "0.8.0"
|
||||||
query-string "6.13.5"
|
query-string "6.13.5"
|
||||||
|
|
||||||
"@walletconnect/web3-provider@^1.3.6":
|
"@walletconnect/web3-provider@^1.4.1":
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@walletconnect/web3-provider/-/web3-provider-1.4.1.tgz#34f6319ab2473ab9ff0fcf1e8bc280c697fa01ff"
|
resolved "https://registry.yarnpkg.com/@walletconnect/web3-provider/-/web3-provider-1.4.1.tgz#34f6319ab2473ab9ff0fcf1e8bc280c697fa01ff"
|
||||||
integrity sha512-gUoBGM5hdtcXSoLXDTG1/WTamnUNpEWfaYMIVkfVnvVFd4whIjb0iOW5ywvDOf/49wq0C2+QThZL2Wc+r+jKLA==
|
integrity sha512-gUoBGM5hdtcXSoLXDTG1/WTamnUNpEWfaYMIVkfVnvVFd4whIjb0iOW5ywvDOf/49wq0C2+QThZL2Wc+r+jKLA==
|
||||||
@@ -4646,24 +4646,24 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@web3-react/types/-/types-6.0.7.tgz#34a6204224467eedc6123abaf55fbb6baeb2809f"
|
resolved "https://registry.yarnpkg.com/@web3-react/types/-/types-6.0.7.tgz#34a6204224467eedc6123abaf55fbb6baeb2809f"
|
||||||
integrity sha512-ofGmfDhxmNT1/P/MgVa8IKSkCStFiyvXe+U5tyZurKdrtTDFU+wJ/LxClPDtFerWpczNFPUSrKcuhfPX1sI6+A==
|
integrity sha512-ofGmfDhxmNT1/P/MgVa8IKSkCStFiyvXe+U5tyZurKdrtTDFU+wJ/LxClPDtFerWpczNFPUSrKcuhfPX1sI6+A==
|
||||||
|
|
||||||
"@web3-react/walletconnect-connector@^6.1.1":
|
"@web3-react/walletconnect-connector@^6.2.0":
|
||||||
version "6.1.9"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@web3-react/walletconnect-connector/-/walletconnect-connector-6.1.9.tgz#3459ccf2a2ac7ae8f155645d29a517712afeb731"
|
resolved "https://registry.yarnpkg.com/@web3-react/walletconnect-connector/-/walletconnect-connector-6.2.0.tgz#5451f332a25b94cf7e615a20cc7d22a27532629d"
|
||||||
integrity sha512-gPtcFFRAnRgqhmBjhH+dtuG3cx23X+JOX+mRO1D7dN+8yxLZhLhjOZlJFECH5hkC20KMM/sk+rq2yy6Vqp76PQ==
|
integrity sha512-F6xYwI3MKiSdKa0248y2wBW0kTDddc2/IGn4CjMSYe0DJFggtxFsAAGHQTRmvwDcLlgQwtemJJ0cTA82MOVfEg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@walletconnect/web3-provider" "^1.3.6"
|
"@walletconnect/web3-provider" "^1.4.1"
|
||||||
"@web3-react/abstract-connector" "^6.0.7"
|
"@web3-react/abstract-connector" "^6.0.7"
|
||||||
"@web3-react/types" "^6.0.7"
|
"@web3-react/types" "^6.0.7"
|
||||||
tiny-invariant "^1.0.6"
|
tiny-invariant "^1.0.6"
|
||||||
|
|
||||||
"@web3-react/walletlink-connector@^6.0.9":
|
"@web3-react/walletlink-connector@^6.2.0":
|
||||||
version "6.1.9"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@web3-react/walletlink-connector/-/walletlink-connector-6.1.9.tgz#3b27b79057ea3865b447a2ecdd3807d094f34061"
|
resolved "https://registry.yarnpkg.com/@web3-react/walletlink-connector/-/walletlink-connector-6.2.0.tgz#7619bdca5a030b475b3a205f92f949d61e3b9b25"
|
||||||
integrity sha512-0kgb28CsUp5k0MVdl3bk5FUSvgDl5psXyRLrXi2WFeHToOJTQnmMstVo9/1Mj36zaYHuSUcdcyLKnLGoabSivQ==
|
integrity sha512-Vz0QOLHQnZD/xDJfZ+TJ19NLYqy0Ii62RKwaF0xiKnAIcwjrq8MVEPtnY7kB9G1g8EoCD2ghqnWb4NyZTltQHw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@web3-react/abstract-connector" "^6.0.7"
|
"@web3-react/abstract-connector" "^6.0.7"
|
||||||
"@web3-react/types" "^6.0.7"
|
"@web3-react/types" "^6.0.7"
|
||||||
walletlink "^2.0.2"
|
walletlink "^2.1.0"
|
||||||
|
|
||||||
"@webassemblyjs/ast@1.9.0":
|
"@webassemblyjs/ast@1.9.0":
|
||||||
version "1.9.0"
|
version "1.9.0"
|
||||||
@@ -9114,7 +9114,7 @@ etag@~1.8.1:
|
|||||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
eth-block-tracker@^4.2.0, eth-block-tracker@^4.4.2:
|
eth-block-tracker@4.4.3, eth-block-tracker@^4.2.0, eth-block-tracker@^4.4.2:
|
||||||
version "4.4.3"
|
version "4.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz#766a0a0eb4a52c867a28328e9ae21353812cf626"
|
resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz#766a0a0eb4a52c867a28328e9ae21353812cf626"
|
||||||
integrity sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw==
|
integrity sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw==
|
||||||
@@ -9126,7 +9126,7 @@ eth-block-tracker@^4.2.0, eth-block-tracker@^4.4.2:
|
|||||||
pify "^3.0.0"
|
pify "^3.0.0"
|
||||||
safe-event-emitter "^1.0.1"
|
safe-event-emitter "^1.0.1"
|
||||||
|
|
||||||
eth-json-rpc-filters@^4.0.2, eth-json-rpc-filters@^4.2.1:
|
eth-json-rpc-filters@4.2.2, eth-json-rpc-filters@^4.0.2, eth-json-rpc-filters@^4.2.1:
|
||||||
version "4.2.2"
|
version "4.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.2.tgz#eb35e1dfe9357ace8a8908e7daee80b2cd60a10d"
|
resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.2.tgz#eb35e1dfe9357ace8a8908e7daee80b2cd60a10d"
|
||||||
integrity sha512-DGtqpLU7bBg63wPMWg1sCpkKCf57dJ+hj/k3zF26anXMzkmtSBDExL8IhUu7LUd34f0Zsce3PYNO2vV2GaTzaw==
|
integrity sha512-DGtqpLU7bBg63wPMWg1sCpkKCf57dJ+hj/k3zF26anXMzkmtSBDExL8IhUu7LUd34f0Zsce3PYNO2vV2GaTzaw==
|
||||||
@@ -9222,6 +9222,13 @@ eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2:
|
|||||||
json-rpc-random-id "^1.0.0"
|
json-rpc-random-id "^1.0.0"
|
||||||
xtend "^4.0.1"
|
xtend "^4.0.1"
|
||||||
|
|
||||||
|
eth-rpc-errors@4.0.2:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.2.tgz#11bc164e25237a679061ac05b7da7537b673d3b7"
|
||||||
|
integrity sha512-n+Re6Gu8XGyfFy1it0AwbD1x0MUzspQs0D5UiPs1fFPCr6WAwZM+vbIhXheBFrpgosqN9bs5PqlB4Q61U/QytQ==
|
||||||
|
dependencies:
|
||||||
|
fast-safe-stringify "^2.0.6"
|
||||||
|
|
||||||
eth-rpc-errors@^3.0.0:
|
eth-rpc-errors@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz#d7b22653c70dbf9defd4ef490fd08fe70608ca10"
|
resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz#d7b22653c70dbf9defd4ef490fd08fe70608ca10"
|
||||||
@@ -12503,6 +12510,14 @@ json-parse-even-better-errors@^2.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||||
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
||||||
|
|
||||||
|
json-rpc-engine@6.1.0, json-rpc-engine@^6.1.0:
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393"
|
||||||
|
integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==
|
||||||
|
dependencies:
|
||||||
|
"@metamask/safe-event-emitter" "^2.0.0"
|
||||||
|
eth-rpc-errors "^4.0.2"
|
||||||
|
|
||||||
json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0:
|
json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0:
|
||||||
version "3.8.0"
|
version "3.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9"
|
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9"
|
||||||
@@ -12523,14 +12538,6 @@ json-rpc-engine@^5.3.0:
|
|||||||
eth-rpc-errors "^3.0.0"
|
eth-rpc-errors "^3.0.0"
|
||||||
safe-event-emitter "^1.0.1"
|
safe-event-emitter "^1.0.1"
|
||||||
|
|
||||||
json-rpc-engine@^6.1.0:
|
|
||||||
version "6.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393"
|
|
||||||
integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==
|
|
||||||
dependencies:
|
|
||||||
"@metamask/safe-event-emitter" "^2.0.0"
|
|
||||||
eth-rpc-errors "^4.0.2"
|
|
||||||
|
|
||||||
json-rpc-error@^2.0.0:
|
json-rpc-error@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02"
|
resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02"
|
||||||
@@ -19214,14 +19221,19 @@ walker@^1.0.7, walker@~1.0.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
makeerror "1.0.x"
|
makeerror "1.0.x"
|
||||||
|
|
||||||
walletlink@^2.0.2:
|
walletlink@^2.1.0:
|
||||||
version "2.0.3"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/walletlink/-/walletlink-2.0.3.tgz#8905deed6ba9a07d5dd49d709db359df571b0cc4"
|
resolved "https://registry.yarnpkg.com/walletlink/-/walletlink-2.1.3.tgz#dd7ae5c5464ab3608c0faa5435ba736b945abcd7"
|
||||||
integrity sha512-fl8LmelFpgVITdGxGkoGhCn9coIcV/8ubg2kT96DaqGi2N4BNvUjlmgOsXMuHvVUMg4kGVZeq2XKaChXBC9ySA==
|
integrity sha512-W8qgXiJn5BoecV8gneo7hMCGue7H5UsXjLfhaph6Z6BT7cC4+3ItWWGY5PoSbXRtR7LGe3h0kPZqCggiPrSQzQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@metamask/safe-event-emitter" "2.0.0"
|
||||||
bind-decorator "^1.0.11"
|
bind-decorator "^1.0.11"
|
||||||
bn.js "^5.1.1"
|
bn.js "^5.1.1"
|
||||||
clsx "^1.1.0"
|
clsx "^1.1.0"
|
||||||
|
eth-block-tracker "4.4.3"
|
||||||
|
eth-json-rpc-filters "4.2.2"
|
||||||
|
eth-rpc-errors "4.0.2"
|
||||||
|
json-rpc-engine "6.1.0"
|
||||||
preact "^10.5.9"
|
preact "^10.5.9"
|
||||||
rxjs "^6.6.3"
|
rxjs "^6.6.3"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user