Merge branch 'main' of https://github.com/Uniswap/v3-interface into main
This commit is contained in:
commit
699bcc25b6
@ -49,7 +49,7 @@
|
||||
"@uniswap/v2-sdk": "^1.0.9",
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "1.0.0",
|
||||
"@uniswap/v3-sdk": "^1.0.1",
|
||||
"@uniswap/v3-sdk": "^1.0.3",
|
||||
"@web3-react/core": "^6.0.9",
|
||||
"@web3-react/fortmatic-connector": "^6.0.9",
|
||||
"@web3-react/injected-connector": "^6.0.7",
|
||||
|
@ -260,7 +260,7 @@ export default function CurrencyInputPanel({
|
||||
{!hideInput && !hideBalance && (
|
||||
<FiatRow>
|
||||
<RowBetween>
|
||||
{account && (
|
||||
{account ? (
|
||||
<RowFixed style={{ height: '17px' }}>
|
||||
<TYPE.body
|
||||
onClick={onMax}
|
||||
@ -280,6 +280,8 @@ export default function CurrencyInputPanel({
|
||||
<StyledBalanceMax onClick={onMax}>(Max)</StyledBalanceMax>
|
||||
) : null}
|
||||
</RowFixed>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
|
||||
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
|
||||
|
@ -4,7 +4,7 @@ import { Text } from 'rebass'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { darken } from 'polished'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { Moon, Sun } from 'react-feather'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import Logo from '../../assets/svg/logo.svg'
|
||||
@ -272,7 +272,7 @@ export const StyledMenuButton = styled.button`
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 35px;
|
||||
background-color: ${({ theme }) => theme.bg3};
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
margin-left: 8px;
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
@ -305,7 +305,7 @@ export default function Header() {
|
||||
|
||||
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
|
||||
// const [isDark] = useDarkModeManager()
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const [darkMode, toggleDarkMode] = useDarkModeManager()
|
||||
|
||||
const toggleClaimModal = useToggleSelfClaimModal()
|
||||
|
||||
@ -381,6 +381,9 @@ export default function Header() {
|
||||
</AccountElement>
|
||||
</HeaderElement>
|
||||
<HeaderElementWrap>
|
||||
<StyledMenuButton onClick={() => toggleDarkMode()}>
|
||||
{darkMode ? <Moon size={20} /> : <Sun size={20} />}
|
||||
</StyledMenuButton>
|
||||
<Menu />
|
||||
</HeaderElementWrap>
|
||||
</HeaderControls>
|
||||
|
@ -6,7 +6,6 @@ import { NavLink, Link as HistoryLink } from 'react-router-dom'
|
||||
|
||||
import { ArrowLeft } from 'react-feather'
|
||||
import { RowBetween } from '../Row'
|
||||
// import QuestionHelper from '../QuestionHelper'
|
||||
import Settings from '../Settings'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { AppDispatch } from 'state'
|
||||
@ -86,7 +85,15 @@ export function FindPoolTabs({ origin }: { origin: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
export function AddRemoveTabs({ adding, creating }: { adding: boolean; creating: boolean }) {
|
||||
export function AddRemoveTabs({
|
||||
adding,
|
||||
creating,
|
||||
positionID,
|
||||
}: {
|
||||
adding: boolean
|
||||
creating: boolean
|
||||
positionID?: string | undefined
|
||||
}) {
|
||||
const theme = useTheme()
|
||||
|
||||
// reset states on back
|
||||
@ -96,7 +103,7 @@ export function AddRemoveTabs({ adding, creating }: { adding: boolean; creating:
|
||||
<Tabs>
|
||||
<RowBetween style={{ padding: '1rem 1rem 0 1rem' }}>
|
||||
<HistoryLink
|
||||
to="/pool"
|
||||
to={'/pool' + (!!positionID ? `/${positionID.toString()}` : '')}
|
||||
onClick={() => {
|
||||
adding && dispatch(resetMintState())
|
||||
}}
|
||||
|
@ -213,12 +213,12 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi
|
||||
>
|
||||
{showMore ? (
|
||||
<>
|
||||
Manage
|
||||
Migrate
|
||||
<ChevronUp size="20" style={{ marginLeft: '10px' }} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Manage
|
||||
Migrate
|
||||
<ChevronDown size="20" style={{ marginLeft: '10px' }} />
|
||||
</>
|
||||
)}
|
||||
|
@ -283,6 +283,7 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
|
||||
<>
|
||||
<RangeLineItem
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setManuallyInverted(!manuallyInverted)
|
||||
}}
|
||||
|
@ -42,6 +42,7 @@ export const PositionPreview = ({
|
||||
: currency0
|
||||
: currency0
|
||||
)
|
||||
|
||||
const sorted = baseCurrency === currency0
|
||||
const quoteCurrency = sorted ? currency1 : currency0
|
||||
|
||||
@ -113,13 +114,14 @@ export const PositionPreview = ({
|
||||
<LightCard width="48%" padding="8px">
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<TYPE.main fontSize="12px">Min price</TYPE.main>
|
||||
<TYPE.mediumHeader textAlign="center">{`${priceLower.toSignificant(4)}`}</TYPE.mediumHeader>
|
||||
<TYPE.mediumHeader textAlign="center">{`${priceLower.toSignificant(5)}`}</TYPE.mediumHeader>
|
||||
<TYPE.main
|
||||
textAlign="center"
|
||||
fontSize="12px"
|
||||
>{` ${quoteCurrency.symbol}/${baseCurrency.symbol}`}</TYPE.main>
|
||||
<TYPE.small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
|
||||
{'Position will be'} <CurrencyLogo currency={baseCurrency} size="10px" /> {' 100% at this price.'}
|
||||
Position will be <CurrencyLogo currency={baseCurrency} size="10px" /> 100% {baseCurrency?.symbol} at
|
||||
this price.
|
||||
</TYPE.small>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
@ -127,14 +129,14 @@ export const PositionPreview = ({
|
||||
<LightCard width="48%" padding="8px">
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<TYPE.main fontSize="12px">Max price</TYPE.main>
|
||||
<TYPE.mediumHeader textAlign="center">{`${priceUpper.toSignificant(4)}`}</TYPE.mediumHeader>
|
||||
<TYPE.mediumHeader textAlign="center">{`${priceUpper.toSignificant(5)}`}</TYPE.mediumHeader>
|
||||
<TYPE.main
|
||||
textAlign="center"
|
||||
fontSize="12px"
|
||||
>{` ${quoteCurrency.symbol}/${baseCurrency.symbol}`}</TYPE.main>
|
||||
<TYPE.small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
|
||||
{' Position will be 100% '}
|
||||
{quoteCurrency?.symbol} {' at this price.'}
|
||||
Position will be <CurrencyLogo currency={quoteCurrency} size="10px" /> 100% {quoteCurrency?.symbol} at
|
||||
this price.
|
||||
</TYPE.small>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
|
@ -2,10 +2,13 @@ import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import React, { useContext } from 'react'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { useUserSlippageTolerance } from '../../state/user/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { computePriceImpactWithMaximumSlippage } from '../../utils/computePriceImpactWithMaximumSlippage'
|
||||
import { computeRealizedLPFeeAmount } from '../../utils/prices'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import FormattedPriceImpact from './FormattedPriceImpact'
|
||||
import SwapRoute from './SwapRoute'
|
||||
|
||||
export interface AdvancedSwapDetailsProps {
|
||||
@ -16,6 +19,7 @@ export function AdvancedSwapDetails({ trade }: AdvancedSwapDetailsProps) {
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
const realizedLPFee = computeRealizedLPFeeAmount(trade)
|
||||
const [allowedSlippage] = useUserSlippageTolerance()
|
||||
|
||||
return !trade ? null : (
|
||||
<AutoColumn gap="8px">
|
||||
@ -40,6 +44,17 @@ export function AdvancedSwapDetails({ trade }: AdvancedSwapDetailsProps) {
|
||||
<SwapRoute trade={trade} />
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
|
||||
Execution price vs. spot price
|
||||
</TYPE.black>
|
||||
</RowFixed>
|
||||
<TYPE.black fontSize={12} color={theme.text1}>
|
||||
<FormattedPriceImpact priceImpact={computePriceImpactWithMaximumSlippage(trade, allowedSlippage)} />
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
)
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ import styled, { ThemeContext } from 'styled-components'
|
||||
import { useUSDCValue } from '../../hooks/useUSDCPrice'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { computeFiatValuePriceImpact, isAddress, shortenAddress } from '../../utils'
|
||||
import { isAddress, shortenAddress } from '../../utils'
|
||||
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { FiatValue } from '../CurrencyInputPanel/FiatValue'
|
||||
import CurrencyLogo from '../CurrencyLogo'
|
||||
|
@ -1,24 +1,17 @@
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade, FeeAmount } from '@uniswap/v3-sdk'
|
||||
import React, { Fragment, memo, useContext } from 'react'
|
||||
import { ChevronLeft, ChevronRight } from 'react-feather'
|
||||
import { ChevronRight } from 'react-feather'
|
||||
import { Flex } from 'rebass'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { TYPE } from '../../theme'
|
||||
import { unwrappedToken } from 'utils/wrappedCurrency'
|
||||
|
||||
function LabeledArrow({ fee }: { fee: FeeAmount }) {
|
||||
function LabeledArrow({}: { fee: FeeAmount }) {
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
// todo: improve the rendering of this labeled arrow
|
||||
return (
|
||||
<>
|
||||
<ChevronLeft size={12} color={theme.text2} />
|
||||
<span style={{ fontSize: 12, marginTop: 2 }}>{new Percent(fee, 1_000_000).toSignificant()}%</span>
|
||||
<ChevronRight size={12} color={theme.text2} />
|
||||
</>
|
||||
)
|
||||
// todo: render the fee in the label
|
||||
return <ChevronRight size={12} color={theme.text2} />
|
||||
}
|
||||
|
||||
export default memo(function SwapRoute({ trade }: { trade: V2Trade | V3Trade }) {
|
||||
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"v3CoreFactoryAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"weth9Address": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
|
||||
"multicall2Address": "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
|
||||
"proxyAdminAddress": "0xB753548F6E010e7e680BA186F9Ca1BdAB2E90cf2",
|
||||
"tickLensAddress": "0xbfd8137f7d1516D3ea5cA83523914859ec47F573",
|
||||
"quoterAddress": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
||||
"swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
||||
"nftDescriptorLibraryAddress": "0x42B24A95702b9986e82d421cC3568932790A48Ec",
|
||||
"nonfungibleTokenPositionDescriptorAddress": "0x91ae842A5Ffd8d12023116943e72A606179294f3",
|
||||
"descriptorProxyAddress": "0xEe6A57eC80ea46401049E92587E52f5Ec1c24785",
|
||||
"nonfungibleTokenPositionManagerAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
"v3MigratorAddress": "0xA5644E29708357803b5A882D272c41cC0dF92B34"
|
||||
}
|
@ -1,30 +1,26 @@
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import goerli from './goerli.json'
|
||||
import ropsten from './ropsten.json'
|
||||
import rinkeby from './rinkeby.json'
|
||||
import kovan from './kovan.json'
|
||||
import mainnet from './mainnet.json'
|
||||
import { FACTORY_ADDRESS } from '@uniswap/v3-sdk'
|
||||
|
||||
function constructAddressMap(
|
||||
key: keyof typeof goerli | keyof typeof ropsten | keyof typeof rinkeby | keyof typeof mainnet
|
||||
): { [chainId in ChainId]: string } {
|
||||
function constructSameAddressMap(address: string): { [chainId in ChainId]: string } {
|
||||
return {
|
||||
[ChainId.MAINNET]: mainnet[key],
|
||||
[ChainId.ROPSTEN]: ropsten[key],
|
||||
[ChainId.KOVAN]: kovan[key],
|
||||
[ChainId.RINKEBY]: rinkeby[key],
|
||||
[ChainId.GÖRLI]: goerli[key],
|
||||
[ChainId.MAINNET]: address,
|
||||
[ChainId.ROPSTEN]: address,
|
||||
[ChainId.KOVAN]: address,
|
||||
[ChainId.RINKEBY]: address,
|
||||
[ChainId.GÖRLI]: address,
|
||||
}
|
||||
}
|
||||
|
||||
export const V3_CORE_FACTORY_ADDRESSES = constructAddressMap('v3CoreFactoryAddress')
|
||||
export const V3_CORE_FACTORY_ADDRESSES = constructSameAddressMap(FACTORY_ADDRESS)
|
||||
|
||||
export const QUOTER_ADDRESSES = constructAddressMap('quoterAddress')
|
||||
export const QUOTER_ADDRESSES = constructSameAddressMap('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6')
|
||||
|
||||
export const TICK_LENS_ADDRESSES = constructAddressMap('tickLensAddress')
|
||||
export const TICK_LENS_ADDRESSES = constructSameAddressMap('0xbfd8137f7d1516D3ea5cA83523914859ec47F573')
|
||||
|
||||
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES = constructAddressMap('nonfungibleTokenPositionManagerAddress')
|
||||
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES = constructSameAddressMap(
|
||||
'0xC36442b4a4522E871399CD717aBDD847Ab11FE88'
|
||||
)
|
||||
|
||||
export const SWAP_ROUTER_ADDRESSES = constructAddressMap('swapRouter')
|
||||
export const SWAP_ROUTER_ADDRESSES = constructSameAddressMap('0xE592427A0AEce92De3Edee1F18E0157C05861564')
|
||||
|
||||
export const V3_MIGRATOR_ADDRESSES = constructAddressMap('v3MigratorAddress')
|
||||
export const V3_MIGRATOR_ADDRESSES = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34')
|
||||
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"v3CoreFactoryAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"weth9Address": "0xd0A1E359811322d97991E03f863a0C30C2cF029C",
|
||||
"multicall2Address": "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
|
||||
"proxyAdminAddress": "0xB753548F6E010e7e680BA186F9Ca1BdAB2E90cf2",
|
||||
"tickLensAddress": "0xbfd8137f7d1516D3ea5cA83523914859ec47F573",
|
||||
"quoterAddress": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
||||
"swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
||||
"nftDescriptorLibraryAddress": "0x42B24A95702b9986e82d421cC3568932790A48Ec",
|
||||
"nonfungibleTokenPositionDescriptorAddress": "0x91ae842A5Ffd8d12023116943e72A606179294f3",
|
||||
"descriptorProxyAddress": "0xEe6A57eC80ea46401049E92587E52f5Ec1c24785",
|
||||
"nonfungibleTokenPositionManagerAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
"v3MigratorAddress": "0xA5644E29708357803b5A882D272c41cC0dF92B34"
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"v3CoreFactoryAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"weth9Address": "0xc778417E063141139Fce010982780140Aa0cD5Ab",
|
||||
"multicall2Address": "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
|
||||
"proxyAdminAddress": "0xB753548F6E010e7e680BA186F9Ca1BdAB2E90cf2",
|
||||
"tickLensAddress": "0xbfd8137f7d1516D3ea5cA83523914859ec47F573",
|
||||
"quoterAddress": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
||||
"swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
||||
"nftDescriptorLibraryAddress": "0x42B24A95702b9986e82d421cC3568932790A48Ec",
|
||||
"nonfungibleTokenPositionDescriptorAddress": "0x91ae842A5Ffd8d12023116943e72A606179294f3",
|
||||
"descriptorProxyAddress": "0xEe6A57eC80ea46401049E92587E52f5Ec1c24785",
|
||||
"nonfungibleTokenPositionManagerAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
"v3MigratorAddress": "0xA5644E29708357803b5A882D272c41cC0dF92B34"
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"v3CoreFactoryAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"weth9Address": "0xc778417E063141139Fce010982780140Aa0cD5Ab",
|
||||
"multicall2Address": "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
|
||||
"proxyAdminAddress": "0xB753548F6E010e7e680BA186F9Ca1BdAB2E90cf2",
|
||||
"tickLensAddress": "0xbfd8137f7d1516D3ea5cA83523914859ec47F573",
|
||||
"quoterAddress": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
||||
"swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
||||
"nftDescriptorLibraryAddress": "0x42B24A95702b9986e82d421cC3568932790A48Ec",
|
||||
"nonfungibleTokenPositionDescriptorAddress": "0x91ae842A5Ffd8d12023116943e72A606179294f3",
|
||||
"descriptorProxyAddress": "0xEe6A57eC80ea46401049E92587E52f5Ec1c24785",
|
||||
"nonfungibleTokenPositionManagerAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
"v3MigratorAddress": "0xA5644E29708357803b5A882D272c41cC0dF92B34"
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"v3CoreFactoryAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"weth9Address": "0xc778417E063141139Fce010982780140Aa0cD5Ab",
|
||||
"multicall2Address": "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
|
||||
"proxyAdminAddress": "0xB753548F6E010e7e680BA186F9Ca1BdAB2E90cf2",
|
||||
"tickLensAddress": "0xbfd8137f7d1516D3ea5cA83523914859ec47F573",
|
||||
"quoterAddress": "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
|
||||
"swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564",
|
||||
"nftDescriptorLibraryAddress": "0x42B24A95702b9986e82d421cC3568932790A48Ec",
|
||||
"nonfungibleTokenPositionDescriptorAddress": "0x91ae842A5Ffd8d12023116943e72A606179294f3",
|
||||
"descriptorProxyAddress": "0xEe6A57eC80ea46401049E92587E52f5Ec1c24785",
|
||||
"nonfungibleTokenPositionManagerAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
||||
"v3MigratorAddress": "0xA5644E29708357803b5A882D272c41cC0dF92B34"
|
||||
}
|
@ -34,7 +34,7 @@ const PERMITTABLE_TOKENS: {
|
||||
}
|
||||
} = {
|
||||
[ChainId.MAINNET]: {
|
||||
[USDC.address]: { type: PermitType.AMOUNT, name: 'USD Coin', version: '1' },
|
||||
[USDC.address]: { type: PermitType.AMOUNT, name: 'USD Coin', version: '2' },
|
||||
[DAI.address]: { type: PermitType.ALLOWED, name: 'Dai Stablecoin', version: '1' },
|
||||
[UNI[ChainId.MAINNET].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
|
||||
},
|
||||
@ -44,6 +44,7 @@ const PERMITTABLE_TOKENS: {
|
||||
},
|
||||
[ChainId.ROPSTEN]: {
|
||||
[UNI[ChainId.ROPSTEN].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
|
||||
['0x07865c6E87B9F70255377e024ace6630C1Eaa37F']: { type: PermitType.AMOUNT, name: 'USD Coin', version: '2' },
|
||||
},
|
||||
[ChainId.GÖRLI]: {
|
||||
[UNI[ChainId.GÖRLI].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useContext, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useContext, useMemo, useState, useEffect } from 'react'
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { Currency, TokenAmount, ETHER, currencyEquals } from '@uniswap/sdk-core'
|
||||
import { WETH9 } from '@uniswap/sdk-core'
|
||||
@ -89,6 +89,13 @@ export default function AddLiquidity({
|
||||
[currencyA, currencyB, baseCurrency]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setBaseCurrency(currencyA)
|
||||
return () => {
|
||||
setBaseCurrency(undefined)
|
||||
}
|
||||
}, [currencyA, currencyB])
|
||||
|
||||
// mint state
|
||||
const { independentField, typedValue, startPriceTypedValue } = useMintState()
|
||||
|
||||
@ -371,7 +378,7 @@ export default function AddLiquidity({
|
||||
pendingText={pendingText}
|
||||
/>
|
||||
<AppBody>
|
||||
<AddRemoveTabs creating={false} adding={true} />
|
||||
<AddRemoveTabs creating={false} adding={true} positionID={tokenId} />
|
||||
<Wrapper>
|
||||
<AutoColumn gap="32px">
|
||||
{!hasExistingPosition && (
|
||||
@ -383,7 +390,6 @@ export default function AddLiquidity({
|
||||
<TYPE.blue fontSize="12px">Clear All</TYPE.blue>
|
||||
</ButtonText>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<CurrencyDropdown
|
||||
value={formattedAmounts[Field.CURRENCY_A]}
|
||||
@ -565,7 +571,6 @@ export default function AddLiquidity({
|
||||
onMax={() => {
|
||||
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
|
||||
}}
|
||||
onCurrencySelect={handleCurrencyASelect}
|
||||
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
|
||||
currency={currencies[Field.CURRENCY_A]}
|
||||
id="add-liquidity-input-tokena"
|
||||
@ -576,7 +581,6 @@ export default function AddLiquidity({
|
||||
<CurrencyInputPanel
|
||||
value={formattedAmounts[Field.CURRENCY_B]}
|
||||
onUserInput={onFieldBInput}
|
||||
onCurrencySelect={handleCurrencyBSelect}
|
||||
onMax={() => {
|
||||
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
|
||||
}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { Fraction, Price, Token, TokenAmount, WETH9 } from '@uniswap/sdk-core'
|
||||
import { FACTORY_ADDRESS, JSBI } from '@uniswap/v2-sdk'
|
||||
import { Redirect, RouteComponentProps } from 'react-router'
|
||||
@ -113,7 +113,7 @@ function V2PairMigration({
|
||||
const theme = useTheme()
|
||||
|
||||
const pairFactory = useSingleCallResult(pair, 'factory')
|
||||
const isNotUniswap = pairFactory.result?.[0] !== FACTORY_ADDRESS
|
||||
const isNotUniswap = pairFactory.result?.[0] !== FACTORY_ADDRESS ?? false
|
||||
|
||||
const deadline = useTransactionDeadline() // custom from users settings
|
||||
const blockTimestamp = useCurrentBlockTimestamp()
|
||||
@ -163,6 +163,11 @@ function V2PairMigration({
|
||||
baseToken
|
||||
)
|
||||
|
||||
// reset the initial state, dont need cleanup token always defined
|
||||
useEffect(() => {
|
||||
setBaseToken(token0)
|
||||
}, [baseToken, token0])
|
||||
|
||||
// get value and prices at ticks
|
||||
const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks
|
||||
const { [Bound.LOWER]: priceLower, [Bound.UPPER]: priceUpper } = pricesAtTicks
|
||||
@ -218,12 +223,12 @@ function V2PairMigration({
|
||||
)
|
||||
|
||||
const refund0 = useMemo(
|
||||
() => v3Amount0Min && new TokenAmount(token0, JSBI.subtract(token0Value.raw, v3Amount0Min.raw)),
|
||||
[token0Value, v3Amount0Min, token0]
|
||||
() => position && new TokenAmount(token0, JSBI.subtract(token0Value.raw, position.amount0.raw)),
|
||||
[token0Value, position, token0]
|
||||
)
|
||||
const refund1 = useMemo(
|
||||
() => v3Amount1Min && new TokenAmount(token1, JSBI.subtract(token1Value.raw, v3Amount1Min.raw)),
|
||||
[token1Value, v3Amount1Min, token1]
|
||||
() => position && new TokenAmount(token1, JSBI.subtract(token1Value.raw, position.amount1.raw)),
|
||||
[token1Value, position, token1]
|
||||
)
|
||||
|
||||
const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false)
|
||||
@ -516,13 +521,13 @@ function V2PairMigration({
|
||||
</YellowCard>
|
||||
) : null}
|
||||
|
||||
{v3Amount0Min && v3Amount1Min ? (
|
||||
{position ? (
|
||||
<DarkGreyCard>
|
||||
<AutoColumn gap="md">
|
||||
<LiquidityInfo token0Amount={v3Amount0Min} token1Amount={v3Amount1Min} />
|
||||
<LiquidityInfo token0Amount={position.amount0} token1Amount={position.amount1} />
|
||||
{chainId && refund0 && refund1 ? (
|
||||
<TYPE.black fontSize={12}>
|
||||
{formatTokenAmount(refund0, 4)} {token0.equals(WETH9[chainId]) ? 'ETH' : token0.symbol} and{' '}
|
||||
At least {formatTokenAmount(refund0, 4)} {token0.equals(WETH9[chainId]) ? 'ETH' : token0.symbol} and{' '}
|
||||
{formatTokenAmount(refund1, 4)} {token1.equals(WETH9[chainId]) ? 'ETH' : token1.symbol} will be
|
||||
refunded to your wallet due to selected price range.
|
||||
</TYPE.black>
|
||||
|
@ -21,15 +21,15 @@ const CTASection = styled.section`
|
||||
|
||||
const CTA1 = styled(ExternalLink)`
|
||||
background-size: 40px 40px;
|
||||
background-image: linear-gradient(to right, #2d2d2d 1px, transparent 1px),
|
||||
linear-gradient(to bottom, #2d2d2d 1px, transparent 1px);
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
background-image: linear-gradient(to right, ${({ theme }) => theme.bg3} 1px, transparent 1px),
|
||||
linear-gradient(to bottom, ${({ theme }) => theme.bg3} 1px, transparent 1px);
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
padding: 32px;
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
border: 1px solid ${({ theme }) => theme.bg4};
|
||||
border: 1px solid ${({ theme }) => theme.bg3};
|
||||
|
||||
* {
|
||||
color: ${({ theme }) => theme.text1};
|
||||
|
@ -12,9 +12,9 @@ import styled from 'styled-components'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { RowBetween, RowFixed } from 'components/Row'
|
||||
import DoubleCurrencyLogo from 'components/DoubleLogo'
|
||||
import { HideExtraSmall, TYPE } from 'theme'
|
||||
import { ExternalLink, HideExtraSmall, TYPE } from 'theme'
|
||||
import Badge from 'components/Badge'
|
||||
import { calculateGasMargin } from 'utils'
|
||||
import { calculateGasMargin, getEtherscanLink } from 'utils'
|
||||
import { ButtonConfirmed, ButtonPrimary, ButtonGray } from 'components/Button'
|
||||
import { DarkCard, DarkGreyCard, LightCard } from 'components/Card'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
@ -131,16 +131,12 @@ function CurrentPriceCard({
|
||||
pool,
|
||||
currencyQuote,
|
||||
currencyBase,
|
||||
ratio,
|
||||
}: {
|
||||
inverted?: boolean
|
||||
pool?: Pool | null
|
||||
currencyQuote?: Currency
|
||||
currencyBase?: Currency
|
||||
ratio?: number
|
||||
}) {
|
||||
const theme = useTheme()
|
||||
|
||||
const { t } = useTranslation()
|
||||
if (!pool || !currencyQuote || !currencyBase) {
|
||||
return null
|
||||
@ -155,26 +151,23 @@ function CurrentPriceCard({
|
||||
</TYPE.mediumHeader>
|
||||
<ExtentsText>{currencyQuote?.symbol + ' / ' + currencyBase?.symbol}</ExtentsText>
|
||||
</AutoColumn>
|
||||
|
||||
{typeof ratio === 'number' && (
|
||||
<TYPE.small color={theme.text3} textAlign="center" style={{ marginTop: '8px' }}>
|
||||
Your position is currently {ratio}% {currencyBase?.symbol} and {100 - ratio}% {currencyQuote?.symbol}
|
||||
</TYPE.small>
|
||||
)}
|
||||
</LightCard>
|
||||
)
|
||||
}
|
||||
|
||||
function getRatio(lower: Price, current: Price, upper: Price) {
|
||||
try {
|
||||
if (!current.greaterThan(lower)) {
|
||||
return 100
|
||||
} else if (!current.lessThan(upper)) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const a = Number.parseFloat(lower.toSignificant(15))
|
||||
const b = Number.parseFloat(upper.toSignificant(15))
|
||||
const c = Number.parseFloat(current.toSignificant(15))
|
||||
|
||||
let ratio = Math.floor(((Math.sqrt(a * b) - Math.sqrt(b * c)) / (c - Math.sqrt(b * c))) * 100)
|
||||
if (ratio > 100) {
|
||||
ratio -= 100
|
||||
}
|
||||
const ratio = Math.floor((1 / ((Math.sqrt(a * b) - Math.sqrt(b * c)) / (c - Math.sqrt(b * c)) + 1)) * 100)
|
||||
|
||||
if (ratio < 0 || ratio > 100) {
|
||||
throw Error('Out of range')
|
||||
@ -243,6 +236,9 @@ export function PositionPage({
|
||||
: undefined
|
||||
}, [inverted, pool, priceLower, priceUpper])
|
||||
|
||||
// really can't figure out why i have to do this, getting conditional hook call errors otherwise
|
||||
const WORKAROUND = typeof ratio === 'number' ? (inverted ? 100 - ratio : ratio) : undefined
|
||||
|
||||
// fees
|
||||
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails)
|
||||
|
||||
@ -460,6 +456,9 @@ export function PositionPage({
|
||||
<div style={{ marginRight: 12 }}>
|
||||
<img height="400px" src={metadata.result.image} />
|
||||
</div>
|
||||
{typeof chainId === 'number' && owner && !ownsNFT ? (
|
||||
<ExternalLink href={getEtherscanLink(chainId, owner, 'address')}>Owner</ExternalLink>
|
||||
) : null}
|
||||
</DarkCard>
|
||||
) : (
|
||||
<DarkCard
|
||||
@ -497,12 +496,12 @@ export function PositionPage({
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<TYPE.main>
|
||||
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)} (
|
||||
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
|
||||
</TYPE.main>
|
||||
{typeof ratio === 'number' && (
|
||||
<DarkGreyCard padding="4px 6px" style={{ width: 'fit-content', marginLeft: '8px' }}>
|
||||
<TYPE.main color={theme.text2} fontSize={11}>
|
||||
{100 - ratio}%
|
||||
{inverted ? ratio : 100 - ratio}%
|
||||
</TYPE.main>
|
||||
</DarkGreyCard>
|
||||
)}
|
||||
@ -515,12 +514,12 @@ export function PositionPage({
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<TYPE.main>
|
||||
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)} (
|
||||
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
|
||||
</TYPE.main>
|
||||
{typeof ratio === 'number' && (
|
||||
<DarkGreyCard padding="4px 6px" style={{ width: 'fit-content', marginLeft: '8px' }}>
|
||||
<TYPE.main color={theme.text2} fontSize={11}>
|
||||
{ratio}%
|
||||
{WORKAROUND}%
|
||||
</TYPE.main>
|
||||
</DarkGreyCard>
|
||||
)}
|
||||
@ -546,7 +545,7 @@ export function PositionPage({
|
||||
</TYPE.largeHeader>
|
||||
)}
|
||||
</AutoColumn>
|
||||
{feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) || !!collectMigrationHash ? (
|
||||
{ownsNFT && (feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) || !!collectMigrationHash) ? (
|
||||
<ButtonConfirmed
|
||||
disabled={collecting || !!collectMigrationHash}
|
||||
confirmed={!!collectMigrationHash && !isCollectPending}
|
||||
@ -644,10 +643,12 @@ export function PositionPage({
|
||||
<ExtentsText>Min price</ExtentsText>
|
||||
<TYPE.mediumHeader textAlign="center">{priceLower?.toSignificant(4)}</TYPE.mediumHeader>
|
||||
<ExtentsText> {currencyQuote?.symbol + ' / ' + currencyBase?.symbol}</ExtentsText>
|
||||
|
||||
{inRange && (
|
||||
<TYPE.small color={theme.text3}>
|
||||
{' Your position is will be 100% '}
|
||||
{currencyBase?.symbol} {' at this price.'}
|
||||
Your position will be 100% {currencyBase?.symbol} at this price.
|
||||
</TYPE.small>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
|
||||
@ -657,10 +658,12 @@ export function PositionPage({
|
||||
<ExtentsText>Max price</ExtentsText>
|
||||
<TYPE.mediumHeader textAlign="center">{priceUpper?.toSignificant(4)}</TYPE.mediumHeader>
|
||||
<ExtentsText> {currencyQuote?.symbol + ' / ' + currencyBase?.symbol}</ExtentsText>
|
||||
|
||||
{inRange && (
|
||||
<TYPE.small color={theme.text3}>
|
||||
{' Your position is will be 100% '}
|
||||
{currencyQuote?.symbol} {' at this price.'}
|
||||
Your position will be 100% {currencyQuote?.symbol} at this price.
|
||||
</TYPE.small>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
</RowBetween>
|
||||
@ -669,7 +672,6 @@ export function PositionPage({
|
||||
pool={pool}
|
||||
currencyQuote={currencyQuote}
|
||||
currencyBase={currencyBase}
|
||||
ratio={typeof ratio === 'number' && inRange ? (inverted ? 100 - ratio : ratio) : undefined}
|
||||
/>
|
||||
</AutoColumn>
|
||||
</DarkCard>
|
||||
|
@ -272,7 +272,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
||||
pendingText={pendingText}
|
||||
/>
|
||||
<AppBody>
|
||||
<AddRemoveTabs creating={false} adding={false} />
|
||||
<AddRemoveTabs creating={false} adding={false} positionID={tokenId.toString()} />
|
||||
<Wrapper>
|
||||
{position ? (
|
||||
<AutoColumn gap="lg">
|
||||
|
@ -48,7 +48,7 @@ import {
|
||||
} from '../../state/swap/hooks'
|
||||
import { useExpertModeManager, useUserSingleHopOnly, useUserSlippageTolerance } from '../../state/user/hooks'
|
||||
import { LinkStyledButton, TYPE } from '../../theme'
|
||||
import { computeFiatValuePriceImpact } from '../../utils'
|
||||
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
|
||||
import { getTradeVersion } from '../../utils/getTradeVersion'
|
||||
import { isTradeBetter } from '../../utils/isTradeBetter'
|
||||
import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
||||
|
18
src/utils/computePriceImpactWithMaximumSlippage.tsx
Normal file
18
src/utils/computePriceImpactWithMaximumSlippage.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { CurrencyAmount, Percent, Price } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
|
||||
function computePriceImpact(midPrice: Price, inputAmount: CurrencyAmount, outputAmount: CurrencyAmount): Percent {
|
||||
const exactQuote = midPrice.raw.multiply(inputAmount.raw)
|
||||
// calculate slippage := (exactQuote - outputAmount) / exactQuote
|
||||
const slippage = exactQuote.subtract(outputAmount.raw).divide(exactQuote)
|
||||
return new Percent(slippage.numerator, slippage.denominator)
|
||||
}
|
||||
|
||||
export function computePriceImpactWithMaximumSlippage(trade: V2Trade | V3Trade, allowedSlippage: Percent): Percent {
|
||||
return computePriceImpact(
|
||||
trade.route.midPrice,
|
||||
trade.maximumAmountIn(allowedSlippage),
|
||||
trade.minimumAmountOut(allowedSlippage)
|
||||
)
|
||||
}
|
@ -119,4 +119,3 @@ export function supportedChainId(chainId: number): ChainId | undefined {
|
||||
export function formattedFeeAmount(feeAmount: FeeAmount): number {
|
||||
return feeAmount / 10000
|
||||
}
|
||||
export { computeFiatValuePriceImpact } from './computeFiatValuePriceImpact'
|
||||
|
@ -41,7 +41,7 @@ export function computeRealizedLPFeeAmount(trade?: V2Trade | V3Trade | null): Cu
|
||||
: ONE_HUNDRED_PERCENT.subtract(
|
||||
trade.route.pools.reduce<Fraction>(
|
||||
(currentFee: Fraction, pool): Fraction =>
|
||||
currentFee.multiply(ONE_HUNDRED_PERCENT.subtract(new Fraction(pool.fee, 10_000))),
|
||||
currentFee.multiply(ONE_HUNDRED_PERCENT.subtract(new Fraction(pool.fee, 1_000_000))),
|
||||
ONE_HUNDRED_PERCENT
|
||||
)
|
||||
)
|
||||
|
@ -4149,10 +4149,10 @@
|
||||
"@uniswap/v3-core" "1.0.0"
|
||||
base64-sol "1.0.1"
|
||||
|
||||
"@uniswap/v3-sdk@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.1.tgz#a44f7de0fff2964dcd7bb848ccd55716c78d088e"
|
||||
integrity sha512-5oOJKnAInJq3uTHNjKj2tw/YQndNW6I4bQglEjGyi8te7IO75lJunMtqwjAKVIDMyoKT7iIR25p4t1ZZLEgiHQ==
|
||||
"@uniswap/v3-sdk@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.3.tgz#8f47b5f8cc8997992811a242ef202f9a8c4797cf"
|
||||
integrity sha512-izIrHTAXCeMhfye0nHntoAS0UTbpa8HyGSD++Zmy+kROeb2gSAcpXvnLHzRDIPxq0G4rOH0h05Y5fhHAxaXj5w==
|
||||
dependencies:
|
||||
"@ethersproject/abi" "^5.0.12"
|
||||
"@ethersproject/solidity" "^5.0.9"
|
||||
|
Loading…
Reference in New Issue
Block a user