Skip to content

Commit a9159c5

Browse files
authored
add relinquish vote in other dao ix (#199)
1 parent 3e9704a commit a9159c5

File tree

4 files changed

+231
-0
lines changed

4 files changed

+231
-0
lines changed

hooks/useGovernanceAssets.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ export default function useGovernanceAssets() {
380380
isVisible: canUseTransferInstruction,
381381
packageId: PackageEnum.Common,
382382
},
383+
[Instructions.RelinquishDaoVote]: {
384+
name: 'Relinquish Vote from DAO',
385+
isVisible: canUseTransferInstruction,
386+
packageId: PackageEnum.Common,
387+
},
383388
[Instructions.DualFinanceVoteDeposit]: {
384389
name: 'Join a VSR DAO',
385390
isVisible: canUseTransferInstruction,
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import Input from '@components/inputs/Input'
2+
import useGovernanceAssets from '@hooks/useGovernanceAssets'
3+
import {
4+
getGovernanceAccounts,
5+
getProposal,
6+
getTokenOwnerRecordAddress,
7+
getVoteRecordAddress,
8+
Governance,
9+
ProgramAccount,
10+
pubkeyFilter,
11+
serializeInstructionToBase64,
12+
TOKEN_PROGRAM_ID,
13+
withRelinquishVote,
14+
} from '@solana/spl-governance'
15+
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
16+
import {
17+
RelinquishDaoVoteForm,
18+
UiInstruction,
19+
} from '@utils/uiTypes/proposalCreationTypes'
20+
import { useRouter } from 'next/router'
21+
import { useContext, useEffect, useState } from 'react'
22+
import GovernedAccountSelect from '../GovernedAccountSelect'
23+
import { NewProposalContext } from '../../new'
24+
import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'
25+
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
26+
import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery'
27+
import { getRealm } from '@realms-today/spl-governance'
28+
import {
29+
createAssociatedTokenAccountIdempotentInstruction,
30+
getAssociatedTokenAddressSync,
31+
} from '@solana/spl-token-new'
32+
33+
const RelinquishDaoVote = ({
34+
index,
35+
governance,
36+
}: {
37+
index: number
38+
governance: ProgramAccount<Governance> | null
39+
}) => {
40+
const wallet = useWalletOnePointOh()
41+
const connection = useLegacyConnectionContext()
42+
43+
const { governedTokenAccounts } = useGovernanceAssets()
44+
45+
const { handleSetInstructions } = useContext(NewProposalContext)
46+
47+
const [form, setForm] = useState<RelinquishDaoVoteForm>({
48+
governedAccount: undefined,
49+
mintInfo: undefined,
50+
realm: '',
51+
proposal: '',
52+
})
53+
54+
const [formErrors, setFormErrors] = useState({})
55+
const handleSetForm = ({ propertyName, value }) => {
56+
setFormErrors({})
57+
setForm({ ...form, [propertyName]: value })
58+
}
59+
60+
61+
const setRealm = (event) => {
62+
const value = event.target.value
63+
handleSetForm({
64+
value: value,
65+
propertyName: 'realm',
66+
})
67+
}
68+
69+
const setProposal = (event) => {
70+
const value = event.target.value
71+
handleSetForm({
72+
value: value,
73+
propertyName: 'proposal',
74+
})
75+
}
76+
77+
async function getInstruction() {
78+
if (
79+
!connection ||
80+
!form.realm ||
81+
!form.governedAccount?.governance.account ||
82+
!form.proposal ||
83+
!wallet?.publicKey
84+
) {
85+
return {
86+
serializedInstruction: '',
87+
isValid: false,
88+
governance: form.governedAccount?.governance,
89+
}
90+
}
91+
const realm = await getRealm(connection.current, new PublicKey(form.realm))
92+
93+
const instructions: TransactionInstruction[] = []
94+
const prerequisiteInstructions: TransactionInstruction[] = []
95+
96+
const programVersion = await fetchProgramVersion(
97+
connection.current,
98+
realm.owner,
99+
)
100+
101+
const mint = realm.account.communityMint
102+
const destinationAccount = getAssociatedTokenAddressSync(
103+
mint,
104+
form.governedAccount.extensions.transferAddress!,
105+
true,
106+
TOKEN_PROGRAM_ID,
107+
)
108+
109+
const createaAta = createAssociatedTokenAccountIdempotentInstruction(
110+
wallet.publicKey,
111+
destinationAccount,
112+
form.governedAccount.extensions.transferAddress!,
113+
mint,
114+
)
115+
prerequisiteInstructions.push(createaAta)
116+
117+
const voterTokenRecord = await getTokenOwnerRecordAddress(
118+
realm.owner,
119+
realm.pubkey,
120+
realm.account.communityMint,
121+
form.governedAccount.extensions.transferAddress!,
122+
)
123+
124+
const proposal = await getProposal(connection.current, new PublicKey(form.proposal))
125+
126+
const voteRecordAddress = await getVoteRecordAddress(
127+
realm.owner,
128+
proposal.pubkey,
129+
voterTokenRecord
130+
)
131+
132+
await withRelinquishVote(
133+
instructions,
134+
realm!.owner,
135+
programVersion,
136+
realm!.pubkey,
137+
proposal!.account.governance,
138+
proposal!.pubkey,
139+
voterTokenRecord,
140+
realm.account.communityMint,
141+
voteRecordAddress,
142+
form.governedAccount.extensions.transferAddress,
143+
form.governedAccount.extensions.transferAddress,
144+
)
145+
146+
const obj: UiInstruction = {
147+
serializedInstruction: '',
148+
additionalSerializedInstructions: instructions.map((x) =>
149+
serializeInstructionToBase64(x),
150+
),
151+
prerequisiteInstructions: prerequisiteInstructions,
152+
isValid: true,
153+
governance: form.governedAccount?.governance,
154+
customHoldUpTime: 0,
155+
chunkBy: 2,
156+
}
157+
return obj
158+
}
159+
160+
// Update mint info when selected token account changes.
161+
useEffect(() => {
162+
setForm({
163+
...form,
164+
mintInfo: form.governedAccount?.extensions.mint?.account,
165+
})
166+
// eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree
167+
}, [form.governedAccount])
168+
169+
useEffect(() => {
170+
handleSetInstructions(
171+
{
172+
governedAccount: form.governedAccount?.governance,
173+
getInstruction,
174+
},
175+
index,
176+
)
177+
// eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree
178+
}, [form])
179+
180+
return (
181+
<>
182+
<Input
183+
label="Realm"
184+
value={form.realm}
185+
type="text"
186+
onChange={setRealm}
187+
error={formErrors['realm']}
188+
/>
189+
<Input
190+
label="Proposal"
191+
value={form.proposal}
192+
type="text"
193+
onChange={setProposal}
194+
error={formErrors['proposal']}
195+
/>
196+
{form.realm ? (
197+
<>
198+
<GovernedAccountSelect
199+
label="Token Account"
200+
governedAccounts={governedTokenAccounts}
201+
onChange={(value) => {
202+
handleSetForm({ value, propertyName: 'governedAccount' })
203+
}}
204+
value={form.governedAccount}
205+
error={formErrors['governedAccount']}
206+
shouldBeGoverned={!!governance}
207+
governance={governance}
208+
type="wallet"
209+
/>
210+
</>
211+
) : null}
212+
</>
213+
)
214+
}
215+
216+
export default RelinquishDaoVote

pages/dao/[symbol]/proposal/new.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ import WithdrawFees from './components/instructions/Token2022/WithdrawFees'
157157
import SquadsV4RemoveMember from './components/instructions/Squads/SquadsV4RemoveMember'
158158
import CollectPoolFees from './components/instructions/Raydium/CollectPoolFees'
159159
import CollectVestedTokens from './components/instructions/Raydium/CollectVestedTokens'
160+
import RelinquishDaoVote from './components/instructions/RelinquishDaoVote'
160161

161162
const TITLE_LENGTH_LIMIT = 130
162163
// the true length limit is either at the tx size level, and maybe also the total account size level (I can't remember)
@@ -517,6 +518,7 @@ const New = () => {
517518
[Instructions.DualFinanceExerciseStakingOption]: DualExercise,
518519
[Instructions.DualFinanceDelegate]: DualDelegate,
519520
[Instructions.DualFinanceDelegateWithdraw]: DualVoteDepositWithdraw,
521+
[Instructions.RelinquishDaoVote]: RelinquishDaoVote,
520522
[Instructions.DualFinanceVoteDeposit]: DualVoteDeposit,
521523
[Instructions.DaoVote]: DaoVote,
522524
[Instructions.DistributionCloseVaults]: CloseVaults,

utils/uiTypes/proposalCreationTypes.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,13 @@ export interface WithdrawDAOForm {
311311
amount?: number
312312
}
313313

314+
export interface RelinquishDaoVoteForm {
315+
governedAccount?: AssetAccount
316+
mintInfo: MintInfo | undefined
317+
realm: string
318+
proposal: string
319+
}
320+
314321
export enum Instructions {
315322
Base64,
316323
Burn,
@@ -340,6 +347,7 @@ export enum Instructions {
340347
DualFinanceStakingOptionWithdraw,
341348
DualFinanceDelegate,
342349
DualFinanceDelegateWithdraw,
350+
RelinquishDaoVote,
343351
DualFinanceVoteDeposit,
344352
DaoVote,
345353
DistributionCloseVaults,

0 commit comments

Comments
 (0)