FABRKNT
Step 5. Liquidation:レバレッジ環境における非単調性の発見と清算エンジンの構築
Orientation
レッスン 1 / 14·CONTENT15 分50 XP
コース
Step 5. Liquidation:レバレッジ環境における非単調性の発見と清算エンジンの構築
レッスンの役割
CONTENT
順序
1 / 14

レッスン0 — OpenHL Liquidation を作る(永久先物ポジション liquidation エンジン)

問い

前コース(Funding)で mark と index の乖離を funding payment で抑える仕組みは手に入った。だがトレーダーの損失が預け入れ collateral を超えたら? その時ポジションを consensus 内で force-close し、不足分を吸収するエンジンを、float なしの決定論で作るには?

注: OpenHL コースのコードブロックは原則として手元で実行可能な形で示す。ただし <file> などのプレースホルダや答え合わせ用コマンドは、各レッスンの指示に従って置換してから実行すること。

原理(最小モデル)

  • perp はレバレッジ position。損失が collateral を食い equity / notional が maintenance margin を下回ると force-close。 反対 side・フルサイズで close、liquidation fee を collateral から引いて insurance fund へ、equity が正なら残りをアカウントに返す。equity が負(underwater)なら不足分を insurance fund が吸収。
  • liquidation は consensus 内で実行する。 全 validator が全 block で、同じデータ・同じコードで maintenance 割れを独立計算する。オフチェーン bot に外注すると、検知〜close の RPC ラウンドトリップ遅延がそのまま chain の損失になる(50× の position は数秒で healthy→underwater に反転しうる)。
  • float 禁止 — consensus が壊れる。 あるアカウントを Liquidatable と分類する validator と AtRisk と分類する validator がいると、close orders / fees / insurance-fund deltas が食い違い block が分岐して fork する。固定小数点 MARGIN_SCALE = 10_000(bps)+ saturating + i64 overflow しうる乗算に i128 中間値。
  • 4 状態の margin classification。 Safe / AtRisk / Liquidatable / Underwater — 各状態が engine に何を許可するかを決める。
  • insurance fund は単なる u64 残高でなく pure state machine。 独自の遷移ルール(deposit / withdraw / absorb_deficit の不変条件)を持つ。

具体例

トレーダーは collateral(USDC) を預け、entry 価格で size(符号付き: 正=long、負=short)の position を開く:

unrealized PnL  = size とともに mark で動く(long は mark>entry で利益)
equity          = collateral + unrealized_pnl
margin_ratio    = equity / notional  (notional = |size| × mark)
  margin_ratio < maintenance(2%) → Liquidatable → force-close + fee → insurance fund
  close 前に equity < 0 → Underwater → 不足分を insurance fund が absorb

bps が margin の慣例単位(HL/Binance/Drift とも)。MarginRatio(1_000) = 10%、MarginRatio(MARGIN_SCALE) = 100%。

失敗例(誤解)

「liquidation はオフチェーンの liquidator bot(アカウントを scan して liquidate(account) を呼ぶ)に外注すればいい」は誤り — perp のスピードでは破綻する。低頻度 settlement(CDS 等)なら機能するが、50× レバレッジの position はニュース cascade で数秒のうちに healthy から underwater に反転する。検知から close までの RPC ラウンドトリップの遅延は丸ごと chain 側の損失として残る。敵対的な市場の動きのもとで chain が支払い能力を保つ手段は、consensus 内 liquidation 以外にない。


ここまでで「なぜ consensus 内 liquidation」「なぜ float 不可」は着地した。ここから先はスコープ・前提・14 レッスンのロードマップに入る。L1 以降は実際に Rust を書く。

🛑 予測。 2 つの validator が同じアカウントの margin health を分類する。片方が f64equity / notional を計算したら、もう片方と bit-exact に一致するか?(答え: 保証されない。float は compiler/CPU/演算順で最下位ビットが食い違いうる。分類が 1 段でもズレると(AtRisk vs Liquidatable)、生成される block が変わり fork する。だから bps スケールの符号付き整数で分類する — 整数演算は全プラットフォームで byte-identical。)

終了時に手にするもの

新規 crates/liquidation/ crate、3 ソースファイル / ~600 LOC:

  • 固定小数点 types モジュールMARGIN_SCALELiquidationParamsMarginRatioMarginHealth enum、AccountSnapshotCloseOrderSpec
  • 純粋な compute モジュール(margin math)notional_value / unrealized_pnl / account_equity / margin_ratio / margin_health / close_order_spec
  • state machine(insurance fund)+ multi-account scannerInsuranceFunddeposit/withdraw/absorb_deficit/credit_fee)と LiquidationScannerscan)。
  • 24+ tests(compute マイルストーン時点、capstone までに増える): hand-traced unit test、margin-ratio の単調性・determinism proptest、insurance fund の保存則 invariant。

