Skip to content本文へ移動

HyperEVM Development · L1 Precompiles & Interop · 4/8

Reading L1 State from HyperEVM

Read Precompiles

The most powerful feature of HyperEVM is the ability to read HyperCore state from Solidity contracts. This is done through read precompiles — special addresses starting at 0x0000000000000000000000000000000000000800 that execute native code instead of EVM bytecode. The official interface is the L1Read.sol file attached to Interacting with HyperCore.

Available Precompiles

A selection of the read precompiles (as of October 2026):

Address Reads Input
0x…0800 Perp position (size, entry notional, leverage) (address user, uint16 perp)
0x…0801 Spot balance (address user, uint64 token)
0x…0802 User's equity in a vault (address user, address vault)
0x…0806 Mark price uint32 perpIndex
0x…0807 Oracle price uint32 perpIndex
0x…0808 Spot price uint32 spotIndex
0x…080e Best bid/offer uint32 asset
0x…080F Account margin summary (account value, margin used) (uint32 perpDexIndex, address user)

Assets are identified by index, not by name — look the index up in the meta / spotMeta info endpoints (on mainnet, BTC is perp 0). There is no funding-rate or full order-book-depth precompile; only best bid/offer is exposed.

Reading Mark and Oracle Prices

Precompiles are called with staticcall and ABI-encoded inputs:

// 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)));
    }
}

Prices are integers: divide a perp price by 10^(6 - szDecimals) to get a human-readable number (spot: 10^(8 - base szDecimals)).

Reading Account State

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;
    }
}

Use Cases for HyperCore Reads

1. Collateral Valuation

A lending protocol can value collateral with HyperCore oracle or spot prices.

2. Automated Vault Strategies

Smart contracts can read prices and their own HyperCore positions, then act through the CoreWriter system contract (covered later).

3. Risk Monitoring

DeFi protocols can check users' leverage on HyperCore to adjust parameters.

4. Conditional Execution

Execute HyperEVM logic only when HyperCore conditions are met (e.g., mark price diverges from oracle price).

Important Caveats

Gas Considerations

Per the docs, a precompile call costs:

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

For comparison, a cold SLOAD costs 2,100 gas and a warm one 100 gas.

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 価格がオラクル価格から離れたとき)。

注意点

ガスについて

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

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

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