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. * Known pages in the app. Highest order context.
*/ */
export const enum PageName { export const enum PageName {
EXPLORE_PAGE = 'explore-page',
POOL_PAGE = 'pool-page',
SWAP_PAGE = 'swap-page', SWAP_PAGE = 'swap-page',
VOTE_PAGE = 'vote-page',
// alphabetize additional page names. // alphabetize additional page names.
} }

@ -3,6 +3,8 @@ import { getAddress, isAddress } from '@ethersproject/address'
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/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 { ButtonError } from 'components/Button'
import { BlueCard } from 'components/Card' import { BlueCard } from 'components/Card'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
@ -225,63 +227,66 @@ ${bodyValue}
} }
return ( return (
<AppBody {...{ maxWidth: '800px' }}> <Trace page={PageName.VOTE_PAGE} shouldLogImpression>
<CreateProposalTabs /> <AppBody {...{ maxWidth: '800px' }}>
<CreateProposalWrapper> <CreateProposalTabs />
<BlueCard> <CreateProposalWrapper>
<AutoColumn gap="10px"> <BlueCard>
<ThemedText.Link fontWeight={400} color={'primaryText1'}> <AutoColumn gap="10px">
<Trans> <ThemedText.Link fontWeight={400} color={'primaryText1'}>
<strong>Tip:</strong> Select an action and describe your proposal for the community. The proposal cannot <Trans>
be modified after submission, so please verify all information before submitting. The voting period will <strong>Tip:</strong> Select an action and describe your proposal for the community. The proposal
begin immediately and last for 7 days. To propose a custom action,{' '} cannot be modified after submission, so please verify all information before submitting. The voting
<ExternalLink href="https://uniswap.org/docs/v2/governance/governance-reference/#propose"> period will begin immediately and last for 7 days. To propose a custom action,{' '}
read the docs <ExternalLink href="https://uniswap.org/docs/v2/governance/governance-reference/#propose">
</ExternalLink> read the docs
. </ExternalLink>
</Trans> .
</ThemedText.Link> </Trans>
</AutoColumn> </ThemedText.Link>
</BlueCard> </AutoColumn>
</BlueCard>
<ProposalActionSelector onClick={handleActionSelectorClick} proposalAction={proposalAction} /> <ProposalActionSelector onClick={handleActionSelectorClick} proposalAction={proposalAction} />
<ProposalActionDetail <ProposalActionDetail
proposalAction={proposalAction} proposalAction={proposalAction}
currency={currencyValue} currency={currencyValue}
amount={amountValue} amount={amountValue}
toAddress={toAddressValue} toAddress={toAddressValue}
onCurrencySelect={handleCurrencySelect} onCurrencySelect={handleCurrencySelect}
onAmountInput={handleAmountInput} onAmountInput={handleAmountInput}
onToAddressInput={handleToAddressInput} 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 <ProposalSubmissionModal isOpen={attempting} hash={hash} onDismiss={handleDismissSubmissionModal} />
title={titleValue} </AppBody>
body={bodyValue} </Trace>
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>
) )
} }

