skills/stanah/dotagents/solidity-governance

solidity-governance

SKILL.md

solidity-governance: DAO・ガバナンス開発スキル

DAO ガバナンスにおける投票、提案、タイムロック、トレジャリー管理のパターンを提供するドメイン特化スキル。

対象

  • OpenZeppelin Governor ベースのガバナンス
  • 投票メカニズム(トークン加重・Quadratic Voting・veToken)
  • タイムロック・遅延実行
  • トレジャリー管理・マルチシグ

ワークフロー

Step 1: ガバナンス要件の整理

ユーザーの要件からガバナンスの構成要素を判定する:

ユースケース リファレンス 読み込み時の注目ポイント
DAO 構築・投票システム references/dao-patterns.md Governor 設計、投票メカニズム選択、提案ライフサイクル
トレジャリー・資金管理 references/treasury-patterns.md マルチシグ、予算制限、支出承認フロー
遅延実行・安全装置 references/timelock-patterns.md TimelockController、緊急停止、ガーディアン

複数のコンポーネントが関連する場合(Governor + Timelock が一般的)は全てのリファレンスを読み込む。

検証ゲート: ガバナンスの基本要件(投票方式・トークン種別・意思決定スコープ)が明確であること。不明な場合は AskUserQuestion で確認する。

Step 2: ガバナンストークンの決定

方式 推奨実装 ユースケース
ERC20 ベース ERC20Votes(投票権委任対応) 一般的な DAO。トークン保有量に比例した投票権
NFT ベース ERC721Votes(1 NFT = 1票) メンバーシップ型 DAO。1人1票の平等な投票
既存トークン活用 ERC20Wrapper + ERC20Votes 既存の ERC20 トークンに投票機能を追加
ロック型 veToken パターン(自前実装) 長期保有を優遇。ロック期間に応じて投票権増加

判断が不明な場合: AskUserQuestion で「既存トークンの有無」「投票権の平等性」「ロックインセンティブの要否」を確認する。

検証ゲート: ガバナンストークンの方式が決定し、OpenZeppelin の対応ライブラリが利用可能であること。

Step 3: Governor パラメータ設計

プロジェクトの規模・性質に応じてパラメータを設計する:

パラメータ 小規模 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: フラッシュローン投票攻撃の防止。スナップショットは提案作成時のブロックで取得されるため、Delay 期間中のトークン購入は投票に反映されない。
  • Proposal Threshold: スパム提案の防止。低すぎると攻撃コスト低下、高すぎると少数派の提案が困難。
  • Quorum: 投票の正当性確保。低すぎると少数派による支配、高すぎると可決が困難。
  • Timelock Delay: 不利な提案が実行される前にユーザーが退出(exit)する時間を確保。

検証ゲート: 全パラメータが設定され、矛盾がないこと(例: Voting Delay < Voting Period)。

Step 4: コード生成

  1. solidity-corelanguage-patterns.md に従い NatSpec・コーディング規約を適用する。
  2. ガバナンス固有のコンポーネントを生成する:
    • Governor コントラクト: OpenZeppelin の Governor + 必要な拡張を継承
    • ガバナンストークン: ERC20Votes または ERC721Votes
    • TimelockController: Governor の executor として設定
    • デプロイスクリプト: 正しいデプロイ順序(Token → Timelock → Governor → Role 設定)
  3. テストコードを同時に生成する:
    • 提案 → 投票 → キュー → 実行の完全フロー
    • Quorum 未達テスト
    • Proposal Threshold 未達テスト
    • タイムロック遅延テスト

検証ゲート: forge build がエラーなく完了し、提案→投票→実行のフローテストがパスすること。

Step 5: セキュリティ確認

ガバナンス特有のセキュリティリスクを確認する:

  1. フラッシュローン投票: ERC20Votes のスナップショット投票が有効か。提案時点の getPastVotes を使用しているか。
  2. ガバナンス乗っ取り: Proposal Threshold と Quorum が攻撃コストに対して十分か。
  3. 提案スパム: Proposal Threshold が設定されているか。
  4. 実行操作のリスク: Timelock の遅延期間が十分か。緊急停止のガーディアンが設定されているか。
  5. 投票権の集中: 大口保有者が Quorum を単独で満たせないか確認。

検証ゲート: CRITICAL レベルのセキュリティ問題が 0 件であること。

使用例

例 1: OpenZeppelin Governor ベースの DAO

ユーザー入力: 「トークン保有者が提案・投票できる DAO を作りたい。タイムロック付きで」

アクション:

  1. Step 1: DAO 構築 + タイムロック → dao-patterns.md + timelock-patterns.md を読み込み
  2. Step 2: ERC20 ベース → ERC20Votes を選択
  3. Step 3: 中規模 DAO のパラメータを適用(Voting Delay: 2日、Period: 7日、Quorum: 4%)
  4. Step 4: 以下を生成:
    • src/GovernanceToken.solERC20Votes + ERC20Permit 継承。ミント関数付き
    • src/MyGovernor.solGovernor + GovernorSettings + GovernorCountingSimple + GovernorVotes + GovernorVotesQuorumFraction + GovernorTimelockControl 継承
    • src/MyTimelock.solTimelockController ラッパー
    • test/Governance.t.sol — 提案→投票→キュー→実行のフルフロー、Quorum 未達、期限切れテスト
    • script/DeployGovernance.s.sol — Token → Timelock → Governor の順序でデプロイ。Timelock に Governor を proposer / executor として設定
  5. Step 5: フラッシュローン防御(スナップショット投票)、タイムロック遅延の確認

結果: 完全なガバナンスシステム(トークン + Governor + Timelock)がテスト・スクリプト付きで生成される。

例 2: NFT ベースの 1人1票 DAO

