はじめに
初めまして。
『DApps開発入門』という本や色々記事を書いているかるでねです。
以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!
AIエージェントが作った成果物を、別のAIエージェントに評価させる場面が増えています。
ただし、1人の判定者へ任せると、その判定者の停止や偏りが作業の受入れ結果を決めてしまいます。
ERC8436は、複数の主体による投票、判断できなかった結果、異議申立て、業務処理への反映を1つのオンチェーン手続きとして記録する規格です。
誰が投票できるかと、誰が資産や作業状態を変更できるかを分けます。
2026年10月16日時点では Draft です。
仕様、全 API、公式参考実装、公式テストベクタ、導入時の安全性を解説します。
概要
ソフトウェア開発を依頼し、AIエージェントから成果物が提出された場面を考えます。
発注者は、1人の評価者ではなく、技術面を確認する5人のAIエージェントに受入れ判断を頼みたいとします。
3人以上が承認すれば成果物を受け入れ、3人以上が反対すれば拒否します。
単に投票結果だけを記録しても、発注者の作業コントラクトが投票結果に従うとは限りません。
評価者の評判や保有トークンは投票資格の根拠になっても、発注者の資産や作業状態を変更する権限にはならないためです。
必要票へ届かなかった場合を承認または拒否へ読み替えると、同じ投票から実装ごとに異なる結果も生まれます。
そこでERC8436は、参加者、必要票、制限時間、異議申立ての回数を投票前に固定します。
この固定した投票規則を Decision Policy と呼びます。
同じ成果物について、同じ質問を、固定した規則で判定する一連の記録が Issue です。
投票結果を業務処理へ反映すると事前に約束するコントラクトまたはアカウントを consumer と呼びます。
consumer は、承認時の処理、拒否時の処理、必要票へ届かなかった時の処理を投票前に固定します。
賛成でも反対でもない結果は NoDecision として残り、 consumer が事前に指定した既定処理へ渡されます。
投票では、各参加者が同じ Issue、同じ round、同じ判断グループへ1票だけ提出します。
必要票が集まるか投票時間が終了すると、そのグループの判断が決まります。
複数のグループを使う場合は、技術面と経済面の両方が賛成した時だけ承認する構成や、拒否権 Body が approve ballot を出した時に全体を止める構成も作れます。
最初の判断に異議申立てがあれば、新しい round を開始します。
異議申立て後に必要票へ届かなかった時、前回の判断を残すか、全体を NoDecision にするかも投票前の規則へ含めます。
最終結果が確定した後だけ、 consumer が自分の権限で成果物の受入れまたは拒否を実行します。
複数人で作業成果を判定する場面
5人中3人の承認を求める場合、同じ成果物と質問を5人へ渡します。
各参加者は、自分が確認した内容に基づいて賛成または反対を提出します。
3票の賛成が集まれば Yes、3票の反対が集まれば No です。
期限までに賛成が2票、反対が2票、未投票が1人なら、どちらの条件にも届きません。
ERC8436は、賛否どちらの必要票にも届かなかった投票を NoDecision として記録します。
未達を自動で拒否へ変換しないため、発注者は投票開始前に**NoDecision なら既存の納期処理へ戻す**と決められます。
結果を受け入れる相手
投票参加者は判断を作りますが、作業報酬や成果物の状態を変更しません。
作業コントラクトを操作できる consumer だけが、最終結果を業務処理へ反映します。
consumer は、 Issue を自分で作る、事前の受入れ条件を登録する、第三者が作った Issue を投票前に承認する、のいずれかで約束を固定します。
この投票前の約束を Consumer commitment と呼びます。
約束が成立した Issue は Binding です。
約束がない Issue は Advisory として判断記録を残せますが、業務処理を拘束しません。
投票開始から業務処理まで
発注者側の adapter は、作業コントラクトから成果物、期限、承認時と拒否時の処理を読み取って Issue を作ります。
Issue Registry は、固定済みの投票規則と consumer の約束を確認して最初の round を開始します。
参加者の投票、必要票の判定、異議申立てを経て、最終結果を保存します。
最終結果が Yes なら adapter が作業コントラクトの受入れ関数を呼び、 No なら拒否関数を呼びます。
呼び出しに失敗しても投票結果は変わりません。
consumer は失敗を実行記録へ残し、作業コントラクトの条件が許す範囲で再試行します。
動機
複数の署名を集める仕組みや、トークン保有者が提案へ投票する仕組みはすでにあります。
しかし、具体的な成果物と質問、結果に従う consumer、必要票へ届かなかった結果、異議申立て、業務処理の成否までを同じ記録へ結び付けるには、追加の約束が必要です。
1人の評価者だけを指定する作業コントラクトでは、評価者の停止がそのまま処理停止になります。
複数の投票者を置いても、投票者と業務実行者の権限を分けなければ、評価資格を持つ主体が発注者の資産まで動かせる設計になります。
ERC8436は、判断を作る手続きと判断を実行する権限を分離します。
投票規則と consumer の約束を先に固定し、投票後に都合のよい結果だけを採用する余地も狭めます。
既存の投票部品で欠ける記録
| 方式 | 質問と対象 | NoDecision |
複数グループ | 異議申立て | 業務処理との接続 |
|---|---|---|---|---|---|
multisig |
呼び出し内容へ埋め込む | 個別設計 | 単一の署名者集合 | 個別設計 | 署名成立で直接実行する |
governor |
提案ごとに持つ |
quorum 未達として扱う |
通常は1つの選挙人集合 | 個別設計 | 提案の実行へ接続する |
単一 evaluator
|
作業ごとに持つ |
evaluator の応答規則次第 |
持たない | 個別設計 | 作業コントラクトが結果を読む |
| ERC8436 |
Issue へ固定する |
独立した正式結果 |
Body ごとに分離する |
Policy へ固定する |
consumer が自分の権限で実行する |
ERC8436が必要になるのは、投票数だけでなくどの質問を、誰の判断で、どの業務へ反映するかを再現したい場合です。
投票資格と実行権限の分離
投票資格は、固定された参加者一覧や、特定の報告者として Policy へ入ります。
一方、業務実行権限は consumer がすでに持つ権限です。
投票参加者が高い評価を持っていても、 consumer の約束なしに報酬や作業状態を変更できません。
この分離により、参加者の選定方法を将来の別仕様へ委ねられます。
身元、評判、利害関係の除外を追加しても、 consumer の権限モデルを変更せずに済みます。
決まらなかった結果の扱い
投票では、賛成にも反対にも届かないまま期限を迎える場合があります。
単一の報告者が期限までに応答しない場合もあります。
拒否権を持つグループが、拒否も許可も明示しない場合もあります。
ERC8436は、これらを NoDecision の理由として分けます。
consumer は NoDecision 時の処理を投票前に固定するため、結果を見てから承認扱いか拒否扱いかを選べません。
判断記録と業務実行の分離
Issue Registry は、投票と異議申立てから最終結果を作ります。
外部コントラクトの資産や作業状態は変更しません。
consumer は最終結果を読み、自分が操作できるコントラクトへ承認または拒否を送ります。
外部呼び出しが失敗した場合、最終結果を巻き戻さず、 Failed の実行記録を残します。
判断の確定と業務処理の成功を別々に監査できます。
仕様
ERC8436は、 Policy Registry と Issue Registry を同時にデプロイする構成を定めます。
Policy Registry は変更できない投票規則を保存し、 Issue Registry は具体的な判断案件、投票回、最終結果を保存します。
ACDFTypes
ACDFTypes ライブラリは、 Policy、 Issue、 round、結果で共有する Enum 型と構造体を定義します。
BodyKind
enum BodyKind { ROSTER_KOFN, AUTHORIZED_SUBMITTER }
BodyKind は、1つの判断グループが固定名簿の投票で決めるか、固定された報告者が結果を提出するかを表します。
| 値 | 入力 | 判断結果 |
|---|---|---|
ROSTER_KOFN |
名簿の各 member が投票する |
K票の賛成またはN-K+1票の反対で決まる |
AUTHORIZED_SUBMITTER |
1つの address が結果を提出する |
Yes、 No、 NoDecision の提出値を使う |
Acceptance
enum Acceptance { ON_CHAIN_TALLY, SIGNED_BALLOTS, AUTHORIZED_SUBMITTER }
Acceptance は、 Body が判断材料を受け取る方式です。
| 値 | 入力条件 | 後続の判定 |
|---|---|---|
ON_CHAIN_TALLY |
voter 自身が transaction を送る |
roster と重複を確認して票数へ加える |
SIGNED_BALLOTS |
voter が署名し、任意の relayer が提出する |
署名検証後に同じ票数判定へ進む |
AUTHORIZED_SUBMITTER |
固定報告者が Body 結果を送る |
個別票を数えず提出値を採用する |
Combinator
enum Combinator { BODY, ALL, ANY, KOFM, VETO }
Combinator は、 Body または子 Node の四値判断を合成する方法です。
| 値 | 条件 | 合成結果 |
|---|---|---|
BODY |
1つの Body を参照する |
Body の値を返す |
ALL |
すべての子が Yes
|
Yes になる。1つでも No なら No になる |
ANY |
1つ以上の子が Yes
|
Yes になる。すべて No なら No になる |
KOFM |
M個の子のうちK個が Yes
|
閾値到達で Yes、到達不能で No になる |
VETO |
target Node と拒否権 Body を別々に参照する |
拒否権 Body の Yes で No、明示的な No で target を通す |
VetoSilence
enum VetoSilence { PASS_THROUGH, REQUIRE_CLEARANCE }
VetoSilence は、拒否権 Body が期限までに結論を出さなかった時の扱いです。
拒否権 Body では、 approve ballot による Yes が veto を意味し、 No が明示的な clearance を意味します。
PASS_THROUGH は沈黙時に target の結果を通し、 REQUIRE_CLEARANCE は明示的な No がないため NoDecision にします。
| 値 | 入力または保存状態 | 後続の判定 | 例 |
|---|---|---|---|
PASS_THROUGH |
拒否権 Body が期限まで沈黙する |
target の値を使う |
技術 Body の Yes をそのまま root へ渡す |
REQUIRE_CLEARANCE |
拒否権 Body が期限まで沈黙する |
NoDecision(NO_CLEARANCE) にする |
審査 Body の明示的な No を待つ |
AppealStanding
enum AppealStanding { ANYONE, CONSUMER_OR_FILER }
AppealStanding は、異議申立てを開始できる主体を表します。
ANYONE は任意の address を許し、 CONSUMER_OR_FILER は consumer または Issue 作成者だけを許します。
| 値 |
caller 条件 |
後続の判定 | 例 |
|---|---|---|---|
ANYONE |
任意の caller
|
window と回数を確認する |
keeper が appeal transaction を送る |
CONSUMER_OR_FILER |
consumer または filer
|
それ以外を拒否する | 発注者または Issue 作成者が再審を求める |
AppealMode
enum AppealMode { PRESERVE_UNLESS_OVERTURNED, REQUIRE_FRESH_DECISION }
AppealMode は、 appeal round が NoDecision になった時に前 round の判断を残すかを表します。
PRESERVE_UNLESS_OVERTURNED は直近の Yes または No を採用し、 REQUIRE_FRESH_DECISION は Issue 全体を NoDecision にします。
| 値 |
appeal 結果 |
Final 結果 |
例 |
|---|---|---|---|
PRESERVE_UNLESS_OVERTURNED |
新 round が NoDecision
|
直近の Yes または No を採用する |
round 1の Yes を残す |
REQUIRE_FRESH_DECISION |
新 round が NoDecision
|
Issue 全体を NoDecision にする |
再審で必要票へ届かず effect を選ばない |
BodySpec
struct BodySpec {
BodyKind kind;
Acceptance acceptance;
address[] members;
uint32 k;
uint64 window;
}
BodySpec 構造体は、1つの判断グループの参加者、入力方式、閾値、期限をまとめます。
Policy 作成者が PolicySpec へ組み込み、 Policy Registry が保存し、 Issue Registry の Body 判定と bodyOf 関数が参照します。
- フィールド
| フィールド | 詳細 |
|---|---|
kind |
名簿投票または固定報告者を選びます。 |
acceptance |
オンチェーン投票、署名投票、報告者提出を選びます。 |
members |
zero 以外で重複しない参加者です。報告者方式では1件です。 |
k |
名簿投票で必要な賛成票数です。 |
window |
round 開始から入力を受け付ける秒数です。 |
Node
struct Node {
Combinator op;
uint32 body;
uint32 k;
uint32 target;
uint32 vetoBody;
VetoSilence silence;
uint32[] children;
}
Node 構造体は、 Body 結果をどの論理で合成するかを表します。
nodes[0] が最終判断を返す root です。
Policy 作成者が tree を組み、 Policy Registry が保存し、 Issue Registry の nodeStatus 関数が root まで評価します。
- フィールド
| フィールド | 詳細 |
|---|---|
op |
Body 参照、 ALL、 ANY、 K-of-M、 VETO を選びます。 |
body |
BODY で参照する Body 番号です。 |
k |
KOFM で必要な Yes の数です。 |
target |
VETO で保護する Node 番号です。 |
vetoBody |
拒否権を持つ Body 番号です。 |
silence |
拒否権 Body が沈黙した時の扱いです。 |
children |
ALL、 ANY、 K-of-M で参照する子 Node 番号です。 |
PolicySpec
struct PolicySpec {
bytes32 family;
uint32 version;
bytes32 previous;
address updateAuthority;
BodySpec[] bodies;
Node[] nodes;
uint32 maxAppeals;
uint64 appealWindow;
uint8 appealable;
AppealStanding appealStanding;
AppealMode appealMode;
uint64 maxTotalDuration;
uint64 ackWindow;
bool allowAdvisory;
bytes32 descriptorHash;
}
PolicySpec 構造体は、投票資格、閾値、合成、時間、異議申立て、受入れ条件を1つにまとめます。
全フィールドの ABI encoding から policyId を計算するため、説明用 JSON と実行規則の食い違いを検出できます。
Policy 作成者が registerPolicy 関数へ渡し、 Policy Registry が変更不能な値として保存し、 Issue Registry と各 read 関数が参照します。
- フィールド
| グループ | フィールド | 意味 |
|---|---|---|
| 版 |
family、 version、 previous、 updateAuthority
|
直前 Policy への参照、増加する版番号、公開主体です。 |
| 判断 |
bodies、 nodes
|
参加者、閾値、合成 tree です。 |
appeal |
maxAppeals、 appealWindow、 appealable、 appealStanding、 appealMode
|
異議申立ての回数、時間、主体、採用規則です。 |
| 時間 |
maxTotalDuration、 ackWindow
|
手続き全体と事後承認の上限です。 |
| 補助 |
allowAdvisory、 descriptorHash
|
Advisory 開始と off-chain 説明の hash です。 |
ProcedureState
enum ProcedureState { None, Filed, Deciding, Provisional, Final, Withdrawn }
ProcedureState は、 Issue が受付から終了までのどこにあるかを保存します。
| 値 | 保存状態 | 許される処理 |
|---|---|---|
None |
Issue が存在しない |
後続操作を拒否する |
Filed |
受付済みで投票開始前 | 承認、 Advisory 開始、期限切れ、取消を受け付ける |
Deciding |
round が進行中 |
投票、 Body 結果提出、 settle を受け付ける |
Provisional |
round 結果が決まり異議申立て待ち |
appeal または finalize を受け付ける |
Final |
最終結果を保存済み |
consumer が結果を実行できる |
Withdrawn |
投票前に取消済み |
terminal として後続操作を拒否する |
OutcomeType
enum OutcomeType { None, Decided, NoDecision }
OutcomeType は、 Final 時に Yes または No が決まったか、判断を作れなかったかを表します。
None では effect を実行せず、 Decided では outcomeYes に対応する effect、 NoDecision では disposition を選びます。
| 値 | 保存状態 | 後続の判定 | 例 |
|---|---|---|---|
None |
Final 前または結果未保存 |
effect を実行しない |
Deciding 中の Issue
|
Decided |
Yes または No を Final へ保存済み |
outcomeYes から effect を選ぶ |
Yes なら accept を呼ぶ |
NoDecision |
判断不能を Final へ保存済み |
事前の disposition を使う |
quorum 不足で既定処理へ戻る |
AcceptanceMode
enum AcceptanceMode { CONSUMER_FILED, STANDING_ACCEPTANCE, POST_ACK }
AcceptanceMode は、 consumer が結果に従う約束を投票前に固定する方法です。
| 値 | 約束を作る操作 | admission |
|---|---|---|
CONSUMER_FILED |
consumer 自身が Issue を作る |
直ちに Binding で開始する |
STANDING_ACCEPTANCE |
consumer が事前条件を登録する |
条件一致時に Binding で開始する |
POST_ACK |
filer が作り、 consumer が期限内に承認する |
承認後に Binding で開始する |
EffectClass
enum EffectClass { Advisory, Binding }
EffectClass は、最終結果が consumer の事前の約束を持つかを表します。
Advisory は判断記録だけを残し、 Binding は固定済みの effects と obligation を持ちます。
| 値 | 保存状態 | 後続の判定 | 例 |
|---|---|---|---|
Advisory |
consumer commitment なし |
enactment を記録しない |
未承認 Issue を参考判断として開始する |
Binding |
consumer、 effects、 obligation を固定済み |
Final-Decided 後に effect を選べる |
Yes で作業を受け入れる |
NodeStatus
enum NodeStatus { Pending, Yes, No, NoDecision }
NodeStatus は、 Body または合成 Node の現在の四値判断です。
例として、 K-of-N の必要票へ届けば Yes、 blocking threshold へ届けば No、期限前でどちらにも届かなければ Pending を返します。
Pending は入力で変わる状態、 Yes と No は実質判断、 NoDecision は期限内に判断条件が成立しなかった状態です。
Reason
enum Reason {
NONE,
QUORUM_NOT_MET,
SUBMITTER_SILENT,
VETOED,
NO_CLEARANCE,
NOT_REACHED,
TOTAL_TIMEOUT,
NO_ACCEPTANCE
}
Reason は、 NoDecision、拒否権、未承認が発生した理由を保存します。
| 値 | 発生条件 |
|---|---|
NONE |
特別な失敗理由がない |
QUORUM_NOT_MET |
名簿投票が必要票へ届かない |
SUBMITTER_SILENT |
固定報告者が期限までに提出しない |
VETOED |
拒否権 Body が拒否する |
NO_CLEARANCE |
明示許可が必要な拒否権 Body が沈黙する |
NOT_REACHED |
子 Node から合成結果を作れない |
TOTAL_TIMEOUT |
hard deadline までに round が終わらない |
NO_ACCEPTANCE |
POST_ACK が承認されない |
EnactmentStatus
enum EnactmentStatus { NotEnacted, Enacted, Failed }
EnactmentStatus は、 consumer が Final 結果を業務コントラクトへ反映できたかを表します。
Failed は後から Enacted へ更新できますが、 Enacted は terminal です。
| 値 | 保存状態 | 後続の判定 | 例 |
|---|---|---|---|
NotEnacted |
実行報告なし | 実行または再試行を待つ |
Final-Decided 直後 |
Failed |
target call 失敗を報告済み |
条件が戻れば再試行できる | 期限条件で accept が失敗する |
Enacted |
effect 成功を報告済み |
後続更新を拒否する |
accept 完了を記録する |
Subject
struct Subject {
uint256 chainId;
address target;
uint256 id;
bytes32 dataHash;
}
Subject 構造体は、どの chain のどの target にある何を評価するかを固定します。
filer または adapter が作り、 Issue Registry が Issue 内へ保存し、 getIssue 関数と consumer adapter が照合します。
- フィールド
| フィールド | 詳細 |
|---|---|
chainId |
評価対象が属する chain です。 |
target |
作業コントラクトや対象コントラクトです。 |
id |
task、 submission、 token の識別番号です。 |
dataHash |
評価する具体的な内容を固定する hash です。 |
IssueInput
struct IssueInput {
bytes32 policyId;
AcceptanceMode mode;
bytes32 acceptanceId;
address consumer;
Subject subject;
bytes32 question;
bytes32 effectYes;
bytes32 effectNo;
bytes32 disposition;
bytes32 obligationId;
uint64 consumerDeadline;
}
IssueInput 構造体は、 filer が Issue を作る時に渡す値をまとめます。
file 関数が acceptance mode 別に値を検証し、 admission 後は Issue Registry の Issue へ固定し、 getIssue 関数から読めます。
- フィールド
| グループ | フィールド | 意味 |
|---|---|---|
| 規則 |
policyId、 mode、 acceptanceId
|
適用 Policy と consumer の約束です。 |
| 主体と対象 |
consumer、 subject、 question
|
実行主体、評価対象、質問です。 |
| 結果処理 |
effectYes、 effectNo、 disposition
|
Yes、 No、 NoDecision 時の処理です。 |
| 義務と期限 |
obligationId、 consumerDeadline
|
並行 Issue を防ぐ範囲と consumer 側期限です。 |
StandingAcceptanceInput
struct StandingAcceptanceInput {
bytes32 policyId;
address subjectTarget;
bytes32 question;
address[] filers;
bytes32 effectYes;
bytes32 effectNo;
bytes32 disposition;
bytes32 obligationId;
uint64 validUntil;
}
StandingAcceptanceInput 構造体は、 consumer が将来の Issue へ事前に適用する条件をまとめます。
subjectTarget と question は zero で任意を表し、 filers は空配列で任意の作成者を許します。
consumer が registerStandingAcceptance 関数へ渡し、 Issue Registry が acceptance record として保存し、 file 関数が照合します。
obligationId == 0 の場合、 admission 時に exact Subject の ABI encoding から Issue 用 obligationId を導出するため、 filer は排他範囲を選べません。
- フィールド
| フィールド | 詳細 |
|---|---|
policyId |
受け入れる正確な Policy です。 |
subjectTarget |
zero なら任意、 zero 以外なら一致を求める target です。 |
question |
zero なら任意、 zero 以外なら一致を求める質問です。 |
filers |
Issue 作成を許す address です。空配列なら制限しません。 |
effectYes |
Yes 時に約束する effect です。 |
effectNo |
No 時に約束する effect です。 |
disposition |
NoDecision 時の処理です。 |
obligationId |
排他範囲です。 zero なら exact Subject から導出します。 |
validUntil |
事前登録の有効期限です。 |
Issue
struct Issue {
bytes32 policyId;
AcceptanceMode mode;
EffectClass effectClass;
ProcedureState state;
address filer;
address consumer;
bytes32 acceptanceId;
Subject subject;
bytes32 question;
bytes32 effectYes;
bytes32 effectNo;
bytes32 disposition;
bytes32 obligationId;
bytes32 obligationKey;
uint64 filedAt;
uint64 admittedAt;
uint64 consumerDeadline;
uint64 hardDeadline;
uint64 finalAt;
uint32 roundCount;
OutcomeType outcomeType;
bool outcomeYes;
Reason reason;
uint32 sourceRound;
uint64 decidedAt;
}
Issue 構造体は、 admission で固定した値、期限、現在状態、採用結果を保存します。
Final 後は outcomeType、 sourceRound、 decidedAt から、どの round の判断を採用したか追跡できます。
Issue Registry が file、 acknowledge、 admitAdvisory で作成・更新し、 getIssue 関数が全保存値を返します。
- フィールド
| グループ | フィールド | 詳細 |
|---|---|---|
| 規則・状態 |
policyId、 mode、 effectClass、 state
|
固定 Policy、受付方式、拘束性、手続き状態です。 |
| 主体・対象 |
filer、 consumer、 acceptanceId、 subject、 question
|
作成者、実行主体、事前登録、評価対象、質問です。 |
| 処理・排他 |
effectYes、 effectNo、 disposition、 obligationId、 obligationKey
|
最終結果の処理と並行 Issue を止める key です。 |
| 時刻 |
filedAt、 admittedAt、 consumerDeadline、 hardDeadline、 finalAt
|
受付、開始、 consumer 期限、手続き上限、確定時刻です。 |
| 結果 |
roundCount、 outcomeType、 outcomeYes、 reason、 sourceRound、 decidedAt
|
round 数、結果種別、賛否、理由、採用 round、判断形成時刻です。 |
RoundState
struct RoundState {
uint64 startedAt;
uint64 deadline;
bool settled;
NodeStatus status;
Reason reason;
uint64 at;
uint64 appealOpenUntil;
}
RoundState 構造体は、1つの round の開始、結果形成、 settle、異議申立て期限を保存します。
at は settle transaction の時刻ではなく、票または期限によって root 値が変わらなくなった時刻です。
Issue Registry が round 開始時と settleRound 関数で更新し、 getRound 関数が履歴を返します。
- フィールド
| フィールド | 詳細 |
|---|---|
startedAt |
round 開始時刻です。 |
deadline |
最長 Body window から決まる終了時刻です。 |
settled |
root 結果を保存済みかを示します。 |
status |
settle した四値判断です。 |
reason |
判断または NoDecision の理由です。 |
at |
判断が変わらなくなった時刻です。 |
appealOpenUntil |
異議申立てを受け付ける上限時刻です。 |
BodyState
struct BodyState {
uint32 yes;
uint32 no;
bool submitted;
NodeStatus submitted_;
uint64 decidedAt;
}
BodyState 構造体は、 Body ごとの票数または固定報告者の提出値を保存します。
名簿投票では yes と no、固定報告者では submitted と submitted_ を読みます。
Issue Registry が投票受理または Body 結果提出時に更新し、 getBodyState 関数と bodyStatus 関数が参照します。
- フィールド
| フィールド | 詳細 |
|---|---|
yes |
受理済み approve ballot 数です。 |
no |
受理済み block ballot 数です。 |
submitted |
固定報告者が提出済みかを示します。 |
submitted_ |
固定報告者が提出した Yes、 No、 NoDecision です。 |
decidedAt |
threshold 到達または提出時刻です。 |
Enactment
struct Enactment {
EnactmentStatus status;
address reporter;
bytes32 ref;
uint64 at;
}
Enactment 構造体は、 consumer が業務 effect を実行した結果、報告者、外部参照、報告時刻を保存します。
consumer が recordEnactment 関数で報告し、 Issue Registry が Issue ・ consumer ・ effect ID の組で保存し、 getEnactment 関数が返します。
- フィールド
| フィールド | 詳細 |
|---|---|
status |
NotEnacted、 Failed、 Enacted の実行状態です。 |
reporter |
実行結果を報告した consumer です。 |
ref |
外部 transaction や失敗理由を結ぶ参照値です。 |
at |
報告時刻です。 |
Result
struct Result {
ProcedureState state;
OutcomeType outcomeType;
bool outcomeYes;
Reason reason;
uint64 decidedAt;
uint64 finalAt;
bytes32 policyId;
uint32 roundCount;
uint32 sourceRound;
EffectClass effectClass;
address consumer;
bytes32 effectYes;
bytes32 effectNo;
bytes32 disposition;
bytes32 obligationId;
bool adoptedFromEarlierRound;
}
Result 構造体は、 client が現在状態、最終判断、採用 round、 consumer、業務 effect をまとめて読む値です。
state == Final と outcomeType == Decided を両方確認してから、 outcomeYes に対応する effect を選びます。
Issue Registry が保存済み Issue と round 履歴から組み立て、 getResult 関数が consumer adapter や client へ返します。
- フィールド
| グループ | フィールド | 詳細 |
|---|---|---|
| 手続き |
state、 outcomeType、 outcomeYes、 reason
|
現在状態、結果種別、賛否、理由です。 |
時刻・ round
|
decidedAt、 finalAt、 roundCount、 sourceRound、 adoptedFromEarlierRound
|
判断形成、確定、 round 数、採用元、以前の round 採用 flag です。 |
| 規則・主体 |
policyId、 effectClass、 consumer
|
Policy、拘束性、実行主体です。 |
| 処理 |
effectYes、 effectNo、 disposition、 obligationId
|
Yes、 No、 NoDecision の処理と義務範囲です。 |
Conformance と署名の前提
client は registry address だけを信用せず、必要な interface ID へ対応するかを supportsInterface 関数で確認します。
この問い合わせ方法をERC165が定めています。
Policy Registry の interface ID は 0xb362eb4e、 Issue Registry は 0xd31aae30 です。
ERC165については以下の記事を参考にしてください。
署名投票では、 Issue、 round、 Body、 voter、賛否と、 chain ID、 registry address を同じ digest へ入れます。
ウォレットとコントラクトが同じ field 順で digest を作る形式がEIP712です。
これにより、 client は署名が別 round や別 registry 向けではないかを確認できます。
EIP712については以下の記事を参考にしてください。
voter がコントラクトアカウントの場合、 Issue Registry は isValidSignature 関数を staticcall し、 magic value を確認します。
この検証方法をERC1271が定めています。
contract wallet が現在の権限設定で署名を承認した時だけ、その ballot を受理します。
ERC1271については以下の記事を参考にしてください。
IACDFPolicyRegistry
IACDFPolicyRegistry は、変更できない Policy を登録し、 family の版、 Body、 Node、時間設定を読み出す interface です。
supportsInterface
function supportsInterface(bytes4 interfaceId) external view returns (bool);
指定した interface ID へ Policy Registry が対応するかを返す関数です。
-
IDを受け取るclientが利用したいAPI集合のIDを渡す。 -
対応状況を確認する
実装済みの
IDと比較する。 -
真偽値を返す
対応していれば
true、未対応ならfalseを返す。
- 引数
| 引数 | 詳細 |
|---|---|
interfaceId |
確認する4-byteの interface ID です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bool |
対応状況です。 |
-
実行条件
-
view関数であり、storageを更新しません。 -
未対応
IDはrevertせずfalseを返します。
Timing
struct Timing {
uint32 maxAppeals;
uint64 appealWindow;
uint8 appealable;
T.AppealStanding appealStanding;
T.AppealMode appealMode;
uint64 maxTotalDuration;
uint64 ackWindow;
bool allowAdvisory;
uint64 roundDuration;
}
Timing 構造体は、 Policy の round、異議申立て、全体期限、事後承認を client がまとめて読む値です。
- フィールド
| フィールド | 詳細 |
|---|---|
maxAppeals |
追加できる round 数です。 |
appealWindow |
異議申立て受付秒数です。 |
appealable |
異議申立て対象を示す bit です。 |
appealStanding |
異議申立てできる主体です。 |
appealMode |
appeal round が NoDecision になった時の扱いです。 |
maxTotalDuration |
admission 後の全体上限秒数です。 |
ackWindow |
POST_ACK の承認秒数です。 |
allowAdvisory |
未承認 Issue を Advisory へ移せるかを表します。 |
roundDuration |
各 Body window の最大値から導出した round 秒数です。 |
PolicyRegistered
event PolicyRegistered(bytes32 indexed policyId, bytes32 indexed family, uint32 version, address indexed by);
新しい Policy を保存する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
policyId |
Policy 全体から計算した識別子です。 |
family |
Policy family です。 |
version |
family 内の版番号です。 |
by |
Policy を登録した address です。 |
イベントから登録者と版を検索できますが、 Body と Node の全内容は read 関数で取得します。
policyIdOf
function policyIdOf(T.PolicySpec calldata spec) external pure returns (bytes32);
PolicySpec 全体の ABI encoding から policyId を計算する関数です。
-
Policyを符号化するBody、Node、時間、authority、descriptor hashを含む構造体をabi.encodeする。 -
hashを計算する符号化結果へ
keccak256を適用する。 -
識別子を返す
登録前後で同じ
Policyを照合できるbytes32を返す。
- 引数
| 引数 | 詳細 |
|---|---|
spec |
識別子を計算する Policy 全体です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bytes32 |
PolicySpec から決まる policyId です。 |
-
実行条件
-
pure関数であり、登録状態やPolicyの妥当性は確認しません。 -
clientは登録結果と事前計算値を照合できます。
registerPolicy
function registerPolicy(T.PolicySpec calldata spec) external returns (bytes32 policyId);
Policy の構造、 family の版、時間条件を検証して保存する関数です。
-
Policyを検証するBody、Node、role、window、異議申立て、全体期限を確認する。 -
familyの版を検証する初版では
familyをclaimし、次版ではauthority、previous == latest policyId、version > latest versionを確認する。 -
Policyを保存するPolicySpec全体と導出したroundDurationを保存し、イベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
spec |
登録する Policy 全体です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
policyId |
保存した Policy の識別子です。 |
-
実行条件
-
Bodyは1件以上32件以下、Nodeは1件以上64件以下です。 -
memberはzero以外で重複させません。 -
treeは循環参照やBodyのrole重複を作れません。 -
次版は
familyのupdate authorityだけが登録できます。 -
次版の
previousはlatest policy IDと一致させ、versionは最新版より大きくします。 -
latest + 1の連番である必要はありません。 -
検証失敗時は
Policyとfamily情報を保存しません。
policyExists
function policyExists(bytes32 policyId) external view returns (bool);
指定した Policy が登録済みかを返す関数です。
-
識別子を受け取る
clientが確認するpolicyIdを渡す。 -
登録状態を読む
Policy Registryの存在フラグを参照する。 -
真偽値を返す
登録済みなら
trueを返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
確認する Policy です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bool |
登録状態です。 |
-
実行条件
-
未登録
IDではfalseを返します。 -
storageを更新しません。
familyAuthority
function familyAuthority(bytes32 family) external view returns (address);
Policy family の次版を登録できる address を返す関数です。
-
familyを指定するclientが監査するfamily IDを渡す。 -
authorityを読む最新
Policyが指定した現在のupdateAuthorityを取得する。 -
addressを返す次版の公開主体を返す。
- 引数
| 引数 | 詳細 |
|---|---|
family |
Policy family の識別子です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
address |
family の update authority です。 |
-
実行条件
-
未登録
familyではzero addressになります。 -
既存
Policyの内容を変更する権限ではありません。
familyLatest
function familyLatest(bytes32 family) external view returns (bytes32 policyId, uint32 version);
Policy family の最新 ID と版番号を返す関数です。
-
familyを指定する更新履歴を確認する
family IDを渡す。 -
最新値を読む
最後に登録された
policyIdとversionを取得する。 -
2つの値を返す
clientが新規Issueへ採用する候補を判断できる形で返す。
- 引数
| 引数 | 詳細 |
|---|---|
family |
Policy family の識別子です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
policyId |
family の最新 Policy です。 |
version |
最新版の番号です。 |
-
実行条件
-
既存
Issueは最新値へ自動更新されません。 -
consumerは許容する正確なpolicyIdを固定します。
roundDurationOf
function roundDurationOf(bytes32 policyId) external view returns (uint64);
Policy 内の Body window から導出した一 round の最大秒数を返す関数です。
-
Policyを指定する期限を確認する
policyIdを渡す。 -
保存済み時間を読む
登録時に計算した
roundDurationを取得する。 -
秒数を返す
clientがround deadlineを予測できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
uint64 |
一 round の最大秒数です。 |
-
実行条件
-
登録済み
Policyを指定します。 -
未登録
IDは実装の拒否条件に従います。
timingOf
function timingOf(bytes32 policyId) external view returns (Timing memory);
Policy の時間設定と異議申立て設定をまとめて返す関数です。
-
Policyを指定するclientが期限を評価するpolicyIdを渡す。 -
保存値と導出値を読む
PolicySpecの時間fieldとroundDurationを取得する。 -
構造体を返す
round、appeal、hard deadlineを同じ単位で比較できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
Timing |
Policy の時間と異議申立て設定です。 |
-
実行条件
-
登録済み
Policyを指定します。 -
Issue Registryのclock modeと合わせて読みます。
policyHeader
function policyHeader(bytes32 policyId) external view returns (bytes32 family, uint32 version, bytes32 previous, address updateAuthority, bytes32 descriptorHash);
Policy family と off-chain 説明を照合する header を返す関数です。
-
Policyを指定する版と説明文を確認する
policyIdを渡す。 -
headerを読むfamily、version、previous、authority、descriptor hashを取得する。 -
5つの値を返す
clientがpreviousによる系譜、増加するversion、説明文のhashを照合できる形で返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
family |
Policy family です。 |
version |
family 内の版番号です。 |
previous |
直前の policyId です。 |
updateAuthority |
次版を登録できる address です。 |
descriptorHash |
off-chain 説明文の hash です。 |
-
実行条件
-
descriptorHashは情報用で、投票判定へ使いません。 -
実行規則は保存済み
PolicySpecから読みます。
bodyCount
function bodyCount(bytes32 policyId) external view returns (uint256);
Policy に登録された Body 数を返す関数です。
-
Policyを指定する読み出す
policyIdを渡す。 -
件数を読む
保存済み
bodiesの長さを取得する。 -
件数を返す
有効な
Body番号を判断できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
uint256 |
Body の件数です。 |
-
実行条件
-
登録済み
Policyを指定します。 -
Body番号は0から件数未満です。
bodyOf
function bodyOf(bytes32 policyId, uint32 body) external view returns (T.BodySpec memory);
指定した Body の投票方式、 member、閾値、 window を返す関数です。
-
PolicyとBody番号を指定するclientが確認する位置を渡す。 -
Bodyを読む保存済み
BodySpecを取得する。 -
構造体を返す
voter eligibilityと判定条件を再現できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
body |
0始まりの Body 番号です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
BodySpec |
指定 Body の全設定です。 |
-
実行条件
-
bodyはbodyCount未満にします。 -
範囲外では
revertします。
nodeCount
function nodeCount(bytes32 policyId) external view returns (uint256);
Policy に登録された Node 数を返す関数です。
-
Policyを指定する読み出す
policyIdを渡す。 -
件数を読む
保存済み
nodesの長さを取得する。 -
件数を返す
合成
treeの有効範囲を判断できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
uint256 |
Node の件数です。 |
-
実行条件
-
登録済み
Policyを指定します。 -
rootはNode0です。
nodeOf
function nodeOf(bytes32 policyId, uint32 node) external view returns (T.Node memory);
指定した Node の合成規則を返す関数です。
-
PolicyとNode番号を指定するclientが確認する位置を渡す。 -
Nodeを読む保存済み
Node構造体を取得する。 -
構造体を返す
Body結果からroot判断を再計算できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
policyId |
対象 Policy です。 |
node |
0始まりの Node 番号です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
Node |
指定 Node の全設定です。 |
-
実行条件
-
nodeはnodeCount未満にします。 -
範囲外では
revertします。
Issue の作成と受入れ
consumer の約束を固定する方法は3種類です。
mode |
Issue を作る主体 |
commitment が成立する時点 |
未承認時 |
|---|---|---|---|
CONSUMER_FILED |
consumer |
file 関数の実行時 |
該当しない |
STANDING_ACCEPTANCE |
許可された filer
|
登録済み条件と一致した時 |
Issue 作成を拒否する |
POST_ACK |
任意または許可された filer
|
consumer が acknowledge 関数を呼んだ時 |
expire または Advisory へ進む |
Binding Issue では、 consumer、 obligationId、 question から obligationKey を作ります。
ここでObligationは、同じ consumer が同じ question を複数 panel へ同時に出してはならない業務上の義務です。
同じ key に未完了 Issue がある間は2件目を拒否し、複数 panel へ同じ義務を出して都合のよい結果だけを選ぶ行為を防ぎます。
admission では、 Policy、 Subject、 question、 effects、 disposition、 consumer、期限を固定します。
投票開始後に standing acceptance を取り消しても進行中 Issue は止まりません。
filer による withdrawal は、まだ Filed で投票が始まっていない Issue だけに限定されます。
投票 Body と合成 Tree
名簿投票はK票の賛成で Yes、N-K+1票の反対で No になります。
どちらにも届かず window が終了すると NoDecision です。
1人の member は Issue、 round、 Body ごとに1票だけ提出できます。
署名投票も同じ票数判定を使います。
署名には round 番号が入るため、遅れて届いた transaction を次 round の票として使えません。
batch 内に1件でも無効な署名があれば transaction 全体を revert します。
固定報告者方式では、 Policy へ登録した address が Yes、 No、 NoDecision を1回だけ提出します。
window 内に提出しなければ SUBMITTER_SILENT です。
各 Body の票は別々に数えます。
この局所的な四値判断を Body decision と呼び、 composition tree の leaf または veto 入力に使います。
技術グループと経済グループの票を1つの票箱へ混ぜず、各 Body の四値判断を tree で合成します。
同じ Body を複数の BODY Node へ置くことや、拒否権 Body を通常 Body として再利用することは禁止されます。
ProcedureとFinality
Issue は Filed から Deciding へ進み、 round 結果が決まると Provisional になります。
異議申立てがあれば Deciding へ戻り、新しい round を開始します。
異議申立てがなければ Final へ進みます。
異議申立て期限は、 settle transaction の時刻ではなく、必要票がそろった時刻または window 終了時刻から計算します。
この判断内容が変わらなくなった時刻が Formation instant です。
settle を遅らせても appeal window を延長できません。
maxTotalDuration から計算した hard deadline を過ぎた後、誰でも enforceHardDeadline 関数を呼べます。
Deciding で現在の root が Pending なら、進行中 round を NoDecision(TOTAL_TIMEOUT) として閉じます。
すでに Yes または No ならその判断を保存し、 Provisional なら保存済み round を使います。
最後に appeal mode の採用規則を適用して手続きを終了します。
Procedureの Final、判断の Decided、業務実行の Enacted は別々の値です。
Final-NoDecision や、 Final-Decided で実行が Failed という組み合わせもあります。
IACDFRegistry
IACDFRegistry は、 consumer の事前登録、 Issue、投票、 round、最終結果、実行報告を保存する interface です。
StandingAcceptanceRegistered
event StandingAcceptanceRegistered(bytes32 indexed acceptanceId, address indexed consumer, bytes32 indexed policyId);
consumer が事前の受入れ条件を登録する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
acceptanceId |
事前登録の識別子です。 |
consumer |
結果を受け入れる主体です。 |
policyId |
受入れ対象に固定した Policy です。 |
このログだけでは、 Subject 制約、 question 制約、 filer 一覧、 effects、期限を復元できません。
必要な場合は、登録トランザクションの入力、オフチェーンの索引、実装固有の取得関数で補います。
StandingAcceptanceRevoked
event StandingAcceptanceRevoked(bytes32 indexed acceptanceId, address indexed consumer);
consumer が事前の受入れ条件を取り消す時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
acceptanceId |
取り消した事前登録です。 |
consumer |
取消を実行した consumer です。 |
取消後の新規 Issue には使えませんが、すでに admit された Issue は継続します。
IssueFiled
event IssueFiled(bytes32 indexed issueId, bytes32 indexed policyId, T.AcceptanceMode mode, address indexed filer, address consumer);
新しい Issue を受け付ける時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
Issue の識別子です。 |
policyId |
固定した Policy です。 |
mode |
consumer commitment の成立方法です。 |
filer |
Issue 作成者です。 |
consumer |
想定または確定した consumer です。 |
このログで Issue の受付主体と mode を追えますが、 Subject、 question、 effects、 obligation、各期限は getIssue 関数で読みます。
IssueAdmitted
event IssueAdmitted(bytes32 indexed issueId, T.EffectClass effectClass, address indexed consumer, uint64 admittedAt, uint64 hardDeadline);
Issue を投票手続きへ入れ、 round 1を開始する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
admission した Issue です。 |
effectClass |
Advisory または Binding です。 |
consumer |
Binding 時の consumer です。 |
admittedAt |
開始時刻です。 |
hardDeadline |
手続き全体の終了上限です。 |
このログで投票開始と全体上限を追えますが、 round 1の deadline、 Body 設定、 Node tree は getRound 関数と Policy Registry の read API で補います。
IssueAcknowledged
event IssueAcknowledged(bytes32 indexed issueId, address indexed consumer);
POST_ACK の Issue を consumer が承認する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
承認した Issue です。 |
consumer |
effects と obligation を固定した主体です。 |
このログで誰が承認したかを追えますが、確定した effects、 disposition、 obligation、 consumer deadline は getIssue 関数で読みます。
IssueWithdrawn
event IssueWithdrawn(bytes32 indexed issueId, T.Reason reason);
投票前の取消または未承認期限切れで Issue を終了する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
終了した Issue です。 |
reason |
NONE または NO_ACCEPTANCE です。 |
このログで取消または未承認終了を追えますが、取消前に固定されていた Subject、 question、 consumer 提案値は getIssue 関数で補います。
BallotCast
event BallotCast(bytes32 indexed issueId, uint32 indexed round, uint32 indexed body, address voter, bool approve, bool signed);
1票を受理して Body の票数を更新する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
投票対象の Issue です。 |
round |
1始まりの round 番号です。 |
body |
Body 番号です。 |
voter |
投票者です。 |
approve |
賛成なら true です。 |
signed |
relayer が署名票を提出した場合に true です。 |
このログで各 voter の受理票を検索できますが、 Body の累計票、 threshold 到達時刻、他 member の未投票状態は getBodyState 関数と bodyStatus 関数で読みます。
BodyResultSubmitted
event BodyResultSubmitted(bytes32 indexed issueId, uint32 indexed round, uint32 indexed body, address submitter, T.NodeStatus status);
固定報告者が Body 結果を提出する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
対象 round です。 |
body |
対象 Body です。 |
submitter |
Policy へ固定された報告者です。 |
status |
Yes、 No、 NoDecision の提出値です。 |
このログで報告者の提出を追えますが、提出済み flag、形成時刻、合成後の root 判断は getBodyState 関数と nodeStatus 関数で補います。
RoundSettled
event RoundSettled(bytes32 indexed issueId, uint32 indexed round, T.NodeStatus status, T.Reason reason, uint64 at, uint64 appealOpenUntil);
root Node の値を round 結果として保存する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
settle した round です。 |
status |
root の四値判断です。 |
reason |
NoDecision や VETO の理由です。 |
at |
値が形成された時刻です。 |
appealOpenUntil |
異議申立て期限です。 |
このログで settle 結果を追えますが、 round 開始・終了時刻、 Issue の現在 state、以前の round 履歴は getRound 関数と getIssue 関数で読みます。
Appealed
event Appealed(bytes32 indexed issueId, uint32 indexed newRound, address indexed by);
異議申立てを受け付け、新しい round を開始する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
newRound |
新しく開始した round 番号です。 |
by |
異議申立てを送った address です。 |
このログで新 round の開始を追えますが、新 round の deadline、各 Body の票数、以前の判断を採用するかは getRound 関数、 getBodyState 関数、 getResult 関数で補います。
Finalized
event Finalized(bytes32 indexed issueId, T.OutcomeType outcomeType, bool outcomeYes, T.Reason reason, uint32 sourceRound);
Issue の最終結果を保存する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
Final になった Issue です。 |
outcomeType |
Decided または NoDecision です。 |
outcomeYes |
Decided 時の Yes または No です。 |
reason |
NoDecision または採用判断の理由です。 |
sourceRound |
採用した判断を作った round です。 |
このログで最終判断と採用 round を追えますが、 consumer、 effects、 final 時刻、以前の round を採用した flag は getResult 関数で読みます。
EnactmentRecorded
event EnactmentRecorded(bytes32 indexed issueId, address indexed consumer, bytes32 indexed effectId, T.EnactmentStatus status, address reporter, bytes32 ref);
consumer が業務 effect の実行結果を報告する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
元の Issue です。 |
consumer |
effect を実行した主体です。 |
effectId |
Yes または No の effect 参照です。 |
status |
Enacted または Failed です。 |
reporter |
報告 transaction の送信者です。 |
ref |
外部実行を参照する値です。 |
このログで consumer の実行報告を追えますが、業務コントラクト側の現在ステートや実行 transaction の成功内容は registry だけでは復元できず、 getEnactment 関数と target 側の記録を照合します。
Evidence
event Evidence(bytes32 indexed issueId, address indexed party, string evidenceURI);
Issue へ証拠 URI を添付する時に発行するイベントです。
- フィールド
| フィールド | 詳細 |
|---|---|
issueId |
証拠を関連付ける Issue です。 |
party |
URI を提出した address です。 |
evidenceURI |
証拠を参照する文字列です。 |
registry は URI の内容や真実性を検証しません。
supportsInterface
function supportsInterface(bytes4 interfaceId) external view returns (bool);
Issue Registry が指定 interface へ対応するかを返す関数です。
-
IDを受け取るclientが必要なinterface IDを渡す。 -
対応状況を確認する
実装済み
IDと比較する。 -
真偽値を返す
対応時は
trueを返す。
- 引数
| 引数 | 詳細 |
|---|---|
interfaceId |
確認する4-byte ID です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bool |
対応状況です。 |
-
実行条件
-
view関数でstorageを更新しません。 -
未対応
IDではfalseを返します。
policies
function policies() external view returns (IACDFPolicyRegistry);
Issue Registry が参照する Policy Registry を返す関数です。
-
保存済み
addressを読むデプロイ時に固定した
Policy Registryを取得する。 -
interface型で返すclientがPolicy内容を読み出せる値を返す。
- 戻り値
| 戻り値 | 詳細 |
|---|---|
IACDFPolicyRegistry |
対応する Policy Registry です。 |
-
実行条件
-
view関数でstorageを更新しません。 -
clientは返されたregistryのERC165対応も確認します。
registerStandingAcceptance
function registerStandingAcceptance(T.StandingAcceptanceInput calldata input) external returns (bytes32 acceptanceId);
consumer が将来の Issue へ適用する受入れ条件を事前登録する関数です。
-
条件を検証する
登録済み
Policyと、zeroではない2つのeffect IDを確認する。 -
consumerを固定するmsg.senderをconsumerとしてacceptanceを保存する。 -
識別子を返す
filerがfile関数で参照するacceptanceIdを返す。
- 引数
| 引数 | 詳細 |
|---|---|
input |
Policy、対象、質問、 filer、 effects、義務、期限です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
acceptanceId |
保存した事前登録の識別子です。 |
-
実行条件
-
consumer自身が呼び出します。 -
登録済みの正確な
policyIdを指定します。 -
未登録
policyIdまたはzero effectを拒否します。 -
期限と
filer一覧は、file関数が事前登録を使用する時に照合します。
revokeStandingAcceptance
function revokeStandingAcceptance(bytes32 acceptanceId) external;
consumer が未使用の将来分を含む事前登録を取り消す関数です。
-
登録を読む
acceptanceIdに対応するconsumerを取得する。 -
callerを確認する登録した
consumerとmsg.senderを比較する。 -
取消を保存する
revoked状態を記録してイベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
acceptanceId |
取り消す事前登録です。 |
-
実行条件
-
登録した
consumerだけが呼び出せます。 -
取消前に
admitされたIssueは継続します。 -
不明
IDは、保存済みconsumerと一致しないため拒否します。 -
同じ
consumerによる再取消は許可され、revokedを再び保存してイベントを発行します。
file
function file(T.IssueInput calldata input) external returns (bytes32 issueId);
判断対象と consumer commitment を受け取り、新しい Issue を作る関数です。
-
mode別に入力を検証するconsumer自身の作成、事前登録、事後承認のどれを使うか確認する。 -
Issueを保存するSubject、question、Policy、提案または確定済みeffectsを保存する。 -
開始または承認待ちにする
commitment成立済みならadmitし、POST_ACKならFiledで待つ。
- 引数
| 引数 | 詳細 |
|---|---|
input |
Policy、 mode、 consumer、 Subject、 question、 effects、義務、期限です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
issueId |
作成した Issue の識別子です。 |
-
実行条件
-
Policyは登録済みである必要があります。 -
CONSUMER_FILEDではconsumerとcallerを一致させます。 -
STANDING_ACCEPTANCEではtarget、question、filer、期限を登録条件と照合します。 -
Binding Issueでは同じobligationKeyの進行中Issueを拒否します。
acknowledge
function acknowledge(bytes32 issueId, bytes32 effectYes, bytes32 effectNo, bytes32 disposition, bytes32 obligationId, uint64 consumerDeadline) external;
consumer が POST_ACK Issue の effects と義務を投票前に固定する関数です。
-
Issueと期限を確認するFiled、POST_ACK、ack window内であることを確認する。 -
consumerの値を固定するcaller、effects、disposition、obligation、consumer deadlineを保存する。 -
round1を開始するBindingとしてadmitし、hard deadlineを計算する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
承認する Issue です。 |
effectYes |
Yes 時の effect です。 |
effectNo |
No 時の effect です。 |
disposition |
NoDecision 時の処理です。 |
obligationId |
consumer が固定する義務範囲です。 |
consumerDeadline |
consumer 側の実行期限です。 |
-
実行条件
-
Issueに指定されたconsumerだけが呼び出せます。 -
ack windowを過ぎた呼び出しを拒否します。 -
同じ
obligationの進行中Issueがあれば拒否します。
admitAdvisory
function admitAdvisory(bytes32 issueId) external;
未承認の POST_ACK Issue を業務拘束のない Advisory として開始する関数です。
-
Policy設定を確認するallowAdvisoryが有効かを読む。 -
Issue状態を確認するFiledのままack windowを過ぎたことを確認する。 -
Advisoryで開始するconsumer effectsを拘束せずround1を開く。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
Advisory として開始する Issue です。 |
-
実行条件
-
PolicyがAdvisoryを許可していることを確認します。 -
ack window終了後は誰でも呼び出せます。 -
すでに
acknowledge、withdraw、admitされたIssueを拒否します。 -
Advisoryはactive obligationを作りません。
expireUnacknowledged
function expireUnacknowledged(bytes32 issueId) external;
ack window を過ぎた未承認 Issue を終了する関数です。
-
Issueを確認するFiledのPOST_ACKであることを確認する。 -
期限を確認する
ack windowが終了したかをclockで判定する。 -
Withdrawnへ移すNO_ACCEPTANCEを記録して終了イベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
期限切れにする Issue です。 |
-
実行条件
-
誰でも呼び出せます。
-
期限前または承認済みの
Issueを拒否します。 -
PolicyのallowAdvisoryがfalseの場合だけ成功します。 -
allowAdvisoryがtrueなら、期限後にadmitAdvisory関数を使います。
withdraw
function withdraw(bytes32 issueId) external;
filer が投票開始前の Issue を取り消す関数です。
-
callerを確認するIssueのfilerとmsg.senderを比較する。 -
状態を確認する
IssueがFiledであることを確認する。 -
取消を保存する
Withdrawnへ移してイベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
取り消す Issue です。 |
-
実行条件
-
filerだけが呼び出せます。 -
admission後のIssueは取り消せません。
submitEvidence
function submitEvidence(bytes32 issueId, string calldata evidenceURI) external;
Issue へ証拠を参照する URI をイベントとして添付する関数です。
-
Issue状態を確認するFiled、Deciding、Provisionalのいずれかであることを確認する。 -
URIを受け取るcallerが指定した証拠参照を受け取る。 -
イベントを発行する
Issue、caller、URIをイベントログへ記録する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
証拠を関連付ける Issue です。 |
evidenceURI |
off-chain 証拠を参照する文字列です。 |
-
実行条件
-
FinalまたはWithdrawnでは受け付けません。 -
registryはURIの内容を取得、検証、実行しません。
castBallot
function castBallot(bytes32 issueId, uint32 round, uint32 body, bool approve) external;
voter 自身が1票をオンチェーンで提出する関数です。
-
対象と資格を確認する
Issue、現在round、Body、member、windowを確認する。 -
重複を確認する
同じ
voterが同じIssue、round、Bodyへ未投票かを確認する。 -
票数を更新する
賛成または反対の
countと投票済みkeyを保存し、イベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
投票対象の Issue です。 |
round |
1始まりの round 番号です。 |
body |
Policy 内の Body 番号です。 |
approve |
賛成なら true、反対なら false です。 |
-
実行条件
-
BodyはON_CHAIN_TALLYである必要があります。 -
callerはBody memberに含まれる必要があります。 -
期限後、重複投票、確定済み
Bodyを拒否します。
submitSignedBallots
function submitSignedBallots(bytes32 issueId, uint32 body, address[] calldata voters, bool[] calldata approves, bytes[] calldata signatures) external;
複数のEIP712署名票を任意の relayer がまとめて提出する関数です。
-
配列と現在
roundを確認する三配列の長さ、
Issue状態、Body方式、windowを確認する。 -
各署名票を検証する
voter、roster、重複、digest、EOAまたはERC1271署名を確認する。 -
batch全体を保存する全件が有効な場合だけ各票を
countし、イベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
投票対象の Issue です。 |
body |
署名投票を受け付ける Body です。 |
voters |
各署名者です。 |
approves |
各署名者の賛否です。 |
signatures |
各EIP712署名です。 |
-
実行条件
-
BodyはSIGNED_BALLOTSである必要があります。 -
署名
digestには現在roundが入ります。 -
1件でも無効なら
batch全体をrevertし、票数を変更しません。
submitBodyResult
function submitBodyResult(bytes32 issueId, uint32 round, uint32 body, T.NodeStatus status) external;
固定報告者が Body の Yes、 No、 NoDecision を提出する関数です。
-
報告者を確認する
PolicyのBody memberとcallerを比較する。 -
roundとwindowを確認する現在
round、未提出、期限内であることを確認する。 -
結果を保存する
status、提出済みflag、時刻を保存してイベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
対象 round です。 |
body |
固定報告者方式の Body です。 |
status |
Yes、 No、 NoDecision です。 |
-
実行条件
-
BodyはAUTHORIZED_SUBMITTER方式である必要があります。 -
Pendingの提出、再提出、期限後提出を拒否します。
settleRound
function settleRound(bytes32 issueId) external;
現在 round の root Node を評価し、 round 結果を保存する関数です。
-
root statusを計算するBodyの票数、提出値、windowと合成treeを評価する。 -
formation instantを計算する結果が変わらなくなった時刻を票または期限から求める。
-
状態を進める
appeal可能ならProvisional、対象外ならFinalへ移す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
settle する Issue です。 |
-
実行条件
-
誰でも呼び出せます。
-
DecidingでrootがPendingではないことを確認します。 -
settle済みroundを拒否します。
appeal
function appeal(bytes32 issueId) external;
Provisional 結果へ異議を申し立て、新しい round を開始する関数です。
-
standingと期限を確認するcaller、appeal window、対象outcome、最大回数を確認する。 -
前判断の扱いを記録する
Policyのappeal modeに従い、後の採用候補を保持または失効させる。 -
新しい
roundを開くround countを増やし、開始時刻とdeadlineを保存する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
異議申立て対象の Issue です。 |
-
実行条件
-
IssueはProvisionalである必要があります。 -
standingが限定されるPolicyではconsumerまたはfilerだけが呼び出せます。 -
appeal window後、最大回数到達後、hard deadline超過後を拒否します。
finalize
function finalize(bytes32 issueId) external;
異議申立て期間が終了した Provisional Issue を Final へ移す関数です。
-
期限を確認する
appeal windowが終了したかをclockで判定する。 -
採用
roundを決める最終
roundとappeal modeから採用するYes、No、NoDecisionを選ぶ。 -
Final結果を保存するoutcome、reason、source round、時刻を保存してobligationを解放する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
Final にする Issue です。 |
-
実行条件
-
誰でも呼び出せます。
-
IssueはProvisionalである必要があります。 -
appeal window終了前は拒否します。
enforceHardDeadline
function enforceHardDeadline(bytes32 issueId) external;
手続き全体の上限時刻を過ぎた Issue を、現在までに形成された判断と appeal mode に基づいて Final へ移す関数です。
-
hard deadlineを確認する現在
clockが保存済み上限を過ぎたかを判定する。 -
進行中
roundの結果を保存するDecidingなら現在のrootを読み、YesまたはNoはその判断を保存する。
Pendingの場合だけNoDecision(TOTAL_TIMEOUT)を保存する。
Provisionalなら保存済みroundをそのまま使う。 -
IssueをFinalにするappeal modeの採用規則でDecidedまたはNoDecisionを選び、active obligationを解放する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
強制終了する Issue です。 |
-
実行条件
-
誰でも呼び出せます。
-
hard deadline以前は拒否します。 -
FinalまたはWithdrawnでは実行できません。
recordEnactment
function recordEnactment(bytes32 issueId, bytes32 effectId, T.EnactmentStatus status, bytes32 ref) external;
consumer が Final decision を業務コントラクトへ反映した結果を記録する関数です。
-
Issueとconsumerを確認するBindingかつFinalであり、callerがconsumerかを確認する。 -
effectとstatusを確認する登録済みの
effectYesまたはeffectNoと一致するeffect IDと、EnactedまたはFailedを確認する。 -
実行報告を保存する
status、reporter、ref、時刻を保存してイベントを発行する。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
元の Issue です。 |
effectId |
実行した Yes または No effect です。 |
status |
Enacted または Failed です。 |
ref |
外部 transaction や業務記録の参照です。 |
-
実行条件
-
consumerだけが呼び出せます。 -
Advisoryでは記録できません。 -
Issue RegistryはoutcomeTypeとeffect IDの対応を検証せず、Final-NoDecisionも一律には拒否しません。 -
採用結果に対応する
effect IDの選択と、NoDecision時にdispositionを適用する処理はconsumerが担います。 -
FailedからEnactedへ更新できますが、Enacted後の変更は拒否します。
getResult
function getResult(bytes32 issueId) external view returns (T.Result memory);
Issue の現在状態と、 Final 後の判断・ effects を返す関数です。
-
Issueを読む保存済み
state、outcome、consumer、effectsを取得する。 -
採用情報を組み立てる
source roundと以前のround採用flagを計算する。 -
Resultを返すclientがeffect実行条件を判定できる構造体を返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
読み出す Issue です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
Result |
procedure、 outcome、 Policy、 consumer、 effects です。 |
-
実行条件
-
view関数でstorageを更新しません。 -
Final前はoutcomeTypeがNoneです。
getIssue
function getIssue(bytes32 issueId) external view returns (T.Issue memory);
Issue へ固定した全値と現在状態を返す関数です。
-
識別子を受け取る
clientが確認するIssueを指定する。 -
保存値を読む
Subject、question、Policy、consumer、期限、結果を取得する。 -
Issueを返すadmission時の固定値と現在状態を同じ構造体で返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
読み出す Issue です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
Issue |
Issue の保存内容です。 |
-
実行条件
-
view関数でstorageを更新しません。 -
不明
IDの扱いは実装のread規則に従います。
getRound
function getRound(bytes32 issueId, uint32 round) external view returns (T.RoundState memory);
指定 round の開始、期限、 settle 結果、異議申立て期限を返す関数です。
-
Issueとroundを指定する履歴を確認する位置を渡す。
-
RoundStateを読む保存済み時刻、
status、reasonを取得する。 -
構造体を返す
clientが形成時刻とsettle時刻を混同せず確認できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
1始まりの round 番号です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
RoundState |
指定 round の保存内容です。 |
-
実行条件
-
作成済み
roundを指定します。 -
view関数でstorageを更新しません。
getBodyState
function getBodyState(bytes32 issueId, uint32 round, uint32 body) external view returns (T.BodyState memory);
指定 Body の票数または固定報告者の提出値を返す関数です。
-
位置を指定する
Issue、round、Body番号を渡す。 -
保存値を読む
yes、no、提出flag、提出status、決定時刻を取得する。 -
構造体を返す
clientがBody判断を再計算できる値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
対象 round です。 |
body |
対象 Body です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
BodyState |
Body の保存内容です。 |
-
実行条件
-
有効な
roundとBody番号を指定します。 -
view関数でstorageを更新しません。
bodyStatus
function bodyStatus(bytes32 issueId, uint32 round, uint32 body) external view returns (T.NodeStatus status, T.Reason reason, uint64 at);
保存票と clock から Body の現在判断を計算する関数です。
-
Body入力を読む票数または固定報告者の提出値と
windowを取得する。 -
四値を判定する
threshold、blocking threshold、期限切れを評価する。 -
判断を返す
status、reason、値が形成された時刻を返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
対象 round です。 |
body |
対象 Body です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
status |
Pending、 Yes、 No、 NoDecision です。 |
reason |
NoDecision または VETO の理由です。 |
at |
値が形成された時刻です。 |
-
実行条件
-
view関数でstorageを更新しません。 -
期限前で
threshold未達ならPendingです。
nodeStatus
function nodeStatus(bytes32 issueId, uint32 round, uint32 node) external view returns (T.NodeStatus status, T.Reason reason, uint64 at);
指定 Node から下の Body と子 Node を評価し、現在の合成判断を返す関数です。
-
Nodeを読むPolicyからcombinatorと参照先を取得する。 -
子の四値を合成する
ALL、ANY、K-of-M、VETOの規則を適用する。 -
判断を返す
status、reason、formation instantを返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
対象 round です。 |
node |
対象 Node です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
status |
合成後の四値判断です。 |
reason |
合成結果の理由です。 |
at |
合成値が形成された時刻です。 |
-
実行条件
-
有効な
Node番号を指定します。 -
view関数でstorageを更新しません。
hasVoted
function hasVoted(bytes32 issueId, uint32 round, uint32 body, address voter) external view returns (bool);
指定 voter が同じ Issue、 round、 Body へ投票済みかを返す関数です。
-
1票
keyを作るIssue、round、Body、voterを組み合わせる。 -
保存
flagを読む受理済み投票の
mappingを参照する。 -
真偽値を返す
投票済みなら
trueを返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
対象 Issue です。 |
round |
対象 round です。 |
body |
対象 Body です。 |
voter |
確認する address です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bool |
投票済みかを表します。 |
-
実行条件
-
受理済み票だけが
trueになります。 -
view関数でstorageを更新しません。
activeIssueOf
function activeIssueOf(address consumer, bytes32 obligationKey) external view returns (bytes32);
consumer の同じ義務について、最後に保存した Binding Issue を返す関数です。
-
consumerとkeyを指定する並行
Issueを確認する組を渡す。 -
active mappingを読むadmissionで保存し、後続のadmissionまで残る値を取得する。 -
Issue IDを返す未登録なら
zero、登録後は終端済みを含む最後のIssue IDを返す。
返却された Issue が Final または Withdrawn なら排他制約は解放済みで、後続の admission が新しい Issue ID へ上書きします。
呼出側は返却値だけで進行中と判断せず、 getIssue 関数で state も確認します。
- 引数
| 引数 | 詳細 |
|---|---|
consumer |
結果を実行する主体です。 |
obligationKey |
義務と question から作る key です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bytes32 |
終端済みを含む最後の Binding Issue ID です。未登録なら zero です。 |
-
実行条件
-
Advisory Issueはactive mappingへ入りません。 -
view関数でstorageを更新しません。
obligationKeyOf
function obligationKeyOf(address consumer, bytes32 obligationId, bytes32 question) external pure returns (bytes32);
同じ consumer の同じ質問に対する義務を識別する key を計算する関数です。
-
3つの値を符号化する
consumer、obligation ID、questionをabi.encodeする。 -
hashを計算する符号化結果へ
keccak256を適用する。 -
keyを返すactiveIssueOfで使うbytes32を返す。
- 引数
| 引数 | 詳細 |
|---|---|
consumer |
結果を実行する主体です。 |
obligationId |
consumer が固定した義務範囲です。 |
question |
判定する質問の hash です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bytes32 |
obligation key です。 |
-
実行条件
-
pure関数でstorageを読み書きしません。 -
Binding Issueではzero以外のobligationIdを使います。
getEnactment
function getEnactment(bytes32 issueId, address consumer, bytes32 effectId) external view returns (T.Enactment memory);
consumer が報告した effect 実行結果を返す関数です。
-
検索
keyを指定するIssue、consumer、effect IDを渡す。 -
実行記録を読む
status、reporter、ref、時刻を取得する。 -
Enactmentを返す実行成功、失敗、未報告を区別できる構造体を返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
元の Issue です。 |
consumer |
effect を実行する主体です。 |
effectId |
Yes または No の effect です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
Enactment |
実行報告の保存内容です。 |
-
実行条件
-
記録がなければ
NotEnacted相当を返します。 -
view関数でstorageを更新しません。
ballotDigest
function ballotDigest(bytes32 issueId, uint32 round, uint32 body, address voter, bool approve) external view returns (bytes32);
署名投票で wallet と registry が共有するEIP712 digest を返す関数です。
-
ballot fieldを符号化するIssue、round、Body、voter、賛否を型付きdataへ入れる。 -
domainを加えるchain IDとIssue Registry addressをdomainへ入れる。 -
digestを返すvoterが署名し、registryが検証する32-byte値を返す。
- 引数
| 引数 | 詳細 |
|---|---|
issueId |
投票対象の Issue です。 |
round |
署名対象 round です。 |
body |
署名対象 Body です。 |
voter |
署名者です。 |
approve |
賛成または反対です。 |
- 戻り値
| 戻り値 | 詳細 |
|---|---|
bytes32 |
EIP712署名 digest です。 |
-
実行条件
-
view関数でregistry addressとchain IDを読みます。 -
署名の有効性や投票資格はこの関数だけでは判定しません。
clock
function clock() external view returns (uint48);
Issue Registry が期限計算に使う現在値を返す関数です。
-
clock sourceを読む実装が採用した
timestampまたはblock数を取得する。 -
48-bit値へ変換する
ERC6372互換の型で表す。
-
現在値を返す
clientがdeadlineと比較できる値を返す。
- 戻り値
| 戻り値 | 詳細 |
|---|---|
uint48 |
現在の contract clock です。 |
-
実行条件
-
view関数でstorageを更新しません。 -
単位は
CLOCK_MODE関数で確認します。
CLOCK_MODE
function CLOCK_MODE() external view returns (string memory);
clock 関数の単位と mode を文字列で返す関数です。
-
modeを読む実装が固定した
clock modeを取得する。 -
文字列を返す
clientがdeadlineを同じ単位で比較できる形式を返す。
- 戻り値
| 戻り値 | 詳細 |
|---|---|
string |
ERC6372の clock mode です。 |
-
実行条件
-
参考実装は
timestamp秒を使います。 -
block数と秒を暗黙に変換しません。
期限計算に使う clock 値と単位を公開する interface がERC6372です。
client は clock 関数と CLOCK_MODE 関数を読み、 Body window、 appeal window、 hard deadline を同じ単位で比較します。
ERC6372については以下の記事を参考にしてください。
Errors
規格は、拒否原因を5つの分類に分け、 reason string または同等の custom error で区別することを推奨します。
文字列そのものは相互運用要件ではありません。
参考実装の revert strings は、これらの分類を追跡するための実装上の手掛かりです。
| 分類 | 拒否する例 | 失敗時 |
|---|---|---|
Policy validation |
Body 数超過、 member 重複、循環 tree、時間上限不足 |
Policy を保存しない |
Issues and acceptance |
未登録 Policy、不一致な事前登録、期限切れ、 active obligation
|
Issue を admit しない |
Voting |
非 member、重複票、期限後、誤 round、無効署名 |
票数を変更しない |
Rounds and finality |
root が Pending、 appeal 期限外、最大回数超過、 hard deadline 前 |
procedure state を変更しない |
Enactment |
Final 前、 NoDecision、誤 consumer、誤 effect、 Enacted 後の更新 |
実行記録を変更しない |
どの分類でも revert した transaction の storage 更新とイベント発行はすべて戻ります。
ClockとProfile
最小 profile は、固定 roster の K-of-N 投票、オンチェーン集計、1つの Body、異議申立てなしです。
署名投票、固定報告者、複数 Body の合成、 VETO、異議申立ては任意 profile として追加できます。
実装は、対応 interface ID、 Policy 内の Body 方式、 clock mode を公開します。
client はこれらを読み、必要な profile へ対応できない registry や Policy を採用候補から外します。
参加資格の算出、ランダム選出、重み付き投票、二値以外の結果、手数料、 executor、 privacy、 multi-consumer、 cross-chain receipt の検証は予約領域です。
ERC8436の kernel は、これらを実装済みとして扱いません。
補足
実行する規則そのものを hash 化する理由
Policy Registry は、説明用ファイルの hash だけでなく、実際に実行する PolicySpec 全体から policyId を計算します。
参加者、閾値、合成 tree、時間、異議申立てのどれかが変われば、別の policyId になります。
コントラクト address や code hash だけでは、 Upgradeable proxy の実装差し替えや、外部 storage にある閾値変更を検出できません。
ERC8436の参考実装は non-upgradeable で、実行 parameters を Policy Registry へ保存します。
プロキシの implementation、 beacon、 admin を標準 slot から読む方法がERC1967です。
デプロイ監査では、 slot だけでなく、実装を交換できる authority と delegatecall 経路も確認します。
ERC1967については以下の記事を参考にしてください。
subject と obligation を分ける理由
Subject は何を評価するかを表します。
一方、 obligation は consumer のどの業務上の義務について、同時に1件だけ Binding Issue を許すかを表します。
成果物ごとに nonce を変えて obligation を毎回別物にすると、同じ質問を複数 panel へ出せます。
反対に、全作業へ同じ obligation を割り当てると、独立した成果物の判定まで止まります。
adapter は作業コントラクトの task ID、 submission ID、 version から安定した範囲を作ります。
四値合成と appeal mode
Yes と No だけで合成すると、入力受付中と判断不能を区別できません。
ERC8436は Pending、 Yes、 No、 NoDecision を保ったまま、 ALL、 ANY、 K-of-M、 VETO を評価します。
異議申立て後も同じ区別を使います。
PRESERVE_UNLESS_OVERTURNED では、 appeal round の NoDecision が前判断を消しません。
REQUIRE_FRESH_DECISION では、 appeal 開始時に前判断を採用候補から外すため、新 round の NoDecision が Issue 全体の NoDecision になります。
decision と execution の境界
Final decision は、 consumer へ新しい authority を与えません。
consumer は、元から操作できる業務コントラクトの current state と期限を確認し、自分の権限で effect を呼び出します。
effect call が失敗しても、 Issue Registry の decision は変更しません。
Failed enactment を記録し、再試行、既定処理、手動回復のどれを使うかは consumer 側の規則で決めます。
規格が予約する拡張
agent identity や reputation は、 roster 候補を選ぶ入力にできます。
ERC8004は agent identity と trust signal を表しますが、ERC8436の投票資格や consumer authority を自動で作りません。
ERC8004については以下の記事を参考にしてください。
weighted vote、 sortition、 non-binary outcome、 privacy、 fee、 executor、 cross-chain result carriage を追加する場合は、 Policy ID へ影響する parameters と検証規則を別 profile で固定します。
テストケース
公式 vector で固定する計算
公式 assets には、3種類の Policy ID、 ballot digest、83行の K-of-N 判定、192行の composition 判定、2つの interface ID があります。
実装者は、自分の ABI encoding、 EIP712 domain、四値合成、ERC165 ID を公式値と比較できます。
vector |
確認する内容 |
|---|---|
policy-id.json |
PolicySpec 全体から同じ policyId を作れるか |
ballot-digest.json |
chain、 registry、 Issue、 round、 Body、 voter、賛否から同じ digest を作れるか |
kofn-tally.json |
Yes、 No、 Pending、 NoDecision の閾値境界 |
composition.json |
ALL、 ANY、2-of-3の四値合成 |
interface-ids.json |
二 interface の selector XOR
|
integration evidence と非保証範囲
公式 discussion の Revision 3では、現行の Body role validation、 VETO と ALL の合成、オンチェーン投票、 reject path を Sepolia で実行した記録があります。
参考実装の Issue Registry は IR pipeline で23,514 bytes となり、EIP170の24,576-byte上限内ですが余裕は1,062 bytes です。
EIP170については以下の記事を参考にしてください。
これらは encoding と確認済み経路の証拠です。
第三者による本番採用、全 profile の public network 検証、 executor の稼働、 roster の独立性、投票内容の真実性までは保証しません。
互換性
既存 contract への adapter 接続
単一 evaluator や arbitrator address を受け取る既存コントラクトは、その address へERC8436 adapter を指定できます。
adapter が Issue を開き、 Final 結果を既存の accept または reject API へ変換するため、既存コントラクトの interface を変更せず接続できます。
ERC8183は、 client、 provider、 evaluator が作業を進める agent commerce の状態を定めます。
その単一 evaluator slot へ adapter を置くと、複数 Body の decision を1つの評価結果へ変換できます。
この読み替えにより、対応 API を選びます。
ERC8183については以下の記事を参考にしてください。
関連規格から読む値
client はERC165 ID から対応 API、 EIP712 domain から署名対象、ERC1271 magic value から contract voter の署名、ERC6372 clock mode から期限単位を確認します。
これらを1つでも暗黙値にすると、別 registry 向け署名や異なる時間単位を誤って受理します。
ERC8033は、特定 query へ情報 agent と judge を配置する council oracle を定めます。
複数の異なる Body、 consumer commitment、 NoDecision、異議申立てを1つの procedure record へ固定する用途ではERC8436を使い分けます。
Draft と policy version の固定
ERC8436は Draft であり、 interface や Policy layout が変わる可能性があります。
consumer は**family の最新版**だけを条件にせず、監査した registry instance と正確な policyId を固定します。
新しい Policy version を登録しても、既存 Issue と standing acceptance は自動移行しません。
移行時は、新旧 Policy の Body、 Node、 timing、 appeal mode を比較し、 consumer が新しい policyId を明示的に受け入れます。
参考実装
2つの registry は decision record を保存し、 consumer adapter だけが業務コントラクトへ effect を呼び出します。
二 registry の保存・評価境界
ACDFPolicyRegistry コントラクトは、検証済み PolicySpec と family version を保存します。
ACDFRegistry コントラクトは、その正確な Policy を参照して Issue、 round、 ballot、 result、 enactment を保存します。
後者の保存領域を、以下では ACDFRegistry acceptance and issue mappings として整理します。
署名検証の境界
SignatureChecker ライブラリは、ERC1271と canonical ECDSA の署名妥当性だけを返します。
member 資格、現在 round、期限、重複票は ACDFRegistry コントラクトが別に確認します。
consumer adapter の実行境界
ACDFTaskTenderAdapter コントラクトは、 Final-Decided を作業コントラクトの accept または reject へ変換します。
target call の失敗を catch して Failed を記録しますが、 decision は変更しません。
off-chain JSON Schema と authoritative registry の境界
公式の JSON Schema は、 Policy document と procedure receipt を off-chain tool 間で交換する形式です。
receipt は Filed、 Deciding、 Provisional、 Final、 Withdrawn を運べ、 Final 前は outcomeType が None になります。
effect 実行には別途 Final を確認します。
receipt は chain ID、 Policy Registry、 Issue Registry、 Issue ID を持ちます。
named registry の record を照合する carrier であり、 receipt 自体がオンチェーンの正本になるわけではありません。
ACDFPolicyRegistry
policy の検証と保存
ACDFPolicyRegistry._validate は、 Body 数、 Node 数、 member、K値、 window、 tree、 Body role、 appeal、 duration を確認します。
全検証が終わった後だけ、 _store 関数が Policy 全体、存在 flag、 round duration、 family authority、 latest version を保存します。
この入口と保存処理をまとめた経路が ACDFPolicyRegistry.registerPolicy/_store です。
次版では caller、 previous、 version を現在の family 情報と照合します。
途中で revert すると、どの mapping も更新されません。
検証条件は規格要件ですが、 private helper の分け方と mapping layout は参考実装固有です。
policy の読み取り
policyHeader、 timingOf、 bodyOf、 nodeOf の各関数から、実行に使う全 parameters を復元できます。
off-chain descriptor は descriptorHash で結び付きますが、投票判定へは使いません。
ACDFRegistry
issue の admission
file、 acknowledge、 admitAdvisory の各関数は、 acceptance mode に応じて consumer values を選びます。
_admit 関数は Policy、 active obligation、 consumer deadline、 hard deadline を確認し、 Issue と round 1を同じ transaction で保存します。
参考実装の file/acknowledge/_admit 経路では、受付方法が違っても同じ admission 検証へ合流します。
Issue ID を nonce から作る方法と private mapping の配置は参考実装固有です。
consumer commitment、 admission で固定する値、 Binding obligation の排他性は規格要件です。
ballot と四値評価
_castBallot 関数は member、 round、 window、重複を確認して票数を更新します。
_bodyStatus、 _nodeStatus、 _vetoStatus の各関数は、保存票と clock から四値判断を計算します。
以下では、この評価経路を _castBallot/_bodyStatus/_nodeStatus/_vetoStatus と表記します。
無効票で revert した場合、投票済み flag、票数、イベントのすべてが残りません。
K-of-N と composition semantics は規格要件です。
round と finalization
settleRound 関数は root status と formation instant を保存します。
appeal 関数は standing、 window、最大回数を確認して新 round を開きます。
finalize 関数と enforceHardDeadline 関数は appeal mode と hard cap から採用結果を決めます。
これらの状態遷移と内部確定処理を合わせた経路が settleRound/appeal/enforceHardDeadline/_finalize です。
enactment の記録
recordEnactment 関数は Final、 Binding、 consumer、 effect、 status を確認します。
Failed から Enacted への更新は許しますが、 Enacted 後の変更は拒否します。
外部 effect の実行自体は行いません。
SignatureChecker
contract 署名と EOA 署名
SignatureChecker.isValid は、署名者に code がある場合、ERC1271の isValidSignature 関数を staticcall します。
call 成功、32 bytes 以上の戻り値、 0x1626ba7e の magic value を確認します。
EOA 署名では65-byte長、 low-s、 v が27または28、 recover 結果が zero ではないことを確認します。
malformed signature や revert は bool の false になり、 batch 側が transaction 全体を revert します。
参考実装の revert strings は診断用であり、文字列自体は相互運用条件ではありません。
ACDFTaskTenderAdapter
issue を開く処理
ACDFTaskTenderAdapter.open は、 caller 入力だけで Subject や effects を作りません。
作業コントラクトから submission、 result hash、 task version、提出期限、支払期限、 accept と reject の effect ID を読み取ります。
adapter authority、 pending submission、 consumer deadline を確認した後、 consumer-filed Binding Issue を作ります。
作業 state が変わっていれば Issue を開かず revert します。
effect を実行する処理
ACDFTaskTenderAdapter.execute は、 Issue Registry から Final-Decided を読み、現在の作業 state と期限を再確認します。
Yes なら accept、 No なら reject を try / catch で呼び出します。
成功時は adapter state を enacted へ更新し、 Issue Registry へ Enacted を報告します。
target call 失敗時は Failed と reason event を残し、再試行を許します。
JSONSchema
policy document と result receipt
policy-spec.schema.json は、 PolicySpec の全 field を off-chain tool 間で交換する形式です。
tool は schema validation 後に全 field から policyId を再計算し、 Policy Registry から同じ policyId と parameters を読み、実行規則を照合します。
result-receipt.schema.json は、全 procedure state、 outcome、 Policy、 Subject、 consumer、 effects、 enactment を運びます。
Final 前の receipt 作成も許されますが、不可逆な effect を実行できるのは registry が Final-Decided を返した時だけです。
この2形式をまとめて参照する時は policy-spec.schema.json / result-receipt.schema.json と表記します。
セキュリティ
consumer authority と obligation scope
caller が自己申告した consumer address だけで Binding Issue を作ると、第三者が権限外の effect を約束できます。
consumer 自身の file、事前登録、事後承認のいずれかを確認し、 adapter は業務コントラクトの state から Subject と effects を導出します。
POST_ACK で投票後の承認を許すと、 consumer は有利な結果だけを Binding へ変えられます。
そのため、 acknowledgment を admission と投票開始より前に確定し、未承認 Issue は ack window 終了後に Advisory または Withdrawn へ進めます。
obligationId を毎回変えると panel shopping を止められません。
広すぎる値を使うと独立した Issue まで塞ぐため、同じ業務義務を安定して識別する粒度を選びます。
さらに、 admission 後の withdrawal を許すと、不利な途中経過を捨てて別 panel へ出し直せます。
withdrawal は未 admission の Filed に限定し、投票開始後は Final または hard deadline まで同じ Issue を維持します。
appeal と期限
PRESERVE_UNLESS_OVERTURNED では、 appeal round を意図的に NoDecision へすると前判断が残ります。
求める安全性が再審で新しい判断を必須にするなら REQUIRE_FRESH_DECISION を選びます。
permissionless な finalize や hard deadline enforcement があっても、自動 executor ではありません。
期限後に transaction を送る keeper、 consumer、利用者の経路を運用で用意します。
admission 時は、全 round と appeal が consumer deadline 内に収まるよう hardDeadline <= consumerDeadline を確認します。
ただし、 Final が consumer deadline の直前に形成されると effect 実行の余裕はほとんど残らないため、 adapter の arrival deadline と consumer deadline の間に運用上の buffer を設けます。
署名と replay
EIP712 domain は別 chain と別 registry への署名移動を防ぎます。
Issue、 round、 Body、 voter、賛否を署名対象へ含め、1票 key で再利用を止めます。
ERC1271の有効性は contract state で変わります。
registry が受理した票を後から無効化しないため、署名検証時点の state と transaction 確定性を監視します。
前提は、攻撃者が有効な署名を別の Issue、 round、 Body、 chain、 registry へ再送できることです。
EIP712 domain と ballot field のどれかが欠けると、意図しない案件へ同じ賛否が転用され、 threshold へ到達する可能性があります。
domain、全 ballot field、投票済み key を同時に照合し、ERC1271の staticcall が revert または不正な magic value を返した票は batch 全体で拒否します。
ただし、署名鍵の漏えい、 contract wallet の権限変更、確定前の chain reorg は registry だけでは防げません。
roster と evidence
異なる address が同じ operator に支配されていても、 kernel は検出しません。
identity、 operator cap、 conflict exclusion、 stake、 reputation は roster を作る外部 profile で確認します。
Evidence event の URI は信頼できない data として扱います。
取得した文書やAI向け prompt を命令として実行せず、 content type、 size、 hash、発行者を consumer 側で検証します。
registry と chain の信頼境界
consumer は、 registry instance、デプロイ済み bytecode、管理権限、正確な Policy version を固定します。
同じ interface ID でも、不正な実装が正しい semantics を保証するわけではありません。
Issue の Final は、対象 chain 上の procedure finality です。
source chain の reorg 耐性、 bridge、 cross-chain receipt の証明までは含みません。
攻撃者が同じ interface ID を返す偽 registry を配備すると、 consumer は存在しない投票や改変された結果を正規の decision として読まされます。
また、 cross-chain receipt を証明なしで受け入れると、別 chain の Final や古い fork の結果で effect が実行されます。
deployment address、 runtime code、 proxy 管理権限、 Policy Registry、 Issue Registry、 chain ID を allowlist へ固定し、 receipt は対象 registry の read 結果と照合します。
この対策後も、 source chain の finality assumption、 bridge validator、 consumer 自身の upgrade authority は信頼境界として残ります。
最後に
ERC8436は、複数のAIエージェントによる判断を、具体的な Subject、 question、 Policy、 consumer commitment へ結び付けます。
必要票へ届かなかった結果を NoDecision として残し、異議申立て後の採用規則も投票前に固定します。
Policy Registry は実行規則を保存し、 Issue Registry は投票、 round、最終結果、実行報告を保存します。
consumer だけが自分の authority 内で業務 effect を実行するため、投票資格と資産を動かす権限を分離できます。
導入時は、 roster の独立性、 obligation の粒度、 appeal mode、 clock 単位、 keeper、 registry instance、 effect 失敗後の回復を別々に確認してください。
他でも色々記事を書いているのでぜひよろしければ読んでいってください!




