From 9396e6e32b0cd1cde12130b12016777fab4e375d Mon Sep 17 00:00:00 2001 From: panosdb Date: Thu, 12 Sep 2024 22:13:22 +0300 Subject: [PATCH 1/2] CreateNewProposalWithInsufficientPower --- components/MultiChoiceForm.tsx | 24 ++++--- hooks/useCreateProposal.ts | 62 +++++++++++++++++++ .../proposal/components/NewProposalBtn.tsx | 44 +------------ pages/dao/[symbol]/proposal/new.tsx | 17 ++--- 4 files changed, 92 insertions(+), 55 deletions(-) diff --git a/components/MultiChoiceForm.tsx b/components/MultiChoiceForm.tsx index b1b605f845..d2fb5ab381 100644 --- a/components/MultiChoiceForm.tsx +++ b/components/MultiChoiceForm.tsx @@ -5,9 +5,10 @@ import { XCircleIcon } from '@heroicons/react/solid' import useGovernanceAssets from '@hooks/useGovernanceAssets' import Input from '@components/inputs/Input' import GovernedAccountSelect from '../pages/dao/[symbol]/proposal/components/GovernedAccountSelect' -import { PublicKey } from '@solana/web3.js' import { AccountType, AssetAccount } from '@utils/uiTypes/assets' import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import { Governance, ProgramAccount } from '@solana/spl-governance' +import { useEffect } from 'react' const MultiChoiceForm = ({ multiChoiceForm, @@ -17,7 +18,7 @@ const MultiChoiceForm = ({ updateMultiFormErrors, }: { multiChoiceForm: { - governance: PublicKey | undefined + governance: ProgramAccount | null options: string[] } updateMultiChoiceForm: any @@ -37,6 +38,17 @@ const MultiChoiceForm = ({ updateMultiChoiceForm({ ...multiChoiceForm, [propertyName]: value }) } + const governedAccounts = assetAccounts.filter((x) => + ownVoterWeight?.canCreateProposal(x.governance.account.config) + ) + + useEffect(() => { + handleMultiForm({ + value: governedAccounts.length ? governedAccounts[0].governance : null, + propertyName: 'governance' + }) + }, [governedAccounts.length]); + const handleNotaButton = () => { const options = [...multiChoiceForm.options] options.push(nota) @@ -78,12 +90,10 @@ const MultiChoiceForm = ({
- ownVoterWeight?.canCreateProposal(x.governance.account.config) - )} + governedAccounts={governedAccounts} onChange={(value: AssetAccount) => { handleMultiForm({ - value: value.governance.pubkey, + value: value.governance, propertyName: 'governance', }) }} @@ -91,7 +101,7 @@ const MultiChoiceForm = ({ governance ? assetAccounts.find( (x) => - x.governance.pubkey.equals(governance) && + x.governance.pubkey.equals(governance.pubkey) && x.type === AccountType.SOL ) : null diff --git a/hooks/useCreateProposal.ts b/hooks/useCreateProposal.ts index 434bdfbbe2..5172be616c 100644 --- a/hooks/useCreateProposal.ts +++ b/hooks/useCreateProposal.ts @@ -17,6 +17,13 @@ import { proposalQueryKeys } from './queries/proposal' import { createLUTProposal } from 'actions/createLUTproposal' import { useLegacyVoterWeight } from './queries/governancePower' import {useVotingClients} from "@hooks/useVotingClients"; +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import useRealm from '@hooks/useRealm' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import BN from 'bn.js' +import { formatNumber } from '@utils/formatNumber' +import { BigNumber } from 'bignumber.js' +import { Governance, ProgramAccount } from '@solana/spl-governance' export default function useCreateProposal() { const connection = useLegacyConnectionContext() @@ -202,3 +209,58 @@ export default function useCreateProposal() { return { handleCreateProposal, propose, proposeMultiChoice } } + +export const useCanCreateProposal = ( + governance?: ProgramAccount | null +) => { + const wallet = useWalletOnePointOh() + const connected = !!wallet?.connected + + const realm = useRealmQuery().data?.result + + const { + ownVoterWeight: communityOwnVoterWeight, + } = useRealmVoterWeightPlugins('community') + const { + isReady, + ownVoterWeight: councilOwnVoterWeight, + } = useRealmVoterWeightPlugins('council') + const { + toManyCommunityOutstandingProposalsForUser, + toManyCouncilOutstandingProposalsForUse, + } = useRealm() + + const communityOwnVoterWeightValue = communityOwnVoterWeight && communityOwnVoterWeight.value + const councilOwnVoterWeightValue = councilOwnVoterWeight && councilOwnVoterWeight.value + + const minWeightToCreateProposal = (governance?.pubkey == realm?.account.communityMint ? + governance?.account.config.minCommunityTokensToCreateProposal : + governance?.account.config.minCouncilTokensToCreateProposal) || new BN(1) + + const votingPower = communityOwnVoterWeightValue || councilOwnVoterWeightValue + + const hasEnoughVotingPower = votingPower?.gt(minWeightToCreateProposal) + + const canCreateProposal = + realm && + hasEnoughVotingPower && + !toManyCommunityOutstandingProposalsForUser && + !toManyCouncilOutstandingProposalsForUse + + const error = !connected + ? 'Connect your wallet to create new proposal' + : isReady && !communityOwnVoterWeight && !councilOwnVoterWeight + ? 'There is no governance configuration to create a new proposal' + : !hasEnoughVotingPower + ? `Please select only one account with at least ${formatNumber(new BigNumber(minWeightToCreateProposal.toString()))} governance power to create a new proposal.` + : toManyCommunityOutstandingProposalsForUser + ? 'Too many community outstanding proposals. You need to finalize them before creating a new one.' + : toManyCouncilOutstandingProposalsForUse + ? 'Too many council outstanding proposals. You need to finalize them before creating a new one.' + : '' + + return { + canCreateProposal, + error + } +} diff --git a/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx b/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx index 5c1e0bbf93..b43846bc53 100644 --- a/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx +++ b/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx @@ -3,52 +3,14 @@ import { PlusCircleIcon } from '@heroicons/react/outline' import useQueryContext from '@hooks/useQueryContext' import useRealm from '@hooks/useRealm' import Tooltip from '@components/Tooltip' -import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { useRealmQuery } from '@hooks/queries/realm' -import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import { useCanCreateProposal } from '@hooks/useCreateProposal' const NewProposalBtn = () => { const { fmtUrlWithCluster } = useQueryContext() - const wallet = useWalletOnePointOh() - const connected = !!wallet?.connected + const { symbol } = useRealm() - const realm = useRealmQuery().data?.result - // const { result: ownVoterWeight } = useLegacyVoterWeight() - const { - ownVoterWeight: communityOwnVoterWeight, - } = useRealmVoterWeightPlugins('community') - const { - isReady, - ownVoterWeight: councilOwnVoterWeight, - } = useRealmVoterWeightPlugins('council') - const { - symbol, - toManyCommunityOutstandingProposalsForUser, - toManyCouncilOutstandingProposalsForUse, - } = useRealm() - - const hasVotingPower = - (communityOwnVoterWeight && communityOwnVoterWeight.value?.gtn(0)) || - (councilOwnVoterWeight && councilOwnVoterWeight.value?.gtn(0)) - - const canCreateProposal = - realm && - hasVotingPower && - !toManyCommunityOutstandingProposalsForUser && - !toManyCouncilOutstandingProposalsForUse - - const tooltipContent = !connected - ? 'Connect your wallet to create new proposal' - : isReady && !communityOwnVoterWeight && !councilOwnVoterWeight - ? 'There is no governance configuration to create a new proposal' - : !hasVotingPower - ? "You don't have enough governance power to create a new proposal" - : toManyCommunityOutstandingProposalsForUser - ? 'Too many community outstanding proposals. You need to finalize them before creating a new one.' - : toManyCouncilOutstandingProposalsForUse - ? 'Too many council outstanding proposals. You need to finalize them before creating a new one.' - : '' + const { canCreateProposal, error: tooltipContent } = useCanCreateProposal() return ( <> diff --git a/pages/dao/[symbol]/proposal/new.tsx b/pages/dao/[symbol]/proposal/new.tsx index 06b669f776..0ce45245a9 100644 --- a/pages/dao/[symbol]/proposal/new.tsx +++ b/pages/dao/[symbol]/proposal/new.tsx @@ -62,7 +62,7 @@ import DeactivateValidatorStake from './components/instructions/Validators/Deact import WithdrawValidatorStake from './components/instructions/Validators/WithdrawStake' import DelegateStake from './components/instructions/Validators/DelegateStake' import SplitStake from './components/instructions/Validators/SplitStake' -import useCreateProposal from '@hooks/useCreateProposal' +import useCreateProposal, { useCanCreateProposal } from '@hooks/useCreateProposal' import RealmConfig from './components/instructions/RealmConfig' import CloseTokenAccount from './components/instructions/CloseTokenAccount' import CloseMultipleTokenAccounts from './components/instructions/CloseMultipleTokenAccounts' @@ -151,7 +151,7 @@ const schema = yup.object().shape({ }) const multiChoiceSchema = yup.object().shape({ - governance: yup.string().required('Governance is required'), + governance: yup.object().required('Governance is required'), options: yup.array().of(yup.string().required('Option cannot be empty')), }) @@ -206,10 +206,10 @@ const New = () => { setVoteByCouncil, } = useVoteByCouncilToggle() const [multiChoiceForm, setMultiChoiceForm] = useState<{ - governance: PublicKey | undefined + governance: ProgramAccount | null options: string[] }>({ - governance: undefined, + governance: null, options: ['', ''], // the multichoice form starts with 2 blank options for the poll }) // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -325,7 +325,7 @@ const New = () => { proposalAddress = await proposeMultiChoice({ title: form.title, description: form.description, - governance: multiChoiceForm.governance, + governance: multiChoiceForm.governance.pubkey, instructionsData: [], voteByCouncil, options, @@ -635,6 +635,8 @@ const New = () => { [governance?.pubkey?.toBase58()] ) + const { canCreateProposal, error } = useCanCreateProposal(isMulti ? multiChoiceForm.governance : governance) + return (
{ )}
handleCreate(true)} > @@ -841,12 +843,13 @@ const New = () => {
+ {error &&

{error}

}
From 73ab42902dd99c1ce80e86f32664ddfac1dc8f45 Mon Sep 17 00:00:00 2001 From: panosdb Date: Tue, 24 Sep 2024 19:11:48 +0300 Subject: [PATCH 2/2] Add check if governance power is enough to vote. If the user hasn't selected a delegate wallet, it will automatically pick the one with most governance power. --- hooks/queries/addresses/tokenOwnerRecord.ts | 26 ++-- hooks/queries/tokenOwnerRecord.ts | 12 ++ hooks/useCreateProposal.ts | 136 +++++++++++++++----- pages/dao/[symbol]/proposal/new.tsx | 3 +- 4 files changed, 138 insertions(+), 39 deletions(-) diff --git a/hooks/queries/addresses/tokenOwnerRecord.ts b/hooks/queries/addresses/tokenOwnerRecord.ts index 96121a8ef0..04a7c3beb0 100644 --- a/hooks/queries/addresses/tokenOwnerRecord.ts +++ b/hooks/queries/addresses/tokenOwnerRecord.ts @@ -5,8 +5,17 @@ import { useQuery } from '@tanstack/react-query' import { useRealmQuery } from '../realm' import { useSelectedDelegatorStore } from 'stores/useSelectedDelegatorStore' -export const useAddressQuery_CouncilTokenOwner = () => { +export const useAddressQuery_CouncilTokenOwnerByPK = (owner: PublicKey | undefined) => { const realm = useRealmQuery().data?.result + return useAddressQuery_TokenOwnerRecord( + realm?.owner, + realm?.pubkey, + realm?.account.config.councilMint, + owner + ) +} + +export const useAddressQuery_CouncilTokenOwner = () => { const wallet = useWalletOnePointOh() const selectedCouncilDelegator = useSelectedDelegatorStore( (s) => s.councilDelegator @@ -18,16 +27,20 @@ export const useAddressQuery_CouncilTokenOwner = () => { ? selectedCouncilDelegator : wallet?.publicKey ?? undefined + return useAddressQuery_CouncilTokenOwnerByPK(owner) +} + +export const useAddressQuery_CommunityTokenOwnerByPK = (owner: PublicKey | undefined) => { + const realm = useRealmQuery().data?.result return useAddressQuery_TokenOwnerRecord( realm?.owner, realm?.pubkey, - realm?.account.config.councilMint, + realm?.account.communityMint, owner ) } export const useAddressQuery_CommunityTokenOwner = () => { - const realm = useRealmQuery().data?.result const wallet = useWalletOnePointOh() const selectedCommunityDelegator = useSelectedDelegatorStore( (s) => s.communityDelegator @@ -40,12 +53,7 @@ export const useAddressQuery_CommunityTokenOwner = () => { : // I wanted to eliminate `null` as a possible type wallet?.publicKey ?? undefined - return useAddressQuery_TokenOwnerRecord( - realm?.owner, - realm?.pubkey, - realm?.account.communityMint, - owner - ) + return useAddressQuery_CommunityTokenOwnerByPK(owner) } export const useAddressQuery_TokenOwnerRecord = ( diff --git a/hooks/queries/tokenOwnerRecord.ts b/hooks/queries/tokenOwnerRecord.ts index 78f3d1f5b8..e18b4cbf2e 100644 --- a/hooks/queries/tokenOwnerRecord.ts +++ b/hooks/queries/tokenOwnerRecord.ts @@ -11,6 +11,8 @@ import asFindable from '@utils/queries/asFindable' import { useAddressQuery_CommunityTokenOwner, useAddressQuery_CouncilTokenOwner, + useAddressQuery_CommunityTokenOwnerByPK, + useAddressQuery_CouncilTokenOwnerByPK } from './addresses/tokenOwnerRecord' import { useRealmQuery } from './realm' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' @@ -238,3 +240,13 @@ export const useUserCouncilTokenOwnerRecord = () => { const { data: tokenOwnerRecordPubkey } = useAddressQuery_CouncilTokenOwner() return useTokenOwnerRecordByPubkeyQuery(tokenOwnerRecordPubkey) } + +export const useUserCommunityTokenOwnerRecordByPK = (pk: PublicKey | undefined) => { + const { data: tokenOwnerRecordPubkey } = useAddressQuery_CommunityTokenOwnerByPK(pk) + return useTokenOwnerRecordByPubkeyQuery(tokenOwnerRecordPubkey) +} + +export const useUserCouncilTokenOwnerRecordByPK = (pk: PublicKey | undefined) => { + const { data: tokenOwnerRecordPubkey } = useAddressQuery_CouncilTokenOwnerByPK(pk) + return useTokenOwnerRecordByPubkeyQuery(tokenOwnerRecordPubkey) +} diff --git a/hooks/useCreateProposal.ts b/hooks/useCreateProposal.ts index 5172be616c..4a66af1352 100644 --- a/hooks/useCreateProposal.ts +++ b/hooks/useCreateProposal.ts @@ -15,15 +15,19 @@ import useLegacyConnectionContext from './useLegacyConnectionContext' import queryClient from './queries/queryClient' import { proposalQueryKeys } from './queries/proposal' import { createLUTProposal } from 'actions/createLUTproposal' -import { useLegacyVoterWeight } from './queries/governancePower' import {useVotingClients} from "@hooks/useVotingClients"; import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' import useRealm from '@hooks/useRealm' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import BN from 'bn.js' -import { formatNumber } from '@utils/formatNumber' import { BigNumber } from 'bignumber.js' import { Governance, ProgramAccount } from '@solana/spl-governance' +import { + useTokenOwnerRecordsDelegatedToUser, + useUserCommunityTokenOwnerRecordByPK, useUserCouncilTokenOwnerRecordByPK +} from '@hooks/queries/tokenOwnerRecord' +import { useSelectedDelegatorStore } from '../stores/useSelectedDelegatorStore' +import { shortenAddress } from '@utils/address' export default function useCreateProposal() { const connection = useLegacyConnectionContext() @@ -31,7 +35,21 @@ export default function useCreateProposal() { const config = useRealmConfigQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result const councilMint = useRealmCouncilMintInfoQuery().data?.result - const { result: ownVoterWeight } = useLegacyVoterWeight() + // const { result: ownVoterWeight } = useLegacyVoterWeight() + const { + power: communityPower, + proposer: communityProposer, + } = useProposeAs('community') + const { data: communityProposerData } = useUserCommunityTokenOwnerRecordByPK(communityProposer) + const communityProposerTokenRecord = communityProposerData?.result + + const { + power: councilPower, + proposer: councilProposer, + } = useProposeAs('council') + + const { data: councilProposerData } = useUserCouncilTokenOwnerRecordByPK(councilProposer) + const councilProposerTokenRecord = councilProposerData?.result const { getRpcContext } = useRpcContext() const votingClients = useVotingClients(); @@ -59,21 +77,26 @@ export default function useCreateProposal() { governance.pubkey ) const minCouncilTokensToCreateProposal = selectedGovernance?.account.config.minCouncilTokensToCreateProposal - const councilPower = ownVoterWeight?.councilTokenRecord?.account.governingTokenDepositAmount + const minCommunityTokensToCreateProposal = selectedGovernance?.account.config.minCommunityTokensToCreateProposal - const ownTokenRecord = - minCouncilTokensToCreateProposal && councilPower && councilPower >= minCouncilTokensToCreateProposal ? - ownVoterWeight?.councilTokenRecord : - ownVoterWeight?.communityTokenRecord + const useCouncilPower = minCouncilTokensToCreateProposal && councilPower && councilPower.gte(minCouncilTokensToCreateProposal) + const ownTokenRecord = + useCouncilPower ? + councilProposerTokenRecord : + communityProposerTokenRecord if (!ownTokenRecord) throw new Error('token owner record does not exist') if (!selectedGovernance) throw new Error('governance not found') if (!realm) throw new Error() + if (!useCouncilPower && communityPower && minCommunityTokensToCreateProposal && communityPower.lt(minCommunityTokensToCreateProposal)) { + throw new Error('Not enough voting power') + } + // this is somewhat confusing - the basic idea is: // although a vote may be by community vote, the proposer may create it with their council token // The choice of which token to use is made when the token record is selected - const proposeByCouncil = ownVoterWeight?.councilTokenRecord?.pubkey.toBase58() === (ownTokenRecord?.pubkey.toBase58() ?? ""); + const proposeByCouncil = councilProposer?.toBase58() === (ownTokenRecord?.pubkey.toBase58() ?? ""); // now we can we identify whether we are using the community or council voting client (to decide which (if any) plugins to use) const votingClient = votingClients(proposeByCouncil ? 'council' : 'community'); @@ -150,12 +173,17 @@ export default function useCreateProposal() { ) const minCouncilTokensToCreateProposal = selectedGovernance?.account.config.minCouncilTokensToCreateProposal - const councilPower = ownVoterWeight?.councilTokenRecord?.account.governingTokenDepositAmount + const minCommunityTokensToCreateProposal = selectedGovernance?.account.config.minCommunityTokensToCreateProposal - const ownTokenRecord = - minCouncilTokensToCreateProposal && councilPower && councilPower >= minCouncilTokensToCreateProposal ? - ownVoterWeight?.councilTokenRecord : - ownVoterWeight?.communityTokenRecord + const useCouncilPower = minCouncilTokensToCreateProposal && councilPower && councilPower.gte(minCouncilTokensToCreateProposal) + const ownTokenRecord = + useCouncilPower ? + councilProposerTokenRecord : + communityProposerTokenRecord + + if (!useCouncilPower && communityPower && minCommunityTokensToCreateProposal && communityPower.lt(minCommunityTokensToCreateProposal)) { + throw new Error('Not enough voting power') + } if (!ownTokenRecord) throw new Error('token owner record does not exist') if (!selectedGovernance) throw new Error('governance not found') @@ -164,7 +192,7 @@ export default function useCreateProposal() { // this is somewhat confusing - the basic idea is: // although a vote may be by community vote, the proposer may create it with their council token // The choice of which token to use is made when the token record is selected - const proposeByCouncil = ownVoterWeight?.councilTokenRecord?.pubkey.toBase58() === (ownTokenRecord?.pubkey.toBase58() ?? ""); + const proposeByCouncil = councilProposer?.toBase58() === (ownTokenRecord?.pubkey.toBase58() ?? ""); // now we can we identify whether we are using the community or council voting client (to decide which (if any) plugins to use) const votingClient = votingClients(proposeByCouncil ? 'council' : 'community'); @@ -210,6 +238,42 @@ export default function useCreateProposal() { return { handleCreateProposal, propose, proposeMultiChoice } } +const useProposeAs = ( + role: 'community' | 'council', +) => { + const wallet = useWalletOnePointOh() + const { voterWeightForWallet, isReady } = useRealmVoterWeightPlugins(role) + + const { councilDelegator, communityDelegator} = useSelectedDelegatorStore() + const { data: delegatesArray } = useTokenOwnerRecordsDelegatedToUser() + + + let proposer = councilDelegator + ? councilDelegator + : communityDelegator + ? communityDelegator + : wallet?.publicKey || undefined + + let maxPower = proposer ? voterWeightForWallet(proposer)?.value : new BN(0) + // The user hasn't selected a specific delegator to perform actions as + // We will use the delegator with the maximum power, or the user's wallet + if (!councilDelegator && !communityDelegator && delegatesArray) { + for (const delegator of delegatesArray) { + const p = voterWeightForWallet(delegator.account.governingTokenOwner)?.value + if (p && maxPower && p.gt(maxPower)) { + maxPower = p + proposer = delegator.account.governingTokenOwner + } + } + } + + return { + power: maxPower, + proposer, + isReady + } +} + export const useCanCreateProposal = ( governance?: ProgramAccount | null ) => { @@ -219,27 +283,32 @@ export const useCanCreateProposal = ( const realm = useRealmQuery().data?.result const { - ownVoterWeight: communityOwnVoterWeight, - } = useRealmVoterWeightPlugins('community') + power: communityPower, + proposer: communityProposer, + isReady: communityReady + } = useProposeAs('community') + const { - isReady, - ownVoterWeight: councilOwnVoterWeight, - } = useRealmVoterWeightPlugins('council') + power: councilPower, + proposer: councilProposer, + isReady: councilReady + } = useProposeAs('council') + + const power = communityPower || councilPower + const proposer = communityPower ? communityProposer : councilProposer + const isReady = communityReady && councilReady + const { toManyCommunityOutstandingProposalsForUser, toManyCouncilOutstandingProposalsForUse, } = useRealm() - const communityOwnVoterWeightValue = communityOwnVoterWeight && communityOwnVoterWeight.value - const councilOwnVoterWeightValue = councilOwnVoterWeight && councilOwnVoterWeight.value const minWeightToCreateProposal = (governance?.pubkey == realm?.account.communityMint ? governance?.account.config.minCommunityTokensToCreateProposal : - governance?.account.config.minCouncilTokensToCreateProposal) || new BN(1) - - const votingPower = communityOwnVoterWeightValue || councilOwnVoterWeightValue + governance?.account.config.minCouncilTokensToCreateProposal) || undefined - const hasEnoughVotingPower = votingPower?.gt(minWeightToCreateProposal) + const hasEnoughVotingPower = power?.gt(minWeightToCreateProposal || new BN(1)) const canCreateProposal = realm && @@ -247,20 +316,29 @@ export const useCanCreateProposal = ( !toManyCommunityOutstandingProposalsForUser && !toManyCouncilOutstandingProposalsForUse + const minWeightToCreateProposalS = minWeightToCreateProposal + ? new BigNumber(minWeightToCreateProposal.toString()).toString() + : "1" + const error = !connected ? 'Connect your wallet to create new proposal' - : isReady && !communityOwnVoterWeight && !councilOwnVoterWeight + : isReady && !communityPower && !councilPower ? 'There is no governance configuration to create a new proposal' : !hasEnoughVotingPower - ? `Please select only one account with at least ${formatNumber(new BigNumber(minWeightToCreateProposal.toString()))} governance power to create a new proposal.` + ? `Please select only one account with at least ${minWeightToCreateProposalS} governance power to create a new proposal.` : toManyCommunityOutstandingProposalsForUser ? 'Too many community outstanding proposals. You need to finalize them before creating a new one.' : toManyCouncilOutstandingProposalsForUse ? 'Too many council outstanding proposals. You need to finalize them before creating a new one.' : '' + const warning = proposer + ? `Add a proposal as: ${shortenAddress(proposer.toString())}.` + : '' + return { canCreateProposal, - error + error, + warning } } diff --git a/pages/dao/[symbol]/proposal/new.tsx b/pages/dao/[symbol]/proposal/new.tsx index 0ce45245a9..eb38889471 100644 --- a/pages/dao/[symbol]/proposal/new.tsx +++ b/pages/dao/[symbol]/proposal/new.tsx @@ -635,7 +635,7 @@ const New = () => { [governance?.pubkey?.toBase58()] ) - const { canCreateProposal, error } = useCanCreateProposal(isMulti ? multiChoiceForm.governance : governance) + const { canCreateProposal, error, warning } = useCanCreateProposal(isMulti ? multiChoiceForm.governance : governance) return (
@@ -849,6 +849,7 @@ const New = () => { Add proposal
+ {warning &&

{warning}

} {error &&

{error}

}