本文へ移動
レビューを依頼

HyperEVM 開発 · L1 の precompile と連携 · 4/8

HyperEVM から L1 の状態を読む

読み取り用の precompile

HyperEVM のいちばん強力な機能は、Solidity のコントラクトから HyperCore の状態を読めることです。これには読み取り用の precompile を使います。0x0000000000000000000000000000000000000800 から始まる特別なアドレスで、EVM のバイトコードではなくネイティブのコードを実行します。公式のインターフェースは、Interacting with HyperCore に添付されている L1Read.sol です。

使える precompile

読み取り用 precompile の一部です(2026年10月時点)。

アドレス 読むもの 入力
0x…0800 無期限先物の建玉(サイズ、建てたときの想定元本、レバレッジ) (address user, uint16 perp)
0x…0801 現物の残高 (address user, uint64 token)
0x…0802 vault にあるユーザーの持ち分 (address user, address vault)
0x…0806 mark 価格 uint32 perpIndex
0x…0807 オラクル価格 uint32 perpIndex
0x…0808 現物の価格 uint32 spotIndex
0x…080e 最良の買い気配と売り気配 uint32 asset
0x…080F 口座の証拠金のまとめ(口座の評価額、使っている証拠金) (uint32 perpDexIndex, address user)

資産は名前ではなく番号で指定します。番号は info エンドポイントの meta / spotMeta で調べます(メインネットでは BTC が perp 0 です)。資金調達率を読む precompile や、板の厚み全体を読む precompile はありません。読めるのは最良の買い気配と売り気配だけです。

mark 価格とオラクル価格を読む

precompile は staticcall で呼び、入力は ABI でエンコードします。

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

contract PriceReader {
    address constant MARK_PX = 0x0000000000000000000000000000000000000806;
    address constant ORACLE_PX = 0x0000000000000000000000000000000000000807;

    function markPx(uint32 perpIndex) public view returns (uint64) {
        (bool ok, bytes memory res) = MARK_PX.staticcall(abi.encode(perpIndex));
        require(ok, "markPx failed");
        return abi.decode(res, (uint64));
    }

    function oraclePx(uint32 perpIndex) public view returns (uint64) {
        (bool ok, bytes memory res) = ORACLE_PX.staticcall(abi.encode(perpIndex));
        require(ok, "oraclePx failed");
        return abi.decode(res, (uint64));
    }

    function priceDivergence(uint32 perpIndex) external view returns (int256) {
        return int256(uint256(markPx(perpIndex))) - int256(uint256(oraclePx(perpIndex)));
    }
}

価格は整数です。無期限先物の価格は 10^(6 - szDecimals) で割ると、人が読める数字になります(現物は 10^(8 - base szDecimals))。

口座の状態を読む

contract MarginReader {
    address constant ACCOUNT_MARGIN_SUMMARY = 0x000000000000000000000000000000000000080F;

    struct AccountMarginSummary {
        int64 accountValue;
        uint64 marginUsed;
        uint64 ntlPos;
        int64 rawUsd;
    }

    function summary(address user) public view returns (AccountMarginSummary memory) {
        // perpDexIndex 0 = the default (validator-operated) perp dex
        (bool ok, bytes memory res) =
            ACCOUNT_MARGIN_SUMMARY.staticcall(abi.encode(uint32(0), user));
        require(ok, "margin summary failed");
        return abi.decode(res, (AccountMarginSummary));
    }

    function isLeveraged(address user, uint256 maxRatioPct) external view returns (bool) {
        AccountMarginSummary memory s = summary(user);
        if (s.accountValue <= 0) return false;
        return (uint256(s.marginUsed) * 100) / uint256(uint64(s.accountValue)) > maxRatioPct;
    }
}

HyperCore を読む使い道

1. 担保の評価

貸し借りのプロトコルは、HyperCore のオラクル価格や現物の価格で担保を評価できます。

2. vault の自動の戦略

スマートコントラクトは、価格と自分の HyperCore の建玉を読み、CoreWriter というシステムコントラクトを通して動けます(あとで扱います)。

3. リスクの監視

DeFi のプロトコルは、ユーザーの HyperCore でのレバレッジを確かめて、設定を調整できます。

4. 条件付きの実行

HyperCore で条件がそろったときだけ、HyperEVM のロジックを動かします(例: mark 価格がオラクル価格から離れたとき)。

注意点

テストネットでの実測

hyperevm-amm を作ったときの記録です(HyperEVM テストネット、2026-10-17)。学習用のプロジェクトで、監査は受けていません。

ガスについて

資料によると、precompile の呼び出しにかかるガスは次のとおりです。

2000 + 65 * (input_len + output_len)   // lengths in bytes

比べると、SLOAD は初めて触るとき(cold)で 2,100 ガス、2回目以降(warm)なら 100 ガスです。