@ -4,6 +4,8 @@ import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Fraction, Percent, Price, Token } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Fraction, Percent, Price, Token } from '@uniswap/sdk-core'
import { NonfungiblePositionManager, Pool, Position } from '@uniswap/v3-sdk' import { NonfungiblePositionManager, Pool, Position } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { PageName } from 'components/AmplitudeAnalytics/constants'
import { Trace } from 'components/AmplitudeAnalytics/Trace'
import { sendEvent } from 'components/analytics' import { sendEvent } from 'components/analytics'
import Badge from 'components/Badge' import Badge from 'components/Badge'
import { ButtonConfirmed, ButtonGray, ButtonPrimary } from 'components/Button' import { ButtonConfirmed, ButtonGray, ButtonPrimary } from 'components/Button'
@ -567,344 +569,347 @@ export function PositionPage({
<div /> <div />
</LoadingRows> </LoadingRows>
) : ( ) : (
<> <Trace page={PageName.POOL_PAGE} shouldLogImpression>
<PageWrapper> <>
<TransactionConfirmationModal <PageWrapper>
isOpen={showConfirm} <TransactionConfirmationModal
onDismiss={() => setShowConfirm(false)} isOpen={showConfirm}
attemptingTxn={collecting} onDismiss={() => setShowConfirm(false)}
hash={collectMigrationHash ?? ''} attemptingTxn={collecting}
content={() => ( hash={collectMigrationHash ?? ''}
<ConfirmationModalContent content={() => (
title={<Trans>Claim fees</Trans>} <ConfirmationModalContent
onDismiss={() => setShowConfirm(false)} title={<Trans>Claim fees</Trans>}
topContent={modalHeader} onDismiss={() => setShowConfirm(false)}
/> topContent={modalHeader}
)}
pendingText={<Trans>Collecting fees</Trans>}
/>
<AutoColumn gap="md">
<AutoColumn gap="sm">
<Link style={{ textDecoration: 'none', width: 'fit-content', marginBottom: '0.5rem' }} to="/pool">
<HoverText>
<Trans> Back to Pools Overview</Trans>
</HoverText>
</Link>
<ResponsiveRow>
<RowFixed>
<DoubleCurrencyLogo currency0={currencyBase} currency1={currencyQuote} size={24} margin={true} />
<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}
/> />
)}
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> </AutoColumn>
</DarkCard> <ResponsiveRow align="flex-start">
</AutoColumn> {'result' in metadata ? (
</PageWrapper> <DarkCard
<SwitchLocaleLink /> 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 { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core' 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 { ButtonGray, ButtonPrimary, ButtonText } from 'components/Button'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import { FlyoutAlignment, NewMenu } from 'components/Menu' import { FlyoutAlignment, NewMenu } from 'components/Menu'
@ -252,76 +254,78 @@ export default function Pool() {
] ]
return ( return (
<> <Trace page={PageName.POOL_PAGE} shouldLogImpression>
<PageWrapper> <>
<SwapPoolTabs active="pool" /> <PageWrapper>
<AutoColumn gap="lg" justify="center"> <SwapPoolTabs active="pool" />
<AutoColumn gap="lg" style={{ width: '100%' }}> <AutoColumn gap="lg" justify="center">
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}> <AutoColumn gap="lg" style={{ width: '100%' }}>
<ThemedText.Body fontSize={'20px'}> <TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
<Trans>Pools Overview</Trans> <ThemedText.Body fontSize={'20px'}>
</ThemedText.Body> <Trans>Pools Overview</Trans>
<ButtonRow> </ThemedText.Body>
{showV2Features && ( <ButtonRow>
<Menu {showV2Features && (
menuItems={menuItems} <Menu
flyoutAlignment={FlyoutAlignment.LEFT} menuItems={menuItems}
ToggleUI={(props: any) => ( flyoutAlignment={FlyoutAlignment.LEFT}
<MoreOptionsButton {...props}> ToggleUI={(props: any) => (
<MoreOptionsText> <MoreOptionsButton {...props}>
<Trans>More</Trans> <MoreOptionsText>
<ChevronDown size={15} /> <Trans>More</Trans>
</MoreOptionsText> <ChevronDown size={15} />
</MoreOptionsButton> </MoreOptionsText>
)} </MoreOptionsButton>
/> )}
)} />
<ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/ETH"> )}
+ <Trans>New Position</Trans> <ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/ETH">
</ResponsiveButtonPrimary> + <Trans>New Position</Trans>
</ButtonRow> </ResponsiveButtonPrimary>
</TitleRow> </ButtonRow>
</TitleRow>
<MainContentWrapper> <MainContentWrapper>
{positionsLoading ? ( {positionsLoading ? (
<PositionsLoadingPlaceholder /> <PositionsLoadingPlaceholder />
) : filteredPositions && closedPositions && filteredPositions.length > 0 ? ( ) : filteredPositions && closedPositions && filteredPositions.length > 0 ? (
<PositionList <PositionList
positions={filteredPositions} positions={filteredPositions}
setUserHideClosedPositions={setUserHideClosedPositions} setUserHideClosedPositions={setUserHideClosedPositions}
userHideClosedPositions={userHideClosedPositions} userHideClosedPositions={userHideClosedPositions}
/> />
) : ( ) : (
<ErrorContainer> <ErrorContainer>
<ThemedText.Body color={theme.text3} textAlign="center"> <ThemedText.Body color={theme.text3} textAlign="center">
<InboxIcon strokeWidth={1} /> <InboxIcon strokeWidth={1} />
<div> <div>
<Trans>Your active V3 liquidity positions will appear here.</Trans> <Trans>Your active V3 liquidity positions will appear here.</Trans>
</div> </div>
</ThemedText.Body> </ThemedText.Body>
{!showConnectAWallet && closedPositions.length > 0 && ( {!showConnectAWallet && closedPositions.length > 0 && (
<ButtonText <ButtonText
style={{ marginTop: '.5rem' }} style={{ marginTop: '.5rem' }}
onClick={() => setUserHideClosedPositions(!userHideClosedPositions)} onClick={() => setUserHideClosedPositions(!userHideClosedPositions)}
> >
<Trans>Show closed positions</Trans> <Trans>Show closed positions</Trans>
</ButtonText> </ButtonText>
)} )}
{showConnectAWallet && ( {showConnectAWallet && (
<ButtonPrimary style={{ marginTop: '2em', padding: '8px 16px' }} onClick={toggleWalletModal}> <ButtonPrimary style={{ marginTop: '2em', padding: '8px 16px' }} onClick={toggleWalletModal}>
<Trans>Connect a wallet</Trans> <Trans>Connect a wallet</Trans>
</ButtonPrimary> </ButtonPrimary>
)} )}
</ErrorContainer> </ErrorContainer>
)} )}
</MainContentWrapper> </MainContentWrapper>
<HideSmall> <HideSmall>
<CTACards /> <CTACards />
</HideSmall> </HideSmall>
</AutoColumn>
</AutoColumn> </AutoColumn>
</AutoColumn> </PageWrapper>
</PageWrapper> <SwitchLocaleLink />
<SwitchLocaleLink /> </>
</> </Trace>
) )
} }

@ -1,6 +1,8 @@
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Pair } from '@uniswap/v2-sdk' import { Pair } from '@uniswap/v2-sdk'
import { useWeb3React } from '@web3-react/core' 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 { UNSUPPORTED_V2POOL_CHAIN_IDS } from 'constants/chains'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useContext, useMemo } from 'react' import { useContext, useMemo } from 'react'
@ -135,147 +137,149 @@ export default function Pool() {
}) })
return ( return (
<> <Trace page={PageName.POOL_PAGE} shouldLogImpression>
<PageWrapper> <>
<SwapPoolTabs active={'pool'} /> <PageWrapper>
<VoteCard> <SwapPoolTabs active={'pool'} />
<CardBGImage /> <VoteCard>
<CardNoise /> <CardBGImage />
<CardSection> <CardNoise />
<AutoColumn gap="md"> <CardSection>
<RowBetween> <AutoColumn gap="md">
<ThemedText.White fontWeight={600}> <RowBetween>
<Trans>Liquidity provider rewards</Trans> <ThemedText.White fontWeight={600}>
</ThemedText.White> <Trans>Liquidity provider rewards</Trans>
</RowBetween> </ThemedText.White>
<RowBetween> </RowBetween>
<ThemedText.White fontSize={14}> <RowBetween>
<Trans> <ThemedText.White fontSize={14}>
Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees are <Trans>
added to the pool, accrue in real time and can be claimed by withdrawing your liquidity. Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees
</Trans> are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.
</ThemedText.White> </Trans>
</RowBetween> </ThemedText.White>
<ExternalLink </RowBetween>
style={{ color: 'white', textDecoration: 'underline' }} <ExternalLink
target="_blank" style={{ color: 'white', textDecoration: 'underline' }}
href="https://uniswap.org/docs/v2/core-concepts/pools/" target="_blank"
> href="https://uniswap.org/docs/v2/core-concepts/pools/"
<ThemedText.White fontSize={14}> >
<Trans>Read more about providing liquidity</Trans> <ThemedText.White fontSize={14}>
</ThemedText.White> <Trans>Read more about providing liquidity</Trans>
</ExternalLink> </ThemedText.White>
</AutoColumn> </ExternalLink>
</CardSection> </AutoColumn>
<CardBGImage /> </CardSection>
<CardNoise /> <CardBGImage />
</VoteCard> <CardNoise />
</VoteCard>
{unsupportedV2Network ? ( {unsupportedV2Network ? (
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="lg" justify="center">
<AutoColumn gap="md" style={{ width: '100%' }}> <AutoColumn gap="md" style={{ width: '100%' }}>
<Layer2Prompt> <Layer2Prompt>
<ThemedText.Body color={theme.text3} textAlign="center"> <ThemedText.Body color={theme.text3} textAlign="center">
<Trans>V2 Pool is not available on Layer 2. Switch to Layer 1 Ethereum.</Trans> <Trans>V2 Pool is not available on Layer 2. Switch to Layer 1 Ethereum.</Trans>
</ThemedText.Body> </ThemedText.Body>
</Layer2Prompt> </Layer2Prompt>
</AutoColumn>
</AutoColumn> </AutoColumn>
</AutoColumn> ) : (
) : ( <AutoColumn gap="lg" justify="center">
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="md" style={{ width: '100%' }}>
<AutoColumn gap="md" style={{ width: '100%' }}> <TitleRow style={{ marginTop: '1rem' }} padding={'0'}>
<TitleRow style={{ marginTop: '1rem' }} padding={'0'}> <HideSmall>
<HideSmall> <ThemedText.MediumHeader style={{ marginTop: '0.5rem', justifySelf: 'flex-start' }}>
<ThemedText.MediumHeader style={{ marginTop: '0.5rem', justifySelf: 'flex-start' }}> <Trans>Your V2 liquidity</Trans>
<Trans>Your V2 liquidity</Trans> </ThemedText.MediumHeader>
</ThemedText.MediumHeader> </HideSmall>
</HideSmall> <ButtonRow>
<ButtonRow> <ResponsiveButtonSecondary as={Link} padding="6px 8px" to="/add/v2/ETH">
<ResponsiveButtonSecondary as={Link} padding="6px 8px" to="/add/v2/ETH"> <Trans>Create a pair</Trans>
<Trans>Create a pair</Trans> </ResponsiveButtonSecondary>
</ResponsiveButtonSecondary> <ResponsiveButtonPrimary id="find-pool-button" as={Link} to="/pool/v2/find" padding="6px 8px">
<ResponsiveButtonPrimary id="find-pool-button" as={Link} to="/pool/v2/find" padding="6px 8px"> <Text fontWeight={500} fontSize={16}>
<Text fontWeight={500} fontSize={16}> <Trans>Import Pool</Trans>
<Trans>Import Pool</Trans> </Text>
</Text> </ResponsiveButtonPrimary>
</ResponsiveButtonPrimary> <ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/v2/ETH" padding="6px 8px">
<ResponsiveButtonPrimary id="join-pool-button" as={Link} to="/add/v2/ETH" padding="6px 8px"> <Text fontWeight={500} fontSize={16}>
<Text fontWeight={500} fontSize={16}> <Trans>Add V2 Liquidity</Trans>
<Trans>Add V2 Liquidity</Trans> </Text>
</Text> </ResponsiveButtonPrimary>
</ResponsiveButtonPrimary> </ButtonRow>
</ButtonRow> </TitleRow>
</TitleRow>
{!account ? ( {!account ? (
<Card padding="40px"> <Card padding="40px">
<ThemedText.Body color={theme.text3} textAlign="center"> <ThemedText.Body color={theme.text3} textAlign="center">
<Trans>Connect to a wallet to view your liquidity.</Trans> <Trans>Connect to a wallet to view your liquidity.</Trans>
</ThemedText.Body> </ThemedText.Body>
</Card> </Card>
) : v2IsLoading ? ( ) : v2IsLoading ? (
<EmptyProposals> <EmptyProposals>
<ThemedText.Body color={theme.text3} textAlign="center"> <ThemedText.Body color={theme.text3} textAlign="center">
<Dots> <Dots>
<Trans>Loading</Trans> <Trans>Loading</Trans>
</Dots> </Dots>
</ThemedText.Body> </ThemedText.Body>
</EmptyProposals> </EmptyProposals>
) : allV2PairsWithLiquidity?.length > 0 || stakingPairs?.length > 0 ? ( ) : allV2PairsWithLiquidity?.length > 0 || stakingPairs?.length > 0 ? (
<> <>
<ButtonSecondary> <ButtonSecondary>
<RowBetween> <RowBetween>
<Trans> <Trans>
<ExternalLink href={'https://v2.info.uniswap.org/account/' + account}> <ExternalLink href={'https://v2.info.uniswap.org/account/' + account}>
Account analytics and accrued fees Account analytics and accrued fees
</ExternalLink> </ExternalLink>
<span> </span> <span> </span>
</Trans> </Trans>
</RowBetween> </RowBetween>
</ButtonSecondary> </ButtonSecondary>
{v2PairsWithoutStakedAmount.map((v2Pair) => ( {v2PairsWithoutStakedAmount.map((v2Pair) => (
<FullPositionCard key={v2Pair.liquidityToken.address} pair={v2Pair} /> <FullPositionCard key={v2Pair.liquidityToken.address} pair={v2Pair} />
))} ))}
{stakingPairs.map( {stakingPairs.map(
(stakingPair, i) => (stakingPair, i) =>
stakingPair[1] && ( // skip pairs that arent loaded stakingPair[1] && ( // skip pairs that arent loaded
<FullPositionCard <FullPositionCard
key={stakingInfosWithBalance[i].stakingRewardAddress} key={stakingInfosWithBalance[i].stakingRewardAddress}
pair={stakingPair[1]} pair={stakingPair[1]}
stakedBalance={stakingInfosWithBalance[i].stakedAmount} stakedBalance={stakingInfosWithBalance[i].stakedAmount}
/> />
) )
)} )}
<RowFixed justify="center" style={{ width: '100%' }}> <RowFixed justify="center" style={{ width: '100%' }}>
<ButtonOutlined <ButtonOutlined
as={Link} as={Link}
to="/migrate/v2" to="/migrate/v2"
id="import-pool-link" id="import-pool-link"
style={{ style={{
padding: '8px 16px', padding: '8px 16px',
margin: '0 4px', margin: '0 4px',
borderRadius: '12px', borderRadius: '12px',
width: 'fit-content', width: 'fit-content',
fontSize: '14px', fontSize: '14px',
}} }}
> >
<ChevronsRight size={16} style={{ marginRight: '8px' }} /> <ChevronsRight size={16} style={{ marginRight: '8px' }} />
<Trans>Migrate Liquidity to V3</Trans> <Trans>Migrate Liquidity to V3</Trans>
</ButtonOutlined> </ButtonOutlined>
</RowFixed> </RowFixed>
</> </>
) : ( ) : (
<EmptyProposals> <EmptyProposals>
<ThemedText.Body color={theme.text3} textAlign="center"> <ThemedText.Body color={theme.text3} textAlign="center">
<Trans>No liquidity found.</Trans> <Trans>No liquidity found.</Trans>
</ThemedText.Body> </ThemedText.Body>
</EmptyProposals> </EmptyProposals>
)} )}
</AutoColumn>
</AutoColumn> </AutoColumn>
</AutoColumn> )}
)} </PageWrapper>
</PageWrapper> <SwitchLocaleLink />
<SwitchLocaleLink /> </>
</> </Trace>
) )
} }

