Crypto OS
Technical Crypto OS第4段階 · DeFi 開発

T21 · オラクル

チェーンは、外部の価格をどう知るか?

この章を 3D で体験する →
練習する能力
BuilderProtocol Literacy
実践
価格フィードを接続し、更新頻度と乖離のしきい値を記録して、データが古くなった場合のコントラクトの動きを模擬する。
AI Lab
AI に現物プール価格をオラクルに使うリスクを分析させ、操作に必要な資金を自分で計算する。

現実の問題

トークン X を担保にステーブルコインを貸すコントラクトを作ります。

担保価値を、借入額の一定倍以上に保つのが中心です。

uint256 collateralValue = amount * getPrice(token) / 1e18;

問題は getPrice です。チェーンのコントラクトは HTTP を送れず、取引所価格も読めず、チェーンにあるデータしか読めません。

AMM プールなら、準備金比が無料で即時の価格になり、第三者も不要です。

こう書きました。

function getPrice(address token) public view returns (uint256) {
    (uint256 r0, uint256 r1) = pair.getReserves();
    return r1 * 1e18 / r0;     // この一行の価値はいくらか?
}

T19 では、定積価格を二倍へ動かすには、片側準備金の約 41% が必要でした。

片側 100 万なら 41 万で、安くは見えません。

しかし攻撃者は、41 万を所有する必要がありません。一取引で借り、価格を動かし、過剰借入し、価格を戻して返済できます。同じブロックで、元本はほぼ不要、費用は手数料だけです。

その一行は、コントラクトの全資金に値します。

思考実験

窓がなく、扉に細い隙間だけある部屋へ閉じ込められた人を考えます。

外の金価格に応じて訪問者へ支払いますが、自分では見えません。

隙間から数値の紙が入ります。

従う前に、四つの問いが必要です。

第一は、誰が書いたかです。 誰でも入れられるなら最後の人が価格を決めます。特定の筆跡だけを認めます。

第二は、いつ書いたかです。 時刻なしでは、5 秒前と 3 日前を区別できず、変動時に危険です。

第三は、前回との差です。 100 から 10000 なら、相場でなく悪ふざけか、情報源の故障かもしれません。

第四は、長く紙が来なければ何をするかです。 最後を使うか、止めるか、保守的に動くか?

普遍的な正解はなくても、全問にコード上の明確な答えが必要です。 省けば最も危険な既定値を選びます。

AMM は、誰でもお金で書き換えられる紙で、時刻すらありません。

あなたが決める

借貸用の価格源を選びます。

結果を観察する

比較します。

情報源操作費用遅延依存先失敗の形
瞬間価格非常に低い、借りた資金で可能なしなし一取引で書き換え
同プールの平均中、維持が必要窓の長さなし急変に遅れる
外部更新高い、複数提供者の侵害秒〜分外部コントラクトと運営停止、遅延、境界固定
複数源の中央値最大遅い源次第複数外部一源失敗の処理

費用を一般化します。

安全な情報源という絶対値はなく、操作費用が抽出価値より高い情報源があります。

比率が役立ちます。

安全余裕 = 価格操作費用 / 攻撃者が取り出せる最大額

1 未満   → 時間の問題で攻撃される
1 付近   → 相場や Gas の変化で逆転する
1 より大 → 暫定的に安全だが、両側が時間で変わる

分母は総 TVL でなく、誤価格で引き出せる最大額です。 総量の 1% の資産でも、全ステーブルプールを借りられるなら分母は全体です。

分子も分母も定数ではありません。

流動性移動で操作費用が減り、担保率増で抽出額が増えます。コードを変えなくても、半年後に安全でなくなり得ます。

モデルを作る

連鎖を見ます。

  1. 実際の市場価格
  2. 情報提供者
  3. オフチェーン集約
  4. チェーンの価格コントラクト
  5. 自コントラクトの判断
