Precompile reference
The 21 read precompiles at 0x800 to 0x814 that let a HyperEVM contract read HyperCore state: address, input, output and scaling for each.
A read precompile is a fixed HyperEVM address that answers with HyperCore state instead of running contract code. Look one up here; patterns and pitfalls are on reading HyperCore.
Calling convention
Section titled “Calling convention”- Calldata is raw
abi.encode(args)with no function selector, which would be read as the first argument.0x809takes empty calldata. - Return data decodes straight into the output tuple.
- Values match the latest HyperCore state when the EVM block is built.
- Gas:
2000 + 65 * (input_len + output_len). An invalid input (unknown asset or vault) errors and consumes all forwarded gas: cap it per call.
(bool ok, bytes memory out) = address(0x807).staticcall{gas: 20_000}(abi.encode(uint32(3)));uint64 raw = abi.decode(out, (uint64)); // divide by 10^(6 - szDecimals) for a perpThe 21 precompiles by address
Section titled “The 21 precompiles by address”| Address | Name in L1Read.sol |
Input | Output | Scaling and notes |
|---|---|---|---|---|
0x800 |
position |
address user, uint16 perp |
(int64 szi, uint64 entryNtl, int64 isolatedRawUsd, uint32 leverage, bool isIsolated) |
superseded by 0x813 for indices above uint16 |
0x801 |
spotBalance |
address user, uint64 token |
(uint64 total, uint64 hold, uint64 entryNtl) |
token also accepts an outcome asset id 100000000 + 10 * outcome + side |
0x802 |
userVaultEquity |
address user, address vault |
(uint64 equity, uint64 lockedUntilTimestamp) |
|
0x803 |
withdrawable |
address user |
uint64 withdrawable |
|
0x804 |
delegations |
address user |
(address validator, uint64 amount, uint64 lockedUntilTimestamp)[] |
per-validator delegations only |
0x805 |
delegatorSummary |
address user |
(uint64 delegated, uint64 undelegated, uint64 totalPendingWithdrawal, uint64 nPendingWithdrawals) |
HYPE wei 1e8; the deployer stake check reads delegated + undelegated here |
0x806 |
markPx |
uint32 index (perp) |
uint64 |
divide by 10^(6 - szDecimals) |
0x807 |
oraclePx |
uint32 index (perp) |
uint64 |
divide by 10^(6 - szDecimals) |
0x808 |
spotPx |
uint32 index (spot pair) |
uint64 |
divide by 10^(8 - base szDecimals); also accepts an outcome asset id |
0x809 |
l1BlockNumber |
none (empty calldata) | uint64 |
the HyperCore block number |
0x80a |
perpAssetInfo |
uint32 perp |
(string coin, uint32 marginTableId, uint8 szDecimals, uint8 maxLeverage, bool onlyIsolated) |
|
0x80b |
spotInfo |
uint32 spot |
(string name, uint64[2] tokens) |
tokens is [base, quote] token indices |
0x80c |
tokenInfo |
uint32 token |
(string name, uint64[] spots, uint64 deployerTradingFeeShare, address deployer, address evmContract, uint8 szDecimals, uint8 weiDecimals, int8 evmExtraWeiDecimals) |
evmContract is the linked ERC20 |
0x80d |
tokenSupply |
uint32 token |
(uint64 maxSupply, uint64 totalSupply, uint64 circulatingSupply, uint64 futureEmissions, (address user, uint64 balance)[] nonCirculatingUserBalances) |
|
0x80e |
bbo |
uint32 asset |
(uint64 bid, uint64 ask) |
a perp index, or 10000 + spot pair index |
0x80f |
accountMarginSummary |
uint32 perp_dex_index, address user |
(int64 accountValue, uint64 marginUsed, uint64 ntlPos, int64 rawUsd) |
per perp dex |
0x810 |
coreUserExists |
address user |
bool exists |
whether the address is a HyperCore account |
0x811 |
borrowLendUserState |
address user, uint64 token |
((uint64 basis, uint64 value) borrow, (uint64 basis, uint64 value) supply) |
reverts when the account has no record for the token |
0x812 |
borrowLendReserveState |
uint64 token (not uint32) |
(uint64 borrowYearlyRateBps, uint64 supplyYearlyRateBps, uint64 balance, uint64 utilizationBps, uint64 oraclePx, uint64 ltvBps, uint64 totalSupplied, uint64 totalBorrowed) |
rates in bps; USDC amounts 1e8 |
0x813 |
position2 |
address user, uint32 perp |
same tuple as 0x800 |
the widened sibling of 0x800 |
0x814 |
outcomeStatus |
uint32 outcome |
(uint8 status, uint64 settledValue, uint32 question) |
see below |
0x815 to 0x8ff are unassigned on both networks (measured 2026-08-17): they return empty 0x with success, where a live one returns data or PrecompileError. New versions arrive as new sibling addresses, as 0x813 did.
0x814 outcome status
Section titled “0x814 outcome status”status |
Meaning | settledValue |
|---|---|---|
| 0 | never existed | none |
| 1 | active | none |
| 2 | settled | readable; 1e8 = 1.0 |
| 3 | settled and pruned | gone for good |
question is type(uint32).max (4294967295) for a standalone outcome or an unavailable question. Status 3 means pruned: the settled value is then only in the info request settledOutcome.
0x812 reserve state
Section titled “0x812 reserve state”- Supply APY is
borrow APY * utilisation * 0.9, reproducing the API to 9 decimal places. balanceis nottotalSupplied - totalBorrowed: the measured gap, a retained buffer, was about 46.57 USDC. Never price shares offbalance.- In the matching info request, HYPE (token 150) and UBTC (token 197) report a supply rate of 0: only quote assets pay.
- There is no rate history: sample
0x812yourself.
Measured behaviour
Section titled “Measured behaviour”| Behaviour | Detail | Basis |
|---|---|---|
| No historical state | Precompiles answer only at latest. Any explicit block number, even the current head, fails with PrecompileOutOfGas on archive nodes |
measured |
| Stale by execution | A read reflects state when the EVM block was built; a CoreWriter action sent in the same transaction executes later | docs and measured |
| Bad input burns everything | PrecompileOutOfGas(50000000) observed on an unsupported input |
measured |
0x811 reverts on no record |
an unguarded totalAssets() bricks a new vault until its first supply |
measured |
Stake check uses 0x805 |
undelegated stake counts toward a deployer requirement; 0x804 alone misses it |
measured |
| No abstraction mode | no precompile exposes an account’s abstraction mode | measured |
For why a read is stale by the time an action lands, see Execution order and timing. The write side is the CoreWriter action reference.