@ -1,6 +1,8 @@
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { PageName } from 'components/AmplitudeAnalytics/constants'
import { Trace } from 'components/AmplitudeAnalytics/Trace'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { Plus } from 'react-feather' import { Plus } from 'react-feather'
@ -95,139 +97,141 @@ export default function PoolFinder() {
) )
return ( return (
<> <Trace page={PageName.POOL_PAGE} shouldLogImpression>
<AppBody> <>
<FindPoolTabs origin={query.get('origin') ?? '/pool/v2'} /> <AppBody>
<AutoColumn style={{ padding: '1rem' }} gap="md"> <FindPoolTabs origin={query.get('origin') ?? '/pool/v2'} />
<BlueCard> <AutoColumn style={{ padding: '1rem' }} gap="md">
<AutoColumn gap="10px"> <BlueCard>
<ThemedText.Link fontWeight={400} color={'primaryText1'}> <AutoColumn gap="10px">
<Trans> <ThemedText.Link fontWeight={400} color={'primaryText1'}>
<b>Tip:</b> Use this tool to find v2 pools that don&apos;t automatically appear in the interface. <Trans>
</Trans> <b>Tip:</b> Use this tool to find v2 pools that don&apos;t automatically appear in the interface.
</ThemedText.Link> </Trans>
</AutoColumn> </ThemedText.Link>
</BlueCard> </AutoColumn>
<ButtonDropdownLight </BlueCard>
onClick={() => { <ButtonDropdownLight
setShowSearch(true) onClick={() => {
setActiveField(Fields.TOKEN0) setShowSearch(true)
}} setActiveField(Fields.TOKEN0)
> }}
{currency0 ? (
<Row>
<CurrencyLogo currency={currency0} />
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
{currency0.symbol}
</Text>
</Row>
) : (
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
<Trans>Select a token</Trans>
</Text>
)}
</ButtonDropdownLight>
<ColumnCenter>
<Plus size="16" color="#888D9B" />
</ColumnCenter>
<ButtonDropdownLight
onClick={() => {
setShowSearch(true)
setActiveField(Fields.TOKEN1)
}}
>
{currency1 ? (
<Row>
<CurrencyLogo currency={currency1} />
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
{currency1.symbol}
</Text>
</Row>
) : (
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
<Trans>Select a token</Trans>
</Text>
)}
</ButtonDropdownLight>
{hasPosition && (
<ColumnCenter
style={{ justifyItems: 'center', backgroundColor: '', padding: '12px 0px', borderRadius: '12px' }}
> >
<Text textAlign="center" fontWeight={500}> {currency0 ? (
<Trans>Pool Found!</Trans> <Row>
</Text> <CurrencyLogo currency={currency0} />
<StyledInternalLink to={`/pool/v2`}> <Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
<Text textAlign="center"> {currency0.symbol}
<Trans>Manage this pool.</Trans> </Text>
</Text> </Row>
</StyledInternalLink>
</ColumnCenter>
)}
{currency0 && currency1 ? (
pairState === PairState.EXISTS ? (
hasPosition && pair ? (
<MinimalPositionCard pair={pair} border="1px solid #CED0D9" />
) : ( ) : (
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
<Trans>Select a token</Trans>
</Text>
)}
</ButtonDropdownLight>
<ColumnCenter>
<Plus size="16" color="#888D9B" />
</ColumnCenter>
<ButtonDropdownLight
onClick={() => {
setShowSearch(true)
setActiveField(Fields.TOKEN1)
}}
>
{currency1 ? (
<Row>
<CurrencyLogo currency={currency1} />
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
{currency1.symbol}
</Text>
</Row>
) : (
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
<Trans>Select a token</Trans>
</Text>
)}
</ButtonDropdownLight>
{hasPosition && (
<ColumnCenter
style={{ justifyItems: 'center', backgroundColor: '', padding: '12px 0px', borderRadius: '12px' }}
>
<Text textAlign="center" fontWeight={500}>
<Trans>Pool Found!</Trans>
</Text>
<StyledInternalLink to={`/pool/v2`}>
<Text textAlign="center">
<Trans>Manage this pool.</Trans>
</Text>
</StyledInternalLink>
</ColumnCenter>
)}
{currency0 && currency1 ? (
pairState === PairState.EXISTS ? (
hasPosition && pair ? (
<MinimalPositionCard pair={pair} border="1px solid #CED0D9" />
) : (
<LightCard padding="45px 10px">
<AutoColumn gap="sm" justify="center">
<Text textAlign="center">
<Trans>You 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"> <LightCard padding="45px 10px">
<AutoColumn gap="sm" justify="center"> <AutoColumn gap="sm" justify="center">
<Text textAlign="center"> <Text textAlign="center">
<Trans>You dont have liquidity in this pool yet.</Trans> <Trans>No pool found.</Trans>
</Text> </Text>
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}> <StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}>
<Text textAlign="center"> <Trans>Create pool.</Trans>
<Trans>Add liquidity.</Trans>
</Text>
</StyledInternalLink> </StyledInternalLink>
</AutoColumn> </AutoColumn>
</LightCard> </LightCard>
) ) : pairState === PairState.INVALID ? (
) : validPairNoLiquidity ? ( <LightCard padding="45px 10px">
<LightCard padding="45px 10px"> <AutoColumn gap="sm" justify="center">
<AutoColumn gap="sm" justify="center"> <Text textAlign="center" fontWeight={500}>
<Text textAlign="center"> <Trans>Invalid pair.</Trans>
<Trans>No pool found.</Trans> </Text>
</Text> </AutoColumn>
<StyledInternalLink to={`/add/${currencyId(currency0)}/${currencyId(currency1)}`}> </LightCard>
<Trans>Create pool.</Trans> ) : pairState === PairState.LOADING ? (
</StyledInternalLink> <LightCard padding="45px 10px">
</AutoColumn> <AutoColumn gap="sm" justify="center">
</LightCard> <Text textAlign="center">
) : pairState === PairState.INVALID ? ( <Trans>Loading</Trans>
<LightCard padding="45px 10px"> <Dots />
<AutoColumn gap="sm" justify="center"> </Text>
<Text textAlign="center" fontWeight={500}> </AutoColumn>
<Trans>Invalid pair.</Trans> </LightCard>
</Text> ) : null
</AutoColumn> ) : (
</LightCard> prerequisiteMessage
) : pairState === PairState.LOADING ? ( )}
<LightCard padding="45px 10px"> </AutoColumn>
<AutoColumn gap="sm" justify="center">
<Text textAlign="center">
<Trans>Loading</Trans>
<Dots />
</Text>
</AutoColumn>
</LightCard>
) : null
) : (
prerequisiteMessage
)}
</AutoColumn>
<CurrencySearchModal <CurrencySearchModal
isOpen={showSearch} isOpen={showSearch}
onCurrencySelect={handleCurrencySelect} onCurrencySelect={handleCurrencySelect}
onDismiss={handleSearchDismiss} onDismiss={handleSearchDismiss}
showCommonBases showCommonBases
selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined} selectedCurrency={(activeField === Fields.TOKEN0 ? currency1 : currency0) ?? undefined}
/> />
</AppBody> </AppBody>
<SwitchLocaleLink /> <SwitchLocaleLink />
</> </>
</Trace>
) )
} }

