はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、DAOガバナンス投票における投票誘導型のインセンティブを安全かつ透明に行う仕組みを提案しているERC6506についてまとめていきます! 特定の提案に特定の方向で投票することを条件に報酬を提供し、それが実際に行われたかをオンチェーンまたはオフチェーンで検証し、検証に成功した場合のみ報酬を支払う仕組みを実現します。

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIPについてまとめています。

概要

ERC6506では、DAO(分散型自律組織)における投票のインセンティブを透明かつ安全に行うための標準的なスマートコントラクトのインターフェースを定義します。 目的は、特定の投票方向を選んでもらう代わりにインセンティブを提供し、投票内容を検証できるまで資金をエスクロー(預かり)する仕組みを構築することです。

ERC6506は、投票における直接的なインセンティブ提供(OTC形式)を通じて、既存プロトコルの報酬分配の非効率性や中央集権的な仕組みといった問題を解決しようとしています。

動機

DAOの投票においてブレイブ(報酬付き投票依頼)を提供する行為はすでにCurveやFraxなどで広く行われていますが、一般的なDAOの提案に対してもブレイブは有効です。 しかし、現状には複数の課題があります。

非効率な分配方式

現行の「投票量に比例して分配される」方式では、大口の投票者が後出しで投票することで、小口のインセンティブ受取者が期待した報酬を受け取れない可能性があります。 これにより、最適な意思決定が損なわれます。

中央集権的なプロトコル

既存のブレイブプロトコル(VotiumやHidden-Handなど)は、中央管理者がインセンティブを分配する構造になっており信頼が必要です。 これはDAOの分散性に反します。

信頼ベースのやり取り

当事者同士が信頼に基づいて取引しなければならず、第三者なしでのエスクロー契約作成が困難です。 これによりブレイブの実行障壁が高くなっています。

オフチェーンの不透明な共謀

大口投票者と第三者がオフチェーンで取引を行うと透明性がなくなり、コミュニティ全体からの監視が不可能になります。

個人への負担と中央集権化

ブレイブを受け取るには、交渉・連絡手段の開示・エスクロー契約の作成など、煩雑なプロセスが必要です。 これをこなせる一部の人に利益が集中し、投票の公正性が損なわれます。

賄賂収益の再分配(補助金化)

Vitalik Buterinが提唱したように、悪い提案がブレイブによって可決された場合でも、その影響をトークンの買い戻しなどで全体に還元することが可能です。 これにより、ブレイブによる不正な投票操作のコストが増し、受け手側の収益性も高まります。

仕様

用語

  • BRIBE / INCENTIVE
    • ユーザーAがユーザーBに対して、特定のDAO提案に対し指定された方向で投票することを条件にデジタル資産を提供する行為。
    • 条件が履行されなければ、資産は返却されます。
  • BRIBER / SENDER / INCENTIVIZER
    • インセンティブを提供する側(ユーザーA)。
  • RECIPIENT / VOTER / INCENTIVIZEE
    • 投票を行い、条件を満たした場合に報酬を受け取る側(ユーザーB)。
  • VOTE
    • アカウントベースのガバナンス投票全般を指します。

コアインターフェースの仕様

この提案では、以下のようなスマートコントラクトインターフェース IEscrowedGovIncentive を実装することが求められています。

IEscrowedGovIncentive.sol
interface IEscrowedGovIncentive {

  struct incentive {
    address incentiveToken;
    address incentivizer;
    address recipient;
    uint amount;
    uint256 proposalId;
    bytes32 direction; //the keccack256 of the vote direction
    uint96 deadline;
    uint96 timestamp;
    bool claimed;
  }

  event incentiveSent(address indexed incentivizer, address indexed token, uint256 indexed amount, address recipient, bytes data);

  event incentiveReclaimed(address incentivizer, address indexed recipient, address indexed token, uint256 indexed amount, bytes data);

  event modifiedClaimer(address recipient, address claimer, bool direction);

  event incentiveClaimed(address indexed incentivizer, address voter, bytes32 incentiveId, bytes proofData);

  event disputeInitiated(bytes32 indexed incentiveId, address indexed plaintiff, address indexed defendant);

  event disputeResolved(bytes32 indexed incentive, address indexed plaintiff, address indexed defendant, bool dismissed);


  //Core mechanism
  function incentivize(bytes32 incentiveId, bytes memory incentiveInfo) external payable;

  function claimIncentive(bytes32 incentiveId, bytes memory reveal, address payable recipient) external;
  
  function reclaimIncentive(bytes32 incentiveId, bytes memory reveal) external;
  
