Commit 30cffb74 authored by Noah Zinsmeister's avatar Noah Zinsmeister Committed by GitHub

feat: governor bravo support (#2271)

* first pass

* Fix code style issues with ESLint

* address comments
Co-authored-by: default avatarLint Action <lint-action@samuelmeuli.com>
parent f59c5f68
This diff is collapsed.
...@@ -10,7 +10,7 @@ import { TYPE, CustomLightSpinner } from '../../theme' ...@@ -10,7 +10,7 @@ import { TYPE, CustomLightSpinner } from '../../theme'
import { X, ArrowUpCircle } from 'react-feather' import { X, ArrowUpCircle } from 'react-feather'
import { ButtonPrimary } from '../Button' import { ButtonPrimary } from '../Button'
import Circle from '../../assets/images/blue-loader.svg' import Circle from '../../assets/images/blue-loader.svg'
import { useVoteCallback, useUserVotes } from '../../state/governance/hooks' import { useVoteCallback, useUserVotes, VoteOption } from '../../state/governance/hooks'
import { ExternalLink } from '../../theme/components' import { ExternalLink } from '../../theme/components'
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
...@@ -38,17 +38,13 @@ const ConfirmedIcon = styled(ColumnCenter)` ...@@ -38,17 +38,13 @@ const ConfirmedIcon = styled(ColumnCenter)`
interface VoteModalProps { interface VoteModalProps {
isOpen: boolean isOpen: boolean
onDismiss: () => void onDismiss: () => void
support: boolean // if user is for or against proposal voteOption: VoteOption | undefined
proposalId: string | undefined // id for the proposal to vote on proposalId: string | undefined // id for the proposal to vote on
} }
export default function VoteModal({ isOpen, onDismiss, proposalId, support }: VoteModalProps) { export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: VoteModalProps) {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const { const { voteCallback } = useVoteCallback()
voteCallback,
}: {
voteCallback: (proposalId: string | undefined, support: boolean) => Promise<string> | undefined
} = useVoteCallback()
const { votes: availableVotes } = useUserVotes() const { votes: availableVotes } = useUserVotes()
// monitor call to help UI loading state // monitor call to help UI loading state
...@@ -69,10 +65,10 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo ...@@ -69,10 +65,10 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo
setAttempting(true) setAttempting(true)
// if callback not returned properly ignore // if callback not returned properly ignore
if (!voteCallback) return if (!voteCallback || voteOption === undefined) return
// try delegation and store hash // try delegation and store hash
const hash = await voteCallback(proposalId, support)?.catch((error) => { const hash = await voteCallback(proposalId, voteOption)?.catch((error) => {
setAttempting(false) setAttempting(false)
console.log(error) console.log(error)
}) })
...@@ -89,10 +85,12 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo ...@@ -89,10 +85,12 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="lg" justify="center">
<RowBetween> <RowBetween>
<TYPE.mediumHeader fontWeight={500}> <TYPE.mediumHeader fontWeight={500}>
{support ? ( {voteOption === VoteOption.Against ? (
<Trans>Vote against proposal {proposalId}</Trans>
) : voteOption === VoteOption.For ? (
<Trans>Vote for proposal {proposalId}</Trans> <Trans>Vote for proposal {proposalId}</Trans>
) : ( ) : (
<Trans>Vote against proposal {proposalId}</Trans> <Trans>Vote to abstain on proposal {proposalId}</Trans>
)} )}
</TYPE.mediumHeader> </TYPE.mediumHeader>
<StyledClosed stroke="black" onClick={wrappedOndismiss} /> <StyledClosed stroke="black" onClick={wrappedOndismiss} />
...@@ -102,10 +100,12 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo ...@@ -102,10 +100,12 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, support }: Vo
</TYPE.largeHeader> </TYPE.largeHeader>
<ButtonPrimary onClick={onVote}> <ButtonPrimary onClick={onVote}>
<TYPE.mediumHeader color="white"> <TYPE.mediumHeader color="white">
{support ? ( {voteOption === VoteOption.Against ? (
<Trans>Vote against proposal {proposalId}</Trans>
) : voteOption === VoteOption.For ? (
<Trans>Vote for proposal {proposalId}</Trans> <Trans>Vote for proposal {proposalId}</Trans>
) : ( ) : (
<Trans>Vote against proposal {proposalId}</Trans> <Trans>Vote to abstain on proposal {proposalId}</Trans>
)} )}
</TYPE.mediumHeader> </TYPE.mediumHeader>
</ButtonPrimary> </ButtonPrimary>
......
...@@ -16,17 +16,23 @@ export const V2_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V2_FACTO ...@@ -16,17 +16,23 @@ export const V2_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V2_FACTO
export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D')
/** /**
* The older V0 governance account * The oldest V0 governance address
*/ */
export const GOVERNANCE_ALPHA_V0_ADDRESSES: AddressMap = constructSameAddressMap( export const GOVERNANCE_ALPHA_V0_ADDRESSES: AddressMap = constructSameAddressMap(
'0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F' '0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F'
) )
/** /**
* The latest governor alpha that is currently admin of timelock * The older V1 governance address
*/ */
export const GOVERNANCE_ALPHA_V1_ADDRESSES: AddressMap = { export const GOVERNANCE_ALPHA_V1_ADDRESSES: AddressMap = {
[SupportedChainId.MAINNET]: '0xC4e172459f1E7939D522503B81AFAaC1014CE6F6', [SupportedChainId.MAINNET]: '0xC4e172459f1E7939D522503B81AFAaC1014CE6F6',
} }
/**
* The latest governor bravo that is currently admin of timelock
*/
export const GOVERNANCE_BRAVO_ADDRESSES: AddressMap = {
[SupportedChainId.MAINNET]: '0x408ED6354d4973f66138C91495F2f2FCbd8724C3',
}
export const TIMELOCK_ADDRESS: AddressMap = constructSameAddressMap('0x1a9C8182C09F50C8318d769245beA52c32BE35BC') export const TIMELOCK_ADDRESS: AddressMap = constructSameAddressMap('0x1a9C8182C09F50C8318d769245beA52c32BE35BC')
......
...@@ -10,6 +10,7 @@ import { abi as IUniswapV2Router02ABI } from '@uniswap/v2-periphery/build/IUnisw ...@@ -10,6 +10,7 @@ import { abi as IUniswapV2Router02ABI } from '@uniswap/v2-periphery/build/IUnisw
import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json' import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
import ARGENT_WALLET_DETECTOR_ABI from 'abis/argent-wallet-detector.json' import ARGENT_WALLET_DETECTOR_ABI from 'abis/argent-wallet-detector.json'
import GOVERNOR_BRAVO_ABI from 'abis/governor-bravo.json'
import ENS_PUBLIC_RESOLVER_ABI from 'abis/ens-public-resolver.json' import ENS_PUBLIC_RESOLVER_ABI from 'abis/ens-public-resolver.json'
import ENS_ABI from 'abis/ens-registrar.json' import ENS_ABI from 'abis/ens-registrar.json'
import ERC20_ABI from 'abis/erc20.json' import ERC20_ABI from 'abis/erc20.json'
...@@ -28,6 +29,7 @@ import { ...@@ -28,6 +29,7 @@ import {
ENS_REGISTRAR_ADDRESSES, ENS_REGISTRAR_ADDRESSES,
GOVERNANCE_ALPHA_V0_ADDRESSES, GOVERNANCE_ALPHA_V0_ADDRESSES,
GOVERNANCE_ALPHA_V1_ADDRESSES, GOVERNANCE_ALPHA_V1_ADDRESSES,
GOVERNANCE_BRAVO_ADDRESSES,
} from 'constants/addresses' } from 'constants/addresses'
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json' import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import { useMemo } from 'react' import { useMemo } from 'react'
...@@ -111,14 +113,18 @@ export function useMerkleDistributorContract() { ...@@ -111,14 +113,18 @@ export function useMerkleDistributorContract() {
} }
export function useGovernanceV0Contract(): Contract | null { export function useGovernanceV0Contract(): Contract | null {
return useContract(GOVERNANCE_ALPHA_V0_ADDRESSES, GOVERNANCE_ABI, true) return useContract(GOVERNANCE_ALPHA_V0_ADDRESSES, GOVERNANCE_ABI, false)
} }
export function useGovernanceV1Contract(): Contract | null { export function useGovernanceV1Contract(): Contract | null {
return useContract(GOVERNANCE_ALPHA_V1_ADDRESSES, GOVERNANCE_ABI, true) return useContract(GOVERNANCE_ALPHA_V1_ADDRESSES, GOVERNANCE_ABI, false)
} }
export const useLatestGovernanceContract = useGovernanceV1Contract export function useGovernanceBravoContract(): Contract | null {
return useContract(GOVERNANCE_BRAVO_ADDRESSES, GOVERNOR_BRAVO_ABI, true)
}
export const useLatestGovernanceContract = useGovernanceBravoContract
export function useUniContract() { export function useUniContract() {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
......
...@@ -87,7 +87,8 @@ export default function CreateProposal() { ...@@ -87,7 +87,8 @@ export default function CreateProposal() {
const { account, chainId } = useActiveWeb3React() const { account, chainId } = useActiveWeb3React()
const latestProposalId = useLatestProposalId(account ?? undefined) ?? '0' const latestProposalId = useLatestProposalId(account ?? undefined) ?? '0'
const latestProposalData = useProposalData(0, latestProposalId) // the first argument below should be the index of the latest governor
const latestProposalData = useProposalData(/* governorIndex */ 2, latestProposalId)
const { votes: availableVotes } = useUserVotes() const { votes: availableVotes } = useUserVotes()
const proposalThreshold: CurrencyAmount<Token> | undefined = useProposalThreshold() const proposalThreshold: CurrencyAmount<Token> | undefined = useProposalThreshold()
......
...@@ -33,6 +33,7 @@ import { ...@@ -33,6 +33,7 @@ import {
useProposalData, useProposalData,
useUserDelegatee, useUserDelegatee,
useUserVotesAsOfBlock, useUserVotesAsOfBlock,
VoteOption,
} from '../../state/governance/hooks' } from '../../state/governance/hooks'
import { useTokenBalance } from '../../state/wallet/hooks' import { useTokenBalance } from '../../state/wallet/hooks'
import { ExternalLink, StyledInternalLink, TYPE } from '../../theme' import { ExternalLink, StyledInternalLink, TYPE } from '../../theme'
...@@ -130,8 +131,8 @@ export default function VotePage({ ...@@ -130,8 +131,8 @@ export default function VotePage({
// get data for this specific proposal // get data for this specific proposal
const proposalData: ProposalData | undefined = useProposalData(Number.parseInt(governorIndex), id) const proposalData: ProposalData | undefined = useProposalData(Number.parseInt(governorIndex), id)
// update support based on button interactions // update vote option based on button interactions
const [support, setSupport] = useState<boolean>(true) const [voteOption, setVoteOption] = useState<VoteOption | undefined>(undefined)
// modal for casting votes // modal for casting votes
const showVoteModal = useModalOpen(ApplicationModal.VOTE) const showVoteModal = useModalOpen(ApplicationModal.VOTE)
...@@ -203,7 +204,12 @@ export default function VotePage({ ...@@ -203,7 +204,12 @@ export default function VotePage({
return ( return (
<> <>
<PageWrapper gap="lg" justify="center"> <PageWrapper gap="lg" justify="center">
<VoteModal isOpen={showVoteModal} onDismiss={toggleVoteModal} proposalId={proposalData?.id} support={support} /> <VoteModal
isOpen={showVoteModal}
onDismiss={toggleVoteModal}
proposalId={proposalData?.id}
voteOption={voteOption}
/>
<DelegateModal isOpen={showDelegateModal} onDismiss={toggleDelegateModal} title={<Trans>Unlock Votes</Trans>} /> <DelegateModal isOpen={showDelegateModal} onDismiss={toggleDelegateModal} title={<Trans>Unlock Votes</Trans>} />
<ProposalInfo gap="lg" justify="start"> <ProposalInfo gap="lg" justify="start">
<RowBetween style={{ width: '100%' }}> <RowBetween style={{ width: '100%' }}>
...@@ -252,7 +258,7 @@ export default function VotePage({ ...@@ -252,7 +258,7 @@ export default function VotePage({
padding="8px" padding="8px"
$borderRadius="8px" $borderRadius="8px"
onClick={() => { onClick={() => {
setSupport(true) setVoteOption(VoteOption.For)
toggleVoteModal() toggleVoteModal()
}} }}
> >
...@@ -262,7 +268,7 @@ export default function VotePage({ ...@@ -262,7 +268,7 @@ export default function VotePage({
padding="8px" padding="8px"
$borderRadius="8px" $borderRadius="8px"
onClick={() => { onClick={() => {
setSupport(false) setVoteOption(VoteOption.Against)
toggleVoteModal() toggleVoteModal()
}} }}
> >
......
This diff is collapsed.
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