終了時にも手にしないもの(意図的な scope cut)

  • Auto-deleveraging(ADL) — この設計の端に位置づくが、本コースでは扱わない(別コース building-openhl-adl)。
  • Oracle(mark/index の供給元) — liquidation は mark を 入力 として受け取るだけ。
  • Bridge 統合 — liquidation engine は純粋な state machine として完結。LiveRethEvmBridge への plug-in は capstone でプレビューし、実装は下流。

前提

  • Step 4(Funding) が頭にあること — fixed-point / saturating 演算 / pure state machine のパターンが再登場する(funding が難しかったなら本コースも難しい)。
  • Step 2(CLOB)AccountId / Side / Qty を直接再利用する(matching engine の内部までは不要)。
  • 基本レベルの margin math(「initial margin 10% / maintenance 2%」で混乱しない程度)。
  • EVM / precompile の知識は不要(liquidation は純粋な state-machine 数学)。

不要: 動作中の openhl ノード(zero I/O)/ 取引所リスクエンジン経験 / 定量金融バックグラウンド。

セットアップ(今やる)

cd ~/code/my-openhl
git checkout main
cargo build --workspace  # baseline — L1 前に通るべき

cd ~/code/openhl-reference  # answer-key 用の別チェックアウト
git checkout 22eedf9

14 レッスンのロードマップ

#build するもの終了時テスト
0Orientation(本レッスン)セットアップ確認
1MARGIN_SCALE = 1e4(bps)+ LiquidationParams + hyperliquid_default()cargo check -p openhl-liquidation
2MarginRatio newtype + MarginHealth enum(4 状態)型がコンパイル
3AccountSnapshot + CloseOrderSpecroster 完成
4notional_value + unrealized_pnl(signed-multiplication)符号テスト pass
5account_equity + margin_ratio + 非単調性 proptestproptest pass(prop_assume!
6margin_health 分類カスケード(strict less-than)分類テスト pass
7close_order_spec(market order の規律)compute 完成
8InsuranceFund + deposit/withdrawsingle-balance state machine
9absorb_deficit(underwater が fund を drain)保存則 test pass
10credit_fee(fee が collateral→fund)+ close-outcome decompositioncomposition test pass
11Scanner 型語彙(CloseOutcomeKind/LiquidationRecord/ScanReport/LiquidationScanner型がコンパイル
12scan(safety cascade の orchestration)scan test pass
13Capstone — 6 unit test + 4 invariant proptest全 tests pass

マイルストーンは レッスン13 — 全 tests が通り、4 状態分類 → insurance fund → multi-account scanner が 1 つの orchestration ループに結合する。レッスン13 で「まだ何が足りないか(oracle / bridge / ADL)」を名指す。

答え合わせの規律

本コースは Liquidation 参照実装の 3 パートにまたがる:

Moduleレッスンopenhl SHA
型 + 純粋な computeL1〜722eedf9(計算パート)
Insurance fundL8〜10260883b(保険基金パート)
Scanner + CapstoneL11〜130a8464e(スキャナパート)
# レッスン範囲に応じて checkout:
# 22eedf9 (計算), 260883b (保険基金), 0a8464e (スキャナ)
cd ~/code/openhl-reference && git checkout 22eedf9
diff -u ~/code/my-openhl/crates/liquidation/src/types.rs ./crates/liquidation/src/types.rs
diff -u ~/code/my-openhl/crates/liquidation/src/compute.rs ./crates/liquidation/src/compute.rs
diff -u ~/code/my-openhl/crates/liquidation/src/insurance.rs ./crates/liquidation/src/insurance.rs
diff -u ~/code/my-openhl/crates/liquidation/src/scanner.rs ./crates/liquidation/src/scanner.rs
diff -u ~/code/my-openhl/crates/liquidation/src/lib.rs ./crates/liquidation/src/lib.rs

合格基準

  • cargo test -p openhl-liquidation --release を全 tests 通せる(コース完走時)。
  • なぜ liquidation を consensus 内で実行するか(オフチェーンだと支払い能力を主張できない)を 1 文で言える。
  • 4 状態分類(Safe/AtRisk/Liquidatable/Underwater)と、それぞれが engine に何を許可するかを説明できる。

まとめ(3行)

  • liquidation は、損失が collateral を食って equity/notional が maintenance を下回った position を consensus 内で force-close するエンジン。fee を insurance fund へ、underwater なら不足分を fund が absorb。
  • float は分類のズレ(AtRisk vs Liquidatable)で block 分岐 → fork を招くので使わず、bps スケール(MARGIN_SCALE = 10_000)の符号付き整数 + saturating で分類する。
  • 3 building block(固定小数点 types → margin math → insurance fund + scanner)。最大の山は レッスン5 の levered-regime 非単調性。ADL は scope 外(別コース)。

次のレッスン(レッスン1)

MARGIN_SCALE = 1e4(bps)と、ネットワークのリスクパラメータを収める LiquidationParams 構造体 + hyperliquid_default()(initial 10% / maintenance 2% / fee 1.5%)を作る。