各環に異なる失敗があります。制御できるのは最後だけでも、先の四環の失敗へ備えます。
環失敗最後でできること
市場流動性枯渇、公正価格なし関連操作の停止
提供者停止、誤値集約の中央値に依存
外の集約全体停止、遅延時刻確認
価格コントラクト更新、停止、境界値範囲と合理性の確認
自コントラクト未確認で使用本章全体

四パラメータは設定可能です。源、資産、チェーンで異なるので、例の桁だけを示し、実数は Lab で調べます。

パラメータ意味典型の桁必要な理由
Heartbeat最大更新間隔分〜時間期限設定の基準
Deviation早期更新の価格差0 数%〜数%静穏時の古さ
Decimals値の桁数通常 8 か 18誤ると桁違い
値の境界最大、最小資産別極端相場で偽価格を返す

境界保護では、実価格が範囲外へ出ても、正常な形式で境界値を返します。時刻だけ確認すると、誤価格で動き続けます。

四確認をコードにします。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPriceSource {
    // 価格と生成時刻
    function latest() external view returns (int256 price, uint256 updatedAt);
}

contract PriceGuard {
    IPriceSource public source;
    uint256 public maxStaleness;   // 最大の古さ。通常 heartbeat の数倍
    uint256 public minPrice;       // 合理的な下限
    uint256 public maxPrice;       // 合理的な上限
    uint256 public maxJumpPercent; // 前回信頼価格からの最大変動率

    uint256 private lastGoodPrice;
    uint256 private lastGoodAt;

    error StalePrice(uint256 age);
    error PriceOutOfRange(uint256 price);
    error PriceJump(uint256 from, uint256 to);

    function readPrice() public view returns (uint256) {
        (int256 raw, uint256 updatedAt) = source.latest();

        // 1:ゼロと負値を拒否
        if (raw <= 0) revert PriceOutOfRange(0);
        uint256 price = uint256(raw);

        // 2:期限切れを拒否
        uint256 age = block.timestamp - updatedAt;
        if (age > maxStaleness) revert StalePrice(age);

        // 3:集約境界へ接した値を拒否
        if (price <= minPrice || price >= maxPrice) revert PriceOutOfRange(price);

        // 4:前回から閾値を超える変動を拒否
        if (lastGoodPrice > 0) {
            uint256 hi = price > lastGoodPrice ? price : lastGoodPrice;
            uint256 lo = price > lastGoodPrice ? lastGoodPrice : price;
            if ((hi - lo) * 100 > lo * maxJumpPercent) revert PriceJump(lastGoodPrice, price);
        }

        return price;
    }
}

第三が漏れやすく、第四には議論があります。

実際にも数十% の急変が起きます。 厳しすぎると最も必要な時に拒否し、清算を止め、不良債務を増やします。操作防止と停止防止の取引で、普遍的な値はありません。

さらに重要なのは、データが使えない時の動作です。三方式から明示的に選びます。

方針動作適する操作代償
全巻き戻しrevert借入、担保引き出し清算も止まる
縮退リスク減少のみ許可返済、担保追加全入口の分類が必要
代替価格予備源か最後の信頼値清算代替も操作され得る

全面 revert は誤りやすい方法です。 安全そうでも、急変で最も清算が必要な時に止めます。

通常は、リスク増加は新価格を要し、減少は価格なしでも許します。

何と呼ぶか

Oracleオラクル

外部情報をチェーンへ持ち込む機構です。

技術より信頼の問題です。同履歴は検証できても、外の金価格は自分で検証できず、外部に信頼を置きます。

Price Feed価格フィード

継続的に価格を書き込むコントラクトと運営です。

価格と生成時刻を読む必要があります。価格だけでは安全に使えません。

Heartbeat更新のハートビート

価格が変わらなくても更新する最大間隔です。

期限が短すぎれば誤検出、長すぎれば古値を許します。通常数倍にし、資産別に設定します。

Deviation Threshold乖離閾値

前回からの変動で、予定前の更新を起こす幅です。

平穏時は周期、変動時は乖離で更新します。静穏時の古さは通常問題なく、変動時に追随するかが重要です。

TWAP時間加重平均価格

