Commit 18408c9c authored by Ian Lapham's avatar Ian Lapham Committed by GitHub

Increase Liquidity, component cleanup, preview components (#50)

* basic +/- buttons

* start increase liquidity

* fix v3 remove
parent 39f018ba
...@@ -102,6 +102,7 @@ ...@@ -102,6 +102,7 @@
"connectWallet": "Connect Wallet", "connectWallet": "Connect Wallet",
"unsupportedAsset": "Unsupported Asset", "unsupportedAsset": "Unsupported Asset",
"feePool": "Fee Pool", "feePool": "Fee Pool",
"feeTier": "Fee Tier",
"rebalanceMessage": "Your underlying tokens will be automatically rebalanced when the rate of the pool changes and may be different when you withdraw the position.", "rebalanceMessage": "Your underlying tokens will be automatically rebalanced when the rate of the pool changes and may be different when you withdraw the position.",
"addEarnHelper": "You will earn fees from trades proportional to your share of the pool.", "addEarnHelper": "You will earn fees from trades proportional to your share of the pool.",
"learnMoreAboutFess": " Learn more about earning fees.", "learnMoreAboutFess": " Learn more about earning fees.",
......
import React from 'react'
import { FeeAmount } from '@uniswap/v3-sdk'
import { useTranslation } from 'react-i18next'
import { AutoColumn } from 'components/Column'
import { DynamicSection } from 'pages/AddLiquidity/styled'
import { TYPE } from 'theme'
import { RowBetween } from 'components/Row'
import { ButtonRadioChecked } from 'components/Button'
export default function FeeSelector({
disabled = false,
feeAmount,
handleFeePoolSelect,
}: {
disabled?: boolean
feeAmount?: FeeAmount
handleFeePoolSelect: (feeAmount: FeeAmount) => void
}) {
const { t } = useTranslation()
return (
<AutoColumn gap="16px">
<DynamicSection gap="md" disabled={disabled}>
<TYPE.label>{t('selectPool')}</TYPE.label>
<RowBetween>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.LOW}
onClick={() => handleFeePoolSelect(FeeAmount.LOW)}
>
<AutoColumn gap="sm" justify="flex-start">
<TYPE.label>0.05% {t('fee')}</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
Optimized for stable assets.
</TYPE.main>
</AutoColumn>
</ButtonRadioChecked>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.MEDIUM}
onClick={() => handleFeePoolSelect(FeeAmount.MEDIUM)}
>
<AutoColumn gap="sm" justify="flex-start">
<TYPE.label>0.3% {t('fee')}</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
The classic Uniswap pool fee.
</TYPE.main>
</AutoColumn>
</ButtonRadioChecked>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.HIGH}
onClick={() => handleFeePoolSelect(FeeAmount.HIGH)}
>
<AutoColumn gap="sm" justify="flex-start">
<TYPE.label>1% {t('fee')}</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
Best for volatile assets.
</TYPE.main>
</AutoColumn>
</ButtonRadioChecked>
</RowBetween>
</DynamicSection>
</AutoColumn>
)
}
...@@ -5,6 +5,9 @@ import { Input as NumericalInput } from '../NumericalInput' ...@@ -5,6 +5,9 @@ import { Input as NumericalInput } from '../NumericalInput'
import styled, { keyframes, css } from 'styled-components' import styled, { keyframes, css } from 'styled-components'
import { TYPE } from 'theme' import { TYPE } from 'theme'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import { ButtonSecondary } from 'components/Button'
import { FeeAmount } from '@uniswap/v3-sdk'
import { formattedFeeAmount } from 'utils'
const pulse = (color: string) => keyframes` const pulse = (color: string) => keyframes`
0% { 0% {
...@@ -20,6 +23,13 @@ const pulse = (color: string) => keyframes` ...@@ -20,6 +23,13 @@ const pulse = (color: string) => keyframes`
} }
` `
const SmallButton = styled(ButtonSecondary)`
background-color: ${({ theme }) => theme.bg2};
border-radius: 8px;
padding: 4px;
width: 48%;
`
const FocusedOutlineCard = styled(OutlineCard)<{ active?: boolean; pulsing?: boolean }>` const FocusedOutlineCard = styled(OutlineCard)<{ active?: boolean; pulsing?: boolean }>`
border-color: ${({ active, theme }) => active && theme.blue1}; border-color: ${({ active, theme }) => active && theme.blue1};
padding: 12px; padding: 12px;
...@@ -44,11 +54,24 @@ const ContentWrapper = styled(RowBetween)` ...@@ -44,11 +54,24 @@ const ContentWrapper = styled(RowBetween)`
interface StepCounterProps { interface StepCounterProps {
value: string value: string
onUserInput: (value: string) => void onUserInput: (value: string) => void
getDecrementValue?: () => string
getIncrementValue?: () => string
feeAmount?: FeeAmount
label?: string label?: string
width?: string width?: string
locked?: boolean // disable input
} }
const StepCounter = ({ value, onUserInput, label, width }: StepCounterProps) => { const StepCounter = ({
value,
onUserInput,
getDecrementValue,
getIncrementValue,
feeAmount,
label,
width,
locked,
}: StepCounterProps) => {
// for focus state, styled components doesnt let you select input parent container // for focus state, styled components doesnt let you select input parent container
const [active, setActive] = useState(false) const [active, setActive] = useState(false)
...@@ -59,11 +82,29 @@ const StepCounter = ({ value, onUserInput, label, width }: StepCounterProps) => ...@@ -59,11 +82,29 @@ const StepCounter = ({ value, onUserInput, label, width }: StepCounterProps) =>
// animation if parent value updates local value // animation if parent value updates local value
const [pulsing, setPulsing] = useState<boolean>(false) const [pulsing, setPulsing] = useState<boolean>(false)
// format fee amount
const feeAmountFormatted = feeAmount ? formattedFeeAmount(feeAmount) : ''
const handleOnFocus = () => { const handleOnFocus = () => {
setUseLocalValue(true) setUseLocalValue(true)
setActive(true) setActive(true)
} }
// for button clicks
const handleDecrement = useCallback(() => {
if (getDecrementValue) {
setLocalValue(getDecrementValue())
onUserInput(getDecrementValue())
}
}, [getDecrementValue, onUserInput])
const handleIncrement = useCallback(() => {
if (getIncrementValue) {
setLocalValue(getIncrementValue())
onUserInput(getIncrementValue())
}
}, [getIncrementValue, onUserInput])
const handleOnBlur = useCallback(() => { const handleOnBlur = useCallback(() => {
setUseLocalValue(false) setUseLocalValue(false)
setActive(false) setActive(false)
...@@ -90,12 +131,23 @@ const StepCounter = ({ value, onUserInput, label, width }: StepCounterProps) => ...@@ -90,12 +131,23 @@ const StepCounter = ({ value, onUserInput, label, width }: StepCounterProps) =>
className="rate-input-0" className="rate-input-0"
value={localValue} value={localValue}
fontSize="18px" fontSize="18px"
disabled={locked}
onUserInput={(val) => { onUserInput={(val) => {
setLocalValue(val) setLocalValue(val)
}} }}
/> />
</ContentWrapper> </ContentWrapper>
{label && <TYPE.label fontSize="12px">{label}</TYPE.label>} {label && <TYPE.label fontSize="12px">{label}</TYPE.label>}
{getDecrementValue && getIncrementValue && !locked ? (
<RowBetween>
<SmallButton onClick={handleDecrement}>
<TYPE.main fontSize="12px">-{feeAmountFormatted}%</TYPE.main>
</SmallButton>
<SmallButton onClick={handleIncrement}>
<TYPE.main fontSize="12px">+{feeAmountFormatted}%</TYPE.main>
</SmallButton>
</RowBetween>
) : null}
</AutoColumn> </AutoColumn>
</FocusedOutlineCard> </FocusedOutlineCard>
) )
......
import React, { useRef } from 'react' import React, { useRef } from 'react'
import { BookOpen, Code, Info, MessageCircle, PieChart } from 'react-feather' import { BookOpen, Code, Info, MessageCircle, PieChart } from 'react-feather'
import { Link } from 'react-router-dom'
import styled, { css } from 'styled-components' import styled, { css } from 'styled-components'
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg' import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
...@@ -96,6 +97,20 @@ const MenuItem = styled(ExternalLink)` ...@@ -96,6 +97,20 @@ const MenuItem = styled(ExternalLink)`
} }
` `
const InternalMenuItem = styled(Link)`
flex: 1;
padding: 0.5rem 0.5rem;
color: ${({ theme }) => theme.text2};
:hover {
color: ${({ theme }) => theme.text1};
cursor: pointer;
text-decoration: none;
}
> svg {
margin-right: 8px;
}
`
const CODE_LINK = 'https://github.com/Uniswap/uniswap-interface' const CODE_LINK = 'https://github.com/Uniswap/uniswap-interface'
export default function Menu() { export default function Menu() {
...@@ -153,14 +168,21 @@ interface NewMenuProps { ...@@ -153,14 +168,21 @@ interface NewMenuProps {
menuItems: { menuItems: {
content: any content: any
link: string link: string
external: boolean
}[] }[]
} }
const NewMenuFlyout = styled(MenuFlyout)` const NewMenuFlyout = styled(MenuFlyout)`
top: 3rem !important; top: 3rem !important;
` `
const NewMenuItem = styled(MenuItem)` const NewMenuItem = styled(InternalMenuItem)`
width: max-content; width: max-content;
text-decoration: none;
`
const ExternalMenuItem = styled(MenuItem)`
width: max-content;
text-decoration: none;
` `
export const NewMenu = ({ flyoutAlignment = FlyoutAlignment.RIGHT, ToggleUI, menuItems, ...rest }: NewMenuProps) => { export const NewMenu = ({ flyoutAlignment = FlyoutAlignment.RIGHT, ToggleUI, menuItems, ...rest }: NewMenuProps) => {
...@@ -174,11 +196,17 @@ export const NewMenu = ({ flyoutAlignment = FlyoutAlignment.RIGHT, ToggleUI, men ...@@ -174,11 +196,17 @@ export const NewMenu = ({ flyoutAlignment = FlyoutAlignment.RIGHT, ToggleUI, men
<ToggleElement onClick={toggle} /> <ToggleElement onClick={toggle} />
{open && ( {open && (
<NewMenuFlyout flyoutAlignment={flyoutAlignment}> <NewMenuFlyout flyoutAlignment={flyoutAlignment}>
{menuItems.map(({ content, link }, i) => ( {menuItems.map(({ content, link, external }, i) =>
<NewMenuItem href={link} key={i}> external ? (
{content} <ExternalMenuItem id="link" href={link} key={link + i}>
</NewMenuItem> {content}
))} </ExternalMenuItem>
) : (
<NewMenuItem id="link" to={link} key={link + i}>
{content}
</NewMenuItem>
)
)}
</NewMenuFlyout> </NewMenuFlyout>
)} )}
</StyledMenu> </StyledMenu>
......
import { BigNumber } from '@ethersproject/bignumber'
import PositionListItem from 'components/PositionListItem' import PositionListItem from 'components/PositionListItem'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
...@@ -37,7 +36,7 @@ const MobileHeader = styled.div` ...@@ -37,7 +36,7 @@ const MobileHeader = styled.div`
` `
export type PositionListProps = React.PropsWithChildren<{ export type PositionListProps = React.PropsWithChildren<{
positions: (PositionDetails & { tokenId: BigNumber })[] positions: PositionDetails[]
}> }>
export default function PositionList({ positions }: PositionListProps) { export default function PositionList({ positions }: PositionListProps) {
...@@ -54,7 +53,7 @@ export default function PositionList({ positions }: PositionListProps) { ...@@ -54,7 +53,7 @@ export default function PositionList({ positions }: PositionListProps) {
<MobileHeader>Your positions</MobileHeader> <MobileHeader>Your positions</MobileHeader>
{positions.map((p, i) => { {positions.map((p, i) => {
const key = `${i}-${p.nonce.toString()} ${p.token0} ${p.token1} ${p.tokensOwed0} ${p.tokensOwed1}` const key = `${i}-${p.nonce.toString()} ${p.token0} ${p.token1} ${p.tokensOwed0} ${p.tokensOwed1}`
return <PositionListItem key={key} positionDetails={p} positionIndex={i} /> return <PositionListItem key={key} positionDetails={p} />
})} })}
</> </>
) )
......
...@@ -16,7 +16,6 @@ import { formatPrice, formatTokenAmount } from 'utils/formatTokenAmount' ...@@ -16,7 +16,6 @@ import { formatPrice, formatTokenAmount } from 'utils/formatTokenAmount'
import Loader from 'components/Loader' import Loader from 'components/Loader'
import { unwrappedToken } from 'utils/wrappedCurrency' import { unwrappedToken } from 'utils/wrappedCurrency'
import { useV3PositionFees } from 'hooks/useV3PositionFees' import { useV3PositionFees } from 'hooks/useV3PositionFees'
import { BigNumber } from '@ethersproject/bignumber'
const ActiveDot = styled.span` const ActiveDot = styled.span`
background-color: ${({ theme }) => theme.success}; background-color: ${({ theme }) => theme.success};
...@@ -121,11 +120,10 @@ const DataText = styled.div` ...@@ -121,11 +120,10 @@ const DataText = styled.div`
` `
export interface PositionListItemProps { export interface PositionListItemProps {
positionDetails: PositionDetails & { tokenId: BigNumber } positionDetails: PositionDetails
positionIndex: number
} }
export default function PositionListItem({ positionDetails, positionIndex }: PositionListItemProps) { export default function PositionListItem({ positionDetails }: PositionListItemProps) {
const { t } = useTranslation() const { t } = useTranslation()
const { const {
...@@ -172,7 +170,7 @@ export default function PositionListItem({ positionDetails, positionIndex }: Pos ...@@ -172,7 +170,7 @@ export default function PositionListItem({ positionDetails, positionIndex }: Pos
// check if price is within range // check if price is within range
const outOfRange: boolean = pool ? pool.tickCurrent < tickLower || pool.tickCurrent > tickUpper : false const outOfRange: boolean = pool ? pool.tickCurrent < tickLower || pool.tickCurrent > tickUpper : false
const positionSummaryLink = '/pool/' + positionIndex.toString() const positionSummaryLink = '/pool/' + positionDetails.tokenId
return ( return (
<Row to={positionSummaryLink}> <Row to={positionSummaryLink}>
......
import React, { useState, useCallback, useMemo } from 'react'
import { Position } from '@uniswap/v3-sdk'
import { DarkCard, DarkGreyCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
import { TYPE } from 'theme'
import { RowBetween, RowFixed } from 'components/Row'
import CurrencyLogo from 'components/CurrencyLogo'
import { unwrappedToken } from 'utils/wrappedCurrency'
import { Break } from 'components/earn/styled'
import { useTranslation } from 'react-i18next'
import RateToggle from 'components/RateToggle'
export const PositionPreview = ({ position, title }: { position: Position; title?: string }) => {
const { t } = useTranslation()
const currency0 = unwrappedToken(position.pool.token0)
const currency1 = unwrappedToken(position.pool.token1)
// track which currency should be base
const [baseCurrency, setBaseCurrency] = useState(currency0)
const sorted = baseCurrency === currency0
const quoteCurrency = sorted ? currency1 : currency0
const quotePrice = useMemo(() => {
return sorted ? position.pool.priceOf(position.pool.token1) : position.pool.priceOf(position.pool.token0)
}, [sorted, position.pool])
const priceLower = sorted ? position.token0PriceUpper.invert() : position.token0PriceLower
const priceUpper = sorted ? position.token0PriceLower.invert() : position.token0PriceUpper
const handleRateChange = useCallback(() => {
setBaseCurrency(quoteCurrency)
}, [quoteCurrency])
return (
<DarkGreyCard>
<AutoColumn gap="md">
<RowBetween>
{title ? <TYPE.main>{title}</TYPE.main> : <div />}
<RateToggle
currencyA={sorted ? currency1 : currency0}
currencyB={sorted ? currency0 : currency1}
handleRateToggle={handleRateChange}
/>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currency0} />
<TYPE.label ml="8px">{currency0?.symbol}</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{position.amount0.toSignificant(4)}</TYPE.label>
</RowFixed>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currency1} />
<TYPE.label ml="8px">{currency1?.symbol}</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{position.amount1.toSignificant(4)}</TYPE.label>
</RowFixed>
</RowBetween>
<Break />
<RowBetween>
<TYPE.label>{t('feeTier')}</TYPE.label>
<TYPE.label>{position?.pool?.fee / 10000}%</TYPE.label>
</RowBetween>
<RowBetween>
<TYPE.label>Current Price</TYPE.label>
<TYPE.label>{`1 ${quoteCurrency?.symbol} = ${quotePrice.toSignificant(6)} ${
baseCurrency?.symbol
}`}</TYPE.label>
</RowBetween>
<RowBetween>
<DarkCard width="46%" padding="8px">
<AutoColumn gap="4px" justify="center">
<TYPE.main fontSize="12px">Min price</TYPE.main>
<TYPE.label textAlign="center">{`${priceLower.toSignificant(4)}`}</TYPE.label>
<TYPE.main
textAlign="center"
fontSize="12px"
>{` ${quoteCurrency.symbol}/${baseCurrency.symbol}`}</TYPE.main>
</AutoColumn>
</DarkCard>
<TYPE.main ml="4px" mr="4px">
</TYPE.main>
<DarkCard width="46%" padding="8px">
<AutoColumn gap="4px" justify="center">
<TYPE.main fontSize="12px">Max price</TYPE.main>
<TYPE.label textAlign="center">{`${priceUpper.toSignificant(4)}`}</TYPE.label>
<TYPE.main
textAlign="center"
fontSize="12px"
>{` ${quoteCurrency.symbol}/${baseCurrency.symbol}`}</TYPE.main>
</AutoColumn>
</DarkCard>
</RowBetween>
</AutoColumn>
</DarkGreyCard>
)
}
import { Currency, Price } from '@uniswap/sdk-core'
import StepCounter from 'components/InputStepCounter/InputStepCounter'
import { RowBetween } from 'components/Row'
import React from 'react'
// currencyA is the base token
export default function RangeSelector({
priceLower,
priceUpper,
onUpperRangeInput,
onLowerRangeInput,
getLowerDecrement,
getLowerIncrement,
getUpperDecrement,
getUpperIncrement,
currencyA,
currencyB,
feeAmount,
fixedValueLower,
fixedValueUpper,
}: {
priceLower?: Price
priceUpper?: Price
getLowerIncrement?: () => string
getLowerDecrement?: () => string
getUpperIncrement?: () => string
getUpperDecrement?: () => string
onLowerRangeInput: (typedValue: string) => void
onUpperRangeInput: (typedValue: string) => void
currencyA?: Currency | null
currencyB?: Currency | null
feeAmount?: number
fixedValueLower?: string
fixedValueUpper?: string
}) {
return (
<RowBetween>
<StepCounter
value={fixedValueLower ?? priceLower?.toSignificant(5) ?? ''}
onUserInput={onLowerRangeInput}
width="48%"
getIncrementValue={getLowerIncrement}
getDecrementValue={getLowerDecrement}
feeAmount={feeAmount}
label={
priceLower && currencyA && currencyB
? `${priceLower.toSignificant(4)} ${currencyB.symbol} / 1 ${currencyA.symbol}`
: '-'
}
locked={!!fixedValueLower}
/>
<StepCounter
value={fixedValueUpper ?? priceUpper?.toSignificant(5) ?? ''}
onUserInput={onUpperRangeInput}
width="48%"
getDecrementValue={getUpperDecrement}
getIncrementValue={getUpperIncrement}
feeAmount={feeAmount}
label={
priceUpper && currencyA && currencyB
? `${priceUpper.toSignificant(4)} ${currencyB?.symbol} / 1 ${currencyA?.symbol}`
: '-'
}
locked={!!fixedValueUpper}
/>
</RowBetween>
)
}
import React from 'react'
import { Currency } from '@uniswap/sdk-core'
import { ToggleElement, ToggleWrapper } from 'components/Toggle/MultiToggle'
import { useActiveWeb3React } from 'hooks'
import { useTranslation } from 'react-i18next'
import { wrappedCurrency } from 'utils/wrappedCurrency'
// the order of displayed base currencies from left to right is always in sort order
// currencyA is treated as the preferred base currency
export default function RateToggle({
currencyA,
currencyB,
handleRateToggle,
}: {
currencyA: Currency
currencyB: Currency
handleRateToggle: () => void
}) {
const { t } = useTranslation()
const { chainId } = useActiveWeb3React()
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
const isSorted = tokenA && tokenB && tokenA.sortsBefore(tokenB)
return tokenA && tokenB ? (
<ToggleWrapper width="fit-content">
<ToggleElement isActive={isSorted} fontSize="12px" onClick={handleRateToggle}>
{isSorted ? currencyA.symbol : currencyB.symbol} {t('rate')}
</ToggleElement>
<ToggleElement isActive={!isSorted} fontSize="12px" onClick={handleRateToggle}>
{isSorted ? currencyB.symbol : currencyA.symbol} {t('rate')}
</ToggleElement>
</ToggleWrapper>
) : null
}
import { Tick } from '@uniswap/v3-sdk' import { computePoolAddress, Tick } from '@uniswap/v3-sdk'
import { ZERO_ADDRESS } from './../constants/index' import { ZERO_ADDRESS } from './../constants/index'
import { Currency } from '@uniswap/sdk-core' import { Currency } from '@uniswap/sdk-core'
import { useMemo } from 'react' import { useMemo } from 'react'
import { useActiveWeb3React } from '../hooks' import { useActiveWeb3React } from '../hooks'
import { useSingleCallResult } from '../state/multicall/hooks' import { useSingleCallResult } from '../state/multicall/hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency' import { wrappedCurrency } from '../utils/wrappedCurrency'
import { Pool, FeeAmount, computePoolAddress } from '@uniswap/v3-sdk' import { Pool, FeeAmount } from '@uniswap/v3-sdk'
import { useV3Factory, useV3Pool } from 'hooks/useContract' import { useV3Factory, useV3Pool } from 'hooks/useContract'
import { V3_CORE_FACTORY_ADDRESSES } from 'constants/v3' import { V3_CORE_FACTORY_ADDRESSES } from 'constants/v3'
import { useAllV3Ticks } from 'hooks/useAllV3Ticks' import { useAllV3Ticks } from 'hooks/useAllV3Ticks'
...@@ -52,11 +52,13 @@ export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?: ...@@ -52,11 +52,13 @@ export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?:
} }
}, [chainId, feeAmount, tokenA, tokenB]) }, [chainId, feeAmount, tokenA, tokenB])
const poolContract = useV3Pool(poolAddress)
// check factory if pools exists // check factory if pools exists
const addressParams = token0 && token1 && feeAmount ? [token0.address, token1.address, feeAmount] : undefined const addressParams = token0 && token1 && feeAmount ? [token0.address, token1.address, feeAmount] : undefined
const addressFromFactory = useSingleCallResult(addressParams ? factoryContract : undefined, 'getPool', addressParams) const addressFromFactory = useSingleCallResult(addressParams ? factoryContract : undefined, 'getPool', addressParams)
const { result: addressesResult, loading: addressesLoading } = addressFromFactory
const poolAddressFromFactory = addressesResult?.[0]
const poolContract = useV3Pool(poolAddress)
// attempt to fetch pool metadata // attempt to fetch pool metadata
const slot0Datas = useSingleCallResult(poolContract, 'slot0') const slot0Datas = useSingleCallResult(poolContract, 'slot0')
...@@ -66,10 +68,8 @@ export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?: ...@@ -66,10 +68,8 @@ export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?:
const { result: slot0, loading: slot0Loading } = slot0Datas const { result: slot0, loading: slot0Loading } = slot0Datas
const { result: liquidityResult, loading: liquidityLoading } = liquidityDatas const { result: liquidityResult, loading: liquidityLoading } = liquidityDatas
const { result: addressesResult, loading: addressesLoading } = addressFromFactory
const liquidity = liquidityResult?.[0] const liquidity = liquidityResult?.[0]
const poolAddressFromFactory = addressesResult?.[0]
// fetch tick data for pool // fetch tick data for pool
const { tickData, loading: tickLoading, syncing: tickSyncing } = useAllV3Ticks(token0, token1, feeAmount) const { tickData, loading: tickLoading, syncing: tickSyncing } = useAllV3Ticks(token0, token1, feeAmount)
......
import { Pool, Position } from '@uniswap/v3-sdk'
import { usePool } from 'data/Pools'
import { PositionDetails } from 'types/position'
import { useCurrency } from './Tokens'
export const useDerivedPositionInfo = (
positionDetails: PositionDetails | undefined
): {
position: Position | undefined
pool: Pool | undefined
} => {
const currency0 = useCurrency(positionDetails?.token0)
const currency1 = useCurrency(positionDetails?.token1)
// construct pool data
const [, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, positionDetails?.fee)
let position = undefined
if (pool && positionDetails) {
position = new Position({
pool,
liquidity: positionDetails.liquidity,
tickLower: positionDetails.tickLower,
tickUpper: positionDetails.tickUpper,
})
}
return {
position,
pool: pool ?? undefined,
}
}
...@@ -47,7 +47,7 @@ function getCounterfactualFees( ...@@ -47,7 +47,7 @@ function getCounterfactualFees(
// 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,
positionDetails?: PositionDetails & { tokenId: BigNumber } positionDetails?: PositionDetails
): [TokenAmount, TokenAmount] | [undefined, undefined] { ): [TokenAmount, TokenAmount] | [undefined, undefined] {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
......
...@@ -7,22 +7,24 @@ import { BigNumber } from '@ethersproject/bignumber' ...@@ -7,22 +7,24 @@ import { BigNumber } from '@ethersproject/bignumber'
interface UseV3PositionsResults { interface UseV3PositionsResults {
loading: boolean loading: boolean
error: boolean error: boolean
positions: (PositionDetails & { tokenId: BigNumber })[] | undefined positions: PositionDetails[] | undefined
} }
function useV3PositionsFromTokenIds(tokenIds: BigNumber[]): UseV3PositionsResults { function useV3PositionsFromTokenIds(tokenIds: BigNumber[] | undefined): UseV3PositionsResults {
const positionManager = useV3NFTPositionManagerContract() const positionManager = useV3NFTPositionManagerContract()
const inputs = useMemo(() => tokenIds.map((tokenId) => [tokenId]), [tokenIds]) const inputs = useMemo(() => (tokenIds ? tokenIds.map((tokenId) => [BigNumber.from(tokenId)]) : []), [tokenIds])
const results = useSingleContractMultipleData(positionManager ?? undefined, 'positions', inputs) const results = useSingleContractMultipleData(positionManager ?? undefined, 'positions', inputs)
const loading = useMemo(() => results.some(({ loading }) => loading), [results]) const loading = useMemo(() => results.some(({ loading }) => loading), [results])
const error = useMemo(() => results.some(({ error }) => error), [results]) const error = useMemo(() => results.some(({ error }) => error), [results])
const positions = useMemo(() => { const positions = useMemo(() => {
if (!loading && !error) { if (!loading && !error && tokenIds) {
return results.map((call) => { return results.map((call, i) => {
const tokenId = tokenIds[i]
const result = call.result as Result const result = call.result as Result
return { return {
tokenId,
fee: result.fee, fee: result.fee,
feeGrowthInside0LastX128: result.feeGrowthInside0LastX128, feeGrowthInside0LastX128: result.feeGrowthInside0LastX128,
feeGrowthInside1LastX128: result.feeGrowthInside1LastX128, feeGrowthInside1LastX128: result.feeGrowthInside1LastX128,
...@@ -39,7 +41,7 @@ function useV3PositionsFromTokenIds(tokenIds: BigNumber[]): UseV3PositionsResult ...@@ -39,7 +41,7 @@ function useV3PositionsFromTokenIds(tokenIds: BigNumber[]): UseV3PositionsResult
}) })
} }
return undefined return undefined
}, [loading, error, results]) }, [loading, error, results, tokenIds])
return { return {
loading, loading,
...@@ -51,11 +53,11 @@ function useV3PositionsFromTokenIds(tokenIds: BigNumber[]): UseV3PositionsResult ...@@ -51,11 +53,11 @@ function useV3PositionsFromTokenIds(tokenIds: BigNumber[]): UseV3PositionsResult
interface UseV3PositionResults { interface UseV3PositionResults {
loading: boolean loading: boolean
error: boolean error: boolean
position: (PositionDetails & { tokenId: BigNumber }) | undefined position: PositionDetails | undefined
} }
export function useV3PositionFromTokenId(tokenId: BigNumber): UseV3PositionResults { export function useV3PositionFromTokenId(tokenId: BigNumber | undefined): UseV3PositionResults {
const position = useV3PositionsFromTokenIds([tokenId]) const position = useV3PositionsFromTokenIds(tokenId ? [tokenId] : undefined)
return { return {
loading: position.loading, loading: position.loading,
error: position.error, error: position.error,
...@@ -75,7 +77,7 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio ...@@ -75,7 +77,7 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio
// we don't expect any account balance to ever exceed the bounds of max safe int // we don't expect any account balance to ever exceed the bounds of max safe int
const accountBalance: number | undefined = balanceResult?.[0] ? Number.parseInt(balanceResult[0]) : undefined const accountBalance: number | undefined = balanceResult?.[0] ? Number.parseInt(balanceResult[0]) : undefined
const positionIndicesArgs = useMemo(() => { const tokenIdsArgs = useMemo(() => {
if (accountBalance && account) { if (accountBalance && account) {
const tokenRequests = [] const tokenRequests = []
for (let i = 0; i < accountBalance; i++) { for (let i = 0; i < accountBalance; i++) {
...@@ -86,33 +88,27 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio ...@@ -86,33 +88,27 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio
return [] return []
}, [account, accountBalance]) }, [account, accountBalance])
const positionIndicesResults = useSingleContractMultipleData( const tokenIdResults = useSingleContractMultipleData(
positionManager ?? undefined, positionManager ?? undefined,
'tokenOfOwnerByIndex', 'tokenOfOwnerByIndex',
positionIndicesArgs tokenIdsArgs
) )
const positionIndicesLoading = useMemo(() => positionIndicesResults.some(({ loading }) => loading), [
positionIndicesResults,
])
const positionIndicesError = useMemo(() => positionIndicesResults.some(({ error }) => error), [
positionIndicesResults,
])
const tokenIds = useMemo(() => { const tokenIds = useMemo(() => {
if (account) { if (account) {
return positionIndicesResults return tokenIdResults
.map(({ result }) => result) .map(({ result }) => result)
.filter((result): result is Result => !!result) .filter((result): result is Result => !!result)
.map((result) => BigNumber.from(result[0])) .map((result) => BigNumber.from(result[0]))
} }
return [] return []
}, [account, positionIndicesResults]) }, [account, tokenIdResults])
const positionsResults = useV3PositionsFromTokenIds(tokenIds) const positionsResults = useV3PositionsFromTokenIds(tokenIds)
// wrap the return value // wrap the return value
const loading = balanceLoading || positionIndicesLoading const loading = balanceLoading || positionsResults.loading
const error = balanceError || positionIndicesError const error = balanceError || positionsResults.error
return { return {
loading: loading || positionsResults.loading, loading: loading || positionsResults.loading,
......
import React, { useMemo } from 'react' import React from 'react'
import { RowBetween, RowFixed } from '../../components/Row' import { RowBetween, RowFixed } from '../../components/Row'
import CurrencyLogo from '../../components/CurrencyLogo'
import { Field } from '../../state/mint/actions' import { Field } from '../../state/mint/actions'
import { TYPE } from '../../theme' import { TYPE } from '../../theme'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import Card, { DarkGreyCard } from 'components/Card' import Card from 'components/Card'
import styled from 'styled-components' import styled from 'styled-components'
import { Break } from 'components/earn/styled'
import { useTranslation } from 'react-i18next'
import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Price } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk' import { Position } from '@uniswap/v3-sdk'
import DoubleCurrencyLogo from 'components/DoubleLogo' import DoubleCurrencyLogo from 'components/DoubleLogo'
import { wrappedCurrency } from 'utils/wrappedCurrency' import { PositionPreview } from 'components/PositionPreview'
import { useActiveWeb3React } from 'hooks' import { RangeBadge } from './styled'
// import QuestionHelper from 'components/QuestionHelper'
// import { WarningBadge } from 'components/Badge/Badge.stories'
// import { AlertCircle } from 'react-feather'
// import useTheme from 'hooks/useTheme'
const Wrapper = styled.div` const Wrapper = styled.div`
padding: 20px; padding: 20px;
min-width: 460px; min-width: 460px;
` `
const Badge = styled(Card)<{ inRange?: boolean }>` export const Badge = styled(Card)<{ inRange?: boolean }>`
width: fit-content; width: fit-content;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
...@@ -35,32 +28,19 @@ const Badge = styled(Card)<{ inRange?: boolean }>` ...@@ -35,32 +28,19 @@ const Badge = styled(Card)<{ inRange?: boolean }>`
export function Review({ export function Review({
position, position,
currencies, currencies,
parsedAmounts,
priceLower,
priceUpper,
outOfRange, outOfRange,
}: { }: {
position?: Position position?: Position
existingPosition?: Position
currencies: { [field in Field]?: Currency } currencies: { [field in Field]?: Currency }
parsedAmounts: { [field in Field]?: CurrencyAmount } parsedAmounts: { [field in Field]?: CurrencyAmount }
priceLower?: Price priceLower?: Price
priceUpper?: Price priceUpper?: Price
outOfRange: boolean outOfRange: boolean
}) { }) {
const { t } = useTranslation()
const { chainId } = useActiveWeb3React()
// const theme = useTheme()
const currencyA: Currency | undefined = currencies[Field.CURRENCY_A] const currencyA: Currency | undefined = currencies[Field.CURRENCY_A]
const currencyB: Currency | undefined = currencies[Field.CURRENCY_B] const currencyB: Currency | undefined = currencies[Field.CURRENCY_B]
// formatted with tokens
const [tokenA, tokenB] = useMemo(() => [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)], [
chainId,
currencyA,
currencyB,
])
return ( return (
<Wrapper> <Wrapper>
<AutoColumn gap="lg"> <AutoColumn gap="lg">
...@@ -71,56 +51,9 @@ export function Review({ ...@@ -71,56 +51,9 @@ export function Review({
{currencyA?.symbol} / {currencyB?.symbol} {currencyA?.symbol} / {currencyB?.symbol}
</TYPE.label> </TYPE.label>
</RowFixed> </RowFixed>
<Badge inRange={!outOfRange}>{outOfRange ? 'Out of range' : 'In Range'}</Badge> <RangeBadge inRange={!outOfRange}>{outOfRange ? 'Out of range' : 'In Range'}</RangeBadge>
</RowBetween> </RowBetween>
{position && tokenA && tokenB && ( {position ? <PositionPreview position={position} title={'Tokens To Add'} /> : null}
<DarkGreyCard>
<AutoColumn gap="md">
<TYPE.label>Deposit Amounts</TYPE.label>
{parsedAmounts[Field.CURRENCY_A] && (
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyA} />
<TYPE.label ml="8px">{currencyA?.symbol}</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{parsedAmounts[Field.CURRENCY_A]?.toSignificant(6)}</TYPE.label>
</RowFixed>
</RowBetween>
)}
{parsedAmounts[Field.CURRENCY_B] && (
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyB} />
<TYPE.label ml="8px">{currencyB?.symbol}</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{parsedAmounts[Field.CURRENCY_B]?.toSignificant(6)}</TYPE.label>
</RowFixed>
</RowBetween>
)}
<Break />
<RowBetween>
<TYPE.label>{t('feePool')}</TYPE.label>
<TYPE.label>{position?.pool?.fee / 10000}%</TYPE.label>
</RowBetween>
<RowBetween>
<TYPE.label>Current Price</TYPE.label>
<TYPE.label>{`1 ${currencyA?.symbol} = ${position?.pool
?.priceOf(position.pool?.token0.equals(tokenA) ? position.pool?.token0 : position.pool?.token1)
.toSignificant(6)} ${position.pool.token1?.symbol}`}</TYPE.label>
</RowBetween>
<RowBetween>
<TYPE.label>Active Range</TYPE.label>
<TYPE.label>{`1 ${
position.pool?.token0.equals(tokenA) ? currencyA?.symbol : currencyB?.symbol
} = ${priceLower?.toSignificant(4)} ⟷ ${priceUpper?.toSignificant(6)} ${
position.pool?.token0.equals(tokenA) ? currencyB?.symbol : currencyA?.symbol
}`}</TYPE.label>
</RowBetween>
</AutoColumn>
</DarkGreyCard>
)}
{/* <YellowCard> {/* <YellowCard>
<AutoColumn gap="md"> <AutoColumn gap="md">
<RowBetween> <RowBetween>
......
import { TransactionResponse } from '@ethersproject/providers' import { TransactionResponse } from '@ethersproject/providers'
import { Currency, TokenAmount, Percent, ETHER, Price } from '@uniswap/sdk-core' import { Currency, TokenAmount, Percent, ETHER } from '@uniswap/sdk-core'
import React, { useCallback, useContext, useState } from 'react' import React, { useCallback, useContext, useState } from 'react'
import { Link2, AlertTriangle } from 'react-feather' import { Link2, AlertTriangle } from 'react-feather'
import ReactGA from 'react-ga' import ReactGA from 'react-ga'
...@@ -7,12 +7,12 @@ import { useV3NFTPositionManagerContract } from '../../hooks/useContract' ...@@ -7,12 +7,12 @@ import { useV3NFTPositionManagerContract } from '../../hooks/useContract'
import { RouteComponentProps } from 'react-router-dom' import { RouteComponentProps } from 'react-router-dom'
import { Text } from 'rebass' import { Text } from 'rebass'
import { ThemeContext } from 'styled-components' import { ThemeContext } from 'styled-components'
import { ButtonError, ButtonLight, ButtonPrimary, ButtonRadioChecked, ButtonText } from '../../components/Button' import { ButtonError, ButtonLight, ButtonPrimary, ButtonText } from '../../components/Button'
import { YellowCard, OutlineCard, BlueCard } from '../../components/Card' import { YellowCard, OutlineCard, BlueCard } from '../../components/Card'
import { AutoColumn, ColumnCenter } from '../../components/Column' import { AutoColumn, ColumnCenter } from '../../components/Column'
import { TransactionSubmittedContent, ConfirmationPendingContent } from '../../components/TransactionConfirmationModal' import { TransactionSubmittedContent, ConfirmationPendingContent } from '../../components/TransactionConfirmationModal'
import CurrencyInputPanel from '../../components/CurrencyInputPanel' import CurrencyInputPanel from '../../components/CurrencyInputPanel'
import { AutoRow, RowBetween } from '../../components/Row' import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
import Review from './Review' import Review from './Review'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useCurrency } from '../../hooks/Tokens' import { useCurrency } from '../../hooks/Tokens'
...@@ -27,163 +27,40 @@ import { TYPE } from '../../theme' ...@@ -27,163 +27,40 @@ import { TYPE } from '../../theme'
import { maxAmountSpend } from '../../utils/maxAmountSpend' import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { wrappedCurrency } from '../../utils/wrappedCurrency' import { wrappedCurrency } from '../../utils/wrappedCurrency'
import AppBody from '../AppBody' import AppBody from '../AppBody'
import { Dots, Wrapper } from '../Pool/styleds' import { Dots } from '../Pool/styleds'
import { currencyId } from '../../utils/currencyId' import { currencyId } from '../../utils/currencyId'
import { useIsTransactionUnsupported } from 'hooks/Trades' import { useIsTransactionUnsupported } from 'hooks/Trades'
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
import { ToggleWrapper, ToggleElement } from 'components/Toggle/MultiToggle'
import StepCounter from 'components/InputStepCounter/InputStepCounter'
import { import {
DynamicSection, DynamicSection,
CurrencyDropdown, CurrencyDropdown,
ScrollableContent, ScrollableContent,
StyledInput, StyledInput,
FixedPreview, FixedPreview,
Wrapper,
RangeBadge,
ScrollablePage, ScrollablePage,
} from './styled' } from './styled'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useMintState, useMintActionHandlers, useDerivedMintInfo } from 'state/mint/hooks' import { useMintState, useMintActionHandlers, useDerivedMintInfo } from 'state/mint/hooks'
import { FeeAmount, NonfungiblePositionManager } from '@uniswap/v3-sdk' import { FeeAmount, NonfungiblePositionManager, tickToPrice, TICK_SPACINGS } from '@uniswap/v3-sdk'
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from 'constants/v3' import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from 'constants/v3'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
export function FeeSelector({ import { useDerivedPositionInfo } from 'hooks/useDerivedPositionInfo'
disabled = false, import { PositionPreview } from 'components/PositionPreview'
feeAmount, import DoubleCurrencyLogo from 'components/DoubleLogo'
handleFeePoolSelect, import FeeSelector from 'components/FeeSelector'
}: { import RangeSelector from 'components/RangeSelector'
disabled?: boolean import RateToggle from 'components/RateToggle'
feeAmount?: FeeAmount import { BigNumber } from '@ethersproject/bignumber'
handleFeePoolSelect: (feeAmount: FeeAmount) => void
}) {
const { t } = useTranslation()
return (
<AutoColumn gap="16px">
<DynamicSection gap="md" disabled={disabled}>
<TYPE.label>{t('selectPool')}</TYPE.label>
<RowBetween>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.LOW}
onClick={() => handleFeePoolSelect(FeeAmount.LOW)}
>
<AutoColumn gap="sm" justify="flex-start">
<TYPE.label>0.05% {t('fee')}</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
Optimized for stable assets.
</TYPE.main>
</AutoColumn>
</ButtonRadioChecked>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.MEDIUM}
onClick={() => handleFeePoolSelect(FeeAmount.MEDIUM)}
>
<AutoColumn gap="sm" justify="flex-start">
<TYPE.label>0.3% {t('fee')}</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
The classic Uniswap pool fee.
</TYPE.main>
</AutoColumn>
</ButtonRadioChecked>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.HIGH}
onClick={() => handleFeePoolSelect(FeeAmount.HIGH)}
>
<AutoColumn gap="sm" justify="flex-start">
<TYPE.label>1% {t('fee')}</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
Best for volatile assets.
</TYPE.main>
</AutoColumn>
</ButtonRadioChecked>
</RowBetween>
</DynamicSection>
</AutoColumn>
)
}
// currencyA is the base token
export function RangeSelector({
priceLower,
priceUpper,
onLowerRangeInput,
onUpperRangeInput,
currencyA,
currencyB,
}: {
priceLower?: Price
priceUpper?: Price
onLowerRangeInput: (typedValue: string) => void
onUpperRangeInput: (typedValue: string) => void
currencyA?: Currency | null
currencyB?: Currency | null
}) {
return (
<RowBetween>
<StepCounter
value={priceLower?.toSignificant(5) ?? ''}
onUserInput={onLowerRangeInput}
width="48%"
label={
priceLower && currencyA && currencyB
? `${priceLower.toSignificant(4)} ${currencyB.symbol} / 1 ${currencyA.symbol}`
: '-'
}
/>
<StepCounter
value={priceUpper?.toSignificant(5) ?? ''}
onUserInput={onUpperRangeInput}
width="48%"
label={
priceUpper && currencyA && currencyB
? `${priceUpper.toSignificant(4)} ${currencyB?.symbol} / 1 ${currencyA?.symbol}`
: '-'
}
/>
</RowBetween>
)
}
// the order of displayed base currencies from left to right is always in sort order
// currencyA is treated as the preferred base currency
export function RateToggle({
currencyA,
currencyB,
handleRateToggle,
}: {
currencyA: Currency
currencyB: Currency
handleRateToggle: () => void
}) {
const { t } = useTranslation()
const { chainId } = useActiveWeb3React()
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
const isSorted = tokenA && tokenB && tokenA.sortsBefore(tokenB)
return tokenA && tokenB ? (
<ToggleWrapper width="fit-content">
<ToggleElement isActive={isSorted} fontSize="12px" onClick={handleRateToggle}>
{isSorted ? currencyA.symbol : currencyB.symbol} {t('rate')}
</ToggleElement>
<ToggleElement isActive={!isSorted} fontSize="12px" onClick={handleRateToggle}>
{isSorted ? currencyB.symbol : currencyA.symbol} {t('rate')}
</ToggleElement>
</ToggleWrapper>
) : null
}
export default function AddLiquidity({ export default function AddLiquidity({
match: { match: {
params: { currencyIdA, currencyIdB, feeAmount: feeAmountFromUrl }, params: { currencyIdA, currencyIdB, feeAmount: feeAmountFromUrl, tokenId },
}, },
history, history,
}: RouteComponentProps<{ currencyIdA?: string; currencyIdB?: string; feeAmount?: string }>) { }: RouteComponentProps<{ currencyIdA?: string; currencyIdB?: string; feeAmount?: string; tokenId?: string }>) {
const { t } = useTranslation() const { t } = useTranslation()
const { account, chainId, library } = useActiveWeb3React() const { account, chainId, library } = useActiveWeb3React()
...@@ -193,8 +70,31 @@ export default function AddLiquidity({ ...@@ -193,8 +70,31 @@ export default function AddLiquidity({
const addTransaction = useTransactionAdder() const addTransaction = useTransactionAdder()
const positionManager = useV3NFTPositionManagerContract() const positionManager = useV3NFTPositionManagerContract()
// check for existing position if tokenId in url
const { position: existingPositionDetails, loading: positionLoading } = useV3PositionFromTokenId(
tokenId ? BigNumber.from(tokenId) : undefined
)
const hasExistingPosition = !!existingPositionDetails && !positionLoading
const { position: existingPosition } = useDerivedPositionInfo(existingPositionDetails)
const fixedValueLower =
hasExistingPosition && existingPosition
? tickToPrice(
existingPosition.pool.token0,
existingPosition.pool.token1,
existingPosition.tickLower
).toSignificant(4)
: undefined
const fixedValueUpper =
hasExistingPosition && existingPosition
? tickToPrice(
existingPosition.pool.token0,
existingPosition.pool.token1,
existingPosition.tickUpper
).toSignificant(4)
: undefined
// fee selection from url // fee selection from url
const feeAmount = const feeAmount: FeeAmount | undefined =
feeAmountFromUrl && Object.values(FeeAmount).includes(parseFloat(feeAmountFromUrl)) feeAmountFromUrl && Object.values(FeeAmount).includes(parseFloat(feeAmountFromUrl))
? parseFloat(feeAmountFromUrl) ? parseFloat(feeAmountFromUrl)
: undefined : undefined
...@@ -221,7 +121,7 @@ export default function AddLiquidity({ ...@@ -221,7 +121,7 @@ export default function AddLiquidity({
outOfRange, outOfRange,
depositADisabled, depositADisabled,
depositBDisabled, depositBDisabled,
} = useDerivedMintInfo(currencyA ?? undefined, currencyB ?? undefined, feeAmount) } = useDerivedMintInfo(currencyA ?? undefined, currencyB ?? undefined, feeAmount, existingPosition)
const { const {
onFieldAInput, onFieldAInput,
...@@ -288,13 +188,21 @@ export default function AddLiquidity({ ...@@ -288,13 +188,21 @@ export default function AddLiquidity({
} }
if (position && account && deadline && fractionalizedTolerance) { if (position && account && deadline && fractionalizedTolerance) {
const { calldata, value } = NonfungiblePositionManager.mintCallParameters(position, { const { calldata, value } =
slippageTolerance: fractionalizedTolerance, hasExistingPosition && tokenId
recipient: account, ? NonfungiblePositionManager.increaseLiquidityCallParameters(position, {
deadline: deadline.toNumber(), tokenId: tokenId,
useEther: currencyA === ETHER || currencyB === ETHER, slippageTolerance: fractionalizedTolerance,
createPool: noLiquidity, deadline: deadline.toNumber(),
}) useEther: currencyA === ETHER || currencyB === ETHER,
})
: NonfungiblePositionManager.mintCallParameters(position, {
slippageTolerance: fractionalizedTolerance,
recipient: account,
deadline: deadline.toNumber(),
useEther: currencyA === ETHER || currencyB === ETHER,
createPool: noLiquidity,
})
const txn = { const txn = {
to: NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId], to: NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId],
...@@ -423,6 +331,58 @@ export default function AddLiquidity({ ...@@ -423,6 +331,58 @@ export default function AddLiquidity({
const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks
const { [Bound.LOWER]: priceLower, [Bound.UPPER]: priceUpper } = pricesAtTicks const { [Bound.LOWER]: priceLower, [Bound.UPPER]: priceUpper } = pricesAtTicks
const getLowerDecrement = () => {
if (tickLower && feeAmount && currencyA && currencyB && chainId) {
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
const tickAmount = TICK_SPACINGS[feeAmount]
const newTick = tickLower - tickAmount
const newPrice = tokenA && tokenB ? tickToPrice(tokenA, tokenB, newTick) : undefined
return newPrice ? newPrice.toFixed(10) : ''
} else {
return ''
}
}
const getLowerIncrement = () => {
if (tickLower && feeAmount && currencyA && currencyB && chainId) {
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
const tickAmount = TICK_SPACINGS[feeAmount]
const newTick = tickLower + tickAmount
const newPrice = tokenA && tokenB ? tickToPrice(tokenA, tokenB, newTick) : undefined
return newPrice ? newPrice.toFixed(10) : ''
} else {
return ''
}
}
const getUpperDecrement = () => {
if (tickUpper && feeAmount && currencyA && currencyB && chainId) {
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
const tickAmount = TICK_SPACINGS[feeAmount]
const newTick = tickUpper - tickAmount
const newPrice = tokenA && tokenB ? tickToPrice(tokenA, tokenB, newTick) : undefined
return newPrice ? newPrice.toFixed(10) : ''
} else {
return ''
}
}
const getUpperIncrement = () => {
if (tickUpper && feeAmount && currencyA && currencyB && chainId) {
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
const tickAmount = TICK_SPACINGS[feeAmount]
const newTick = tickUpper + tickAmount
const newPrice = tokenA && tokenB ? tickToPrice(tokenA, tokenB, newTick) : undefined
return newPrice ? newPrice.toFixed(10) : ''
} else {
return ''
}
}
const handleRateToggle = useCallback(() => { const handleRateToggle = useCallback(() => {
if (currencyA && currencyB) { if (currencyA && currencyB) {
const currencyIdA = currencyId(currencyA) const currencyIdA = currencyId(currencyA)
...@@ -477,6 +437,7 @@ export default function AddLiquidity({ ...@@ -477,6 +437,7 @@ export default function AddLiquidity({
currencies={currencies} currencies={currencies}
parsedAmounts={parsedAmounts} parsedAmounts={parsedAmounts}
position={position} position={position}
existingPosition={existingPosition}
priceLower={priceLower} priceLower={priceLower}
priceUpper={priceUpper} priceUpper={priceUpper}
outOfRange={outOfRange} outOfRange={outOfRange}
...@@ -485,149 +446,180 @@ export default function AddLiquidity({ ...@@ -485,149 +446,180 @@ export default function AddLiquidity({
) : ( ) : (
<AppBody> <AppBody>
<Wrapper> <Wrapper>
<AutoColumn gap="40px"> <AutoColumn gap="lg">
<AutoColumn gap="md"> {!hasExistingPosition ? (
<RowBetween paddingBottom="20px"> <>
<TYPE.label>Select a pair</TYPE.label> <AutoColumn gap="md">
<ButtonText onClick={clearAll}> <RowBetween paddingBottom="20px">
<TYPE.blue fontSize="12px">Clear All</TYPE.blue> <TYPE.label>Select a pair</TYPE.label>
</ButtonText> <ButtonText onClick={clearAll}>
</RowBetween> <TYPE.blue fontSize="12px">Clear All</TYPE.blue>
{/* <TYPE.main fontWeight={400} fontSize="14px"> </ButtonText>
{t('selectAPool')} </RowBetween>
</TYPE.main> */}
<RowBetween>
<CurrencyDropdown
value={formattedAmounts[Field.CURRENCY_A]}
onUserInput={onFieldAInput}
hideInput={true}
onMax={() => {
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
}}
onCurrencySelect={handleCurrencyASelect}
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
currency={currencies[Field.CURRENCY_A]}
id="add-liquidity-input-tokena"
showCommonBases
/>
<CurrencyDropdown
value={formattedAmounts[Field.CURRENCY_B]}
hideInput={true}
onUserInput={onFieldBInput}
onCurrencySelect={handleCurrencyBSelect}
onMax={() => {
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
}}
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
currency={currencies[Field.CURRENCY_B]}
id="add-liquidity-input-tokenb"
showCommonBases
/>
</RowBetween>
</AutoColumn>{' '}
</>
) : (
<RowBetween> <RowBetween>
<CurrencyDropdown <RowFixed>
value={formattedAmounts[Field.CURRENCY_A]} <DoubleCurrencyLogo
onUserInput={onFieldAInput} currency0={currencyA ?? undefined}
hideInput={true} currency1={currencyB ?? undefined}
onMax={() => { size={24}
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '') margin={true}
}} />
onCurrencySelect={handleCurrencyASelect} <TYPE.label ml="10px" fontSize="24px">
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]} {currencyA?.symbol} / {currencyB?.symbol}
currency={currencies[Field.CURRENCY_A]} </TYPE.label>
id="add-liquidity-input-tokena" </RowFixed>
showCommonBases <RangeBadge inRange={!outOfRange}>{outOfRange ? 'Out of range' : 'In Range'}</RangeBadge>
/> </RowBetween>
)}
<CurrencyDropdown {hasExistingPosition && existingPosition ? (
value={formattedAmounts[Field.CURRENCY_B]} <PositionPreview position={existingPosition} title={'Current Position'} />
hideInput={true} ) : (
onUserInput={onFieldBInput} <>
onCurrencySelect={handleCurrencyBSelect} <FeeSelector
onMax={() => { disabled={!currencyB || !currencyA}
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '') feeAmount={feeAmount}
}} handleFeePoolSelect={handleFeePoolSelect}
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
currency={currencies[Field.CURRENCY_B]}
id="add-liquidity-input-tokenb"
showCommonBases
/> />
</RowBetween>
</AutoColumn>
<FeeSelector {noLiquidity && (
disabled={!currencyB || !currencyA} <DynamicSection disabled={!currencyA || !currencyB}>
feeAmount={feeAmount} <AutoColumn gap="md">
handleFeePoolSelect={handleFeePoolSelect} <BlueCard width="100%" padding="1rem">
/> You are the first to provide liquidity to this pool.
</BlueCard>
<RowBetween>
<TYPE.label>{t('selectStartingPrice')}</TYPE.label>
{currencyA && currencyB ? (
<RateToggle
currencyA={currencyA}
currencyB={currencyB}
handleRateToggle={handleRateToggle}
/>
) : null}
</RowBetween>
<OutlineCard padding="12px">
<StyledInput
className="start-price-input"
value={startPriceTypedValue}
onUserInput={onStartPriceInput}
/>
</OutlineCard>
<RowBetween style={{ backgroundColor: theme.bg6, padding: '12px', borderRadius: '12px' }}>
<TYPE.main>Starting Price</TYPE.main>
{price ? (
<TYPE.main>
1 {currencyA?.symbol} = {price?.toSignificant(8)} {currencyB?.symbol}
</TYPE.main>
) : (
'-'
)}
</RowBetween>
</AutoColumn>
</DynamicSection>
)}
{noLiquidity && ( <DynamicSection
<DynamicSection disabled={!currencyA || !currencyB}> gap="md"
<AutoColumn gap="md"> disabled={!feeAmount || invalidPool || (noLiquidity && !startPriceTypedValue)}
<BlueCard width="100%" padding="1rem"> >
You are the first to provide liquidity to this pool.
</BlueCard>
<RowBetween> <RowBetween>
<TYPE.label>{t('selectStartingPrice')}</TYPE.label> <TYPE.label>{t('selectLiquidityRange')}</TYPE.label>
{currencyA && currencyB ? ( {currencyA && currencyB && !noLiquidity && (
<RateToggle currencyA={currencyA} currencyB={currencyB} handleRateToggle={handleRateToggle} /> <RateToggle currencyA={currencyA} currencyB={currencyB} handleRateToggle={handleRateToggle} />
) : null}
</RowBetween>
{/* <TYPE.main fontWeight={400} fontSize="14px">
{t('newPoolPrice')}
</TYPE.main> */}
<OutlineCard padding="12px">
<StyledInput
className="start-price-input"
value={startPriceTypedValue}
onUserInput={onStartPriceInput}
/>
</OutlineCard>
<RowBetween style={{ backgroundColor: theme.bg6, padding: '12px', borderRadius: '12px' }}>
<TYPE.main>Starting Price</TYPE.main>
{price ? (
<TYPE.main>
1 {currencyA?.symbol} = {price?.toSignificant(8)} {currencyB?.symbol}
</TYPE.main>
) : (
'-'
)} )}
</RowBetween> </RowBetween>
</AutoColumn>
</DynamicSection>
)}
<DynamicSection gap="md" disabled={!feeAmount || invalidPool || (noLiquidity && !startPriceTypedValue)}> {price && currencyA && !noLiquidity && (
<RowBetween> <RowBetween style={{ backgroundColor: theme.bg6, padding: '12px', borderRadius: '12px' }}>
<TYPE.label>{t('selectLiquidityRange')}</TYPE.label> <TYPE.main>{t('currentRate', { label: currencyA.symbol })}</TYPE.main>
{currencyA && currencyB && !noLiquidity && ( <TYPE.main>
<RateToggle currencyA={currencyA} currencyB={currencyB} handleRateToggle={handleRateToggle} /> {price.toSignificant(3)} {currencyB?.symbol}
)} </TYPE.main>
</RowBetween> </RowBetween>
{/* <TYPE.main fontWeight={400} fontSize="14px"> )}
{t('rangeWarning')}
</TYPE.main> */}
{price && currencyA && !noLiquidity && (
<RowBetween style={{ backgroundColor: theme.bg6, padding: '12px', borderRadius: '12px' }}>
<TYPE.main>{t('currentRate', { label: currencyA.symbol })}</TYPE.main>
<TYPE.main>
{price.toSignificant(3)} {currencyB?.symbol}
</TYPE.main>
</RowBetween>
)}
<RangeSelector
priceLower={priceLower}
priceUpper={priceUpper}
onLowerRangeInput={onLowerRangeInput}
onUpperRangeInput={onUpperRangeInput}
currencyA={currencyA}
currencyB={currencyB}
/>
{outOfRange ? (
<YellowCard padding="8px 12px" borderRadius="12px">
<RowBetween>
<AlertTriangle stroke={theme.yellow3} size="16px" />
<TYPE.yellow ml="12px" fontSize="12px">
{t('inactiveRangeWarning')}
</TYPE.yellow>
</RowBetween>
</YellowCard>
) : null}
{invalidRange ? ( <RangeSelector
<YellowCard padding="8px 12px" borderRadius="12px"> priceLower={priceLower}
<RowBetween> priceUpper={priceUpper}
<AlertTriangle stroke={theme.yellow3} size="16px" /> getLowerDecrement={getLowerDecrement}
<TYPE.yellow ml="12px" fontSize="12px"> getLowerIncrement={getLowerIncrement}
{t('invalidRangeWarning')} getUpperDecrement={getUpperDecrement}
</TYPE.yellow> getUpperIncrement={getUpperIncrement}
</RowBetween> onLowerRangeInput={onLowerRangeInput}
</YellowCard> onUpperRangeInput={onUpperRangeInput}
) : null} currencyA={currencyA}
</DynamicSection> currencyB={currencyB}
feeAmount={feeAmount}
fixedValueLower={fixedValueLower}
fixedValueUpper={fixedValueUpper}
/>
{outOfRange ? (
<YellowCard padding="8px 12px" borderRadius="12px">
<RowBetween>
<AlertTriangle stroke={theme.yellow3} size="16px" />
<TYPE.yellow ml="12px" fontSize="12px">
{t('inactiveRangeWarning')}
</TYPE.yellow>
</RowBetween>
</YellowCard>
) : null}
{invalidRange ? (
<YellowCard padding="8px 12px" borderRadius="12px">
<RowBetween>
<AlertTriangle stroke={theme.yellow3} size="16px" />
<TYPE.yellow ml="12px" fontSize="12px">
{t('invalidRangeWarning')}
</TYPE.yellow>
</RowBetween>
</YellowCard>
) : null}
</DynamicSection>
</>
)}
<DynamicSection <DynamicSection
disabled={tickLower === undefined || tickUpper === undefined || invalidPool || invalidRange} disabled={tickLower === undefined || tickUpper === undefined || invalidPool || invalidRange}
> >
<AutoColumn gap="md"> <AutoColumn gap="md">
<TYPE.label>{t('depositAmounts')}</TYPE.label> <TYPE.label>{hasExistingPosition ? 'Add more liquidity' : t('depositAmounts')}</TYPE.label>
{/* <TYPE.main fontWeight={400} fontSize="14px">
{t('chooseLiquidityAmount')}
</TYPE.main> */}
<CurrencyInputPanel <CurrencyInputPanel
value={formattedAmounts[Field.CURRENCY_A]} value={formattedAmounts[Field.CURRENCY_A]}
onUserInput={onFieldAInput} onUserInput={onFieldAInput}
......
import styled from 'styled-components' import styled from 'styled-components'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import CurrencyInputPanel from 'components/CurrencyInputPanel' import CurrencyInputPanel from 'components/CurrencyInputPanel'
import { DarkGreyCard } from 'components/Card' import Card, { DarkGreyCard } from 'components/Card'
import Input from 'components/NumericalInput' import Input from 'components/NumericalInput'
export const Wrapper = styled.div`
position: relative;
padding: 20px;
min-width: 460px;
`
export const ScrollablePage = styled.div` export const ScrollablePage = styled.div`
position: relative; position: relative;
display: flex; display: flex;
...@@ -14,6 +20,15 @@ export const ScrollableContent = styled.div` ...@@ -14,6 +20,15 @@ export const ScrollableContent = styled.div`
margin-right: 16px; margin-right: 16px;
` `
export const RangeBadge = styled(Card)<{ inRange?: boolean }>`
width: fit-content;
font-size: 14px;
font-weight: 500;
border-radius: 8px;
padding: 4px 6px;
background-color: ${({ inRange, theme }) => (inRange ? theme.green1 : theme.yellow2)};
`
export const FixedPreview = styled.div` export const FixedPreview = styled.div`
position: relative; position: relative;
padding: 16px; padding: 16px;
......
...@@ -27,6 +27,7 @@ import Vote from './Vote' ...@@ -27,6 +27,7 @@ import Vote from './Vote'
import VotePage from './Vote/VotePage' import VotePage from './Vote/VotePage'
import { RedirectDuplicateTokenIdsV2 } from './AddLiquidityV2/redirects' import { RedirectDuplicateTokenIdsV2 } from './AddLiquidityV2/redirects'
import { PositionPage } from './Pool/PositionPage' import { PositionPage } from './Pool/PositionPage'
import AddLiquidity from './AddLiquidity'
const AppWrapper = styled.div` const AppWrapper = styled.div`
display: flex; display: flex;
...@@ -101,7 +102,7 @@ export default function App() { ...@@ -101,7 +102,7 @@ export default function App() {
<Route exact strict path="/find" component={PoolFinder} /> <Route exact strict path="/find" component={PoolFinder} />
<Route exact strict path="/pool/v2" component={PoolV2} /> <Route exact strict path="/pool/v2" component={PoolV2} />
<Route exact strict path="/pool" component={Pool} /> <Route exact strict path="/pool" component={Pool} />
<Route exact strict path="/pool/:positionIndex" component={PositionPage} /> <Route exact strict path="/pool/:tokenId" component={PositionPage} />
<Route exact strict path="/add/v2/:currencyIdA?/:currencyIdB?" component={RedirectDuplicateTokenIdsV2} /> <Route exact strict path="/add/v2/:currencyIdA?/:currencyIdB?" component={RedirectDuplicateTokenIdsV2} />
<Route <Route
...@@ -111,6 +112,13 @@ export default function App() { ...@@ -111,6 +112,13 @@ export default function App() {
component={RedirectDuplicateTokenIds} component={RedirectDuplicateTokenIds}
/> />
<Route
exact
strict
path="/increase/:currencyIdA?/:currencyIdB?/:feeAmount?/:tokenId?"
component={AddLiquidity}
/>
<Route exact strict path="/remove/v2/:currencyIdA/:currencyIdB" component={RemoveLiquidity} /> <Route exact strict path="/remove/v2/:currencyIdA/:currencyIdB" component={RemoveLiquidity} />
<Route exact strict path="/remove/:tokenId" component={RemoveLiquidityV3} /> <Route exact strict path="/remove/:tokenId" component={RemoveLiquidityV3} />
......
...@@ -20,7 +20,6 @@ import { BodyWrapper } from '../AppBody' ...@@ -20,7 +20,6 @@ import { BodyWrapper } from '../AppBody'
import { V2_MIGRATOR_ADDRESSES } from 'constants/v3' import { V2_MIGRATOR_ADDRESSES } from 'constants/v3'
import { PoolState, usePool } from 'data/Pools' import { PoolState, usePool } from 'data/Pools'
import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk' import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk'
import { FeeSelector, RangeSelector, RateToggle } from 'pages/AddLiquidity'
import { LightCard, PinkCard, YellowCard } from 'components/Card' import { LightCard, PinkCard, YellowCard } from 'components/Card'
import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback' import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback'
import { Dots } from 'components/swap/styleds' import { Dots } from 'components/swap/styleds'
...@@ -34,6 +33,9 @@ import { useDerivedMintInfo, useMintActionHandlers } from 'state/mint/hooks' ...@@ -34,6 +33,9 @@ import { useDerivedMintInfo, useMintActionHandlers } from 'state/mint/hooks'
import { Bound } from 'state/mint/actions' import { Bound } from 'state/mint/actions'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { ChevronDown } from 'react-feather' import { ChevronDown } from 'react-feather'
import FeeSelector from 'components/FeeSelector'
import RangeSelector from 'components/RangeSelector'
import RateToggle from 'components/RateToggle'
import useIsArgentWallet from 'hooks/useIsArgentWallet' import useIsArgentWallet from 'hooks/useIsArgentWallet'
import { Contract } from '@ethersproject/contracts' import { Contract } from '@ethersproject/contracts'
import { splitSignature } from '@ethersproject/bytes' import { splitSignature } from '@ethersproject/bytes'
......
import React, { useMemo } from 'react' import React, { useMemo } from 'react'
import { Position } from '@uniswap/v3-sdk' import { Position } from '@uniswap/v3-sdk'
import { PoolState, usePool } from 'data/Pools' import { PoolState, usePool } from 'data/Pools'
import { useActiveWeb3React } from 'hooks'
import { useToken } from 'hooks/Tokens' import { useToken } from 'hooks/Tokens'
import { useV3Positions } from 'hooks/useV3Positions' import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
import { RouteComponentProps, Link } from 'react-router-dom' import { Link, RouteComponentProps } from 'react-router-dom'
import { unwrappedToken } from 'utils/wrappedCurrency' import { unwrappedToken } from 'utils/wrappedCurrency'
import { LoadingRows } from './styleds' import { LoadingRows } from './styleds'
import styled from 'styled-components' import styled from 'styled-components'
...@@ -19,8 +18,10 @@ import { DarkCard, DarkGreyCard } from 'components/Card' ...@@ -19,8 +18,10 @@ import { DarkCard, DarkGreyCard } from 'components/Card'
import CurrencyLogo from 'components/CurrencyLogo' import CurrencyLogo from 'components/CurrencyLogo'
import { AlertTriangle } from 'react-feather' import { AlertTriangle } from 'react-feather'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useV3PositionFees } from 'hooks/useV3PositionFees' import { currencyId } from 'utils/currencyId'
import { formatTokenAmount } from 'utils/formatTokenAmount' import { formatTokenAmount } from 'utils/formatTokenAmount'
import { useV3PositionFees } from 'hooks/useV3PositionFees'
import { BigNumber } from '@ethersproject/bignumber'
const PageWrapper = styled.div` const PageWrapper = styled.div`
min-width: 800px; min-width: 800px;
...@@ -75,7 +76,7 @@ const ActiveDot = styled.span` ...@@ -75,7 +76,7 @@ const ActiveDot = styled.span`
margin-right: 4px; margin-right: 4px;
` `
const DarkBadge = styled.div` export const DarkBadge = styled.div`
widthL fit-content; widthL fit-content;
border-radius: 8px; border-radius: 8px;
background-color: ${({ theme }) => theme.bg0}; background-color: ${({ theme }) => theme.bg0};
...@@ -84,15 +85,13 @@ const DarkBadge = styled.div` ...@@ -84,15 +85,13 @@ const DarkBadge = styled.div`
export function PositionPage({ export function PositionPage({
match: { match: {
params: { positionIndex }, params: { tokenId: tokenIdFromUrl },
}, },
}: RouteComponentProps<{ positionIndex?: string }>) { }: RouteComponentProps<{ tokenId?: string }>) {
const { account } = useActiveWeb3React()
const { t } = useTranslation() const { t } = useTranslation()
const { loading, positions } = useV3Positions(account ?? undefined) const parsedTokenId = tokenIdFromUrl ? BigNumber.from(tokenIdFromUrl) : undefined
const { loading, position: positionDetails } = useV3PositionFromTokenId(parsedTokenId)
const positionDetails = positionIndex && positions ? positions[parseInt(positionIndex)] : undefined
const { token0: token0Address, token1: token1Address, fee: feeAmount, liquidity, tickLower, tickUpper, tokenId } = const { token0: token0Address, token1: token1Address, fee: feeAmount, liquidity, tickLower, tickUpper, tokenId } =
positionDetails || {} positionDetails || {}
...@@ -121,6 +120,10 @@ export function PositionPage({ ...@@ -121,6 +120,10 @@ export function PositionPage({
const outOfRange: boolean = const outOfRange: boolean =
pool && tickLower && tickUpper ? pool.tickCurrent < tickLower || pool.tickCurrent > tickUpper : false pool && tickLower && tickUpper ? pool.tickCurrent < tickLower || pool.tickCurrent > tickUpper : false
const linkToIncrease =
currency0 && currency1
? `/increase/${currencyId(currency0)}/${currencyId(currency1)}/${feeAmount}/${tokenId}`
: `/pool`
// fees // fees
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails) const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails)
...@@ -153,11 +156,16 @@ export function PositionPage({ ...@@ -153,11 +156,16 @@ export function PositionPage({
<BadgeText>{basisPointsToPercent(feeAmount / 100).toSignificant()}%</BadgeText> <BadgeText>{basisPointsToPercent(feeAmount / 100).toSignificant()}%</BadgeText>
</Badge> </Badge>
</RowFixed> </RowFixed>
{tokenId && ( <RowFixed>
<ButtonPrimary width="200px" padding="8px" borderRadius="12px" as={Link} to={`/remove/${tokenId}`}> <Link to={linkToIncrease}>
<ButtonPrimary mr="20px" width="200px" padding="8px" borderRadius="12px">
Increase liquidity
</ButtonPrimary>
</Link>
<ButtonPrimary width="200px" padding="8px" borderRadius="12px">
Remove liquidity Remove liquidity
</ButtonPrimary> </ButtonPrimary>
)} </RowFixed>
</RowBetween> </RowBetween>
<RowBetween> <RowBetween>
<BadgeWrapper> <BadgeWrapper>
......
...@@ -105,7 +105,8 @@ export default function Pool() { ...@@ -105,7 +105,8 @@ export default function Pool() {
{t('Create a pool')} {t('Create a pool')}
</MenuItem> </MenuItem>
), ),
link: '/#/add', link: '/add/ETH',
external: false,
}, },
{ {
content: ( content: (
...@@ -115,6 +116,7 @@ export default function Pool() { ...@@ -115,6 +116,7 @@ export default function Pool() {
</MenuItem> </MenuItem>
), ),
link: 'https://uniswap.org/docs/v2/', link: 'https://uniswap.org/docs/v2/',
external: true,
}, },
] ]
if (showMigrateHeaderLink) { if (showMigrateHeaderLink) {
...@@ -125,7 +127,8 @@ export default function Pool() { ...@@ -125,7 +127,8 @@ export default function Pool() {
{t('Migrate v2 liquidity')} {t('Migrate v2 liquidity')}
</MenuItem> </MenuItem>
), ),
link: '/#/migrate/v2', link: '/migrate/v2',
external: false,
}) })
} }
return ( return (
......
...@@ -17,7 +17,7 @@ export function useBurnV3State(): AppState['burnV3'] { ...@@ -17,7 +17,7 @@ export function useBurnV3State(): AppState['burnV3'] {
} }
export function useDerivedV3BurnInfo( export function useDerivedV3BurnInfo(
position?: PositionDetails & { tokenId: BigNumber } position?: PositionDetails
): { ): {
liquidity?: BigNumber liquidity?: BigNumber
liquidityValue0?: TokenAmount liquidityValue0?: TokenAmount
......
...@@ -77,7 +77,9 @@ export function useMintActionHandlers( ...@@ -77,7 +77,9 @@ export function useMintActionHandlers(
export function useDerivedMintInfo( export function useDerivedMintInfo(
currencyA: Currency | undefined, currencyA: Currency | undefined,
currencyB: Currency | undefined, currencyB: Currency | undefined,
feeAmount: FeeAmount | undefined feeAmount: FeeAmount | undefined,
// override for existing position
existingPosition?: Position | undefined
): { ): {
pool?: Pool | null pool?: Pool | null
poolState: PoolState poolState: PoolState
...@@ -176,10 +178,14 @@ export function useDerivedMintInfo( ...@@ -176,10 +178,14 @@ export function useDerivedMintInfo(
[key: string]: number | undefined [key: string]: number | undefined
} = useMemo(() => { } = useMemo(() => {
return { return {
[Bound.LOWER]: tryParseTick(tokenA, tokenB, feeAmount, lowerRangeTypedValue), [Bound.LOWER]: existingPosition
[Bound.UPPER]: tryParseTick(tokenA, tokenB, feeAmount, upperRangeTypedValue), ? existingPosition.tickLower
: tryParseTick(tokenA, tokenB, feeAmount, lowerRangeTypedValue),
[Bound.UPPER]: existingPosition
? existingPosition.tickUpper
: tryParseTick(tokenA, tokenB, feeAmount, upperRangeTypedValue),
} }
}, [feeAmount, lowerRangeTypedValue, tokenA, tokenB, upperRangeTypedValue]) }, [existingPosition, feeAmount, lowerRangeTypedValue, tokenA, tokenB, upperRangeTypedValue])
const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks || {} const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks || {}
const sortedTicks = useMemo( const sortedTicks = useMemo(
......
import { BigNumber } from '@ethersproject/bignumber' import { BigNumberish } from '@ethersproject/bignumber'
export interface PositionDetails { export interface PositionDetails {
nonce: BigNumber nonce: BigNumber
tokenId: BigNumberish | undefined
operator: string operator: string
token0: string token0: string
token1: string token1: string
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
dependencies: dependencies:
"@babel/highlight" "^7.12.13" "@babel/highlight" "^7.12.13"
"@babel/compat-data@^7.12.1", "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8": "@babel/compat-data@^7.12.1", "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8":
version "7.13.15" version "7.13.15"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4"
integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA== integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==
...@@ -73,19 +73,19 @@ ...@@ -73,19 +73,19 @@
source-map "^0.5.0" source-map "^0.5.0"
"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.7.5", "@babel/core@^7.8.4": "@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.7.5", "@babel/core@^7.8.4":
version "7.13.15" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.15.tgz#a6d40917df027487b54312202a06812c4f7792d0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.16.tgz#7756ab24396cc9675f1c3fcd5b79fcce192ea96a"
integrity sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ== integrity sha512-sXHpixBiWWFti0AV2Zq7avpTasr6sIAu7Y396c608541qAU2ui4a193m0KSQmfPSKFZLnQ3cvlKDOm3XkuXm3Q==
dependencies: dependencies:
"@babel/code-frame" "^7.12.13" "@babel/code-frame" "^7.12.13"
"@babel/generator" "^7.13.9" "@babel/generator" "^7.13.16"
"@babel/helper-compilation-targets" "^7.13.13" "@babel/helper-compilation-targets" "^7.13.16"
"@babel/helper-module-transforms" "^7.13.14" "@babel/helper-module-transforms" "^7.13.14"
"@babel/helpers" "^7.13.10" "@babel/helpers" "^7.13.16"
"@babel/parser" "^7.13.15" "@babel/parser" "^7.13.16"
"@babel/template" "^7.12.13" "@babel/template" "^7.12.13"
"@babel/traverse" "^7.13.15" "@babel/traverse" "^7.13.15"
"@babel/types" "^7.13.14" "@babel/types" "^7.13.16"
convert-source-map "^1.7.0" convert-source-map "^1.7.0"
debug "^4.1.0" debug "^4.1.0"
gensync "^1.0.0-beta.2" gensync "^1.0.0-beta.2"
...@@ -93,12 +93,12 @@ ...@@ -93,12 +93,12 @@
semver "^6.3.0" semver "^6.3.0"
source-map "^0.5.0" source-map "^0.5.0"
"@babel/generator@^7.12.1", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.13.9": "@babel/generator@^7.12.1", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.13.16":
version "7.13.9" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.16.tgz#0befc287031a201d84cdfc173b46b320ae472d14"
integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw== integrity sha512-grBBR75UnKOcUWMp8WoDxNsWCFl//XCK6HWTrBQKTr5SV9f5g0pNOjdyzi/DTBv12S9GnYPInIXQBTky7OXEMg==
dependencies: dependencies:
"@babel/types" "^7.13.0" "@babel/types" "^7.13.16"
jsesc "^2.5.1" jsesc "^2.5.1"
source-map "^0.5.0" source-map "^0.5.0"
...@@ -117,12 +117,12 @@ ...@@ -117,12 +117,12 @@
"@babel/helper-explode-assignable-expression" "^7.12.13" "@babel/helper-explode-assignable-expression" "^7.12.13"
"@babel/types" "^7.12.13" "@babel/types" "^7.12.13"
"@babel/helper-compilation-targets@^7.12.1", "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8": "@babel/helper-compilation-targets@^7.12.1", "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.13.8":
version "7.13.13" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c"
integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ== integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==
dependencies: dependencies:
"@babel/compat-data" "^7.13.12" "@babel/compat-data" "^7.13.15"
"@babel/helper-validator-option" "^7.12.17" "@babel/helper-validator-option" "^7.12.17"
browserslist "^4.14.5" browserslist "^4.14.5"
semver "^6.3.0" semver "^6.3.0"
...@@ -198,12 +198,12 @@ ...@@ -198,12 +198,12 @@
"@babel/types" "^7.12.13" "@babel/types" "^7.12.13"
"@babel/helper-hoist-variables@^7.13.0": "@babel/helper-hoist-variables@^7.13.0":
version "7.13.0" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz#5d5882e855b5c5eda91e0cadc26c6e7a2c8593d8" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30"
integrity sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g== integrity sha512-1eMtTrXtrwscjcAeO4BVK+vvkxaLJSPFz1w1KLawz6HLNi9bPFGBNwwDyVfiu1Tv/vRRFYfoGaKhmAQPGPn5Wg==
dependencies: dependencies:
"@babel/traverse" "^7.13.0" "@babel/traverse" "^7.13.15"
"@babel/types" "^7.13.0" "@babel/types" "^7.13.16"
"@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.13.12": "@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.13.12":
version "7.13.12" version "7.13.12"
...@@ -310,14 +310,14 @@ ...@@ -310,14 +310,14 @@
"@babel/traverse" "^7.13.0" "@babel/traverse" "^7.13.0"
"@babel/types" "^7.13.0" "@babel/types" "^7.13.0"
"@babel/helpers@^7.12.1", "@babel/helpers@^7.12.5", "@babel/helpers@^7.13.10": "@babel/helpers@^7.12.1", "@babel/helpers@^7.12.5", "@babel/helpers@^7.13.16":
version "7.13.10" version "7.13.17"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.17.tgz#b497c7a00e9719d5b613b8982bda6ed3ee94caf6"
integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ== integrity sha512-Eal4Gce4kGijo1/TGJdqp3WuhllaMLSrW6XcL0ulyUAQOuxHcCafZE8KHg9857gcTehsm/v7RcOx2+jp0Ryjsg==
dependencies: dependencies:
"@babel/template" "^7.12.13" "@babel/template" "^7.12.13"
"@babel/traverse" "^7.13.0" "@babel/traverse" "^7.13.17"
"@babel/types" "^7.13.0" "@babel/types" "^7.13.17"
"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": "@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13":
version "7.13.10" version "7.13.10"
...@@ -328,10 +328,10 @@ ...@@ -328,10 +328,10 @@
chalk "^2.0.0" chalk "^2.0.0"
js-tokens "^4.0.0" js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.13", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.13.15", "@babel/parser@^7.7.0": "@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.13", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.7.0":
version "7.13.15" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37"
integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ== integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw==
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12":
version "7.13.12" version "7.13.12"
...@@ -683,11 +683,11 @@ ...@@ -683,11 +683,11 @@
"@babel/helper-plugin-utils" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-block-scoping@^7.12.1", "@babel/plugin-transform-block-scoping@^7.12.12", "@babel/plugin-transform-block-scoping@^7.12.13": "@babel/plugin-transform-block-scoping@^7.12.1", "@babel/plugin-transform-block-scoping@^7.12.12", "@babel/plugin-transform-block-scoping@^7.12.13":
version "7.12.13" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.13.16.tgz#a9c0f10794855c63b1d629914c7dcfeddd185892"
integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ== integrity sha512-ad3PHUxGnfWF4Efd3qFuznEtZKoBp0spS+DgqzVzRPV7urEBvPLue3y2j80w4Jf2YLzZHj8TOv/Lmvdmh3b2xg==
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.12.13" "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.13.0": "@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.13.0":
version "7.13.0" version "7.13.0"
...@@ -710,9 +710,9 @@ ...@@ -710,9 +710,9 @@
"@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-destructuring@^7.12.1", "@babel/plugin-transform-destructuring@^7.13.0": "@babel/plugin-transform-destructuring@^7.12.1", "@babel/plugin-transform-destructuring@^7.13.0":
version "7.13.0" version "7.13.17"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27"
integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA== integrity sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA==
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0"
...@@ -1225,20 +1225,20 @@ ...@@ -1225,20 +1225,20 @@
"@babel/plugin-transform-typescript" "^7.13.0" "@babel/plugin-transform-typescript" "^7.13.0"
"@babel/register@^7.12.1": "@babel/register@^7.12.1":
version "7.13.14" version "7.13.16"
resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.13.14.tgz#bbfa8f4f027c2ebc432e8e69e078b632605f2d9b" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.13.16.tgz#ae3ab0b55c8ec28763877383c454f01521d9a53d"
integrity sha512-iyw0hUwjh/fzN8qklVqZodbyWjEBOG0KdDnBOpv3zzIgK3NmuRXBmIXH39ZBdspkn8LTHvSboN+oYb4MT43+9Q== integrity sha512-dh2t11ysujTwByQjXNgJ48QZ2zcXKQVdV8s0TbeMI0flmtGWCdTwK9tJiACHXPLmncm5+ktNn/diojA45JE4jg==
dependencies: dependencies:
clone-deep "^4.0.1"
find-cache-dir "^2.0.0" find-cache-dir "^2.0.0"
lodash "^4.17.19"
make-dir "^2.1.0" make-dir "^2.1.0"
pirates "^4.0.0" pirates "^4.0.0"
source-map-support "^0.5.16" source-map-support "^0.5.16"
"@babel/runtime-corejs3@^7.10.2": "@babel/runtime-corejs3@^7.10.2":
version "7.13.10" version "7.13.17"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.13.10.tgz#14c3f4c85de22ba88e8e86685d13e8861a82fe86" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.13.17.tgz#9baf45f03d4d013f021760b992d6349a9d27deaf"
integrity sha512-x/XYVQ1h684pp1mJwOV4CyvqZXqbc8CMsMGUnAbuc82ZCdv1U63w5RSUzgDSXQHG5Rps/kiksH6g2D5BuaKyXg== integrity sha512-RGXINY1YvduBlGrP+vHjJqd/nK7JVpfM4rmZLGMx77WoL3sMrhheA0qxii9VNn1VHnxJLEyxmvCB+Wqc+x/FMw==
dependencies: dependencies:
core-js-pure "^3.0.0" core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
...@@ -1258,9 +1258,9 @@ ...@@ -1258,9 +1258,9 @@
regenerator-runtime "^0.12.0" regenerator-runtime "^0.12.0"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4": "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4":
version "7.13.10" version "7.13.17"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.17.tgz#8966d1fc9593bf848602f0662d6b4d0069e3a7ec"
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw== integrity sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
...@@ -1273,27 +1273,26 @@ ...@@ -1273,27 +1273,26 @@
"@babel/parser" "^7.12.13" "@babel/parser" "^7.12.13"
"@babel/types" "^7.12.13" "@babel/types" "^7.12.13"
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15", "@babel/traverse@^7.7.0": "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15", "@babel/traverse@^7.13.17", "@babel/traverse@^7.7.0":
version "7.13.15" version "7.13.17"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.17.tgz#c85415e0c7d50ac053d758baec98b28b2ecfeea3"
integrity sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ== integrity sha512-BMnZn0R+X6ayqm3C3To7o1j7Q020gWdqdyP50KEoVqaCO2c/Im7sYZSmVgvefp8TTMQ+9CtwuBp0Z1CZ8V3Pvg==
dependencies: dependencies:
"@babel/code-frame" "^7.12.13" "@babel/code-frame" "^7.12.13"
"@babel/generator" "^7.13.9" "@babel/generator" "^7.13.16"
"@babel/helper-function-name" "^7.12.13" "@babel/helper-function-name" "^7.12.13"
"@babel/helper-split-export-declaration" "^7.12.13" "@babel/helper-split-export-declaration" "^7.12.13"
"@babel/parser" "^7.13.15" "@babel/parser" "^7.13.16"
"@babel/types" "^7.13.14" "@babel/types" "^7.13.17"
debug "^4.1.0" debug "^4.1.0"
globals "^11.1.0" globals "^11.1.0"
"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.6", "@babel/types@^7.12.7", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": "@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.6", "@babel/types@^7.12.7", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.13.17", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
version "7.13.14" version "7.13.17"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.17.tgz#48010a115c9fba7588b4437dd68c9469012b38b4"
integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ== integrity sha512-RawydLgxbOPDlTLJNtoIypwdmAy//uQIzlKt2+iBiJaRlVuI6QLUxVAyWGNfOzp8Yu4L4lLIacoCyTNtpb4wiA==
dependencies: dependencies:
"@babel/helper-validator-identifier" "^7.12.11" "@babel/helper-validator-identifier" "^7.12.11"
lodash "^4.17.19"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@base2/pretty-print-object@1.0.0": "@base2/pretty-print-object@1.0.0":
...@@ -1495,10 +1494,10 @@ ...@@ -1495,10 +1494,10 @@
minimatch "^3.0.4" minimatch "^3.0.4"
strip-json-comments "^3.1.1" strip-json-comments "^3.1.1"
"@ethersproject/abi@5.1.0", "@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.1.0": "@ethersproject/abi@5.1.1", "@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.1.0":
version "5.1.0" version "5.1.1"
resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.0.tgz#d582c9f6a8e8192778b5f2c991ce19d7b336b0c5" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.1.1.tgz#79525f582338d98660ac709c65b44c3c081ed2fc"
integrity sha512-N/W9Sbn1/C6Kh2kuHRjf/hX6euMK4+9zdJRBB8sDWmihVntjUAfxbusGZKzDQD8i3szAHhTz8K7XADV5iFNfJw== integrity sha512-UNmhRL4ngm1nCWvhJWRd55PvP1JWojGD4BR63JxyiiWZQAszYzaHHeYdRcj+NY3S0kV6SmAS2dZWSBOZPnXbSw==
dependencies: dependencies:
"@ethersproject/address" "^5.1.0" "@ethersproject/address" "^5.1.0"
"@ethersproject/bignumber" "^5.1.0" "@ethersproject/bignumber" "^5.1.0"
...@@ -1560,10 +1559,10 @@ ...@@ -1560,10 +1559,10 @@
"@ethersproject/bytes" "^5.1.0" "@ethersproject/bytes" "^5.1.0"
"@ethersproject/properties" "^5.1.0" "@ethersproject/properties" "^5.1.0"
"@ethersproject/bignumber@5.1.0", "@ethersproject/bignumber@^5.1.0": "@ethersproject/bignumber@5.1.1", "@ethersproject/bignumber@^5.1.0":
version "5.1.0" version "5.1.1"
resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.1.0.tgz#966a013a5d871fc03fc67bf33cd8aadae627f0fd" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.1.1.tgz#84812695253ccbc639117f7ac49ee1529b68e637"
integrity sha512-wUvQlhTjPjFXIdLPOuTrFeQmSa6Wvls1bGXQNQWvB/SEn1NsTCE8PmumIEZxmOPjSHl1eV2uyHP5jBm5Cgj92Q== integrity sha512-AVz5iqz7+70RIqoQTznsdJ6DOVBYciNlvO+AlQmPTB6ofCvoihI9bQdr6wljsX+d5W7Yc4nyvQvP4JMzg0Agig==
dependencies: dependencies:
"@ethersproject/bytes" "^5.1.0" "@ethersproject/bytes" "^5.1.0"
"@ethersproject/logger" "^5.1.0" "@ethersproject/logger" "^5.1.0"
...@@ -1600,9 +1599,9 @@ ...@@ -1600,9 +1599,9 @@
"@ethersproject/transactions" "^5.1.0" "@ethersproject/transactions" "^5.1.0"
"@ethersproject/experimental@^5.0.1": "@ethersproject/experimental@^5.0.1":
version "5.1.1" version "5.1.2"
resolved "https://registry.yarnpkg.com/@ethersproject/experimental/-/experimental-5.1.1.tgz#cfee1df95c8c007e7e30837e925066f6020852bf" resolved "https://registry.yarnpkg.com/@ethersproject/experimental/-/experimental-5.1.2.tgz#5bb850d907e9510eca8036abdd952487502837a0"
integrity sha512-WnG6jnlG3L0spm5RadC5v0/Jab1XfkF5q9WG0kCLxUPog6fkuRTqzeFY7q+xZ8mY7dm17Lj7pbYN9I4cz1I33Q== integrity sha512-Agz2/Of+qaNddu/8XJcH2eSewwDZpEId4R1/hj3pgQagYR0hGcCjICDqYizFM4b8MoZs/nA/DuhgWnT6YmjhyQ==
dependencies: dependencies:
"@ethersproject/web" "^5.1.0" "@ethersproject/web" "^5.1.0"
ethers "^5.1.0" ethers "^5.1.0"
...@@ -1694,10 +1693,10 @@ ...@@ -1694,10 +1693,10 @@
dependencies: dependencies:
"@ethersproject/logger" "^5.1.0" "@ethersproject/logger" "^5.1.0"
"@ethersproject/providers@5.1.1": "@ethersproject/providers@5.1.2":
version "5.1.1" version "5.1.2"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.1.1.tgz#a72f446ee0ddd93eb8f7d86178629565c03b55b6" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.1.2.tgz#4e4459698903f911402fe91aa7544eb07f3921ed"
integrity sha512-+xWqQh4eLnAePRR5CHSySCVke//NxGSuQEUzGTdDtt0yCbizwlKGm7CrsU0zF8JUcKDrDh36ezzTicOMd5sl9w== integrity sha512-GqsS8rd+eyd4eNkcNgzZ4l9IRULBPUZa7JPnv22k4MHflMobUseyhfbVnmoN5bVNNkOxjV1IPTw9i0sV1hwdpg==
dependencies: dependencies:
"@ethersproject/abstract-provider" "^5.1.0" "@ethersproject/abstract-provider" "^5.1.0"
"@ethersproject/abstract-signer" "^5.1.0" "@ethersproject/abstract-signer" "^5.1.0"
...@@ -2183,9 +2182,9 @@ ...@@ -2183,9 +2182,9 @@
regenerator-runtime "^0.13.3" regenerator-runtime "^0.13.3"
"@json-rpc-tools/types@^1.6.1": "@json-rpc-tools/types@^1.6.1":
version "1.7.1" version "1.7.2"
resolved "https://registry.yarnpkg.com/@json-rpc-tools/types/-/types-1.7.1.tgz#e341947679c57192b13e7d2e4ec49009b1c448c2" resolved "https://registry.yarnpkg.com/@json-rpc-tools/types/-/types-1.7.2.tgz#1925e2c8071233beee99f8b4a12a09255489567a"
integrity sha512-SNhhx84LQwc9/QnOpdVd8LvXqurB0WcfIEe6961Qx+9ixeK1+U3Dt4tZTPkVohyKwBZ6YyRsqQl9ZYsy2SjdxQ== integrity sha512-PrR9NqzGTG0gWRUARa1SbPaQb1SNXv4dJMLp8lEmTNXWtEGS032m3qaWPwyhaqr6/ocpNxsrPra7KtKFzQgIoA==
dependencies: dependencies:
keyvaluestorage-interface "^1.0.0" keyvaluestorage-interface "^1.0.0"
...@@ -3397,9 +3396,9 @@ ...@@ -3397,9 +3396,9 @@
loader-utils "^2.0.0" loader-utils "^2.0.0"
"@testing-library/dom@^7.11.0": "@testing-library/dom@^7.11.0":
version "7.30.3" version "7.30.4"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.30.3.tgz#779ea9bbb92d63302461800a388a5a890ac22519" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.30.4.tgz#c6a4a91557e92035fd565246bbbfb8107aa4634d"
integrity sha512-7JhIg2MW6WPwyikH2iL3o7z+FTVgSOd2jqCwTAHqK7Qal2gRRYiUQyURAxtbK9VXm/UTyG9bRihv8C5Tznr2zw== integrity sha512-GObDVMaI4ARrZEXaRy4moolNAxWPKvEYNV/fa6Uc2eAzR/t4otS6A7EhrntPBIQLeehL9DbVhscvvv7gd6hWqA==
dependencies: dependencies:
"@babel/code-frame" "^7.10.4" "@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5" "@babel/runtime" "^7.12.5"
...@@ -6215,14 +6214,14 @@ browserslist@^3.2.6: ...@@ -6215,14 +6214,14 @@ browserslist@^3.2.6:
caniuse-lite "^1.0.30000844" caniuse-lite "^1.0.30000844"
electron-to-chromium "^1.3.47" electron-to-chromium "^1.3.47"
browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.6.2, browserslist@^4.6.4: browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.4, browserslist@^4.6.2, browserslist@^4.6.4:
version "4.16.4" version "4.16.5"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.4.tgz#7ebf913487f40caf4637b892b268069951c35d58" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.5.tgz#952825440bca8913c62d0021334cbe928ef062ae"
integrity sha512-d7rCxYV8I9kj41RH8UKYnvDYCRENUlHRgyXy/Rhr/1BaeLGfiCptEdFE8MIrvGfWbBFNjVYx76SQWvNX1j+/cQ== integrity sha512-C2HAjrM1AI/djrpAUU/tr4pml1DqLIzJKSLDBXBrNErl9ZCCTXdhwxdJjYc16953+mBWf7Lw+uUJgpgb8cN71A==
dependencies: dependencies:
caniuse-lite "^1.0.30001208" caniuse-lite "^1.0.30001214"
colorette "^1.2.2" colorette "^1.2.2"
electron-to-chromium "^1.3.712" electron-to-chromium "^1.3.719"
escalade "^3.1.1" escalade "^3.1.1"
node-releases "^1.1.71" node-releases "^1.1.71"
...@@ -6478,10 +6477,10 @@ caniuse-api@^3.0.0: ...@@ -6478,10 +6477,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2" lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001208: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001214:
version "1.0.30001211" version "1.0.30001214"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001211.tgz#be40d528bb10272eba0037a88adc40054810f8e2" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001214.tgz#70f153c78223515c6d37a9fde6cd69250da9d872"
integrity sha512-v3GXWKofIkN3PkSidLI5d1oqeKNsam9nQkqieoMhP87nxOY0RPDC8X2+jcv8pjV4dRozPLSoMqNii9sDViOlIg== integrity sha512-O2/SCpuaU3eASWVaesQirZv1MSjUNOvmugaD8zNSJqw6Vv5SGwoOpA9LJs3pNPfM745nxqPvfZY3MQKY4AKHYg==
capture-exit@^2.0.0: capture-exit@^2.0.0:
version "2.0.0" version "2.0.0"
...@@ -6548,9 +6547,9 @@ chalk@^3.0.0: ...@@ -6548,9 +6547,9 @@ chalk@^3.0.0:
supports-color "^7.1.0" supports-color "^7.1.0"
chalk@^4.0.0, chalk@^4.1.0: chalk@^4.0.0, chalk@^4.1.0:
version "4.1.0" version "4.1.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
dependencies: dependencies:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
...@@ -6788,6 +6787,15 @@ cliui@^6.0.0: ...@@ -6788,6 +6787,15 @@ cliui@^6.0.0:
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
wrap-ansi "^6.2.0" wrap-ansi "^6.2.0"
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
dependencies:
is-plain-object "^2.0.4"
kind-of "^6.0.2"
shallow-clone "^3.0.0"
clone@^1.0.2: clone@^1.0.2:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
...@@ -7121,17 +7129,17 @@ copy-to-clipboard@^3.2.0, copy-to-clipboard@^3.3.1: ...@@ -7121,17 +7129,17 @@ copy-to-clipboard@^3.2.0, copy-to-clipboard@^3.3.1:
toggle-selection "^1.0.6" toggle-selection "^1.0.6"
core-js-compat@^3.6.2, core-js-compat@^3.8.1, core-js-compat@^3.9.0, core-js-compat@^3.9.1: core-js-compat@^3.6.2, core-js-compat@^3.8.1, core-js-compat@^3.9.0, core-js-compat@^3.9.1:
version "3.10.1" version "3.11.0"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.10.1.tgz#62183a3a77ceeffcc420d907a3e6fc67d9b27f1c" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.11.0.tgz#635683f43480a0b41e3f6be3b1c648dadb8b4390"
integrity sha512-ZHQTdTPkqvw2CeHiZC970NNJcnwzT6YIueDMASKt+p3WbZsLXOcoD392SkcWhkC0wBBHhlfhqGKKsNCQUozYtg== integrity sha512-3wsN9YZJohOSDCjVB0GequOyHax8zFiogSX3XWLE28M1Ew7dTU57tgHjIylSBKSIouwmLBp3g61sKMz/q3xEGA==
dependencies: dependencies:
browserslist "^4.16.3" browserslist "^4.16.4"
semver "7.0.0" semver "7.0.0"
core-js-pure@^3.0.0, core-js-pure@^3.8.2: core-js-pure@^3.0.0, core-js-pure@^3.8.2:
version "3.10.1" version "3.11.0"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.10.1.tgz#28642697dfcf02e0fd9f4d9891bd03a22df28ecf" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.11.0.tgz#e07f25a8f616d178ec16b0354b008ad28b20b2f0"
integrity sha512-PeyJH2SE0KuxY5eCGNWA+W+CeDpB6M1PN3S7Am7jSv/Ttuxz2SnWbIiVQOn/TDaGaGtxo8CRWHkXwJscbUHtVw== integrity sha512-PxEiQGjzC+5qbvE7ZIs5Zn6BynNeZO9zHhrrWmkRff2SZLq0CE/H5LuZOJHhmOQ8L38+eMzEHAmPYWrUtDfuDQ==
core-js@^2.4.0, core-js@^2.5.0: core-js@^2.4.0, core-js@^2.5.0:
version "2.6.12" version "2.6.12"
...@@ -7139,9 +7147,9 @@ core-js@^2.4.0, core-js@^2.5.0: ...@@ -7139,9 +7147,9 @@ core-js@^2.4.0, core-js@^2.5.0:
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.0.1, core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2: core-js@^3.0.1, core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2:
version "3.10.1" version "3.11.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.10.1.tgz#e683963978b6806dcc6c0a4a8bd4ab0bdaf3f21a" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.0.tgz#05dac6aa70c0a4ad842261f8957b961d36eb8926"
integrity sha512-pwCxEXnj27XG47mu7SXAwhLP3L5CrlvCB91ANUkIz40P27kUcvNfSdvyZJ9CLHiVoKSp+TTChMQMSKQEH/IQxA== integrity sha512-bd79DPpx+1Ilh9+30aT5O1sgpQd4Ttg8oqkqi51ZzhedMM1omD2e6IOF48Z/DzDCZ2svp49tN/3vneTK6ZBkXw==
core-util-is@1.0.2, core-util-is@~1.0.0: core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2" version "1.0.2"
...@@ -8159,9 +8167,9 @@ dotignore@~0.1.2: ...@@ -8159,9 +8167,9 @@ dotignore@~0.1.2:
minimatch "^3.0.4" minimatch "^3.0.4"
downshift@^6.0.15: downshift@^6.0.15:
version "6.1.2" version "6.1.3"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.2.tgz#99d9a03d4da4bf369df766effc3b70f7e789950e" resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.3.tgz#e794b7805d24810968f21e81ad6bdd9f3fdc40da"
integrity sha512-WnPoQ6miic4+uEzPEfqgeen0t5YREOUabMopU/Juo/UYDMZl0ZACkO6ykWCRg48dlEUmEt6zfaJlj1x7kEy78g== integrity sha512-RA1MuaNcTbt0j+sVLhSs8R2oZbBXYAtdQP/V+uHhT3DoDteZzJPjlC+LQVm9T07Wpvo84QXaZtUCePLDTDwGXg==
dependencies: dependencies:
"@babel/runtime" "^7.13.10" "@babel/runtime" "^7.13.10"
compute-scroll-into-view "^1.0.17" compute-scroll-into-view "^1.0.17"
...@@ -8210,10 +8218,10 @@ ejs@^2.6.1: ...@@ -8210,10 +8218,10 @@ ejs@^2.6.1:
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.712: electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.719:
version "1.3.717" version "1.3.719"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.717.tgz#78d4c857070755fb58ab64bcc173db1d51cbc25f" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.719.tgz#87166fee347a46a2557f19aadb40a1d68241e61c"
integrity sha512-OfzVPIqD1MkJ7fX+yTl2nKyOE4FReeVfMCzzxQS+Kp43hZYwHwThlGP+EGIZRXJsxCM7dqo8Y65NOX/HP12iXQ== integrity sha512-heM78GKSqrIzO9Oz0/y22nTBN7bqSP1Pla2SyU9DiSnQD+Ea9SyyN5RWWlgqsqeBLNDkSlE9J9EHFmdMPzxB/g==
elegant-spinner@^1.0.1: elegant-spinner@^1.0.1:
version "1.0.1" version "1.0.1"
...@@ -8637,14 +8645,15 @@ eslint-visitor-keys@^2.0.0: ...@@ -8637,14 +8645,15 @@ eslint-visitor-keys@^2.0.0:
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
eslint-webpack-plugin@^2.5.2: eslint-webpack-plugin@^2.5.2:
version "2.5.3" version "2.5.4"
resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.5.3.tgz#a125585a1d8bb9c939f2a920a9bc9be4a21cdb58" resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.5.4.tgz#473b84932f1a8e2c2b8e66a402d0497bf440b986"
integrity sha512-LewNevZf9ghDCxCGT6QltNWVi8KIYWc4LKcin8K9Azh1hypG7YAmobUDIU67fAPa+eMjRnU4rjEkLbYI1w5/UA== integrity sha512-7rYh0m76KyKSDE+B+2PUQrlNS4HJ51t3WKpkJg6vo2jFMbEPTG99cBV0Dm7LXSHucN4WGCG65wQcRiTFrj7iWw==
dependencies: dependencies:
"@types/eslint" "^7.2.6" "@types/eslint" "^7.2.6"
arrify "^2.0.1" arrify "^2.0.1"
jest-worker "^26.6.2" jest-worker "^26.6.2"
micromatch "^4.0.2" micromatch "^4.0.2"
normalize-path "^3.0.0"
schema-utils "^3.0.0" schema-utils "^3.0.0"
eslint@^7.11.0: eslint@^7.11.0:
...@@ -9077,17 +9086,17 @@ ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: ...@@ -9077,17 +9086,17 @@ ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0:
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
ethers@^5.0.7, ethers@^5.1.0: ethers@^5.0.7, ethers@^5.1.0:
version "5.1.2" version "5.1.3"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.1.2.tgz#232bf78d7ccca3a05d7b15db6d33e9d693cf3c35" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.1.3.tgz#68eb48742b8a8ca53480bca2e53fb314c23fea7f"
integrity sha512-yM+2bINj7Li9jeKX+hGZ/rFTo6kXcCwZTcCBmAwS+J3bLfyGX/o21fcssuPb9kfR26suCV+98XTWIuTuGiDO5A== integrity sha512-QAj+LG3z5HsK6UDAOdCjDEthWioZ7sTzAcMWyVrQF+ACioalQ99NrrSxIq5qS0c+hoy3TAIjqpYteHgC2Iqy+w==
dependencies: dependencies:
"@ethersproject/abi" "5.1.0" "@ethersproject/abi" "5.1.1"
"@ethersproject/abstract-provider" "5.1.0" "@ethersproject/abstract-provider" "5.1.0"
"@ethersproject/abstract-signer" "5.1.0" "@ethersproject/abstract-signer" "5.1.0"
"@ethersproject/address" "5.1.0" "@ethersproject/address" "5.1.0"
"@ethersproject/base64" "5.1.0" "@ethersproject/base64" "5.1.0"
"@ethersproject/basex" "5.1.0" "@ethersproject/basex" "5.1.0"
"@ethersproject/bignumber" "5.1.0" "@ethersproject/bignumber" "5.1.1"
"@ethersproject/bytes" "5.1.0" "@ethersproject/bytes" "5.1.0"
"@ethersproject/constants" "5.1.0" "@ethersproject/constants" "5.1.0"
"@ethersproject/contracts" "5.1.1" "@ethersproject/contracts" "5.1.1"
...@@ -9099,7 +9108,7 @@ ethers@^5.0.7, ethers@^5.1.0: ...@@ -9099,7 +9108,7 @@ ethers@^5.0.7, ethers@^5.1.0:
"@ethersproject/networks" "5.1.0" "@ethersproject/networks" "5.1.0"
"@ethersproject/pbkdf2" "5.1.0" "@ethersproject/pbkdf2" "5.1.0"
"@ethersproject/properties" "5.1.0" "@ethersproject/properties" "5.1.0"
"@ethersproject/providers" "5.1.1" "@ethersproject/providers" "5.1.2"
"@ethersproject/random" "5.1.0" "@ethersproject/random" "5.1.0"
"@ethersproject/rlp" "5.1.0" "@ethersproject/rlp" "5.1.0"
"@ethersproject/sha2" "5.1.0" "@ethersproject/sha2" "5.1.0"
...@@ -9741,9 +9750,9 @@ fork-ts-checker-webpack-plugin@4.1.6, fork-ts-checker-webpack-plugin@^4.1.0, for ...@@ -9741,9 +9750,9 @@ fork-ts-checker-webpack-plugin@4.1.6, fork-ts-checker-webpack-plugin@^4.1.0, for
worker-rpc "^0.1.0" worker-rpc "^0.1.0"
fork-ts-checker-webpack-plugin@^6.0.4: fork-ts-checker-webpack-plugin@^6.0.4:
version "6.2.1" version "6.2.4"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.2.1.tgz#e3a7e64c90e5490a75d43d86d47f02e538c0a13e" resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.2.4.tgz#f46dc0700820476f260451518b9d545c42277aff"
integrity sha512-Pyhn2kav/Y2g6I7aInABgcph/B78jjdXc4kGHzaAUBL4UVthknxM6aMH47JwpnuTJmdOuf6p5vMbIahsBHuWGg== integrity sha512-M0+lELATBqzf+tubq9PcRfJm4/wW172P7cAoCs1OpgfRICtEuJ/JUMuUm0H9JAZ57lLaN1gj38uxNktDhscYhA==
dependencies: dependencies:
"@babel/code-frame" "^7.8.3" "@babel/code-frame" "^7.8.3"
"@types/json-schema" "^7.0.5" "@types/json-schema" "^7.0.5"
...@@ -14974,9 +14983,9 @@ postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, po ...@@ -14974,9 +14983,9 @@ postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, po
supports-color "^6.1.0" supports-color "^6.1.0"
postcss@^8.1.0: postcss@^8.1.0:
version "8.2.10" version "8.2.12"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.12.tgz#81248a1a87e0f575cc594a99a08207fd1c4addc4"
integrity sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw== integrity sha512-BJnGT5+0q2tzvs6oQfnY2NpEJ7rIXNfBnZtQOKCIsweeWXBXeDd5k31UgTdS3d/c02ouspufn37mTaHWkJyzMQ==
dependencies: dependencies:
colorette "^1.2.2" colorette "^1.2.2"
nanoid "^3.1.22" nanoid "^3.1.22"
...@@ -16917,6 +16926,13 @@ sha.js@^2.4.0, sha.js@^2.4.8: ...@@ -16917,6 +16926,13 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1" inherits "^2.0.1"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
dependencies:
kind-of "^6.0.2"
shallowequal@^1.1.0: shallowequal@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
...@@ -17709,9 +17725,9 @@ symbol.prototype.description@^1.0.0: ...@@ -17709,9 +17725,9 @@ symbol.prototype.description@^1.0.0:
object.getownpropertydescriptors "^2.1.2" object.getownpropertydescriptors "^2.1.2"
table@^6.0.4: table@^6.0.4:
version "6.3.0" version "6.3.2"
resolved "https://registry.yarnpkg.com/table/-/table-6.3.0.tgz#b88c2be1ae7d318638cc064b2c0604baffec79f1" resolved "https://registry.yarnpkg.com/table/-/table-6.3.2.tgz#afa86bee5cfe305f9328f89bb3e5454132cdea28"
integrity sha512-gM9kB7aNIuSagW89Fh+SdL49uhKnVSORxMcV72u/dfptFdqExInNn5M21wgq/Uf5UdJpsboFhNe/0SoNKjaxzg== integrity sha512-I9/Ca6Huf2oxFag7crD0DhA+arIdfLtWunSn0NIXSzjtUlDgIBGVZY7SsMkNPNT3Psd/z4gza0nuEpmra9eRbg==
dependencies: dependencies:
ajv "^8.0.1" ajv "^8.0.1"
is-boolean-object "^1.1.0" is-boolean-object "^1.1.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment