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 価格がオラクル価格から離れたとき)。
注意点
- 値はEVM ブロックが作られた時点の HyperCore の最新の状態と一致します。ブロックの途中で値が更新されることはありません
- 不正な入力(間違った資産の番号や vault のアドレスなど)で呼ぶと revert し、その呼び出しに渡したガスをすべて使い切ります
- HyperCore の状態がすべて読めるわけではありません。読めるのは
L1Read.solに載っている precompile だけです - precompile の顔ぶれは変わっていきます。必ず最新の資料を確かめてください
L1Read.solの precompile には、時刻やブロックを入力に取るものがありません。どれも今のブロック時点の状態を返します。過去のある時点の価格が要るコントラクトは、自分で記録するか、外から渡された価格を検証する必要があります
テストネットでの実測
hyperevm-amm を作ったときの記録です(HyperEVM テストネット、2026-10-17)。学習用のプロジェクトで、監査は受けていません。
- 現物の価格(0x808)は直近の約定価格です。 板が広いと片側に張り付きます。実際に売買できる価格が要るときは、最良の買値・売値(0x80e)を読みます。現物の市場の資産 ID は
10000 + 現物の番号です - 書くときと読むときで単位が違います。 CoreWriter の注文サイズは 1e8 倍ですが、ポジションの precompile(0x800)は、その市場の
szDecimalsの単位でサイズを返します
ガスについて
資料によると、precompile の呼び出しにかかるガスは次のとおりです。
2000 + 65 * (input_len + output_len) // lengths in bytes
比べると、SLOAD は初めて触るとき(cold)で 2,100 ガス、2回目以降(warm)なら 100 ガスです。