マルチシグとタイムロックの権限設定|待機時間の決め方と見落としやすい抜け道
約14分で読めます
約14分
目次(タップで折りたたみ)
スマートコントラクトの本番の権限を、「3-of-5のマルチシグと48時間のタイムロック」のような設定値から決めたとします。マルチシグは複数人の署名がそろわないと実行できない仕組み、タイムロックは承認後すぐには実行させず、決めた時間待たせる仕組みです。
ところが、どの操作がどの経路を通るかを決めていないと、逆転が起こりえます。緊急停止までタイムロックを通して48時間待たされる。一方で、全資産を動かす権限は、タイムロックを通らない別の経路に残っていて、即時に実行できてしまう。どちらも置いただけでは、本番の権限は守れないのです。
順番を変えます。
- まず、管理のための操作を、失敗したときの損失の大きさで分けます。
- 次に操作ごとに、誰が提案し、何人が承認し、どれだけ待ち、誰が実行・取消できるかを決めます。
- 最後に、緊急用の鍵や追加の部品から、待機を飛ばせる抜け道が残っていないかを確かめます。実際の権限のつながりを図にして探します。
以下では、EVM系のスマートコントラクトについて、この3つを順に進めます。事業責任者は、「管理操作を損失の大きさで分ける」「待機時間の決め方」「緊急権限の絞り方」の3節を読めば、判断に要るところがつかめます。
マルチシグそのものの仕組みと利点・注意点はマルチシグのメリットとリスクで解説しています。ここではその上に、本番の管理者権限をどう組むかを積み上げます。
この記事で使う言葉
- m-of-n(例:3-of-5):n人の署名者のうちm人の署名で実行できる設定
- しきい値:実行に要る署名の数(上の例のm)
- calldata:コントラクトへ渡す呼び出しの中身
- Safe:マルチシグのウォレットの1つ。機能を足す「モジュール」を付けられる
- フォーク環境:本番チェーンの状態を写し取った試験環境
管理操作を、失敗したときの損失の大きさで分ける
製品を選ぶ前に、管理のための操作をすべて書き出します。コントラクトのアドレスと、呼び出す関数ごとにです。そして、失敗したときの最大の影響と、元に戻せるかを評価します。
取り返しのつかない操作は、待っている間に誤りに気づき、取り消せるようにしたいものです。逆に、止める操作は、遅れるほど損失が広がります。だから、取り返しのつかない操作ほど長く待たせ、止める操作だけは即時にします。4つの区分に分けると、次のようになります。
| 操作の区分 | 例 | 承認・遅延の考え方 |
|---|---|---|
| A: 不可逆・全体 | アップグレード、発行上限の変更、全資産移動、ロール管理者の変更 | 高い署名しきい値、独立レビュー、長いタイムロック |
| B: 高影響・限定 | オラクル、手数料、ブリッジ、許可リストの管理 | マルチシグと操作別の遅延・上限 |
| C: 封じ込め | 一時停止、預入停止、上限引下げ | 少人数で迅速、対象と期限を限定 |
| D: 定常運用 | 少額支払、定期的な資産配分の調整 | 宛先、トークン、期間上限をコントラクトで制約 |
失敗したときの影響と、緊急時の手段は区分ごとに次のとおりです。
- A:資産の流出、残高やルールの全体の変更。緊急の手段は原則なし。取消か一時停止だけ
- B:対象の機能や市場に広がる。緊急時は、安全な側への値の変更だけを許す
- C:使えなくなる代わりに、損失の広がりを抑える。即時に動いてよい。再開はふだんの手順で
- D:設定した期間・金額まで。緊急時は取消か、上限をゼロにする
OpenZeppelin Contractsは、1人の所有者(Owner)だけでなく、役割ごとの権限の管理を用意しています。必要最小限の権限だけを与える考え方も説明しています。中でもDEFAULT_ADMIN_ROLEは、ほかのロールを管理でき、自分自身の管理者でもあるため危険度が高いものです。2段階の移転と待機を強制するAccessControlDefaultAdminRulesで和らげる方法が案内されています(OpenZeppelin Access Control)。
書き出す操作には、直接お金を動かすものだけでなく、「将来の実行権限を作る操作」も入れます。署名者の追加、しきい値の引き下げ、タイムロックの待ち時間の短縮、モジュールの追加、Proxyの管理者の変更などです。
マルチシグとタイムロックは、それぞれ何を防ぐのか
マルチシグは、n人の所有者のうちm人の署名がそろわなければ実行できない仕組みです。1つの鍵の漏えい・紛失・誤操作には強くなります。
ただし、必要な人数の署名者が同じものに頼っていれば、数字ほど独立していません。同じ端末、同じパスワード管理、同じ担当部署、同じクラウドの管理者などです。署名者が、悪い中身(calldata)をそろって承認してしまう危険も残ります。
タイムロックは、承認された操作をすぐには実行させず、待ち時間をチェーン上で強制します。OpenZeppelinのTimelockControllerでは、提案者(Proposer)が予約(schedule)し、最低限の待ち時間の後に実行者(Executor)が実行(execute)します。
待っている間に、見張り役が中身を確かめます。呼び出し先、送るETHの額、calldata、操作IDです。必要なら取消、一時停止、利用者への通知を行えます(OpenZeppelin TimelockController API)。
だから基本の流れは、「申請資料 → 提案用のマルチシグ → タイムロック → 対象のコントラクト」です。対象のコントラクトの持ち主(ロールの保有者)はタイムロックにします。マルチシグには、タイムロックへ提案する権限だけを持たせます。マルチシグが対象のコントラクトにも直接の管理者権限を持つと、待機を飛ばせてしまいます。
待機を飛ばせる抜け道がないか、権限のつながりを図にして探す
組織図ではなく、実際のアドレスの間の権限を図にします。矢印ごとに、「どのコントラクトのどの関数を呼べるか」を書きます。そのうえで、次の問いに1つずつ答えます。
- コントラクトの中身を差し替えられる人は誰か。その人は待機を飛ばして直接呼べないか。
- トークンの発行・焼却・一時停止・凍結、ロールの付与・取り消しは、誰ができるか。
- 資金管理、ブリッジ、オラクル、手数料の受取先、決済用のコントラクトは、誰が変えられるか。
- Safeの所有者、しきい値、モジュール、取引の事前チェック(Guard)は、誰が変えられるか。
- タイムロックの提案者・実行者・取消者・管理者は誰か。待ち時間を変えられるのは誰か。
Safeのモジュールも確かめます。モジュールは、ふだんの複数署名の流れとは別に、トランザクションを実行できます。Safe公式のDocsも、悪意あるモジュールはSafeを乗っ取れると警告しています。信頼でき、監査済みのものだけを追加するように、とのことです(Safe Modules)。
つまり、「Safeが3-of-5」というだけでは、本当のしきい値は分かりません。モジュール、Guard、所有者を変える権限まで確かめる必要があります。
コントラクトが増えて、個別のAccessControl(コントラクトごとのロール管理)の棚卸しが追いつかなくなることもあります。その場合の候補が、OpenZeppelinのAccessManagerです。複数のコントラクトのロールと対象の関数を1か所で管理し、ロールのメンバーごとに実行の待ち時間も設定できます(OpenZeppelin Access Management)。
ただし、AccessManagerの管理者そのものが、新しい弱点の集まる場所になります。その変更権限も、マルチシグ・待機・見張りの対象にします。問いに対応する部品名の一覧は、後半の「実装する人向けの詳細」にまとめました。
署名者の人数は、「一度にまとめて使えなくなる鍵」を数えて決める
3-of-5は、2つの鍵を失っても耐えられます。ただし、5つの鍵が同じ故障の影響を受けるなら意味がありません。
そこで所有者の候補ごとに、次のものを対応させて書き出します。
- 担当者、雇用関係
- 端末、署名用のデバイス、シードのバックアップ、保管場所
- ネットワーク、クラウド、本人確認・復旧の窓口
経営の承認と技術の確認を分ける場合も、前提があります。同じトランザクションハッシュと、読み解いたcalldataを、それぞれが独立に確かめられることです。
署名者を設計するときの論点は、次の5つです。
| 論点 | 設計する内容 | 避ける状態 |
|---|---|---|
| 独立性 | 部署、法人、端末、保管場所、認証基盤を分散 | 1人が複数の所有者鍵を保有 |
| 可用性 | 休暇・退職・災害時にも必要人数を確保 | 最低人数ちょうどで常時運用 |
| 内容確認 | チェーンID、呼出先、セレクタ、引数、送金額、nonceを別のツールで照合 | 署名画面の「Confirm」だけを見て承認 |
| 交代 | 追加→検証→削除の順序、期限、証跡 | 退職者の鍵が残る、先に削除して操作不能になる |
| 復旧 | 鍵喪失・危殆化を別の想定として演習 | シードを共有してしきい値を実質1に戻す |
しきい値の変更や所有者の追加は、将来の実行権限そのものを変えます。ふだんの送金よりも強い操作です。変更後の所有者の顔ぶれ、しきい値、モジュールの一覧を、トランザクションの結果とチェーン上の読み出しで確かめます。その時点の記録は台帳に残します。
待機時間は、気づいてから安全に対応できるまでの実際の時間で決める
タイムロックの長さは、「業界では48時間だから」で決めるものではありません。次の時間を実際に測り、余裕を足して決めます。
- 見張りが提案に気づくまで
- calldataとコードの違いを調べ、承認者へ連絡するまで
- 取消か一時停止を実行できるまで
夜間・休日、チェーンの混雑、RPCの障害、ハードウェアウォレットに手が届くまでの時間、関係者の時差も含めます。
1つの待ち時間を、すべての操作に当てはめる必要はありません。OpenZeppelinのAccessManagerは、ロールのメンバーごとに実行の待ち時間を持てます。TimelockControllerでも、最低限より長い待ち時間を操作ごとに選べます。
アップグレードや管理者の変更は長く、限られた設定値の変更は短くします。一時停止は、即時に動かせる別の手段にします。待ち時間を短くする操作そのものも、タイムロックを通ることを確かめます。
待ち時間が長いと、安全になる一方で、直すまでの時間も延びます。Compound V2の価格フィードの障害では、修正の提案が7日間のガバナンス上の待機を受けました。直接の損失は出ませんでしたが、待機が修正による回復を遅らせた実例です(Compound cETH Price Feed Incident Post-Mortem)。待っている間も、機能を絞って安全に動かし続けられる設計が要ります。
DAOで投票を経て実行する場合も、待ち時間の決め方は同じです。投票力の偏り、フラッシュローン、委任、予算の管理といったDAOならではの論点はDAOガバナンスの実行設計で扱っています。
提案から、実行後の確認までをどう進めるか
- 起案(Draft):ソースのコミット、チェーンID、呼び出し先、送る額、読み解いたcalldata、期待するイベント、シミュレーションの結果、取消の条件を、申請に固定します。
- 提案(Proposed):マルチシグのトランザクションハッシュを出します。申請者とは別の担当者が、中身を読み解いて照らし合わせます。
- 承認(Approved):必要な署名がそろっても、対象のコントラクトはまだ変えません。署名者の顔ぶれとしきい値を記録します。
- 予約(Scheduled):予約した中身から操作IDを作って、タイムロックに登録します。実行するときに、中身がすり替わっていないかを確かめられるようにするためです。
- 待機(Waiting):独立した見張りが、提案、実行予定の時刻、ロールの変更、待ち時間の変更を知らせます。フォーク環境でのシミュレーションもやり直します。
- 実行可(Ready)/取消(Cancelled):条件を満たした操作だけを実行します。違い・事故・期限切れがあれば取り消します。
- 実行済み(Executed)/確認済み(Verified):処理結果だけでなく、所有者、ロール、実装の差し替え先、設定値、残高の関係、イベント、フロントエンド・インデクサーを確かめます。
署名がそろったことと、正しい変更が本番に入ったことは別です。トランザクションが成功しても、違うコントラクト、別のチェーン、間違った設定値を変えているかもしれません。最終の状態を読み出して期待した値と照らし合わせるまで、完了にしません。
緊急権限は、速く動ける代わりにできることを絞る
緊急時の手段は、ふだんより速く動ける分、できることを狭くします。許すのは、安全な側で元に戻せる操作だけです。即時の一時停止、預入の停止、支出上限の引き下げ、特定のモジュールの無効化などです。
任意の送金、任意のアップグレード、上限の引き上げ、ロールの付与まで許すと、待機を飛ばして同じことができてしまいます。それでは、タイムロックは意味をなくします。
緊急の操作には、次のことを決めておきます。
- 対象のコントラクトと関数、最長でどれだけ続けるか
- 発動の条件、知らせる先
- 再開の条件、事後のふり返りの期限
一時停止の解除、恒久的な修正、資産の移動は、ふだんのマルチシグ+タイムロックに戻します。取消者(Canceller)は、不正な操作は止められても、新しい操作は作れず実行もできない人にします。そうすれば、緊急の担当者が資産を持ち出すのを防げます。
本番の前に、権限を失ったときと抜け道を試す
正常に動くことより、次の異常で壊れないかを先に確かめます。
| 試験 | 注入する状態 | 合格条件 |
|---|---|---|
| 単独侵害 | 所有者の1鍵、提案者の1鍵を攻撃者が保持 | 高影響の操作を予約・実行できない |
| 署名者喪失 | 複数の所有者が応答不能 | 定めた目標復旧時間(RTO)内に交代でき、単独の復旧鍵を使わない |
| 迂回 | モジュール、別の管理者、ProxyAdmin、緊急鍵から直接呼出 | タイムロック対象の操作がすべて拒否される |
| 悪い提案 | 誤ったチェーン、誤った呼出先、似たセレクタ、値の桁違い | 署名前または待機中に検知・取消できる |
| 可用性 | RPC停止、ガス高騰、ハードウェアウォレット故障 | 代替経路で監視・取消・限定的な一時停止ができる |
| 自己ロック | 提案者・実行者の喪失、管理者権限の放棄順序の誤り | 権限を迂回せずに復旧できるか、できなければ移行手順がある |
最後の「自己ロック」には注意が要ります。TimelockControllerを自分で自分を管理する形にし、デプロイ担当者の管理者権限を手放せば、抜け道は減ります。けれども、提案者や実行者をすべて失えば、管理対象ごと無期限に固まりかねません。OpenZeppelinもこの点を注意しています(Using TimelockController)。
権限を手放すのは最後です。所有者の顔ぶれ、ロール、待ち時間、予約、取消、実行を、本番と同じ環境で一通り試してから行います。
マルチシグ+タイムロックを使わない、または追加の制御が要るのは、どんなときか
1人で運用する小さなPoCで、資産を持たず、止めて出し直せるなら、複雑なタイムロックはかえって障害からの復旧を難しくすることがあります。
反対に、秒単位で回るふだんの処理は、人の手のマルチシグに載せません。自動化のモジュールや別のコントラクトに切り出し、次のもので縛ります。
- 宛先の許可リスト
- 1回ごと・期間ごとの上限
- 用途を限った鍵と、見張り
回数の多い処理を楽にするために、本番の管理者のしきい値を下げないことが大切です。
マルチシグとタイムロックだけでは解決しないこともあります。コントラクトの不具合、署名者の共謀、不十分な見張り、誤った仕様、鍵の開示の強要です。資産の規模に応じた保管の判断も、技術の構成だけでは決まりません。監査や組織の統制とは分けて評価します。
導入のときに残しておくもの
- コントラクトアドレス×関数セレクタ×ロール×実行する主体の権限表
- マルチシグの所有者、しきい値、独立性、交代・復旧の手順
- タイムロックのロール、最低の待ち時間、操作ごとの待ち時間、取消・期限切れの条件
- モジュール、Guard、ProxyAdmin、AccessManager、緊急鍵を含む権限のつながりの図
- 申請、読み解き、シミュレーション、署名、予約、見張り、実行、事後の確認の運用手順書
- 鍵の侵害、鍵の喪失、悪い提案、RPCの障害、自己ロックの演習の結果
アップグレードの方式と、保存データ・移行の試験まで含めて考えるなら、スマートコントラクトのアップグレード設計で方式の選び方を扱っています。Safeのアカウント・モジュールの構成を比べるならSafeのモジュラー設計と採用判断、署名鍵をHSM・MPCで持つならHSM・MPCを使った署名鍵の本番運用をご覧ください。
実装する人向けの詳細
ここからは、権限の棚卸しや予約の仕組みを実際に組む開発者向けの補足です。
操作を書き出す単位
管理操作は、コントラクトアドレスと関数セレクタ(呼び出す関数を識別する4バイトの値)の単位で書き出します。
権限の図で追う部品
- Proxy、Implementation、ProxyAdmin、Beacon、AccessManagerの所有者・管理者
- トークンの発行・焼却・一時停止・凍結、ロールの付与・剥奪
- 資金管理、ブリッジ、オラクル、手数料の受取先、決済用のコントラクト
- Safeの所有者、しきい値、モジュール、Guard、fallback handler
- タイムロックの提案者・実行者・取消者(Canceller)・管理者と
updateDelay
Safeのモジュールは、execTransactionFromModuleからトランザクションを実行できます。
予約するときの操作ID
タイムロックへ登録する操作IDは、同じ呼出先、送金額、calldata、predecessor、saltから算出します。
実行後に読み出す値
実行済みの確認では、トランザクションのレシートに加え、Implementationスロットと残高の不変条件を読み出して照らし合わせます。
XTELAができること
私たちは、権限表とオンチェーンの権限グラフを作り、操作ごとの承認人数・待機時間、フォーク環境でのシミュレーション、監視、障害時の手順書までを設計・実装します。本番前の迂回試験や自己ロックの演習もPoCとして一緒に回し、貴社の運用体制に合う形に仕上げます。技術設計のご相談はお問い合わせからご連絡ください。
主要参考資料
- OpenZeppelin Contracts 5.x: Access Control(2026年9月24日確認)
- OpenZeppelin Contracts 5.x: TimelockController API(2026年8月12日確認)
- OpenZeppelin Contracts 5.x: AccessManager API(2026年8月12日確認)
- Safe Docs: Safe Modules(2026年9月24日確認)
- Safe Help Center: What is a transaction guard?(2026年8月12日確認)
- Compound: cETH Price Feed Incident Post-Mortem
資料の確認日と注意
仕様・公式資料は2026年8月12日に確認し、OpenZeppelinとSafeの記述は2026年9月24日に確認し直しました。EVM系の技術情報をもとにした一般的な設計の解説です。導入時は、利用するコントラクトのバージョン、チェーン、署名基盤、モジュール、監視基盤の公式資料と監査範囲を確認し直してください。カストディ該当性などの法的な判断は、専門家へご確認ください。