Skip to content

Commit

Permalink
Delegation & Govpower rework part 1 (solana-labs#1781)
Browse files Browse the repository at this point in the history
  • Loading branch information
asktree authored Sep 22, 2023
1 parent b49088b commit ededc09
Show file tree
Hide file tree
Showing 42 changed files with 1,093 additions and 855 deletions.
2 changes: 1 addition & 1 deletion HeliumVotePlugin/components/LockTokensAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
getMintNaturalAmountFromDecimalAsBN,
} from '@tools/sdk/units'
import PreviousRouteBtn from '@components/PreviousRouteBtn'
import { TokenDeposit } from '@components/TokenBalance/TokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenDeposit'
import { GoverningTokenRole } from '@solana/spl-governance'
import InlineNotification from '@components/InlineNotification'
import tokenPriceService from '@utils/services/tokenPrice'
Expand Down
4 changes: 1 addition & 3 deletions HeliumVotePlugin/components/VotingPowerCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import useRealm from '@hooks/useRealm'
import { fmtMintAmount } from '@tools/sdk/units'
import { getMintMetadata } from '@components/instructions/programs/splToken'
import InlineNotification from '@components/InlineNotification'
import DelegateTokenBalanceCard from '@components/TokenBalance/DelegateTokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenDeposit'
import useHeliumVsrStore from 'HeliumVotePlugin/hooks/useHeliumVsrStore'
import { MintInfo } from '@solana/spl-token'
import { VotingPowerBox } from './VotingPowerBox'
Expand Down Expand Up @@ -69,7 +68,6 @@ export const VotingPowerCard: React.FC<{
/>
</div>
)}
<DelegateTokenBalanceCard />
</>
) : (
<>
Expand Down
2 changes: 1 addition & 1 deletion VoteStakeRegistry/components/Account/LockTokensAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
} from '@heroicons/react/outline'
import { getMintMetadata } from '@components/instructions/programs/splToken'
import { abbreviateAddress } from '@utils/formatting'
import { TokenDeposit } from '@components/TokenBalance/TokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenDeposit'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import { useRealmQuery } from '@hooks/queries/realm'
import { useTokenOwnerRecordByPubkeyQuery } from '@hooks/queries/tokenOwnerRecord'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import {
LockClosedIcon,
} from '@heroicons/react/outline'
import { getMintMetadata } from '@components/instructions/programs/splToken'
import Account from '../../../components/Account'
import Account from '../../../pages/dao/[symbol]/account/Account'
import { abbreviateAddress } from '@utils/formatting'
import { TokenDeposit } from '@components/TokenBalance/TokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenDeposit'
import { VsrClient } from 'VoteStakeRegistry/sdk/client'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import { useRealmQuery } from '@hooks/queries/realm'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import { useEffect, useState } from 'react'
import { ChevronRightIcon } from '@heroicons/react/solid'
import InlineNotification from '@components/InlineNotification'
import Link from 'next/link'
import DelegateTokenBalanceCard from '@components/TokenBalance/DelegateTokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenDeposit'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import { useRealmQuery } from '@hooks/queries/realm'
import { useRouter } from 'next/router'
Expand Down Expand Up @@ -138,7 +137,6 @@ const LockPluginTokenBalanceCard = ({
/>
</div>
)}
<DelegateTokenBalanceCard />
</>
) : (
<>
Expand Down
9 changes: 5 additions & 4 deletions actions/castVote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ export async function castVote(
const plugin = await votingPlugin?.withCastPluginVote(
instructions,
proposal,
tokenOwnerRecord,
tokenOwnerRecord.pubkey,
createCastNftVoteTicketIxs
)

const isMulti = proposal.account.voteType !== VoteType.SINGLE_CHOICE
&& proposal.account.accountType === GovernanceAccountType.ProposalV2
const isMulti =
proposal.account.voteType !== VoteType.SINGLE_CHOICE &&
proposal.account.accountType === GovernanceAccountType.ProposalV2

// It is not clear that defining these extraneous fields, `deny` and `veto`, is actually necessary.
// See: https://discord.com/channels/910194960941338677/910630743510777926/1044741454175674378
Expand Down Expand Up @@ -151,7 +152,7 @@ export async function castVote(
if (message) {
const plugin = await votingPlugin?.withUpdateVoterWeightRecord(
instructions,
tokenOwnerRecord,
tokenOwnerRecord.pubkey,
'commentProposal',
createPostMessageTicketIxs
)
Expand Down
2 changes: 1 addition & 1 deletion actions/chat/postMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function postChatMessage(
//will run only if plugin is connected with realm
const plugin = await client?.withUpdateVoterWeightRecord(
instructions,
tokeOwnerRecord,
tokeOwnerRecord.pubkey,
'commentProposal',
createNftTicketsIxs
)
Expand Down
2 changes: 1 addition & 1 deletion actions/createLUTproposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const createLUTProposal = async (
//will run only if plugin is connected with realm
const plugin = await client?.withUpdateVoterWeightRecord(
instructions,
tokenOwnerRecord,
tokenOwnerRecord.pubkey,
'createProposal'
)

Expand Down
2 changes: 1 addition & 1 deletion actions/createProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const createProposal = async (
//will run only if plugin is connected with realm
const plugin = await client?.withUpdateVoterWeightRecord(
instructions,
tokenOwnerRecord,
tokenOwnerRecord.pubkey,
'createProposal',
createNftTicketsIxs
)
Expand Down
71 changes: 71 additions & 0 deletions components/GovernancePower/GovernancePowerCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ChevronRightIcon } from '@heroicons/react/solid'
import { useGovernancePowerAsync } from '@hooks/queries/governancePower'
import useQueryContext from '@hooks/useQueryContext'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import Link from 'next/link'
import { useRouter } from 'next/router'
import GovernancePowerForRole from './GovernancePowerForRole'

const GovernancePowerTitle = () => {
const { symbol } = useRouter().query
const { fmtUrlWithCluster } = useQueryContext()
const connected = useWalletOnePointOh()?.connected ?? undefined

return (
<div className="flex items-center justify-between mb-4">
<h3 className="mb-0">My governance power</h3>
<Link href={fmtUrlWithCluster(`/dao/${symbol}/account/me`)}>
<a
className={`default-transition flex items-center text-fgd-2 text-sm transition-all hover:text-fgd-3 ${
!connected ? 'opacity-50 pointer-events-none' : ''
}`}
>
View
<ChevronRightIcon className="flex-shrink-0 w-6 h-6" />
</a>
</Link>
</div>
)
}

const GovernancePowerCard = () => {
const connected = useWalletOnePointOh()?.connected ?? false

const communityPower = useGovernancePowerAsync('community')
const councilPower = useGovernancePowerAsync('council')

const bothLoading = communityPower.loading && councilPower.loading

const bothZero =
communityPower.result !== undefined &&
councilPower.result !== undefined &&
communityPower.result.isZero() &&
councilPower.result.isZero()

return (
<div>
<GovernancePowerTitle />
{!connected ? (
<div className={'text-xs text-white/50 mt-8'}>
Connect your wallet to see governance power
</div>
) : bothLoading ? (
<>
<div className="h-12 mb-4 rounded-lg animate-pulse bg-bkg-3" />
<div className="h-10 rounded-lg animate-pulse bg-bkg-3" />
</>
) : bothZero ? (
<div className={'text-xs text-white/50 mt-8'}>
You do not have any governance power in this dao
</div>
) : (
<div className="flex flex-col gap-2">
<GovernancePowerForRole role="community" />
<GovernancePowerForRole role="council" />
</div>
)}
</div>
)
}

export default GovernancePowerCard
56 changes: 56 additions & 0 deletions components/GovernancePower/GovernancePowerForRole.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import classNames from 'classnames'

import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import { useAsync } from 'react-async-hook'
import { determineVotingPowerType } from '@hooks/queries/governancePower'
import { useConnection } from '@solana/wallet-adapter-react'
import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey'
import LockedCommunityVotingPower from '@components/ProposalVotingPower/LockedCommunityVotingPower'
import NftVotingPower from '@components/ProposalVotingPower/NftVotingPower'
import LockedCommunityNFTRecordVotingPower from '@components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower'
import VanillaVotingPower from './Vanilla/VanillaVotingPower'

export default function GovernancePowerForRole({
role,
...props
}: {
role: 'community' | 'council'
className?: string
}) {
const { connection } = useConnection()

const realmPk = useSelectedRealmPubkey()

const wallet = useWalletOnePointOh()
const connected = !!wallet?.connected

const { result: kind } = useAsync(async () => {
if (realmPk === undefined) return undefined

return determineVotingPowerType(connection, realmPk, role)
}, [connection, realmPk, role])

if (connected && kind === undefined) {
return (
<div className="animate-pulse bg-bkg-1 col-span-1 h-[76px] rounded-lg" />
)
}

return (
<div className={classNames(props.className)}>
{role === 'community' ? (
kind === 'vanilla' ? (
<VanillaVotingPower role="community" />
) : kind === 'VSR' ? (
<LockedCommunityVotingPower />
) : kind === 'NFT' ? (
<NftVotingPower />
) : kind === 'HeliumVSR' ? (
<LockedCommunityNFTRecordVotingPower />
) : null
) : kind === 'vanilla' ? (
<VanillaVotingPower role="council" />
) : null}
</div>
)
}
75 changes: 75 additions & 0 deletions components/GovernancePower/Vanilla/Deposit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { BigNumber } from 'bignumber.js'
import { SecondaryButton } from '@components/Button'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import { useRealmQuery } from '@hooks/queries/realm'
import { useConnection } from '@solana/wallet-adapter-react'
import { useAsync } from 'react-async-hook'
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
Token,
TOKEN_PROGRAM_ID,
} from '@solana/spl-token'
import BN from 'bn.js'
import { fetchMintInfoByPubkey } from '@hooks/queries/mintInfo'
import { fetchTokenAccountByPubkey } from '@hooks/queries/tokenAccount'
import { useDepositCallback } from './useDepositCallback'
import { getMintMetadata } from '@components/instructions/programs/splToken'

export const Deposit = ({ role }: { role: 'community' | 'council' }) => {
const realm = useRealmQuery().data?.result
const wallet = useWalletOnePointOh()
const walletPk = wallet?.publicKey ?? undefined

const { connection } = useConnection()

const { result } = useAsync(async () => {
if (realm === undefined || walletPk === undefined) return undefined
const mint =
role === 'community'
? realm.account.communityMint
: realm.account.config.councilMint
if (mint === undefined) return undefined

const userAtaPk = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mint, // mint
walletPk // owner
)

const { result: userAta } = await fetchTokenAccountByPubkey(
connection,
userAtaPk
)
const { result: mintInfo } = await fetchMintInfoByPubkey(connection, mint)
return { mint, userAta, mintInfo } as const
}, [connection, realm, role, walletPk])

const depositAmount = result?.userAta?.amount
? new BigNumber(result.userAta.amount.toString())
: new BigNumber(0)

const tokenName =
getMintMetadata(result?.mint)?.name ?? realm?.account.name ?? ''

const deposit = useDepositCallback(role)

return !depositAmount.isGreaterThan(0) ? null : (
<>
<div className="mt-3 text-xs text-white/50">
You have{' '}
{result?.mintInfo
? depositAmount.shiftedBy(-result.mintInfo.decimals).toFormat()
: depositAmount.toFormat()}{' '}
more {tokenName} votes in your wallet. Do you want to deposit them to
increase your voting power in this Dao?
</div>
<SecondaryButton
className="mt-4 w-48"
onClick={() => deposit(new BN(depositAmount.toString()))}
>
Deposit
</SecondaryButton>
</>
)
}
Loading

0 comments on commit ededc09

Please sign in to comment.