一定窓の累積から求める平均です。

高めるのは精度より操作費用です。誤値を維持させる代わりに遅れ、窓は安全性と応答性の取引です。

Price Manipulation価格操作

取引で情報源を変え、依存コントラクトから利益を得ます。

多くはバグでなく、合法な取引の組み合わせです。動かし、対象を呼び、戻し、正しいコードの想定を回避します。

Circuit Breakerサーキットブレーカー

異常時に一部機能を止めます。

鍵は何を止めるかです。全部なら清算も止まり、増加だけなら自力回復を続けられます。

実践

実践価格源の更新間隔と乖離を調べ、期限切れ時の動作を模擬するテストネット + フォーク環境 + コントラクトテストフレームワーク0 円、テストネットとローカルフォークのみ

コードの前に調査します。 主流と小規模の二資産で埋めます。

主流資産小資産
最大更新間隔
乖離閾値
桁数
24 時間の実更新数
最長更新間隔
上下界の有無と値

最後の二行は実データから統計し、文書を写しません。約束と実際が違うこともあります。

PriceGuard の四確認を実装します。非正値、期限、範囲、急変に、別のエラーを設けます。

フォークで読みます。 エクスプローラーと一致し、特に精度を確認します。8 を 18 と扱うと十桁違っても、エラーが出ません。

制御可能なスタブで四故障を試します。

  1. 一時間前の時刻 → 期限切れ
  2. 0 → 非正値
  3. 上界 → 範囲外
  4. 前回の 10 倍 → 急変

区別できて第一層が完成します。

期限切れの動作を決めます。

借入、担保引き出し、返済、清算の各入口を分類し、テストします。

入口期限切れ時理由
借入
担保引き出し
返済
清算

全部を巻き戻すなら、第三、第四を再考します。 返済と清算を拒否すると、不良債務を増やします。

操作費用を計算します。中心の演習です。

瞬間価格の版で計算します。

片側深度 D、貸せるステーブル額 L、担保率 c(例えば 0.75)

1. X を m 倍に動かす資金は約 D * (sqrt(m) - 1)
2. 実価値 V の X から借りられるのは min(V * m * c, L)
3. 元本は同取引で借り返せてほぼ不要。
   実費 = 二交換手数料 + Gas + フラッシュローン費用
        ≈ D * (sqrt(m) - 1) * 0.6% + その他
4. 純利益 = 2 - 3 - 担保の実価値
5. 安全余裕 = 3 / 2

D = 100 万、1000 万、5000 万、m = 2、L = 500 万で試します。

第一の安全余裕は 1 よりはるかに小さくなります。 記録し、新源導入時には比率を先に求め、許容する倍数未満なら公開しません。

L = 500 万なら、攻撃が割に合わない最低深度はいくらですか? 安全に担保へ入れる最低流動性です。

テストネットとローカルフォークだけで、実資金は使いません。 卒業課題でも第五段階の安全性確認後です。

AI Lab

AI LabAI に瞬間価格のリスクを分析させ、必要な操作資金を自分で計算するLevel 2 · AI Copilot

三段階で問いかけます。

第 1 段階:
定積の瞬間準備金比を担保価格へ使い、深度 D、借出可能 L とします。
全攻撃工程と、代入可能な費用式を示してください。

第 2 段階:
同プールの N ブロック TWAP へ変え、費用を再導出してください。
倍率と、その前提も示してください。

第 3 段階:
残る五つのリスクを、確率と損失の積で並べ、検出信号を示してください。

第一の概要は答えられても、費用で間違えます。41 万元本を費用とし、借り返せることを漏らせば、百倍程度の差が安全判断を変えます。

第二は「より安全」だけでなく倍率が必要です。各ブロックの費用と、裁定者の逆取引を追問します。

第三が成果です。第五工程の表と照合し、未考慮の入口を探します。

具体値はすべてチェーンで確認します。 幻覚が起きやすく、もっともらしいので気付きにくいものです。