  function verifyVote(bytes32 incentive, bytes memory voteInfo) external view returns (bool isVerifiable, bytes proofData);

  function modifyClaimer(address claimer, bool designation) external;

  //Dispute Mechanism
  function beginDispute(bytes32 incentiveId, bytes memory disputeInfo) external payable;

  function resolveDispute(bytes32 incentiveId, bytes memory disputeResolutionInfo) external returns (bool isDismissed);

}

構造体

incentive構造体は、投票インセンティブに関する情報を持ちます。 投票方向は keccak256 でハッシュ化されており、透明性を持たせつつ識別性も確保しています。

関数

  • incentivize
    • インセンティブを設定・ロックする関数。
  • claimIncentive
    • インセンティブの条件が満たされたとき報酬を請求する関数。
  • reclaimIncentive
    • 条件が満たされなかった場合資金を回収する関数。
  • verifyVote
    • 投票内容の検証を行う関数。
  • modifyClaimer
    • 受領者を第三者に変更する関数。
  • beginDispute / resolveDispute
    • 紛争が発生した時の紛争解決の仕組みを提供する関数。

オプション実装例

ERC6506では、インセンティブ付き投票の透明性・秘匿性・互換性に応じた3つの実装モデルが提案されています。 これらは、用途やDAOの運用スタイルに応じて選択可能です。

完全な透明性モデル

この実装では、インセンティブのすべての情報(投票方向・報酬額・受取人)が常に公開されます。 データはプレーンテキストの形式で calldata としてコントラクトに渡され、そのままストレージに保存されるかイベントとして発行されます。

この方式は高い透明性を提供し、誰でもオンチェーン上でインセンティブの内容を確認できますが、受取人の匿名性や意思決定の秘匿性は確保されません。

完了時までの秘匿モデル(Opacity Until Completion, OUC)

このモデルでは、インセンティブが請求されるまで、受取人・投票方向・金額といった情報が秘匿されます。

インセンティブ情報は受取人の公開鍵で暗号化され、コントラクトにはその暗号化データが渡されます。 コントラクトはこれをそのままイベントとして発行し、受取人はオフチェーンで復号することで内容を確認できます。

資金の秘匿送金には、CREATE2 オペコードを用いた決定論的アドレス生成などの手法を使い、第三者からの追跡を困難にします。

受取人が報酬を請求する時には、ハッシュ化されたコミットメントを公開してそれに基づいてオンチェーンで整合性が確認されれば報酬が支払われます。

オフチェーン投票との互換性

多くのDAOではSnapshotのようなオフチェーンプラットフォームを使って投票が行われます。 ERC6506では、このようなオフチェーン投票との互換性も考慮されています。

実行フローの例

  1. ユーザーAがユーザーBに対して、Snapshot上の特定提案への投票に対するインセンティブをロックします。
  2. Bが実際に投票します。
  3. 投票締切後、一定期間のチャレンジウィンドウが始まります。
  4. Aは、この期間内に「Bが約束通りに投票しなかった」という証拠(例:逆方向の署名済みメッセージ)を提出できます。
  5. 証明が成功すれば、資金はAに返還されます。提出されなければBが報酬を受け取れます。

このチャレンジ期間が設けられている理由は、Bが署名のみ行って投票をブロードキャストせずに報酬だけ受け取ることを防ぐためです。

もしBがまったく投票しなかった場合、Aは「Bが投票していない」ことを直接証明できません。 その場合、Aは「特別な紛争期間」に移行できます。 この紛争処理には以下のような方法が考えられます。

  • 信頼できる第三者による裁定
  • 投票者リストにBが含まれていないことを証明するMerkle rootの提示

どの方式を採用するかは、実装するコントラクトに依存します。

構造体

incentive

javascript
struct incentive {
  address incentiveToken;
  address incentivizer;
  address recipient;
  uint amount;
  uint256 proposalId;
  bytes32 direction;
  uint96 deadline;
  uint96 timestamp;
  bool claimed;
}

投票インセンティブ情報を記録する構造体。 インセンティブ提供者、受取者、金額、提案ID、投票方向(ハッシュ化)、締切時間など、インセンティブの詳細情報を保持します。

パラメータ

  • incentiveToken
    • 支払いに使用されるERC20トークンのアドレス。
  • incentivizer
    • インセンティブを提供したユーザーのアドレス。
  • recipient
    • インセンティブの受取予定者。
  • amount
    • インセンティブの金額。
  • proposalId
    • 対象となる提案のID。
  • direction
    • 投票方向を表すkeccak256ハッシュ値。
  • deadline
    • インセンティブ有効期限(UNIXタイム)。
  • timestamp
    • インセンティブが作成されたタイムスタンプ。
  • claimed
    • インセンティブがすでに請求されたかを示すフラグ。

