feat: implement-page-viewed-event-for-all-main-pages-of-app (#4089)
* init commit: initial constants for pages, implement vote page viewed * implement swap * implement pool * remove charts * simplify shouldLogImpression
This commit is contained in:
parent
64cb9f3ff2
commit
4e0c9b36a0
@ -17,7 +17,10 @@ export enum EventName {
|
||||
* Known pages in the app. Highest order context.
|
||||
*/
|
||||
export const enum PageName {
|
||||
EXPLORE_PAGE = 'explore-page',
|
||||
POOL_PAGE = 'pool-page',
|
||||
SWAP_PAGE = 'swap-page',
|
||||
VOTE_PAGE = 'vote-page',
|
||||
// alphabetize additional page names.
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ import { getAddress, isAddress } from '@ethersproject/address'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import { ButtonError } from 'components/Button'
|
||||
import { BlueCard } from 'components/Card'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
@ -225,63 +227,66 @@ ${bodyValue}
|
||||
}
|
||||
|
||||
return (
|
||||
<AppBody {...{ maxWidth: '800px' }}>
|
||||
<CreateProposalTabs />
|
||||
<CreateProposalWrapper>
|
||||
<BlueCard>
|
||||
<AutoColumn gap="10px">
|
||||
<ThemedText.Link fontWeight={400} color={'primaryText1'}>
|
||||
<Trans>
|
||||
<strong>Tip:</strong> Select an action and describe your proposal for the community. The proposal cannot
|
||||
be modified after submission, so please verify all information before submitting. The voting period will
|
||||
begin immediately and last for 7 days. To propose a custom action,{' '}
|
||||
<ExternalLink href="https://uniswap.org/docs/v2/governance/governance-reference/#propose">
|
||||
read the docs
|
||||
</ExternalLink>
|
||||
.
|
||||
</Trans>
|
||||
</ThemedText.Link>
|
||||
</AutoColumn>
|
||||
</BlueCard>
|
||||
<Trace page={PageName.VOTE_PAGE} shouldLogImpression>
|
||||
<AppBody {...{ maxWidth: '800px' }}>
|
||||
<CreateProposalTabs />
|
||||
<CreateProposalWrapper>
|
||||
<BlueCard>
|
||||
<AutoColumn gap="10px">
|
||||
<ThemedText.Link fontWeight={400} color={'primaryText1'}>
|
||||
<Trans>
|
||||
<strong>Tip:</strong> Select an action and describe your proposal for the community. The proposal
|
||||
cannot be modified after submission, so please verify all information before submitting. The voting
|
||||
period will begin immediately and last for 7 days. To propose a custom action,{' '}
|
||||
<ExternalLink href="https://uniswap.org/docs/v2/governance/governance-reference/#propose">
|
||||
read the docs
|
||||
</ExternalLink>
|
||||
.
|
||||
</Trans>
|
||||
</ThemedText.Link>
|
||||
</AutoColumn>
|
||||
</BlueCard>
|
||||
|
||||
<ProposalActionSelector onClick={handleActionSelectorClick} proposalAction={proposalAction} />
|
||||
<ProposalActionDetail
|
||||
proposalAction={proposalAction}
|
||||
currency={currencyValue}
|
||||
amount={amountValue}
|
||||
toAddress={toAddressValue}
|
||||
onCurrencySelect={handleCurrencySelect}
|
||||
onAmountInput={handleAmountInput}
|
||||
onToAddressInput={handleToAddressInput}
|
||||
<ProposalActionSelector onClick={handleActionSelectorClick} proposalAction={proposalAction} />
|
||||
<ProposalActionDetail
|
||||
proposalAction={proposalAction}
|
||||
currency={currencyValue}
|
||||
amount={amountValue}
|
||||
toAddress={toAddressValue}
|
||||
onCurrencySelect={handleCurrencySelect}
|
||||
onAmountInput={handleAmountInput}
|
||||
onToAddressInput={handleToAddressInput}
|
||||
/>
|
||||
<ProposalEditor
|
||||
title={titleValue}
|
||||
body={bodyValue}
|
||||
onTitleInput={handleTitleInput}
|
||||
onBodyInput={handleBodyInput}
|
||||
/>
|
||||
<CreateProposalButton
|
||||
proposalThreshold={proposalThreshold}
|
||||
hasActiveOrPendingProposal={
|
||||
latestProposalData?.status === ProposalState.ACTIVE ||
|
||||
latestProposalData?.status === ProposalState.PENDING
|
||||
}
|
||||
hasEnoughVote={hasEnoughVote}
|
||||
isFormInvalid={isFormInvalid}
|
||||
handleCreateProposal={handleCreateProposal}
|
||||
/>
|
||||
{!hasEnoughVote ? (
|
||||
<AutonomousProposalCTA>
|
||||
Don’t have 2.5M votes? Anyone can create an autonomous proposal using{' '}
|
||||
<ExternalLink href="https://fish.vote">fish.vote</ExternalLink>
|
||||
</AutonomousProposalCTA>
|
||||
) : null}
|
||||
</CreateProposalWrapper>
|
||||
<ProposalActionSelectorModal
|
||||
isOpen={modalOpen}
|
||||
onDismiss={handleDismissActionSelector}
|
||||
onProposalActionSelect={(proposalAction: ProposalAction) => handleActionChange(proposalAction)}
|
||||
/>
|
||||
<ProposalEditor
|
||||
title={titleValue}
|
||||
body={bodyValue}
|
||||
onTitleInput={handleTitleInput}
|
||||
onBodyInput={handleBodyInput}
|
||||
/>
|
||||
<CreateProposalButton
|
||||
proposalThreshold={proposalThreshold}
|
||||
hasActiveOrPendingProposal={
|
||||
latestProposalData?.status === ProposalState.ACTIVE || latestProposalData?.status === ProposalState.PENDING
|
||||
}
|
||||
hasEnoughVote={hasEnoughVote}
|
||||
isFormInvalid={isFormInvalid}
|
||||
handleCreateProposal={handleCreateProposal}
|
||||
/>
|
||||
{!hasEnoughVote ? (
|
||||
<AutonomousProposalCTA>
|
||||
Don’t have 2.5M votes? Anyone can create an autonomous proposal using{' '}
|
||||
<ExternalLink href="https://fish.vote">fish.vote</ExternalLink>
|
||||
</AutonomousProposalCTA>
|
||||
) : null}
|
||||
</CreateProposalWrapper>
|
||||
<ProposalActionSelectorModal
|
||||
isOpen={modalOpen}
|
||||
onDismiss={handleDismissActionSelector}
|
||||
onProposalActionSelect={(proposalAction: ProposalAction) => handleActionChange(proposalAction)}
|
||||
/>
|
||||
<ProposalSubmissionModal isOpen={attempting} hash={hash} onDismiss={handleDismissSubmissionModal} />
|
||||
</AppBody>
|
||||
<ProposalSubmissionModal isOpen={attempting} hash={hash} onDismiss={handleDismissSubmissionModal} />
|
||||
</AppBody>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Fraction, Percent, Price, Token } from '@uniswap/sdk-core'
|
||||
import { NonfungiblePositionManager, Pool, Position } from '@uniswap/v3-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import { sendEvent } from 'components/analytics'
|
||||
import Badge from 'components/Badge'
|
||||
import { ButtonConfirmed, ButtonGray, ButtonPrimary } from 'components/Button'
|
||||
@ -567,344 +569,347 @@ export function PositionPage({
|
||||
<div />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<>
|
||||
<PageWrapper>
|
||||
<TransactionConfirmationModal
|
||||
isOpen={showConfirm}
|
||||
onDismiss={() => setShowConfirm(false)}
|
||||
attemptingTxn={collecting}
|
||||
hash={collectMigrationHash ?? ''}
|
||||
content={() => (
|
||||
<ConfirmationModalContent
|
||||
title={<Trans>Claim fees</Trans>}
|
||||
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} />
|
||||
<ThemedText.Label fontSize={'24px'} mr="10px">
|
||||
{currencyQuote?.symbol} / {currencyBase?.symbol}
|
||||
</ThemedText.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)) ? (
|
||||
<ThemedText.LargeHeader fontSize="36px" fontWeight={500}>
|
||||
<Trans>${fiatValueOfLiquidity.toFixed(2, { groupSeparator: ',' })}</Trans>
|
||||
</ThemedText.LargeHeader>
|
||||
) : (
|
||||
<ThemedText.LargeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
||||
<Trans>$-</Trans>
|
||||
</ThemedText.LargeHeader>
|
||||
)}
|
||||
</AutoColumn>
|
||||
<LightCard padding="12px 16px">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<LinkedCurrency chainId={chainId} currency={currencyQuote} />
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
|
||||
</ThemedText.Main>
|
||||
{typeof ratio === 'number' && !removed ? (
|
||||
<Badge style={{ marginLeft: '10px' }}>
|
||||
<ThemedText.Main fontSize={11}>
|
||||
<Trans>{inverted ? ratio : 100 - ratio}%</Trans>
|
||||
</ThemedText.Main>
|
||||
</Badge>
|
||||
) : null}
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<LinkedCurrency chainId={chainId} currency={currencyBase} />
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
|
||||
</ThemedText.Main>
|
||||
{typeof ratio === 'number' && !removed ? (
|
||||
<Badge style={{ marginLeft: '10px' }}>
|
||||
<ThemedText.Main color={theme.text2} fontSize={11}>
|
||||
<Trans>{inverted ? 100 - ratio : ratio}%</Trans>
|
||||
</ThemedText.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)) ? (
|
||||
<ThemedText.LargeHeader color={theme.green1} fontSize="36px" fontWeight={500}>
|
||||
<Trans>${fiatValueOfFees.toFixed(2, { groupSeparator: ',' })}</Trans>
|
||||
</ThemedText.LargeHeader>
|
||||
) : (
|
||||
<ThemedText.LargeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
||||
<Trans>$-</Trans>
|
||||
</ThemedText.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 ? (
|
||||
<ThemedText.Main color={theme.text1}>
|
||||
<Trans> Collected</Trans>
|
||||
</ThemedText.Main>
|
||||
) : isCollectPending || collecting ? (
|
||||
<ThemedText.Main color={theme.text1}>
|
||||
{' '}
|
||||
<Dots>
|
||||
<Trans>Collecting</Trans>
|
||||
</Dots>
|
||||
</ThemedText.Main>
|
||||
) : (
|
||||
<>
|
||||
<ThemedText.Main color={theme.white}>
|
||||
<Trans>Collect fees</Trans>
|
||||
</ThemedText.Main>
|
||||
</>
|
||||
)}
|
||||
</ButtonConfirmed>
|
||||
) : null}
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
<LightCard padding="12px 16px">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<CurrencyLogo
|
||||
currency={feeValueUpper?.currency}
|
||||
size={'20px'}
|
||||
style={{ marginRight: '0.5rem' }}
|
||||
/>
|
||||
<ThemedText.Main>{feeValueUpper?.currency?.symbol}</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{feeValueUpper ? formatCurrencyAmount(feeValueUpper, 4) : '-'}
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<CurrencyLogo
|
||||
currency={feeValueLower?.currency}
|
||||
size={'20px'}
|
||||
style={{ marginRight: '0.5rem' }}
|
||||
/>
|
||||
<ThemedText.Main>{feeValueLower?.currency?.symbol}</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{feeValueLower ? formatCurrencyAmount(feeValueLower, 4) : '-'}
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
{showCollectAsWeth && (
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
<Trans>Collect as {nativeWrappedSymbol}</Trans>
|
||||
</ThemedText.Main>
|
||||
<Toggle
|
||||
id="receive-as-weth"
|
||||
isActive={receiveWETH}
|
||||
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
|
||||
/>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
)}
|
||||
</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>
|
||||
<ThemedText.MediumHeader textAlign="center">
|
||||
{formatTickPrice(priceLower, tickAtLimit, Bound.LOWER)}
|
||||
</ThemedText.MediumHeader>
|
||||
<ExtentsText>
|
||||
{' '}
|
||||
<Trans>
|
||||
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
||||
</Trans>
|
||||
</ExtentsText>
|
||||
|
||||
{inRange && (
|
||||
<ThemedText.Small color={theme.text3}>
|
||||
<Trans>Your position will be 100% {currencyBase?.symbol} at this price.</Trans>
|
||||
</ThemedText.Small>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
|
||||
<DoubleArrow>⟷</DoubleArrow>
|
||||
<LightCard padding="12px" width="100%">
|
||||
<AutoColumn gap="8px" justify="center">
|
||||
<ExtentsText>
|
||||
<Trans>Max price</Trans>
|
||||
</ExtentsText>
|
||||
<ThemedText.MediumHeader textAlign="center">
|
||||
{formatTickPrice(priceUpper, tickAtLimit, Bound.UPPER)}
|
||||
</ThemedText.MediumHeader>
|
||||
<ExtentsText>
|
||||
{' '}
|
||||
<Trans>
|
||||
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
||||
</Trans>
|
||||
</ExtentsText>
|
||||
|
||||
{inRange && (
|
||||
<ThemedText.Small color={theme.text3}>
|
||||
<Trans>Your position will be 100% {currencyQuote?.symbol} at this price.</Trans>
|
||||
</ThemedText.Small>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
</RowBetween>
|
||||
<CurrentPriceCard
|
||||
inverted={inverted}
|
||||
pool={pool}
|
||||
currencyQuote={currencyQuote}
|
||||
currencyBase={currencyBase}
|
||||
<Trace page={PageName.POOL_PAGE} shouldLogImpression>
|
||||
<>
|
||||
<PageWrapper>
|
||||
<TransactionConfirmationModal
|
||||
isOpen={showConfirm}
|
||||
onDismiss={() => setShowConfirm(false)}
|
||||
attemptingTxn={collecting}
|
||||
hash={collectMigrationHash ?? ''}
|
||||
content={() => (
|
||||
<ConfirmationModalContent
|
||||
title={<Trans>Claim fees</Trans>}
|
||||
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} />
|
||||
<ThemedText.Label fontSize={'24px'} mr="10px">
|
||||
{currencyQuote?.symbol} / {currencyBase?.symbol}
|
||||
</ThemedText.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>
|
||||
</DarkCard>
|
||||
</AutoColumn>
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
<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)) ? (
|
||||
<ThemedText.LargeHeader fontSize="36px" fontWeight={500}>
|
||||
<Trans>${fiatValueOfLiquidity.toFixed(2, { groupSeparator: ',' })}</Trans>
|
||||
</ThemedText.LargeHeader>
|
||||
) : (
|
||||
<ThemedText.LargeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
||||
<Trans>$-</Trans>
|
||||
</ThemedText.LargeHeader>
|
||||
)}
|
||||
</AutoColumn>
|
||||
<LightCard padding="12px 16px">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<LinkedCurrency chainId={chainId} currency={currencyQuote} />
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
|
||||
</ThemedText.Main>
|
||||
{typeof ratio === 'number' && !removed ? (
|
||||
<Badge style={{ marginLeft: '10px' }}>
|
||||
<ThemedText.Main fontSize={11}>
|
||||
<Trans>{inverted ? ratio : 100 - ratio}%</Trans>
|
||||
</ThemedText.Main>
|
||||
</Badge>
|
||||
) : null}
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<LinkedCurrency chainId={chainId} currency={currencyBase} />
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
|
||||
</ThemedText.Main>
|
||||
{typeof ratio === 'number' && !removed ? (
|
||||
<Badge style={{ marginLeft: '10px' }}>
|
||||
<ThemedText.Main color={theme.text2} fontSize={11}>
|
||||
<Trans>{inverted ? 100 - ratio : ratio}%</Trans>
|
||||
</ThemedText.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)) ? (
|
||||
<ThemedText.LargeHeader color={theme.green1} fontSize="36px" fontWeight={500}>
|
||||
<Trans>${fiatValueOfFees.toFixed(2, { groupSeparator: ',' })}</Trans>
|
||||
</ThemedText.LargeHeader>
|
||||
) : (
|
||||
<ThemedText.LargeHeader color={theme.text1} fontSize="36px" fontWeight={500}>
|
||||
<Trans>$-</Trans>
|
||||
</ThemedText.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 ? (
|
||||
<ThemedText.Main color={theme.text1}>
|
||||
<Trans> Collected</Trans>
|
||||
</ThemedText.Main>
|
||||
) : isCollectPending || collecting ? (
|
||||
<ThemedText.Main color={theme.text1}>
|
||||
{' '}
|
||||
<Dots>
|
||||
<Trans>Collecting</Trans>
|
||||
</Dots>
|
||||
</ThemedText.Main>
|
||||
) : (
|
||||
<>
|
||||
<ThemedText.Main color={theme.white}>
|
||||
<Trans>Collect fees</Trans>
|
||||
</ThemedText.Main>
|
||||
</>
|
||||
)}
|
||||
</ButtonConfirmed>
|
||||
) : null}
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
<LightCard padding="12px 16px">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<CurrencyLogo
|
||||
currency={feeValueUpper?.currency}
|
||||
size={'20px'}
|
||||
style={{ marginRight: '0.5rem' }}
|
||||
/>
|
||||
<ThemedText.Main>{feeValueUpper?.currency?.symbol}</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{feeValueUpper ? formatCurrencyAmount(feeValueUpper, 4) : '-'}
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<CurrencyLogo
|
||||
currency={feeValueLower?.currency}
|
||||
size={'20px'}
|
||||
style={{ marginRight: '0.5rem' }}
|
||||
/>
|
||||
<ThemedText.Main>{feeValueLower?.currency?.symbol}</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<ThemedText.Main>
|
||||
{feeValueLower ? formatCurrencyAmount(feeValueLower, 4) : '-'}
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
{showCollectAsWeth && (
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
<Trans>Collect as {nativeWrappedSymbol}</Trans>
|
||||
</ThemedText.Main>
|
||||
<Toggle
|
||||
id="receive-as-weth"
|
||||
isActive={receiveWETH}
|
||||
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
|
||||
/>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
)}
|
||||
</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>
|
||||
<ThemedText.MediumHeader textAlign="center">
|
||||
{formatTickPrice(priceLower, tickAtLimit, Bound.LOWER)}
|
||||
</ThemedText.MediumHeader>
|
||||
<ExtentsText>
|
||||
{' '}
|
||||
<Trans>
|
||||
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
||||
</Trans>
|
||||
</ExtentsText>
|
||||
|
||||
{inRange && (
|
||||
<ThemedText.Small color={theme.text3}>
|
||||
<Trans>Your position will be 100% {currencyBase?.symbol} at this price.</Trans>
|
||||
</ThemedText.Small>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
|
||||
<DoubleArrow>⟷</DoubleArrow>
|
||||
<LightCard padding="12px" width="100%">
|
||||
<AutoColumn gap="8px" justify="center">
|
||||
<ExtentsText>
|
||||
<Trans>Max price</Trans>
|
||||
</ExtentsText>
|
||||
<ThemedText.MediumHeader textAlign="center">
|
||||
{formatTickPrice(priceUpper, tickAtLimit, Bound.UPPER)}
|
||||
</ThemedText.MediumHeader>
|
||||
<ExtentsText>
|
||||
{' '}
|
||||
<Trans>
|
||||
{currencyQuote?.symbol} per {currencyBase?.symbol}
|
||||
</Trans>
|
||||
</ExtentsText>
|
||||
|
||||
{inRange && (
|
||||
<ThemedText.Small color={theme.text3}>
|
||||
<Trans>Your position will be 100% {currencyQuote?.symbol} at this price.</Trans>
|
||||
</ThemedText.Small>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
</RowBetween>
|
||||
<CurrentPriceCard
|
||||
inverted={inverted}
|
||||
pool={pool}
|
||||
currencyQuote={currencyQuote}
|
||||
currencyBase={currencyBase}
|
||||
/>
|
||||
</AutoColumn>
|
||||
</DarkCard>
|
||||
</AutoColumn>
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import { ButtonGray, ButtonPrimary, ButtonText } from 'components/Button'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { FlyoutAlignment, NewMenu } from 'components/Menu'
|
||||
@ -252,76 +254,78 @@ export default function Pool() {
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageWrapper>
|
||||
<SwapPoolTabs active="pool" />
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<AutoColumn gap="lg" style={{ width: '100%' }}>
|
||||
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
|
||||
<ThemedText.Body fontSize={'20px'}>
|
||||
<Trans>Pools Overview</Trans>
|
||||
</ThemedText.Body>
|
||||
<ButtonRow>
|
||||
{showV2Features && (
|
||||
<Menu
|
||||
menuItems={menuItems}
|
||||
flyoutAlignment={FlyoutAlignment.LEFT}
|
||||
ToggleUI={(props: any) => (
|
||||
<MoreOptionsButton {...props}>
|
||||
<MoreOptionsText>
|
||||
<Trans>More</Trans>
|
||||
<ChevronDown size={15} />
|
||||
</MoreOptionsText>
|
||||
</MoreOptionsButton>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/ETH">
|
||||
+ <Trans>New Position</Trans>
|
||||
</ResponsiveButtonPrimary>
|
||||
</ButtonRow>
|
||||
</TitleRow>
|
||||
<Trace page={PageName.POOL_PAGE} shouldLogImpression>
|
||||
<>
|
||||
<PageWrapper>
|
||||
<SwapPoolTabs active="pool" />
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<AutoColumn gap="lg" style={{ width: '100%' }}>
|
||||
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
|
||||
<ThemedText.Body fontSize={'20px'}>
|
||||
<Trans>Pools Overview</Trans>
|
||||
</ThemedText.Body>
|
||||
<ButtonRow>
|
||||
{showV2Features && (
|
||||
<Menu
|
||||
menuItems={menuItems}
|
||||
flyoutAlignment={FlyoutAlignment.LEFT}
|
||||
ToggleUI={(props: any) => (
|
||||
<MoreOptionsButton {...props}>
|
||||
<MoreOptionsText>
|
||||
<Trans>More</Trans>
|
||||
<ChevronDown size={15} />
|
||||
</MoreOptionsText>
|
||||
</MoreOptionsButton>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/ETH">
|
||||
+ <Trans>New Position</Trans>
|
||||
</ResponsiveButtonPrimary>
|
||||
</ButtonRow>
|
||||
</TitleRow>
|
||||
|
||||
<MainContentWrapper>
|
||||
{positionsLoading ? (
|
||||
<PositionsLoadingPlaceholder />
|
||||
) : filteredPositions && closedPositions && filteredPositions.length > 0 ? (
|
||||
<PositionList
|
||||
positions={filteredPositions}
|
||||
setUserHideClosedPositions={setUserHideClosedPositions}
|
||||
userHideClosedPositions={userHideClosedPositions}
|
||||
/>
|
||||
) : (
|
||||
<ErrorContainer>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<InboxIcon strokeWidth={1} />
|
||||
<div>
|
||||
<Trans>Your active V3 liquidity positions will appear here.</Trans>
|
||||
</div>
|
||||
</ThemedText.Body>
|
||||
{!showConnectAWallet && closedPositions.length > 0 && (
|
||||
<ButtonText
|
||||
style={{ marginTop: '.5rem' }}
|
||||
onClick={() => setUserHideClosedPositions(!userHideClosedPositions)}
|
||||
>
|
||||
<Trans>Show closed positions</Trans>
|
||||
</ButtonText>
|
||||
)}
|
||||
{showConnectAWallet && (
|
||||
<ButtonPrimary style={{ marginTop: '2em', padding: '8px 16px' }} onClick={toggleWalletModal}>
|
||||
<Trans>Connect a wallet</Trans>
|
||||
</ButtonPrimary>
|
||||
)}
|
||||
</ErrorContainer>
|
||||
)}
|
||||
</MainContentWrapper>
|
||||
<HideSmall>
|
||||
<CTACards />
|
||||
</HideSmall>
|
||||
<MainContentWrapper>
|
||||
{positionsLoading ? (
|
||||
<PositionsLoadingPlaceholder />
|
||||
) : filteredPositions && closedPositions && filteredPositions.length > 0 ? (
|
||||
<PositionList
|
||||
positions={filteredPositions}
|
||||
setUserHideClosedPositions={setUserHideClosedPositions}
|
||||
userHideClosedPositions={userHideClosedPositions}
|
||||
/>
|
||||
) : (
|
||||
<ErrorContainer>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<InboxIcon strokeWidth={1} />
|
||||
<div>
|
||||
<Trans>Your active V3 liquidity positions will appear here.</Trans>
|
||||
</div>
|
||||
</ThemedText.Body>
|
||||
{!showConnectAWallet && closedPositions.length > 0 && (
|
||||
<ButtonText
|
||||
style={{ marginTop: '.5rem' }}
|
||||
onClick={() => setUserHideClosedPositions(!userHideClosedPositions)}
|
||||
>
|
||||
<Trans>Show closed positions</Trans>
|
||||
</ButtonText>
|
||||
)}
|
||||
{showConnectAWallet && (
|
||||
<ButtonPrimary style={{ marginTop: '2em', padding: '8px 16px' }} onClick={toggleWalletModal}>
|
||||
<Trans>Connect a wallet</Trans>
|
||||
</ButtonPrimary>
|
||||
)}
|
||||
</ErrorContainer>
|
||||
)}
|
||||
</MainContentWrapper>
|
||||
<HideSmall>
|
||||
<CTACards />
|
||||
</HideSmall>
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import { UNSUPPORTED_V2POOL_CHAIN_IDS } from 'constants/chains'
|
||||
import JSBI from 'jsbi'
|
||||
import { useContext, useMemo } from 'react'
|
||||
@ -135,147 +137,149 @@ export default function Pool() {
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageWrapper>
|
||||
<SwapPoolTabs active={'pool'} />
|
||||
<VoteCard>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White fontWeight={600}>
|
||||
<Trans>Liquidity provider rewards</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>
|
||||
Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees are
|
||||
added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.
|
||||
</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<ExternalLink
|
||||
style={{ color: 'white', textDecoration: 'underline' }}
|
||||
target="_blank"
|
||||
href="https://uniswap.org/docs/v2/core-concepts/pools/"
|
||||
>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>Read more about providing liquidity</Trans>
|
||||
</ThemedText.White>
|
||||
</ExternalLink>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
</VoteCard>
|
||||
<Trace page={PageName.POOL_PAGE} shouldLogImpression>
|
||||
<>
|
||||
<PageWrapper>
|
||||
<SwapPoolTabs active={'pool'} />
|
||||
<VoteCard>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White fontWeight={600}>
|
||||
<Trans>Liquidity provider rewards</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>
|
||||
Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees
|
||||
are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.
|
||||
</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<ExternalLink
|
||||
style={{ color: 'white', textDecoration: 'underline' }}
|
||||
target="_blank"
|
||||
href="https://uniswap.org/docs/v2/core-concepts/pools/"
|
||||
>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>Read more about providing liquidity</Trans>
|
||||
</ThemedText.White>
|
||||
</ExternalLink>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
</VoteCard>
|
||||
|
||||
{unsupportedV2Network ? (
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<AutoColumn gap="md" style={{ width: '100%' }}>
|
||||
<Layer2Prompt>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Trans>V2 Pool is not available on Layer 2. Switch to Layer 1 Ethereum.</Trans>
|
||||
</ThemedText.Body>
|
||||
</Layer2Prompt>
|
||||
{unsupportedV2Network ? (
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<AutoColumn gap="md" style={{ width: '100%' }}>
|
||||
<Layer2Prompt>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Trans>V2 Pool is not available on Layer 2. Switch to Layer 1 Ethereum.</Trans>
|
||||
</ThemedText.Body>
|
||||
</Layer2Prompt>
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
) : (
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<AutoColumn gap="md" style={{ width: '100%' }}>
|
||||
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
|
||||
<HideSmall>
|
||||
<ThemedText.MediumHeader style={{ marginTop: '0.5rem', justifySelf: 'flex-start' }}>
|
||||
<Trans>Your V2 liquidity</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
</HideSmall>
|
||||
<ButtonRow>
|
||||
<ResponsiveButtonSecondary as={Link} padding="6px 8px" to="/add/v2/ETH">
|
||||
<Trans>Create a pair</Trans>
|
||||
</ResponsiveButtonSecondary>
|
||||
<ResponsiveButtonPrimary id="find-pool-button" as={Link} to="/pool/v2/find" padding="6px 8px">
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
<Trans>Import Pool</Trans>
|
||||
</Text>
|
||||
</ResponsiveButtonPrimary>
|
||||
<ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/v2/ETH" padding="6px 8px">
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
<Trans>Add V2 Liquidity</Trans>
|
||||
</Text>
|
||||
</ResponsiveButtonPrimary>
|
||||
</ButtonRow>
|
||||
</TitleRow>
|
||||
) : (
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<AutoColumn gap="md" style={{ width: '100%' }}>
|
||||
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
|
||||
<HideSmall>
|
||||
<ThemedText.MediumHeader style={{ marginTop: '0.5rem', justifySelf: 'flex-start' }}>
|
||||
<Trans>Your V2 liquidity</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
</HideSmall>
|
||||
<ButtonRow>
|
||||
<ResponsiveButtonSecondary as={Link} padding="6px 8px" to="/add/v2/ETH">
|
||||
<Trans>Create a pair</Trans>
|
||||
</ResponsiveButtonSecondary>
|
||||
<ResponsiveButtonPrimary id="find-pool-button" as={Link} to="/pool/v2/find" padding="6px 8px">
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
<Trans>Import Pool</Trans>
|
||||
</Text>
|
||||
</ResponsiveButtonPrimary>
|
||||
<ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/v2/ETH" padding="6px 8px">
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
<Trans>Add V2 Liquidity</Trans>
|
||||
</Text>
|
||||
</ResponsiveButtonPrimary>
|
||||
</ButtonRow>
|
||||
</TitleRow>
|
||||
|
||||
{!account ? (
|
||||
<Card padding="40px">
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Trans>Connect to a wallet to view your liquidity.</Trans>
|
||||
</ThemedText.Body>
|
||||
</Card>
|
||||
) : v2IsLoading ? (
|
||||
<EmptyProposals>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Dots>
|
||||
<Trans>Loading</Trans>
|
||||
</Dots>
|
||||
</ThemedText.Body>
|
||||
</EmptyProposals>
|
||||
) : allV2PairsWithLiquidity?.length > 0 || stakingPairs?.length > 0 ? (
|
||||
<>
|
||||
<ButtonSecondary>
|
||||
<RowBetween>
|
||||
<Trans>
|
||||
<ExternalLink href={'https://v2.info.uniswap.org/account/' + account}>
|
||||
Account analytics and accrued fees
|
||||
</ExternalLink>
|
||||
<span> ↗ </span>
|
||||
</Trans>
|
||||
</RowBetween>
|
||||
</ButtonSecondary>
|
||||
{v2PairsWithoutStakedAmount.map((v2Pair) => (
|
||||
<FullPositionCard key={v2Pair.liquidityToken.address} pair={v2Pair} />
|
||||
))}
|
||||
{stakingPairs.map(
|
||||
(stakingPair, i) =>
|
||||
stakingPair[1] && ( // skip pairs that arent loaded
|
||||
<FullPositionCard
|
||||
key={stakingInfosWithBalance[i].stakingRewardAddress}
|
||||
pair={stakingPair[1]}
|
||||
stakedBalance={stakingInfosWithBalance[i].stakedAmount}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<RowFixed justify="center" style={{ width: '100%' }}>
|
||||
<ButtonOutlined
|
||||
as={Link}
|
||||
to="/migrate/v2"
|
||||
id="import-pool-link"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
margin: '0 4px',
|
||||
borderRadius: '12px',
|
||||
width: 'fit-content',
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
<ChevronsRight size={16} style={{ marginRight: '8px' }} />
|
||||
<Trans>Migrate Liquidity to V3</Trans>
|
||||
</ButtonOutlined>
|
||||
</RowFixed>
|
||||
</>
|
||||
) : (
|
||||
<EmptyProposals>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Trans>No liquidity found.</Trans>
|
||||
</ThemedText.Body>
|
||||
</EmptyProposals>
|
||||
)}
|
||||
{!account ? (
|
||||
<Card padding="40px">
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Trans>Connect to a wallet to view your liquidity.</Trans>
|
||||
</ThemedText.Body>
|
||||
</Card>
|
||||
) : v2IsLoading ? (
|
||||
<EmptyProposals>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Dots>
|
||||
<Trans>Loading</Trans>
|
||||
</Dots>
|
||||
</ThemedText.Body>
|
||||
</EmptyProposals>
|
||||
) : allV2PairsWithLiquidity?.length > 0 || stakingPairs?.length > 0 ? (
|
||||
<>
|
||||
<ButtonSecondary>
|
||||
<RowBetween>
|
||||
<Trans>
|
||||
<ExternalLink href={'https://v2.info.uniswap.org/account/' + account}>
|
||||
Account analytics and accrued fees
|
||||
</ExternalLink>
|
||||
<span> ↗ </span>
|
||||
</Trans>
|
||||
</RowBetween>
|
||||
</ButtonSecondary>
|
||||
{v2PairsWithoutStakedAmount.map((v2Pair) => (
|
||||
<FullPositionCard key={v2Pair.liquidityToken.address} pair={v2Pair} />
|
||||
))}
|
||||
{stakingPairs.map(
|
||||
(stakingPair, i) =>
|
||||
stakingPair[1] && ( // skip pairs that arent loaded
|
||||
<FullPositionCard
|
||||
key={stakingInfosWithBalance[i].stakingRewardAddress}
|
||||
pair={stakingPair[1]}
|
||||
stakedBalance={stakingInfosWithBalance[i].stakedAmount}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<RowFixed justify="center" style={{ width: '100%' }}>
|
||||
<ButtonOutlined
|
||||
as={Link}
|
||||
to="/migrate/v2"
|
||||
id="import-pool-link"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
margin: '0 4px',
|
||||
borderRadius: '12px',
|
||||
width: 'fit-content',
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
<ChevronsRight size={16} style={{ marginRight: '8px' }} />
|
||||
<Trans>Migrate Liquidity to V3</Trans>
|
||||
</ButtonOutlined>
|
||||
</RowFixed>
|
||||
</>
|
||||
) : (
|
||||
<EmptyProposals>
|
||||
<ThemedText.Body color={theme.text3} textAlign="center">
|
||||
<Trans>No liquidity found.</Trans>
|
||||
</ThemedText.Body>
|
||||
</EmptyProposals>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
)}
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
)}
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import JSBI from 'jsbi'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Plus } from 'react-feather'
|
||||
@ -95,139 +97,141 @@ export default function PoolFinder() {
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppBody>
|
||||
<FindPoolTabs origin={query.get('origin') ?? '/pool/v2'} />
|
||||
<AutoColumn style={{ padding: '1rem' }} gap="md">
|
||||
<BlueCard>
|
||||
<AutoColumn gap="10px">
|
||||
<ThemedText.Link fontWeight={400} color={'primaryText1'}>
|
||||
<Trans>
|
||||
<b>Tip:</b> Use this tool to find v2 pools that don't automatically appear in the interface.
|
||||
</Trans>
|
||||
</ThemedText.Link>
|
||||
</AutoColumn>
|
||||
</BlueCard>
|
||||
<ButtonDropdownLight
|
||||
onClick={() => {
|
||||
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' }}
|
||||
<Trace page={PageName.POOL_PAGE} shouldLogImpression>
|
||||
<>
|
||||
<AppBody>
|
||||
<FindPoolTabs origin={query.get('origin') ?? '/pool/v2'} />
|
||||
<AutoColumn style={{ padding: '1rem' }} gap="md">
|
||||
<BlueCard>
|
||||
<AutoColumn gap="10px">
|
||||
<ThemedText.Link fontWeight={400} color={'primaryText1'}>
|
||||
<Trans>
|
||||
<b>Tip:</b> Use this tool to find v2 pools that don't automatically appear in the interface.
|
||||
</Trans>
|
||||
</ThemedText.Link>
|
||||
</AutoColumn>
|
||||
</BlueCard>
|
||||
<ButtonDropdownLight
|
||||
onClick={() => {
|
||||
setShowSearch(true)
|
||||
setActiveField(Fields.TOKEN0)
|
||||
}}
|
||||
>
|
||||
<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" />
|
||||
{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}>
|
||||
<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">
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Text textAlign="center">
|
||||
<Trans>You don’t have liquidity in this pool yet.</Trans>
|
||||
<Trans>No pool found.</Trans>
|
||||
</Text>
|
||||
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
|
||||
<Text textAlign="center">
|
||||
<Trans>Add liquidity.</Trans>
|
||||
</Text>
|
||||
<Trans>Create pool.</Trans>
|
||||
</StyledInternalLink>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
)
|
||||
) : validPairNoLiquidity ? (
|
||||
<LightCard padding="45px 10px">
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Text textAlign="center">
|
||||
<Trans>No pool found.</Trans>
|
||||
</Text>
|
||||
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
|
||||
<Trans>Create pool.</Trans>
|
||||
</StyledInternalLink>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
) : pairState === PairState.INVALID ? (
|
||||
<LightCard padding="45px 10px">
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Text textAlign="center" fontWeight={500}>
|
||||
<Trans>Invalid pair.</Trans>
|
||||
</Text>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
) : pairState === PairState.LOADING ? (
|
||||
<LightCard padding="45px 10px">
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Text textAlign="center">
|
||||
<Trans>Loading</Trans>
|
||||
<Dots />
|
||||
</Text>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
) : null
|
||||
) : (
|
||||
prerequisiteMessage
|
||||
)}
|
||||
</AutoColumn>
|
||||
) : pairState === PairState.INVALID ? (
|
||||
<LightCard padding="45px 10px">
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Text textAlign="center" fontWeight={500}>
|
||||
<Trans>Invalid pair.</Trans>
|
||||
</Text>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
) : pairState === PairState.LOADING ? (
|
||||
<LightCard padding="45px 10px">
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Text textAlign="center">
|
||||
<Trans>Loading</Trans>
|
||||
<Dots />
|
||||
</Text>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
) : null
|
||||
) : (
|
||||
prerequisiteMessage
|
||||
)}
|
||||
</AutoColumn>
|
||||
|
||||
<CurrencySearchModal
|
||||
isOpen={showSearch}
|
||||
onCurrencySelect={handleCurrencySelect}
|
||||
onDismiss={handleSearchDismiss}
|
||||
showCommonBases
|
||||
selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined}
|
||||
/>
|
||||
</AppBody>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
<CurrencySearchModal
|
||||
isOpen={showSearch}
|
||||
onCurrencySelect={handleCurrencySelect}
|
||||
onDismiss={handleSearchDismiss}
|
||||
showCommonBases
|
||||
selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined}
|
||||
/>
|
||||
</AppBody>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
||||
const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode
|
||||
|
||||
return (
|
||||
<Trace page={PageName.SWAP_PAGE} shouldLogImpression={false}>
|
||||
<Trace page={PageName.SWAP_PAGE} shouldLogImpression>
|
||||
<>
|
||||
<TokenWarningModal
|
||||
isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import { ButtonPrimary } from 'components/Button'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { CardBGImage, CardNoise, CardSection, DataCard } from 'components/earn/styled'
|
||||
@ -132,150 +134,155 @@ export default function Landing() {
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<PageWrapper gap="lg" justify="center">
|
||||
<DelegateModal
|
||||
isOpen={showDelegateModal}
|
||||
onDismiss={toggleDelegateModal}
|
||||
title={showUnlockVoting ? <Trans>Unlock Votes</Trans> : <Trans>Update Delegation</Trans>}
|
||||
/>
|
||||
<TopSection gap="md">
|
||||
<VoteCard>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
<CardSection>
|
||||
<Trace page={PageName.VOTE_PAGE} shouldLogImpression>
|
||||
<PageWrapper gap="lg" justify="center">
|
||||
<DelegateModal
|
||||
isOpen={showDelegateModal}
|
||||
onDismiss={toggleDelegateModal}
|
||||
title={showUnlockVoting ? <Trans>Unlock Votes</Trans> : <Trans>Update Delegation</Trans>}
|
||||
/>
|
||||
<TopSection gap="md">
|
||||
<VoteCard>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White fontWeight={600}>
|
||||
<Trans>Uniswap Governance</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>
|
||||
UNI tokens represent voting shares in Uniswap governance. You can vote on each proposal yourself
|
||||
or delegate your votes to a third party.
|
||||
</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<ExternalLink
|
||||
style={{ color: 'white', textDecoration: 'underline' }}
|
||||
href="https://uniswap.org/blog/uni"
|
||||
target="_blank"
|
||||
>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>Read more about Uniswap governance</Trans>
|
||||
</ThemedText.White>
|
||||
</ExternalLink>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
</VoteCard>
|
||||
</TopSection>
|
||||
<TopSection gap="2px">
|
||||
<WrapSmall>
|
||||
<ThemedText.MediumHeader style={{ margin: '0.5rem 0.5rem 0.5rem 0', flexShrink: 0 }}>
|
||||
<Trans>Proposals</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<AutoRow gap="6px" justify="flex-end">
|
||||
{loadingProposals || loadingAvailableVotes ? <Loader /> : null}
|
||||
{showUnlockVoting ? (
|
||||
<ButtonPrimary
|
||||
style={{ width: 'fit-content' }}
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={toggleDelegateModal}
|
||||
>
|
||||
<Trans>Unlock Voting</Trans>
|
||||
</ButtonPrimary>
|
||||
) : availableVotes && JSBI.notEqual(JSBI.BigInt(0), availableVotes?.quotient) ? (
|
||||
<ThemedText.Body fontWeight={500} mr="6px">
|
||||
<Trans>
|
||||
<FormattedCurrencyAmount currencyAmount={availableVotes} /> Votes
|
||||
</Trans>
|
||||
</ThemedText.Body>
|
||||
) : uniBalance &&
|
||||
userDelegatee &&
|
||||
userDelegatee !== ZERO_ADDRESS &&
|
||||
JSBI.notEqual(JSBI.BigInt(0), uniBalance?.quotient) ? (
|
||||
<ThemedText.Body fontWeight={500} mr="6px">
|
||||
<Trans>
|
||||
<FormattedCurrencyAmount currencyAmount={uniBalance} /> Votes
|
||||
</Trans>
|
||||
</ThemedText.Body>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<ButtonPrimary
|
||||
as={Link}
|
||||
to="/create-proposal"
|
||||
style={{ width: 'fit-content', borderRadius: '8px' }}
|
||||
padding="8px"
|
||||
>
|
||||
<Trans>Create Proposal</Trans>
|
||||
</ButtonPrimary>
|
||||
</AutoRow>
|
||||
</WrapSmall>
|
||||
{!showUnlockVoting && (
|
||||
<RowBetween>
|
||||
<div />
|
||||
{userDelegatee && userDelegatee !== ZERO_ADDRESS ? (
|
||||
<RowFixed>
|
||||
<ThemedText.Body fontWeight={500} mr="4px">
|
||||
<Trans>Delegated to:</Trans>
|
||||
</ThemedText.Body>
|
||||
<AddressButton>
|
||||
<StyledExternalLink
|
||||
href={getExplorerLink(1, userDelegatee, ExplorerDataType.ADDRESS)}
|
||||
style={{ margin: '0 4px' }}
|
||||
>
|
||||
{userDelegatee === account ? <Trans>Self</Trans> : shortenAddress(userDelegatee)}
|
||||
</StyledExternalLink>
|
||||
<TextButton onClick={toggleDelegateModal} style={{ marginLeft: '4px' }}>
|
||||
<Trans>(edit)</Trans>
|
||||
</TextButton>
|
||||
</AddressButton>
|
||||
</RowFixed>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</RowBetween>
|
||||
)}
|
||||
|
||||
{allProposals?.length === 0 && <ProposalEmptyState />}
|
||||
|
||||
{allProposals?.length > 0 && (
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White fontWeight={600}>
|
||||
<Trans>Uniswap Governance</Trans>
|
||||
</ThemedText.White>
|
||||
<ThemedText.Main>
|
||||
<Trans>Show Cancelled</Trans>
|
||||
</ThemedText.Main>
|
||||
<Toggle
|
||||
isActive={!hideCancelled}
|
||||
toggle={() => setHideCancelled((hideCancelled) => !hideCancelled)}
|
||||
/>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>
|
||||
UNI tokens represent voting shares in Uniswap governance. You can vote on each proposal yourself
|
||||
or delegate your votes to a third party.
|
||||
</Trans>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<ExternalLink
|
||||
style={{ color: 'white', textDecoration: 'underline' }}
|
||||
href="https://uniswap.org/blog/uni"
|
||||
target="_blank"
|
||||
>
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>Read more about Uniswap governance</Trans>
|
||||
</ThemedText.White>
|
||||
</ExternalLink>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
</VoteCard>
|
||||
</TopSection>
|
||||
<TopSection gap="2px">
|
||||
<WrapSmall>
|
||||
<ThemedText.MediumHeader style={{ margin: '0.5rem 0.5rem 0.5rem 0', flexShrink: 0 }}>
|
||||
<Trans>Proposals</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<AutoRow gap="6px" justify="flex-end">
|
||||
{loadingProposals || loadingAvailableVotes ? <Loader /> : null}
|
||||
{showUnlockVoting ? (
|
||||
<ButtonPrimary
|
||||
style={{ width: 'fit-content' }}
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={toggleDelegateModal}
|
||||
>
|
||||
<Trans>Unlock Voting</Trans>
|
||||
</ButtonPrimary>
|
||||
) : availableVotes && JSBI.notEqual(JSBI.BigInt(0), availableVotes?.quotient) ? (
|
||||
<ThemedText.Body fontWeight={500} mr="6px">
|
||||
<Trans>
|
||||
<FormattedCurrencyAmount currencyAmount={availableVotes} /> Votes
|
||||
</Trans>
|
||||
</ThemedText.Body>
|
||||
) : uniBalance &&
|
||||
userDelegatee &&
|
||||
userDelegatee !== ZERO_ADDRESS &&
|
||||
JSBI.notEqual(JSBI.BigInt(0), uniBalance?.quotient) ? (
|
||||
<ThemedText.Body fontWeight={500} mr="6px">
|
||||
<Trans>
|
||||
<FormattedCurrencyAmount currencyAmount={uniBalance} /> Votes
|
||||
</Trans>
|
||||
</ThemedText.Body>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<ButtonPrimary
|
||||
as={Link}
|
||||
to="/create-proposal"
|
||||
style={{ width: 'fit-content', borderRadius: '8px' }}
|
||||
padding="8px"
|
||||
>
|
||||
<Trans>Create Proposal</Trans>
|
||||
</ButtonPrimary>
|
||||
</AutoRow>
|
||||
</WrapSmall>
|
||||
{!showUnlockVoting && (
|
||||
<RowBetween>
|
||||
<div />
|
||||
{userDelegatee && userDelegatee !== ZERO_ADDRESS ? (
|
||||
<RowFixed>
|
||||
<ThemedText.Body fontWeight={500} mr="4px">
|
||||
<Trans>Delegated to:</Trans>
|
||||
</ThemedText.Body>
|
||||
<AddressButton>
|
||||
<StyledExternalLink
|
||||
href={getExplorerLink(1, userDelegatee, ExplorerDataType.ADDRESS)}
|
||||
style={{ margin: '0 4px' }}
|
||||
>
|
||||
{userDelegatee === account ? <Trans>Self</Trans> : shortenAddress(userDelegatee)}
|
||||
</StyledExternalLink>
|
||||
<TextButton onClick={toggleDelegateModal} style={{ marginLeft: '4px' }}>
|
||||
<Trans>(edit)</Trans>
|
||||
</TextButton>
|
||||
</AddressButton>
|
||||
</RowFixed>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</RowBetween>
|
||||
)}
|
||||
)}
|
||||
|
||||
{allProposals?.length === 0 && <ProposalEmptyState />}
|
||||
{allProposals
|
||||
?.slice(0)
|
||||
?.reverse()
|
||||
?.filter((p: ProposalData) => (hideCancelled ? p.status !== ProposalState.CANCELED : true))
|
||||
?.map((p: ProposalData) => {
|
||||
return (
|
||||
<Proposal as={Link} to={`/vote/${p.governorIndex}/${p.id}`} key={`${p.governorIndex}${p.id}`}>
|
||||
<ProposalNumber>
|
||||
{p.governorIndex}.{p.id}
|
||||
</ProposalNumber>
|
||||
<ProposalTitle>{p.title}</ProposalTitle>
|
||||
<ProposalStatus status={p.status} />
|
||||
</Proposal>
|
||||
)
|
||||
})}
|
||||
</TopSection>
|
||||
|
||||
{allProposals?.length > 0 && (
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
<Trans>Show Cancelled</Trans>
|
||||
</ThemedText.Main>
|
||||
<Toggle isActive={!hideCancelled} toggle={() => setHideCancelled((hideCancelled) => !hideCancelled)} />
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
)}
|
||||
|
||||
{allProposals
|
||||
?.slice(0)
|
||||
?.reverse()
|
||||
?.filter((p: ProposalData) => (hideCancelled ? p.status !== ProposalState.CANCELED : true))
|
||||
?.map((p: ProposalData) => {
|
||||
return (
|
||||
<Proposal as={Link} to={`/vote/${p.governorIndex}/${p.id}`} key={`${p.governorIndex}${p.id}`}>
|
||||
<ProposalNumber>
|
||||
{p.governorIndex}.{p.id}
|
||||
</ProposalNumber>
|
||||
<ProposalTitle>{p.title}</ProposalTitle>
|
||||
<ProposalStatus status={p.status} />
|
||||
</Proposal>
|
||||
)
|
||||
})}
|
||||
</TopSection>
|
||||
|
||||
<ThemedText.SubHeader color="text3">
|
||||
<Trans>A minimum threshold of 0.25% of the total UNI supply is required to submit proposals</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</PageWrapper>
|
||||
<ThemedText.SubHeader color="text3">
|
||||
<Trans>A minimum threshold of 0.25% of the total UNI supply is required to submit proposals</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</PageWrapper>
|
||||
</Trace>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
)
|
||||
|
@ -2,6 +2,8 @@ import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Fraction, Token } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'components/AmplitudeAnalytics/constants'
|
||||
import { Trace } from 'components/AmplitudeAnalytics/Trace'
|
||||
import ExecuteModal from 'components/vote/ExecuteModal'
|
||||
import QueueModal from 'components/vote/QueueModal'
|
||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||
@ -258,226 +260,232 @@ export default function VotePage({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageWrapper gap="lg" justify="center">
|
||||
<VoteModal
|
||||
isOpen={showVoteModal}
|
||||
onDismiss={toggleVoteModal}
|
||||
proposalId={proposalData?.id}
|
||||
voteOption={voteOption}
|
||||
/>
|
||||
<DelegateModal isOpen={showDelegateModal} onDismiss={toggleDelegateModal} title={<Trans>Unlock Votes</Trans>} />
|
||||
<QueueModal isOpen={showQueueModal} onDismiss={toggleQueueModal} proposalId={proposalData?.id} />
|
||||
<ExecuteModal isOpen={showExecuteModal} onDismiss={toggleExecuteModal} proposalId={proposalData?.id} />
|
||||
<ProposalInfo gap="lg" justify="start">
|
||||
<RowBetween style={{ width: '100%' }}>
|
||||
<ArrowWrapper to="/vote">
|
||||
<Trans>
|
||||
<ArrowLeft size={20} /> All Proposals
|
||||
</Trans>
|
||||
</ArrowWrapper>
|
||||
{proposalData && <ProposalStatus status={proposalData.status} />}
|
||||
</RowBetween>
|
||||
<AutoColumn gap="10px" style={{ width: '100%' }}>
|
||||
<ThemedText.LargeHeader style={{ marginBottom: '.5rem' }}>{proposalData?.title}</ThemedText.LargeHeader>
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
{startDate && startDate > now ? (
|
||||
<Trans>Voting starts approximately {startDate.toLocaleString(locale, dateFormat)}</Trans>
|
||||
) : null}
|
||||
</ThemedText.Main>
|
||||
<Trace page={PageName.VOTE_PAGE} shouldLogImpression>
|
||||
<>
|
||||
<PageWrapper gap="lg" justify="center">
|
||||
<VoteModal
|
||||
isOpen={showVoteModal}
|
||||
onDismiss={toggleVoteModal}
|
||||
proposalId={proposalData?.id}
|
||||
voteOption={voteOption}
|
||||
/>
|
||||
<DelegateModal
|
||||
isOpen={showDelegateModal}
|
||||
onDismiss={toggleDelegateModal}
|
||||
title={<Trans>Unlock Votes</Trans>}
|
||||
/>
|
||||
<QueueModal isOpen={showQueueModal} onDismiss={toggleQueueModal} proposalId={proposalData?.id} />
|
||||
<ExecuteModal isOpen={showExecuteModal} onDismiss={toggleExecuteModal} proposalId={proposalData?.id} />
|
||||
<ProposalInfo gap="lg" justify="start">
|
||||
<RowBetween style={{ width: '100%' }}>
|
||||
<ArrowWrapper to="/vote">
|
||||
<Trans>
|
||||
<ArrowLeft size={20} /> All Proposals
|
||||
</Trans>
|
||||
</ArrowWrapper>
|
||||
{proposalData && <ProposalStatus status={proposalData.status} />}
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
{endDate &&
|
||||
(endDate < now ? (
|
||||
<Trans>Voting ended {endDate.toLocaleString(locale, dateFormat)}</Trans>
|
||||
) : (
|
||||
<Trans>Voting ends approximately {endDate.toLocaleString(locale, dateFormat)}</Trans>
|
||||
))}
|
||||
</ThemedText.Main>
|
||||
</RowBetween>
|
||||
{proposalData && proposalData.status === ProposalState.ACTIVE && !showVotingButtons && (
|
||||
<GreyCard>
|
||||
<ThemedText.Black>
|
||||
<Trans>
|
||||
Only UNI votes that were self delegated or delegated to another address before block{' '}
|
||||
{proposalData.startBlock} are eligible for voting.
|
||||
</Trans>{' '}
|
||||
{showLinkForUnlock && (
|
||||
<span>
|
||||
<Trans>
|
||||
<StyledInternalLink to="/vote">Unlock voting</StyledInternalLink> to prepare for the next
|
||||
proposal.
|
||||
</Trans>
|
||||
</span>
|
||||
)}
|
||||
</ThemedText.Black>
|
||||
</GreyCard>
|
||||
)}
|
||||
</AutoColumn>
|
||||
{showVotingButtons && (
|
||||
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
setVoteOption(VoteOption.For)
|
||||
toggleVoteModal()
|
||||
}}
|
||||
>
|
||||
<Trans>Vote For</Trans>
|
||||
</ButtonPrimary>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
setVoteOption(VoteOption.Against)
|
||||
toggleVoteModal()
|
||||
}}
|
||||
>
|
||||
<Trans>Vote Against</Trans>
|
||||
</ButtonPrimary>
|
||||
</RowFixed>
|
||||
)}
|
||||
{showQueueButton && (
|
||||
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
toggleQueueModal()
|
||||
}}
|
||||
>
|
||||
<Trans>Queue</Trans>
|
||||
</ButtonPrimary>
|
||||
</RowFixed>
|
||||
)}
|
||||
{showExecuteButton && (
|
||||
<>
|
||||
{eta && (
|
||||
<RowBetween>
|
||||
<AutoColumn gap="10px" style={{ width: '100%' }}>
|
||||
<ThemedText.LargeHeader style={{ marginBottom: '.5rem' }}>{proposalData?.title}</ThemedText.LargeHeader>
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
{startDate && startDate > now ? (
|
||||
<Trans>Voting starts approximately {startDate.toLocaleString(locale, dateFormat)}</Trans>
|
||||
) : null}
|
||||
</ThemedText.Main>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.Main>
|
||||
{endDate &&
|
||||
(endDate < now ? (
|
||||
<Trans>Voting ended {endDate.toLocaleString(locale, dateFormat)}</Trans>
|
||||
) : (
|
||||
<Trans>Voting ends approximately {endDate.toLocaleString(locale, dateFormat)}</Trans>
|
||||
))}
|
||||
</ThemedText.Main>
|
||||
</RowBetween>
|
||||
{proposalData && proposalData.status === ProposalState.ACTIVE && !showVotingButtons && (
|
||||
<GreyCard>
|
||||
<ThemedText.Black>
|
||||
<Trans>This proposal may be executed after {eta.toLocaleString(locale, dateFormat)}.</Trans>
|
||||
<Trans>
|
||||
Only UNI votes that were self delegated or delegated to another address before block{' '}
|
||||
{proposalData.startBlock} are eligible for voting.
|
||||
</Trans>{' '}
|
||||
{showLinkForUnlock && (
|
||||
<span>
|
||||
<Trans>
|
||||
<StyledInternalLink to="/vote">Unlock voting</StyledInternalLink> to prepare for the next
|
||||
proposal.
|
||||
</Trans>
|
||||
</span>
|
||||
)}
|
||||
</ThemedText.Black>
|
||||
</RowBetween>
|
||||
</GreyCard>
|
||||
)}
|
||||
</AutoColumn>
|
||||
{showVotingButtons && (
|
||||
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
toggleExecuteModal()
|
||||
setVoteOption(VoteOption.For)
|
||||
toggleVoteModal()
|
||||
}}
|
||||
// can't execute until the eta has arrived
|
||||
disabled={!currentTimestamp || !proposalData?.eta || currentTimestamp.lt(proposalData.eta)}
|
||||
>
|
||||
<Trans>Execute</Trans>
|
||||
<Trans>Vote For</Trans>
|
||||
</ButtonPrimary>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
setVoteOption(VoteOption.Against)
|
||||
toggleVoteModal()
|
||||
}}
|
||||
>
|
||||
<Trans>Vote Against</Trans>
|
||||
</ButtonPrimary>
|
||||
</RowFixed>
|
||||
</>
|
||||
)}
|
||||
<CardWrapper>
|
||||
<StyledDataCard>
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<WrapSmall>
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
<Trans>For</Trans>
|
||||
)}
|
||||
{showQueueButton && (
|
||||
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
toggleQueueModal()
|
||||
}}
|
||||
>
|
||||
<Trans>Queue</Trans>
|
||||
</ButtonPrimary>
|
||||
</RowFixed>
|
||||
)}
|
||||
{showExecuteButton && (
|
||||
<>
|
||||
{eta && (
|
||||
<RowBetween>
|
||||
<ThemedText.Black>
|
||||
<Trans>This proposal may be executed after {eta.toLocaleString(locale, dateFormat)}.</Trans>
|
||||
</ThemedText.Black>
|
||||
{proposalData && (
|
||||
</RowBetween>
|
||||
)}
|
||||
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
||||
<ButtonPrimary
|
||||
padding="8px"
|
||||
$borderRadius="8px"
|
||||
onClick={() => {
|
||||
toggleExecuteModal()
|
||||
}}
|
||||
// can't execute until the eta has arrived
|
||||
disabled={!currentTimestamp || !proposalData?.eta || currentTimestamp.lt(proposalData.eta)}
|
||||
>
|
||||
<Trans>Execute</Trans>
|
||||
</ButtonPrimary>
|
||||
</RowFixed>
|
||||
</>
|
||||
)}
|
||||
<CardWrapper>
|
||||
<StyledDataCard>
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<WrapSmall>
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
{proposalData.forCount.toFixed(0, { groupSeparator: ',' })}
|
||||
{quorumAmount && (
|
||||
<span style={{ fontWeight: 400 }}>{` / ${quorumAmount.toExact({
|
||||
groupSeparator: ',',
|
||||
})}`}</span>
|
||||
)}
|
||||
<Trans>For</Trans>
|
||||
</ThemedText.Black>
|
||||
)}
|
||||
</WrapSmall>
|
||||
</AutoColumn>
|
||||
<ProgressWrapper>
|
||||
<Progress
|
||||
status={'for'}
|
||||
percentageString={
|
||||
proposalData?.forCount.greaterThan(0) ? `${forPercentage?.toFixed(0) ?? 0}%` : '0%'
|
||||
}
|
||||
/>
|
||||
</ProgressWrapper>
|
||||
</CardSection>
|
||||
</StyledDataCard>
|
||||
<StyledDataCard>
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<WrapSmall>
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
<Trans>Against</Trans>
|
||||
</ThemedText.Black>
|
||||
{proposalData && (
|
||||
{proposalData && (
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
{proposalData.forCount.toFixed(0, { groupSeparator: ',' })}
|
||||
{quorumAmount && (
|
||||
<span style={{ fontWeight: 400 }}>{` / ${quorumAmount.toExact({
|
||||
groupSeparator: ',',
|
||||
})}`}</span>
|
||||
)}
|
||||
</ThemedText.Black>
|
||||
)}
|
||||
</WrapSmall>
|
||||
</AutoColumn>
|
||||
<ProgressWrapper>
|
||||
<Progress
|
||||
status={'for'}
|
||||
percentageString={
|
||||
proposalData?.forCount.greaterThan(0) ? `${forPercentage?.toFixed(0) ?? 0}%` : '0%'
|
||||
}
|
||||
/>
|
||||
</ProgressWrapper>
|
||||
</CardSection>
|
||||
</StyledDataCard>
|
||||
<StyledDataCard>
|
||||
<CardSection>
|
||||
<AutoColumn gap="md">
|
||||
<WrapSmall>
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
{proposalData.againstCount.toFixed(0, { groupSeparator: ',' })}
|
||||
<Trans>Against</Trans>
|
||||
</ThemedText.Black>
|
||||
)}
|
||||
</WrapSmall>
|
||||
</AutoColumn>
|
||||
<ProgressWrapper>
|
||||
<Progress
|
||||
status={'against'}
|
||||
percentageString={
|
||||
proposalData?.againstCount?.greaterThan(0) ? `${againstPercentage?.toFixed(0) ?? 0}%` : '0%'
|
||||
}
|
||||
/>
|
||||
</ProgressWrapper>
|
||||
</CardSection>
|
||||
</StyledDataCard>
|
||||
</CardWrapper>
|
||||
<AutoColumn gap="md">
|
||||
<ThemedText.MediumHeader fontWeight={600}>
|
||||
<Trans>Details</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
{proposalData?.details?.map((d, i) => {
|
||||
return (
|
||||
<DetailText key={i}>
|
||||
{i + 1}: {linkIfAddress(d.target)}.{d.functionSig}(
|
||||
{d.callData.split(',').map((content, i) => {
|
||||
return (
|
||||
<span key={i}>
|
||||
{linkIfAddress(content)}
|
||||
{d.callData.split(',').length - 1 === i ? '' : ','}
|
||||
</span>
|
||||
{proposalData && (
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
{proposalData.againstCount.toFixed(0, { groupSeparator: ',' })}
|
||||
</ThemedText.Black>
|
||||
)}
|
||||
</WrapSmall>
|
||||
</AutoColumn>
|
||||
<ProgressWrapper>
|
||||
<Progress
|
||||
status={'against'}
|
||||
percentageString={
|
||||
proposalData?.againstCount?.greaterThan(0) ? `${againstPercentage?.toFixed(0) ?? 0}%` : '0%'
|
||||
}
|
||||
/>
|
||||
</ProgressWrapper>
|
||||
</CardSection>
|
||||
</StyledDataCard>
|
||||
</CardWrapper>
|
||||
<AutoColumn gap="md">
|
||||
<ThemedText.MediumHeader fontWeight={600}>
|
||||
<Trans>Details</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
{proposalData?.details?.map((d, i) => {
|
||||
return (
|
||||
<DetailText key={i}>
|
||||
{i + 1}: {linkIfAddress(d.target)}.{d.functionSig}(
|
||||
{d.callData.split(',').map((content, i) => {
|
||||
return (
|
||||
<span key={i}>
|
||||
{linkIfAddress(content)}
|
||||
{d.callData.split(',').length - 1 === i ? '' : ','}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
)
|
||||
})}
|
||||
)
|
||||
</DetailText>
|
||||
)
|
||||
})}
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<ThemedText.MediumHeader fontWeight={600}>
|
||||
<Trans>Description</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<MarkDownWrapper>
|
||||
<ReactMarkdown source={proposalData?.description} />
|
||||
</MarkDownWrapper>
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<ThemedText.MediumHeader fontWeight={600}>
|
||||
<Trans>Proposer</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<ProposerAddressLink
|
||||
href={
|
||||
proposalData?.proposer && chainId
|
||||
? getExplorerLink(chainId, proposalData?.proposer, ExplorerDataType.ADDRESS)
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<ReactMarkdown source={proposalData?.proposer} />
|
||||
</ProposerAddressLink>
|
||||
</AutoColumn>
|
||||
</ProposalInfo>
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</DetailText>
|
||||
)
|
||||
})}
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<ThemedText.MediumHeader fontWeight={600}>
|
||||
<Trans>Description</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<MarkDownWrapper>
|
||||
<ReactMarkdown source={proposalData?.description} />
|
||||
</MarkDownWrapper>
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<ThemedText.MediumHeader fontWeight={600}>
|
||||
<Trans>Proposer</Trans>
|
||||
</ThemedText.MediumHeader>
|
||||
<ProposerAddressLink
|
||||
href={
|
||||
proposalData?.proposer && chainId
|
||||
? getExplorerLink(chainId, proposalData?.proposer, ExplorerDataType.ADDRESS)
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<ReactMarkdown source={proposalData?.proposer} />
|
||||
</ProposerAddressLink>
|
||||
</AutoColumn>
|
||||
</ProposalInfo>
|
||||
</PageWrapper>
|
||||
<SwitchLocaleLink />
|
||||
</>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user