@ -398,7 +398,7 @@ export default function Swap({ history }: RouteComponentProps) {
const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode
return ( return (
<Trace page={PageName.SWAP_PAGE} shouldLogImpression={false}> <Trace page={PageName.SWAP_PAGE} shouldLogImpression>
<> <>
<TokenWarningModal <TokenWarningModal
isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning} isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning}

@ -1,6 +1,8 @@
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { CurrencyAmount, Token } from '@uniswap/sdk-core' import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/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 { ButtonPrimary } from 'components/Button'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import { CardBGImage, CardNoise, CardSection, DataCard } from 'components/earn/styled' import { CardBGImage, CardNoise, CardSection, DataCard } from 'components/earn/styled'
@ -132,150 +134,155 @@ export default function Landing() {
) )
return ( return (
<> <>
<PageWrapper gap="lg" justify="center"> <Trace page={PageName.VOTE_PAGE} shouldLogImpression>
<DelegateModal <PageWrapper gap="lg" justify="center">
isOpen={showDelegateModal} <DelegateModal
onDismiss={toggleDelegateModal} isOpen={showDelegateModal}
title={showUnlockVoting ? <Trans>Unlock Votes</Trans> : <Trans>Update Delegation</Trans>} onDismiss={toggleDelegateModal}
/> title={showUnlockVoting ? <Trans>Unlock Votes</Trans> : <Trans>Update Delegation</Trans>}
<TopSection gap="md"> />
<VoteCard> <TopSection gap="md">
<CardBGImage /> <VoteCard>
<CardNoise /> <CardBGImage />
<CardSection> <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"> <AutoColumn gap="md">
<RowBetween> <RowBetween>
<ThemedText.White fontWeight={600}> <ThemedText.Main>
<Trans>Uniswap Governance</Trans> <Trans>Show Cancelled</Trans>
</ThemedText.White> </ThemedText.Main>
<Toggle
isActive={!hideCancelled}
toggle={() => setHideCancelled((hideCancelled) => !hideCancelled)}
/>
</RowBetween> </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> </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 && ( <ThemedText.SubHeader color="text3">
<AutoColumn gap="md"> <Trans>A minimum threshold of 0.25% of the total UNI supply is required to submit proposals</Trans>
<RowBetween> </ThemedText.SubHeader>
<ThemedText.Main> </PageWrapper>
<Trans>Show Cancelled</Trans> </Trace>
</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>
<SwitchLocaleLink /> <SwitchLocaleLink />
</> </>
) )

@ -2,6 +2,8 @@ import { BigNumber } from '@ethersproject/bignumber'
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { CurrencyAmount, Fraction, Token } from '@uniswap/sdk-core' import { CurrencyAmount, Fraction, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/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 ExecuteModal from 'components/vote/ExecuteModal'
import QueueModal from 'components/vote/QueueModal' import QueueModal from 'components/vote/QueueModal'
import { useActiveLocale } from 'hooks/useActiveLocale' import { useActiveLocale } from 'hooks/useActiveLocale'
@ -258,226 +260,232 @@ export default function VotePage({
} }
return ( return (
<> <Trace page={PageName.VOTE_PAGE} shouldLogImpression>
<PageWrapper gap="lg" justify="center"> <>
<VoteModal <PageWrapper gap="lg" justify="center">
isOpen={showVoteModal} <VoteModal
onDismiss={toggleVoteModal} isOpen={showVoteModal}
proposalId={proposalData?.id} onDismiss={toggleVoteModal}
voteOption={voteOption} proposalId={proposalData?.id}
/> voteOption={voteOption}
<DelegateModal isOpen={showDelegateModal} onDismiss={toggleDelegateModal} title={<Trans>Unlock Votes</Trans>} /> />
<QueueModal isOpen={showQueueModal} onDismiss={toggleQueueModal} proposalId={proposalData?.id} /> <DelegateModal
<ExecuteModal isOpen={showExecuteModal} onDismiss={toggleExecuteModal} proposalId={proposalData?.id} /> isOpen={showDelegateModal}
<ProposalInfo gap="lg" justify="start"> onDismiss={toggleDelegateModal}
<RowBetween style={{ width: '100%' }}> title={<Trans>Unlock Votes</Trans>}
<ArrowWrapper to="/vote"> />
<Trans> <QueueModal isOpen={showQueueModal} onDismiss={toggleQueueModal} proposalId={proposalData?.id} />
<ArrowLeft size={20} /> All Proposals <ExecuteModal isOpen={showExecuteModal} onDismiss={toggleExecuteModal} proposalId={proposalData?.id} />
</Trans> <ProposalInfo gap="lg" justify="start">
</ArrowWrapper> <RowBetween style={{ width: '100%' }}>
{proposalData && <ProposalStatus status={proposalData.status} />} <ArrowWrapper to="/vote">
</RowBetween> <Trans>
<AutoColumn gap="10px" style={{ width: '100%' }}> <ArrowLeft size={20} /> All Proposals
<ThemedText.LargeHeader style={{ marginBottom: '.5rem' }}>{proposalData?.title}</ThemedText.LargeHeader> </Trans>
<RowBetween> </ArrowWrapper>
<ThemedText.Main> {proposalData && <ProposalStatus status={proposalData.status} />}
{startDate && startDate > now ? (
<Trans>Voting starts approximately {startDate.toLocaleString(locale, dateFormat)}</Trans>
) : null}
</ThemedText.Main>
</RowBetween> </RowBetween>
<RowBetween> <AutoColumn gap="10px" style={{ width: '100%' }}>
<ThemedText.Main> <ThemedText.LargeHeader style={{ marginBottom: '.5rem' }}>{proposalData?.title}</ThemedText.LargeHeader>
{endDate && <RowBetween>
(endDate < now ? ( <ThemedText.Main>
<Trans>Voting ended {endDate.toLocaleString(locale, dateFormat)}</Trans> {startDate && startDate > now ? (
) : ( <Trans>Voting starts approximately {startDate.toLocaleString(locale, dateFormat)}</Trans>
<Trans>Voting ends approximately {endDate.toLocaleString(locale, dateFormat)}</Trans> ) : null}
))} </ThemedText.Main>
</ThemedText.Main> </RowBetween>
</RowBetween> <RowBetween>
{proposalData && proposalData.status === ProposalState.ACTIVE && !showVotingButtons && ( <ThemedText.Main>
<GreyCard> {endDate &&
<ThemedText.Black> (endDate < now ? (
<Trans> <Trans>Voting ended {endDate.toLocaleString(locale, dateFormat)}</Trans>
Only UNI votes that were self delegated or delegated to another address before block{' '} ) : (
{proposalData.startBlock} are eligible for voting. <Trans>Voting ends approximately {endDate.toLocaleString(locale, dateFormat)}</Trans>
</Trans>{' '} ))}
{showLinkForUnlock && ( </ThemedText.Main>
<span> </RowBetween>
<Trans> {proposalData && proposalData.status === ProposalState.ACTIVE && !showVotingButtons && (
<StyledInternalLink to="/vote">Unlock voting</StyledInternalLink> to prepare for the next <GreyCard>
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>
<ThemedText.Black> <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> </ThemedText.Black>
</RowBetween> </GreyCard>
)} )}
</AutoColumn>
{showVotingButtons && (
<RowFixed style={{ width: '100%', gap: '12px' }}> <RowFixed style={{ width: '100%', gap: '12px' }}>
<ButtonPrimary <ButtonPrimary
padding="8px" padding="8px"
$borderRadius="8px" $borderRadius="8px"
onClick={() => { 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> </ButtonPrimary>
</RowFixed> </RowFixed>
</> )}
)} {showQueueButton && (
<CardWrapper> <RowFixed style={{ width: '100%', gap: '12px' }}>
<StyledDataCard> <ButtonPrimary
<CardSection> padding="8px"
<AutoColumn gap="md"> $borderRadius="8px"
<WrapSmall> onClick={() => {
<ThemedText.Black fontWeight={600}> toggleQueueModal()
<Trans>For</Trans> }}
>
<Trans>Queue</Trans>
</ButtonPrimary>
</RowFixed>
)}
{showExecuteButton && (
<>
{eta && (
<RowBetween>
<ThemedText.Black>
<Trans>This proposal may be executed after {eta.toLocaleString(locale, dateFormat)}.</Trans>
</ThemedText.Black> </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}> <ThemedText.Black fontWeight={600}>
{proposalData.forCount.toFixed(0, { groupSeparator: ',' })} <Trans>For</Trans>
{quorumAmount && (
<span style={{ fontWeight: 400 }}>{` / ${quorumAmount.toExact({
groupSeparator: ',',
})}`}</span>
)}
</ThemedText.Black> </ThemedText.Black>
)} {proposalData && (
</WrapSmall> <ThemedText.Black fontWeight={600}>
</AutoColumn> {proposalData.forCount.toFixed(0, { groupSeparator: ',' })}
<ProgressWrapper> {quorumAmount && (
<Progress <span style={{ fontWeight: 400 }}>{` / ${quorumAmount.toExact({
status={'for'} groupSeparator: ',',
percentageString={ })}`}</span>
proposalData?.forCount.greaterThan(0) ? `${forPercentage?.toFixed(0) ?? 0}%` : '0%' )}
} </ThemedText.Black>
/> )}
</ProgressWrapper> </WrapSmall>
</CardSection> </AutoColumn>
</StyledDataCard> <ProgressWrapper>
<StyledDataCard> <Progress
<CardSection> status={'for'}
<AutoColumn gap="md"> percentageString={
<WrapSmall> proposalData?.forCount.greaterThan(0) ? `${forPercentage?.toFixed(0) ?? 0}%` : '0%'
<ThemedText.Black fontWeight={600}> }
<Trans>Against</Trans> />
</ThemedText.Black> </ProgressWrapper>
{proposalData && ( </CardSection>
</StyledDataCard>
<StyledDataCard>
<CardSection>
<AutoColumn gap="md">
<WrapSmall>
<ThemedText.Black fontWeight={600}> <ThemedText.Black fontWeight={600}>
{proposalData.againstCount.toFixed(0, { groupSeparator: ',' })} <Trans>Against</Trans>
</ThemedText.Black> </ThemedText.Black>
)} {proposalData && (
</WrapSmall> <ThemedText.Black fontWeight={600}>
</AutoColumn> {proposalData.againstCount.toFixed(0, { groupSeparator: ',' })}
<ProgressWrapper> </ThemedText.Black>
<Progress )}
status={'against'} </WrapSmall>
percentageString={ </AutoColumn>
proposalData?.againstCount?.greaterThan(0) ? `${againstPercentage?.toFixed(0) ?? 0}%` : '0%' <ProgressWrapper>
} <Progress
/> status={'against'}
</ProgressWrapper> percentageString={
</CardSection> proposalData?.againstCount?.greaterThan(0) ? `${againstPercentage?.toFixed(0) ?? 0}%` : '0%'
</StyledDataCard> }
</CardWrapper> />
<AutoColumn gap="md"> </ProgressWrapper>
<ThemedText.MediumHeader fontWeight={600}> </CardSection>
<Trans>Details</Trans> </StyledDataCard>
</ThemedText.MediumHeader> </CardWrapper>
{proposalData?.details?.map((d, i) => { <AutoColumn gap="md">
return ( <ThemedText.MediumHeader fontWeight={600}>
<DetailText key={i}> <Trans>Details</Trans>
{i + 1}: {linkIfAddress(d.target)}.{d.functionSig}( </ThemedText.MediumHeader>
{d.callData.split(',').map((content, i) => { {proposalData?.details?.map((d, i) => {
return ( return (
<span key={i}> <DetailText key={i}>
{linkIfAddress(content)} {i + 1}: {linkIfAddress(d.target)}.{d.functionSig}(
{d.callData.split(',').length - 1 === i ? '' : ','} {d.callData.split(',').map((content, i) => {
</span> return (
<span key={i}>
{linkIfAddress(content)}
{d.callData.split(',').length - 1 === i ? '' : ','}
</span>
)
})}
) )
})} </DetailText>
) )
</DetailText> })}
) </AutoColumn>
})} <AutoColumn gap="md">
</AutoColumn> <ThemedText.MediumHeader fontWeight={600}>
<AutoColumn gap="md"> <Trans>Description</Trans>
<ThemedText.MediumHeader fontWeight={600}> </ThemedText.MediumHeader>
<Trans>Description</Trans> <MarkDownWrapper>
</ThemedText.MediumHeader> <ReactMarkdown source={proposalData?.description} />
<MarkDownWrapper> </MarkDownWrapper>
<ReactMarkdown source={proposalData?.description} /> </AutoColumn>
</MarkDownWrapper> <AutoColumn gap="md">
</AutoColumn> <ThemedText.MediumHeader fontWeight={600}>
<AutoColumn gap="md"> <Trans>Proposer</Trans>
<ThemedText.MediumHeader fontWeight={600}> </ThemedText.MediumHeader>
<Trans>Proposer</Trans> <ProposerAddressLink
</ThemedText.MediumHeader> href={
<ProposerAddressLink proposalData?.proposer && chainId
href={ ? getExplorerLink(chainId, proposalData?.proposer, ExplorerDataType.ADDRESS)
proposalData?.proposer && chainId : ''
? getExplorerLink(chainId, proposalData?.proposer, ExplorerDataType.ADDRESS) }
: '' >
} <ReactMarkdown source={proposalData?.proposer} />
> </ProposerAddressLink>
<ReactMarkdown source={proposalData?.proposer} /> </AutoColumn>
</ProposerAddressLink> </ProposalInfo>
</AutoColumn> </PageWrapper>
</ProposalInfo> <SwitchLocaleLink />
</PageWrapper> </>
<SwitchLocaleLink /> </Trace>
</>
) )
} }