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:
lynn 2022-07-13 16:16:42 -04:00 committed by GitHub
parent 64cb9f3ff2
commit 4e0c9b36a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1104 additions and 1064 deletions

@ -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>
Dont 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>
Dont 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">
&nbsp;{currencyQuote?.symbol}&nbsp;/&nbsp;{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">
&nbsp;{currencyQuote?.symbol}&nbsp;/&nbsp;{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&apos;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&apos;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 dont 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 dont 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>
)
}