A production-ready decentralized autonomous organization (DAO) built with OpenZeppelin's governance framework, featuring on-chain voting, proposal execution through a timelock, and comprehensive testing.
This DAO governance system enables token holders to collectively make decisions through on-chain proposals and voting. The system uses a timelock mechanism to ensure a delay between proposal approval and execution, providing time for stakeholders to react to governance decisions.
Key Components:
- GovernanceToken: ERC20 token with voting capabilities (ERC20Votes)
- Governor: Main governance contract for proposals and voting
- TimeLock: Enforces execution delays on approved proposals
- Box: Example governance-controlled contract
- β On-chain Governance: Fully decentralized decision-making
- β Token-based Voting: 1 token = 1 vote with delegation support
- β Timelock Protection: Mandatory delay before proposal execution
- β Flexible Parameters: Configurable voting periods, delays, and quorum
- β OpenZeppelin Standard: Battle-tested governance contracts
- β Comprehensive Testing: Unit tests and staging tests included
- β Hardhat Ignition: Declarative deployment system
- β Multi-network Support: Deploy to localhost, testnets, or mainnet
βββββββββββββββββββ
β GovernanceToken β (ERC20Votes)
ββββββββββ¬βββββββββ
β
β voting power
βΌ
βββββββββββββββββββ proposes ββββββββββββ
β Governor β βββββββββββββββββββΊ β TimeLock β
β (Proposals) β β (Delays) β
βββββββββββββββββββ βββββββ¬βββββ
β
β executes
βΌ
ββββββββββββ
β Box β
β (Target) β
ββββββββββββ
- Delegate: Token holders delegate voting power to themselves or others
- Propose: Users with sufficient voting power create proposals
- Vote: Token holders vote For/Against/Abstain during voting period
- Queue: Successful proposals are queued in the TimeLock
- Execute: After delay, anyone can execute queued proposals
ERC20 token with voting capabilities using OpenZeppelin's ERC20Votes extension.
- Total Supply: 1,000,000 tokens
- Voting: Checkpoint-based voting power
- Delegation: Required before voting
Main governance contract inheriting from multiple OpenZeppelin Governor extensions.
- Extensions: Settings, CountingSimple, Votes, VotesQuorumFraction, TimelockControl
- Voting Delay: Configurable delay before voting starts
- Voting Period: Duration of voting
- Quorum: Minimum percentage of votes required
Timelock controller that enforces delays on proposal execution.
- Min Delay: Minimum time between queue and execution
- Roles: Proposer (Governor), Executor (anyone), Admin (self)
Example governance-controlled contract demonstrating DAO control.
- Owner: TimeLock contract (controlled by DAO)
- Function: Stores a single value that only governance can change
- Node.js v18+ and npm/yarn
- Basic understanding of Ethereum and Solidity
- Testnet ETH for deployment (Sepolia recommended)
# Clone the repository
git clone https://github.com/ndubuisi-ugwuja/dao-template.git
cd dao-template
# Install dependencies
yarn installCreate a .env file with the following:
# Network Configuration
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
PRIVATE_KEY=your_private_key_here
ETHERSCAN_API_KEY=your_etherscan_api_key // For etherscan Verification
# Deployed Contract Addresses (after deployment)
GOVERNANCE_TOKEN_ADDRESS=
GOVERNOR_ADDRESS=
TIMELOCK_ADDRESS=
BOX_ADDRESS=
# For proposals
PROPOSAL_ID=
NEW_VALUE=
yarn hardhat compile# Start local Hardhat node
yarn hardhat node
# Deploy to localhost (in another terminal)
yarn hardhat ignition deploy ignition/modules/FullDaoModule.ts --network localhost# Deploy to Sepolia
yarn hardhat ignition deploy ignition/modules/FullDaoModule.ts --network sepolia
# Verify contracts on Etherscan
yarn hardhat ignition verify deployments/chain-11155111Run comprehensive unit tests on local Hardhat network:
# Run all unit tests
yarn hardhat test
# Run with coverage
yarn hardhat coverageTest deployed contracts on testnets:
# Run staging tests on Sepolia
yarn hardhat test --network sepolia# Delegate votes to yourself
yarn hardhat run scripts/delegate.ts --network sepolia
# Wait 1-2 blocks for voting power to activate# Create proposal with unique value set in your .env
yarn hardhat run scripts/propose.ts --network sepolia
# Save the PROPOSAL_ID from output to .env# Wait for voting delay to pass
# Check current block: await ethers.provider.getBlockNumber()
# Cast your vote
yarn hardhat run scripts/vote.ts --network sepolia# Wait for voting period to end
# Proposal must have succeeded (reached quorum)
# Queue in TimeLock
yarn hardhat run scripts/queue.ts --network sepolia# Wait for TimeLock delay (e.g., 300 seconds on Sepolia)
# Execute the proposal
yarn hardhat run scripts/execute.ts --network sepoliaKey configurations in hardhat.config.ts:
const config: HardhatUserConfig = {
solidity: {
version: "0.8.28",
settings: {
evmVersion: "cancun", // Required for OpenZeppelin 5.5.0
optimizer: {
enabled: true,
runs: 200,
},
},
},
networks: {
sepolia: {
url: SEPOLIA_RPC_URL,
accounts: [PRIVATE_KEY],
chainId: 11155111,
},
},
};Blocks to wait before voting starts after proposal creation.
- Localhost: 1 block (~12 seconds)
- Testnet: 1 block (~12 seconds)
- Mainnet: 7200 blocks (~1 day)
Duration of voting in blocks.
- Localhost: 5 blocks (~1 minute)
- Testnet: 5 blocks (~1 minute)
- Mainnet: 50400 blocks (~7 days)
Minimum percentage of total supply that must vote for proposal to pass.
- Default: 4% of total supply
Seconds to wait between queue and execution.
- Localhost: 10 seconds
- Testnet: 10 seconds
- Mainnet: 172800 seconds (2 days)
- PROPOSER_ROLE: Only Governor contract can propose to TimeLock
- EXECUTOR_ROLE: Anyone can execute (address(0))
- DEFAULT_ADMIN_ROLE: TimeLock is self-administered
β DO:
- Always test on testnet first
- Verify contracts on Etherscan
- Use multi-sig for critical operations
- Document all governance parameters
- Monitor proposal events
- Keep private keys secure
β DON'T:
- Deploy to mainnet without testing
- Share private keys
- Use low gas limits
- Skip timelock delays
- Ignore failed transactions
- Deploy with admin backdoors
Before mainnet deployment:
- Complete security audit by reputable firm
- Bug bounty program
- Formal verification of critical functions
- Emergency pause mechanism (if needed)
- Multi-sig control for admin functions
Estimated gas costs on Ethereum mainnet:
| Operation | Gas Cost (est.) | USD Cost @ 30 gwei |
|---|---|---|
| Deploy Full DAO | ~5,000,000 | ~$150 |
| Delegate | ~150,000 | ~$4.50 |
| Create Proposal | ~200,000 | ~$6.00 |
| Cast Vote | ~100,000 | ~$3.00 |
| Queue Proposal | ~150,000 | ~$4.50 |
| Execute Proposal | ~100,000 | ~$3.00 |
Costs are estimates and vary with gas prices
Issue: "Cannot find module typechain-types"
# Solution: Compile contracts to generate TypeChain types
yarn hardhat compileIssue: "execution reverted" when creating proposal
# Solution: Delegate votes and wait 1 block
yarn hardhat run scripts/delegate.ts --network sepolia
# Wait 12-24 seconds, then create proposalContributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Install dependencies
yarn install
# Run tests
yarn hardhat testThis project is UNLICENSED. See the LICENSE file for details.
- OpenZeppelin for secure smart contract libraries
- Hardhat for development environment
- Ethereum community for governance standards
For questions and support:
- Open an issue on GitHub
- Review existing documentation
- Check troubleshooting guide
- Connect on x
- Add proposal cancellation functionality
- Implement voting power snapshots
- Create governance UI
- Add proposal templates
- Integrate with multisig wallets
- Add proposal simulation tools
- Create governance analytics dashboard
- Initial release
- Complete DAO implementation
- Comprehensive testing suite
- Deployment scripts
- Documentation