関数

incentivize

javascript
function incentivize(bytes32 incentiveId, bytes memory incentiveInfo) external payable

インセンティブを登録する関数。 インセンティブ提供者が、投票インセンティブを事前に登録・デポジットします。 OUCモードでは一部データだけが公開されます。

引数

  • incentiveId
    • インセンティブを一意に識別するID(ハッシュ値など)。
  • incentiveInfo
    • インセンティブ内容を含むエンコード済みデータ。

claimIncentive

javascript
function claimIncentive(bytes32 incentiveId, bytes memory reveal, address payable recipient) external

インセンティブを請求する関数。 インセンティブの対象となるユーザーが、インセンティブを受け取るために使用します。 条件に合致しない場合は revert されます。

引数

  • incentiveId
    • 対象のインセンティブID。
  • reveal
    • コミットされた内容を復元するための証拠データ。
  • recipient
    • 実際の報酬受取人(受取代理人も可)。

reclaimIncentive

javascript
function reclaimIncentive(bytes32 incentiveId, bytes memory reveal) external

不履行時にインセンティブを回収する関数。 投票が条件を満たさなかった場合、インセンティブ提供者が資金を回収するために呼び出します。

引数

  • incentiveId
    • 対象のインセンティブID。
  • reveal
    • 不履行を証明するためのデータ。

verifyVote

javascript
function verifyVote(bytes32 incentiveId, bytes memory voteInfo) public view returns (bool isVerified, bytes memory proofData)

投票内容を検証する関数。 インセンティブ対象者が条件に合った投票をしたかを検証します。

引数

  • incentiveId
    • 対象のインセンティブID。
  • voteInfo
    • 投票内容に関する情報。

戻り値

  • isVerified
    • 投票が条件に一致していたかを示す真偽値。
  • proofData
    • 検証に使用された証拠データ。

modifyClaimer

javascript
function modifyClaimer(address claimer, bool designation) external

代理受取人の許可を設定する関数。 受取人が第三者にインセンティブの代理請求権を与えるか、取り消すために使用します。

引数

  • claimer
    • 代理人となるアドレス。
  • designation
    • 許可(true)または取り消し(false)を指定。

beginDispute

javascript
function beginDispute(bytes32 incentiveId, bytes memory disputeInfo) external payable

紛争を開始する関数。 インセンティブに関する意見の不一致を処理するための、裁定プロセスの起点となる関数です。

引数

  • incentiveId
    • 対象のインセンティブID。
  • disputeInfo
    • 紛争の証拠や追加データ。

resolveDispute

javascript
function resolveDispute(bytes32 incentiveId, bytes memory disputeResolutionInfo) external returns (bool isDismissed)

紛争を解決する関数。 開始された紛争に対して、条件に応じて資金の返還または支払いを決定します。

引数

  • incentiveId
    • 対象のインセンティブID。
  • disputeResolutionInfo
    • 解決のための証拠やメタ情報。

戻り値

  • isDismissed
    • 紛争が却下されたか(trueなら被告の勝利)。

イベント

incentiveSent

javascript
event incentiveSent(address indexed incentivizer, address indexed token, uint256 indexed amount, address recipient);

インセンティブが送信された時に発行されるイベント。 インセンティブ提供者が、投票インセンティブの詳細をコントラクトに記録した際に発行されます。 OUC(秘匿モード)では、受取人や金額はゼロにされることがあります。

パラメータ

  • incentivizer
    • インセンティブを送ったユーザーのアドレス。
  • token
    • 支払いに使われたトークンのアドレス。
  • amount
    • インセンティブの金額。
  • recipient
    • 指定された受取人のアドレス。

incentiveClaimed

javascript
event incentiveClaimed(address indexed recipient, address indexed token, uint256 indexed amount, bytes data);

インセンティブが請求された時に発行されるイベント。 インセンティブ対象者が報酬を受け取ったときに発行され、どのトークンがどれだけ送られたかが記録されます。

パラメータ

  • recipient
    • 報酬を受け取ったアドレス。
  • token
    • トークンのアドレス。
  • amount
    • 請求された金額。
  • data
    • 補足情報や証明データ。

modifiedClaimer

javascript
event modifiedClaimer(address recipient, address claimer, bool direction);

インセンティブ請求代理人の設定変更時に発行されるイベント。 受取人が代理人の登録または削除を行ったときに発行されます。

