Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae27e245b4 | ||
|
|
897f354202 | ||
|
|
4745052f0e | ||
|
|
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"
|
||||||
|
|||||||
16
.github/workflows/release.yaml
vendored
16
.github/workflows/release.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Bump version and push tag
|
- name: Bump version and push tag
|
||||||
id: github_tag_action
|
id: github_tag_action
|
||||||
uses: mathieudutour/github-tag-action@v4.5
|
uses: mathieudutour/github-tag-action@331898d5052eedac9b15fec867b5ba66ebf9b692
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
release_branches: .*
|
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).
|
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",
|
||||||
|
|||||||
@@ -184,7 +184,12 @@ export function TransactionErrorContent({ message, onDismiss }: { message: strin
|
|||||||
</RowBetween>
|
</RowBetween>
|
||||||
<AutoColumn style={{ marginTop: 20, padding: '2rem 0' }} gap="24px" justify="center">
|
<AutoColumn style={{ marginTop: 20, padding: '2rem 0' }} gap="24px" justify="center">
|
||||||
<AlertTriangle color={theme.red1} style={{ strokeWidth: 1.5 }} size={64} />
|
<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}
|
{message}
|
||||||
</Text>
|
</Text>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ export function SwapCallbackError({ error }: { error: string }) {
|
|||||||
<SwapCallbackErrorInnerAlertTriangle>
|
<SwapCallbackErrorInnerAlertTriangle>
|
||||||
<AlertTriangle size={24} />
|
<AlertTriangle size={24} />
|
||||||
</SwapCallbackErrorInnerAlertTriangle>
|
</SwapCallbackErrorInnerAlertTriangle>
|
||||||
<p>{error}</p>
|
<p style={{ wordBreak: 'break-word' }}>{error}</p>
|
||||||
</SwapCallbackErrorInner>
|
</SwapCallbackErrorInner>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,26 @@ 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.'
|
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 +281,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 +312,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