Skip to content

Commit

Permalink
fix possible governance warning
Browse files Browse the repository at this point in the history
  • Loading branch information
abrzezinski94 committed Oct 4, 2023
1 parent 936cb8b commit e31064d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 71 deletions.
47 changes: 1 addition & 46 deletions components/ProposalStateBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
Proposal,
ProposalState,
getNativeTreasuryAddress,
} from '@solana/spl-governance'
import { Proposal, ProposalState } from '@solana/spl-governance'
import classNames from 'classnames'

import assertUnreachable from '@utils/typescript/assertUnreachable'
Expand All @@ -12,8 +8,6 @@ import {
useUserCouncilTokenOwnerRecord,
} from '@hooks/queries/tokenOwnerRecord'
import { useGovernanceByPubkeyQuery } from '@hooks/queries/governance'
import { useSelectedProposalTransactions } from '@hooks/queries/proposalTransaction'
import { useAsync } from 'react-async-hook'

export const hasInstructions = (proposal: Proposal) => {
if (proposal.instructionsCount) {
Expand Down Expand Up @@ -178,25 +172,6 @@ export default function ProposalStateBadge(props: Props) {

const coolOff = isInCoolOffTime(props.proposal, governance?.account)

const { data: allTransactions } = useSelectedProposalTransactions()
const treasuryAddress = useAsync(
async () =>
governance !== undefined
? getNativeTreasuryAddress(governance.owner, governance.pubkey)
: undefined,
[governance]
)
const walletsPassedToInstructions = allTransactions?.flatMap((tx) =>
tx.account.instructions.flatMap((ins) =>
ins.accounts.map((acc) => acc.pubkey)
)
)
const possibleWrongGovernance =
allTransactions?.length &&
!walletsPassedToInstructions?.find(
(x) => treasuryAddress.result && x.equals(treasuryAddress.result)
)

const otherState = {
isCreator,
isSignatory,
Expand All @@ -207,26 +182,6 @@ export default function ProposalStateBadge(props: Props) {

return (
<div>
{possibleWrongGovernance && (
<div
className={classNames(
props.className,
'border',
'inline-flex',
'min-w-max',
'items-center',
'px-2',
'py-1',
'rounded-full',
'text-xs',
'border-[#F5A458]',
'text-[#F5A458]',
'mr-2'
)}
>
Possible wrong governance
</div>
)}
<div
className={classNames(
props.className,
Expand Down
101 changes: 80 additions & 21 deletions pages/dao/[symbol]/proposal/[pk]/ProposalWarnings.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { ExclamationCircleIcon } from '@heroicons/react/solid'
import { useGovernanceByPubkeyQuery } from '@hooks/queries/governance'
import { useSelectedProposalTransactions } from '@hooks/queries/proposalTransaction'
import { useRealmConfigQuery } from '@hooks/queries/realmConfig'
import useRealm from '@hooks/useRealm'
import { Proposal, getNativeTreasuryAddress } from '@solana/spl-governance'
import { useMemo } from 'react'
import { useAsync } from 'react-async-hook'

const SetRealmConfigWarning = () => (
<div className="rounded-md bg-yellow-50 p-4">
Expand Down Expand Up @@ -81,11 +84,44 @@ const SetGovernanceConfig = () => (
</div>
)

const useProposalSafetyCheck = () => {
const PossibleWrongGovernance = () => (
<div className="rounded-md bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<ExclamationCircleIcon
className="h-5 w-5 text-yellow-400"
aria-hidden="true"
/>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-yellow-800">
Possible wrong governance pass, check accounts.
</h3>
</div>
</div>
</div>
)

const useProposalSafetyCheck = (proposal: Proposal) => {
const config = useRealmConfigQuery().data?.result

const { realmInfo } = useRealm()
const { data: transactions } = useSelectedProposalTransactions()
const governance = useGovernanceByPubkeyQuery(proposal.governance).data
?.result

const treasuryAddress = useAsync(
async () =>
governance !== undefined
? getNativeTreasuryAddress(governance.owner, governance.pubkey)
: undefined,
[governance]
)
const walletsPassedToInstructions = transactions?.flatMap((tx) =>
tx.account.instructions.flatMap((ins) =>
ins.accounts.map((acc) => acc.pubkey)
)
)

const realmConfigWarnings = useMemo(() => {
if (
Expand All @@ -97,41 +133,64 @@ const useProposalSafetyCheck = () => {

const ixs = transactions.flatMap((pix) => pix.account.getAllInstructions())

const realmConfigWarnings = ixs.map((ix) => {
if (ix.programId.equals(realmInfo.programId) && ix.data[0] === 19) {
return 'setGovernanceConfig'
}
if (ix.programId.equals(realmInfo.programId) && ix.data[0] === 22) {
return 'setRealmConfig'
}
if (
ix.accounts.find(
(a) => a.isWritable && a.pubkey.equals(config.pubkey)
) !== undefined
) {
if (ix.programId.equals(realmInfo.programId)) {
const possibleWrongGovernance =
transactions?.length &&
!walletsPassedToInstructions?.find(
(x) => governance?.pubkey.equals(x) || treasuryAddress.result?.equals(x)
)

const realmConfigWarnings: (
| 'setGovernanceConfig'
| 'setRealmConfig'
| 'thirdPartyInstructionWritesConfig'
| 'possibleWrongGovernance'
| undefined
)[] = []

realmConfigWarnings.push(
...ixs.map((ix) => {
if (ix.programId.equals(realmInfo.programId) && ix.data[0] === 19) {
return 'setGovernanceConfig'
}
if (ix.programId.equals(realmInfo.programId) && ix.data[0] === 22) {
return 'setRealmConfig'
} else {
return 'ThirdPartyInstructionWritesConfig'
}
}
})
if (
ix.accounts.find(
(a) => a.isWritable && a.pubkey.equals(config.pubkey)
) !== undefined
) {
if (ix.programId.equals(realmInfo.programId)) {
return 'setRealmConfig'
} else {
return 'thirdPartyInstructionWritesConfig'
}
}
})
)

if (possibleWrongGovernance) {
realmConfigWarnings.push('possibleWrongGovernance')
}

return realmConfigWarnings
}, [config, transactions, realmInfo])

return realmConfigWarnings
}

const ProposalWarnings = () => {
const warnings = useProposalSafetyCheck()
const ProposalWarnings = ({ proposal }: { proposal: Proposal }) => {
const warnings = useProposalSafetyCheck(proposal)
return (
<>
{warnings?.includes('setGovernanceConfig') && <SetGovernanceConfig />}
{warnings?.includes('setRealmConfig') && <SetRealmConfigWarning />}
{warnings?.includes('ThirdPartyInstructionWritesConfig') && (
{warnings?.includes('thirdPartyInstructionWritesConfig') && (
<ThirdPartyInstructionWritesConfigWarning />
)}
{warnings?.includes('possibleWrongGovernance') && (
<PossibleWrongGovernance></PossibleWrongGovernance>
)}
</>
)
}
Expand Down
13 changes: 9 additions & 4 deletions pages/dao/[symbol]/proposal/[pk]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import ProposalTimeStatus from 'components/ProposalTimeStatus'
import { useEffect, useState } from 'react'
import ProposalActionsPanel from '@components/ProposalActions'
import { getRealmExplorerHost } from 'tools/routing'
import { GovernanceAccountType, ProposalState, VoteType } from '@solana/spl-governance'
import {
GovernanceAccountType,
ProposalState,
VoteType,
} from '@solana/spl-governance'
import VoteResultStatus from '@components/VoteResultStatus'
import VoteResults from '@components/VoteResults'
import MultiChoiceVotes from '@components/MultiChoiceVotes'
Expand All @@ -37,8 +41,9 @@ const Proposal = () => {
const governance = useProposalGovernanceQuery().data?.result
const descriptionLink = proposal?.account.descriptionLink
const allowDiscussion = realmInfo?.allowDiscussion ?? true
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

const [description, setDescription] = useState('')
const voteData = useProposalVotes(proposal?.account)
Expand Down Expand Up @@ -120,7 +125,7 @@ const Proposal = () => {
</ReactMarkdown>
</div>
)}
<ProposalWarnings />
<ProposalWarnings proposal={proposal.account} />
<TransactionPanel />
{isTwoCol && allowDiscussion && <DiscussionPanel />}
</>
Expand Down

0 comments on commit e31064d

Please sign in to comment.