Commit 4e0c9b36 authored by lynn's avatar lynn Committed by GitHub

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
parent 64cb9f3f
......@@ -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>
<ProposalActionSelector onClick={handleActionSelectorClick} proposalAction={proposalAction} />
<ProposalActionDetail
proposalAction={proposalAction}
currency={currencyValue}
amount={amountValue}
toAddress={toAddressValue}
onCurrencySelect={handleCurrencySelect}
onAmountInput={handleAmountInput}
onToAddressInput={handleToAddressInput}
<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}
/>
<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">
&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 && (
<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>
{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}
<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>
)}
</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 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>
<LightCard padding="12px 16px">
</DarkCard>
<DarkCard>
<AutoColumn gap="md" style={{ width: '100%' }}>
<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>
<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>
</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>
) : isCollectPending || collecting ? (
<ThemedText.Main color={theme.text1}>
{' '}
<Dots>
<Trans>Collecting</Trans>
</Dots>
</ThemedText.Main>
</Badge>
) : null}
</RowFixed>
) : (
<>
<ThemedText.Main color={theme.white}>
<Trans>Collect fees</Trans>
</ThemedText.Main>
</>
)}
</ButtonConfirmed>
) : null}
</RowBetween>
</AutoColumn>
</LightCard>
</AutoColumn>
</DarkCard>
<DarkCard>
<AutoColumn gap="md" style={{ width: '100%' }}>
<AutoColumn gap="md">
<RowBetween style={{ alignItems: 'flex-start' }}>
<LightCard padding="12px 16px">
<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>
<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>
) : isCollectPending || collecting ? (
<ThemedText.Main color={theme.text1}>
{' '}
<Dots>
<Trans>Collecting</Trans>
</Dots>
</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>
) : (
<>
<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>
</RowFixed>
</RowBetween>
</AutoColumn>
</LightCard>
{showCollectAsWeth && (
<AutoColumn gap="md">
<RowBetween>
<ThemedText.Main>
{feeValueUpper ? formatCurrencyAmount(feeValueUpper, 4) : '-'}
<Trans>Collect as {nativeWrappedSymbol}</Trans>
</ThemedText.Main>
</RowFixed>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo
currency={feeValueLower?.currency}
size={'20px'}
style={{ marginRight: '0.5rem' }}
<Toggle
id="receive-as-weth"
isActive={receiveWETH}
toggle={() => setReceiveWETH((receiveWETH) => !receiveWETH)}
/>
<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>
</RowBetween>
</AutoColumn>
)}
</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>
</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)}
/>
)}
</AutoColumn>
</LightCard>
</RowBetween>
<CurrentPriceCard
inverted={inverted}
pool={pool}
currencyQuote={currencyQuote}
currencyBase={currencyBase}
/>
</AutoColumn>
</DarkCard>
</AutoColumn>
</PageWrapper>
<SwitchLocaleLink />
</>
</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>
)
}
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>
)}
<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>
)}
<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>
<HideSmall>
<CTACards />
</HideSmall>
</AutoColumn>
</AutoColumn>
</AutoColumn>
</PageWrapper>
<SwitchLocaleLink />
</>
</PageWrapper>
<SwitchLocaleLink />
</>
</Trace>
)
}
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>
{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 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>
<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>
{!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>
{unsupportedV2Network ? (
<AutoColumn gap="lg" justify="center">
<AutoColumn gap="md" style={{ width: '100%' }}>
<Layer2Prompt>
<ThemedText.Body color={theme.text3} textAlign="center">
<Dots>
<Trans>Loading</Trans>
</Dots>
<Trans>V2 Pool is not available on Layer 2. Switch to Layer 1 Ethereum.</Trans>
</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>
)}
</Layer2Prompt>
</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>
{!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>
)
}
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} />
<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)
}}
>
{currency0 ? (
<Row>
<CurrencyLogo currency={currency0} />
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
{currency0.symbol}
</Text>
</Row>
) : (
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
{currency1.symbol}
<Trans>Select a token</Trans>
</Text>
</Row>
) : (
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
<Trans>Select a token</Trans>
</Text>
)}
</ButtonDropdownLight>
)}
</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>
<Plus size="16" color="#888D9B" />
</ColumnCenter>
)}
{currency0 && currency1 ? (
pairState === PairState.EXISTS ? (
hasPosition && pair ? (
<MinimalPositionCard pair={pair} border="1px solid #CED0D9" />
<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>
<CurrencySearchModal
isOpen={showSearch}
onCurrencySelect={handleCurrencySelect}
onDismiss={handleSearchDismiss}
showCommonBases
selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined}
/>
</AppBody>
<SwitchLocaleLink />
</>
) : 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 />
</>
</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}
......
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>
<AutoColumn gap="md">
<RowBetween>
<ThemedText.White fontWeight={600}>
<Trans>Uniswap Governance</Trans>
</ThemedText.White>
</RowBetween>
<RowBetween>
<ThemedText.White fontSize={14}>
<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>
UNI tokens represent voting shares in Uniswap governance. You can vote on each proposal yourself
or delegate your votes to a third party.
<FormattedCurrencyAmount currencyAmount={availableVotes} /> Votes
</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 ? (
</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
style={{ width: 'fit-content' }}
as={Link}
to="/create-proposal"
style={{ width: 'fit-content', borderRadius: '8px' }}
padding="8px"
$borderRadius="8px"
onClick={toggleDelegateModal}
>
<Trans>Unlock Voting</Trans>
<Trans>Create Proposal</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">
</AutoRow>
</WrapSmall>
{!showUnlockVoting && (
<RowBetween>
<ThemedText.Main>
<Trans>Show Cancelled</Trans>
</ThemedText.Main>
<Toggle isActive={!hideCancelled} toggle={() => setHideCancelled((hideCancelled) => !hideCancelled)} />
<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>
</AutoColumn>
)}
)}
{allProposals?.length === 0 && <ProposalEmptyState />}
{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>
{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()
}}
>
<Trans>Vote For</Trans>
</ButtonPrimary>
<ButtonPrimary
padding="8px"
$borderRadius="8px"
onClick={() => {
setVoteOption(VoteOption.Against)
toggleVoteModal()
}}
// can't execute until the eta has arrived
disabled={!currentTimestamp || !proposalData?.eta || currentTimestamp.lt(proposalData.eta)}
>
<Trans>Execute</Trans>
<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>
)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment