use crate::primitives::{Address, Timestamp};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct GovernanceVote {
pub vote_id: String,
pub proposal_id: String,
pub voter: Address,
pub vote_type: VoteType,
pub voting_power: u128,
pub voted_at: Timestamp,
pub justification: Option<String>,
}
impl GovernanceVote {
pub fn new(
proposal_id: String,
voter: Address,
vote_type: VoteType,
voting_power: u128,
) -> Self {
Self {
vote_id: uuid::Uuid::new_v4().to_string(),
proposal_id,
voter,
vote_type,
voting_power,
voted_at: Timestamp::now(),
justification: None,
}
}
pub fn with_justification(mut self, justification: String) -> Self {
self.justification = Some(justification);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum VoteType {
For,
Against,
Abstain,
}
impl VoteType {
pub fn is_for(&self) -> bool {
matches!(self, Self::For)
}
pub fn is_against(&self) -> bool {
matches!(self, Self::Against)
}
pub fn is_abstain(&self) -> bool {
matches!(self, Self::Abstain)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct VotingDelegation {
pub delegator: Address,
pub delegate: Address,
pub voting_power: u128,
pub delegated_at: Timestamp,
pub expires_at: Option<Timestamp>,
pub status: DelegationStatus,
}
impl VotingDelegation {
pub fn new(delegator: Address, delegate: Address, voting_power: u128) -> Self {
Self {
delegator,
delegate,
voting_power,
delegated_at: Timestamp::now(),
expires_at: None,
status: DelegationStatus::Active,
}
}
pub fn with_expiration(mut self, expires_at: Timestamp) -> Self {
self.expires_at = Some(expires_at);
self
}
pub fn is_active(&self) -> bool {
if self.status != DelegationStatus::Active {
return false;
}
if let Some(expires_at) = self.expires_at {
Timestamp::now() < expires_at
} else {
true
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DelegationStatus {
Active,
Revoked,
Expired,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct QuorumRequirements {
pub minimum_participation_bps: u32,
pub minimum_approval_bps: u32,
pub minimum_votes: u128,
}
impl Default for QuorumRequirements {
fn default() -> Self {
Self {
minimum_participation_bps: 2000, minimum_approval_bps: 5000, minimum_votes: 1000u128.saturating_mul(10u128.saturating_pow(18)), }
}
}
impl QuorumRequirements {
pub fn is_met(&self, votes_for: u128, votes_against: u128, total_supply: u128) -> bool {
let total_votes = votes_for.saturating_add(votes_against);
if total_votes < self.minimum_votes {
return false;
}
let participation = (total_votes as f64 / total_supply as f64) * 10000.0;
if (participation as u32) < self.minimum_participation_bps {
return false;
}
let approval = (votes_for as f64 / total_votes as f64) * 10000.0;
(approval as u32) >= self.minimum_approval_bps
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct VoterInfo {
pub address: Address,
pub direct_voting_power: u128,
pub delegated_voting_power: u128,
pub total_votes_cast: u64,
pub participation_rate: u32,
}
impl VoterInfo {
pub fn new(address: Address, voting_power: u128) -> Self {
Self {
address,
direct_voting_power: voting_power,
delegated_voting_power: 0,
total_votes_cast: 0,
participation_rate: 0,
}
}
pub fn total_voting_power(&self) -> u128 {
self.direct_voting_power
.saturating_add(self.delegated_voting_power)
}
pub fn record_vote(&mut self) {
self.total_votes_cast += 1;
}
}