DAO Delegation Support (#1692)
Co-authored-by: Adrian Brzeziński <a.brzezinski94@gmail.com>
This commit is contained in:
parent
766de633a3
commit
e2d34f924c
|
@ -66,7 +66,8 @@ export default async function depositTokens({
|
|||
wallet!.publicKey,
|
||||
transferAuthority.publicKey,
|
||||
wallet!.publicKey,
|
||||
amountBN
|
||||
amountBN,
|
||||
true
|
||||
)
|
||||
|
||||
const transaction = new Transaction()
|
||||
|
|
|
@ -80,6 +80,8 @@ export const GOVERNANCE_INSTRUCTIONS = {
|
|||
connection,
|
||||
realm.owner
|
||||
)
|
||||
|
||||
//accounts[2] is token account not mint account
|
||||
const mintInfoQuery = await fetchMintInfoByPubkey(
|
||||
connection,
|
||||
accounts[2].pubkey
|
||||
|
@ -90,7 +92,11 @@ export const GOVERNANCE_INSTRUCTIONS = {
|
|||
DepositGoverningTokensArgs,
|
||||
Buffer.from(data)
|
||||
) as DepositGoverningTokensArgs
|
||||
|
||||
console.log(
|
||||
args.amount,
|
||||
mintInfoQuery?.result,
|
||||
accounts[2].pubkey.toBase58()
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
|
|
|
@ -400,6 +400,21 @@ export default function useGovernanceAssets() {
|
|||
isVisible: canUseTransferInstruction,
|
||||
packageId: PackageEnum.Dual,
|
||||
},
|
||||
[Instructions.DualFinanceDelegate]: {
|
||||
name: 'Delegate',
|
||||
isVisible: canUseTransferInstruction,
|
||||
packageId: PackageEnum.Dual,
|
||||
},
|
||||
[Instructions.DualFinanceDelegateWithdraw]: {
|
||||
name: 'Withdraw Delegate',
|
||||
isVisible: canUseTransferInstruction,
|
||||
packageId: PackageEnum.Dual,
|
||||
},
|
||||
[Instructions.DualFinanceVoteDeposit]: {
|
||||
name: 'Vote Deposit',
|
||||
isVisible: canUseTransferInstruction,
|
||||
packageId: PackageEnum.Dual,
|
||||
},
|
||||
|
||||
/*
|
||||
███████ ██ ██ ███████ ██████ ██ ███████ ███ ██ ██████
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { ProgramAccount, Governance } from '@solana/spl-governance'
|
||||
import {
|
||||
UiInstruction,
|
||||
DualFinanceDelegateForm,
|
||||
} from '@utils/uiTypes/proposalCreationTypes'
|
||||
import { NewProposalContext } from '../../../new'
|
||||
import GovernedAccountSelect from '../../GovernedAccountSelect'
|
||||
import useGovernanceAssets from '@hooks/useGovernanceAssets'
|
||||
import Input from '@components/inputs/Input'
|
||||
import { getDelegateInstruction } from '@utils/instructions/Dual/delegate'
|
||||
import { getDualFinanceDelegateSchema } from '@utils/validations'
|
||||
import Tooltip from '@components/Tooltip'
|
||||
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
|
||||
import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'
|
||||
|
||||
const DualDelegate = ({
|
||||
index,
|
||||
governance,
|
||||
}: {
|
||||
index: number
|
||||
governance: ProgramAccount<Governance> | null
|
||||
}) => {
|
||||
const [form, setForm] = useState<DualFinanceDelegateForm>({
|
||||
delegateAccount: undefined,
|
||||
realm: undefined,
|
||||
delegateToken: undefined,
|
||||
})
|
||||
const connection = useLegacyConnectionContext()
|
||||
const wallet = useWalletOnePointOh()
|
||||
const shouldBeGoverned = !!(index !== 0 && governance)
|
||||
const { assetAccounts } = useGovernanceAssets()
|
||||
const [governedAccount, setGovernedAccount] = useState<
|
||||
ProgramAccount<Governance> | undefined
|
||||
>(undefined)
|
||||
const [formErrors, setFormErrors] = useState({})
|
||||
const { handleSetInstructions } = useContext(NewProposalContext)
|
||||
const handleSetForm = ({ propertyName, value }) => {
|
||||
setFormErrors({})
|
||||
setForm({ ...form, [propertyName]: value })
|
||||
}
|
||||
const schema = getDualFinanceDelegateSchema()
|
||||
useEffect(() => {
|
||||
function getInstruction(): Promise<UiInstruction> {
|
||||
return getDelegateInstruction({
|
||||
connection,
|
||||
form,
|
||||
schema,
|
||||
setFormErrors,
|
||||
wallet,
|
||||
})
|
||||
}
|
||||
handleSetInstructions(
|
||||
{ governedAccount: governedAccount, getInstruction },
|
||||
index
|
||||
)
|
||||
}, [
|
||||
form,
|
||||
governedAccount,
|
||||
handleSetInstructions,
|
||||
index,
|
||||
connection,
|
||||
schema,
|
||||
wallet,
|
||||
])
|
||||
useEffect(() => {
|
||||
setGovernedAccount(form.delegateToken?.governance)
|
||||
}, [form.delegateToken?.governance])
|
||||
|
||||
// TODO: Include this in the config instruction which can optionally be done
|
||||
// if the project doesnt need to change where the tokens get returned to.
|
||||
return (
|
||||
<>
|
||||
<Tooltip content="Account to Delegate Votes">
|
||||
<Input
|
||||
label="Delegate Account"
|
||||
value={form.delegateAccount}
|
||||
type="text"
|
||||
onChange={(evt) =>
|
||||
handleSetForm({
|
||||
value: evt.target.value,
|
||||
propertyName: 'delegateAccount',
|
||||
})
|
||||
}
|
||||
error={formErrors['delegateAccount']}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Input
|
||||
label="Realm"
|
||||
value={form.realm}
|
||||
type="text"
|
||||
onChange={(evt) =>
|
||||
handleSetForm({
|
||||
value: evt.target.value,
|
||||
propertyName: 'realm',
|
||||
})
|
||||
}
|
||||
error={formErrors['realm']}
|
||||
/>
|
||||
<Tooltip content="Token to be delegated.">
|
||||
<GovernedAccountSelect
|
||||
label="Delegate Token"
|
||||
governedAccounts={assetAccounts}
|
||||
onChange={(value) => {
|
||||
handleSetForm({ value, propertyName: 'delegateToken' })
|
||||
}}
|
||||
value={form.delegateToken}
|
||||
error={formErrors['delegateToken']}
|
||||
shouldBeGoverned={shouldBeGoverned}
|
||||
governance={governance}
|
||||
type="token"
|
||||
></GovernedAccountSelect>
|
||||
</Tooltip>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DualDelegate
|
|
@ -0,0 +1,104 @@
|
|||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { ProgramAccount, Governance } from '@solana/spl-governance'
|
||||
import {
|
||||
UiInstruction,
|
||||
DualFinanceDelegateWithdrawForm,
|
||||
} from '@utils/uiTypes/proposalCreationTypes'
|
||||
import { NewProposalContext } from '../../../new'
|
||||
import GovernedAccountSelect from '../../GovernedAccountSelect'
|
||||
import useGovernanceAssets from '@hooks/useGovernanceAssets'
|
||||
import Input from '@components/inputs/Input'
|
||||
import { getDelegateWithdrawInstruction } from '@utils/instructions/Dual/delegate'
|
||||
import { getDualFinanceDelegateWithdrawSchema } from '@utils/validations'
|
||||
import Tooltip from '@components/Tooltip'
|
||||
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
|
||||
import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'
|
||||
|
||||
const DualDelegateWithdraw = ({
|
||||
index,
|
||||
governance,
|
||||
}: {
|
||||
index: number
|
||||
governance: ProgramAccount<Governance> | null
|
||||
}) => {
|
||||
const [form, setForm] = useState<DualFinanceDelegateWithdrawForm>({
|
||||
realm: undefined,
|
||||
delegateToken: undefined,
|
||||
})
|
||||
const connection = useLegacyConnectionContext()
|
||||
const wallet = useWalletOnePointOh()
|
||||
const shouldBeGoverned = !!(index !== 0 && governance)
|
||||
const { assetAccounts } = useGovernanceAssets()
|
||||
const [governedAccount, setGovernedAccount] = useState<
|
||||
ProgramAccount<Governance> | undefined
|
||||
>(undefined)
|
||||
const [formErrors, setFormErrors] = useState({})
|
||||
const { handleSetInstructions } = useContext(NewProposalContext)
|
||||
const handleSetForm = ({ propertyName, value }) => {
|
||||
setFormErrors({})
|
||||
setForm({ ...form, [propertyName]: value })
|
||||
}
|
||||
const schema = getDualFinanceDelegateWithdrawSchema()
|
||||
useEffect(() => {
|
||||
function getInstruction(): Promise<UiInstruction> {
|
||||
return getDelegateWithdrawInstruction({
|
||||
connection,
|
||||
form,
|
||||
schema,
|
||||
setFormErrors,
|
||||
wallet,
|
||||
})
|
||||
}
|
||||
handleSetInstructions(
|
||||
{ governedAccount: governedAccount, getInstruction },
|
||||
index
|
||||
)
|
||||
}, [
|
||||
form,
|
||||
governedAccount,
|
||||
handleSetInstructions,
|
||||
index,
|
||||
connection,
|
||||
schema,
|
||||
wallet,
|
||||
])
|
||||
useEffect(() => {
|
||||
setGovernedAccount(form.delegateToken?.governance)
|
||||
}, [form.delegateToken?.governance])
|
||||
|
||||
// TODO: Include this in the config instruction which can optionally be done
|
||||
// if the project doesnt need to change where the tokens get returned to.
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
label="Realm"
|
||||
value={form.realm}
|
||||
type="text"
|
||||
onChange={(evt) =>
|
||||
handleSetForm({
|
||||
value: evt.target.value,
|
||||
propertyName: 'realm',
|
||||
})
|
||||
}
|
||||
error={formErrors['realm']}
|
||||
/>
|
||||
<Tooltip content="Token to be delegated.">
|
||||
<GovernedAccountSelect
|
||||
label="Delegate Token"
|
||||
governedAccounts={assetAccounts}
|
||||
onChange={(value) => {
|
||||
handleSetForm({ value, propertyName: 'delegateToken' })
|
||||
}}
|
||||
value={form.delegateToken}
|
||||
error={formErrors['delegateToken']}
|
||||
shouldBeGoverned={shouldBeGoverned}
|
||||
governance={governance}
|
||||
type="token"
|
||||
></GovernedAccountSelect>
|
||||
</Tooltip>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DualDelegateWithdraw
|
|
@ -0,0 +1,114 @@
|
|||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { ProgramAccount, Governance } from '@solana/spl-governance'
|
||||
import {
|
||||
UiInstruction,
|
||||
DualFinanceVoteDepositForm,
|
||||
} from '@utils/uiTypes/proposalCreationTypes'
|
||||
import { NewProposalContext } from '../../../new'
|
||||
import GovernedAccountSelect from '../../GovernedAccountSelect'
|
||||
import useGovernanceAssets from '@hooks/useGovernanceAssets'
|
||||
import Input from '@components/inputs/Input'
|
||||
import { getVoteDepositInstruction } from '@utils/instructions/Dual/delegate'
|
||||
import { getDualFinanceVoteDepositSchema } from '@utils/validations'
|
||||
import Tooltip from '@components/Tooltip'
|
||||
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
|
||||
import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'
|
||||
|
||||
const DualVoteDeposit = ({
|
||||
index,
|
||||
governance,
|
||||
}: {
|
||||
index: number
|
||||
governance: ProgramAccount<Governance> | null
|
||||
}) => {
|
||||
const [form, setForm] = useState<DualFinanceVoteDepositForm>({
|
||||
numTokens: 0,
|
||||
realm: undefined,
|
||||
delegateToken: undefined,
|
||||
})
|
||||
const connection = useLegacyConnectionContext()
|
||||
const wallet = useWalletOnePointOh()
|
||||
const shouldBeGoverned = !!(index !== 0 && governance)
|
||||
const { assetAccounts } = useGovernanceAssets()
|
||||
const [governedAccount, setGovernedAccount] = useState<
|
||||
ProgramAccount<Governance> | undefined
|
||||
>(undefined)
|
||||
const [formErrors, setFormErrors] = useState({})
|
||||
const { handleSetInstructions } = useContext(NewProposalContext)
|
||||
const handleSetForm = ({ propertyName, value }) => {
|
||||
setFormErrors({})
|
||||
setForm({ ...form, [propertyName]: value })
|
||||
}
|
||||
const schema = getDualFinanceVoteDepositSchema()
|
||||
useEffect(() => {
|
||||
function getInstruction(): Promise<UiInstruction> {
|
||||
return getVoteDepositInstruction({
|
||||
connection,
|
||||
form,
|
||||
schema,
|
||||
setFormErrors,
|
||||
wallet,
|
||||
})
|
||||
}
|
||||
handleSetInstructions(
|
||||
{ governedAccount: governedAccount, getInstruction },
|
||||
index
|
||||
)
|
||||
}, [form, governedAccount, handleSetInstructions, index, connection, schema, wallet])
|
||||
useEffect(() => {
|
||||
handleSetForm({ value: undefined, propertyName: 'mintPk' })
|
||||
}, [form.delegateToken])
|
||||
useEffect(() => {
|
||||
setGovernedAccount(form.delegateToken?.governance)
|
||||
}, [form.delegateToken])
|
||||
|
||||
// TODO: Include this in the config instruction which can optionally be done
|
||||
// if the project doesnt need to change where the tokens get returned to.
|
||||
return (
|
||||
<>
|
||||
<Tooltip content="How many option tokens are exercised staking options.">
|
||||
<Input
|
||||
label="Quantity"
|
||||
value={form.numTokens}
|
||||
type="number"
|
||||
onChange={(evt) =>
|
||||
handleSetForm({
|
||||
value: evt.target.value,
|
||||
propertyName: 'numTokens',
|
||||
})
|
||||
}
|
||||
error={formErrors['numTokens']}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Input
|
||||
label="Realm"
|
||||
value={form.realm}
|
||||
type="text"
|
||||
onChange={(evt) =>
|
||||
handleSetForm({
|
||||
value: evt.target.value,
|
||||
propertyName: 'realm',
|
||||
})
|
||||
}
|
||||
error={formErrors['realm']}
|
||||
/>
|
||||
<Tooltip content="Token to be delegated.">
|
||||
<GovernedAccountSelect
|
||||
label="Delegate Token"
|
||||
governedAccounts={assetAccounts}
|
||||
onChange={(value) => {
|
||||
handleSetForm({ value, propertyName: 'delegateToken' })
|
||||
}}
|
||||
value={form.delegateToken}
|
||||
error={formErrors['delegateToken']}
|
||||
shouldBeGoverned={shouldBeGoverned}
|
||||
governance={governance}
|
||||
type="token"
|
||||
></GovernedAccountSelect>
|
||||
</Tooltip>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DualVoteDeposit
|
|
@ -115,6 +115,9 @@ import RemoveServiceFromDID from './components/instructions/Identity/RemoveServi
|
|||
import DualAirdrop from './components/instructions/Dual/DualAirdrop'
|
||||
import DualWithdraw from './components/instructions/Dual/DualWithdraw'
|
||||
import DualExercise from './components/instructions/Dual/DualExercise'
|
||||
import DualDelegate from './components/instructions/Dual/DualDelegate'
|
||||
import DualDelegateWithdraw from './components/instructions/Dual/DualDelegateWithdraw'
|
||||
import DualVoteDeposit from './components/instructions/Dual/DualVoteDeposit'
|
||||
import PsyFinanceMintAmericanOptions from './components/instructions/PsyFinance/MintAmericanOptions'
|
||||
import IxGateSet from './components/instructions/Mango/MangoV4/IxGateSet'
|
||||
import StubOracleCreate from './components/instructions/Mango/MangoV4/StubOracleCreate'
|
||||
|
@ -422,6 +425,9 @@ const New = () => {
|
|||
[Instructions.DualFinanceLiquidityStakingOption]: LiquidityStakingOption,
|
||||
[Instructions.DualFinanceWithdraw]: DualWithdraw,
|
||||
[Instructions.DualFinanceExercise]: DualExercise,
|
||||
[Instructions.DualFinanceDelegate]: DualDelegate,
|
||||
[Instructions.DualFinanceDelegateWithdraw]: DualDelegateWithdraw,
|
||||
[Instructions.DualFinanceVoteDeposit]: DualVoteDeposit,
|
||||
[Instructions.MeanCreateAccount]: MeanCreateAccount,
|
||||
[Instructions.MeanFundAccount]: MeanFundAccount,
|
||||
[Instructions.MeanWithdrawFromAccount]: MeanWithdrawFromAccount,
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
import {
|
||||
TokenOwnerRecord,
|
||||
getGovernanceProgramVersion,
|
||||
getTokenOwnerRecordAddress,
|
||||
serializeInstructionToBase64,
|
||||
withCreateTokenOwnerRecord,
|
||||
withDepositGoverningTokens,
|
||||
withSetGovernanceDelegate,
|
||||
ProgramAccount,
|
||||
getTokenOwnerRecordForRealm,
|
||||
withWithdrawGoverningTokens,
|
||||
} from '@solana/spl-governance'
|
||||
import { ConnectionContext } from '@utils/connection'
|
||||
import { validateInstruction } from '@utils/instructionTools'
|
||||
import {
|
||||
DualFinanceVoteDepositForm,
|
||||
DualFinanceDelegateForm,
|
||||
UiInstruction,
|
||||
DualFinanceDelegateWithdrawForm,
|
||||
} from '@utils/uiTypes/proposalCreationTypes'
|
||||
import { WalletAdapter } from '@solana/wallet-adapter-base'
|
||||
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||
import { getMintNaturalAmountFromDecimalAsBN } from '@tools/sdk/units'
|
||||
|
||||
interface DelegateArgs {
|
||||
connection: ConnectionContext
|
||||
form: DualFinanceDelegateForm
|
||||
setFormErrors: any
|
||||
schema: any
|
||||
wallet: WalletAdapter | undefined
|
||||
}
|
||||
|
||||
interface DelegateWithdrawArgs {
|
||||
connection: ConnectionContext
|
||||
form: DualFinanceDelegateWithdrawForm
|
||||
setFormErrors: any
|
||||
schema: any
|
||||
wallet: WalletAdapter | undefined
|
||||
}
|
||||
|
||||
interface VoteDepositArgs {
|
||||
connection: ConnectionContext
|
||||
form: DualFinanceVoteDepositForm
|
||||
setFormErrors: any
|
||||
schema: any
|
||||
wallet: WalletAdapter | undefined
|
||||
}
|
||||
|
||||
export async function getDelegateInstruction({
|
||||
connection,
|
||||
wallet,
|
||||
form,
|
||||
schema,
|
||||
setFormErrors,
|
||||
}: DelegateArgs): Promise<UiInstruction> {
|
||||
const isValid = await validateInstruction({ schema, form, setFormErrors })
|
||||
const serializedInstruction = ''
|
||||
const additionalSerializedInstructions: string[] = []
|
||||
const prerequisiteInstructions: TransactionInstruction[] = []
|
||||
const instructions: TransactionInstruction[] = []
|
||||
if (
|
||||
isValid &&
|
||||
form.delegateAccount &&
|
||||
wallet?.publicKey &&
|
||||
form.realm &&
|
||||
form.delegateToken &&
|
||||
form.delegateToken.extensions.mint?.publicKey
|
||||
) {
|
||||
const programVersion = await getGovernanceProgramVersion(
|
||||
connection.current,
|
||||
form.delegateToken?.governance.owner // governance program public key
|
||||
)
|
||||
|
||||
await withSetGovernanceDelegate(
|
||||
instructions,
|
||||
form.delegateToken.governance.owner, // publicKey of program/programId
|
||||
programVersion, // program version of realm
|
||||
new PublicKey(form.realm), // realm public key
|
||||
form.delegateToken.extensions.mint.publicKey, // mint of governance token
|
||||
form.delegateToken.governance.nativeTreasuryAddress, // governingTokenOwner (walletId) publicKey of tokenOwnerRecord of this wallet
|
||||
form.delegateToken.governance.nativeTreasuryAddress, // governanceAuthority: publicKey of connected wallet
|
||||
new PublicKey(form.delegateAccount) // public key of wallet who to delegated vote to
|
||||
)
|
||||
for (const ix of instructions) {
|
||||
additionalSerializedInstructions.push(serializeInstructionToBase64(ix))
|
||||
}
|
||||
}
|
||||
return {
|
||||
serializedInstruction,
|
||||
isValid: true,
|
||||
prerequisiteInstructions: prerequisiteInstructions,
|
||||
governance: form.delegateToken?.governance,
|
||||
additionalSerializedInstructions,
|
||||
chunkBy: 1,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getVoteDepositInstruction({
|
||||
connection,
|
||||
wallet,
|
||||
form,
|
||||
schema,
|
||||
setFormErrors,
|
||||
}: VoteDepositArgs): Promise<UiInstruction> {
|
||||
const isValid = await validateInstruction({ schema, form, setFormErrors })
|
||||
|
||||
const serializedInstruction = ''
|
||||
const additionalSerializedInstructions: string[] = []
|
||||
const prerequisiteInstructions: TransactionInstruction[] = []
|
||||
const instructions: TransactionInstruction[] = []
|
||||
if (
|
||||
isValid &&
|
||||
form.numTokens &&
|
||||
wallet?.publicKey &&
|
||||
form.realm &&
|
||||
form.delegateToken &&
|
||||
form.delegateToken.extensions.mint?.publicKey
|
||||
) {
|
||||
const programVersion = await getGovernanceProgramVersion(
|
||||
connection.current,
|
||||
form.delegateToken.governance.owner // governance program public key
|
||||
)
|
||||
const tokenOwnerRecordAddress = await getTokenOwnerRecordAddress(
|
||||
form.delegateToken.governance.owner,
|
||||
new PublicKey(form.realm),
|
||||
form.delegateToken.extensions.mint.publicKey,
|
||||
form.delegateToken.governance.nativeTreasuryAddress
|
||||
)
|
||||
let existingTokenOwnerRecord: null | ProgramAccount<TokenOwnerRecord> = null
|
||||
try {
|
||||
existingTokenOwnerRecord = await getTokenOwnerRecordForRealm(
|
||||
connection.current,
|
||||
form.delegateToken.governance.owner,
|
||||
new PublicKey(form.realm),
|
||||
form.delegateToken.extensions.mint.publicKey,
|
||||
form.delegateToken.governance.nativeTreasuryAddress
|
||||
)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
console.log(existingTokenOwnerRecord)
|
||||
if (!existingTokenOwnerRecord) {
|
||||
console.log(
|
||||
'Creating new vote record',
|
||||
tokenOwnerRecordAddress.toBase58(),
|
||||
connection.current.rpcEndpoint
|
||||
)
|
||||
await withCreateTokenOwnerRecord(
|
||||
instructions,
|
||||
form.delegateToken.governance.owner,
|
||||
programVersion,
|
||||
new PublicKey(form.realm),
|
||||
form.delegateToken.governance.nativeTreasuryAddress,
|
||||
form.delegateToken.extensions.mint.publicKey,
|
||||
form.delegateToken.governance.nativeTreasuryAddress
|
||||
)
|
||||
}
|
||||
|
||||
await withDepositGoverningTokens(
|
||||
instructions,
|
||||
form.delegateToken.governance.owner, // publicKey of program/programId
|
||||
programVersion, // program version of realm
|
||||
new PublicKey(form.realm), // realm public key
|
||||
form.delegateToken.pubkey,
|
||||
form.delegateToken.extensions.mint.publicKey, // mint of governance token
|
||||
form.delegateToken.governance.nativeTreasuryAddress, // governingTokenOwner (walletId) publicKey of tokenOwnerRecord of this wallet
|
||||
form.delegateToken.governance.nativeTreasuryAddress, // governanceAuthority: publicKey of connected wallet
|
||||
form.delegateToken.governance.nativeTreasuryAddress,
|
||||
getMintNaturalAmountFromDecimalAsBN(
|
||||
form.numTokens,
|
||||
form.delegateToken.extensions.mint.account.decimals
|
||||
)
|
||||
)
|
||||
for (const ix of instructions) {
|
||||
additionalSerializedInstructions.push(serializeInstructionToBase64(ix))
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
serializedInstruction,
|
||||
isValid: true,
|
||||
prerequisiteInstructions: prerequisiteInstructions,
|
||||
governance: form.delegateToken?.governance,
|
||||
additionalSerializedInstructions,
|
||||
chunkBy: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove need for delegateToken
|
||||
// TODO: use a prequiste if community mint ata was burnt
|
||||
// TODO: Relinquish vote or finalize if delegate has active vote
|
||||
export async function getDelegateWithdrawInstruction({
|
||||
connection,
|
||||
wallet,
|
||||
form,
|
||||
schema,
|
||||
setFormErrors,
|
||||
}: DelegateWithdrawArgs): Promise<UiInstruction> {
|
||||
const isValid = await validateInstruction({ schema, form, setFormErrors })
|
||||
const serializedInstruction = ''
|
||||
const additionalSerializedInstructions: string[] = []
|
||||
const prerequisiteInstructions: TransactionInstruction[] = []
|
||||
const instructions: TransactionInstruction[] = []
|
||||
if (
|
||||
isValid &&
|
||||
wallet?.publicKey &&
|
||||
form.realm &&
|
||||
form.delegateToken &&
|
||||
form.delegateToken.extensions.mint?.publicKey
|
||||
) {
|
||||
const programVersion = await getGovernanceProgramVersion(
|
||||
connection.current,
|
||||
form.delegateToken?.governance.owner // governance program public key
|
||||
)
|
||||
|
||||
await withSetGovernanceDelegate(
|
||||
instructions,
|
||||
form.delegateToken.governance.owner, // publicKey of program/programId
|
||||
programVersion, // program version of realm
|
||||
new PublicKey(form.realm), // realm public key
|
||||
form.delegateToken.extensions.mint.publicKey, // mint of governance token
|
||||
form.delegateToken.governance.nativeTreasuryAddress, // governingTokenOwner (walletId) publicKey of tokenOwnerRecord of this wallet
|
||||
form.delegateToken.governance.nativeTreasuryAddress, // governanceAuthority: publicKey of connected wallet
|
||||
// @ts-ignore
|
||||
null // remove delegate
|
||||
)
|
||||
|
||||
await withWithdrawGoverningTokens(
|
||||
instructions,
|
||||
form.delegateToken.governance.owner, // publicKey of program/programId
|
||||
programVersion, // program version of realm
|
||||
new PublicKey(form.realm), // realm public key
|
||||
form.delegateToken.pubkey,
|
||||
form.delegateToken.extensions.mint.publicKey,
|
||||
form.delegateToken.governance.nativeTreasuryAddress,
|
||||
)
|
||||
for (const ix of instructions) {
|
||||
additionalSerializedInstructions.push(serializeInstructionToBase64(ix))
|
||||
}
|
||||
}
|
||||
return {
|
||||
serializedInstruction,
|
||||
isValid: true,
|
||||
prerequisiteInstructions: prerequisiteInstructions,
|
||||
governance: form.delegateToken?.governance,
|
||||
additionalSerializedInstructions,
|
||||
chunkBy: 1,
|
||||
}
|
||||
}
|
||||
|
|
@ -416,6 +416,9 @@ export enum Instructions {
|
|||
DualFinanceInitStrike,
|
||||
DualFinanceStakingOption,
|
||||
DualFinanceWithdraw,
|
||||
DualFinanceDelegate,
|
||||
DualFinanceDelegateWithdraw,
|
||||
DualFinanceVoteDeposit,
|
||||
EverlendDeposit,
|
||||
EverlendWithdraw,
|
||||
ForesightAddMarketListToCategory,
|
||||
|
@ -593,3 +596,20 @@ export interface DualFinanceWithdrawForm {
|
|||
baseTreasury: AssetAccount | undefined
|
||||
mintPk: string | undefined
|
||||
}
|
||||
|
||||
export interface DualFinanceDelegateForm {
|
||||
delegateAccount: string | undefined
|
||||
realm: string | undefined
|
||||
delegateToken: AssetAccount | undefined
|
||||
}
|
||||
|
||||
export interface DualFinanceDelegateWithdrawForm {
|
||||
realm: string | undefined
|
||||
delegateToken: AssetAccount | undefined
|
||||
}
|
||||
|
||||
export interface DualFinanceVoteDepositForm {
|
||||
numTokens: number
|
||||
realm: string | undefined
|
||||
delegateToken: AssetAccount | undefined
|
||||
}
|
||||
|
|
|
@ -684,6 +684,45 @@ export const getDualFinanceWithdrawSchema = () => {
|
|||
})
|
||||
}
|
||||
|
||||
export const getDualFinanceDelegateSchema = () => {
|
||||
return yup.object().shape({
|
||||
delegateAccount: yup
|
||||
.string()
|
||||
.test('is-valid-address1', 'Please enter a valid PublicKey', (value) =>
|
||||
value ? validatePubkey(value) : true
|
||||
),
|
||||
realm: yup
|
||||
.string()
|
||||
.test('is-valid-address1', 'Please enter a valid PublicKey', (value) =>
|
||||
value ? validatePubkey(value) : true
|
||||
),
|
||||
token: yup.object().typeError('Delegate Token is required'),
|
||||
})
|
||||
}
|
||||
|
||||
export const getDualFinanceDelegateWithdrawSchema = () => {
|
||||
return yup.object().shape({
|
||||
realm: yup
|
||||
.string()
|
||||
.test('is-valid-address1', 'Please enter a valid PublicKey', (value) =>
|
||||
value ? validatePubkey(value) : true
|
||||
),
|
||||
token: yup.object().typeError('Delegate Token is required'),
|
||||
})
|
||||
}
|
||||
|
||||
export const getDualFinanceVoteDepositSchema = () => {
|
||||
return yup.object().shape({
|
||||
numTokens: yup.number().typeError('Num tokens is required'),
|
||||
realm: yup
|
||||
.string()
|
||||
.test('is-valid-address1', 'Please enter a valid PublicKey', (value) =>
|
||||
value ? validatePubkey(value) : true
|
||||
),
|
||||
token: yup.object().typeError('Delegate Token is required'),
|
||||
})
|
||||
}
|
||||
|
||||
export const getGoblinGoldDepositSchema = ({ form }) => {
|
||||
const governedTokenAccount = form.governedTokenAccount as AssetAccount
|
||||
return yup.object().shape({
|
||||
|
|
Loading…
Reference in New Issue