Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddf88345a9 | ||
|
|
32ac25556b | ||
|
|
50a599c005 | ||
|
|
9c473270ee | ||
|
|
b650b17563 | ||
|
|
fc76177791 | ||
|
|
69655980db |
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.9 KiB |
@@ -99,7 +99,7 @@ const LowerSection = styled.div`
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background-color: ${({ theme }) => theme.bg2};
|
background-color: ${({ theme }) => theme.bg2};
|
||||||
border-bottom-left-radius: 25px;
|
border-bottom-left-radius: 20px;
|
||||||
border-bottom-right-radius: 20px;
|
border-bottom-right-radius: 20px;
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ export const MKR = new Token(ChainId.MAINNET, '0x9f8F72aA9304c8B593d555F12eF6589
|
|||||||
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
|
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
|
||||||
export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 18, 'WBTC', 'Wrapped BTC')
|
export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 18, 'WBTC', 'Wrapped BTC')
|
||||||
|
|
||||||
// TODO this is only approximate, it's actually based on blocks
|
// Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time
|
||||||
export const PROPOSAL_LENGTH_IN_DAYS = 7
|
export const AVERAGE_BLOCK_TIME_IN_SECS = 14
|
||||||
|
export const PROPOSAL_LENGTH_IN_BLOCKS = 40_320
|
||||||
|
export const PROPOSAL_LENGTH_IN_SECS = AVERAGE_BLOCK_TIME_IN_SECS * PROPOSAL_LENGTH_IN_BLOCKS
|
||||||
|
|
||||||
export const GOVERNANCE_ADDRESS = '0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F'
|
export const GOVERNANCE_ADDRESS = '0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F'
|
||||||
|
|
||||||
|
export const TIMELOCK_ADDRESS = '0x1a9C8182C09F50C8318d769245beA52c32BE35BC'
|
||||||
|
|
||||||
const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
|
const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
|
||||||
export const UNI: { [chainId in ChainId]: Token } = {
|
export const UNI: { [chainId in ChainId]: Token } = {
|
||||||
[ChainId.MAINNET]: new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
|
[ChainId.MAINNET]: new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
|
||||||
@@ -34,6 +38,12 @@ export const UNI: { [chainId in ChainId]: Token } = {
|
|||||||
[ChainId.KOVAN]: new Token(ChainId.KOVAN, UNI_ADDRESS, 18, 'UNI', 'Uniswap')
|
[ChainId.KOVAN]: new Token(ChainId.KOVAN, UNI_ADDRESS, 18, 'UNI', 'Uniswap')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const COMMON_CONTRACT_NAMES: { [address: string]: string } = {
|
||||||
|
[UNI_ADDRESS]: 'UNI',
|
||||||
|
[GOVERNANCE_ADDRESS]: 'Governance',
|
||||||
|
[TIMELOCK_ADDRESS]: 'Timelock'
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: specify merkle distributor for mainnet
|
// TODO: specify merkle distributor for mainnet
|
||||||
export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = {
|
export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = {
|
||||||
[ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e'
|
[ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e'
|
||||||
|
|||||||
@@ -9,16 +9,20 @@ import { CardSection, DataCard } from '../../components/earn/styled'
|
|||||||
import { ArrowLeft } from 'react-feather'
|
import { ArrowLeft } from 'react-feather'
|
||||||
import { ButtonPrimary } from '../../components/Button'
|
import { ButtonPrimary } from '../../components/Button'
|
||||||
import { ProposalStatus } from './styled'
|
import { ProposalStatus } from './styled'
|
||||||
import { useProposalData, useUserVotes, useUserDelegatee, ProposalData } from '../../state/governance/hooks'
|
import { useProposalData, useUserVotesAsOfBlock, ProposalData, useUserDelegatee } from '../../state/governance/hooks'
|
||||||
import { useTimestampFromBlock } from '../../hooks/useTimestampFromBlock'
|
import { useTimestampFromBlock } from '../../hooks/useTimestampFromBlock'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
import ReactMarkdown from 'react-markdown'
|
import ReactMarkdown from 'react-markdown'
|
||||||
import VoteModal from '../../components/vote/VoteModal'
|
import VoteModal from '../../components/vote/VoteModal'
|
||||||
import { TokenAmount, JSBI } from '@uniswap/sdk'
|
import { TokenAmount, JSBI } from '@uniswap/sdk'
|
||||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { UNI, ZERO_ADDRESS, PROPOSAL_LENGTH_IN_DAYS } from '../../constants'
|
import { PROPOSAL_LENGTH_IN_SECS, COMMON_CONTRACT_NAMES, UNI, ZERO_ADDRESS } from '../../constants'
|
||||||
import { isAddress, getEtherscanLink } from '../../utils'
|
import { isAddress, getEtherscanLink } from '../../utils'
|
||||||
|
import { ApplicationModal } from '../../state/application/actions'
|
||||||
|
import { useModalOpen, useToggleDelegateModal, useToggleVoteModal } from '../../state/application/hooks'
|
||||||
|
import DelegateModal from '../../components/vote/DelegateModal'
|
||||||
|
import { GreyCard } from '../../components/Card'
|
||||||
|
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||||
|
|
||||||
const PageWrapper = styled(AutoColumn)`
|
const PageWrapper = styled(AutoColumn)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -99,7 +103,7 @@ export default function VotePage({
|
|||||||
params: { id }
|
params: { id }
|
||||||
}
|
}
|
||||||
}: RouteComponentProps<{ id: string }>) {
|
}: RouteComponentProps<{ id: string }>) {
|
||||||
const { account, chainId } = useActiveWeb3React()
|
const { chainId, account } = useActiveWeb3React()
|
||||||
|
|
||||||
// get data for this specific proposal
|
// get data for this specific proposal
|
||||||
const proposalData: ProposalData | undefined = useProposalData(id)
|
const proposalData: ProposalData | undefined = useProposalData(id)
|
||||||
@@ -108,12 +112,17 @@ export default function VotePage({
|
|||||||
const [support, setSupport] = useState<boolean>(true)
|
const [support, setSupport] = useState<boolean>(true)
|
||||||
|
|
||||||
// modal for casting votes
|
// modal for casting votes
|
||||||
const [showModal, setShowModal] = useState<boolean>(false)
|
const showVoteModal = useModalOpen(ApplicationModal.VOTE)
|
||||||
|
const toggleVoteModal = useToggleVoteModal()
|
||||||
|
|
||||||
|
// toggle for showing delegation modal
|
||||||
|
const showDelegateModal = useModalOpen(ApplicationModal.DELEGATE)
|
||||||
|
const toggelDelegateModal = useToggleDelegateModal()
|
||||||
|
|
||||||
// get and format date from data
|
// get and format date from data
|
||||||
const startTimestamp: number | undefined = useTimestampFromBlock(proposalData?.startBlock)
|
const startTimestamp: number | undefined = useTimestampFromBlock(proposalData?.startBlock)
|
||||||
const endDate: DateTime | undefined = startTimestamp
|
const endDate: DateTime | undefined = startTimestamp
|
||||||
? DateTime.fromSeconds(startTimestamp).plus({ days: PROPOSAL_LENGTH_IN_DAYS })
|
? DateTime.fromSeconds(startTimestamp).plus({ seconds: PROPOSAL_LENGTH_IN_SECS })
|
||||||
: undefined
|
: undefined
|
||||||
const now: DateTime = DateTime.local()
|
const now: DateTime = DateTime.local()
|
||||||
|
|
||||||
@@ -124,30 +133,38 @@ export default function VotePage({
|
|||||||
const againstPercentage: string =
|
const againstPercentage: string =
|
||||||
proposalData && totalVotes ? ((proposalData.againstCount * 100) / totalVotes).toFixed(0) + '%' : '0%'
|
proposalData && totalVotes ? ((proposalData.againstCount * 100) / totalVotes).toFixed(0) + '%' : '0%'
|
||||||
|
|
||||||
// show delegation option if they have have a balance, have not delegated
|
// only count available votes as of the proposal start block
|
||||||
const availableVotes: TokenAmount | undefined = useUserVotes()
|
const availableVotes: TokenAmount | undefined = useUserVotesAsOfBlock(proposalData?.startBlock ?? undefined)
|
||||||
|
|
||||||
|
// only show voting if user has > 0 votes at proposal start block and proposal is active,
|
||||||
|
const showVotingButtons =
|
||||||
|
availableVotes &&
|
||||||
|
JSBI.greaterThan(availableVotes.raw, JSBI.BigInt(0)) &&
|
||||||
|
proposalData &&
|
||||||
|
proposalData.status === 'active'
|
||||||
|
|
||||||
const uniBalance: TokenAmount | undefined = useTokenBalance(account ?? undefined, chainId ? UNI[chainId] : undefined)
|
const uniBalance: TokenAmount | undefined = useTokenBalance(account ?? undefined, chainId ? UNI[chainId] : undefined)
|
||||||
const userDelegatee: string | undefined = useUserDelegatee()
|
const userDelegatee: string | undefined = useUserDelegatee()
|
||||||
const showUnlockVoting = Boolean(
|
|
||||||
|
// in blurb link to home page if they are able to unlock
|
||||||
|
const showLinkForUnlock = Boolean(
|
||||||
uniBalance && JSBI.notEqual(uniBalance.raw, JSBI.BigInt(0)) && userDelegatee === ZERO_ADDRESS
|
uniBalance && JSBI.notEqual(uniBalance.raw, JSBI.BigInt(0)) && userDelegatee === ZERO_ADDRESS
|
||||||
)
|
)
|
||||||
|
|
||||||
// show links in propsoal details if content is an address
|
// show links in propsoal details if content is an address
|
||||||
|
// if content is contract with common name, replace address with common name
|
||||||
const linkIfAddress = (content: string) => {
|
const linkIfAddress = (content: string) => {
|
||||||
if (isAddress(content) && chainId) {
|
if (isAddress(content) && chainId) {
|
||||||
return <ExternalLink href={getEtherscanLink(chainId, content, 'address')}>{content}</ExternalLink>
|
const commonName = COMMON_CONTRACT_NAMES[content] ?? content
|
||||||
|
return <ExternalLink href={getEtherscanLink(chainId, content, 'address')}>{commonName}</ExternalLink>
|
||||||
}
|
}
|
||||||
return <span>{content}</span>
|
return <span>{content}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper gap="lg" justify="center">
|
<PageWrapper gap="lg" justify="center">
|
||||||
<VoteModal
|
<VoteModal isOpen={showVoteModal} onDismiss={toggleVoteModal} proposalId={proposalData?.id} support={support} />
|
||||||
isOpen={showModal}
|
<DelegateModal isOpen={showDelegateModal} onDismiss={toggelDelegateModal} title="Unlock Votes" />
|
||||||
onDismiss={() => setShowModal(false)}
|
|
||||||
proposalId={proposalData?.id}
|
|
||||||
support={support}
|
|
||||||
/>
|
|
||||||
<ProposalInfo gap="lg" justify="start">
|
<ProposalInfo gap="lg" justify="start">
|
||||||
<RowBetween style={{ width: '100%' }}>
|
<RowBetween style={{ width: '100%' }}>
|
||||||
<ArrowWrapper to="/vote">
|
<ArrowWrapper to="/vote">
|
||||||
@@ -162,33 +179,32 @@ export default function VotePage({
|
|||||||
{endDate && endDate < now
|
{endDate && endDate < now
|
||||||
? 'Voting ended ' + (endDate && endDate.toLocaleString(DateTime.DATETIME_FULL))
|
? 'Voting ended ' + (endDate && endDate.toLocaleString(DateTime.DATETIME_FULL))
|
||||||
: proposalData
|
: proposalData
|
||||||
? 'Voting ends approximately' + (endDate && endDate.toLocaleString(DateTime.DATETIME_FULL))
|
? 'Voting ends approximately ' + (endDate && endDate.toLocaleString(DateTime.DATETIME_FULL))
|
||||||
: ''}
|
: ''}
|
||||||
</TYPE.main>
|
</TYPE.main>
|
||||||
{showUnlockVoting && endDate && endDate > now && (
|
|
||||||
<ButtonPrimary
|
|
||||||
style={{ width: 'fit-content' }}
|
|
||||||
padding="8px"
|
|
||||||
borderRadius="8px"
|
|
||||||
onClick={() => setShowModal(true)}
|
|
||||||
>
|
|
||||||
Unlock Voting
|
|
||||||
</ButtonPrimary>
|
|
||||||
)}
|
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
{proposalData && proposalData.status === 'active' && !showVotingButtons && (
|
||||||
|
<GreyCard>
|
||||||
|
<TYPE.black>
|
||||||
|
Only UNI votes that were self delegated or delegated to another address before block{' '}
|
||||||
|
{proposalData.startBlock} are eligible for voting.{' '}
|
||||||
|
{showLinkForUnlock && (
|
||||||
|
<span>
|
||||||
|
<StyledInternalLink to="/vote">Unlock voting</StyledInternalLink> to prepare for the next proposal.
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TYPE.black>
|
||||||
|
</GreyCard>
|
||||||
|
)}
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
{!showUnlockVoting &&
|
{showVotingButtons ? (
|
||||||
availableVotes &&
|
|
||||||
JSBI.greaterThan(availableVotes?.raw, JSBI.BigInt(0)) &&
|
|
||||||
endDate &&
|
|
||||||
endDate > now ? (
|
|
||||||
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
<RowFixed style={{ width: '100%', gap: '12px' }}>
|
||||||
<ButtonPrimary
|
<ButtonPrimary
|
||||||
padding="8px"
|
padding="8px"
|
||||||
borderRadius="8px"
|
borderRadius="8px"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSupport(true)
|
setSupport(true)
|
||||||
setShowModal(true)
|
toggleVoteModal()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Vote For
|
Vote For
|
||||||
@@ -198,7 +214,7 @@ export default function VotePage({
|
|||||||
borderRadius="8px"
|
borderRadius="8px"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSupport(false)
|
setSupport(false)
|
||||||
setShowModal(true)
|
toggleVoteModal()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Vote Against
|
Vote Against
|
||||||
@@ -260,7 +276,7 @@ export default function VotePage({
|
|||||||
})}
|
})}
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
<AutoColumn gap="md">
|
<AutoColumn gap="md">
|
||||||
<TYPE.mediumHeader fontWeight={600}>Overview</TYPE.mediumHeader>
|
<TYPE.mediumHeader fontWeight={600}>Description</TYPE.mediumHeader>
|
||||||
<MarkDownWrapper>
|
<MarkDownWrapper>
|
||||||
<ReactMarkdown source={proposalData?.description} />
|
<ReactMarkdown source={proposalData?.description} />
|
||||||
</MarkDownWrapper>
|
</MarkDownWrapper>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react'
|
import React from 'react'
|
||||||
import { AutoColumn } from '../../components/Column'
|
import { AutoColumn } from '../../components/Column'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { TYPE, ExternalLink } from '../../theme'
|
import { TYPE, ExternalLink } from '../../theme'
|
||||||
@@ -19,6 +19,8 @@ import { JSBI, TokenAmount, ChainId } from '@uniswap/sdk'
|
|||||||
import { shortenAddress, getEtherscanLink } from '../../utils'
|
import { shortenAddress, getEtherscanLink } from '../../utils'
|
||||||
import Loader from '../../components/Loader'
|
import Loader from '../../components/Loader'
|
||||||
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
||||||
|
import { useModalOpen, useToggleDelegateModal } from '../../state/application/hooks'
|
||||||
|
import { ApplicationModal } from '../../state/application/actions'
|
||||||
|
|
||||||
const PageWrapper = styled(AutoColumn)``
|
const PageWrapper = styled(AutoColumn)``
|
||||||
|
|
||||||
@@ -102,7 +104,10 @@ const EmptyProposals = styled.div`
|
|||||||
|
|
||||||
export default function Vote() {
|
export default function Vote() {
|
||||||
const { account, chainId } = useActiveWeb3React()
|
const { account, chainId } = useActiveWeb3React()
|
||||||
const [showModal, setShowModal] = useState<boolean>(false)
|
|
||||||
|
// toggle for showing delegation modal
|
||||||
|
const showDelegateModal = useModalOpen(ApplicationModal.DELEGATE)
|
||||||
|
const toggelDelegateModal = useToggleDelegateModal()
|
||||||
|
|
||||||
// get data to list all proposals
|
// get data to list all proposals
|
||||||
const allProposals: ProposalData[] = useAllProposalData()
|
const allProposals: ProposalData[] = useAllProposalData()
|
||||||
@@ -120,8 +125,8 @@ export default function Vote() {
|
|||||||
return (
|
return (
|
||||||
<PageWrapper gap="lg" justify="center">
|
<PageWrapper gap="lg" justify="center">
|
||||||
<DelegateModal
|
<DelegateModal
|
||||||
isOpen={showModal}
|
isOpen={showDelegateModal}
|
||||||
onDismiss={() => setShowModal(false)}
|
onDismiss={toggelDelegateModal}
|
||||||
title={showUnlockVoting ? 'Unlock Votes' : 'Update Delegation'}
|
title={showUnlockVoting ? 'Unlock Votes' : 'Update Delegation'}
|
||||||
/>
|
/>
|
||||||
<TopSection gap="md">
|
<TopSection gap="md">
|
||||||
@@ -154,14 +159,14 @@ export default function Vote() {
|
|||||||
</TopSection>
|
</TopSection>
|
||||||
<TopSection gap="2px">
|
<TopSection gap="2px">
|
||||||
<WrapSmall>
|
<WrapSmall>
|
||||||
<TYPE.mediumHeader style={{ margin: '0.5rem 0' }}>Proposals</TYPE.mediumHeader>
|
<TYPE.mediumHeader style={{ margin: '0.5rem 0.5rem 0.5rem 0', flexShrink: 0 }}>Proposals</TYPE.mediumHeader>
|
||||||
{(!allProposals || allProposals.length === 0) && !availableVotes && <Loader />}
|
{(!allProposals || allProposals.length === 0) && !availableVotes && <Loader />}
|
||||||
{showUnlockVoting ? (
|
{showUnlockVoting ? (
|
||||||
<ButtonPrimary
|
<ButtonPrimary
|
||||||
style={{ width: 'fit-content' }}
|
style={{ width: 'fit-content' }}
|
||||||
padding="8px"
|
padding="8px"
|
||||||
borderRadius="8px"
|
borderRadius="8px"
|
||||||
onClick={() => setShowModal(true)}
|
onClick={toggelDelegateModal}
|
||||||
>
|
>
|
||||||
Unlock Voting
|
Unlock Voting
|
||||||
</ButtonPrimary>
|
</ButtonPrimary>
|
||||||
@@ -195,7 +200,7 @@ export default function Vote() {
|
|||||||
>
|
>
|
||||||
{userDelegatee === account ? 'Self' : shortenAddress(userDelegatee)}
|
{userDelegatee === account ? 'Self' : shortenAddress(userDelegatee)}
|
||||||
</StyledExternalLink>
|
</StyledExternalLink>
|
||||||
<TextButton onClick={() => setShowModal(true)} style={{ marginLeft: '4px' }}>
|
<TextButton onClick={toggelDelegateModal} style={{ marginLeft: '4px' }}>
|
||||||
(edit)
|
(edit)
|
||||||
</TextButton>
|
</TextButton>
|
||||||
</AddressButton>
|
</AddressButton>
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export enum ApplicationModal {
|
|||||||
SELF_CLAIM,
|
SELF_CLAIM,
|
||||||
ADDRESS_CLAIM,
|
ADDRESS_CLAIM,
|
||||||
CLAIM_POPUP,
|
CLAIM_POPUP,
|
||||||
MENU
|
MENU,
|
||||||
|
DELEGATE,
|
||||||
|
VOTE
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateBlockNumber = createAction<{ chainId: number; blockNumber: number }>('application/updateBlockNumber')
|
export const updateBlockNumber = createAction<{ chainId: number; blockNumber: number }>('application/updateBlockNumber')
|
||||||
|
|||||||
@@ -51,6 +51,14 @@ export function useToggleSelfClaimModal(): () => void {
|
|||||||
return useToggleModal(ApplicationModal.SELF_CLAIM)
|
return useToggleModal(ApplicationModal.SELF_CLAIM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useToggleDelegateModal(): () => void {
|
||||||
|
return useToggleModal(ApplicationModal.DELEGATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useToggleVoteModal(): () => void {
|
||||||
|
return useToggleModal(ApplicationModal.VOTE)
|
||||||
|
}
|
||||||
|
|
||||||
// returns a function that allows adding a popup
|
// returns a function that allows adding a popup
|
||||||
export function useAddPopup(): (content: PopupContent, key?: string) => void {
|
export function useAddPopup(): (content: PopupContent, key?: string) => void {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ export function useUserDelegatee(): string {
|
|||||||
return result?.[0] ?? undefined
|
return result?.[0] ?? undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gets the users current votes
|
||||||
export function useUserVotes(): TokenAmount | undefined {
|
export function useUserVotes(): TokenAmount | undefined {
|
||||||
const { account, chainId } = useActiveWeb3React()
|
const { account, chainId } = useActiveWeb3React()
|
||||||
const uniContract = useUniContract()
|
const uniContract = useUniContract()
|
||||||
@@ -163,6 +164,18 @@ export function useUserVotes(): TokenAmount | undefined {
|
|||||||
return votes && uni ? new TokenAmount(uni, votes) : undefined
|
return votes && uni ? new TokenAmount(uni, votes) : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetch available votes as of block (usually proposal start block)
|
||||||
|
export function useUserVotesAsOfBlock(block: number | undefined): TokenAmount | undefined {
|
||||||
|
const { account, chainId } = useActiveWeb3React()
|
||||||
|
const uniContract = useUniContract()
|
||||||
|
|
||||||
|
// check for available votes
|
||||||
|
const uni = chainId ? UNI[chainId] : undefined
|
||||||
|
const votes = useSingleCallResult(uniContract, 'getPriorVotes', [account ?? undefined, block ?? undefined])
|
||||||
|
?.result?.[0]
|
||||||
|
return votes && uni ? new TokenAmount(uni, votes) : undefined
|
||||||
|
}
|
||||||
|
|
||||||
export function useDelegateCallback(): (delegatee: string | undefined) => undefined | Promise<string> {
|
export function useDelegateCallback(): (delegatee: string | undefined) => undefined | Promise<string> {
|
||||||
const { account, chainId, library } = useActiveWeb3React()
|
const { account, chainId, library } = useActiveWeb3React()
|
||||||
const addTransaction = useTransactionAdder()
|
const addTransaction = useTransactionAdder()
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ export default function Updater(): null {
|
|||||||
const { library } = useActiveWeb3React()
|
const { library } = useActiveWeb3React()
|
||||||
const dispatch = useDispatch<AppDispatch>()
|
const dispatch = useDispatch<AppDispatch>()
|
||||||
const lists = useSelector<AppState, AppState['lists']['byUrl']>(state => state.lists.byUrl)
|
const lists = useSelector<AppState, AppState['lists']['byUrl']>(state => state.lists.byUrl)
|
||||||
|
const selectedListUrl = useSelector<AppState, AppState['lists']['selectedListUrl']>(
|
||||||
|
state => state.lists.selectedListUrl
|
||||||
|
)
|
||||||
|
|
||||||
const isWindowVisible = useIsWindowVisible()
|
const isWindowVisible = useIsWindowVisible()
|
||||||
|
|
||||||
@@ -54,19 +57,21 @@ export default function Updater(): null {
|
|||||||
// automatically update minor/patch as long as bump matches the min update
|
// automatically update minor/patch as long as bump matches the min update
|
||||||
if (bump >= min) {
|
if (bump >= min) {
|
||||||
dispatch(acceptListUpdate(listUrl))
|
dispatch(acceptListUpdate(listUrl))
|
||||||
dispatch(
|
if (listUrl === selectedListUrl) {
|
||||||
addPopup({
|
dispatch(
|
||||||
key: listUrl,
|
addPopup({
|
||||||
content: {
|
key: listUrl,
|
||||||
listUpdate: {
|
content: {
|
||||||
listUrl,
|
listUpdate: {
|
||||||
oldList: list.current,
|
listUrl,
|
||||||
newList: list.pendingUpdate,
|
oldList: list.current,
|
||||||
auto: true
|
newList: list.pendingUpdate,
|
||||||
|
auto: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
)
|
||||||
)
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
`List at url ${listUrl} could not automatically update because the version bump was only PATCH/MINOR while the update had breaking changes and should have been MAJOR`
|
`List at url ${listUrl} could not automatically update because the version bump was only PATCH/MINOR while the update had breaking changes and should have been MAJOR`
|
||||||
@@ -75,24 +80,26 @@ export default function Updater(): null {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case VersionUpgrade.MAJOR:
|
case VersionUpgrade.MAJOR:
|
||||||
dispatch(
|
if (listUrl === selectedListUrl) {
|
||||||
addPopup({
|
dispatch(
|
||||||
key: listUrl,
|
addPopup({
|
||||||
content: {
|
key: listUrl,
|
||||||
listUpdate: {
|
content: {
|
||||||
listUrl,
|
listUpdate: {
|
||||||
auto: false,
|
listUrl,
|
||||||
oldList: list.current,
|
auto: false,
|
||||||
newList: list.pendingUpdate
|
oldList: list.current,
|
||||||
}
|
newList: list.pendingUpdate
|
||||||
},
|
}
|
||||||
removeAfterMs: null
|
},
|
||||||
})
|
removeAfterMs: null
|
||||||
)
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [dispatch, lists])
|
}, [dispatch, lists, selectedListUrl])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,10 @@ body {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: ${colors(false).blue1};
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user