ユーザー入力: 「メンバーシップ NFT を持っている人が投票できる DAO。1人1票にしたい」

アクション:

  1. Step 1: DAO 構築 → dao-patterns.md を読み込み → NFT 投票パターンを選択
  2. Step 2: NFT ベース → ERC721Votes を選択(solidity-nft のトークン標準も参照)
  3. Step 3: 小規模 DAO パラメータ(Voting Delay: 1日、Period: 5日、Quorum: 5%)
  4. Step 4: 以下を生成:
    • src/MembershipNFT.solERC721Votes 継承。招待制ミント(owner のみ)
    • src/NFTGovernor.sol — NFT ベース Governor
    • test/NFTGovernance.t.sol — NFT 保有者の投票テスト、非保有者の投票拒否テスト
  5. Step 5: 1人が複数 NFT を保有した場合の投票権確認(NFT 数 = 投票権数)

結果: メンバーシップ NFT による投票システムが生成される。

例 3: マルチシグ + Governor ハイブリッド

ユーザー入力: 「初期は少人数のマルチシグで運営して、将来的にフルオンチェーンガバナンスに移行したい」

アクション:

  1. Step 1: トレジャリー + DAO → treasury-patterns.md + dao-patterns.md を読み込み
  2. Step 2: 初期は既存トークンなし → まずマルチシグ、後で ERC20Votes を導入
  3. Step 3: 段階的移行パラメータ設計
  4. Step 4: 以下を生成:
    • Phase 1: src/Treasury.solTimelockController ベース。3/5 マルチシグを proposer / executor に設定
    • Phase 2(移行用): src/GovernanceToken.sol + src/MyGovernor.sol — Governor を Timelock の proposer に追加し、マルチシグを段階的に executor から削除
    • test/Migration.t.sol — Phase 1 → Phase 2 の移行テスト
  5. Step 5: 移行中のセキュリティ(マルチシグと Governor が同時に権限を持つ期間の管理)

結果: 段階的にオンチェーンガバナンスへ移行可能なハイブリッドシステムが生成される。

トラブルシューティング

1. 提案が実行できない(タイムロックエラー)

症状: 投票成功後、queue または executeAccessControl: account is missing role でリバート

原因と対策:

  • Governor に Timelock の role が設定されていない: デプロイ後に TimelockController.grantRole(PROPOSER_ROLE, governorAddress)grantRole(EXECUTOR_ROLE, governorAddress) を実行する必要がある。デプロイスクリプトに含めること。
  • Timelock の delay が経過していない: queue 後、execute には Timelock の minDelay 以上の時間経過が必要。テストでは vm.warp(block.timestamp + minDelay + 1) でスキップする。

2. Quorum が達成できない

症状: 十分な票数があるのに提案が Defeated になる

原因と対策:

  • 投票権の委任忘れ: ERC20Votes はデフォルトで投票権が 0。トークン保有者は delegate(自分のアドレス) を呼ぶ必要がある。フロントエンドで自動委任を実装するか、_afterTokenTransfer で自動委任する。
  • スナップショットのタイミング: 投票権は提案作成時のブロックで確定する。提案作成後にトークンを取得しても投票権に反映されない。
  • Quorum 計算の対象: GovernorVotesQuorumFractiontoken.getPastTotalSupply() に対するパーセンテージ。トークン総供給量が大きすぎると Quorum 達成が困難。

3. 提案の作成ができない

症状: proposeGovernorInsufficientProposerVotes でリバート

原因と対策:

  • Proposal Threshold 未達: 提案者の投票権が proposalThreshold() 未満。投票権を委任済みか確認する。
  • 投票権の委任タイミング: delegate のタイミングが提案作成と同一ブロック内だと反映されない。少なくとも 1 ブロック前に委任する。

4. 投票結果が反映されない

症状: castVote が成功するが、投票結果に反映されない

原因と対策:

  • 投票期間外: state()Active でない期間に投票している。votingDelay 経過後、votingPeriod 内に投票する。テストでは vm.roll(block.number + votingDelay + 1) でスキップ。
  • 重複投票: 同一アドレスからの 2 回目の投票は無視される(エラーにならない場合がある)。hasVoted で確認する。

5. デプロイ順序の問題

症状: Governor / Timelock の参照がゼロアドレスになる

原因と対策:

  • 循環依存: Governor は Timelock を、Timelock は Governor を参照する。正しいデプロイ順序: (1) Token → (2) Timelock(Governor = address(0) で仮設定)→ (3) Governor(Timelock 参照)→ (4) Timelock に Governor の role を付与。
  • Deployer の admin role: デプロイ後、deployer が Timelock の DEFAULT_ADMIN_ROLE を放棄(renounceRole)することを忘れない。放棄しないとデプロイヤーが全権を持ち続ける。

注意事項

  • ガバナンス攻撃(フラッシュローン投票)への防御としてスナップショット投票(ERC20Votes)を使用する。
  • タイムロックは提案実行前の監視期間として不可欠。最低 1 日以上を推奨。
  • 初期段階ではマルチシグ + ガバナンスの併用を推奨する。フルオンチェーンガバナンスは十分にコミュニティが成熟してから移行する。
  • 投票権の自動委任(_afterTokenTransfer 内で _delegate)を検討する。委任忘れは最も一般的な UX 問題。
  • 基盤的なパターン(アクセス制御、ガス最適化等)は solidity-core を参照する。
  • フロントエンド統合(提案 UI、投票 UI)は web3-frontend を参照する。
  • OpenZeppelin Governor の利用を推奨し、カスタムガバナンスの独自実装は避ける。
Weekly Installs
2
First Seen
Feb 21, 2026
Installed on
opencode2
gemini-cli2
claude-code2
github-copilot2
codex2
kimi-cli2