Proposals
Understand the complete lifecycle of governance proposals in CredDAO.
Proposal Types
| Type | Description | Tier Required | Time-Lock |
|---|---|---|---|
| Standard | Regular governance decisions | Gold+ | Per tier |
| Expedited | Time-sensitive matters | Platinum | 24 hours |
| Emergency | Critical situations | Platinum + badges | 24 hours |
Proposal States
| State | Description |
|---|---|
| Draft | Initial state (reserved for future use) |
| Voting | Active voting period |
| Succeeded | Passed voting, awaiting time-lock |
| Defeated | Failed to pass |
| Executed | Successfully executed on-chain |
| Cancelled | Cancelled by proposer |
Proposal Account Structure
#[account]
pub struct ProposalAccount {
pub dao_config: Pubkey, // Reference to DAO config
pub proposer: Pubkey, // Proposal creator
pub proposal_type: ProposalType,
pub state: ProposalState,
pub for_votes: u64, // Total votes for
pub against_votes: u64, // Total votes against
pub abstain_votes: u64, // Abstain votes
pub voting_start: i64, // Unix timestamp
pub voting_end: i64, // Voting deadline
pub time_lock_expiry: i64, // Execution available after
pub quorum_required: u64, // Minimum participation
pub total_voting_power: u64, // Total power at creation
pub executed_at: Option<i64>, // Execution timestamp
pub bump: u8,
}Creating Proposals
Requirements
Standard
- Gold or Platinum tier
- 30+ active days
- Sufficient SOL for rent
Expedited
- Platinum tier only
- 30+ active days
- Sufficient SOL for rent
Emergency
- Platinum tier
- Required badge count
- 30+ active days
- DAO authority approval (optional)
SDK Example
const proposal = await client.createProposal({
proposalType: ProposalType.Standard,
title: 'Treasury Allocation',
description: 'Allocate funds for development...',
});Voting on Proposals
Vote Types
enum VoteType {
For = 0,
Against = 1,
Abstain = 2,
}Voting Power
Your voting power is locked at the time of voting:
// In cast_vote
let voting_power = calculate_voting_power(voter.delegated_power, voter.fairscore);
vote_record.voting_power = voting_power;
vote_record.fairscore_at_vote = voter.fairscore;Note:
Your FairScore at the time of voting is recorded. This prevents last-minute score manipulation.
Quorum Requirements
Proposals require minimum participation:
let total_votes = proposal.for_votes + proposal.against_votes + proposal.abstain_votes;
let quorum_reached = total_votes >= proposal.quorum_required;Quorum is calculated as:
quorumRequired = totalVotingPower × quorumPercentage / 100Finalization
After voting ends, anyone can finalize:
pub fn finalize_proposal(ctx: Context<FinalizeProposal>) -> Result<()> {
require!(
clock.unix_timestamp >= proposal.voting_end,
CredDAOError::ProposalVotingActive
);
let total_votes = proposal.for_votes + proposal.against_votes + proposal.abstain_votes;
if total_votes < proposal.quorum_required {
proposal.state = ProposalState::Defeated;
} else {
proposal.state = if proposal.for_votes > proposal.against_votes {
ProposalState::Succeeded
} else {
ProposalState::Defeated
};
}
}Execution
After time-lock expires:
await client.executeProposal(proposalAddress);Requirements:
- Proposal state is Succeeded
- Current time >= time_lock_expiry
Events
ProposalCreated {
proposal: Pubkey,
proposer: Pubkey,
proposal_type: ProposalType,
voting_end: i64,
time_lock_expiry: i64,
}
VoteCast {
proposal: Pubkey,
voter: Pubkey,
vote: u8,
voting_power: u64,
fairscore: u64,
}
ProposalFinalized {
proposal: Pubkey,
state: ProposalState,
for_votes: u64,
against_votes: u64,
}
ProposalExecuted {
proposal: Pubkey,
executed_at: i64,
}