Skip to main content

Voting System

The Savitri governance voting system enables token-weighted on-chain decision making.

Vote Types

TypeMeaning
YesSupport the proposal
NoOppose the proposal
AbstainCounted for quorum but not approval

Proposal Lifecycle

Creation (+ deposit)

Review Period (24 hours)
│ Pending state, no voting allowed

Voting Period (7 days default)
│ ActiveVoting state

Tally
├── Quorum met + Approval met → Approved
├── Quorum met + Approval not met → Rejected
└── Quorum not met → Rejected (insufficient participation)


Execution (if Approved)

Quorum and Approval

ThresholdValueDescription
Quorum10%Of total vote tokens must participate
Approval65%Of Yes votes (excluding Abstain)

Calculation

total_votes = yes_votes + no_votes + abstain_votes
quorum_met = total_votes >= (total_vote_supply * 0.10)
approval = yes_votes / (yes_votes + no_votes) >= 0.65

Abstain votes count toward quorum but not toward approval calculation.

Vote Token Locking

When a user casts a vote, their vote tokens are locked for the duration of the voting period. This prevents:

  • Double voting (voting with same tokens on multiple proposals)
  • Token transfer to vote again from a different address

Tokens are unlocked after the voting period ends.

Deposit Mechanism

Proposal creation requires a deposit (anti-spam):

  • Deposit returned if proposal reaches quorum (regardless of outcome)
  • Deposit slashed if proposal fails to reach quorum

Proposal Actions

ActionDescription
SetParameterChange network parameters
TransferTreasuryTransfer treasury funds
UpgradeContractUpgrade a smart contract
SetFlPolicyUpdate FL training parameters
ApproveFlModelApprove FL model for production
AbortFlRoundEmergency abort FL training round
SlashValidatorSlash a misbehaving validator
CustomCustom governance action

Voting Results

pub struct VotingResult {
pub yes_votes: u64,
pub no_votes: u64,
pub abstain_votes: u64,
pub total_eligible: u64,
pub quorum_reached: bool,
pub approved: bool,
pub participation_rate: f64,
}

Vote Token Distribution

Vote tokens are earned through node participation:

PoU TierScore RangeVote Tokens / Epoch
Bronze300-49910
Silver500-69925
Gold700-89950
Platinum900-1000100

Via SDK

Cast a Vote

use savitri_sdk::{ContractClient, Wallet};

let contract = ContractClient::from_url_and_wallet(url, wallet)?;
let gov = contract.governance();

// Vote YES on proposal #42
let tx = gov.vote(&governance_address, 42, true).await?;

// Vote NO
let tx = gov.vote(&governance_address, 42, false).await?;

Check Proposal Status

let status = gov.get_proposal_status(&governance_address, 42).await?;
println!("Votes: {} for / {} against", status.votes_for, status.votes_against);
println!("Status: {} (executed: {})", status.status, status.executed);

Execute Approved Proposal

Any participant can trigger execution of an approved proposal:

let tx = gov.execute(&governance_address, 42).await?;

Storage

Column FamilyKeyValue
CF_GOVERNANCEproposal_id (u64 LE)Proposal (bincode)
CF_VOTE_TOKENSaddress (32 bytes)Vote token balance

Timeline

PhaseDurationState
Review24 hoursPending
Voting7 days (configurable)ActiveVoting
ExecutionImmediate after tallyApprovedExecuted