OpenZeppelin GovernorでDAO(分散型自律組織)を設計・実装する実践ガイド
この記事でわかること
- DAOの基本アーキテクチャと3つのメンバーシップモデル(トークンベース・シェアベース・レピュテーションベース)の設計思想
- OpenZeppelin Governorを使ったオンチェーンガバナンスコントラクトの実装手順
- Snapshot・Aragon・Tallyを活用したハイブリッドガバナンスの構築方法
- フラッシュローン攻撃やリエントランシーなど2025年のDAOセキュリティ脅威への対策
- 日本における合同会社型DAOの法的フレームワークと実務上の注意点
対象読者
- 想定読者: AIエンジニア・MLエンジニア(ブロックチェーン初級者)
-
必要な前提知識:
- Pythonでの開発経験(クラス、デコレータ、パッケージ管理の理解)
- 機械学習の基本概念(モデルのデプロイ、パイプライン、分散学習など)
- ターミナル操作とGitの基本
-
不要な前提知識:
- ブロックチェーンやSolidityの知識は一切不要です(本記事で基礎から解説します)
結論・成果
OpenZeppelin Governorフレームワークを採用することで、提案・投票・実行の一連のガバナンスサイクルをフルオンチェーンで実装できます。DAOtimesのレポートによると、Snapshotが処理するオフチェーン投票のシェアは96%に達しており、オフチェーンで合意形成→オンチェーンで拘束力のある実行というハイブリッドガバナンスが現在の実務標準となっています。一方で、Markaicodeの報告では2025年前半だけでDAOのセキュリティ損失が7億8000万ドルを超えており、TimelockControllerの導入や投票期間の適切な設定がセキュリティ上不可欠です。
ブロックチェーンとスマートコントラクトの基礎知識
この記事を読むために必要なブロックチェーンの基礎知識を、AI/MLの概念と対比しながら解説します。すでにブロックチェーンの基礎を理解している方は、このセクションをスキップしてください。
ブロックチェーンとは
ブロックチェーンは分散型の台帳(データベース)です。取引記録(トランザクション)がブロック単位でまとめられ、暗号学的にチェーン状につながっています。
AI/MLの文脈で例えると、Git + 分散ファイルシステムに近い概念です。
- Gitと同様に、過去の全履歴が改ざん不可能な形で記録される
- 分散ファイルシステムのように、世界中の複数ノード(コンピュータ)が同じデータを保持する
- 一度記録されたデータは変更できない(イミュータブル)
MLの学習データ管理で「データのバージョン管理」や「リネージ(来歴追跡)」を考えたことがあれば、ブロックチェーンはそれをグローバル規模で実現する仕組みだと理解してください。
Ethereumとは
Ethereumは、ブロックチェーン上でプログラムを実行できるプラットフォームです。ビットコインが「デジタルな通貨台帳」であるのに対し、Ethereumは「分散型のコンピュータ」と捉えられます。
| 比較 | ビットコイン | Ethereum |
|---|---|---|
| 主な用途 | 価値の送受信 | プログラムの実行 + 価値の送受信 |
| プログラマビリティ | 限定的 | チューリング完全 |
| 例え | 分散型の銀行口座 | 分散型のクラウドコンピューティング(AWS Lambda的) |
スマートコントラクトとは
スマートコントラクトは、Ethereum上にデプロイされる自動実行プログラムです。条件が満たされると、人間の介在なしに自動的に処理が実行されます。
MLパイプラインに例えると理解しやすいでしょう。
- MLパイプライン: 学習データ投入 → 前処理 → 学習 → 評価 → デプロイ(条件を満たせば自動で次のステージへ)
- スマートコントラクト: トランザクション送信 → 条件チェック → 状態更新 → 結果の記録(条件を満たせば自動で実行)
重要な特性として、一度デプロイすると変更できません。これはMLモデルのイミュータブルデプロイメント(バージョン固定でデプロイし、更新時は新バージョンを別途デプロイ)と同じ考え方です。バグがあっても「修正して再デプロイ」はできず、新しいコントラクトをデプロイして移行する必要があります。
Solidityとは
Solidityは、Ethereum上のスマートコントラクトを記述するプログラミング言語です。JavaScriptに似た構文を持ちますが、Pythonエンジニアにとっても直感的に理解できる部分が多いです。
| Solidityの概念 | Pythonの対応概念 | 説明 |
|---|---|---|
pragma solidity ^0.8.24 |
python_requires=">=3.10" |
コンパイラ/インタプリタのバージョン指定 |
import {...} from "..." |
from package import module |
パッケージのインポート |
contract MyContract |
class MyClass |
クラス(コントラクト)定義 |
constructor() |
__init__(self) |
初期化関数 |
function foo() public |
def foo(self): |
メソッド定義 |
mapping(address => uint) |
dict[str, int] |
辞書(マッピング)型 |
require(x > 0, "error") |
assert x > 0, "error" |
バリデーション |
modifier onlyOwner |
@only_owner デコレータ |
関数の前処理デコレータ |
override |
メソッドオーバーライド | 親クラスの関数を上書き |
event Transfer(...) |
logging.info(...) |
イベントログの発行 |
ガス(Gas)とは
ガスは、Ethereum上で計算を実行するためのコスト単位です。すべてのトランザクション(送金、コントラクト実行など)にはガスが必要で、ETH(Ethereumの暗号通貨)で支払います。
AWS/GCPのGPU課金に例えると理解しやすいでしょう。
- GPUインスタンスで推論を実行すると、使用した計算量に応じて課金される
- 同様に、Ethereum上でスマートコントラクトを実行すると、使った計算量に応じてガス代がかかる
- 複雑な処理ほどガス代が高くなる(大きなモデルの推論ほどGPUコストが高いのと同じ)
2025年現在、Ethereum L1の一般的なトランザクションのガス代は数百円〜数千円程度です。これが「すべてをオンチェーンで行うのは現実的ではない」理由の一つであり、後述するオフチェーン(Snapshot)との使い分けが重要になります。
ERC-20トークンとは
ERC-20は、Ethereum上で「トークン」(デジタル資産)を作成するための標準規格です。PythonのABCクラス(抽象基底クラス)のようなもので、transfer()、balanceOf()、approve() などの共通インターフェースを定義しています。
この標準に従って作られたトークンは、すべてのウォレットや取引所で共通の方法で扱えます。DAO(分散型自律組織)では、このERC-20トークンに投票機能を追加した「ガバナンストークン」を使って意思決定を行います。
ウォレットとアドレス
ブロックチェーンでの身元証明には公開鍵暗号方式が使われます。SSH鍵認証やAPIキー管理の概念と同じです。
- 秘密鍵(Private Key): SSH秘密鍵に相当。絶対に他人に共有しない。紛失すると資産にアクセスできなくなる
-
アドレス(公開鍵から生成): GitHubのユーザーIDに相当。取引相手に共有する。
0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18のような形式 - ウォレット: 秘密鍵を管理するアプリケーション。MetaMask(ブラウザ拡張)が最も一般的
オンチェーン vs オフチェーン
ブロックチェーンの世界では、処理が「どこで」実行されるかが重要です。
| オンチェーン | オフチェーン | |
|---|---|---|
| 実行場所 | ブロックチェーン上 | 通常のサーバー/クライアント |
| コスト | ガス代が必要 | 無料〜低コスト |
| 信頼性 | 改ざん不可能、検証可能 | 運営者を信頼する必要あり |
| 速度 | 数秒〜数分 | ミリ秒〜秒 |
| AI/MLでの例え | 推論結果をブロックチェーンに記録 | 推論をローカルGPUで実行 |
DAOでは、「日常的な投票はオフチェーン(Snapshot)で低コストに行い、資金移動など重要な決定のみオンチェーンで実行する」というハイブリッドアプローチが主流です。
テストネット vs メインネット
| テストネット | メインネット | |
|---|---|---|
| 用途 | 開発・テスト | 本番環境 |
| ETH | 無料で入手可能(Faucetから) | 実際のお金で購入 |
| AI/MLでの例え | ステージング環境 | プロダクション環境 |
| 代表例 | Sepolia, Holesky | Ethereum Mainnet |
開発中は必ずテストネットを使い、十分にテストしてからメインネットにデプロイします。テストネットのETHは「Faucet」と呼ばれるWebサイトから無料で取得できます。
開発環境をセットアップする
DAOのスマートコントラクトを開発するために必要な環境を構築します。Pythonでの開発と対比しながら進めます。
前提ツールの確認
# Node.js(JavaScriptランタイム)の確認
# Pythonでいう python --version に相当
node --version # v18以上が必要
# npm(パッケージマネージャ)の確認
# Pythonでいう pip --version に相当
npm --version
Node.jsが未インストールの場合は、公式サイトからLTS版をインストールしてください。
Hardhatプロジェクトを初期化する
Hardhatは、Solidityの開発フレームワークです。Pythonにおけるpytest + setuptoolsに相当し、コンパイル、テスト、デプロイを一括管理できます。
# プロジェクトディレクトリの作成
mkdir my-dao && cd my-dao
# Hardhatプロジェクトの初期化
# Pythonでいう uv init + pyproject.toml 生成に相当
npx hardhat init
# → "Create a JavaScript project" を選択
# OpenZeppelin Contractsのインストール
# Pythonでいう uv add pydantic に相当
npm install @openzeppelin/contracts
インストール後のディレクトリ構成は以下のようになります。
my-dao/
├── contracts/ # Solidityソースコード(Pythonの src/ に相当)
│ └── Lock.sol # サンプルコントラクト
├── test/ # テストファイル(Pythonの tests/ に相当)
│ └── Lock.js
├── scripts/ # デプロイスクリプト
│ └── deploy.js
├── hardhat.config.js # 設定ファイル(pyproject.toml に相当)
├── package.json # 依存管理(pyproject.toml に相当)
└── node_modules/ # 依存パッケージ(.venv/ に相当)
コンパイル → テスト → デプロイの流れ
Solidityの開発サイクルはPythonと似ています。
# 1. コンパイル: Solidityコードをバイトコードに変換
# Pythonは動的言語なので直接対応はないが、型チェック(mypy)に近い
npx hardhat compile
# 2. テスト: ローカル環境でテスト実行
# Pythonでいう uv run pytest に相当
npx hardhat test
# 3. ローカルノード起動: テスト用のEthereumネットワーク
# Pythonでいう ローカルのdev serverを起動するイメージ
npx hardhat node
# 4. テストネットへのデプロイ(別ターミナルから)
npx hardhat run scripts/deploy.js --network sepolia
テストネット(Sepolia)のETHを取得する
テストネットでコントラクトをデプロイするには、テスト用ETH(無料)が必要です。
- MetaMaskウォレットをインストール: metamask.io からブラウザ拡張をインストール
- ネットワークをSepoliaに切り替え: MetaMaskの設定からSepoliaテストネットを選択
-
Faucetからテスト用ETHを取得:
- Google Cloud Web3 Faucet
- Alchemy Sepolia Faucet
- ウォレットアドレスを入力すると、テスト用ETHが送られます(数分かかる場合があります)
補足: テストネットのETHには金銭的価値はありません。何度でもFaucetから取得できるので、気軽に実験してください。
DAOのアーキテクチャを設計する
DAOは「Decentralized Autonomous Organization(分散型自律組織)」の略称で、中央管理者を持たずブロックチェーン上のスマートコントラクト(自動実行プログラム)によって運営される組織形態です。Ethereum.orgの公式ドキュメントでは「共有ミッションに向けて活動する集合的に所有される組織」と定義されています。
AI/MLの文脈で例えると、フェデレーテッドラーニング(連合学習)の組織版と捉えられます。フェデレーテッドラーニングでは各参加者が独立にモデルを学習し、集約ルールに基づいてグローバルモデルを更新します。DAOも同様に、各参加者が独立に投票し、スマートコントラクトの集約ルールに基づいて組織の意思決定を行います。
DAOと従来の組織の構造的な違いを理解する
DAOと従来の階層型組織には根本的な設計思想の違いがあります。以下の表で比較してみましょう。
| 側面 | DAO | 従来の組織 |
|---|---|---|
| 意思決定 | トークン保有者の投票で民主的に決定 | 経営層が階層的に判断 |
| 変更の適用 | スマートコントラクトが投票結果を自動実行 | 承認プロセスを経て手動実施 |
| 透明性 | 全活動がブロックチェーン上で公開 | 社内に限定、選択的に公開 |
| 参加条件 | トークン保有で誰でも参加可能 | 雇用・契約関係が必要 |
| 資金管理 | トレジャリー(共有金庫)の使途は投票で決定 | 予算は経営層が配分 |
なぜこの違いが重要か: 従来の組織では「誰が決めたか」が問題になりがちですが、DAOでは「どのルールに基づいて決まったか」がコードとして明確に定義されています。ただし、この透明性はすべての意思決定が公開されることも意味するため、競争上の秘密が保てないというトレードオフがあります。
3つのメンバーシップモデルを選定する
DAOの設計で最初に決めるべきはメンバーシップモデルです。Ethereum.orgのドキュメントに基づくと、主に3つの類型が存在します。
1. トークンベース(最も一般的)
ERC-20ガバナンストークン(DAO内での投票権を表すデジタル資産)の保有量に応じて投票権が付与されます。トークンは取引所で売買可能なため、参入障壁が低い反面、大口保有者(クジラ)による投票力の集中が課題です。MakerDAOやUniswapがこのモデルを採用しています。
2. シェアベース(許可型)
新規メンバーの参加には既存メンバーの承認が必要です。退出時にはトレジャリーから比例配分を受領できるため、「Rage Quit(怒りの退出)」メカニズムで少数派の権利を保護します。MolochDAOがこの設計の代表例です。
3. レピュテーションベース(貢献重視)
プロジェクトへの貢献度に応じて投票権が付与されます。トークンは譲渡不可(Non-transferable)のため、投票権の売買ができません。DXdaoがこのモデルを採用しています。
注意: トークンベースモデルは参入障壁が低い一方で、フラッシュローン(1トランザクション内で借入と返却を完結させる無担保ローン)による一時的な投票力取得というセキュリティリスクが存在します。2025年2月にはフラッシュローン攻撃による6700万ドルの損失事例が報告されています。
OpenZeppelin Governorでオンチェーンガバナンスを実装する
オンチェーンガバナンス(ブロックチェーン上で完結する意思決定プロセス)の実装には、OpenZeppelin ContractsのGovernorフレームワークが業界標準として広く採用されています。OpenZeppelinはSolidity界の「scikit-learn」のような存在で、監査済みの再利用可能なコンポーネント集です。このフレームワークはERC20Votes(ガバナンストークン)、Governor(提案・投票の管理)、TimelockController(遅延実行)の3つのコンポーネントで構成されます。
ガバナンストークン(ERC20Votes)を実装する
まず、投票権を追跡するガバナンストークンを実装します。ERC20Votes拡張により、過去の任意の時点でのトークン残高を記録するスナップショット機能が有効になります。
// SPDX-License-Identifier: MIT // ライセンス宣言(Pythonのファイル先頭コメントに相当)
pragma solidity ^0.8.24; // コンパイラバージョン指定(python_requires=">=3.10" に相当)
// パッケージのインポート(Pythonの from package import Class と同じ)
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
/// @title DAOガバナンストークン
/// @notice ERC20Votesにより投票権のスナップショットと委任をサポート
// contract = Pythonの class に相当
// "is ERC20, ERC20Permit, ERC20Votes" = 多重継承(class Foo(Base1, Base2, Base3) と同じ)
contract GovernanceToken is ERC20, ERC20Permit, ERC20Votes {
// constructor = Pythonの __init__ に相当(コントラクト作成時に1回だけ実行)
// string memory = Pythonの str 型(memoryはデータの保存場所を指定)
// uint256 = Pythonの int(ただし0以上の256bit整数に限定)
constructor(
string memory name,
string memory symbol,
uint256 initialSupply
) ERC20(name, symbol) ERC20Permit(name) { // 親クラスの__init__呼び出しに相当
// msg.sender = このコントラクトを作成したアドレス(Pythonにはない概念)
// _mint = トークンを新規発行してmsg.senderの残高に加算
_mint(msg.sender, initialSupply * 10 ** decimals());
}
// override = 親クラスのメソッドを上書き(Pythonのメソッドオーバーライドと同じ)
// internal = クラス内部からのみ呼び出し可能(Pythonの _private_method に近い)
// override(ERC20, ERC20Votes) = 多重継承時にどの親を上書きするか明示
function _update(
address from,
address to,
uint256 amount
) internal override(ERC20, ERC20Votes) {
super._update(from, to, amount); // super() と同じ
}
// public view = 読み取り専用メソッド(状態を変更しない)
// returns (uint256) = 戻り値の型を明示(Pythonの -> int に相当)
function nonces(
address owner
) public view virtual override(ERC20Permit, Nonces) returns (uint256) {
return super.nonces(owner);
}
}
なぜERC20Votesが必要か:
- スナップショット: 提案作成時点のトークン残高を記録し、投票期間中のトークン移動による二重投票を防止します
- 委任(Delegation): トークン保有者が投票権を別のアドレスに委任できます。自分で投票しない保有者の投票力を活用可能です
- Permit: ガスレス承認により、ユーザーがトークン承認のトランザクションを省略できます
ハマりポイント:
ERC20Votesを使う場合、トークン保有者は必ず自分自身または他のアドレスに投票権を委任(delegate)する必要があります。委任しないと投票力が0になります。初期設定で_delegate(msg.sender, msg.sender)を忘れるケースが多いため注意してください。
Governorコントラクトを実装する
次に、提案・投票・実行のロジックを管理するGovernorコントラクトを実装します。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
// OpenZeppelinのGovernor関連モジュールをインポート
// Pythonでいう from governance import Governor, CountingSimple, ... に相当
import {Governor} from "@openzeppelin/contracts/governance/Governor.sol";
import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol";
/// @title DAOガバナンスコントラクト
/// @notice OpenZeppelin Governorベースのモジュラーガバナンス
// 5つの親コントラクトを多重継承(Pythonの class Foo(A, B, C, D, E) と同じ)
// Solidityでは多重継承時にメソッドの衝突を明示的に解決する必要がある
contract DAOGovernor is
Governor,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction,
GovernorTimelockControl
{
// private = 外部から読み取り不可(Pythonの __変数名 に近い)
uint256 private _votingDelay; // 提案後の投票開始待機ブロック数
uint256 private _votingPeriod; // 投票期間(ブロック数)
// constructor(__init__)で各親クラスの初期化も呼び出す
constructor(
IVotes token, // ガバナンストークンのアドレス
TimelockController timelock, // タイムロックのアドレス
uint256 votingDelayBlocks, // 投票開始までの待機ブロック数
uint256 votingPeriodBlocks, // 投票受付期間のブロック数
uint256 quorumPercentage // 定足数(%)
)
Governor("DAOGovernor") // 親の__init__呼び出し
GovernorVotes(token) // 同上
GovernorVotesQuorumFraction(quorumPercentage) // 同上
GovernorTimelockControl(timelock) // 同上
{
_votingDelay = votingDelayBlocks;
_votingPeriod = votingPeriodBlocks;
}
// public view = 誰でも呼べる読み取り専用メソッド(@property に近い)
// override = 親クラスの抽象メソッドを実装
function votingDelay() public view override returns (uint256) {
return _votingDelay; // 例: 7200ブロック ≈ 1日
}
function votingPeriod() public view override returns (uint256) {
return _votingPeriod; // 例: 50400ブロック ≈ 1週間
}
// --- 以下はOpenZeppelinの多重継承による衝突解決 ---
// Pythonでも多重継承時にMRO(Method Resolution Order)で解決するが、
// Solidityでは明示的に override(親A, 親B) と書いて解決する
function state(uint256 proposalId)
public view override(Governor, GovernorTimelockControl)
returns (ProposalState)
{
return super.state(proposalId);
}
function proposalNeedsQueuing(uint256 proposalId)
public view override(Governor, GovernorTimelockControl)
returns (bool)
{
return super.proposalNeedsQueuing(proposalId);
}
// address[] memory = Pythonの list[str] に相当(アドレスの配列)
// bytes[] memory = Pythonの list[bytes] に相当
// bytes32 = 32バイト固定長のハッシュ値
function _queueOperations(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) returns (uint48) {
return super._queueOperations(
proposalId, targets, values, calldatas, descriptionHash
);
}
function _executeOperations(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) {
super._executeOperations(
proposalId, targets, values, calldatas, descriptionHash
);
}
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor()
internal view override(Governor, GovernorTimelockControl)
returns (address)
{
return super._executor();
}
}
主要パラメータの設計指針
ガバナンスパラメータの設定はDAOのセキュリティと使いやすさのバランスに直結します。以下はOpenZeppelin公式ドキュメントと主要DAOの設定を参考にした推奨値です。
| パラメータ | 説明 | 推奨値 | 設定根拠 |
|---|---|---|---|
votingDelay |
提案作成→投票開始の待機時間 | 7,200ブロック(約1日) | トークン保有者が提案を確認し委任を調整する時間 |
votingPeriod |
投票の受付期間 | 50,400ブロック(約1週間) | 十分な参加率を確保しつつ迅速な意思決定 |
quorum |
投票成立に必要な最低参加率 | 4%(総供給量比) | 参加率が低すぎると攻撃に脆弱、高すぎると提案が通らない |
proposalThreshold |
提案に必要な最低トークン数 | 総供給量の0.1〜1% | スパム提案の防止 |
timelockDelay |
可決後の実行遅延 | 1〜2日 | 悪意のある提案への対応時間 |
よくある間違い:
votingDelayを0に設定するDAOが散見されますが、これはフラッシュローン攻撃のリスクを大幅に高めます。提案作成と同じブロックでトークンを大量取得し、即座に投票できてしまうためです。最低でも1ブロック、推奨は1日以上の遅延を設定してください。
提案のライフサイクルを理解する
提案の状態遷移を図示すると、以下のようになります。
投票には3つの選択肢があります。0 = Against(反対)、1 = For(賛成)、2 = Abstain(棄権)です。棄権はquorum(定足数。議決に必要な最低投票参加率で、フェデレーテッドラーニングの「最低参加ノード数」に相当する概念)にはカウントされますが、賛否の判定には影響しません。これにより「参加はするが立場を明確にしたくない」という選択が可能になります。
ハイブリッドガバナンスを構築する
実務では、すべての意思決定をオンチェーンで行うのはガスコスト(計算手数料)の観点から現実的ではありません。そこで多くのDAOが採用しているのが、オフチェーン投票(Snapshot)でシグナリング→オンチェーン投票(Tally/Governor)で拘束力のある実行というハイブリッドアプローチです。
MLシステムで例えると、「軽量モデルでスクリーニング(候補絞り込み)→重量モデルで最終判定」というカスケード推論と同じ発想です。コストの高い処理は本当に必要なときだけ使います。
Snapshotでガスレスのオフチェーン投票を実装する
Snapshotは、DAOのオフチェーン投票プラットフォームとして96%の市場シェアを持ちます。DAOtimesの2025年レポートによると、21,000以上のスペース、月間約60万アクティブユーザー、累計1,000万票以上が記録されています。
Snapshotの仕組み:
- トークン保有者がEIP-712署名メッセージを作成(ガス不要)
- 署名メッセージがIPFSに保存
- スナップショット時点のトークン残高で投票力を計算
- 投票結果はオフチェーンで集計
{
"space": "your-dao.eth",
"type": "single-choice",
"title": "トレジャリーからの助成金配分",
"body": "## 提案概要\n50 ETHを開発助成金として配分",
"choices": ["賛成", "反対", "棄権"],
"start": 1740700800,
"end": 1741305600,
"snapshot": 19500000,
"plugins": "{}",
"network": "1",
"strategies": [
{
"name": "erc20-balance-of",
"params": {
"address": "0xYourTokenAddress",
"decimals": 18
}
}
]
}
なぜSnapshotを使うのか:
- ガスコストゼロ: EIP-712署名のみで投票でき、トランザクション手数料が不要
- 400以上の投票戦略: ERC-20残高、NFT所有権、二次投票、委任投票など多様な戦略を組み合わせ可能
- 52チェーン対応: マルチチェーンでのトークン残高を統合して投票力を計算
制約条件: Snapshotの投票結果自体にはオンチェーンでの拘束力がありません。投票結果を実行に移すには、SafeSnapやoSnapプラグインを通じてオンチェーンのGovernorやGnosis Safeにブリッジする必要があります。
Snapshot Xによるオンチェーン投票の進化
2024年9月にローンチされたSnapshot Xは、Starknet上で完全オンチェーン投票を実現するプロトコルです。DAOtimesの報告によると、Ethereum L1の10〜50倍安価に投票が可能とされています。
ストレージプルーフ技術を活用し、Ethereum上のトークン残高をStarknet上で証明することで、クロスチェーンでの投票権検証を実現しています。2025年11月にリリースされたSpaces 2.0では、vote.yourdao.ethのようなカスタムドメイン対応も追加されました。
Tallyでオンチェーン実行を管理する
TallyはOpenZeppelin Governor互換のオンチェーン実行プラットフォームです。提案作成ウィザード、リアルタイム分析、投票ダッシュボードを提供し、300億ドル以上のプロトコルのガバナンスを支えています。
ハイブリッドガバナンスの典型的なフローは以下の通りです。
なぜハイブリッドなのか:
- コスト効率: 日常的な意思決定(シグナリング)はSnapshotでガスレスに実施
- セキュリティ: 資金移動を伴う重要な決定のみオンチェーンで拘束力を持たせる
- 参加率向上: ガスコスト不要のため投票のハードルが下がり、DAOの平均投票率が20%以下という課題の改善につながる
DAOのセキュリティ脅威と対策を実装する
DAOのセキュリティは、2016年のThe DAO Hack以来一貫して重要な課題です。Markaicodeの調査によると、2025年前半の6ヶ月間だけでDAOは合計7億8000万ドル以上のセキュリティ損失を被っています。
The DAO Hackから学ぶリエントランシー攻撃
2016年のThe DAO事件は、DAOセキュリティの歴史的な転換点です。Chainlinkの解説によると、攻撃者はリエントランシー(再入)脆弱性を利用して、1500万ETHのトレジャリー(共有金庫)から約360万ETH(当時6000万ドル相当)を窃取しました。
リエントランシー攻撃は、ML推論サービスにおける「コールバック中の状態不整合」に近い問題です。推論リクエストの処理中に別のリクエストが割り込み、まだ更新されていない古い状態を参照してしまうレースコンディションのようなものです。
攻撃の原理は以下の通りです。
// 脆弱なコード(The DAOと同等のパターン)
contract VulnerableDAO {
// mapping = Pythonの dict[str, int] に相当(アドレス→残高の対応表)
// public = 自動的にgetterが生成される(Pythonの @property に近い)
mapping(address => uint256) public balances;
// public = 誰でも呼び出せるメソッド
function withdraw() public {
uint256 amount = balances[msg.sender]; // msg.sender = 呼び出し元のアドレス
// ← ここで外部呼び出し: 攻撃コントラクトのreceive()が呼ばれる
// .call{value: amount}("") = ETHを送金する低レベル関数
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed"); // require = assert(失敗時にrevert)
// ← 残高更新が外部呼び出しの後!(これがバグ)
balances[msg.sender] = 0;
}
}
// 攻撃コントラクト
contract Attacker {
VulnerableDAO public target;
constructor(address _target) { // __init__ に相当
target = VulnerableDAO(_target);
}
// receive() = ETHを受け取ったときに自動実行されるコールバック関数
// external payable = 外部からETH付きで呼ばれる関数
receive() external payable {
if (address(target).balance >= 1 ether) {
// 残高がまだ更新されていないため、再度引き出し可能
// → これが「リエントランシー(再入)」攻撃
target.withdraw();
}
}
function attack() external payable {
target.withdraw();
}
}
対策: Checks-Effects-Interactions パターン
// 安全な実装(Checks-Effects-Interactions パターン)
// MLパイプラインの「入力検証→状態更新→外部API呼び出し」の順序と同じ考え方
contract SecureDAO {
mapping(address => uint256) public balances; // アドレス→残高の辞書
function withdraw() public {
uint256 amount = balances[msg.sender];
require(amount > 0, "No balance"); // 1. Checks: 条件確認(assert に相当)
// 2. Effects: 状態変更を先に実行(外部呼び出しの前に残高を0にする)
balances[msg.sender] = 0;
// 3. Interactions: 最後に外部呼び出し
// → 仮にreceive()から再度withdraw()が呼ばれても、残高はすでに0
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
2025年の主要なセキュリティ脅威と対策
ConsensysのレポートとMarkaicodeの分析に基づき、現在のDAOが直面する主要な脅威を整理します。
| 脅威 | 攻撃手法 | 損失事例(2025年) | 対策 |
|---|---|---|---|
| フラッシュローン攻撃 | 1トランザクション内でトークンを借入→投票→返却 | 6700万ドル | votingDelay設定、最低保有期間の導入 |
| ガバナンス攻撃 | 低参加率を悪用し少数トークンで提案可決 | - | 段階的quorum、二次投票の導入 |
| スマートコントラクト脆弱性 | 未チェックの外部呼び出し、整数オーバーフロー | 4200万ドル | 複数の独立監査、形式検証 |
| フィッシング | Discordでの管理者なりすまし→秘密鍵窃取 | 3700万ドル | ハードウェアウォレット必須、多段階認証 |
| クロスチェーン脆弱性 | ブリッジコントラクトのメッセージ検証欠陥 | 8900万ドル | チェーン別マルチシグ、専門監査 |
TimelockControllerによるセキュリティ層の実装
フラッシュローン攻撃への防御として、TimelockControllerは可決された提案の実行に遅延を設けます。MLパイプラインに例えると、モデルが承認された後もすぐに本番デプロイせず、カナリアリリース期間を設けて異常を検知する仕組みと同じです。この遅延期間中に、コミュニティは悪意のある提案に気づき、対策を講じることができます。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
// TimelockController = MLパイプラインの「ステージゲート」に相当
// 提案が可決されても、一定時間待ってから実行される安全装置
// ML例: モデル承認後、本番デプロイまでに24時間の監視期間を設けるのと同じ
contract DeployTimelock {
// external = 外部からのみ呼び出せる(internal/publicとの違い)
// returns (TimelockController) = 戻り値の型(Pythonの -> TimelockController に相当)
function deploy() external returns (TimelockController) {
uint256 timelockDelay = 1 days; // 1日の遅延(Solidityの時間リテラル)
// address[] memory = アドレスの配列(Pythonの list[str] に相当)
// new address[](1) = 要素数1の配列を初期化
address[] memory proposers = new address[](1);
proposers[0] = address(0); // 後でGovernorのアドレスを設定
address[] memory executors = new address[](1);
executors[0] = address(0); // address(0) = 「誰でも実行可能」を意味する特殊値
// new = 新しいコントラクトをデプロイ(インスタンスの作成)
TimelockController timelock = new TimelockController(
timelockDelay,
proposers,
executors,
msg.sender // 初期admin(デプロイ後にrenounceRole()で権限放棄が必須)
);
return timelock;
}
}
注意: TimelockControllerのadminロールは、デプロイ完了後に必ず
renounceRoleで放棄してください。adminロールを保持したままにすると、単一アドレスがTimelockのパラメータを変更できてしまい、ガバナンスの分散性が損なわれます。
セキュリティチェックリスト
DAOをデプロイする前に、以下の項目を確認してください。
-
votingDelay≥ 1ブロック(推奨: 7200ブロック = 約1日) -
quorum≥ 4%(DAOの規模に応じて調整) -
timelockDelay≥ 1日(重要な資金操作は2日以上) - TimelockControllerのadminロールがrenounce済み
- Checks-Effects-Interactions パターンの適用
- 複数の独立したセキュリティ監査の実施
- バグバウンティプログラムの設置
- 緊急停止メカニズム(Emergency Pause)の実装
トレジャリー管理とマルチシグを設計する
DAOのトレジャリー(共有金庫。DAOが保有する暗号資産の保管庫)は、ガバナンスと直結する重要な設計要素です。Aragonのデータによると、同プラットフォームだけで60億ドルのアクティブトレジャリーが管理されています。
マルチシグによる実行管理
大規模なDAOでは、オンチェーン投票の結果をマルチシグウォレット(複数人の署名が必要なウォレット。Gnosis Safe等)で実行するケースが一般的です。AWSのIAMで「特定の操作には複数人の承認が必要」と設定するのと同じ発想です。
典型的な構成:
- 署名者: 9名(コア貢献者、コミュニティ代表、外部アドバイザー)
- 閾値: 5-of-9(過半数以上)
- 日常的な支出($10,000未満): 3-of-9で実行可能
- 大規模な支出($10,000以上): Snapshot投票で60%以上の承認 + 5-of-9で実行
トレードオフ: マルチシグの閾値を低く設定すると実行の迅速性が上がりますが、セキュリティリスクも高まります。Consensysのレポートでは、2-of-3のマルチシグは「容易に悪用可能」と指摘されています。最低でも3-of-5、推奨は5-of-9以上の閾値を設定してください。
トークナイズドUS Treasury(2026年の新トレンド)
OnChain Treasuryの報告によると、2026年1月時点でトークナイズドUS Treasuryの市場規模は86.6億ドルに達しています。BUIDL、BENJI、USDY等のトークナイズドT-Bills(短期国債)をDAOトレジャリーに組み込むことで、オンチェーンのプログラマビリティを維持しつつ安定利回りを得る戦略が注目されています。
ただし、トークナイズド国債には規制リスク(各法域での証券規制への該当可能性)と流動性リスク(償還までの拘束期間)が存在するため、トレジャリー全体の一部(20〜30%程度)に留めることが推奨されています。
日本における法規制とDAOの法的位置づけを理解する
日本でDAOを運営する場合、法的な枠組みの理解が不可欠です。
合同会社型DAOの法制度
EMURGOの報告によると、日本政府は合同会社(LLC)型DAOの設立を可能にする法律を承認しました。これにより以下が実現しています。
- NFTによる無制限の資本調達: 既存金融法の緩和により、メンバーシップNFTを通じた資金調達が可能
- オンチェーン意思決定の法的承認: すべての意思決定をブロックチェーン上で実施・記録可能
- 日本DAO協会: DAOの認知度向上と開発を推進する公的組織が設立
法的リスクと注意点
Monolith Lawの分析では、以下の法的リスクが指摘されています。
| 法律 | 適用条件 | リスク |
|---|---|---|
| 金融商品取引法 | 配当付きトークンの販売 | 第一種金融商品取引業の登録が必要 |
| 資金決済法 | 暗号資産としてのトークン発行 | 暗号資産交換業の登録が必要 |
| 税法 | ガバナンストークンの取得・売却 | 法人税・所得税の対象 |
実務上の注意点:
- ガバナンストークンに配当機能を付与する場合、金融商品取引法の規制対象となる可能性が高い
- サービストークンや貢献トークンの法的分類はまだ明確でないため、法務専門家への相談が必須
- 税務上の取り扱い(特にトークンのエアドロップや報酬の課税タイミング)については、国税庁のFAQを確認すること
制約条件: この法的情報は2026年2月時点のものです。暗号資産・DAOに関する法規制は頻繁に変更されるため、実際のDAO運営にあたっては必ず最新の法令と専門家の助言を確認してください。
よくある問題と解決方法
| 問題 | 原因 | 解決方法 |
|---|---|---|
| 投票力が0と表示される | トークン保有者が自身にdelegateしていない |
token.delegate(msg.sender) を実行 |
| 提案が即座にDefeatedになる | quorumが高すぎる or トークン分配が不均等 | quorumを下げる or トークン配布を見直す |
| execute()がrevert | timelockDelayが経過していない |
block.timestamp を確認し待機 |
| フラッシュローンで投票される | votingDelayが0 | votingDelayを7200ブロック以上に設定 |
| Snapshot投票が反映されない | オフチェーン投票にオンチェーンの拘束力がない | SafeSnapプラグインでオンチェーンにブリッジ |
| ガバナンス提案のスパム | proposalThresholdが低すぎる | 総供給量の0.1〜1%をthresholdに設定 |
まとめと次のステップ
まとめ:
- DAOのオンチェーンガバナンスにはOpenZeppelin Governor(ERC20Votes + Governor + TimelockController)が業界標準として確立されている
- 実務ではSnapshot(オフチェーン)+ Tally(オンチェーン)のハイブリッドガバナンスが標準的なアーキテクチャとなっている
- 2025年のセキュリティ損失は7億8000万ドルを超えており、
votingDelayの適切な設定、TimelockControllerの導入、複数の独立監査が不可欠 - 日本では合同会社型DAOが法的に認められているが、配当付きトークンは金融商品取引法の規制対象となる可能性がある
- DAOの平均投票率は20%以下であり、投票インセンティブ設計と委任メカニズムの活用が課題
次にやるべきこと:
- OpenZeppelin Contracts WizardでガバナンストークンとGovernorの初期コードを生成し、テストネット(Sepolia等)にデプロイしてみる
- Snapshotでテスト用スペースを作成し、オフチェーン投票の流れを体験する
- TallyにデプロイしたGovernorを登録し、提案・投票・実行のライフサイクルを一通り確認する
用語集
本記事で登場するブロックチェーン関連用語を、AI/MLの類似概念とともにまとめます。
| 用語 | 説明 | AI/MLでの類似概念 |
|---|---|---|
| ブロックチェーン | 分散型の改ざん不可能な台帳 | Git + 分散ファイルシステム |
| Ethereum | プログラム実行可能なブロックチェーン | 分散型クラウドコンピューティング |
| スマートコントラクト | ブロックチェーン上の自動実行プログラム | MLパイプライン(条件ベース自動実行) |
| Solidity | スマートコントラクト記述言語 | Python(文法の対応表は基礎知識セクション参照) |
| ガス(Gas) | 計算実行コスト(ETHで支払い) | GPU課金(計算量に応じた従量課金) |
| ERC-20 | トークンの標準規格 | ABCクラス(共通インターフェース定義) |
| ガバナンストークン | DAO内での投票権を表すトークン | アクセストークン + 重み付き投票権 |
| ウォレット | 秘密鍵を管理するアプリケーション | SSH鍵管理ツール |
| アドレス | ブロックチェーン上のアカウント識別子 | GitHubユーザーID |
| トランザクション | ブロックチェーンへの状態変更リクエスト | APIリクエスト |
| デプロイ | コントラクトをブロックチェーンに配置 | モデルを本番環境にデプロイ |
| オンチェーン | ブロックチェーン上で実行・記録 | 本番APIエンドポイントでの推論 |
| オフチェーン | ブロックチェーン外で実行 | ローカルGPUでの推論 |
| テストネット | 開発・テスト用ネットワーク | ステージング環境 |
| メインネット | 本番ネットワーク | プロダクション環境 |
| Faucet | テスト用ETHを無料配布するサービス | 無料枠のGPUクレジット |
| トレジャリー | DAOの共有金庫 | プロジェクトの共有予算 |
| マルチシグ | 複数署名が必要なウォレット | IAMの多段階承認 |
| フラッシュローン | 1トランザクション内で完結する無担保ローン | (ブロックチェーン固有、ML対応なし) |
| リエントランシー | 関数の再入による脆弱性 | レースコンディション |
| quorum(定足数) | 議決に必要な最低投票参加率 | 連合学習の最低参加ノード数 |
| TimelockController | 実行遅延を設ける安全装置 | カナリアリリース / ステージゲート |
| delegate(委任) | 投票権を他者に委ねること | プロキシ(代理実行) |
| Snapshot | オフチェーン投票プラットフォーム | 軽量モデルでのスクリーニング |
| Tally | オンチェーン実行プラットフォーム | 重量モデルでの最終判定 |
参考
- 分散型自律組織(DAO) - Ethereum.org
- How to set up on-chain governance - OpenZeppelin Docs
- Governor.sol - OpenZeppelin GitHub
- Snapshot DAO Tool Report For 2025 - DAOtimes
- Aragon DAO Tool Report For 2025 - DAOtimes
- OpenZeppelin Governor - Tally Docs
- Top 5 DAO Security Pitfalls in 2025 - Markaicode
- The State of DAO Security - Consensys
- Reentrancy Attacks and The DAO Hack Explained - Chainlink
- What is the Japan DAO Law? - EMURGO
- DAO in the Web 3.0 Era: Legal Issues - Monolith Law
- Tokenized US Treasuries for DAO Treasuries - OnChain Treasury
注意: この記事はAI(Claude Code)により自動生成されました。内容の正確性については複数の情報源で検証していますが、実際の利用時は公式ドキュメントもご確認ください。