This commit is contained in:
Callil Capuozzo 2021-05-04 20:52:27 -04:00
commit 699bcc25b6
27 changed files with 152 additions and 173 deletions

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

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