DAO・ガバナンス開発スキル。OpenZeppelin Governor、投票メカニズム、 タイムロック、トレジャリー管理のパターンを提供する。 ユーザーが "DAO", "ガバナンス", "投票", "Governor", "タイムロック", "マルチシグ", "solidity-governance" 等と言った時に使用。
DAO ガバナンスにおける投票、提案、タイムロック、トレジャリー管理のパターンを提供するドメイン特化スキル。
ユーザーの要件からガバナンスの構成要素を判定する:
| ユースケース | リファレンス | 読み込み時の注目ポイント |
|---|---|---|
| DAO 構築・投票システム | references/dao-patterns.md | Governor 設計、投票メカニズム選択、提案ライフサイクル |
| トレジャリー・資金管理 | references/treasury-patterns.md | マルチシグ、予算制限、支出承認フロー |
| 遅延実行・安全装置 | references/timelock-patterns.md | TimelockController、緊急停止、ガーディアン |
複数のコンポーネントが関連する場合(Governor + Timelock が一般的)は全てのリファレンスを読み込む。
検証ゲート: ガバナンスの基本要件(投票方式・トークン種別・意思決定スコープ)が明確であること。不明な場合は AskUserQuestion で確認する。
| 方式 | 推奨実装 | ユースケース |
|---|---|---|
| ERC20 ベース | ERC20Votes(投票権委任対応) | 一般的な DAO。トークン保有量に比例した投票権 |
| NFT ベース | ERC721Votes(1 NFT = 1票) | メンバーシップ型 DAO。1人1票の平等な投票 |
| 既存トークン活用 | ERC20Wrapper + ERC20Votes | 既存の ERC20 トークンに投票機能を追加 |
| ロック型 | veToken パターン(自前実装) | 長期保有を優遇。ロック期間に応じて投票権増加 |
判断が不明な場合: AskUserQuestion で「既存トークンの有無」「投票権の平等性」「ロックインセンティブの要否」を確認する。
検証ゲート: ガバナンストークンの方式が決定し、OpenZeppelin の対応ライブラリが利用可能であること。
プロジェクトの規模・性質に応じてパラメータを設計する:
| パラメータ | 小規模 DAO(<100人) | 中規模 DAO(100-1000人) | 大規模 DAO(1000+人) |
|---|---|---|---|
| Voting Delay | 1 day (7200 blocks) | 2 days | 3 days |
| Voting Period | 3-5 days | 7 days | 14 days |
| Proposal Threshold | 0.1-1% of supply | 0.5-2% | 1-5% |
| Quorum | 2-5% | 4-10% | 10-20% |
| Timelock Delay | 1-2 days | 2-3 days | 3-7 days |
設計の考慮事項:
検証ゲート: 全パラメータが設定され、矛盾がないこと(例: Voting Delay < Voting Period)。
solidity-core の language-patterns.md に従い NatSpec・コーディング規約を適用する。ERC20Votes または ERC721Votes検証ゲート: forge build がエラーなく完了し、提案→投票→実行のフローテストがパスすること。
ガバナンス特有のセキュリティリスクを確認する:
ERC20Votes のスナップショット投票が有効か。提案時点の getPastVotes を使用しているか。検証ゲート: CRITICAL レベルのセキュリティ問題が 0 件であること。
ユーザー入力: 「トークン保有者が提案・投票できる DAO を作りたい。タイムロック付きで」
アクション:
dao-patterns.md + timelock-patterns.md を読み込みERC20Votes を選択src/GovernanceToken.sol — ERC20Votes + ERC20Permit 継承。ミント関数付きsrc/MyGovernor.sol — Governor + GovernorSettings + GovernorCountingSimple + GovernorVotes + GovernorVotesQuorumFraction + GovernorTimelockControl 継承src/MyTimelock.sol — TimelockController ラッパーtest/Governance.t.sol — 提案→投票→キュー→実行のフルフロー、Quorum 未達、期限切れテストscript/DeployGovernance.s.sol — Token → Timelock → Governor の順序でデプロイ。Timelock に Governor を proposer / executor として設定結果: 完全なガバナンスシステム(トークン + Governor + Timelock)がテスト・スクリプト付きで生成される。
ユーザー入力: 「メンバーシップ NFT を持っている人が投票できる DAO。1人1票にしたい」
アクション:
dao-patterns.md を読み込み → NFT 投票パターンを選択ERC721Votes を選択(solidity-nft のトークン標準も参照)src/MembershipNFT.sol — ERC721Votes 継承。招待制ミント(owner のみ)src/NFTGovernor.sol — NFT ベース Governortest/NFTGovernance.t.sol — NFT 保有者の投票テスト、非保有者の投票拒否テスト結果: メンバーシップ NFT による投票システムが生成される。
ユーザー入力: 「初期は少人数のマルチシグで運営して、将来的にフルオンチェーンガバナンスに移行したい」
アクション:
treasury-patterns.md + dao-patterns.md を読み込みsrc/Treasury.sol — TimelockController ベース。3/5 マルチシグを proposer / executor に設定src/GovernanceToken.sol + src/MyGovernor.sol — Governor を Timelock の proposer に追加し、マルチシグを段階的に executor から削除test/Migration.t.sol — Phase 1 → Phase 2 の移行テスト結果: 段階的にオンチェーンガバナンスへ移行可能なハイブリッドシステムが生成される。
症状: 投票成功後、queue または execute が AccessControl: account is missing role でリバート
原因と対策:
TimelockController.grantRole(PROPOSER_ROLE, governorAddress) と grantRole(EXECUTOR_ROLE, governorAddress) を実行する必要がある。デプロイスクリプトに含めること。queue 後、execute には Timelock の minDelay 以上の時間経過が必要。テストでは vm.warp(block.timestamp + minDelay + 1) でスキップする。症状: 十分な票数があるのに提案が Defeated になる
原因と対策:
ERC20Votes はデフォルトで投票権が 0。トークン保有者は delegate(自分のアドレス) を呼ぶ必要がある。フロントエンドで自動委任を実装するか、_afterTokenTransfer で自動委任する。GovernorVotesQuorumFraction は token.getPastTotalSupply() に対するパーセンテージ。トークン総供給量が大きすぎると Quorum 達成が困難。症状: propose が GovernorInsufficientProposerVotes でリバート
原因と対策:
proposalThreshold() 未満。投票権を委任済みか確認する。delegate のタイミングが提案作成と同一ブロック内だと反映されない。少なくとも 1 ブロック前に委任する。症状: castVote が成功するが、投票結果に反映されない
原因と対策:
state() が Active でない期間に投票している。votingDelay 経過後、votingPeriod 内に投票する。テストでは vm.roll(block.number + votingDelay + 1) でスキップ。hasVoted で確認する。症状: Governor / Timelock の参照がゼロアドレスになる
原因と対策:
DEFAULT_ADMIN_ROLE を放棄(renounceRole)することを忘れない。放棄しないとデプロイヤーが全権を持ち続ける。ERC20Votes)を使用する。_afterTokenTransfer 内で _delegate)を検討する。委任忘れは最も一般的な UX 問題。solidity-core を参照する。web3-frontend を参照する。