AI の回答後、自分で必ず検証すること

  • 同取引で借り返せることを費用計算へ含め、必要元本だけを費用としない
  • 平方根を含む式が、手計算と一致する
  • 抽出価値を総 TVL でなく、誤価格で実際に借りられる額にする
  • TWAP の費用増加倍率を自分で導ける
  • 生成時間が窓内の操作費用を変えることを扱う
  • 更新間隔、閾値、担保率の具体値を、記憶でなくチェーンで照合した

実例

瞬間価格で担保を評価した2020 年以降繰り返し

大口を一取引で借り、価格を上げ、小担保で過剰なステーブルを借り、戻して返済する同じ形です。

コントラクトにバグはありません。 呼び出しも送金も確認も正常で、回避したのは価格が信頼できるという想定です。

大きな損失を生む経済攻撃でも、情報源アドレスの変更で防げることがあります。

浅い資産を担保にした複数の事故

情報源は正常でも、市場が小さく、どこでも操作が安価でした。

実市場で買い上げ、主流資産を借り、担保を放棄すると、換金不能の資産と不良債務が残ります。

正しい価格だけでなく、その背後の深度も安全性です。 担保適格性は市場深度と上限に依存します。

更新停止後も古値を使った複数回複数チェーン

混雑、提供者故障、廃止で停止しました。

時刻未確認では、急落時も清算すべきポジションが健康に見えます。再開時に一斉に債務超過となります。

時刻確認と、桁ほど違い得る更新間隔を資産別に設定する理由です。

極端相場で境界へ固定された急変時

実価格が下界を下回っても、新時刻、正値、正形式で下界を返しました。

担保を過大評価して清算せず、調整時には既に債務超過でした。

新鮮さだけでなく合理性も確認します。 独立源との乖離で停止し、複数源の価値を異常検出に使います。

変数を一つ変える

もしTWAP を 30 分から 5 分へ短縮する

応答が六倍速く、清算が適時になり、T22 の不良債務が減ります。

操作費用は窓にほぼ比例して減り、逆裁定を受ける時間も短くなるため、実際にはさらに大きく減り得ます。

守る額から窓を逆算します。 許容安全余裕を先に決めます。

もし生成時間が 12 秒から 0.4 秒のチェーンへ変える

30 ブロックが 6 分から 12 秒になり、ブロック数の窓なら、保護が静かに三十分の一になります。

時刻なら長さは同じでも、維持するブロックが増え、費用が増える可能性があります。

時間関連の設定は換算し直し、コピーしません。 跨チェーンの危険な想定です。

もし独立した第二源を加え、乖離で停止する

単一故障を減らし、能動的な異常信号を得ます。

一方の揺れでも止まり、可用性が思った以上に落ちます。

停止中も返済と担保追加を許し、最も緊張した時に自力救済を拒否しません。

もし市場深度が数十万しかない担保へ変える

費用の分子が下がり、抽出額は同じで、比率が 1 未満になります。

資産自体を動かしやすいため、完璧な情報源でも、実市場の買い上げを防げません。

抽出上限を操作費用未満へ制限します。データ源でなくパラメータの問題です。

持ち帰る問い

2
なぜブロックチェーンが必要なのか?

なぜ Blockchain が必要ですか?同履歴を保証しても、外部事実を自分では検証できません。オラクルが境界のインターフェースで、最も分散的でない部分です。

8
誰が流動性を提供するか?

誰が流動性を提供しますか?深度は操作費用を決めます。市場深度は、価格源の安全予算です。 移動すればコードなしでも危険になります。

9
誰がリスクを負うか?

誰がリスクを負いますか?情報提供者でなく、準備金と LP です。価格を出す人は、誤価格の結果をほぼ負いません。

10
インセンティブは何か?

動機は何ですか?罰没可能な担保、評判、契約のどれで誠実にするか確認します。信頼の深さを決めます。

章末チェック

要点

オラクルはプロトコルで最も一般的な単一障害点であり、攻撃の入口でもある。

この章の実践課題を終えたらチェックしてください進捗をすべて見る

このページの内容