Track 8 · Capstones · lesson 5
DAO voting
120 min
On-chain governance: proposals, votes weighted by token holdings, and execution of what passes. The help drops again — you get a written spec and the test names, nothing else.
Scaffolding tier: spec. No starter repo, no signatures. A specification and the names of the tests your contract must pass. You design the whole thing.
Specification
A governance contract where holders of a governance token vote on proposals:
- Anyone holding at least a proposal threshold of tokens can create a proposal (a target address, calldata, and a description).
- Voting is open for a fixed window. Voting weight equals the voter's token balance at the block the proposal was created — not current balance.
- After the window, a proposal that reached quorum and has more votes for than against can be executed, which performs its target call exactly once.
- No double voting. No voting after the window. No executing twice.
The tests it must pass
test_CreateProposal_RequiresThreshold
test_Vote_WeightedByBalanceAtSnapshot
test_Vote_RevertsAfterWindow
test_Vote_RevertsOnDoubleVote
test_Execute_RevertsBeforeQuorum
test_Execute_RunsTargetCallOnce
test_Execute_RevertsIfAlreadyExecuted
The subtle requirement is the snapshot. If voting weight used current balance, someone could vote, transfer their tokens to another address, and vote again — buying unlimited influence with the same tokens. Weight must be fixed at proposal creation.
OpenZeppelin's ERC20Votes implements exactly this checkpointing. Using it is
fair game; understanding why it exists is the point.
Check
Why must voting weight be snapshotted at proposal creation rather than read live?
Worth remembering
- Capstone 5, spec scaffolding: a written spec and test names, no code given.
- Token-weighted governance: propose, vote within a window, execute what passes.
- Voting weight is snapshotted at proposal creation, not read live.
- The snapshot prevents voting, transferring, and voting again with the same tokens.