Token Governance System
Introduction
Token governance systems enable decentralized decision-making in blockchain projects. This tutorial explains how to implement a comprehensive governance system using smart contracts.
Features
- Proposal creation and voting
- Token-weighted voting power
- Time-locked execution
- Delegation mechanism
- Vote tracking and history
Contract Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract GovernanceToken is ERC20, Ownable {
constructor(string memory name, string memory symbol)
ERC20(name, symbol) {}
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}
}
contract Governance is ReentrancyGuard {
using SafeMath for uint256;
// Governance token
GovernanceToken public token;
// Proposal struct
struct Proposal {
uint256 id;
address proposer;
string description;
uint256 startBlock;
uint256 endBlock;
uint256 forVotes;
uint256 againstVotes;
bool executed;
mapping(address => Receipt) receipts;
}
// Vote receipt
struct Receipt {
bool hasVoted;
bool support;
uint256 votes;
}
// Voting parameters
uint256 public votingDelay = 1; // blocks before voting starts
uint256 public votingPeriod = 17280; // blocks for voting (approximately 3 days)
uint256 public proposalThreshold; // minimum tokens to create proposal
uint256 public quorumVotes; // minimum votes for proposal to pass
// Proposal tracking
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
// Events
event ProposalCreated(uint256 id, address proposer, string description);
event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);
event ProposalExecuted(uint256 id);
constructor(
address _token,
uint256 _proposalThreshold,
uint256 _quorumVotes
) {
token = GovernanceToken(_token);
proposalThreshold = _proposalThreshold;
quorumVotes = _quorumVotes;
}
// Create a proposal
function propose(string memory description) external returns (uint256) {
require(
token.balanceOf(msg.sender) >= proposalThreshold,
"Insufficient tokens to propose"
);
uint256 startBlock = block.number.add(votingDelay);
uint256 endBlock = startBlock.add(votingPeriod);
proposalCount++;
Proposal storage proposal = proposals[proposalCount];
proposal.id = proposalCount;
proposal.proposer = msg.sender;
proposal.description = description;
proposal.startBlock = startBlock;
proposal.endBlock = endBlock;
emit ProposalCreated(proposalCount, msg.sender, description);
return proposalCount;
}
// Cast a vote
function castVote(uint256 proposalId, bool support) external {
require(state(proposalId) == ProposalState.Active, "Voting is closed");
Proposal storage proposal = proposals[proposalId];
Receipt storage receipt = proposal.receipts[msg.sender];
require(!receipt.hasVoted, "Already voted");
uint256 votes = token.balanceOf(msg.sender);
require(votes > 0, "No voting power");
if (support) {
proposal.forVotes = proposal.forVotes.add(votes);
} else {
proposal.againstVotes = proposal.againstVotes.add(votes);
}
receipt.hasVoted = true;
receipt.support = support;
receipt.votes = votes;
emit VoteCast(msg.sender, proposalId, support, votes);
}
// Execute a proposal
function execute(uint256 proposalId) external {
require(state(proposalId) == ProposalState.Succeeded, "Proposal not passed");
Proposal storage proposal = proposals[proposalId];
proposal.executed = true;
emit ProposalExecuted(proposalId);
// Execute proposal actions
}
// Get proposal state
function state(uint256 proposalId) public view returns (ProposalState) {
require(proposalId <= proposalCount && proposalId > 0, "Invalid proposal");
Proposal storage proposal = proposals[proposalId];
if (proposal.executed) {
return ProposalState.Executed;
}
if (block.number <= proposal.startBlock) {
return ProposalState.Pending;
}
if (block.number <= proposal.endBlock) {
return ProposalState.Active;
}
if (proposal.forVotes <= proposal.againstVotes ||
proposal.forVotes < quorumVotes) {
return ProposalState.Defeated;
}
return ProposalState.Succeeded;
}
// Get voting power at a specific block
function getVotes(address account, uint256 blockNumber)
public view returns (uint256)
{
return token.balanceOf(account);
}
}
// Proposal states
enum ProposalState {
Pending,
Active,
Defeated,
Succeeded,
Executed
}
Core Concepts
1. Governance Token
The governance token represents voting power in the system:
- One token equals one vote
- Tokens can be delegated
- Token balance determines proposal rights
- Voting power is snapshot at proposal creation
2. Proposal Lifecycle
A proposal goes through several states:
- Pending - Waiting for voting to start
- Active - Open for voting
- Defeated - Failed to reach quorum or majority
- Succeeded - Passed but not executed
- Executed - Successfully implemented
3. Voting Mechanism
The voting process includes:
- Token-weighted voting
- Quorum requirements
- Time-bound voting periods
- Vote delegation options
4. Execution Process
Proposal execution involves:
- Timelock delay
- Security checks
- Action implementation
- State updates
Security Considerations
Access Control
- Proposal thresholds
- Voting power verification
- Execution permissions
- Delegation rules
Time Management
- Voting delays
- Voting periods
- Execution timelock
- Block number tracking
Vote Integrity
- Double voting prevention
- Vote weight calculation
- Delegation tracking
- Snapshot mechanism
Economic Security
- Quorum requirements
- Proposal thresholds
- Vote locking
- Incentive alignment
Best Practices
Implementation
- Use standard libraries
- Implement safeguards
- Follow patterns
- Document thoroughly
Testing
- Unit tests
- Integration tests
- Scenario testing
- Security audits
Deployment
- Parameter setting
- Gradual rollout
- Emergency procedures
- Monitoring systems
Maintenance
- Upgrades
- Parameter adjustments
- Bug fixes
- Community feedback
Extended Features
Advanced Voting
- Quadratic voting
- Ranked choice
- Vote delegation
- Vote escrow
Proposal Enhancement
- Multiple actions
- Conditional execution
- Batch proposals
- Amendment process
Integration
- Multi-chain governance
- DAO frameworks
- DeFi protocols
- NFT voting
Analytics
- Voting patterns
- Participation metrics
- Proposal success rates
- Voter behavior
FAQ
General Questions
Q: What is token governance?
A: Token governance is a system that enables:
- Decentralized decision-making
- Community participation
- Transparent voting
- Automated execution
Q: Why use token governance?
A: Benefits include:
- Community ownership
- Decentralized control
- Transparent decisions
- Automated enforcement
Technical Questions
Q: How to handle vote delegation?
A: Delegation involves:
- Power transfer tracking
- Delegation history
- Vote weight calculation
- Revocation mechanism
Q: What about vote manipulation?
A: Prevention measures:
- Snapshot mechanisms
- Vote locking
- Quorum requirements
- Activity monitoring
Implementation Questions
Q: How to set parameters?
A: Consider these factors:
- Community size
- Token distribution
- Voting patterns
- Security needs
Q: What about upgrades?
A: Upgrade strategy should include:
- Proxy patterns
- Testing procedures
- Community approval
- Gradual rollout