「監査済みなら安心」——この思い込みは危険です。スマートコントラクトの脆弱性は、単一の欠陥でTVLが瞬時に蒸発する非連続リスクを生みます。本稿では投資家の立場から、監査(スマコン監査)をどう読み、どう補完し、最終判断に落とし込むかを実務の順序で解説します。専門用語は使いますが、手を動かして確認できる初歩の手順に落として説明します。
監査とは何を保証し、何を保証しないのか
監査は「一定の観点でのレビュー記録」にすぎません。保証しない代表例は次のとおりです。
① 経済設計の妥当性:トークンインセンティブやエミッションが価格クラッシュを招くかは、コード外の設計問題です。
② オラクル・マーケット依存:価格取得の遅延や歪みは仕様次第で起きます。
③ 運用オペレーション:権限ローテ、マルチシグ閾値、緊急停止の実装と運用体制は別問題です。
つまり監査レポートは必要条件であって十分条件ではありません。投資家は「監査のカバレッジ外」を自分で埋める必要があります。
監査レポートの読み方:5つの赤信号
1) 未解決のHigh/Mediumが残存:修正済みか、パッチのタグ・コミットIDまで追跡します。更新がリリースに反映されていなければ未解決同然です。
2) 再現手順の曖昧さ:PoC(概念実証)がテキストだけでコード不在なら、本当に直ったかが検証不能です。
3) 権限集中:アップグレード、ミント、パラメータ変更が単一アドレス権限になっていないか。実態がEOAなら運用リスクは跳ね上がります。
4) 外部依存:ブリッジやオラクルに対する依存が列挙されていない、あるいはフェイルセーフがない。
5) テストカバレッジ不明:単体・プロパティ・ファジングの別が記載なし。
コードを見る最低限の順序(初心者でもできる)
以下は読みやすい→重大影響の順です。リポジトリが公開されている前提で、タグは実デプロイのコミットに合わせます。
① 権限周り:Ownable
等のonlyOwner
メソッド、AccessControl
のDEFAULT_ADMIN_ROLE
の配布、マルチシグの閾値。
② 資産の出入り:transfer
、transferFrom
、safeTransferFrom
の呼び出し箇所を横断検索。入出金の単一経路化が理想。
③ 外部呼び出し:call
、delegatecall
、external
の有無。順序(Checks-Effects-Interactions)が崩れていないか。
④ パラメータ更新:手数料、担保率、上限額などガバナンス変数の上限・下限チェック。
⑤ 初期化:アップグレード可能プロキシでの二重初期化防止(initializer
修飾子)。
典型的な脆弱性と投資家の実務影響
1. リエントランシー
外部コール後の状態更新が遅れると再入可能になります。投資家への影響は、プール資産の抜き取りと会計不整合です。Checks-Effects-Interactionsの順序、ReentrancyGuard
、プル型払い出しの採用を確認します。
2. 整数オーバーフロー/アンダーフロー
近年はSolidity 0.8+で標準的に検出されますが、unchecked
ブロックや低レイヤ最適化で露出します。報酬計算の桁あふれはAPR/APYの虚偽表示に直結します。
3. オラクル依存と価格操作
低流動性ペアを参照するspot
一本足打法は危険です。TWAPや複数オラクルの合議、デペッグ検知のガードを確認します。
4. アクセス制御不備
緊急停止の呼び出し権限や、アップグレード管理者がEOAであることは赤信号です。マルチシグかMPCでの管理、タイムロック付与が望ましいです。
5. 初期化ミス/鍵漏えい
未初期化のプロキシ、テスト用鍵の残骸、公開レポジトリに秘密情報が残っていないか。これはゼロデイ級の破壊力です。
セルフレビューの最小手順(実務フロー)
1) デプロイ情報の固定:アドレス、チェーン、バージョン、コミットID、ブロック高。エクスプローラのソース検証が一致するか。
2) 依存関係ロック:package-lock.json
やfoundry.toml
のバージョン固定を確認。
3) 権限台帳を作る:各コントラクトの管理者・ミンター・パウザーを表にし、誰が何をいつ変えられるかを把握します。
4) 資金フロー図:入金→保管→出金の矢印を一本化。分岐や短絡(ショートカット)があると攻撃面が増えます。
5) 最小ファジング:境界値(0、最大値、同一トランザクション連打)で簡易ファズ。リワード計算や手数料が破綻しないか。
監査の「外側」を詰める:運用とガバナンス
・権限の分散:3/5以上のマルチシグ+タイムロック24–48h。
・緊急停止:停止ロジックが資産を凍結するのか、操作のみ無効化するのか。復帰手順と所要時間。
・パラメータ変更の透明性:オンチェーン投票or多署名の公開通知。
・運用監視:残高、価格乖離、オラクル遅延、ガス急騰のしきい値監視。
投資判断への落とし込み:スコアリング
定性・定量を混ぜてスコアリングします。
【例:20点満点】
・コード健全性(0–6):未解決のHigh=−3、外部呼出の順序正しい+2、テスト記述+1など。
・権限/ガバナンス(0–6):マルチシグ+2、タイムロック+2、権限範囲明記+2。
・外部依存(0–4):オラクル多重化+2、ブリッジ冗長化+2。
・運用体制(0–4):監視/アラート+2、インシデント手順+2。
閾値例:16点以上→許容、12–15→少額から、11以下→見送り。数式ではなく意思決定の拘束具として使います。
ケーススタディ:単純化した金庫コントラクト
以下の擬似コードは、典型的な落とし穴と是正案を同時に示します。
// 擬似Solidity
withdraw(amount) {
// NG: 外部呼出しを先にしている(リエントランシー)
token.transfer(msg.sender, amount);
balances[msg.sender] -= amount;
}
// 改善
withdraw(amount) {
uint256 b = balances[msg.sender];
require(b >= amount, "exceed");
balances[msg.sender] = b - amount; // Effects
bool ok = token.transfer(msg.sender, amount); // Interactions
require(ok, "transfer failed");
}
投資家としては、こうした書き換えの痕跡が実デプロイに反映されているか(コミット→タグ→アドレス)をトレースすることが要点です。
テストを一つだけ書くなら(最小実験)
・連続出金:同一トランザクションで2回withdraw
を試み、2回目が失敗すること。
・境界値:残高=0、最大値−1、最大値+1での挙動。
・権限:一般ユーザが管理関数を呼べないこと。
よくある誤解と対処
・「監査会社が有名ならOK」:バグはゼロになりません。自分のスコアリングで上書きします。
・「TVLが大きいから安全」:攻撃者の動機が強まり、逆に危険です。
・「アップグレード可能=柔軟で良い」:後出しで仕様変更できるため、投資家保護の観点ではリスクです。
まとめ
監査はスタート地点です。投資家は、権限・資金フロー・外部依存・運用体制を最小限の手順で確認し、独自スコアで意思決定を固定化します。複雑さを避け、確認可能性を重視することが、長期的な損失回避に直結します。
コメント