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 mainnetArguments
| Argument | Type | Required | Description |
|---|---|---|---|
--proposal-id | String | Yes | Proposal PDA address (base58) |
--for-votes | u64 | Yes | Basis points allocated to For (0–10,000) |
--against-votes | u64 | Yes | Basis points allocated to Against (0–10,000) |
--abstain-votes | u64 | Yes | Basis points allocated to Abstain (0–10,000) |
--network | String | No | Network override: mainnet, testnet |
--close-timestamp | i64 | No | Unix timestamp after which the MetaMerkleProof PDA can be closed permissionlessly. Defaults to the proposal’s vote-expiry time |
Global Arguments
| Option | Short | Description |
|---|---|---|
--keypair <PATH> | -k | Path to validator identity keypair JSON |
--rpc-url <URL> | -r | Custom 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_votesmust equal exactly 10,000- NCN operators must have finalized the
ConsensusResultfor this proposal’s snapshot
Basis Points Reference
| Basis Points | Percentage | Example (100 SOL stake) |
|---|---|---|
10,000 | 100% | 100 SOL |
7,000 | 70% | 70 SOL |
5,000 | 50% | 50 SOL |
1,000 | 10% | 10 SOL |
0 | 0% | 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.comWhat Happens On-Chain
- CLI fetches your
MetaMerkleProoffrom the operator API (/proof/vote_account/:vote_account) - CLI stores the proof in a temporary on-chain
MetaMerkleProofPDA, setting itsclose_timestampto the proposal’s vote-expiry time (or the--close-timestampoverride) so the rent-bearing account can be reclaimed permissionlessly once voting ends cast_voteinstruction:- Reads the
MetaMerkleProofPDA - CPIs to
ncn-snapshot::verify_merkle_proofto confirm your stake weight - If delegators have already overridden your vote via
VoteOverrideCache, their portion is subtracted - Records your
VotePDA with lamport amounts
- Reads the
proposal.for_votes_lamports / against_votes_lamports / abstain_votes_lamportsare 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.
Related
- Modify Vote — Change your vote during the voting phase
- Finalize Proposal — Lock results after voting ends