パラメータ

  • recipient
    • 対象となる元の受取人。
  • claimer
    • 登録・削除された代理人。
  • direction
    • true なら登録、false なら削除。

incentiveReclaimed

javascript
event incentiveReclaimed(address indexed incentivizer, address indexed voter, bytes32 incentiveId, bytes proofData);

インセンティブが回収されたときに発行されるイベント。 受取人が条件を満たさなかった場合に、提供者が資金を取り戻したことを示します。

パラメータ

  • incentivizer
    • インセンティブを送ったアドレス。
  • voter
    • 投票したはずの受取人。
  • incentiveId
    • 対象となるインセンティブのID。
  • proofData
    • 不履行を示す証明データ。

disputeInitiated

javascript
event disputeInitiated(bytes32 incentiveId, address plaintiff, address defendant);

インセンティブに関する紛争が開始されたときに発行されるイベント。 双方の間で意見の相違が発生し、裁定を求めるリクエストが提出されたときに使用されます。

パラメータ

  • incentiveId
    • 対象のインセンティブID。
  • plaintiff
    • 原告(通常はインセンティブ提供者)。
  • defendant
    • 被告(インセンティブ受取人)。

disputeResolved

javascript
event disputeResolved(bytes32 incentiveId, address plaintiff, address defendant, bool dismissed);

インセンティブに関する紛争が解決された時に発行されるイベント。 裁定によってどちらに資金を配分するかが決まり、その結果が反映されたことを示します。

パラメータ

  • incentiveId
    • 対象のインセンティブID。
  • plaintiff
    • 紛争を提起した側。
  • defendant
    • 被告。
  • dismissed
    • 被告が勝訴したかどうか(trueで勝訴)。

JSON ABIスキーマ(イベント部分)

以下は incentiveClaimed の例です。他イベントも同様に展開可能です。

json
{
  "anonymous": false,
  "inputs": [
    { "indexed": true, "internalType": "address", "name": "recipient", "type": "address" },
    { "indexed": true, "internalType": "address", "name": "token", "type": "address" },
    { "indexed": true, "internalType": "uint256", "name": "amount", "type": "uint256" },
    { "indexed": false, "internalType": "bytes", "name": "data", "type": "bytes" }
  ],
  "name": "incentiveClaimed",
  "type": "event"
}

シーケンス図

以下は、インセンティブの発行から請求、検証、紛争処理までの一連の流れを表したシーケンス図です。

sequenceDiagram
  participant A as インセンティブ提供者(User A)
  participant B as 投票者・受取人(User B)
  participant C as スマートコントラクト
  participant D as 紛争裁定者(任意)

  A->>C: incentivize(incentiveId, incentiveInfo)
  C-->>A: event: incentiveSent

  B->>C: claimIncentive(incentiveId, reveal, B)
  alt 投票内容が一致する
    C-->>B: トークン送付
    C-->>B: event: incentiveClaimed
  else 投票内容が不一致
    A->>C: reclaimIncentive(incentiveId, reveal)
    C-->>A: トークン返還
    C-->>A: event: incentiveReclaimed
  end

  alt 紛争が発生
    A->>C: beginDispute(incentiveId, disputeInfo)
    C-->>C: event: disputeInitiated

    D->>C: resolveDispute(incentiveId, disputeResolutionInfo)
    C-->>C: event: disputeResolved
  end

補足

投票インセンティブの透明化と分散化の必要性

投票に対してインセンティブ(いわゆるブレイブ)の提供は、DAOにおいて避けられません。 ユーザー同士がオフチェーンで特定の投票方向に合意し、外部からはその実態を完全に隠蔽することが可能である以上、これを禁止することは現実的ではありません。

したがって、解決すべきは「行為の存在」ではなく、「その透明性と公正な再配分」です。

FlashbotsはMEV(最大抽出可能価値)を完全に防ぐことができない中で、MEVを可視化・分配する手段として登場しました。 同様に、ERC6506はブレイブの存在を前提とした上で、誰もがその市場に参加できるOTC型のブレイブ市場を整備することで、公平性と効率性を両立させようとするものです。

公開によるコミュニティの反応促進と受益者の公平化

誰が誰にどのような条件でインセンティブを渡しているのかをオンチェーン上で可視化することにより、以下が期待されます。

  • コミュニティが不自然な投票行動を検知しやすくなる。
  • インセンティブの金額と投票方向が明らかになるため、他の参加者も対抗的な提案や報酬を提示しやすくなる。
  • 受益者が限られた「上級者」だけでなく、誰もが対価を得られる機会が広がる。

