Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #51

Merged
merged 33 commits into from
Nov 16, 2023
Merged

fix #51

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c853106
always show deposit options in vanilla
asktree Nov 8, 2023
f441c69
Merge pull request #1911 from solana-labs:agrippa/fix-no-gov-power-bug
asktree Nov 8, 2023
c2e354f
silent fail out of non critical function (#1910)
asktree Nov 8, 2023
2b6bff5
fix issue where CastNftVote and CastVote must share tx (#1909)
asktree Nov 8, 2023
c1ed6a6
Delegator rework for vanilla + ux adjustment (#1912)
asktree Nov 9, 2023
eebc0a7
show current bank values in token edit (#1914)
abrzezinski94 Nov 11, 2023
5ffea9d
mango v4 create deposit delegate tweak (#1915)
abrzezinski94 Nov 11, 2023
25a8642
blaze aux account for mango dao (#1917)
abrzezinski94 Nov 13, 2023
c0ae63d
update mango season prefix (#1919)
abrzezinski94 Nov 13, 2023
a6bb595
[bugfix] just use realm pks when talking to governance-api (#1921)
asktree Nov 14, 2023
9447152
update mango settings lib (#1923)
abrzezinski94 Nov 15, 2023
3b8b7e6
Add missing smart wallet (PDA wallet) support (#1922)
valentinmadrid Nov 15, 2023
edeaa94
skip delegator votes if already voted (#1920)
asktree Nov 15, 2023
e7057ea
Progress
guibescos Nov 10, 2023
a184166
Progress
guibescos Nov 10, 2023
f341deb
WIll need this imo
guibescos Nov 10, 2023
6382250
Add constant
guibescos Nov 10, 2023
5731d52
Add yarn
guibescos Nov 10, 2023
60351c0
Add client
guibescos Nov 10, 2023
88721b3
This works
guibescos Nov 12, 2023
13217e7
Cleanup
guibescos Nov 12, 2023
dcd0075
correct yarn lock
guibescos Nov 12, 2023
a63209c
Fix bug
guibescos Nov 12, 2023
5ea711b
Another bug
guibescos Nov 12, 2023
dcef8f4
Mainnet addresses
guibescos Nov 13, 2023
a1db6a4
regen yarn.lock
cctdaniel Nov 16, 2023
ef25a26
fix
cctdaniel Nov 16, 2023
dd42dbe
Merge branch 'main' into fix
cctdaniel Nov 16, 2023
8fb4204
fix
cctdaniel Nov 16, 2023
db68013
add yarn.lock
cctdaniel Nov 16, 2023
8ef9bea
Update yarn lock
guibescos Nov 16, 2023
9f832fe
Fix 2
guibescos Nov 16, 2023
9756304
New banner
guibescos Nov 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ yarn-error.log*

# Sentry
.sentryclirc

.vscode/settings.json
12 changes: 0 additions & 12 deletions .vscode/settings.json

This file was deleted.

205 changes: 176 additions & 29 deletions actions/castVote.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Connection,
Keypair,
PublicKey,
Transaction,
TransactionInstruction,
} from '@solana/web3.js'
import {
Expand All @@ -14,6 +14,8 @@ import {
VoteKind,
VoteType,
withPostChatMessage,
withCreateTokenOwnerRecord,
getVoteRecordAddress,
} from '@solana/spl-governance'
import { ProgramAccount } from '@solana/spl-governance'
import { RpcContext } from '@solana/spl-governance'
Expand All @@ -28,12 +30,17 @@ import {
SequenceType,
txBatchesToInstructionSetWithSigners,
} from '@utils/sendTransactions'
import { sendTransaction } from '@utils/send'
import { calcCostOfNftVote, checkHasEnoughSolToVote } from '@tools/nftVoteCalc'
import useNftProposalStore from 'NftVotePlugin/NftProposalStore'
import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client'
import { NftVoterClient } from '@utils/uiTypes/NftVoterClient'
import { fetchRealmByPubkey } from '@hooks/queries/realm'
import { fetchProposalByPubkeyQuery } from '@hooks/queries/proposal'
import { findPluginName } from '@hooks/queries/governancePower'
import { DELEGATOR_BATCH_VOTE_SUPPORT_BY_PLUGIN } from '@constants/flags'
import { fetchTokenOwnerRecordByPubkey } from '@hooks/queries/tokenOwnerRecord'
import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery'
import { fetchVoteRecordByPubkey } from '@hooks/queries/voteRecord'

const getVetoTokenMint = (
proposal: ProgramAccount<Proposal>,
Expand All @@ -50,6 +57,86 @@ const getVetoTokenMint = (
return vetoTokenMint
}

const createDelegatorVote = async ({
connection,
realmPk,
proposalPk,
tokenOwnerRecordPk,
userPk,
vote,
}: {
connection: Connection
realmPk: PublicKey
proposalPk: PublicKey
tokenOwnerRecordPk: PublicKey
userPk: PublicKey
vote: Vote
}) => {
//
const realm = (await fetchRealmByPubkey(connection, realmPk)).result
if (!realm) throw new Error()
const proposal = (await fetchProposalByPubkeyQuery(connection, proposalPk))
.result
if (!proposal) throw new Error()

const programVersion = await fetchProgramVersion(connection, realm.owner)

const castVoteIxs: TransactionInstruction[] = []
await withCastVote(
castVoteIxs,
realm.owner,
programVersion,
realm.pubkey,
proposal.account.governance,
proposal.pubkey,
proposal.account.tokenOwnerRecord,
tokenOwnerRecordPk,
userPk,
proposal.account.governingTokenMint,
vote,
userPk
//plugin?.voterWeightPk,
//plugin?.maxVoterWeightRecord
)
return castVoteIxs
}

const createTokenOwnerRecordIfNeeded = async ({
connection,
realmPk,
tokenOwnerRecordPk,
payer,
governingTokenMint,
}: {
connection: Connection
realmPk: PublicKey
tokenOwnerRecordPk: PublicKey
payer: PublicKey
governingTokenMint: PublicKey
}) => {
const realm = await fetchRealmByPubkey(connection, realmPk)
if (!realm.result) throw new Error()
const version = await fetchProgramVersion(connection, realm.result.owner)

const tokenOwnerRecord = await fetchTokenOwnerRecordByPubkey(
connection,
tokenOwnerRecordPk
)
if (tokenOwnerRecord.result) return []
// create token owner record
const ixs: TransactionInstruction[] = []
await withCreateTokenOwnerRecord(
ixs,
realm.result.owner,
version,
realmPk,
payer,
governingTokenMint,
payer
)
return ixs
}

export async function castVote(
{ connection, wallet, programId, walletPubkey }: RpcContext,
realm: ProgramAccount<Realm>,
Expand All @@ -60,9 +147,9 @@ export async function castVote(
votingPlugin?: VotingClient,
runAfterConfirmation?: (() => void) | null,
voteWeights?: number[],
_additionalTokenOwnerRecords?: []
additionalTokenOwnerRecords?: PublicKey[]
) {
const signers: Keypair[] = []
const chatMessageSigners: Keypair[] = []

const createCastNftVoteTicketIxs: TransactionInstruction[] = []
const createPostMessageTicketIxs: TransactionInstruction[] = []
Expand All @@ -81,7 +168,6 @@ export async function castVote(
tokenOwnerRecord,
createCastNftVoteTicketIxs
)
console.log('PLUGIN IXS', pluginCastVoteIxs)

const isMulti =
proposal.account.voteType !== VoteType.SINGLE_CHOICE &&
Expand Down Expand Up @@ -153,6 +239,39 @@ export async function castVote(
plugin?.maxVoterWeightRecord
)

const delegatorCastVoteAtoms =
additionalTokenOwnerRecords &&
DELEGATOR_BATCH_VOTE_SUPPORT_BY_PLUGIN[
findPluginName(votingPlugin?.client?.program.programId)
]
? (
await Promise.all(
additionalTokenOwnerRecords.map(async (tokenOwnerRecordPk) => {
// Skip vote if already voted
const voteRecordPk = await getVoteRecordAddress(
realm.owner,
proposal.pubkey,
tokenOwnerRecordPk
)
const voteRecord = await fetchVoteRecordByPubkey(
connection,
voteRecordPk
)
if (voteRecord.found) return undefined

return createDelegatorVote({
connection,
realmPk: realm.pubkey,
proposalPk: proposal.pubkey,
tokenOwnerRecordPk,
userPk: walletPubkey,
vote,
})
})
)
).filter((x): x is NonNullable<typeof x> => x !== undefined)
: []

const pluginPostMessageIxs: TransactionInstruction[] = []
const postMessageIxs: TransactionInstruction[] = []
if (message) {
Expand All @@ -165,7 +284,7 @@ export async function castVote(

await withPostChatMessage(
postMessageIxs,
signers,
chatMessageSigners,
GOVERNANCE_CHAT_PROGRAM_ID,
programId,
realm.pubkey,
Expand All @@ -182,22 +301,48 @@ export async function castVote(

const isNftVoter = votingPlugin?.client instanceof NftVoterClient
const isHeliumVoter = votingPlugin?.client instanceof HeliumVsrClient
const tokenOwnerRecordIxs = await createTokenOwnerRecordIfNeeded({
connection,
realmPk: realm.pubkey,
tokenOwnerRecordPk: tokenOwnerRecord,
payer,
governingTokenMint: tokenMint,
})

if (!isNftVoter && !isHeliumVoter) {
const transaction = new Transaction()
transaction.add(
...[
...pluginCastVoteIxs,
...castVoteIxs,
...pluginPostMessageIxs,
...postMessageIxs,
]
const batch1 = [
...tokenOwnerRecordIxs,
...pluginCastVoteIxs,
...castVoteIxs,
...pluginPostMessageIxs,
...postMessageIxs,
]
// chunk size chosen conservatively. "Atoms" refers to atomic clusters of instructions (namely, updatevoterweight? + vote)
const delegatorBatches = chunks(delegatorCastVoteAtoms, 2).map((x) =>
x.flat()
)
const actions = [batch1, ...delegatorBatches].map((ixs) => ({
instructionsSet: ixs.map((ix) => ({
transactionInstruction: ix,
signers: chatMessageSigners.filter((kp) =>
ix.keys.find((key) => key.isSigner && key.pubkey.equals(kp.publicKey))
),
})),
sequenceType: SequenceType.Parallel,
}))

await sendTransaction({ transaction, wallet, connection, signers })
if (runAfterConfirmation) {
runAfterConfirmation()
}
await sendTransactionsV3({
connection,
wallet,
transactionInstructions: actions,
callbacks: {
afterAllTxConfirmed: () => {
if (runAfterConfirmation) {
runAfterConfirmation()
}
},
},
})
}

// we need to chunk instructions
Expand All @@ -217,7 +362,7 @@ export async function castVote(
return {
instructionsSet: txBatchesToInstructionSetWithSigners(
txBatch,
message ? [[], signers] : [],
message ? [[], chatMessageSigners] : [], // seeing signer related bugs when posting chat? This is likely culprit
batchIdx
),
sequenceType: SequenceType.Sequential,
Expand Down Expand Up @@ -249,16 +394,18 @@ export async function castVote(
[...createCastNftVoteTicketIxs, ...createPostMessageTicketIxs],
1
)
const otherChunks = chunks(
[
...pluginCastVoteIxs,
...castVoteIxs,
...pluginPostMessageIxs,
...postMessageIxs,
],
2

// last element of pluginCastVoteIxs
const last = pluginCastVoteIxs[pluginCastVoteIxs.length - 1]
// everything except last element of pluginCastVoteIxs
const nftCountingChunks = pluginCastVoteIxs.slice(0, -1)
const voteChunk = [last, ...castVoteIxs] // the final nft-voter.CastNftVote instruction has to in same tx as the vote
const chunkedIxs = [...chunks(nftCountingChunks, 2), voteChunk].filter(
(x) => x.length > 0
)

// note that we are not chunking postMessageIxs, not yet supported (somehow)

const instructionsChunks = [
...createNftVoteTicketsChunks.map((txBatch, batchIdx) => {
return {
Expand All @@ -270,11 +417,11 @@ export async function castVote(
sequenceType: SequenceType.Parallel,
}
}),
...otherChunks.map((txBatch, batchIdx) => {
...chunkedIxs.map((txBatch, batchIdx) => {
return {
instructionsSet: txBatchesToInstructionSetWithSigners(
txBatch,
message ? [[], signers] : [],
message ? [[], chatMessageSigners] : [], // seeing signer related bugs when posting chat? This is likely culprit
batchIdx
),
sequenceType: SequenceType.Sequential,
Expand Down
24 changes: 14 additions & 10 deletions components/GovernancePower/GovernancePowerCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ const GovernancePowerTitle = () => {
</div>
)
}
/*
// TODO: refactor deposit components to their own generic DepositForRole component
const VanillaDeposit = ({ role }: { role: 'community' | 'council' }) => {
const { connection } = useConnection()

const realmPk = useSelectedRealmPubkey()

const { result: kind } = useAsync(async () => {
if (realmPk === undefined) return undefined
return determineVotingPowerType(connection, realmPk, role)
}, [connection, realmPk, role])

return kind === 'vanilla' ? <Deposit role={role} /> : <></>
} */

const GovernancePowerCard = () => {
const connected = useWalletOnePointOh()?.connected ?? false
Expand All @@ -38,12 +52,6 @@ const GovernancePowerCard = () => {

const bothLoading = communityPower.loading && councilPower.loading

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

const realmConfig = useRealmConfigQuery().data?.result

return (
Expand All @@ -58,10 +66,6 @@ const GovernancePowerCard = () => {
<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">
{realmConfig?.account.communityTokenConfig.tokenType ===
Expand Down
Loading
Loading