fix: Add SwitchLocaleLink to a page where it does not exist (#1867)
This commit is contained in:
parent
9e93f809a0
commit
37cf492dd5
@ -55,6 +55,7 @@ import RateToggle from 'components/RateToggle'
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
import { AddRemoveTabs } from 'components/NavigationTabs'
|
import { AddRemoveTabs } from 'components/NavigationTabs'
|
||||||
import HoverInlineText from 'components/HoverInlineText'
|
import HoverInlineText from 'components/HoverInlineText'
|
||||||
|
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
||||||
|
|
||||||
const DEFAULT_ADD_IN_RANGE_SLIPPAGE_TOLERANCE = new Percent(50, 10_000)
|
const DEFAULT_ADD_IN_RANGE_SLIPPAGE_TOLERANCE = new Percent(50, 10_000)
|
||||||
|
|
||||||
@ -385,393 +386,401 @@ export default function AddLiquidity({
|
|||||||
!argentWalletContract && approvalB !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_B]
|
!argentWalletContract && approvalB !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_B]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollablePage>
|
<>
|
||||||
<TransactionConfirmationModal
|
<ScrollablePage>
|
||||||
isOpen={showConfirm}
|
<TransactionConfirmationModal
|
||||||
onDismiss={handleDismissConfirmation}
|
isOpen={showConfirm}
|
||||||
attemptingTxn={attemptingTxn}
|
onDismiss={handleDismissConfirmation}
|
||||||
hash={txHash}
|
attemptingTxn={attemptingTxn}
|
||||||
content={() => (
|
hash={txHash}
|
||||||
<ConfirmationModalContent
|
content={() => (
|
||||||
title={'Add Liquidity'}
|
<ConfirmationModalContent
|
||||||
onDismiss={handleDismissConfirmation}
|
title={'Add Liquidity'}
|
||||||
topContent={() => (
|
onDismiss={handleDismissConfirmation}
|
||||||
<Review
|
topContent={() => (
|
||||||
parsedAmounts={parsedAmounts}
|
<Review
|
||||||
position={position}
|
parsedAmounts={parsedAmounts}
|
||||||
existingPosition={existingPosition}
|
position={position}
|
||||||
priceLower={priceLower}
|
existingPosition={existingPosition}
|
||||||
priceUpper={priceUpper}
|
priceLower={priceLower}
|
||||||
outOfRange={outOfRange}
|
priceUpper={priceUpper}
|
||||||
/>
|
outOfRange={outOfRange}
|
||||||
)}
|
|
||||||
bottomContent={() => (
|
|
||||||
<ButtonPrimary style={{ marginTop: '1rem' }} onClick={onAdd}>
|
|
||||||
<Text fontWeight={500} fontSize={20}>
|
|
||||||
<Trans>Add</Trans>
|
|
||||||
</Text>
|
|
||||||
</ButtonPrimary>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
pendingText={pendingText}
|
|
||||||
/>
|
|
||||||
<AppBody>
|
|
||||||
<AddRemoveTabs
|
|
||||||
creating={false}
|
|
||||||
adding={true}
|
|
||||||
positionID={tokenId}
|
|
||||||
defaultSlippage={DEFAULT_ADD_IN_RANGE_SLIPPAGE_TOLERANCE}
|
|
||||||
/>
|
|
||||||
<Wrapper>
|
|
||||||
<AutoColumn gap="32px">
|
|
||||||
{!hasExistingPosition && (
|
|
||||||
<>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween paddingBottom="20px">
|
|
||||||
<TYPE.label>
|
|
||||||
<Trans>Select pair</Trans>
|
|
||||||
</TYPE.label>
|
|
||||||
<ButtonText onClick={clearAll}>
|
|
||||||
<TYPE.blue fontSize="12px">
|
|
||||||
<Trans>Clear All</Trans>
|
|
||||||
</TYPE.blue>
|
|
||||||
</ButtonText>
|
|
||||||
</RowBetween>
|
|
||||||
<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
|
|
||||||
/>
|
|
||||||
<div style={{ width: '12px' }} />
|
|
||||||
|
|
||||||
<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>{' '}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasExistingPosition && existingPosition ? (
|
|
||||||
<PositionPreview
|
|
||||||
position={existingPosition}
|
|
||||||
title={<Trans>Selected Range</Trans>}
|
|
||||||
inRange={!outOfRange}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<FeeSelector
|
|
||||||
disabled={!currencyB || !currencyA}
|
|
||||||
feeAmount={feeAmount}
|
|
||||||
handleFeePoolSelect={handleFeePoolSelect}
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{noLiquidity && (
|
bottomContent={() => (
|
||||||
<DynamicSection disabled={!currencyA || !currencyB}>
|
<ButtonPrimary style={{ marginTop: '1rem' }} onClick={onAdd}>
|
||||||
<AutoColumn gap="md">
|
<Text fontWeight={500} fontSize={20}>
|
||||||
<RowBetween>
|
<Trans>Add</Trans>
|
||||||
<TYPE.label>
|
</Text>
|
||||||
<Trans>Set Starting Price</Trans>
|
</ButtonPrimary>
|
||||||
</TYPE.label>
|
)}
|
||||||
{baseCurrency && quoteCurrency ? (
|
/>
|
||||||
<RateToggle
|
)}
|
||||||
currencyA={baseCurrency}
|
pendingText={pendingText}
|
||||||
currencyB={quoteCurrency}
|
/>
|
||||||
handleRateToggle={() => {
|
<AppBody>
|
||||||
onLeftRangeInput('')
|
<AddRemoveTabs
|
||||||
onRightRangeInput('')
|
creating={false}
|
||||||
history.push(
|
adding={true}
|
||||||
`/add/${currencyIdB as string}/${currencyIdA as string}${
|
positionID={tokenId}
|
||||||
feeAmount ? '/' + feeAmount : ''
|
defaultSlippage={DEFAULT_ADD_IN_RANGE_SLIPPAGE_TOLERANCE}
|
||||||
}`
|
/>
|
||||||
)
|
<Wrapper>
|
||||||
}}
|
<AutoColumn gap="32px">
|
||||||
/>
|
{!hasExistingPosition && (
|
||||||
) : null}
|
<>
|
||||||
</RowBetween>
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween paddingBottom="20px">
|
||||||
<OutlineCard padding="12px">
|
<TYPE.label>
|
||||||
<StyledInput
|
<Trans>Select pair</Trans>
|
||||||
className="start-price-input"
|
</TYPE.label>
|
||||||
value={startPriceTypedValue}
|
<ButtonText onClick={clearAll}>
|
||||||
onUserInput={onStartPriceInput}
|
<TYPE.blue fontSize="12px">
|
||||||
/>
|
<Trans>Clear All</Trans>
|
||||||
</OutlineCard>
|
</TYPE.blue>
|
||||||
<RowBetween style={{ backgroundColor: theme.bg1, padding: '12px', borderRadius: '12px' }}>
|
</ButtonText>
|
||||||
<TYPE.main>
|
</RowBetween>
|
||||||
<Trans>Current {baseCurrency?.symbol} Price:</Trans>
|
<RowBetween>
|
||||||
</TYPE.main>
|
<CurrencyDropdown
|
||||||
<TYPE.main>
|
value={formattedAmounts[Field.CURRENCY_A]}
|
||||||
{price ? (
|
onUserInput={onFieldAInput}
|
||||||
<TYPE.main>
|
hideInput={true}
|
||||||
<RowFixed>
|
onMax={() => {
|
||||||
<HoverInlineText
|
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
|
||||||
maxCharacters={20}
|
|
||||||
text={invertPrice ? price?.invert()?.toSignificant(5) : price?.toSignificant(5)}
|
|
||||||
/>{' '}
|
|
||||||
<span style={{ marginLeft: '4px' }}>{quoteCurrency?.symbol}</span>
|
|
||||||
</RowFixed>
|
|
||||||
</TYPE.main>
|
|
||||||
) : (
|
|
||||||
'-'
|
|
||||||
)}
|
|
||||||
</TYPE.main>
|
|
||||||
</RowBetween>
|
|
||||||
<BlueCard
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: ' 1.5rem 1.25rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AlertCircle color={theme.text1} size={32} style={{ marginBottom: '12px', opacity: 0.8 }} />
|
|
||||||
<TYPE.body
|
|
||||||
fontSize={14}
|
|
||||||
style={{ marginBottom: 8, fontWeight: 500, opacity: 0.8 }}
|
|
||||||
textAlign="center"
|
|
||||||
>
|
|
||||||
You are the first liquidity provider for this Uniswap V3 pool.
|
|
||||||
</TYPE.body>
|
|
||||||
|
|
||||||
<TYPE.body fontWeight={500} textAlign="center" fontSize={14} style={{ opacity: 0.8 }}>
|
|
||||||
The transaction cost will be much higher as it includes the gas to create the pool.
|
|
||||||
</TYPE.body>
|
|
||||||
</BlueCard>
|
|
||||||
</AutoColumn>
|
|
||||||
</DynamicSection>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<DynamicSection gap="md" disabled={!feeAmount || invalidPool || (noLiquidity && !startPriceTypedValue)}>
|
|
||||||
<RowBetween>
|
|
||||||
<TYPE.label>
|
|
||||||
<Trans>Set Price Range</Trans>
|
|
||||||
</TYPE.label>
|
|
||||||
|
|
||||||
{baseCurrency && quoteCurrency ? (
|
|
||||||
<RateToggle
|
|
||||||
currencyA={baseCurrency}
|
|
||||||
currencyB={quoteCurrency}
|
|
||||||
handleRateToggle={() => {
|
|
||||||
onLeftRangeInput('')
|
|
||||||
onRightRangeInput('')
|
|
||||||
history.push(
|
|
||||||
`/add/${currencyIdB as string}/${currencyIdA as string}${feeAmount ? '/' + feeAmount : ''}`
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
|
onCurrencySelect={handleCurrencyASelect}
|
||||||
|
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
|
||||||
|
currency={currencies[Field.CURRENCY_A]}
|
||||||
|
id="add-liquidity-input-tokena"
|
||||||
|
showCommonBases
|
||||||
/>
|
/>
|
||||||
) : null}
|
<div style={{ width: '12px' }} />
|
||||||
</RowBetween>
|
|
||||||
<TYPE.main fontSize={14} fontWeight={400} style={{ marginBottom: '.5rem', lineHeight: '125%' }}>
|
|
||||||
<Trans>
|
|
||||||
Your liquidity will only earn fees when the market price of the pair is within your range.{' '}
|
|
||||||
<ExternalLink
|
|
||||||
href={'https://docs.uniswap.org/concepts/introduction/liquidity-user-guide#4-set-price-range'}
|
|
||||||
style={{ fontSize: '14px' }}
|
|
||||||
>
|
|
||||||
Need help picking a range?
|
|
||||||
</ExternalLink>
|
|
||||||
</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
|
|
||||||
<RangeSelector
|
<CurrencyDropdown
|
||||||
priceLower={priceLower}
|
value={formattedAmounts[Field.CURRENCY_B]}
|
||||||
priceUpper={priceUpper}
|
hideInput={true}
|
||||||
getDecrementLower={getDecrementLower}
|
onUserInput={onFieldBInput}
|
||||||
getIncrementLower={getIncrementLower}
|
onCurrencySelect={handleCurrencyBSelect}
|
||||||
getDecrementUpper={getDecrementUpper}
|
onMax={() => {
|
||||||
getIncrementUpper={getIncrementUpper}
|
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
|
||||||
onLeftRangeInput={onLeftRangeInput}
|
}}
|
||||||
onRightRangeInput={onRightRangeInput}
|
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
|
||||||
currencyA={baseCurrency}
|
currency={currencies[Field.CURRENCY_B]}
|
||||||
currencyB={quoteCurrency}
|
id="add-liquidity-input-tokenb"
|
||||||
|
showCommonBases
|
||||||
|
/>
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>{' '}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasExistingPosition && existingPosition ? (
|
||||||
|
<PositionPreview
|
||||||
|
position={existingPosition}
|
||||||
|
title={<Trans>Selected Range</Trans>}
|
||||||
|
inRange={!outOfRange}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<FeeSelector
|
||||||
|
disabled={!currencyB || !currencyA}
|
||||||
feeAmount={feeAmount}
|
feeAmount={feeAmount}
|
||||||
|
handleFeePoolSelect={handleFeePoolSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{price && baseCurrency && quoteCurrency && !noLiquidity && (
|
{noLiquidity && (
|
||||||
<LightCard style={{ padding: '12px' }}>
|
<DynamicSection disabled={!currencyA || !currencyB}>
|
||||||
<AutoColumn gap="4px">
|
<AutoColumn gap="md">
|
||||||
<TYPE.main fontWeight={500} textAlign="center" fontSize={12}>
|
<RowBetween>
|
||||||
<Trans>Current Price</Trans>
|
<TYPE.label>
|
||||||
</TYPE.main>
|
<Trans>Set Starting Price</Trans>
|
||||||
<TYPE.body fontWeight={500} textAlign="center" fontSize={20}>
|
</TYPE.label>
|
||||||
<HoverInlineText
|
{baseCurrency && quoteCurrency ? (
|
||||||
maxCharacters={20}
|
<RateToggle
|
||||||
text={invertPrice ? price.invert().toSignificant(6) : price.toSignificant(6)}
|
currencyA={baseCurrency}
|
||||||
/>{' '}
|
currencyB={quoteCurrency}
|
||||||
</TYPE.body>
|
handleRateToggle={() => {
|
||||||
<TYPE.main fontWeight={500} textAlign="center" fontSize={12}>
|
onLeftRangeInput('')
|
||||||
<Trans>
|
onRightRangeInput('')
|
||||||
{quoteCurrency?.symbol} per {baseCurrency.symbol}
|
history.push(
|
||||||
</Trans>
|
`/add/${currencyIdB as string}/${currencyIdA as string}${
|
||||||
</TYPE.main>
|
feeAmount ? '/' + feeAmount : ''
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</RowBetween>
|
||||||
|
|
||||||
|
<OutlineCard padding="12px">
|
||||||
|
<StyledInput
|
||||||
|
className="start-price-input"
|
||||||
|
value={startPriceTypedValue}
|
||||||
|
onUserInput={onStartPriceInput}
|
||||||
|
/>
|
||||||
|
</OutlineCard>
|
||||||
|
<RowBetween style={{ backgroundColor: theme.bg1, padding: '12px', borderRadius: '12px' }}>
|
||||||
|
<TYPE.main>
|
||||||
|
<Trans>Current {baseCurrency?.symbol} Price:</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
<TYPE.main>
|
||||||
|
{price ? (
|
||||||
|
<TYPE.main>
|
||||||
|
<RowFixed>
|
||||||
|
<HoverInlineText
|
||||||
|
maxCharacters={20}
|
||||||
|
text={invertPrice ? price?.invert()?.toSignificant(5) : price?.toSignificant(5)}
|
||||||
|
/>{' '}
|
||||||
|
<span style={{ marginLeft: '4px' }}>{quoteCurrency?.symbol}</span>
|
||||||
|
</RowFixed>
|
||||||
|
</TYPE.main>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
)}
|
||||||
|
</TYPE.main>
|
||||||
|
</RowBetween>
|
||||||
|
<BlueCard
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: ' 1.5rem 1.25rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AlertCircle color={theme.text1} size={32} style={{ marginBottom: '12px', opacity: 0.8 }} />
|
||||||
|
<TYPE.body
|
||||||
|
fontSize={14}
|
||||||
|
style={{ marginBottom: 8, fontWeight: 500, opacity: 0.8 }}
|
||||||
|
textAlign="center"
|
||||||
|
>
|
||||||
|
You are the first liquidity provider for this Uniswap V3 pool.
|
||||||
|
</TYPE.body>
|
||||||
|
|
||||||
|
<TYPE.body fontWeight={500} textAlign="center" fontSize={14} style={{ opacity: 0.8 }}>
|
||||||
|
The transaction cost will be much higher as it includes the gas to create the pool.
|
||||||
|
</TYPE.body>
|
||||||
|
</BlueCard>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</LightCard>
|
</DynamicSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{outOfRange ? (
|
<DynamicSection
|
||||||
<YellowCard padding="8px 12px" borderRadius="12px">
|
gap="md"
|
||||||
<RowBetween>
|
disabled={!feeAmount || invalidPool || (noLiquidity && !startPriceTypedValue)}
|
||||||
<AlertTriangle stroke={theme.yellow3} size="16px" />
|
|
||||||
<TYPE.yellow ml="12px" fontSize="12px">
|
|
||||||
<Trans>
|
|
||||||
Your position will not earn fees or be used in trades until the market price moves into your
|
|
||||||
range.
|
|
||||||
</Trans>
|
|
||||||
</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">
|
|
||||||
<Trans>Invalid range selected. The min price must be lower than the max price.</Trans>
|
|
||||||
</TYPE.yellow>
|
|
||||||
</RowBetween>
|
|
||||||
</YellowCard>
|
|
||||||
) : null}
|
|
||||||
</DynamicSection>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<DynamicSection
|
|
||||||
disabled={tickLower === undefined || tickUpper === undefined || invalidPool || invalidRange}
|
|
||||||
>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<TYPE.label>{hasExistingPosition ? 'Add more liquidity' : t`Deposit Amounts`}</TYPE.label>
|
|
||||||
|
|
||||||
<CurrencyInputPanel
|
|
||||||
value={formattedAmounts[Field.CURRENCY_A]}
|
|
||||||
onUserInput={onFieldAInput}
|
|
||||||
onMax={() => {
|
|
||||||
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
|
|
||||||
}}
|
|
||||||
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
|
|
||||||
currency={currencies[Field.CURRENCY_A]}
|
|
||||||
id="add-liquidity-input-tokena"
|
|
||||||
fiatValue={usdcValues[Field.CURRENCY_A]}
|
|
||||||
showCommonBases
|
|
||||||
locked={depositADisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CurrencyInputPanel
|
|
||||||
value={formattedAmounts[Field.CURRENCY_B]}
|
|
||||||
onUserInput={onFieldBInput}
|
|
||||||
onMax={() => {
|
|
||||||
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
|
|
||||||
}}
|
|
||||||
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
|
|
||||||
fiatValue={usdcValues[Field.CURRENCY_B]}
|
|
||||||
currency={currencies[Field.CURRENCY_B]}
|
|
||||||
id="add-liquidity-input-tokenb"
|
|
||||||
showCommonBases
|
|
||||||
locked={depositBDisabled}
|
|
||||||
/>
|
|
||||||
</AutoColumn>
|
|
||||||
</DynamicSection>
|
|
||||||
<div>
|
|
||||||
{addIsUnsupported ? (
|
|
||||||
<ButtonPrimary disabled={true} borderRadius="12px" padding={'12px'}>
|
|
||||||
<TYPE.main mb="4px">
|
|
||||||
<Trans>Unsupported Asset</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
</ButtonPrimary>
|
|
||||||
) : !account ? (
|
|
||||||
<ButtonLight onClick={toggleWalletModal} borderRadius="12px" padding={'12px'}>
|
|
||||||
<Trans>Connect wallet</Trans>
|
|
||||||
</ButtonLight>
|
|
||||||
) : (
|
|
||||||
<AutoColumn gap={'md'}>
|
|
||||||
{(approvalA === ApprovalState.NOT_APPROVED ||
|
|
||||||
approvalA === ApprovalState.PENDING ||
|
|
||||||
approvalB === ApprovalState.NOT_APPROVED ||
|
|
||||||
approvalB === ApprovalState.PENDING) &&
|
|
||||||
isValid && (
|
|
||||||
<RowBetween>
|
|
||||||
{showApprovalA && (
|
|
||||||
<ButtonPrimary
|
|
||||||
borderRadius="12px"
|
|
||||||
padding={'12px'}
|
|
||||||
onClick={approveACallback}
|
|
||||||
disabled={approvalA === ApprovalState.PENDING}
|
|
||||||
width={showApprovalB ? '48%' : '100%'}
|
|
||||||
>
|
|
||||||
{approvalA === ApprovalState.PENDING ? (
|
|
||||||
<Dots>
|
|
||||||
<Trans>Approving {currencies[Field.CURRENCY_A]?.symbol}</Trans>
|
|
||||||
</Dots>
|
|
||||||
) : (
|
|
||||||
<Trans>Approve {currencies[Field.CURRENCY_A]?.symbol}</Trans>
|
|
||||||
)}
|
|
||||||
</ButtonPrimary>
|
|
||||||
)}
|
|
||||||
{showApprovalB && (
|
|
||||||
<ButtonPrimary
|
|
||||||
borderRadius="12px"
|
|
||||||
padding={'12px'}
|
|
||||||
onClick={approveBCallback}
|
|
||||||
disabled={approvalB === ApprovalState.PENDING}
|
|
||||||
width={showApprovalA ? '48%' : '100%'}
|
|
||||||
>
|
|
||||||
{approvalB === ApprovalState.PENDING ? (
|
|
||||||
<Dots>
|
|
||||||
<Trans>Approving {currencies[Field.CURRENCY_B]?.symbol}</Trans>
|
|
||||||
</Dots>
|
|
||||||
) : (
|
|
||||||
<Trans>Approve {currencies[Field.CURRENCY_B]?.symbol}</Trans>
|
|
||||||
)}
|
|
||||||
</ButtonPrimary>
|
|
||||||
)}
|
|
||||||
</RowBetween>
|
|
||||||
)}
|
|
||||||
<ButtonError
|
|
||||||
onClick={() => {
|
|
||||||
expertMode ? onAdd() : setShowConfirm(true)
|
|
||||||
}}
|
|
||||||
disabled={
|
|
||||||
!isValid ||
|
|
||||||
(!argentWalletContract && approvalA !== ApprovalState.APPROVED && !depositADisabled) ||
|
|
||||||
(!argentWalletContract && approvalB !== ApprovalState.APPROVED && !depositBDisabled)
|
|
||||||
}
|
|
||||||
error={!isValid && !!parsedAmounts[Field.CURRENCY_A] && !!parsedAmounts[Field.CURRENCY_B]}
|
|
||||||
>
|
>
|
||||||
<Text fontWeight={500}>{errorMessage ? errorMessage : <Trans>Add</Trans>}</Text>
|
<RowBetween>
|
||||||
</ButtonError>
|
<TYPE.label>
|
||||||
</AutoColumn>
|
<Trans>Set Price Range</Trans>
|
||||||
|
</TYPE.label>
|
||||||
|
|
||||||
|
{baseCurrency && quoteCurrency ? (
|
||||||
|
<RateToggle
|
||||||
|
currencyA={baseCurrency}
|
||||||
|
currencyB={quoteCurrency}
|
||||||
|
handleRateToggle={() => {
|
||||||
|
onLeftRangeInput('')
|
||||||
|
onRightRangeInput('')
|
||||||
|
history.push(
|
||||||
|
`/add/${currencyIdB as string}/${currencyIdA as string}${
|
||||||
|
feeAmount ? '/' + feeAmount : ''
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</RowBetween>
|
||||||
|
<TYPE.main fontSize={14} fontWeight={400} style={{ marginBottom: '.5rem', lineHeight: '125%' }}>
|
||||||
|
<Trans>
|
||||||
|
Your liquidity will only earn fees when the market price of the pair is within your range.{' '}
|
||||||
|
<ExternalLink
|
||||||
|
href={'https://docs.uniswap.org/concepts/introduction/liquidity-user-guide#4-set-price-range'}
|
||||||
|
style={{ fontSize: '14px' }}
|
||||||
|
>
|
||||||
|
Need help picking a range?
|
||||||
|
</ExternalLink>
|
||||||
|
</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
|
||||||
|
<RangeSelector
|
||||||
|
priceLower={priceLower}
|
||||||
|
priceUpper={priceUpper}
|
||||||
|
getDecrementLower={getDecrementLower}
|
||||||
|
getIncrementLower={getIncrementLower}
|
||||||
|
getDecrementUpper={getDecrementUpper}
|
||||||
|
getIncrementUpper={getIncrementUpper}
|
||||||
|
onLeftRangeInput={onLeftRangeInput}
|
||||||
|
onRightRangeInput={onRightRangeInput}
|
||||||
|
currencyA={baseCurrency}
|
||||||
|
currencyB={quoteCurrency}
|
||||||
|
feeAmount={feeAmount}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{price && baseCurrency && quoteCurrency && !noLiquidity && (
|
||||||
|
<LightCard style={{ padding: '12px' }}>
|
||||||
|
<AutoColumn gap="4px">
|
||||||
|
<TYPE.main fontWeight={500} textAlign="center" fontSize={12}>
|
||||||
|
<Trans>Current Price</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
<TYPE.body fontWeight={500} textAlign="center" fontSize={20}>
|
||||||
|
<HoverInlineText
|
||||||
|
maxCharacters={20}
|
||||||
|
text={invertPrice ? price.invert().toSignificant(6) : price.toSignificant(6)}
|
||||||
|
/>{' '}
|
||||||
|
</TYPE.body>
|
||||||
|
<TYPE.main fontWeight={500} textAlign="center" fontSize={12}>
|
||||||
|
<Trans>
|
||||||
|
{quoteCurrency?.symbol} per {baseCurrency.symbol}
|
||||||
|
</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
</AutoColumn>
|
||||||
|
</LightCard>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{outOfRange ? (
|
||||||
|
<YellowCard padding="8px 12px" borderRadius="12px">
|
||||||
|
<RowBetween>
|
||||||
|
<AlertTriangle stroke={theme.yellow3} size="16px" />
|
||||||
|
<TYPE.yellow ml="12px" fontSize="12px">
|
||||||
|
<Trans>
|
||||||
|
Your position will not earn fees or be used in trades until the market price moves into
|
||||||
|
your range.
|
||||||
|
</Trans>
|
||||||
|
</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">
|
||||||
|
<Trans>Invalid range selected. The min price must be lower than the max price.</Trans>
|
||||||
|
</TYPE.yellow>
|
||||||
|
</RowBetween>
|
||||||
|
</YellowCard>
|
||||||
|
) : null}
|
||||||
|
</DynamicSection>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</AutoColumn>
|
<DynamicSection
|
||||||
</Wrapper>
|
disabled={tickLower === undefined || tickUpper === undefined || invalidPool || invalidRange}
|
||||||
</AppBody>
|
>
|
||||||
{addIsUnsupported && (
|
<AutoColumn gap="md">
|
||||||
<UnsupportedCurrencyFooter
|
<TYPE.label>{hasExistingPosition ? 'Add more liquidity' : t`Deposit Amounts`}</TYPE.label>
|
||||||
show={addIsUnsupported}
|
|
||||||
currencies={[currencies.CURRENCY_A, currencies.CURRENCY_B]}
|
<CurrencyInputPanel
|
||||||
/>
|
value={formattedAmounts[Field.CURRENCY_A]}
|
||||||
)}
|
onUserInput={onFieldAInput}
|
||||||
</ScrollablePage>
|
onMax={() => {
|
||||||
|
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
|
||||||
|
}}
|
||||||
|
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
|
||||||
|
currency={currencies[Field.CURRENCY_A]}
|
||||||
|
id="add-liquidity-input-tokena"
|
||||||
|
fiatValue={usdcValues[Field.CURRENCY_A]}
|
||||||
|
showCommonBases
|
||||||
|
locked={depositADisabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CurrencyInputPanel
|
||||||
|
value={formattedAmounts[Field.CURRENCY_B]}
|
||||||
|
onUserInput={onFieldBInput}
|
||||||
|
onMax={() => {
|
||||||
|
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
|
||||||
|
}}
|
||||||
|
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
|
||||||
|
fiatValue={usdcValues[Field.CURRENCY_B]}
|
||||||
|
currency={currencies[Field.CURRENCY_B]}
|
||||||
|
id="add-liquidity-input-tokenb"
|
||||||
|
showCommonBases
|
||||||
|
locked={depositBDisabled}
|
||||||
|
/>
|
||||||
|
</AutoColumn>
|
||||||
|
</DynamicSection>
|
||||||
|
<div>
|
||||||
|
{addIsUnsupported ? (
|
||||||
|
<ButtonPrimary disabled={true} borderRadius="12px" padding={'12px'}>
|
||||||
|
<TYPE.main mb="4px">
|
||||||
|
<Trans>Unsupported Asset</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
</ButtonPrimary>
|
||||||
|
) : !account ? (
|
||||||
|
<ButtonLight onClick={toggleWalletModal} borderRadius="12px" padding={'12px'}>
|
||||||
|
<Trans>Connect wallet</Trans>
|
||||||
|
</ButtonLight>
|
||||||
|
) : (
|
||||||
|
<AutoColumn gap={'md'}>
|
||||||
|
{(approvalA === ApprovalState.NOT_APPROVED ||
|
||||||
|
approvalA === ApprovalState.PENDING ||
|
||||||
|
approvalB === ApprovalState.NOT_APPROVED ||
|
||||||
|
approvalB === ApprovalState.PENDING) &&
|
||||||
|
isValid && (
|
||||||
|
<RowBetween>
|
||||||
|
{showApprovalA && (
|
||||||
|
<ButtonPrimary
|
||||||
|
borderRadius="12px"
|
||||||
|
padding={'12px'}
|
||||||
|
onClick={approveACallback}
|
||||||
|
disabled={approvalA === ApprovalState.PENDING}
|
||||||
|
width={showApprovalB ? '48%' : '100%'}
|
||||||
|
>
|
||||||
|
{approvalA === ApprovalState.PENDING ? (
|
||||||
|
<Dots>
|
||||||
|
<Trans>Approving {currencies[Field.CURRENCY_A]?.symbol}</Trans>
|
||||||
|
</Dots>
|
||||||
|
) : (
|
||||||
|
<Trans>Approve {currencies[Field.CURRENCY_A]?.symbol}</Trans>
|
||||||
|
)}
|
||||||
|
</ButtonPrimary>
|
||||||
|
)}
|
||||||
|
{showApprovalB && (
|
||||||
|
<ButtonPrimary
|
||||||
|
borderRadius="12px"
|
||||||
|
padding={'12px'}
|
||||||
|
onClick={approveBCallback}
|
||||||
|
disabled={approvalB === ApprovalState.PENDING}
|
||||||
|
width={showApprovalA ? '48%' : '100%'}
|
||||||
|
>
|
||||||
|
{approvalB === ApprovalState.PENDING ? (
|
||||||
|
<Dots>
|
||||||
|
<Trans>Approving {currencies[Field.CURRENCY_B]?.symbol}</Trans>
|
||||||
|
</Dots>
|
||||||
|
) : (
|
||||||
|
<Trans>Approve {currencies[Field.CURRENCY_B]?.symbol}</Trans>
|
||||||
|
)}
|
||||||
|
</ButtonPrimary>
|
||||||
|
)}
|
||||||
|
</RowBetween>
|
||||||
|
)}
|
||||||
|
<ButtonError
|
||||||
|
onClick={() => {
|
||||||
|
expertMode ? onAdd() : setShowConfirm(true)
|
||||||
|
}}
|
||||||
|
disabled={
|
||||||
|
!isValid ||
|
||||||
|
(!argentWalletContract && approvalA !== ApprovalState.APPROVED && !depositADisabled) ||
|
||||||
|
(!argentWalletContract && approvalB !== ApprovalState.APPROVED && !depositBDisabled)
|
||||||
|
}
|
||||||
|
error={!isValid && !!parsedAmounts[Field.CURRENCY_A] && !!parsedAmounts[Field.CURRENCY_B]}
|
||||||
|
>
|
||||||
|
<Text fontWeight={500}>{errorMessage ? errorMessage : <Trans>Add</Trans>}</Text>
|
||||||
|
</ButtonError>
|
||||||
|
</AutoColumn>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</AutoColumn>
|
||||||
|
</Wrapper>
|
||||||
|
</AppBody>
|
||||||
|
{addIsUnsupported && (
|
||||||
|
<UnsupportedCurrencyFooter
|
||||||
|
show={addIsUnsupported}
|
||||||
|
currencies={[currencies.CURRENCY_A, currencies.CURRENCY_B]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ScrollablePage>
|
||||||
|
<SwitchLocaleLink />
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ import { ConfirmAddModalBottom } from './ConfirmAddModalBottom'
|
|||||||
import { currencyId } from '../../utils/currencyId'
|
import { currencyId } from '../../utils/currencyId'
|
||||||
import { PoolPriceBar } from './PoolPriceBar'
|
import { PoolPriceBar } from './PoolPriceBar'
|
||||||
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
||||||
|
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
||||||
import { t, Trans } from '@lingui/macro'
|
import { t, Trans } from '@lingui/macro'
|
||||||
|
|
||||||
const DEFAULT_ADD_V2_SLIPPAGE_TOLERANCE = new Percent(50, 10_000)
|
const DEFAULT_ADD_V2_SLIPPAGE_TOLERANCE = new Percent(50, 10_000)
|
||||||
@ -485,6 +486,8 @@ export default function AddLiquidity({
|
|||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
</AppBody>
|
</AppBody>
|
||||||
|
<SwitchLocaleLink />
|
||||||
|
|
||||||
{!addIsUnsupported ? (
|
{!addIsUnsupported ? (
|
||||||
pair && !noLiquidity && pairState !== PairState.INVALID ? (
|
pair && !noLiquidity && pairState !== PairState.INVALID ? (
|
||||||
<AutoColumn style={{ minWidth: '20rem', width: '100%', maxWidth: '400px', marginTop: '1rem' }}>
|
<AutoColumn style={{ minWidth: '20rem', width: '100%', maxWidth: '400px', marginTop: '1rem' }}>
|
||||||
|
@ -16,6 +16,7 @@ import { Dots } from '../../components/swap/styleds'
|
|||||||
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
|
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
|
||||||
import MigrateV2PositionCard from 'components/PositionCard/V2'
|
import MigrateV2PositionCard from 'components/PositionCard/V2'
|
||||||
import MigrateSushiPositionCard from 'components/PositionCard/Sushi'
|
import MigrateSushiPositionCard from 'components/PositionCard/Sushi'
|
||||||
|
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
||||||
import { PairState, useV2Pairs } from 'hooks/useV2Pairs'
|
import { PairState, useV2Pairs } from 'hooks/useV2Pairs'
|
||||||
import { getCreate2Address } from '@ethersproject/address'
|
import { getCreate2Address } from '@ethersproject/address'
|
||||||
import { pack, keccak256 } from '@ethersproject/solidity'
|
import { pack, keccak256 } from '@ethersproject/solidity'
|
||||||
@ -110,73 +111,76 @@ export default function MigrateV2() {
|
|||||||
const v2IsLoading = fetchingPairBalances || v2Pairs.some(([pairState]) => pairState === PairState.LOADING)
|
const v2IsLoading = fetchingPairBalances || v2Pairs.some(([pairState]) => pairState === PairState.LOADING)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BodyWrapper style={{ padding: 24 }}>
|
<>
|
||||||
<AutoColumn gap="16px">
|
<BodyWrapper style={{ padding: 24 }}>
|
||||||
<AutoRow style={{ alignItems: 'center', justifyContent: 'space-between' }} gap="8px">
|
<AutoColumn gap="16px">
|
||||||
<BackArrow to="/pool/v2" />
|
<AutoRow style={{ alignItems: 'center', justifyContent: 'space-between' }} gap="8px">
|
||||||
<TYPE.mediumHeader>
|
<BackArrow to="/pool/v2" />
|
||||||
<Trans>Migrate V2 Liquidity</Trans>
|
<TYPE.mediumHeader>
|
||||||
</TYPE.mediumHeader>
|
<Trans>Migrate V2 Liquidity</Trans>
|
||||||
<div>
|
</TYPE.mediumHeader>
|
||||||
<QuestionHelper text={<Trans>Migrate your liquidity tokens from Uniswap V2 to Uniswap V3.</Trans>} />
|
<div>
|
||||||
</div>
|
<QuestionHelper text={<Trans>Migrate your liquidity tokens from Uniswap V2 to Uniswap V3.</Trans>} />
|
||||||
</AutoRow>
|
</div>
|
||||||
|
</AutoRow>
|
||||||
|
|
||||||
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
|
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
|
||||||
<Trans>
|
|
||||||
For each pool shown below, click migrate to remove your liquidity from Uniswap V2 and deposit it into
|
|
||||||
Uniswap V3.
|
|
||||||
</Trans>
|
|
||||||
</TYPE.body>
|
|
||||||
|
|
||||||
{!account ? (
|
|
||||||
<LightCard padding="40px">
|
|
||||||
<TYPE.body color={theme.text3} textAlign="center">
|
|
||||||
<Trans>Connect to a wallet to view your V2 liquidity.</Trans>
|
|
||||||
</TYPE.body>
|
|
||||||
</LightCard>
|
|
||||||
) : v2IsLoading ? (
|
|
||||||
<LightCard padding="40px">
|
|
||||||
<TYPE.body color={theme.text3} textAlign="center">
|
|
||||||
<Dots>
|
|
||||||
<Trans>Loading</Trans>
|
|
||||||
</Dots>
|
|
||||||
</TYPE.body>
|
|
||||||
</LightCard>
|
|
||||||
) : v2Pairs.filter(([, pair]) => !!pair).length > 0 ? (
|
|
||||||
<>
|
|
||||||
{v2Pairs
|
|
||||||
.filter(([, pair]) => !!pair)
|
|
||||||
.map(([, pair]) => (
|
|
||||||
<MigrateV2PositionCard key={(pair as Pair).liquidityToken.address} pair={pair as Pair} />
|
|
||||||
))}
|
|
||||||
|
|
||||||
{tokenPairsWithSushiBalance.map(({ sushiLiquidityToken, tokens }) => {
|
|
||||||
return (
|
|
||||||
<MigrateSushiPositionCard
|
|
||||||
key={(sushiLiquidityToken as Token).address}
|
|
||||||
tokenA={tokens[0]}
|
|
||||||
tokenB={tokens[1]}
|
|
||||||
liquidityToken={sushiLiquidityToken as Token}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<EmptyState message={<Trans>No V2 Liquidity found.</Trans>} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<AutoColumn justify={'center'} gap="md">
|
|
||||||
<Text textAlign="center" fontSize={14} style={{ padding: '.5rem 0 .5rem 0' }}>
|
|
||||||
<Trans>
|
<Trans>
|
||||||
Don’t see one of your v2 positions?{' '}
|
For each pool shown below, click migrate to remove your liquidity from Uniswap V2 and deposit it into
|
||||||
<StyledInternalLink id="import-pool-link" to={'/find?origin=/migrate/v2'}>
|
Uniswap V3.
|
||||||
Import it.
|
|
||||||
</StyledInternalLink>
|
|
||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</TYPE.body>
|
||||||
|
|
||||||
|
{!account ? (
|
||||||
|
<LightCard padding="40px">
|
||||||
|
<TYPE.body color={theme.text3} textAlign="center">
|
||||||
|
<Trans>Connect to a wallet to view your V2 liquidity.</Trans>
|
||||||
|
</TYPE.body>
|
||||||
|
</LightCard>
|
||||||
|
) : v2IsLoading ? (
|
||||||
|
<LightCard padding="40px">
|
||||||
|
<TYPE.body color={theme.text3} textAlign="center">
|
||||||
|
<Dots>
|
||||||
|
<Trans>Loading</Trans>
|
||||||
|
</Dots>
|
||||||
|
</TYPE.body>
|
||||||
|
</LightCard>
|
||||||
|
) : v2Pairs.filter(([, pair]) => !!pair).length > 0 ? (
|
||||||
|
<>
|
||||||
|
{v2Pairs
|
||||||
|
.filter(([, pair]) => !!pair)
|
||||||
|
.map(([, pair]) => (
|
||||||
|
<MigrateV2PositionCard key={(pair as Pair).liquidityToken.address} pair={pair as Pair} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
{tokenPairsWithSushiBalance.map(({ sushiLiquidityToken, tokens }) => {
|
||||||
|
return (
|
||||||
|
<MigrateSushiPositionCard
|
||||||
|
key={(sushiLiquidityToken as Token).address}
|
||||||
|
tokenA={tokens[0]}
|
||||||
|
tokenB={tokens[1]}
|
||||||
|
liquidityToken={sushiLiquidityToken as Token}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<EmptyState message={<Trans>No V2 Liquidity found.</Trans>} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<AutoColumn justify={'center'} gap="md">
|
||||||
|
<Text textAlign="center" fontSize={14} style={{ padding: '.5rem 0 .5rem 0' }}>
|
||||||
|
<Trans>
|
||||||
|
Don’t see one of your v2 positions?{' '}
|
||||||
|
<StyledInternalLink id="import-pool-link" to={'/find?origin=/migrate/v2'}>
|
||||||
|
Import it.
|
||||||
|
</StyledInternalLink>
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</AutoColumn>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</AutoColumn>
|
</BodyWrapper>
|
||||||
</BodyWrapper>
|
<SwitchLocaleLink />
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import useTheme from '../../hooks/useTheme'
|
|||||||
import RateToggle from '../../components/RateToggle'
|
import RateToggle from '../../components/RateToggle'
|
||||||
import { useSingleCallResult } from 'state/multicall/hooks'
|
import { useSingleCallResult } from 'state/multicall/hooks'
|
||||||
import RangeBadge from '../../components/Badge/RangeBadge'
|
import RangeBadge from '../../components/Badge/RangeBadge'
|
||||||
|
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
|
||||||
import useUSDCPrice from 'hooks/useUSDCPrice'
|
import useUSDCPrice from 'hooks/useUSDCPrice'
|
||||||
import Loader from 'components/Loader'
|
import Loader from 'components/Loader'
|
||||||
import Toggle from 'components/Toggle'
|
import Toggle from 'components/Toggle'
|
||||||
@ -495,338 +496,341 @@ export function PositionPage({
|
|||||||
<div />
|
<div />
|
||||||
</LoadingRows>
|
</LoadingRows>
|
||||||
) : (
|
) : (
|
||||||
<PageWrapper>
|
<>
|
||||||
<TransactionConfirmationModal
|
<PageWrapper>
|
||||||
isOpen={showConfirm}
|
<TransactionConfirmationModal
|
||||||
onDismiss={() => setShowConfirm(false)}
|
isOpen={showConfirm}
|
||||||
attemptingTxn={collecting}
|
onDismiss={() => setShowConfirm(false)}
|
||||||
hash={collectMigrationHash ?? ''}
|
attemptingTxn={collecting}
|
||||||
content={() => (
|
hash={collectMigrationHash ?? ''}
|
||||||
<ConfirmationModalContent
|
content={() => (
|
||||||
title={<Trans>Claim fees</Trans>}
|
<ConfirmationModalContent
|
||||||
onDismiss={() => setShowConfirm(false)}
|
title={<Trans>Claim fees</Trans>}
|
||||||
topContent={modalHeader}
|
onDismiss={() => setShowConfirm(false)}
|
||||||
/>
|
topContent={modalHeader}
|
||||||
)}
|
|
||||||
pendingText={<Trans>Collecting fees</Trans>}
|
|
||||||
/>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<AutoColumn gap="sm">
|
|
||||||
<Link style={{ textDecoration: 'none', width: 'fit-content', marginBottom: '0.5rem' }} to="/pool">
|
|
||||||
<HoverText>
|
|
||||||
<Trans>← Back to Pools Overview</Trans>
|
|
||||||
</HoverText>
|
|
||||||
</Link>
|
|
||||||
<ResponsiveRow>
|
|
||||||
<RowFixed>
|
|
||||||
<DoubleCurrencyLogo currency0={currencyBase} currency1={currencyQuote} size={24} margin={true} />
|
|
||||||
<TYPE.label fontSize={'24px'} mr="10px">
|
|
||||||
{currencyQuote?.symbol} / {currencyBase?.symbol}
|
|
||||||
</TYPE.label>
|
|
||||||
<Badge style={{ marginRight: '8px' }}>
|
|
||||||
<BadgeText>
|
|
||||||
<Trans>{new Percent(feeAmount, 1_000_000).toSignificant()}%</Trans>
|
|
||||||
</BadgeText>
|
|
||||||
</Badge>
|
|
||||||
<RangeBadge removed={removed} inRange={inRange} />
|
|
||||||
</RowFixed>
|
|
||||||
{ownsNFT && (
|
|
||||||
<RowFixed>
|
|
||||||
{currency0 && currency1 && feeAmount && tokenId ? (
|
|
||||||
<ButtonGray
|
|
||||||
as={Link}
|
|
||||||
to={`/increase/${currencyId(currency0)}/${currencyId(currency1)}/${feeAmount}/${tokenId}`}
|
|
||||||
width="fit-content"
|
|
||||||
padding="6px 8px"
|
|
||||||
borderRadius="12px"
|
|
||||||
style={{ marginRight: '8px' }}
|
|
||||||
>
|
|
||||||
<Trans>Increase Liquidity</Trans>
|
|
||||||
</ButtonGray>
|
|
||||||
) : null}
|
|
||||||
{tokenId && !removed ? (
|
|
||||||
<ResponsiveButtonPrimary
|
|
||||||
as={Link}
|
|
||||||
to={`/remove/${tokenId}`}
|
|
||||||
width="fit-content"
|
|
||||||
padding="6px 8px"
|
|
||||||
borderRadius="12px"
|
|
||||||
>
|
|
||||||
<Trans>Remove Liquidity</Trans>
|
|
||||||
</ResponsiveButtonPrimary>
|
|
||||||
) : null}
|
|
||||||
</RowFixed>
|
|
||||||
)}
|
|
||||||
</ResponsiveRow>
|
|
||||||
<RowBetween></RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
<ResponsiveRow align="flex-start">
|
|
||||||
{'result' in metadata ? (
|
|
||||||
<DarkCard
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
marginRight: '12px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ marginRight: 12 }}>
|
|
||||||
<NFT image={metadata.result.image} height={400} />
|
|
||||||
</div>
|
|
||||||
{typeof chainId === 'number' && owner && !ownsNFT ? (
|
|
||||||
<ExternalLink href={getExplorerLink(chainId, owner, ExplorerDataType.ADDRESS)}>
|
|
||||||
<Trans>Owner</Trans>
|
|
||||||
</ExternalLink>
|
|
||||||
) : null}
|
|
||||||
</DarkCard>
|
|
||||||
) : (
|
|
||||||
<DarkCard
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
style={{
|
|
||||||
marginRight: '12px',
|
|
||||||
minWidth: '340px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Loader />
|
|
||||||
</DarkCard>
|
|
||||||
)}
|
|
||||||
<AutoColumn gap="sm" style={{ width: '100%', height: '100%' }}>
|
|
||||||
<DarkCard>
|
|
||||||
<AutoColumn gap="md" style={{ width: '100%' }}>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<Label>
|
|
||||||
<Trans>Liquidity</Trans>
|
|
||||||
</Label>
|
|
||||||
{fiatValueOfLiquidity?.greaterThan(new Fraction(1, 100)) ? (
|
|
||||||
<TYPE.largeHeader fontSize="36px" fontWeight={500}>
|
|
||||||
<Trans>${fiatValueOfLiquidity.toFixed(2, { groupSeparator: ',' })}</Trans>
|
|
||||||
</TYPE.largeHeader>
|
|
||||||
) : (
|
|
||||||
<TYPE.largeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
|
||||||
<Trans>$-</Trans>
|
|
||||||
</TYPE.largeHeader>
|
|
||||||
)}
|
|
||||||
</AutoColumn>
|
|
||||||
<LightCard padding="12px 16px">
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween>
|
|
||||||
<LinkedCurrency chainId={chainId} currency={currencyQuote} />
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.main>
|
|
||||||
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
|
|
||||||
</TYPE.main>
|
|
||||||
{typeof ratio === 'number' && !removed ? (
|
|
||||||
<Badge style={{ marginLeft: '10px' }}>
|
|
||||||
<TYPE.main fontSize={11}>
|
|
||||||
<Trans>{inverted ? ratio : 100 - ratio}%</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
</Badge>
|
|
||||||
) : null}
|
|
||||||
</RowFixed>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<LinkedCurrency chainId={chainId} currency={currencyBase} />
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.main>
|
|
||||||
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
|
|
||||||
</TYPE.main>
|
|
||||||
{typeof ratio === 'number' && !removed ? (
|
|
||||||
<Badge style={{ marginLeft: '10px' }}>
|
|
||||||
<TYPE.main color={theme.text2} fontSize={11}>
|
|
||||||
<Trans>{inverted ? 100 - ratio : ratio}%</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
</Badge>
|
|
||||||
) : null}
|
|
||||||
</RowFixed>
|
|
||||||
</RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
</LightCard>
|
|
||||||
</AutoColumn>
|
|
||||||
</DarkCard>
|
|
||||||
<DarkCard>
|
|
||||||
<AutoColumn gap="md" style={{ width: '100%' }}>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween style={{ alignItems: 'flex-start' }}>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<Label>
|
|
||||||
<Trans>Unclaimed fees</Trans>
|
|
||||||
</Label>
|
|
||||||
{fiatValueOfFees?.greaterThan(new Fraction(1, 100)) ? (
|
|
||||||
<TYPE.largeHeader color={theme.green1} fontSize="36px" fontWeight={500}>
|
|
||||||
<Trans>${fiatValueOfFees.toFixed(2, { groupSeparator: ',' })}</Trans>
|
|
||||||
</TYPE.largeHeader>
|
|
||||||
) : (
|
|
||||||
<TYPE.largeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
|
||||||
<Trans>$-</Trans>
|
|
||||||
</TYPE.largeHeader>
|
|
||||||
)}
|
|
||||||
</AutoColumn>
|
|
||||||
{ownsNFT && (feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) || !!collectMigrationHash) ? (
|
|
||||||
<ButtonConfirmed
|
|
||||||
disabled={collecting || !!collectMigrationHash}
|
|
||||||
confirmed={!!collectMigrationHash && !isCollectPending}
|
|
||||||
width="fit-content"
|
|
||||||
style={{ borderRadius: '12px' }}
|
|
||||||
padding="4px 8px"
|
|
||||||
onClick={() => setShowConfirm(true)}
|
|
||||||
>
|
|
||||||
{!!collectMigrationHash && !isCollectPending ? (
|
|
||||||
<TYPE.main color={theme.text1}>
|
|
||||||
<Trans> Collected</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
) : isCollectPending || collecting ? (
|
|
||||||
<TYPE.main color={theme.text1}>
|
|
||||||
{' '}
|
|
||||||
<Dots>
|
|
||||||
<Trans>Collecting</Trans>
|
|
||||||
</Dots>
|
|
||||||
</TYPE.main>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<TYPE.main color={theme.white}>
|
|
||||||
<Trans>Collect fees</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</ButtonConfirmed>
|
|
||||||
) : null}
|
|
||||||
</RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
<LightCard padding="12px 16px">
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween>
|
|
||||||
<RowFixed>
|
|
||||||
<CurrencyLogo
|
|
||||||
currency={feeValueUpper?.currency}
|
|
||||||
size={'20px'}
|
|
||||||
style={{ marginRight: '0.5rem' }}
|
|
||||||
/>
|
|
||||||
<TYPE.main>{feeValueUpper?.currency?.symbol}</TYPE.main>
|
|
||||||
</RowFixed>
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.main>{feeValueUpper ? formatCurrencyAmount(feeValueUpper, 4) : '-'}</TYPE.main>
|
|
||||||
</RowFixed>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<RowFixed>
|
|
||||||
<CurrencyLogo
|
|
||||||
currency={feeValueLower?.currency}
|
|
||||||
size={'20px'}
|
|
||||||
style={{ marginRight: '0.5rem' }}
|
|
||||||
/>
|
|
||||||
<TYPE.main>{feeValueLower?.currency?.symbol}</TYPE.main>
|
|
||||||
</RowFixed>
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.main>{feeValueLower ? formatCurrencyAmount(feeValueLower, 4) : '-'}</TYPE.main>
|
|
||||||
</RowFixed>
|
|
||||||
</RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
</LightCard>
|
|
||||||
{ownsNFT &&
|
|
||||||
(feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) &&
|
|
||||||
currency0 &&
|
|
||||||
currency1 &&
|
|
||||||
(currency0.isNative || currency1.isNative) &&
|
|
||||||
!collectMigrationHash ? (
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween>
|
|
||||||
<TYPE.main>
|
|
||||||
<Trans>Collect as WETH</Trans>
|
|
||||||
</TYPE.main>
|
|
||||||
<Toggle
|
|
||||||
id="receive-as-weth"
|
|
||||||
isActive={receiveWETH}
|
|
||||||
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
|
|
||||||
/>
|
|
||||||
</RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
) : null}
|
|
||||||
</AutoColumn>
|
|
||||||
</DarkCard>
|
|
||||||
</AutoColumn>
|
|
||||||
</ResponsiveRow>
|
|
||||||
<DarkCard>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween>
|
|
||||||
<RowFixed>
|
|
||||||
<Label display="flex" style={{ marginRight: '12px' }}>
|
|
||||||
<Trans>Price range</Trans>
|
|
||||||
</Label>
|
|
||||||
<HideExtraSmall>
|
|
||||||
<>
|
|
||||||
<RangeBadge removed={removed} inRange={inRange} />
|
|
||||||
<span style={{ width: '8px' }} />
|
|
||||||
</>
|
|
||||||
</HideExtraSmall>
|
|
||||||
</RowFixed>
|
|
||||||
<RowFixed>
|
|
||||||
{currencyBase && currencyQuote && (
|
|
||||||
<RateToggle
|
|
||||||
currencyA={currencyBase}
|
|
||||||
currencyB={currencyQuote}
|
|
||||||
handleRateToggle={() => setManuallyInverted(!manuallyInverted)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</RowFixed>
|
|
||||||
</RowBetween>
|
|
||||||
|
|
||||||
<RowBetween>
|
|
||||||
<LightCard padding="12px" width="100%">
|
|
||||||
<AutoColumn gap="8px" justify="center">
|
|
||||||
<ExtentsText>
|
|
||||||
<Trans>Min price</Trans>
|
|
||||||
</ExtentsText>
|
|
||||||
<TYPE.mediumHeader textAlign="center">{priceLower?.toSignificant(5)}</TYPE.mediumHeader>
|
|
||||||
<ExtentsText>
|
|
||||||
{' '}
|
|
||||||
<Trans>
|
|
||||||
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
|
||||||
</Trans>
|
|
||||||
</ExtentsText>
|
|
||||||
|
|
||||||
{inRange && (
|
|
||||||
<TYPE.small color={theme.text3}>
|
|
||||||
<Trans>Your position will be 100% {currencyBase?.symbol} at this price.</Trans>
|
|
||||||
</TYPE.small>
|
|
||||||
)}
|
|
||||||
</AutoColumn>
|
|
||||||
</LightCard>
|
|
||||||
|
|
||||||
<DoubleArrow>⟷</DoubleArrow>
|
|
||||||
<LightCard padding="12px" width="100%">
|
|
||||||
<AutoColumn gap="8px" justify="center">
|
|
||||||
<ExtentsText>
|
|
||||||
<Trans>Max price</Trans>
|
|
||||||
</ExtentsText>
|
|
||||||
<TYPE.mediumHeader textAlign="center">{priceUpper?.toSignificant(5)}</TYPE.mediumHeader>
|
|
||||||
<ExtentsText>
|
|
||||||
{' '}
|
|
||||||
<Trans>
|
|
||||||
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
|
||||||
</Trans>
|
|
||||||
</ExtentsText>
|
|
||||||
|
|
||||||
{inRange && (
|
|
||||||
<TYPE.small color={theme.text3}>
|
|
||||||
<Trans>Your position will be 100% {currencyQuote?.symbol} at this price.</Trans>
|
|
||||||
</TYPE.small>
|
|
||||||
)}
|
|
||||||
</AutoColumn>
|
|
||||||
</LightCard>
|
|
||||||
</RowBetween>
|
|
||||||
<CurrentPriceCard
|
|
||||||
inverted={inverted}
|
|
||||||
pool={pool}
|
|
||||||
currencyQuote={currencyQuote}
|
|
||||||
currencyBase={currencyBase}
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
pendingText={<Trans>Collecting fees</Trans>}
|
||||||
|
/>
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<AutoColumn gap="sm">
|
||||||
|
<Link style={{ textDecoration: 'none', width: 'fit-content', marginBottom: '0.5rem' }} to="/pool">
|
||||||
|
<HoverText>
|
||||||
|
<Trans>← Back to Pools Overview</Trans>
|
||||||
|
</HoverText>
|
||||||
|
</Link>
|
||||||
|
<ResponsiveRow>
|
||||||
|
<RowFixed>
|
||||||
|
<DoubleCurrencyLogo currency0={currencyBase} currency1={currencyQuote} size={24} margin={true} />
|
||||||
|
<TYPE.label fontSize={'24px'} mr="10px">
|
||||||
|
{currencyQuote?.symbol} / {currencyBase?.symbol}
|
||||||
|
</TYPE.label>
|
||||||
|
<Badge style={{ marginRight: '8px' }}>
|
||||||
|
<BadgeText>
|
||||||
|
<Trans>{new Percent(feeAmount, 1_000_000).toSignificant()}%</Trans>
|
||||||
|
</BadgeText>
|
||||||
|
</Badge>
|
||||||
|
<RangeBadge removed={removed} inRange={inRange} />
|
||||||
|
</RowFixed>
|
||||||
|
{ownsNFT && (
|
||||||
|
<RowFixed>
|
||||||
|
{currency0 && currency1 && feeAmount && tokenId ? (
|
||||||
|
<ButtonGray
|
||||||
|
as={Link}
|
||||||
|
to={`/increase/${currencyId(currency0)}/${currencyId(currency1)}/${feeAmount}/${tokenId}`}
|
||||||
|
width="fit-content"
|
||||||
|
padding="6px 8px"
|
||||||
|
borderRadius="12px"
|
||||||
|
style={{ marginRight: '8px' }}
|
||||||
|
>
|
||||||
|
<Trans>Increase Liquidity</Trans>
|
||||||
|
</ButtonGray>
|
||||||
|
) : null}
|
||||||
|
{tokenId && !removed ? (
|
||||||
|
<ResponsiveButtonPrimary
|
||||||
|
as={Link}
|
||||||
|
to={`/remove/${tokenId}`}
|
||||||
|
width="fit-content"
|
||||||
|
padding="6px 8px"
|
||||||
|
borderRadius="12px"
|
||||||
|
>
|
||||||
|
<Trans>Remove Liquidity</Trans>
|
||||||
|
</ResponsiveButtonPrimary>
|
||||||
|
) : null}
|
||||||
|
</RowFixed>
|
||||||
|
)}
|
||||||
|
</ResponsiveRow>
|
||||||
|
<RowBetween></RowBetween>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</DarkCard>
|
<ResponsiveRow align="flex-start">
|
||||||
</AutoColumn>
|
{'result' in metadata ? (
|
||||||
</PageWrapper>
|
<DarkCard
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
marginRight: '12px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ marginRight: 12 }}>
|
||||||
|
<NFT image={metadata.result.image} height={400} />
|
||||||
|
</div>
|
||||||
|
{typeof chainId === 'number' && owner && !ownsNFT ? (
|
||||||
|
<ExternalLink href={getExplorerLink(chainId, owner, ExplorerDataType.ADDRESS)}>
|
||||||
|
<Trans>Owner</Trans>
|
||||||
|
</ExternalLink>
|
||||||
|
) : null}
|
||||||
|
</DarkCard>
|
||||||
|
) : (
|
||||||
|
<DarkCard
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
marginRight: '12px',
|
||||||
|
minWidth: '340px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Loader />
|
||||||
|
</DarkCard>
|
||||||
|
)}
|
||||||
|
<AutoColumn gap="sm" style={{ width: '100%', height: '100%' }}>
|
||||||
|
<DarkCard>
|
||||||
|
<AutoColumn gap="md" style={{ width: '100%' }}>
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<Label>
|
||||||
|
<Trans>Liquidity</Trans>
|
||||||
|
</Label>
|
||||||
|
{fiatValueOfLiquidity?.greaterThan(new Fraction(1, 100)) ? (
|
||||||
|
<TYPE.largeHeader fontSize="36px" fontWeight={500}>
|
||||||
|
<Trans>${fiatValueOfLiquidity.toFixed(2, { groupSeparator: ',' })}</Trans>
|
||||||
|
</TYPE.largeHeader>
|
||||||
|
) : (
|
||||||
|
<TYPE.largeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
||||||
|
<Trans>$-</Trans>
|
||||||
|
</TYPE.largeHeader>
|
||||||
|
)}
|
||||||
|
</AutoColumn>
|
||||||
|
<LightCard padding="12px 16px">
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween>
|
||||||
|
<LinkedCurrency chainId={chainId} currency={currencyQuote} />
|
||||||
|
<RowFixed>
|
||||||
|
<TYPE.main>
|
||||||
|
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
|
||||||
|
</TYPE.main>
|
||||||
|
{typeof ratio === 'number' && !removed ? (
|
||||||
|
<Badge style={{ marginLeft: '10px' }}>
|
||||||
|
<TYPE.main fontSize={11}>
|
||||||
|
<Trans>{inverted ? ratio : 100 - ratio}%</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
</Badge>
|
||||||
|
) : null}
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
<RowBetween>
|
||||||
|
<LinkedCurrency chainId={chainId} currency={currencyBase} />
|
||||||
|
<RowFixed>
|
||||||
|
<TYPE.main>
|
||||||
|
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
|
||||||
|
</TYPE.main>
|
||||||
|
{typeof ratio === 'number' && !removed ? (
|
||||||
|
<Badge style={{ marginLeft: '10px' }}>
|
||||||
|
<TYPE.main color={theme.text2} fontSize={11}>
|
||||||
|
<Trans>{inverted ? 100 - ratio : ratio}%</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
</Badge>
|
||||||
|
) : null}
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>
|
||||||
|
</LightCard>
|
||||||
|
</AutoColumn>
|
||||||
|
</DarkCard>
|
||||||
|
<DarkCard>
|
||||||
|
<AutoColumn gap="md" style={{ width: '100%' }}>
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween style={{ alignItems: 'flex-start' }}>
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<Label>
|
||||||
|
<Trans>Unclaimed fees</Trans>
|
||||||
|
</Label>
|
||||||
|
{fiatValueOfFees?.greaterThan(new Fraction(1, 100)) ? (
|
||||||
|
<TYPE.largeHeader color={theme.green1} fontSize="36px" fontWeight={500}>
|
||||||
|
<Trans>${fiatValueOfFees.toFixed(2, { groupSeparator: ',' })}</Trans>
|
||||||
|
</TYPE.largeHeader>
|
||||||
|
) : (
|
||||||
|
<TYPE.largeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
||||||
|
<Trans>$-</Trans>
|
||||||
|
</TYPE.largeHeader>
|
||||||
|
)}
|
||||||
|
</AutoColumn>
|
||||||
|
{ownsNFT && (feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0) || !!collectMigrationHash) ? (
|
||||||
|
<ButtonConfirmed
|
||||||
|
disabled={collecting || !!collectMigrationHash}
|
||||||
|
confirmed={!!collectMigrationHash && !isCollectPending}
|
||||||
|
width="fit-content"
|
||||||
|
style={{ borderRadius: '12px' }}
|
||||||
|
padding="4px 8px"
|
||||||
|
onClick={() => setShowConfirm(true)}
|
||||||
|
>
|
||||||
|
{!!collectMigrationHash && !isCollectPending ? (
|
||||||
|
<TYPE.main color={theme.text1}>
|
||||||
|
<Trans> Collected</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
) : isCollectPending || collecting ? (
|
||||||
|
<TYPE.main color={theme.text1}>
|
||||||
|
{' '}
|
||||||
|
<Dots>
|
||||||
|
<Trans>Collecting</Trans>
|
||||||
|
</Dots>
|
||||||
|
</TYPE.main>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<TYPE.main color={theme.white}>
|
||||||
|
<Trans>Collect fees</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ButtonConfirmed>
|
||||||
|
) : null}
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>
|
||||||
|
<LightCard padding="12px 16px">
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween>
|
||||||
|
<RowFixed>
|
||||||
|
<CurrencyLogo
|
||||||
|
currency={feeValueUpper?.currency}
|
||||||
|
size={'20px'}
|
||||||
|
style={{ marginRight: '0.5rem' }}
|
||||||
|
/>
|
||||||
|
<TYPE.main>{feeValueUpper?.currency?.symbol}</TYPE.main>
|
||||||
|
</RowFixed>
|
||||||
|
<RowFixed>
|
||||||
|
<TYPE.main>{feeValueUpper ? formatCurrencyAmount(feeValueUpper, 4) : '-'}</TYPE.main>
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
<RowBetween>
|
||||||
|
<RowFixed>
|
||||||
|
<CurrencyLogo
|
||||||
|
currency={feeValueLower?.currency}
|
||||||
|
size={'20px'}
|
||||||
|
style={{ marginRight: '0.5rem' }}
|
||||||
|
/>
|
||||||
|
<TYPE.main>{feeValueLower?.currency?.symbol}</TYPE.main>
|
||||||
|
</RowFixed>
|
||||||
|
<RowFixed>
|
||||||
|
<TYPE.main>{feeValueLower ? formatCurrencyAmount(feeValueLower, 4) : '-'}</TYPE.main>
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>
|
||||||
|
</LightCard>
|
||||||
|
{ownsNFT &&
|
||||||
|
(feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) &&
|
||||||
|
currency0 &&
|
||||||
|
currency1 &&
|
||||||
|
(currency0.isNative || currency1.isNative) &&
|
||||||
|
!collectMigrationHash ? (
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween>
|
||||||
|
<TYPE.main>
|
||||||
|
<Trans>Collect as WETH</Trans>
|
||||||
|
</TYPE.main>
|
||||||
|
<Toggle
|
||||||
|
id="receive-as-weth"
|
||||||
|
isActive={receiveWETH}
|
||||||
|
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
|
||||||
|
/>
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>
|
||||||
|
) : null}
|
||||||
|
</AutoColumn>
|
||||||
|
</DarkCard>
|
||||||
|
</AutoColumn>
|
||||||
|
</ResponsiveRow>
|
||||||
|
<DarkCard>
|
||||||
|
<AutoColumn gap="md">
|
||||||
|
<RowBetween>
|
||||||
|
<RowFixed>
|
||||||
|
<Label display="flex" style={{ marginRight: '12px' }}>
|
||||||
|
<Trans>Price range</Trans>
|
||||||
|
</Label>
|
||||||
|
<HideExtraSmall>
|
||||||
|
<>
|
||||||
|
<RangeBadge removed={removed} inRange={inRange} />
|
||||||
|
<span style={{ width: '8px' }} />
|
||||||
|
</>
|
||||||
|
</HideExtraSmall>
|
||||||
|
</RowFixed>
|
||||||
|
<RowFixed>
|
||||||
|
{currencyBase && currencyQuote && (
|
||||||
|
<RateToggle
|
||||||
|
currencyA={currencyBase}
|
||||||
|
currencyB={currencyQuote}
|
||||||
|
handleRateToggle={() => setManuallyInverted(!manuallyInverted)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
|
||||||
|
<RowBetween>
|
||||||
|
<LightCard padding="12px" width="100%">
|
||||||
|
<AutoColumn gap="8px" justify="center">
|
||||||
|
<ExtentsText>
|
||||||
|
<Trans>Min price</Trans>
|
||||||
|
</ExtentsText>
|
||||||
|
<TYPE.mediumHeader textAlign="center">{priceLower?.toSignificant(5)}</TYPE.mediumHeader>
|
||||||
|
<ExtentsText>
|
||||||
|
{' '}
|
||||||
|
<Trans>
|
||||||
|
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
||||||
|
</Trans>
|
||||||
|
</ExtentsText>
|
||||||
|
|
||||||
|
{inRange && (
|
||||||
|
<TYPE.small color={theme.text3}>
|
||||||
|
<Trans>Your position will be 100% {currencyBase?.symbol} at this price.</Trans>
|
||||||
|
</TYPE.small>
|
||||||
|
)}
|
||||||
|
</AutoColumn>
|
||||||
|
</LightCard>
|
||||||
|
|
||||||
|
<DoubleArrow>⟷</DoubleArrow>
|
||||||
|
<LightCard padding="12px" width="100%">
|
||||||
|
<AutoColumn gap="8px" justify="center">
|
||||||
|
<ExtentsText>
|
||||||
|
<Trans>Max price</Trans>
|
||||||
|
</ExtentsText>
|
||||||
|
<TYPE.mediumHeader textAlign="center">{priceUpper?.toSignificant(5)}</TYPE.mediumHeader>
|
||||||
|
<ExtentsText>
|
||||||
|
{' '}
|
||||||
|
<Trans>
|
||||||
|
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
||||||
|
</Trans>
|
||||||
|
</ExtentsText>
|
||||||
|
|
||||||
|
{inRange && (
|
||||||
|
<TYPE.small color={theme.text3}>
|
||||||
|
<Trans>Your position will be 100% {currencyQuote?.symbol} at this price.</Trans>
|
||||||
|
</TYPE.small>
|
||||||
|
)}
|
||||||
|
</AutoColumn>
|
||||||
|
</LightCard>
|
||||||
|
</RowBetween>
|
||||||
|
<CurrentPriceCard
|
||||||
|
inverted={inverted}
|
||||||
|
pool={pool}
|
||||||
|
currencyQuote={currencyQuote}
|
||||||
|
currencyBase={currencyBase}
|
||||||
|
/>
|
||||||
|
</AutoColumn>
|
||||||
|
</DarkCard>
|
||||||
|
</AutoColumn>
|
||||||
|
</PageWrapper>
|
||||||
|
<SwitchLocaleLink />
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import { useV2Pairs } from '../../hooks/useV2Pairs'
|
|||||||
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
|
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
|
||||||
import { Dots } from '../../components/swap/styleds'
|
import { Dots } from '../../components/swap/styleds'
|
||||||
import { CardSection, DataCard, CardNoise, CardBGImage } from '../../components/earn/styled'
|
import { CardSection, DataCard, CardNoise, CardBGImage } from '../../components/earn/styled'
|
||||||
|
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
|
||||||
import { useStakingInfo } from '../../state/stake/hooks'
|
import { useStakingInfo } from '../../state/stake/hooks'
|
||||||
import { BIG_INT_ZERO } from '../../constants/misc'
|
import { BIG_INT_ZERO } from '../../constants/misc'
|
||||||
import { Pair } from '@uniswap/v2-sdk'
|
import { Pair } from '@uniswap/v2-sdk'
|
||||||
@ -256,6 +257,7 @@ export default function Pool() {
|
|||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
<SwitchLocaleLink />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import { FindPoolTabs } from '../../components/NavigationTabs'
|
|||||||
import { MinimalPositionCard } from '../../components/PositionCard'
|
import { MinimalPositionCard } from '../../components/PositionCard'
|
||||||
import Row from '../../components/Row'
|
import Row from '../../components/Row'
|
||||||
import CurrencySearchModal from '../../components/SearchModal/CurrencySearchModal'
|
import CurrencySearchModal from '../../components/SearchModal/CurrencySearchModal'
|
||||||
|
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
|
||||||
import { ExtendedEther } from '../../constants/tokens'
|
import { ExtendedEther } from '../../constants/tokens'
|
||||||
import { PairState, useV2Pair } from '../../hooks/useV2Pairs'
|
import { PairState, useV2Pair } from '../../hooks/useV2Pairs'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
@ -93,136 +94,139 @@ export default function PoolFinder() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBody>
|
<>
|
||||||
<FindPoolTabs origin={query.get('origin') ?? '/pool/v2'} />
|
<AppBody>
|
||||||
<AutoColumn style={{ padding: '1rem' }} gap="md">
|
<FindPoolTabs origin={query.get('origin') ?? '/pool/v2'} />
|
||||||
<BlueCard>
|
<AutoColumn style={{ padding: '1rem' }} gap="md">
|
||||||
<AutoColumn gap="10px">
|
<BlueCard>
|
||||||
<TYPE.link fontWeight={400} color={'primaryText1'}>
|
<AutoColumn gap="10px">
|
||||||
<Trans>
|
<TYPE.link fontWeight={400} color={'primaryText1'}>
|
||||||
<b>Tip:</b> Use this tool to find v2 pools that don't automatically appear in the interface.
|
<Trans>
|
||||||
</Trans>
|
<b>Tip:</b> Use this tool to find v2 pools that don't automatically appear in the interface.
|
||||||
</TYPE.link>
|
</Trans>
|
||||||
</AutoColumn>
|
</TYPE.link>
|
||||||
</BlueCard>
|
</AutoColumn>
|
||||||
<ButtonDropdownLight
|
</BlueCard>
|
||||||
onClick={() => {
|
<ButtonDropdownLight
|
||||||
setShowSearch(true)
|
onClick={() => {
|
||||||
setActiveField(Fields.TOKEN0)
|
setShowSearch(true)
|
||||||
}}
|
setActiveField(Fields.TOKEN0)
|
||||||
>
|
}}
|
||||||
{currency0 ? (
|
|
||||||
<Row>
|
|
||||||
<CurrencyLogo currency={currency0} />
|
|
||||||
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
|
||||||
{currency0.symbol}
|
|
||||||
</Text>
|
|
||||||
</Row>
|
|
||||||
) : (
|
|
||||||
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
|
||||||
<Trans>Select a token</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</ButtonDropdownLight>
|
|
||||||
|
|
||||||
<ColumnCenter>
|
|
||||||
<Plus size="16" color="#888D9B" />
|
|
||||||
</ColumnCenter>
|
|
||||||
|
|
||||||
<ButtonDropdownLight
|
|
||||||
onClick={() => {
|
|
||||||
setShowSearch(true)
|
|
||||||
setActiveField(Fields.TOKEN1)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{currency1 ? (
|
|
||||||
<Row>
|
|
||||||
<CurrencyLogo currency={currency1} />
|
|
||||||
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
|
||||||
{currency1.symbol}
|
|
||||||
</Text>
|
|
||||||
</Row>
|
|
||||||
) : (
|
|
||||||
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
|
||||||
<Trans>Select a token</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</ButtonDropdownLight>
|
|
||||||
|
|
||||||
{hasPosition && (
|
|
||||||
<ColumnCenter
|
|
||||||
style={{ justifyItems: 'center', backgroundColor: '', padding: '12px 0px', borderRadius: '12px' }}
|
|
||||||
>
|
>
|
||||||
<Text textAlign="center" fontWeight={500}>
|
{currency0 ? (
|
||||||
<Trans>Pool Found!</Trans>
|
<Row>
|
||||||
</Text>
|
<CurrencyLogo currency={currency0} />
|
||||||
<StyledInternalLink to={`/pool/v2`}>
|
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
||||||
<Text textAlign="center">
|
{currency0.symbol}
|
||||||
<Trans>Manage this pool.</Trans>
|
</Text>
|
||||||
</Text>
|
</Row>
|
||||||
</StyledInternalLink>
|
|
||||||
</ColumnCenter>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{currency0 && currency1 ? (
|
|
||||||
pairState === PairState.EXISTS ? (
|
|
||||||
hasPosition && pair ? (
|
|
||||||
<MinimalPositionCard pair={pair} border="1px solid #CED0D9" />
|
|
||||||
) : (
|
) : (
|
||||||
|
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
||||||
|
<Trans>Select a token</Trans>
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</ButtonDropdownLight>
|
||||||
|
|
||||||
|
<ColumnCenter>
|
||||||
|
<Plus size="16" color="#888D9B" />
|
||||||
|
</ColumnCenter>
|
||||||
|
|
||||||
|
<ButtonDropdownLight
|
||||||
|
onClick={() => {
|
||||||
|
setShowSearch(true)
|
||||||
|
setActiveField(Fields.TOKEN1)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{currency1 ? (
|
||||||
|
<Row>
|
||||||
|
<CurrencyLogo currency={currency1} />
|
||||||
|
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
||||||
|
{currency1.symbol}
|
||||||
|
</Text>
|
||||||
|
</Row>
|
||||||
|
) : (
|
||||||
|
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
||||||
|
<Trans>Select a token</Trans>
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</ButtonDropdownLight>
|
||||||
|
|
||||||
|
{hasPosition && (
|
||||||
|
<ColumnCenter
|
||||||
|
style={{ justifyItems: 'center', backgroundColor: '', padding: '12px 0px', borderRadius: '12px' }}
|
||||||
|
>
|
||||||
|
<Text textAlign="center" fontWeight={500}>
|
||||||
|
<Trans>Pool Found!</Trans>
|
||||||
|
</Text>
|
||||||
|
<StyledInternalLink to={`/pool/v2`}>
|
||||||
|
<Text textAlign="center">
|
||||||
|
<Trans>Manage this pool.</Trans>
|
||||||
|
</Text>
|
||||||
|
</StyledInternalLink>
|
||||||
|
</ColumnCenter>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currency0 && currency1 ? (
|
||||||
|
pairState === PairState.EXISTS ? (
|
||||||
|
hasPosition && pair ? (
|
||||||
|
<MinimalPositionCard pair={pair} border="1px solid #CED0D9" />
|
||||||
|
) : (
|
||||||
|
<LightCard padding="45px 10px">
|
||||||
|
<AutoColumn gap="sm" justify="center">
|
||||||
|
<Text textAlign="center">
|
||||||
|
<Trans>You don’t have liquidity in this pool yet.</Trans>
|
||||||
|
</Text>
|
||||||
|
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
|
||||||
|
<Text textAlign="center">
|
||||||
|
<Trans>Add liquidity.</Trans>
|
||||||
|
</Text>
|
||||||
|
</StyledInternalLink>
|
||||||
|
</AutoColumn>
|
||||||
|
</LightCard>
|
||||||
|
)
|
||||||
|
) : validPairNoLiquidity ? (
|
||||||
<LightCard padding="45px 10px">
|
<LightCard padding="45px 10px">
|
||||||
<AutoColumn gap="sm" justify="center">
|
<AutoColumn gap="sm" justify="center">
|
||||||
<Text textAlign="center">
|
<Text textAlign="center">
|
||||||
<Trans>You don’t have liquidity in this pool yet.</Trans>
|
<Trans>No pool found.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
|
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
|
||||||
<Text textAlign="center">
|
<Trans>Create pool.</Trans>
|
||||||
<Trans>Add liquidity.</Trans>
|
|
||||||
</Text>
|
|
||||||
</StyledInternalLink>
|
</StyledInternalLink>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</LightCard>
|
</LightCard>
|
||||||
)
|
) : pairState === PairState.INVALID ? (
|
||||||
) : validPairNoLiquidity ? (
|
<LightCard padding="45px 10px">
|
||||||
<LightCard padding="45px 10px">
|
<AutoColumn gap="sm" justify="center">
|
||||||
<AutoColumn gap="sm" justify="center">
|
<Text textAlign="center" fontWeight={500}>
|
||||||
<Text textAlign="center">
|
<Trans>Invalid pair.</Trans>
|
||||||
<Trans>No pool found.</Trans>
|
</Text>
|
||||||
</Text>
|
</AutoColumn>
|
||||||
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
|
</LightCard>
|
||||||
<Trans>Create pool.</Trans>
|
) : pairState === PairState.LOADING ? (
|
||||||
</StyledInternalLink>
|
<LightCard padding="45px 10px">
|
||||||
</AutoColumn>
|
<AutoColumn gap="sm" justify="center">
|
||||||
</LightCard>
|
<Text textAlign="center">
|
||||||
) : pairState === PairState.INVALID ? (
|
<Trans>Loading</Trans>
|
||||||
<LightCard padding="45px 10px">
|
<Dots />
|
||||||
<AutoColumn gap="sm" justify="center">
|
</Text>
|
||||||
<Text textAlign="center" fontWeight={500}>
|
</AutoColumn>
|
||||||
<Trans>Invalid pair.</Trans>
|
</LightCard>
|
||||||
</Text>
|
) : null
|
||||||
</AutoColumn>
|
) : (
|
||||||
</LightCard>
|
prerequisiteMessage
|
||||||
) : pairState === PairState.LOADING ? (
|
)}
|
||||||
<LightCard padding="45px 10px">
|
</AutoColumn>
|
||||||
<AutoColumn gap="sm" justify="center">
|
|
||||||
<Text textAlign="center">
|
|
||||||
<Trans>Loading</Trans>
|
|
||||||
<Dots />
|
|
||||||
</Text>
|
|
||||||
</AutoColumn>
|
|
||||||
</LightCard>
|
|
||||||
) : null
|
|
||||||
) : (
|
|
||||||
prerequisiteMessage
|
|
||||||
)}
|
|
||||||
</AutoColumn>
|
|
||||||
|
|
||||||
<CurrencySearchModal
|
<CurrencySearchModal
|
||||||
isOpen={showSearch}
|
isOpen={showSearch}
|
||||||
onCurrencySelect={handleCurrencySelect}
|
onCurrencySelect={handleCurrencySelect}
|
||||||
onDismiss={handleSearchDismiss}
|
onDismiss={handleSearchDismiss}
|
||||||
showCommonBases
|
showCommonBases
|
||||||
selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined}
|
selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined}
|
||||||
/>
|
/>
|
||||||
</AppBody>
|
</AppBody>
|
||||||
|
<SwitchLocaleLink />
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user