実装の基本的なイメージ

以下のようなシナリオを想定しています。

AliceがBobに対して「DAO提案 #420 にYES票を入れてくれたら10ドル渡す」と約束したい。ただし、Bobが実際にYES票を投じたことが確認できない限り、資金を支払いたくない。

このような取引に対応するため、ERC6506に準拠したコントラクトはエスクロー機能を持ち、投票後に検証が完了して初めて資金が移動します。 信頼できる第三者を必要とせず、オンチェーンとオフチェーン(Snapshotなど)の両方に対応可能です。

また、秘匿性を担保するために受取人や金額を暗号化する設計も選択肢として許容されています。

コア要件:健全性と完全性

この仕組みが満たすべき要件は以下です。

  • 健全性(Soundness)
    • インセンティブ対象者が条件に沿った投票を行った場合にのみ資金が支払われる。
  • 完全性(Completeness)
    • 条件に沿った投票を行っていない者には、いかなる方法でも資金を受け取る手段が存在しない。

技術的補足:コミットメントスキームの活用

提案が投票期間中に変更できないよう、ブレイブ情報はハッシュ化されたコミットメントとして事前に固定されます。 投票が終了するまでは、提供者はそのインセンティブを取り消すことができず、正しいエスクロー状態が維持されます。

潜在的な倫理的論点とその反論

「お金で投票を誘導することの倫理性」が問題視されることがありますが、ERC6506はその是非ではなく、「何もしないことで起こる問題」への対応策として設計されています。

何も対策しない場合のリスク

  • フライホイール効果 大規模な資産保有者のみが効率的にブレイブを獲得し続け、投票権力が一極集中していきます。結果としてDAO運営の中立性が損なわれます。

  • 透明性の欠如 投票の背後にある意図や対価が見えず、正当な提案が通らなかったり、不当な提案が通過する可能性が高まります。コミュニティの意思が正しく反映されなくなります。

セキュリティ

ガバナンスシステム全体の安全性が前提

ERC6506は既存のガバナンスシステムと連携して動作することを前提とした仕様です。 そのため、基盤となるガバナンスシステムに脆弱性がある場合、ERC6506の仕組みにも直接的な影響が及びます**。

たとえば以下のような既知のリスクが想定されます。

  • 投票権の水増しやマニピュレーション
  • 投票データの改ざんや偽造
  • オフチェーン投票結果との照合失敗(Snapshot等)
  • 投票内容の検証手順が不完全であることによる不正なインセンティブ請求

このようなリスクが存在する場合、誤った相手にインセンティブが支払われるなど、資産流出につながる恐れがあります。 そのため、統合先のDAOプロトコルやガバナンスロジック全体のセキュリティ監査は必須です。

暗号技術の正確な実装が必要

この仕様に基づく実装には、以下のような暗号的処理が含まれる可能性があります。

  • デジタル署名の検証(投票内容や本人性の確認)
  • SNARKなどゼロ知識証明の導入
  • 暗号化されたデータの復号(OUCモデルにおける受取人情報など)
  • コミットメントとオープニングの正当性検証

これらの処理は高度な技術を要求し、誤実装によって「秘匿性が失われる」、「不正請求を防げない」、「署名の再利用(リプレイ攻撃)が可能になる」といった深刻な問題が発生する可能性があります。

そのため、以下の対策が推奨されます。

  • 暗号アルゴリズムの使用においては、既存の実績あるライブラリを利用する。
  • オフチェーン・オンチェーンを問わず署名検証ロジックは再利用可能な形で書かれ、外部からも再現可能な仕様にしておく。
  • 署名の一意性確保(nonceやproposalIdの活用)によるリプレイ攻撃の回避。
  • OUC(完了時までの秘匿)モデルでの暗号鍵管理と復号の検証手順は、堅牢な方式で設計する。

実装時の留意点

この標準仕様自体はあくまで枠組みを定義しており、具体的な検証方式や実装方針はプロトコルごとに任されています。 そのため、セキュリティ確保は各プロジェクトの実装レベルに委ねられている点に注意が必要です。

十分な検証と安全性の確保がなければ、結果として本来のブレイブ(インセンティブ)モデルが機能せず、DAO全体のガバナンスが歪む危険があります。

引用

Josh Weintraub (@jhweintraub), "ERC-6506: P2P Escrowed Governance Incentives [DRAFT]," Ethereum Improvement Proposals, no. 6506, February 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6506.

最後に

今回は「DAOガバナンス投票における投票誘導型のインセンティブを安全かつ透明に行う仕組みを提案しているERC6506」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!