Skip to Content

Cast Vote

Cast a stake-weighted vote on an active governance proposal.

Description

Votes are allocated using basis points (bp) where 10,000 bp = 100% of the validator’s stake. You distribute your stake across three positions: For, Against, and Abstain — and the three values must add up to exactly 10,000.

The program verifies your stake weight on-chain by reading a MetaMerkleProof PDA and calling the NCN verify_merkle_proof instruction. You do not need to supply the proof manually — the CLI fetches it from the operator API.

Usage

svmgov cast-vote \ --proposal-id "ABC123..." \ --for-votes 7000 \ --against-votes 2000 \ --abstain-votes 1000 \ --network mainnet

Arguments

ArgumentTypeRequiredDescription
--proposal-idStringYesProposal PDA address (base58)
--for-votesu64YesBasis points allocated to For (0–10,000)
--against-votesu64YesBasis points allocated to Against (0–10,000)
--abstain-votesu64YesBasis points allocated to Abstain (0–10,000)
--networkStringNoNetwork override: mainnet, testnet
--close-timestampi64NoUnix timestamp after which the MetaMerkleProof PDA can be closed permissionlessly. Defaults to the proposal’s vote-expiry time

Global Arguments

OptionShortDescription
--keypair <PATH>-kPath to validator identity keypair JSON
--rpc-url <URL>-rCustom RPC URL

Requirements

  • Proposal must be in voting phase (proposal.voting == true)
  • Current epoch must be within [start_epoch, end_epoch]
  • for_votes + against_votes + abstain_votes must equal exactly 10,000
  • NCN operators must have finalized the ConsensusResult for this proposal’s snapshot

Basis Points Reference

Basis PointsPercentageExample (100 SOL stake)
10,000100%100 SOL
7,00070%70 SOL
5,00050%50 SOL
1,00010%10 SOL
00%0 SOL

Examples

# 70% For, 20% Against, 10% Abstain svmgov cast-vote \ --proposal-id "AbCdEf..." \ --for-votes 7000 \ --against-votes 2000 \ --abstain-votes 1000 \ --network mainnet # 100% For svmgov cast-vote \ --proposal-id "AbCdEf..." \ --for-votes 10000 \ --against-votes 0 \ --abstain-votes 0 \ --network mainnet # 100% Against — explicit RPC svmgov cast-vote \ --proposal-id "AbCdEf..." \ --for-votes 0 \ --against-votes 10000 \ --abstain-votes 0 \ --network mainnet \ --rpc-url https://api.mainnet-beta.solana.com

What Happens On-Chain

  1. CLI fetches your MetaMerkleProof from the operator API (/proof/vote_account/:vote_account)
  2. CLI stores the proof in a temporary on-chain MetaMerkleProof PDA, setting its close_timestamp to the proposal’s vote-expiry time (or the --close-timestamp override) so the rent-bearing account can be reclaimed permissionlessly once voting ends
  3. cast_vote instruction:
    • Reads the MetaMerkleProof PDA
    • CPIs to ncn-snapshot::verify_merkle_proof to confirm your stake weight
    • If delegators have already overridden your vote via VoteOverrideCache, their portion is subtracted
    • Records your Vote PDA with lamport amounts
  4. proposal.for_votes_lamports / against_votes_lamports / abstain_votes_lamports are updated

If delegators have pre-submitted vote overrides before you vote, their stake is automatically subtracted from your effective vote weight when you call cast_vote.

You normally don’t need --close-timestamp. The CLI defaults it to the proposal’s vote-expiry time (the start of end_epoch), so the MetaMerkleProof PDA stays protected during voting and only becomes permissionlessly closeable afterward. Pass an explicit Unix timestamp only if you want different close semantics. The value is an estimate derived from the current epoch and slot timing.

Last updated on