The Hypurrliquid Paper
A Complete Reverse Engineering Reference for the Hyperliquid L1
lastdotnet/hyperliquid-rust · Binary build 105cb1dc (2026-03-21) mainnet / 331bef9b (2026-04-03) testnet · Hardfork v81
This document is derived entirely from reverse engineering of the deployed hl-node binary (81MB stripped ELF), live traffic captures, on-chain observation, and ABCI state snapshot analysis. It is not official Hyperliquid documentation. Every structural claim traces to confirmed binary evidence and is cited with its source.
Use the White Paper for the architectural narrative and the Yellow Paper for protocol-truth and implementation-boundary details.
1. Architecture Overview #
Hyperliquid L1 (HyperCore) is a purpose-built blockchain for perpetual futures, spot trading, lending (BOLE), prediction markets (HIP-4), and an integrated EVM (HyperEVM). It uses HyperBFT consensus with sub-second block times and processes ~200,000 operations/second.[1]
1.1 System Stack
1.2 Crate Map
| Crate | Lines | Purpose |
|---|---|---|
hl-engine | ~4K | Exchange state machine, matching, clearinghouse, funding, fees, state hash (LtHash16) |
hl-evm | ~2.5K | revm 36, Cancun spec, L1 precompiles (0x0800+), CoreWriter, RocksDB, JSON-RPC |
hl-consensus | ~1.5K | HyperBFT two-chain commit, QC/TC validation, mempool, epoch manager |
hl-network | ~2K | Gossip wire protocol, TCP framing, LZ4, MsgConcise/OutMsgConcise parsing |
hl-devnet | ~2K | Devnet orchestrator: mock oracle/bridge/broadcaster, block producer, HTTP API |
hl-node | ~1K | CLI binary (hlx), node builder, mode dispatch |
hl-primitives | ~1.5K | Core types: blocks, actions, validators, chain config |
hl-rpc | ~500 | HTTP RPC server, /info API (30+ query types) |
hl-storage | ~500 | QMDB backend, S3 ingest |
hl-stages | ~300 | Reth-style pipeline stages |
hl-exex | ~200 | Execution extensions (ExEx) framework |
hl-re | ~200 | Binary RE tools (not runtime) |
1.3 Confirmed Dependency Versions
Extracted from path strings in the 81MB binary.[2]
| Crate | Version | Purpose |
|---|---|---|
blake3 | 1.7.0 | LtHash XOF (SSE2/AVX2/AVX512) |
sha2 | 0.10.8 | LtHash finalization (SHA-256) |
k256 | 0.13.3 | secp256k1 signatures |
secp256k1 | 0.29.0 | Consensus signing |
rmp-serde | 1.3.0 | State serialization (MessagePack) |
ethers-core | 2.0.14 | Ethereum types |
tiny-keccak | 2.0.2 | Keccak-256 (address derivation) |
revm | 19.2.0 | EVM executor |
revm-precompile | 16.0.0 | EVM precompiles |
alloy-rpc-types-eth | 0.9.2 | RPC types |
alloy-consensus | 0.9.2 | Consensus types |
tokio | 1.44.2 | Async runtime |
serde_json | 1.0.120 | JSON serialization |
chrono | 0.4.38 | Timestamps |
clap | 2.34.0 | CLI parsing |
rand_chacha | 0.3.1 | Deterministic RNG |
Internal Source Layout (from binary panic paths)
/home/ubuntu/hl/code_Mainnet/ (mainnet build 105cb1dc)
+-- base/ -- Shared utilities (40+ files)
+-- db/ -- RocksDB backend
+-- evm_rpc/ -- EVM JSON-RPC
+-- l1/ -- Core logic
| +-- abci/engine.rs, state.rs
| +-- book/book/impl_insert_order.rs
| +-- clearinghouse/
| +-- exchange/impl_trading.rs, end_block.rs, exchange.rs, impl_outcome.rs
| +-- evm/hyper_evm.rs, transactor.rs
| +-- staking.rs, vault/, fees/compute.rs, bole/user_state.rs
+-- net_utils/ -- TCP + LZ4
+-- node/consensus/ -- state.rs, server.rs, types.rs, timer.rs, mempool.rs,
client_block.rs, heartbeat_tracker.rs, rpc.rs, network.rs
/home/ubuntu/hl/code_Testnet/ (testnet build 331bef9b, 2026-04-03)
+-- base/ -- Utilities (50+ files, expanded)
+-- db/ -- RocksDB backend
+-- evm_rpc/ -- EVM JSON-RPC
+-- l1/ -- Core logic (+ core_writer.rs in evm/)
+-- node/ -- Orchestration + Consensus2. Consensus: HyperBFT #
HyperBFT is a two-chain HotStuff variant. CONFIRMED BIN: "CertifiedTwoChainCommit" in rodata[3]
2.1 Parameters
| Parameter | Value | Evidence |
|---|---|---|
| Block time | ~70ms | OBSERVED |
| Finality | Instant (no reorgs) | CONFIRMED |
| Active validators | 24 (mainnet), top 50 (testnet) | OBSERVED |
| Epoch | 100,000 rounds (~90 min) | CONFIRMED |
| Proposer selection | RoundRobinTtl | CONFIRMED |
| Signing | secp256k1 (RFC 6979, low-S/EIP-2) | CONFIRMED BIN: k256-0.13.3 |
| Domain separator | "Hyperliquid Consensus Payload" + 0x00 | CONFIRMED BIN: VA 0x6d10f4, GDB live capture |
| Signing formula | keccak256(domain + 0x00 + bincode(content)) | CONFIRMED |
| VoteAppHash | Every 2000 blocks | OBSERVED |
2.2 Round Lifecycle
2.3 Core Structures
Block { round, parent_round, tx_hashes, qc, tc, block_hash, time, proposer }
ClientBlock { proof: { signed_block, commit_proof }, txs }
Qc { block_hash, round, signatures }
Tc { signed_timeouts, round }
CommitProof { child: Signed<Block>, grandchild_qc: Qc }
EpochTracker { epoch_states, active_epoch, cur_epoch_state, cur_epoch, epoch_duration_seconds }
2.4 Consensus Errors
CONFIRMED at VA 0x6600fa.[4]
| Error | Meaning |
|---|---|
QcNoQuorum | Insufficient stake weight |
QcRoundBeforeHardfork | QC before hardfork boundary |
EmptyValidators | No validators |
CommitProofChildQc | Child QC must reference committed block |
CommitProofGrandchildQc | Grandchild QC must reference child |
CommitProofConsecutive | Blocks must be consecutive rounds |
TcNoQuorum | Insufficient TC stake weight |
TimeoutRoundMismatch | Timeout round mismatch |
AlreadyHaveTimeoutFromNode | Duplicate timeout |
BadBlockRound | Block/commit round mismatch |
BlockAlreadyRegistered | Duplicate block |
ValidatorIPMismatch | IP mismatch |
2.5 Validator Signing Gates (6 Checks)
| # | Check | Failure |
|---|---|---|
| 1 | is_main_signer | Not designated signer |
| 2 | Active set | "Home validator has left the active set." |
| 3 | Not jailed | jailed_signers |
| 4 | last_vote_round | Double-vote prevention |
| 5 | Not disabled | disabled_validators |
| 6 | Round match | Vote round != consensus round |
3. Mempool #
Mempool {
committed_tx_hashes: HashSet, // dedup
uncommitted_txs: HashMap, // pending
tx_hash_to_seq_num: HashMap, // ordering
block_hash_to_block: HashMap, // block buffer
broadcaster_nonces: HashMap, // per-broadcaster
}
No hard mempool size limit CONFIRMED. Eviction is time-based.[5]
3.1 Admission Pipeline (7 Stages)
| Stage | Check | Error |
|---|---|---|
| 1 | Parse action | "could not parse action" |
| 2 | Signature verify | AddTxNotSigned |
| 3 | Broadcaster whitelist | TxUnexpectedBroadcaster |
| 4 | Broadcaster nonce | TxInvalidBroadcasterNonce |
| 5 | Dedup | AddTxDuplicate |
| 6 | Already committed | AddTxCommitted |
| 7 | Enqueue | -- |
4. Block Execution Pipeline #
CONFIRMED from binary VA 0x01e748e0 and string at 0x539f8a. Pipeline: RecoverUsers → BeginBlock → DeliverSignedActions → ProcessFills → EVM Block → EndBlock → Commit → VoteAppHash.[6]
4.1 RecoverUsers
Before any effects: parse block header, validate proposer is active validator, verify broadcaster authorization per bundle, recover EIP-712 signers, reject duplicate nonces.
4.2 BeginBlock — 9 Named Effects CONFIRMED
Binary-confirmed order from VA 0x01e748e0 (2026-04-02). Note: this ordering differs from older RE notes which placed BOLE after funding.
| # | Effect | Guard | What |
|---|---|---|---|
| 1 | update_oracle | — | Pre-process oracle state for block |
| 2 | distribute_funding | funding_distribute_guard (8s) | Settle funding: payment = szi × px × Δcum_funding |
| 3 | apply_bole_liquidations | — | Health < 0.8 → partial/market/backstop liquidation + ADL cascade |
| 4 | update_funding_rates | funding_update_guard (8s) | Sample premium, update DeterministicEma |
| 5 | refresh_hip3_stale_mark_pxs | hip3_stale_mark_px_guard | Fall back stale mark prices to oracle (10s window) |
| 6 | prune_book_empty_user_states | book_empty_user_states_pruning_guard (60s) | Remove users with zero-size positions |
| 7 | update_staking_rewards | — | Stage epoch staking rewards |
| 8 | update_action_delayer | — | Drain matured CoreWriter delayed actions and execute as L1 |
| 9 | update_aligned_quote_token | — | Sample stake-weighted median SOFR rate from validator votes |
Supplementary per-book maintenance (after the 9 named effects):
| Effect | Guard |
|---|---|
check_trigger_orders (TP/SL) | — |
cancel_aggressive_orders_at_oi_cap | cancel_oi_cap_guard (1s) |
validator_l1_vote_tracker_prune_expired | Internal (60s) |
reset_recent_ois | reset_recent_oi_guard (1s) |
update_stale_mark_guards | Per-book |
4.3 DeliverSignedActions
Each bundle is processed sequentially. Per action: resolve actor (EIP-712 recovery), nonce check, try typed dispatch (HlAction enum, 90 variants), fall back to JSON string dispatch. Fills accumulate in BlockResult.
4.4 ProcessFills
After all actions: per-fill fee computation (compute_fee() with tiers + referral), debit fees, clearinghouse.process_fill() for position updates, volume tracking for tier progression, fill history (capped 1000/user), ExEx event emission.
4.5 EVM Block Phase
Dual-block architecture: small blocks (1s, 2M gas) for responsive UX + big blocks (60s, 30M gas) for heavy computation. Each block's receipts are scanned for CoreWriter RawAction(address,bytes) logs from 0x3333...3333. Decoded actions are enqueued in ActionDelayer with delay_scale × 3000ms delay and later fire through the named delayed-action lane in the next block's begin_block (slot 8 in the current widened testnet note).
In replay mode (no executor): raw tx calldata parsed via minimal RLP scanner to extract CoreWriter calls without EVM execution.
4.6 EndBlock
Update mark prices from order book mid-prices: for each book with orders, mark_prices[asset] = book.mid_price().
4.7 Commit + VoteAppHash
State hash: rmp_serde → blake3 XOF (2048B) → paddw u16 (LtHash16) → SHA-256 (32B). 11 L1 + 3 EVM accumulator categories. Final app_hash is first_16(SHA-256(L1_combined)) || first_16(SHA-256(EVM_combined)). Every 2000 blocks, validators submit VoteAppHash; quorum at 2/3+ stake agreement.
4.8 Timing Parameters
| Parameter | Value |
|---|---|
| Block time (HyperBFT) | ~70ms |
| Funding interval | 8000ms |
| OI cap check | 1000ms |
| Book pruning | 60000ms |
| HIP-3 stale mark | From snapshot |
| CoreWriter delay | 3000ms × delay_scale |
| BOLE partial liq cooldown | 30s |
| VoteAppHash checkpoint | 2000 blocks |
| Aligned quote token vote | Daily 22:00 UTC |
4.9 Action Dispatch — All 97 Variants
Main dispatcher at VA 0x0272a320 (>500KB). CONFIRMED: the current widened testnet note exposes 90 mainnet + 7 testnet-only variants. Use the dedicated Action Inventory for the authoritative family/sub-variant tables; local parity work on the full surface is still active.[8]
Trading (9 types)
| Wire Name | Action | State Touched | Share |
|---|---|---|---|
order | Place limit/IOC/ALO order | matching.books, oid_to_order, fills | 68.2% |
cancel | Cancel by OID | matching.books, oid_to_order | 10.5% |
cancelByCloid | Cancel by client order ID | matching.books, cloid_to_oid | 16.7% |
modify | Modify resting order price/size | matching.books | <0.1% |
batchModify | Batch modify multiple orders | matching.books | 0.9% |
scheduleCancel | Schedule future cancel for asset | user_to_scheduled_cancel | 0.3% |
twapOrder | Submit TWAP order | twap.running_heap | <0.1% |
twapCancel | Cancel TWAP order | twap.user_to_id_to_state | <0.1% |
liquidate | Liquidate underwater position | clearinghouse.positions, balances | <0.1% |
Margin & Leverage (3 types)
| Wire Name | Action | State Touched |
|---|---|---|
updateLeverage | Set leverage for asset | clearinghouse.positions |
updateIsolatedMargin | Add/remove isolated margin | clearinghouse.balances, isolated_margins |
topUpIsolatedOnlyMargin | Top up isolated-only margin | clearinghouse.balances |
Transfers (6 types)
| Wire Name | Action | State Touched |
|---|---|---|
usdSend | Send USDC to another user | clearinghouse.balances (both users) |
usdClassTransfer | USD class transfer | clearinghouse.balances |
spotSend | Send spot token | spot_clearinghouse.user_balances |
sendAsset | General asset transfer (multi-dex) | routing + balances |
withdraw3 | Withdraw USDC (v3) | clearinghouse.balances |
sendToEvmWithData | L1 → EVM transfer with calldata | clearinghouse.balances, hyper_evm queues |
Sub-Accounts (3 types)
| Wire Name | Action | State Touched |
|---|---|---|
createSubAccount | Create sub-account | sub_accounts |
subAccountTransfer | Transfer USD between master/sub | clearinghouse.balances |
subAccountSpotTransfer | Transfer spot token between master/sub | spot_clearinghouse.user_balances |
Vaults (6 types)
| Wire Name | Action | State Touched |
|---|---|---|
createVault | Create a new vault | vaults.vaults |
vaultTransfer | Deposit/withdraw from vault | vaults.followers, clearinghouse.balances |
vaultDistribute | Distribute vault profits | vaults.followers, total_equity |
vaultModify | Modify vault config | vaults.vaults |
netChildVaultPositions | Net child vault positions | vaults.children |
setVaultDisplayName | Set vault display name | vaults.vaults |
Staking (5 types)
| Wire Name | Action | State Touched |
|---|---|---|
tokenDelegate | Delegate HYPE to validator | staking.delegations, stakes |
claimRewards | Claim staking rewards | staking.rewards, clearinghouse.balances |
linkStakingUser | Link staking identity | staking.linked_staking_users |
registerValidator | Register new validator | staking.validator_profiles |
extendLongTermStaking | Extend long-term lock | staking.long_term_locks |
Account (7 types)
| Wire Name | Action | State Touched |
|---|---|---|
approveAgent | Authorize agent address | agents.user_to_main_agent |
setDisplayName | Set user display name | user_to_display_name |
setReferrer | Set referrer code | fee_tracker.referrer_states |
convertToMultiSigUser | Convert to multi-sig account | multi_sig_users |
approveBuilderFee | Approve builder fee rate | agents.builder_fees |
startFeeTrial | Start fee trial period | fee_tracker.fee_trials |
userPortfolioMargin | Enable portfolio margin | portfolio_margin_users |
DeFi & Abstraction (5 types)
| Wire Name | Action | State Touched |
|---|---|---|
borrowLend | BOLE deposit/borrow/repay | bole.reserves, user_positions |
userDexAbstraction | Enable DEX abstraction | user_abstraction_settings |
userSetAbstraction | Set abstraction config | user_abstraction_settings |
agentSetAbstraction | Agent abstraction config | user_abstraction_settings |
agentEnableDexAbstraction | Agent enable DEX abstraction | user_abstraction_settings |
Governance (3 types)
| Wire Name | Action | State Touched |
|---|---|---|
govPropose | Submit governance proposal | governance_proposals |
govVote | Vote on proposal | governance_proposals[].votes |
voteGlobal | Validator governance vote (22 sub-types) | Various (see below) |
VoteGlobal Sub-Types (22 wired)
| Sub-Type | State Touched |
|---|---|
ModifyBroadcaster | staking.broadcasters |
HaltPerpTrading | clearinghouse.halted_assets |
SetPerpDexOpenInterestCap | open_interest_caps |
DisableNodeIp | disabled_node_ips |
QuarantineUser | quarantined_users + cancel all orders |
CancelUserOrders | matching.cancel_all_for_user |
SetOutcomeFeeScale | outcome_fee_scale |
SetCoreWriterActionEnabled | hyper_evm.disabled_core_writer_actions |
SetScheduledFreezeHeight | scheduled_freeze_height |
SetPostOnlyUntilTime | post_only_until_time |
SetPostOnlyUntilHeight | post_only_until_height |
SetMaxOrderDistanceFromAnchor | max_order_distance_from_anchor |
SetBridge2WithdrawFee | bridge2_withdraw_fee |
SetPerformAutoDeleveraging | perform_auto_deleveraging |
SetSpotDisabled | spot_disabled |
SetEvmEnabled | evm_enabled |
SetL1TransfersEnabled | hyper_evm.l1_transfers_enabled |
SetDexAbstractionEnabled | dex_abstraction_enabled |
SetPerpsDisabledLaunch | perps_disabled_launch |
SetHip3NoCross | hip3_no_cross |
SetFundingMultiplier | funding[asset].multiplier |
SetMarginMode | margin_modes |
Validator (9 types)
| Wire Name | Action | State Touched |
|---|---|---|
CValidator | Validator profile management | staking.validator_profiles |
CSigner | Unjail/jail validator | staking.jailed |
validatorL1Vote | L1 oracle consensus vote | validator_l1_vote_tracker |
validatorL1Stream | L1 stream (SOFR rate vote) | hpt.validator_rate_votes |
signValidatorSetUpdate | Sign bridge validator set update | bridge_vote_tracker |
ValidatorSignWithdrawal | Sign bridge withdrawal | bridge_vote_tracker |
VoteEthDeposit | Vote on ETH deposit | bridge_vote_tracker |
VoteEthFinalizedWithdrawal | Vote finalized withdrawal | bridge_vote_tracker |
VoteEthFinalizedValidatorSetUpdate | Vote finalized validator set | bridge_vote_tracker |
HIP-3/HIP-4 (3 types + sub-types)
| Wire Name | Action | Sub-Types |
|---|---|---|
SetGlobalAction | Oracle/margin/fee config | oraclePxs, externalPerpPxs, usdtUsdcPx, nativePx, markPxs, marginTable |
perpDeploy | HIP-3 perp deployment | registerAsset, setOracle, setSubDeployers, setPerpAnnotation, setFeeScale, setFeeRecipient, haltTrading, insertMarginTable, outcomeDeploy |
spotDeploy | Spot market deployment | — |
System (11 types)
| Wire Name | Action | State Touched |
|---|---|---|
SystemBole | System BOLE operations | bole (stub) |
SystemSpotSend | System spot transfer | routing + balances |
SystemUsdClassTransfer | System USD class transfer | routing + balances |
SystemSendAsset | System asset transfer | routing + balances |
SystemApproveBuilderFee | System builder fee approval | agents.builder_fees |
SystemAlignedQuoteSupplyDelta | Aligned quote supply adjustment | clearinghouse.balances |
DeployerSendToEvmForFrozenUser | Recovery for frozen users | clearinghouse.balances |
CWithdraw | Consensus withdrawal | clearinghouse.balances |
CUserModify | Consensus user balance modify | clearinghouse.balances |
EvmUserModify | EVM user balance modify | clearinghouse.balances |
ReassessFees | Reassess user fee tier | fee_tracker |
Special (7 types)
| Wire Name | Action | State Touched |
|---|---|---|
evmRawTx | Execute raw EVM transaction | hyper_evm, action_delayer (via CoreWriter) |
multiSig | Multi-sig wrapper | Re-dispatches inner action |
noop | No-op (heartbeat) | None |
VoteAppHash | Validator state hash vote | app_hash_vote_tracker |
ForceIncreaseEpoch | Force epoch increment | staking.current_epoch |
userOutcome | Outcome market operations | outcomes (split/merge/negate/mergeQuestion) |
settleFraction | Partial outcome settlement | outcomes.markets |
Additional (8 types)
| Wire Name | Action | State Touched |
|---|---|---|
priorityBid | Gas priority bidding | priority_bids |
registerSpot / registerSpot2 | Register spot asset | spot_registrations |
disableDex | Halt asset trading | clearinghouse.halted_assets |
setPerpAnnotation | Set perp metadata | perp_annotations |
evmContractTransfer | EVM contract transfer | finalized_evm_contracts |
cancelAllOrders | Cancel all user orders | matching.cancel_all_for_user |
quarantineUser | Freeze + cancel all | matching + quarantined_users |
setMarginModes | Set per-asset margin modes | margin_modes |
Total: the current widened testnet note exposes 97 action variants, expanding to 126 sub-types (+ 6 SetGlobal + 8 PerpDeploy + 22 VoteGlobal). Treat that as the current action-surface map, not as a blanket claim that parity is complete on every branch.[9]
5. Exchange State (57 Keys) #
The Exchange struct: ALL L1 state. ~1.1GB as .rmp, saved every ~20 min.[10]
CONFIRMED Serde struct chain discovered at .rodata offset 0x543428 in testnet binary (2026-04-03). This gives the complete ABCI state serialization layout -- every field name, order, and nesting depth for the full Exchange struct hierarchy. BIN: testnet 331bef9b .rodata 0x543428
All 57 Exchange Fields
| # | Field | Type |
|---|---|---|
| 1 | locus | Locus(15) |
| 2 | perp_dexs | PerpDex(4)[] |
| 3 | spot_books | Book[] |
| 4 | agent_tracker | AgentTracker(5) |
| 5-6 | funding_distribute_guard, funding_update_guard | BucketGuard |
| 7 | sub_account_tracker | SubAccountTracker(2) |
| 8 | allowed_liquidators | Vec |
| 9 | bridge2 | Bridge2(10) |
| 10 | staking | Staking(6) |
| 11 | c_staking | CStaking(23) |
| 12 | funding_err_dur_guard | ErrDurGuard |
| 13 | max_order_distance_from_anchor | Config |
| 14-15 | scheduled_freeze_height, simulate_crash_height | Option<u64> |
| 16 | validator_power_updates | Vec |
| 17 | cancel_aggressive_orders_at_oi_cap_guard | BucketGuard |
| 18-20 | last_hlp_cancel_time, post_only_until_time, post_only_until_height | u64/Option |
| 21-24 | spot_twap_tracker, user_to_display_name, book_empty_user_states_pruning_guard, user_to_scheduled_cancel | Various |
| 25-29 | hyperliquidity, spot_disabled, prune_agent_idx, max_hlp_withdraw_fraction_per_day, hlp_start_of_day_account_value | Various |
| 30-32 | register_token_gas_auction, perp_deploy_gas_auction, spot_pair_deploy_gas_auction | GasAuction |
| 33 | hyper_evm | HyperEvm(13) |
| 34-36 | vtg, app_hash_vote_tracker, begin_block_logic_guard | Various |
| 37-39 | user_to_evm_state, multi_sig_tracker, reserve_accumulators | Various |
| 40-43 | partial_liquidation_cooldown, evm_enabled, validator_l1_vote_tracker, staking_link_tracker | Various |
| 44-47 | action_delayer(9), default_hip3_limits(6), hip3_stale_mark_px_guard, disabled_precompiles | Various |
| 48-54 | lvt, hip3_no_cross, initial_usdc_evm_system_balance, validator_l1_stream_tracker, last_aligned_quote_token_sample_time, user_to_evm_to_l1_wei_remaining, dex_abstraction_enabled | Various |
| 55-57 | hil, oh, abstraction | Unknown/AbstractionState |
5.1 Locus (15 Keys, 3-Char Serde Renames)
Locus is the compact core container inside the 57-field Exchange. The parent Exchange uses full field names in serde; Locus is the notable exception that still uses short 3-character keys.
| Key | Full name | Role |
|---|---|---|
cls | clearinghouses | Main perp clearinghouse plus HIP-3 clearinghouses. |
scl | spot_clearinghouse | Separate spot clearinghouse state. |
ctx | context | Block height, round, time, next IDs, system nonce. |
ftr | fee_tracker | Fee schedule, referral state, builder fees. |
ust | user_states | Main user state map. |
chn | chain | Chain label such as Mainnet or Testnet. |
pdl | perps_disabled_launch | Launch / gating flag for perp activity. |
uaR | user_action_registry | Sparse or empty registry surface; exact operational use still weakly grounded. |
blp | bole_pool | BOLE lending pool and reserve-level state. |
qus | queue_signers | Queue signer addresses. |
ctr | counters | Transaction / validation / action counters. |
uac | user_account_configs | Per-user account configuration and mode state. |
vlt | vaults | All vault state. |
hcm | hot_cold_mode | Operational hot/cold mode switch. |
aux | auxiliary | Later-added auxiliary slot; present in snapshots even though older binary descriptors still say 14 elements. |
5.2 Clearinghouse (18 Fields)
This is the perp risk and balance core that locus.cls[] stores for the main market and each HIP-3 perp universe.
| Field | Role |
|---|---|
meta | Perp metadata, margin tables, collateral token, and market-level configuration. |
user_states | Per-user position, balance, and open-order state for this clearinghouse. |
oracle | Oracle and external-perp pricing state for this clearinghouse. |
total_net_deposit | Aggregate net deposits into the clearinghouse. |
total_non_bridge_deposit | Non-bridge deposit aggregate used in accounting and safety checks. |
perform_auto_deleveraging | Flag that ADL is active for this clearinghouse. |
adl_shortfall_remaining | Residual shortfall still needing deleveraging. |
bridge2_withdraw_fee | Bridge-related withdrawal fee carried in clearinghouse state. |
daily_exchange_scaled_and_raw_vlms | Volume accounting and daily scaled volume trackers. |
halted_assets | Per-asset halt state. |
override_max_signed_distances_from_oracle | Per-asset order-distance overrides relative to oracle / anchor prices. |
max_withdraw_leverage | Withdrawal leverage guardrail. |
last_set_global_time | Timestamp of the last oracle / governance-style global update. |
usdc_ntl_scale | USDC notional scaling tuple. |
isolated_external | Isolated-margin external accounting surface. |
isolated_oracle | Oracle-side isolated-margin state. |
moh | MainOrHip3 discriminator for main clearinghouse vs HIP-3 clearinghouse. |
znfn | Fill nonce counter. |
5.3 CStaking (23 Fields)
CStaking is the on-chain validator, delegation, governance, and broadcaster-control surface. The raw binary inventory is easier to use when grouped by purpose.
| Field | Purpose |
|---|---|
stakes | Validator stake ledger. |
allow_all_validators | Open vs permissioned validator-set switch. |
allowed_validators | Explicit allow-list when the set is permissioned. |
broadcasters | Whitelisted broadcaster addresses for signed user action intake. |
validator_to_profile | Validator metadata and profile state. |
validator_to_last_signer_change_time | Signer rotation timing guard. |
delegations | Delegator-to-validator stake mapping. |
proposals | Governance proposal storage. |
stakes_decay_bucket_guard | Rate limiter for stake decay / maintenance logic. |
jailed_signers | Currently jailed signer set. |
jail_vote_tracker | Vote aggregation for jailing decisions. |
jail_until | Jail expiry timestamps. |
signer_to_last_manual_unjail_time | Manual unjail cooldown tracking. |
native_token_reserve | Native-token reward / reserve pool. |
stage_reward_bucket_guard | Rate limiter for reward staging. |
validator_to_staged_rewards | Pending rewards not yet distributed. |
distribute_reward_bucket_guard | Rate limiter for reward distribution. |
pending_withdrawals | Unstaking and pending withdrawal queue. |
self_delegation_requirement | Minimum self-bond requirement for validators. |
disabled_validators | Validators removed from service without deleting historical state. |
disabled_node_ips | Node IP denylist / disable surface. |
validator_to_state | Per-validator lifecycle state. |
gversion | Governance version marker. |
5.4 Live State Size
| Metric | Value |
|---|---|
| Users | 2,138,136 |
| Positions | 3,760,980 |
| Total USDC | $3.01B |
| Order book levels | 170,972 |
6. Matching Engine #
6.1 Cancel Reasons (11)
CONFIRMED at offset 0x64f964.[11]
| # | Status | Cause |
|---|---|---|
| 0 | marginCanceled | Insufficient margin |
| 1 | perpMaxPositionCanceled | Exceeds max position |
| 2 | vaultWithdrawalCanceled | Vault withdrawal |
| 3 | openInterestCapCanceled | OI cap |
| 4 | selfTradeCanceled | Self-trade prevention |
| 5 | reduceOnlyCanceled | Would increase position |
| 6 | siblingFilledCanceled | OCO sibling filled |
| 7 | liquidatedCanceled | User liquidated |
| 8 | outcomeSettledCanceled | Market settled |
| 9 | scheduledCancel | User-scheduled |
| 10 | internalCancel | System-internal |
6.2 Reject Reasons (17)
| # | Status | Message |
|---|---|---|
| 0 | tickRejected | "Price must be divisible by tick size." |
| 1 | minTradeNtlRejected | Below minimum notional |
| 2 | perpMarginRejected | "Insufficient margin to place order." |
| 3 | perpMaxPositionRejected | "Order would exceed maximum position size" |
| 4 | reduceOnlyRejected | "Reduce only order would increase position." |
| 5 | iocCancelRejected | "Order could not immediately match" |
| 6 | badTriggerPxRejected | "Invalid TP/SL price." |
| 7 | badAloPxRejected | "Post only order would have immediately matched." |
| 8 | marketOrderNoLiquidityRejected | "No liquidity available for market order." |
| 9 | positionIncreaseAtOpenInterestCapRejected | "Cannot increase position when OI is at cap." |
| 10 | positionFlipAtOpenInterestCapRejected | "Cannot flip position when OI is at cap." |
| 11 | tooAggressiveAtOpenInterestCapRejected | "Asset open interest is at cap." |
| 12 | openInterestIncreaseRejected | "Open interest is increasing too quickly." |
| 13 | insufficientSpotBalanceRejected | "Insufficient spot balance" |
| 14 | oracleRejected | "Price too far from oracle" |
| 15 | outcomeSettledRejected | "Outcome has been settled" |
| 16 | hip3CrossMarginReduceOnly | "Cross margin currently only supports reduce-only" |
6.3 Fee Tiers
VIP Tiers (7 Levels) API: app.hyperliquid.xyz/fees[12]
| Tier | 14d NTL | Perp Taker | Perp Maker | Spot Taker | Spot Maker |
|---|---|---|---|---|---|
| Base | $0 | 4.5 bps | 1.5 bps | 7.0 bps | 4.0 bps |
| VIP1 | $5M | 4.0 | 1.2 | 6.0 | 3.0 |
| VIP2 | $25M | 3.5 | 0.8 | 5.0 | 2.0 |
| VIP3 | $100M | 3.0 | 0.4 | 4.0 | 1.0 |
| VIP4 | $500M | 2.8 | 0.0 | 3.5 | 0.0 |
| VIP5 | $2B | 2.6 | 0.0 | 3.0 | 0.0 |
| VIP6 | $7B | 2.4 | 0.0 | 2.5 | 0.0 |
MM Tiers (3): MM1 0.5%/-0.1bps, MM2 1.5%/-0.2bps, MM3 3.0%/-0.3bps
Staking Discount Tiers (7)
| bps Staked | 0 | 0.01 | 0.1 | 1 | 10 | 100 | 500 |
|---|---|---|---|---|---|---|---|
| Discount | 0% | 5% | 10% | 15% | 20% | 30% | 40% |
6.3.1 FeeSchedule and FeeTracker Layouts
CONFIRMED from binary struct chain in testnet build 331bef9b (2026-04-03). BIN: serde field chain at .rodata 0x543428
FeeSchedule (9 fields)
tiers // VIP tier definitions
referral_discount // Referral discount percentage
referrer_keep // Referrer keep percentage
extra_destination_fractions // Extra fee destination routing
stake_discount_tiers // Staking discount tier table
weigh_spot_volume_double // Double-weight spot volume flag
aligned_quote_token_config // Aligned quote token configuration
+2 unknown fields // Under investigation
FeeTracker (10 fields)
fee_schedule // Active FeeSchedule(9)
unrewarded_users // Users pending reward distribution
user_states // Per-user fee accounting state
referrer_states // Per-referrer fee accounting state
code_to_referrer // Referral code -> referrer mapping
referral_bucket_millis // Referral bucket timing
total_fees_collected // Cumulative fees collected
total_spot_fees_collected // Cumulative spot fees collected
collected_builder_fees // Builder fee accumulator
trials_disabled // Fee trial disable flag
6.4 Wire Format
OrderWireSerde { a: u32, b: bool, p: String, s: String, r: bool, t: OrderTypeWire, c: Option<Cloid> }
OrderAction { orders: Vec, builder: Option<OrderBuilderInfo>, grouping: Grouping }
Cancel { a: u32, o: u64 }
CancelByCloid { asset: u32, cloid: Cloid }
ModifyWire { oid: u64, order: OrderWireSerde }
TwapWireSerde { a: u32, b: bool, s: String, r: bool, m: u64, t: bool }
// Tif: Alo | Ioc | Gtc Tpsl: Na | NormalTpsl | PositionTpsl
// Grouping: Na | Default | DexAbstraction | UnifiedAccount | PortfolioMargin
6.5 Matching Algorithm CONFIRMED
Price-time priority CLOB with self-trade prevention and post-only enforcement. Each asset has an independent order book backed by BTreeMap<PriceKey, VecDeque<Order>>.
Data Structure Layout
OrderBook {
bid_levels: BTreeMap<-price, PriceLevel> // negative key = descending sort (best bid first)
ask_levels: BTreeMap<+price, PriceLevel> // positive key = ascending sort (best ask first)
oid_index: HashMap<u64, (Side, PriceKey)> // O(1) cancel by OID
}
PriceLevel {
orders: VecDeque<Order> // FIFO: front = oldest (first priority)
total_size: f64 // aggregate size at this price
}
// BTreeMap guarantees: O(log n) insert/lookup, ordered iteration
// VecDeque guarantees: O(1) push_back (new orders), O(1) pop_front (best time priority)
// HashMap guarantees: O(1) cancel by OID
Key Properties
| Property | Behavior | Evidence |
|---|---|---|
| Price priority | Best price matched first (highest bid, lowest ask) | BTreeMap iteration order |
| Time priority | At same price, earliest order fills first | VecDeque FIFO (front = oldest) |
| Self-trade prevention | Cancel resting maker order, continue matching | CONFIRMED: "selfTradeCanceled" |
| Post-only (ALO) | Reject BEFORE matching if would cross book | CONFIRMED: "badAloPxRejected" |
| IOC behavior | Fill what's available, discard remainder (no rest) | CONFIRMED: "iocCancelRejected" |
| Reduce-only | Never rests on book, cancels if would increase position | CONFIRMED: "reduceOnlyCanceled" |
| Fill price | Maker's resting price (not taker's limit price) | Standard CLOB: passive side sets execution price |
| Trigger orders | Stored separately, activated when oracle crosses trigger_px | CONFIRMED: must be reduce-only |
Post-Match Pipeline
For each fill in block:
1. Compute fees via full fee pipeline (VIP tier, MM, staking, referral, builder)
2. Debit fees from maker and taker balances
3. Update positions via clearinghouse.process_fill()
4. Increment fill nonce counter (znfn)
5. Record fill in state hash (OrderStatusHash::Filled → Na accumulator)
6. Track volume for VIP tier advancement
7. Emit fill event for WebSocket subscribers
7. Funding Rate System #
7.1 Parameters
| Parameter | Value | Evidence |
|---|---|---|
| Settlement | 1 hour | API: fundingHistory 3600s apart[13] |
| Rate expression | per 8h | INFERRED |
| Default interest | 0.01%/8h = 0.0000125/1h | OBSERVED: BTC pins 314/500 samples |
7.2 Algorithm
1. premium = (mark_px - oracle_px) / oracle_px
2. EMA: decay = exp(-dt * ln(2) / half_life)
num = num * decay + premium * (1 - decay)
denom = denom * decay + (1 - decay)
smoothed = num / denom
3. Clamp to [-max_slippage, +max_slippage]
4. rate = smoothed * perp_to_funding_multiplier[asset]
5. rate += perp_to_funding_interest_rate[asset]
6. Binance mode: premium_index + clamp(interest - premium_index, -0.0005, 0.0005)
7.3 FundingTracker (8 Fields)
1. asset_to_premiums 2. override_impact_usd 3. clamp
4. default_impact_usd 5. hl_only_perps 6. use_binance_formula
7. perp_to_funding_multiplier 8. perp_to_funding_interest_rate
DeterministicEma(5): num, denom, decay_duration, n_samples, [last_update_time]
DeterministicVty(7): desc, samples, emas, val, n_updates, n_bucket_updates, alert_bucket_guard
8. Oracle and Mark Price #
The oracle pipeline transforms external price feeds into consensus oracle prices, mark prices, and ultimately funding rates and liquidation triggers. Every step has been confirmed from binary RE.[13]
8.1 Full Oracle Pipeline
8.2 SetGlobalAction (4 Fields) CONFIRMED
The broadcaster submits consensus oracle prices via SetGlobalAction (variant 1 of SetGlobal sub-types). The 4th field is nativePx -- the native token (HYPE) price. BIN: confirmed 2026-04-02
SetGlobalAction {
pxs: Vec<Option<String>>, // oracle prices, indexed by asset
externalPerpPxs: Vec<Option<String>>, // external perp prices (Binance, etc.)
usdtUsdcPx: Option<String>, // USDT/USDC exchange rate
nativePx: Option<String>, // CONFIRMED: HYPE price
}
Governance sub-actions (variant index 0..14): registerAsset, setOracle, insertMarginTable, setFeeRecipient, haltTrading, setMarginTableIds, setOpenInterestCaps, setFundingMultipliers, setMarginModes, setFeeScale, setGrowthModes, setFundingInterestRates, disableDex, setPerpAnnotation.
8.3 Oracle Struct (4 Fields) CONFIRMED
Oracle {
pxs: HashMap<u32, f64>, // consensus oracle prices per asset
external_perp_pxs: HashMap<u32, f64>, // external perp prices
err_dur_guard: BucketGuard, // error duration tracking
lpxk: OracleKindMap, // last price kind map
}
OracleKindMap // Maps assets to oracle kind: Reserved, NO_ERROR, universe, oraclePx, disabled
8.4 Oracle History Ring Buffer CONFIRMED
Exchange field [55] oh is a ring buffer of 100 oracle snapshots, each containing a full copy of the oracle state at that point in time. SNAP: confirmed from ABCI state at h=942770000
Exchange.oh: Vec<(DateTime, OracleSnapshot)> // 100 entries
OracleSnapshot {
pxs: HashMap<u32, f64>,
external_perp_pxs: HashMap<u32, f64>,
err_dur_guard: BucketGuard,
l: ???, // abbreviated field, purpose TBD
}
This ring buffer provides recent oracle price history for mark price smoothing, stale detection, and error duration tracking.
8.5 Validator Voting Pipeline
Validators submit price votes via ValidatorL1VoteAction. Votes are tracked per action type with expiry-based rounds. CONFIRMED: stake-weighted median.
ValidatorL1VoteTracker(3) {
prune_bucket_guard: BucketGuard,
action_to_tracker: HashMap<ActionType, ActionTracker>,
active: bool,
}
ActionTracker(3) { active: bool, expire_time: u64, vote_tracker: VoteTracker }
VoteTracker(7) { version, round, initial_round, round_to_val, order_ntl, max_px, ema }
StreamTracker(3) {
validator_to_value: HashMap<Address, ValidatorValue>,
median_value: f64, // CONFIRMED: stake-weighted median
update_median_bucket_guard: BucketGuard,
}
8.6 Mark Price Formula CONFIRMED
Mark price is derived from the oracle price and order book impact prices. The impact price simulates a trade of impact_usd notional against the book to determine a fair market price.
Impact price configuration:
default_impact_usd: f64, // typically 200 USD
override_impact_usd: HashMap<u32, f64>, // per-asset override
clamp: bool, // whether to clamp impact price
Mark price computation:
impact_bid = simulate_buy(book, impact_usd_notional)
impact_ask = simulate_sell(book, impact_usd_notional)
mark_px = f(oracle_px, impact_bid, impact_ask, ema)
Three parallel price maps in exchange state:
coin_to_mark_px: HashMap<u32, f64> // mark prices
coin_to_oracle_px: HashMap<u32, f64> // oracle prices
coin_to_external_perp_px: HashMap<u32, f64> // external perp prices
API response per asset (PerpAssetCtx): markPx, funding, openInterest, prevDayPx, dayNtlVlm, premium, midPx, impactPxs (array of [bid_impact, ask_impact]), dayBaseVlm, circulatingSupply, totalSupply.
8.7 HIP-3 Stale Mark Price CONFIRMED
HIP-3 stale mark price detection uses a 10-second window. Mark prices older than 10 seconds are considered stale and refreshed during begin_block (effect #7 of 9). BIN: hip3_stale_mark_px_guard, refresh_hip3_stale_mark_pxs
Exchange fields:
hip3_stale_mark_px_guard: BucketGuard, // guards stale mark detection
hip3_no_cross: bool, // disable crossing
Function: refresh_hip3_stale_mark_pxs() -- called in begin_block effect #7
Companion: prune_book_empty_user_states() -- cleanup (begin_block effect #4)
8.8 Oracle Price Bounds
| Bound | Field / Message |
|---|---|
| Max oracle price | has_max_oracle_px |
| Min oracle price | has_min_oracle_px |
| Per-asset distance override | override_max_signed_distances_from_oracle |
| Order distance from anchor | max_order_distance_from_anchor = 0.95 |
| OI cap rejection | "more aggressive than oracle when open interest is at cap." |
9. Liquidation Engine #
See the dedicated Liquidation and ADL reference for the execution split across perps, portfolio margin, BOLE, spot, and outcomes, plus the current call-graph links and open-gap table.
| Type | LtHash Category | Trigger |
|---|---|---|
| Cross liquidation | LiquidatedCross | Cross margin below maintenance |
| Isolated liquidation | LiquidatedIsolated | Isolated margin below maintenance |
| BOLE market | BoleMarketLiquidation | Health factor below threshold |
| BOLE backstop | BoleBackstopLiquidation | Backstop takes over |
| BOLE partial | BolePartialLiquidation | Partial reduction (cooldown) |
Perp liquidation condition: margin_available < 0, equivalently account_value < maintenance_margin. Maintenance is tiered by notional bracket using lower_bound, max_leverage, and maintenance_deduction. Cross positions share account equity; isolated positions use per-position allocated margin.
9.0 begin_block Liquidation Trigger Flow CONFIRMED
BOLE liquidations run as effect #3 of the 9-step begin_block pipeline. Perp liquidations are user-initiated via the Liquidate action during action processing.
9.1 Margin And Trigger Logic
| Component | Current best formula / rule | Status |
|---|---|---|
| Initial margin | sum(notional_in_tier / max_leverage) | Confirmed structure |
| Maintenance margin | sum(notional_in_tier / max_leverage - maintenance_deduction) | Confirmed |
| Cross liquidation | balance + cross_uPnL - maintenance_margin_used < 0 | Confirmed |
| Isolated liquidation | allocated_margin + uPnL - maintenance_margin < 0 | Confirmed |
| Liquidation price | Tier-aware maintenance boundary; local implementation uses an approximate closed form | Approximation |
9.2 Auto-Deleveraging (ADL)
ADL is the shortfall path, not the first path. Standard liquidation runs first. If liquidation still leaves residual bad debt, Hyperliquid flips on perform_auto_deleveraging and tracks the unresolved amount in adl_shortfall_remaining. There are no socialized losses in the current model; loss is pushed into opposing profitable positions.
| ADL property | Meaning |
|---|---|
perform_auto_deleveraging | Exchange / clearinghouse flag indicating ADL mode is active |
adl_shortfall_remaining | Residual shortfall that liquidation did not cover |
asset_and_side_to_adl_requirements | Per-asset, per-side shortfall buckets in the binary model |
position_index, risk_key | Ordering fields used in the liquidation / ADL pipeline |
returnOnEquity | API-facing profitability field that matches the ADL ranking surface |
Ranking rule: counter-parties are selected from the opposing profitable side and ranked by ROE / PnL%, i.e. unrealized_pnl / margin_allocated. Higher ROE means higher ADL priority. In practical terms: a liquidated long pushes into profitable shorts first; a liquidated short pushes into profitable longs first.
1. Detect liquidatable account
2. Execute ordinary liquidation
3. Compute residual shortfall
4. If residual shortfall > 0:
- set perform_auto_deleveraging = true
- update adl_shortfall_remaining
- bucket by (asset, opposing side)
- rank profitable counterparties by ROE descending
- delever until shortfall is exhausted or no eligible size remains
9.3 BOLE Liquidation
BOLE is a separate lending liquidation system with its own three LtHash categories. The strongest confirmed trigger is a 0.8 health-factor threshold. When a BOLE user falls below that boundary, the system can route through one of three liquidation modes:
| BOLE mode | Meaning | Guardrail |
|---|---|---|
| Market | Ordinary BOLE liquidation into the market path | Runs only when health is below threshold and no higher-priority backstop route applies |
| Backstop | Default/backstop liquidator takes over the borrow position | Requires configured liquidator routing |
| Partial | Reduce risk without fully closing the borrow | Subject to partial_liquidation_cooldown |
The current best state model for BOLE risk is: supplied_value, borrowed_value, ltv, and healthFactor. The begin-block pass apply_bole_liquidations is the confirmed entrypoint for that lane.
9.4 Safeguards And Safety Controls
| Control | Purpose |
|---|---|
allowed_liquidators | Explicit liquidator allowlist at Exchange scope |
defaultLiquidator | User/BOLE routing hint for backstop-style liquidations |
partial_liquidation_cooldown | ~30 second spacing between repeated partial liquidations |
halted_assets | Per-asset halt switch preventing normal trading on frozen markets |
override_max_signed_distances_from_oracle | Per-asset mark/oracle distance overrides used in risk gating |
max_withdraw_leverage | Prevents high-leverage withdrawals from extracting too much collateral |
MarginMode::NoCross / StrictIsolated | Blocks unsafe cross-margin usage on selected assets |
Operational rule set: liquidator margin is checked before liquidation, some assets require the liquidator to use cross margin, and BOLE backstop routing sits beside the ordinary liquidation path rather than replacing it. The current implementation effort mirrors that separation: planner first, then exact state transitions once the remaining edge semantics are proved.
9.5 Formula Sheet
Cross account value
= balance + sum(unrealized_pnl_cross_positions)
Cross margin available
= account_value - cross_maintenance_margin_used
Cross liquidation trigger
= (margin_available < 0)
Isolated margin available
= allocated_margin + unrealized_pnl - maintenance_margin
Isolated liquidation trigger
= (isolated_margin_available < 0)
Initial margin
= sum_over_tiers(notional_in_tier / max_leverage)
Maintenance margin
= sum_over_tiers(notional_in_tier / max_leverage - maintenance_deduction)
ADL ranking score
= return_on_equity
= unrealized_pnl / margin_allocated
BOLE utilization
= total_borrows / total_deposits
BOLE local health factor
= supplied_value / borrowed_value
BOLE liquidation trigger
= (health_factor < 0.8)
Confirmed for the trigger shapes and tier structure. Inferred / local model for parts that still depend on exact binary-side execution semantics, especially final BOLE transfer sizing and full portfolio-margin netting.
9.6 Product Surfaces
| Surface | Trigger path | What happens | Status |
|---|---|---|---|
| Perps, cross margin | margin_available < 0 at account level | User-facing Liquidate path, then ADL if residual shortfall remains | Core trigger confirmed |
| Perps, isolated margin | allocated_margin + uPnL - maintenance < 0 | LiquidateRequest::Isolated on one asset | Confirmed |
| Portfolio margin | Same liquidation family, but on portfolio-netted account state | Mode overlay on top of margin engine, not a separate liquidation subsystem | Semantics still being tightened |
| Spot | No ordinary leverage liquidation engine confirmed | SpotDustConversion is a separate system cleanup path, not perp-style liquidation | Distinct from liquidation |
| Outcomes (HIP-4) | No liquidation path | 1x isolated-only; settlement auto-cancels open orders and rejects new orders post-settlement | No leverage, no liquidation |
| BOLE lending | healthFactor < 0.8 | Market / Backstop / Partial liquidation lane in begin_block | Mode family confirmed |
9.7 Trigger Call Graph
10. State Hashing: LtHash16 #
10.1 Algorithm CONFIRMED
Action Response (per action)
-> rmp_serde::to_vec_named(response) // rmp-serde 1.3.0, named/map mode
-> blake3::Hasher (streaming Write) // blake3 1.7.0 at VA 0x04e03010
-> blake3 XOF (2048 bytes)
-> 1024 x u16 LE
-> SSE2 paddw wrapping-add // VA 0x04e05786
-> Per-category LtHash16 accumulator (11 L1 + 3 EVM = 14 total)
Final app_hash (32 bytes):
L1_combined = paddw(all 11 L1 accumulators)
EVM_combined = paddw(all 3 EVM accumulators)
app_hash = first_16(SHA-256(L1_combined)) || first_16(SHA-256(EVM_combined))
// NOT a single SHA-256 of all 14 combined! Confirmed from node log at h=536290000
10.2 All 11 L1 Hash Categories
CONFIRMED at rodata 0x65fb61.[15]
| # | Category | Offset | Pairing |
|---|---|---|---|
| 0 | CValidator | 0x75fb61 | [0,1] |
| 1 | CSigner | 0x75fb6b | [0,1] |
| 2 | Na | 0x75fb72 | [2,3] |
| 3 | LiquidatedCross | 0x75fb74 | [2,3] |
| 4 | LiquidatedIsolated | 0x75fb83 | Unique |
| 5 | Settlement | 0x75fb95 | Unique |
| 6 | NetChildVaultPositions | 0x75fb9f | Unique |
| 7 | SpotDustConversion | 0x75fbb5 | [7,8] |
| 8 | BoleMarketLiquidation | 0x75fbc7 | [7,8] |
| 9 | BoleBackstopLiquidation | 0x75fbdc | [9,10] |
| 10 | BolePartialLiquidation | 0x75fbf3 | [9,10] |
10.3 RespHash Dispatch
VA 0x205a300. 20-entry jump table at 0x37fe2c. 14 accumulators at 0x800-byte intervals (0x50066c8..0x500cec8). Hashes response structs (not raw mutations).[15]
Response Struct Field Ordering (11 structs, CRACKED)
| Struct | Fields (order) | VA |
|---|---|---|
| OrderStatus | "filled": totalSz, avgPx, oid; "error": string; "waitingForFill": oid; "waitingForTrigger": oid; "resting": oid, cloid | 0x4a75120 |
| RestingOrder (15) | coin, side, limitPx, sz, timestamp, triggerCondition, isTrigger, triggerPx, isPositionTpsl, reduceOnly, orderType, origSz, tif, cloid, children | 0x4a98d30 |
| TwapSliceFill (10) | coin, user, side, sz, executedSz, executedNtl, minutes, reduceOnly, randomize, timestamp | 0x4a701a0 |
| TwapState (4) | status, running, error, twapId | 0x4a70410 |
| Fill/Trade API wrapper (24) | API/user-fill wrapper with coin, feeToken, fill context, and externally-tagged OrderStatus; hashed fill payload is a separate 18-field struct | 0x4a47ec0 |
| ActionError (3) | status, success, error | 0x4a707f0 |
| StatusResult (1) | status | 0x4a70a60 |
| OrderBase (3) | side, sz, reduceOnly | 0x4a80610 |
| OrderWithTiming (5) | side, sz, reduceOnly, randomize, timestamp | 0x4a82640 |
| TriggerParams (2) | triggerPx, tpsl | 0x4a8d2d0 |
| TriggeredFill (2) | triggered, filled | 0x4a99070 |
2026-04-05 clarification: hybrid G-family actions hash as {status:"success"} on success and use the 3-field {status:"err", success:false, error:<msg>} payload only on error. Fill hashes also no longer share the ordinary ledger-update/API wrapper shape.
10.4 EVM Element Formats
| Category | Size | Format (raw byte concat) |
|---|---|---|
accounts_hash | 92B | address(20) || balance(32 BE) || nonce(8 BE) || code_hash(32) |
storage_hash | 84B | address(20) || slot(32) || value(32) |
contracts_hash | Variable | address(20) || code(bytecode) |
10.5 VoteAppHash
Every 2000 blocks, 3 validators, ~150 blocks after checkpoint. Mismatch: /tmp/abci_state_with_quorum_app_hash_mismatch.rmp.
10.6 Hash Accumulator Naming Pattern CONFIRMED
Binary strings reveal a systematic naming convention for hash accumulators, partitioned per clearinghouse (DEX) instance. BIN: rodata string search
Pattern: {category}_{dex_prefix}
Where dex_prefix:
H = main clearinghouse (clearinghouse index 0)
H3 = HIP-3 clearinghouses
Examples from binary strings:
AllBoleTH3 -- all BOLE state for HIP-3 clearinghouse
borrowLeH3 -- borrow ledger entries, HIP-3
funding_H3 -- funding state, HIP-3
1emasH -- EMAs for main clearinghouse
Per-clearinghouse hash partitioning confirmed:
Each clearinghouse (main + HIP-3 instances) maintains
separate LtHash16 accumulators for its own state.
The suffix distinguishes which clearinghouse owns the
accumulator. This enables incremental hashing per-DEX
without cross-contamination between clearinghouse instances.
The 14 total accumulators (11 L1 + 3 EVM) cover: validator state changes, liquidation events (cross, isolated, BOLE), settlement, vault netting, spot dust conversion, and EVM state (accounts, contracts, storage).
11. Gossip Protocol (FULLY CRACKED) #
11.1 Wire Frame
[u32 BE body_len][u8 kind][body] kind=0x01: LZ4 bincode-fork
11.2 Handshake
Out: [00 00 00 02][00][00][00] (7B) In: [00 00 00 01][00][chain] (6B, chain=0x04=Mainnet)
11.3 MsgConcise (Tag 27, 8 variants)
| # | Variant |
|---|---|
| 0 | Tx |
| 1 | Block |
| 2 | Vote |
| 3 | Timeout |
| 4 | Tc |
| 5 | BlocksAndTxs |
| 6 | Heartbeat |
| 7 | HeartbeatAck |
11.4 OutMsgConcise (Tag 28, 9+ variants)
| # | Variant |
|---|---|
| 0 | Block |
| 1 | ClientBlock |
| 2 | VoteJailBundle |
| 3 | Timeout |
| 4 | Tc |
| 5 | Heartbeat |
| 6 | NextProposer |
| 7 | Tx |
| 8 | RpcRequest |
11.5 Mid Field
CONFIRMED: jump table VA 0x65f47c.[20]
| Mid | Label |
|---|---|
| 0 | in |
| 1 | execution state |
| 2 | out |
| 3 | status |
| 4 | round advance |
11.6 Heartbeat Wire Layout
Heartbeat { validator(20B), round(u64),
snapshot: HeartbeatSnapshot {
validator_set_snapshot: { stakes, jailed_validators },
evm_block_number: u64,
concise_lt_hashes: {
accounts_hash: ConciseLtHash { hash_concise: [u8;32], n_elements, n_bytes },
contracts_hash: ConciseLtHash,
storage_hash: ConciseLtHash
}
},
validator_to_last_msg_round, random_id
}
// hash_concise = 32B SHA-256 digest (NOT 2048B LtHash16)
11.7 Send Path (6 Layers)
| Layer | VA | Role |
|---|---|---|
| 1 | 0x043b8330..8f70 | Field serializers |
| 2 | 0x04593d40 | MsgConcise struct builder |
| 3 | 0x042f8fc0 | Ring buffer producer |
| 4 | 0x043bf670 | send_to_destination + bincode-fork |
| 5 | 0x0409c0e0 | BTreeMap peer routing |
| 6 | 0x01cc9d00 | tcp_bytes (bswap for BE) |
12. HyperEVM #
| Param | Value |
|---|---|
| Engine | revm 36 (upstream 19.2.0) |
| Spec | Cancun (no blobs) |
| Chain ID | 999 mainnet / 998 testnet |
| Fast blocks | 1s, 3M gas |
| Large blocks | 60s, 30M gas |
| Fees | Base + priority burned |
| HYPE | 0x2222...2222 |
| CoreWriter | 0x3333...3333 (15 actions, ~25K gas) |
| Read precompiles | 0x0800+, gas=2000+65*(in+out) |
12.1 Dual-Block Architecture CONFIRMED
HyperEVM runs two parallel block streams with different parameters:
| Property | Fast Block | Large Block |
|---|---|---|
| Interval | 1 second | 60 seconds |
| Gas limit | 3,000,000 | 30,000,000 |
| Use case | Default transactions | Heavy computation (deploys, batch ops) |
| Routing | Default | evmUserModify.usingBigBlocks |
Users opt into large blocks via the evmUserModify action with usingBigBlocks: true. Both block types share the same state -- they are sequential, not parallel execution environments.
12.2 CoreWriter (0x3333...3333) CONFIRMED
CoreWriter is the EVM-to-L1 bridge contract at address 0x3333333333333333333333333333333333333333. It is a system precompile, not a deployed contract.
Interface
interface ICoreWriter {
event RawAction(address indexed user, bytes data);
function sendRawAction(bytes calldata data) external;
}
Packed Encoding
abi.encodePacked(uint8(1), uint24(actionId), abi.encode(params...))
The version byte is always 1. The uint24 action ID selects the L1 action type. Parameters are standard ABI-encoded after the 4-byte prefix.
CoreWriter Action Types (15)
| ID | Action | Parameters |
|---|---|---|
| 1 | IocOrder | asset, isBuy, limitPx, sz, reduceOnly, cloid |
| 2 | Cancel | asset, cloid |
| 3 | TransferUsd | destination, amount |
| 4 | TransferSpot | destination, token, amount |
| 5 | Withdraw | destination, amount |
| 6 | SpotDeploy | token params |
| 7 | VaultTransfer | vault, isDeposit, usd |
| 8 | UpdateLeverage | asset, isCross, leverage |
| 9 | UpdateIsolatedMargin | asset, isBuy, ntl |
| 10 | Delegate | validator, amount |
| 11 | Undelegate | validator, amount |
| 12 | ApproveAgent | agentAddress, agentName |
| 13 | ApproveBuilderFee | builder, maxFeeRate |
| 14 | BorrowLend | operation, token, amount |
| 15 | SetReferrer | code |
All CoreWriter actions go through the ActionDelayer -- they are NOT executed immediately. CONFIRMED
12.3 L1 to EVM Flow (sendToEvmWithData) CONFIRMED
The sendToEvmWithData action transfers funds from L1 (HyperCore) to HyperEVM, with optional calldata execution on arrival. 11 fields confirmed for the action.
| Step | Description |
|---|---|
| 1 | User submits sendToEvmWithData on L1 |
| 2 | User is debited on L1 immediately |
| 3 | Transfer is queued for the next EVM block |
| 4 | SystemTx is injected in next EVM block to mint tokens to the user's EVM address |
| 5 | If calldata was specified, it is executed on the EVM side after minting |
12.4 EVM to L1 Flow (CoreWriter Scan Loop) CONFIRMED
After each EVM block is executed, the L1 state machine scans transaction receipts for CoreWriter log events and enqueues them as delayed L1 actions.
| Step | Description |
|---|---|
| 1 | EVM block finishes execution |
| 2 | Scan all transaction receipts for RawAction events from 0x3333...3333 |
| 3 | Decode packed params: version byte (0x01) + uint24 action ID + ABI-encoded parameters |
| 4 | Check disabled_core_writer_actions per-type kill switch |
| 5 | Enqueue in ActionDelayer with maturity timestamp |
| 6 | Actions execute in a future begin_block when the delay has elapsed; exact placement within begin_block is still open in current RE |
12.5 Action Delayer (9 Fields) CONFIRMED
delayed_actions, user_to_n_delayed_actions, n_total_delayed_actions,
max_n_delayed_actions, vty_trackers, status_guard, enabled,
delayer_mode(Alternating), delay_scale
Capacity behavior: When the delayer is at capacity (n_total_delayed_actions >= max_n_delayed_actions), new actions are silently rejected. There is no eviction of existing actions and no error returned to the caller. CONFIRMED
Placement note: the widened execution note and current local engine now align on update_action_delayer as the named delayed-action lane at slot 8. What remains open is the ActionDelayer control logic around enabled, delayer_mode, status_guard, and vty_trackers.
ActionDelayerStatus
enum ActionDelayerStatus {
On, // Always active
Alternating { seconds: u64 }, // Active in alternating windows
}
DelayedActionSerde
DelayedActionSerde {
action, // The L1 action to execute
id, // Unique action identifier
is_frontend, // Whether submitted via frontend
expires_after, // Expiry timestamp
evm_tx_hash, // Source EVM transaction hash
broadcaster, // Broadcasting validator
}
12.6 Security Model
| Control | Purpose |
|---|---|
| No ERC20 approve attack | CoreWriter reads msg.sender directly -- no transferFrom pattern, preventing approval-based exploits |
disabled_core_writer_actions | Per-action-type kill switch. Validators can disable individual CoreWriter action IDs |
l1_transfers_enabled | Global kill switch for all L1 transfers |
| Action delay | All CoreWriter actions go through ActionDelayer, preventing MEV/front-running from EVM contracts |
| Frozen user recovery | DeployerSendToEvmForFrozenUserAction allows deployers to recover funds for frozen users (new in testnet 2026-04-03) |
| Silent rejection at capacity | No eviction, no error -- prevents DoS amplification |
13. Bridge #
The ETH-Hyperliquid bridge (version 2, "Bridge2") enables deposits and withdrawals between Ethereum L1 (Arbitrum) and HyperCore. Bridge operations use the same validator signer keys as consensus -- there are NOT separate EOA signing keys for bridge operations. CONFIRMED[22]
13.1 Bridge2 Struct (10 Fields) CONFIRMED
Exchange field [8] bridge2. SNAP: confirmed from ABCI state
Bridge2(10) {
eth_id_to_deposit_votes, // deposit confirmation tracking
finished_deposits_data, // completed deposits
withdrawal_signatures, // withdrawal signature collection
withdrawal_finalized_votes, // finalization vote tracking
finished_withdrawal_to_time, // withdrawal completion timestamps
validator_set_signatures, // validator set update signatures
validator_set_finalized_votes, // validator set finalization votes
bal, // bridge balance as UsdcNtl [usdc, ntl]
last_pruned_deposit_block_number, // deposit pruning watermark
oaw, // only-allow-withdrawals flag
}
13.2 Signing Model CONFIRMED
Bridge signing = consensus signing. The consensus signer key (the key used for HyperBFT voting) is the same key that signs bridge withdrawal messages and validator set updates. There are NOT separate EOAs.
| Property | Value |
|---|---|
| Signing key | Same secp256k1 key as consensus (hot signer) |
| Quorum threshold | 2/3+ stake-weighted (same as HyperBFT consensus) |
| Ethereum-side architecture | Hot/cold wallet on Bridge2.sol contract |
| Hot signers | Validator signer keys (mirrors consensus signer set) |
| Cold signers | Higher-security keys for validator set updates and emergencies |
| Dispute period | Withdrawals have a dispute period before finalization on Ethereum |
13.3 Deposit Flow
VoteEthDepositAction (3 fields): deposit_id, chain, validator. Each validator independently observes the Ethereum deposit and submits a vote. When 2/3+ of stake weight has voted, the deposit is confirmed and funds are credited.
13.4 Withdrawal Flow
ValidatorSignWithdrawalAction (5 fields): signature, chain, nonce, withdrawal_hash, validator. Validators sign the withdrawal using their consensus signer keys. After 2/3+ signatures are collected, the withdrawal enters a dispute period on Ethereum before funds can be claimed.
13.5 Validator Set Update Flow
When the active validator set changes (due to staking changes, jailing, or epoch transitions), the bridge's Ethereum-side contract must be updated to reflect the new signer set.
1. Validator set changes on HyperCore (epoch transition, delegation change)
2. Validators sign the new validator set: SignValidatorSetUpdateAction
3. validator_set_signatures accumulates signatures
4. 2/3+ stake-weighted signatures collected
5. validator_set_finalized_votes confirms finalization
6. New validator set submitted to Bridge2.sol on Ethereum
7. Bridge2.sol updates hot/cold signer sets
13.6 Bridge Action Types
| Action | Fields | Purpose |
|---|---|---|
VoteEthDepositAction | 3 | Vote to confirm L1 deposit |
ValidatorSignWithdrawalAction | 5 | Sign withdrawal message |
SignValidatorSetUpdateAction | -- | Sign validator set change |
VoteEthFinalizedWithdrawalAction | -- | Finalize withdrawal on L1 |
InvalidateWithdrawals | -- | Cancel pending withdrawals during dispute period |
13.7 Security Model
| Finding | Severity | Detail |
|---|---|---|
| Broadcaster centralization | Critical | Single broadcaster controls action ordering and inclusion. MEV extraction possible. |
| InvalidateWithdrawals | Critical | Validators can cancel ANY pending withdrawal during dispute period. No escape hatch for users if validators collude. |
| No escape hatch | Critical | Users cannot force-withdraw if the validator set becomes adversarial. Bridge is fully trust-dependent on active validator set. |
| Broadcaster MEV | High | Broadcaster sees all pending transactions before inclusion and can front-run, sandwich, or censor. |
| Instant validator set update | High | ModifyBroadcaster is instant (no timelock). Validator set update on Ethereum can be changed with hot key quorum. |
| Configurable withdrawal fee | Medium | bridge2_withdraw_fee -- validators can change the withdrawal fee via governance. |
14. HIP-4: Outcomes #
Native L1 prediction markets (event contracts). Binary instruments that settle between 0 and 1 (or fractionally via settleFraction). Deployed through the HIP-3 (builder-deployed perps) pipeline but with fundamentally different mechanics: 1x isolated margin only, no leverage, no liquidation, no continuous oracle feed. Price discovery is purely CLOB-based. Settlement by deployer-designated oracleUpdater. Requires 1M HYPE stake (slashable for oracle manipulation).[23]
14.1 OutcomeTracker (11 Fields) CONFIRMED
The OutcomeTracker is stored in the Exchange state and manages all live/active outcomes. BIN: struct OutcomeTracker with 11 elements
State structures:
OutcomeTracker(11) -- manages all outcome state in Exchange
OutcomeSpec(4) -- tuple struct: settleFraction, details, questions, outcome
OutcomeSideSpec(3) -- one side (YES or NO)
QuestionSpec(5) -- question grouping related outcomes
SettledOutcome -- resolved state
SettledOutcomeSpec(3) -- settlement parameters
SettledOutcomeHistory(3) -- historical record
SettledQuestionSpec(4) -- question-level settlement
14.2 Outcome Lifecycle
14.3 OutcomeDeploy Enum (8 Variants) CONFIRMED
Nested inside Hip3DeployAction. BIN: impl_outcome.rs
| Variant | Fields | Purpose |
|---|---|---|
RegisterQuestion | 3 | Create question grouping multiple outcomes |
RegisterOutcome | 4 | Create outcome (outcome, settleFraction, details, namedOutcome) |
RegisterNamedOutcome | 2 | Add named outcome to existing question |
ChangeOutcomeDescription | 2 | Update outcome metadata |
SettleOutcome | 3 | Oracle posts final resolution |
ChangeQuestionDescription | 2 | Update question metadata |
RegisterOutcomeToken | 1 | Register backing token for outcome market |
RegisterTokensAndStandaloneOutcome | 3 | Combined token + outcome registration |
14.4 UserOutcomeAction Enum (4 Variants) CONFIRMED
| Variant | Fields | Purpose |
|---|---|---|
SplitOutcome | 2 (wei, outcome_id) | Lock collateral, mint YES+NO pair. Deposit 1 unit collateral = 1 YES + 1 NO. |
MergeOutcome | 1 | Burn 1 YES + 1 NO to reclaim 1 unit of collateral. Exit without directional view. |
MergeQuestion | 1 | Redeem complete set across all outcomes in a question (multi-outcome markets). |
NegateOutcome | 3 | Flip YES to NO (or vice versa) atomically. Swap without two separate trades. |
14.5 Settlement Flow
The oracleUpdater address is set at deployment time in Hip3SchemaInput. It is the deployer-designated settlement authority -- the deployer IS the oracle. There is no Chainlink, Pyth, or continuous feed for outcome prices.
Settlement flow:
1. oracleUpdater submits SettleOutcome(3) via Hip3DeployAction
2. Trading halts immediately
3. All open orders auto-cancelled (outcomeSettledCanceled)
4. New orders rejected (outcomeSettledRejected)
5. Positions auto-settle at posted outcome value (0, 1, or settleFraction)
6. Collateral released to winners in collateralToken
7. Slot recycled -- 1M HYPE stake available for new markets
Price bounds during trading: 0.001 to 0.999
Settlement values: 0 or 1 (binary), or fractional via settleFraction
Collateral: configurable per deployment (any aligned quote token, NOT restricted to USDH)
14.6 Price Discovery Model
| Property | Perps (HIP-3) | Outcomes (HIP-4) |
|---|---|---|
| Price during trading | coin_to_oracle_px (external feed) + coin_to_mark_px (book) | CLOB mid only -- no external oracle feed |
| Oracle role | Continuous price feed (Binance/Pyth) for mark/funding | Settlement only -- oracleUpdater posts final 0/1 result |
| Mark price | Derived from oracle + book | Derived from book only |
| Funding | Yes (EMA premium) | No funding rates |
| Leverage | Up to 50x | 1x only (isolated) |
| Liquidation | Yes (margin engine) | None -- loss capped at premium |
14.7 HIP-3 Shared Infrastructure
Outcomes share deployment and orderbook infrastructure with HIP-3 perps:
Hip3SchemaInput(3): collateralToken, oracleUpdater, OutcomeDeploy
Hip3Schema(9): full_name, oracle_updater, fee_recipient, asset_to_oi_cap,
sub_deployers, deployer_fee_scale, last_deployer_fee_scale_change_time, +2
Hip3Limits(6): total_oi_cap2, oi_sz_cap_per_perp, max_transfer_ntl2,
max_under_initial_margin_transfer_ntl2, daily_px_range, max_n_users_with_positions
LtHash category: Settlement (index 5 of 11 L1 categories)
15. BOLE Lending #
Protocol-controlled lending system built into HyperCore L1. Not an EVM contract. BOLE is NOT deployer-configurable -- pool parameters (reserves, rate limits, ADL, backstop liquidation) are set at protocol level by validator governance via SystemBole (action 46, broadcaster-only).[24]
15.1 BolePool (19 Fields) CONFIRMED
Per-token lending pool state. Stored in locus.blp (Exchange Locus field [8]). SNAP: confirmed from ABCI state
BolePool(19) {
dp, du, o, pmmt, e, pmv, r, p, n, b,
bog, pmdl, pml, uobc, ubgl, ubul, bwo, mbs, u
}
// Abbreviated serde names. Maps to:
// totalSupplied, totalBorrowed, utilization, rates,
// reserve config, user states, backstop params, etc.
Key API state per token:
totalSupplied // total supplied to pool
totalBorrowed // total borrowed from pool
utilization // totalBorrowed / totalSupplied
healthFactor // per-user health metric
ltv // loan-to-value ratio
predictedRate // predicted interest rate
borrowYearlyRate // annualized borrow rate
interestAmount // accrued interest
portfolioMarginEnabled // portfolio margin flag
15.2 User Operations CONFIRMED
BoleAction(3): operation, token, amount. Wire name: borrowLend.
| Operation | Description |
|---|---|
borrow | Borrow tokens from pool. Requires sufficient collateral. |
supply | Supply tokens to pool. Earn interest. |
repay | Repay borrowed tokens. |
defaultLiquidator | Designate a default liquidator for borrow positions. |
optOut | Opt out of lending. |
15.3 Rate Curve (Aave-Style Kink Model) CONFIRMED
Interest rates follow a standard two-slope kink model, similar to Aave/Compound.
RawRateCurve {
kink_rate: f64, // interest rate at kink utilization point
kink_utilization: f64, // utilization threshold where slope changes
base_rate: f64, // base interest rate (at 0% utilization)
slope1: f64, // slope below kink (gentle)
slope2: f64, // slope above kink (steep)
}
Rate computation:
if utilization <= kink_utilization:
rate = base_rate + (utilization / kink_utilization) * slope1
else:
excess = (utilization - kink_utilization) / (1 - kink_utilization)
rate = base_rate + slope1 + excess * slope2
15.4 SetBole Governance Variants (6) CONFIRMED
Protocol-level configuration via SystemBole (broadcaster-only). BIN: SetBole variants from Ghidra
| Variant | Fields | Purpose |
|---|---|---|
Reserve | 9 | Configure reserve parameters per token |
Adl | 2 | Auto-deleveraging for lending positions |
BackstopLiquidatorTokenParams | 4 | Per-token backstop liquidator configuration |
ResetIndex | 2 | Reset lending index (administrative) |
RateLimit | 7 | Rate limiting configuration for lending operations |
TestnetAction | 2 | Testnet-only operations |
15.5 BOLE Liquidation Flow CONFIRMED
BOLE liquidation is triggered in begin_block effect #3 (apply_bole_liquidations). Health factor threshold: 0.8. Three liquidation modes with distinct LtHash categories.
BOLE health computation:
healthFactor = supplied_value / borrowed_value
Liquidation trigger: healthFactor < 0.8
Order type: borrowLendLiquidation (display: "Borrow Liquidation")
Cooldown: partial_liquidation_cooldown = 30.0 seconds
Error messages:
"Insufficient collateral for operation"
"Insufficient balance"
"Exceeded cap for asset"
"Only supplying is enabled"
"Too many operations"
"borrow_cap > supply_cap"
15.6 Hash Accumulator Naming CONFIRMED
BOLE state is tracked in per-clearinghouse hash accumulators following the naming pattern from Section 10.6.
AllBoleTH3 -- all BOLE state for HIP-3 clearinghouse
borrowLeH3 -- borrow ledger entries, HIP-3
LtHash categories for BOLE liquidation events:
BoleMarketLiquidation (index 8 of 11 L1 categories)
BoleBackstopLiquidation (index 9, paired with [9,10])
BolePartialLiquidation (index 10, paired with [9,10])
Exchange field: reserve_accumulators -- Vec of (token_id, accumulator) pairs
Mainnet keys: 107, 207, 232, 255 (4 tokens with BOLE reserves)
16. Guards (16 BucketGuards) #
| Guard | Purpose |
|---|---|
funding_distribute_guard | Hourly funding |
funding_update_guard | EMA updates |
begin_block_logic_guard | Reentrancy |
cancel_aggressive_orders_at_oi_cap_guard | OI cap cancels |
book_empty_user_states_pruning_guard | State pruning |
ensure_order_bucket_guard | Order validation |
reset_recent_oi_bucket_guard | OI reset |
stakes_decay_bucket_guard | Stake decay |
stage_reward_bucket_guard | Reward staging |
distribute_reward_bucket_guard | Reward distribution |
update_median_bucket_guard | Median price |
prune_bucket_guard | General pruning |
alert_bucket_guard | Alert rate |
partial_liquidation_cooldown | ~30s spacing |
hip3_stale_mark_px_guard | HIP-3 stale detection |
status_guard | Action Delayer |
Volume-Gated: Sub-accounts, scheduled cancels, portfolio margin, extra agents, referral codes.
17. Validator Operations #
Hyperliquid uses a two-key model per validator: a cold validator key that holds funds, receives rewards, and manages the validator profile, and a hot signer key stored in node_config.json that signs consensus messages and bridge operations.
17.1 CStaking (23 Fields) CONFIRMED
Exchange field [10] c_staking. Full consensus staking state. SNAP: confirmed from ABCI state
CStaking(23) {
stakes, // validator stakes
allowed_validators, // validator allowlist
allow_all_validators, // permissionless mode flag
broadcasters, // whitelisted broadcasters
validator_to_profile, // CValidatorProfile per validator
validator_to_last_signer_change_time, // signer rotation tracking
delegations, // delegation state per user
proposals, // governance proposals
stakes_decay_bucket_guard, // stake decay timing
jailed_signers, // currently jailed signers
jail_vote_tracker, // jail vote accumulation
jail_until, // jail expiry per validator
signer_to_last_manual_unjail_time, // unjail cooldown tracking
native_token_reserve, // HYPE reserve for rewards
stage_reward_bucket_guard, // reward staging timing
validator_to_staged_rewards, // staged (pending) rewards
distribute_reward_bucket_guard, // reward distribution timing
user_states, // per-user staking state
pending_withdrawals, // pending stake withdrawals
self_delegation_requirement, // minimum self-delegation
disabled_validators, // disabled validator set
disabled_node_ips, // disabled node IPs
validator_to_state, // per-validator state tracking
}
17.2 CValidatorProfile and CValidatorAction CONFIRMED
CValidatorProfile (6 Fields)
CValidatorProfile {
node_ip: String, // validator node IP address
delegations_disabled: bool, // whether delegations are accepted
commission_bps: u32, // commission in basis points
signer: Address, // hot signer key address
register_time: u64, // registration timestamp
last_signer_change_time: u64, // last signer rotation time
}
CValidatorAction (16 Variants) CONFIRMED
Requires cold validator key. BIN: variant index 0 <= i < 16
| Action | Purpose |
|---|---|
Register (3 fields) | Register as validator (profile, signer, initial stake) |
ChangeProfile (7 fields) | Update node_ip, delegations_disabled, commission_bps, signer, etc. |
registerAsset | Register new tradeable asset |
registerAsset2 | Extended asset registration |
setOracle | Oracle management |
setFeeRecipient | Fee destination configuration |
setFeeScale | Fee scale adjustment |
insertMarginTable | Add margin table |
setMarginTableIds | Assign margin tables to assets |
setOpenInterestCaps | Set OI caps per asset |
setFundingMultipliers | Per-asset funding multipliers |
setFundingInterestRates | Per-asset funding interest rates |
disableDex | Disable a DEX instance |
setPerpAnnotation | Set perp annotation metadata |
setMarginModes | Set margin modes per asset |
setGrowthModes | Set growth modes per asset |
CSignerAction (3 Variants)
Requires hot signer key. BIN: CSignerAction dispatch at VA 0x3352310
| Action | Purpose |
|---|---|
unjailSelf | Self-unjail after cooldown period |
jailSelf | Voluntary jail before shutdown/maintenance |
jailSelfIsolated | Jail in isolated mode |
17.3 Epoch Lifecycle CONFIRMED
Validator set transitions are epoch-based. The active set is determined by total delegation at epoch boundaries.
Staking(6) {
epoch_states, // historical epoch state snapshots
active_epoch, // currently active epoch index
cur_epoch_state, // current epoch validator set
cur_epoch, // current epoch number
epoch_duration_seconds, // epoch length (e.g. ~90 min for 100K rounds)
allowed_validators, // validator whitelist
}
EpochTracker {
epoch_states, // Vec of epoch snapshots
active_epoch, // active epoch index
cur_epoch_state, // current state
cur_epoch, // epoch counter
epoch_duration_seconds, // duration
}
Epoch transition:
1. ForceIncreaseEpoch action triggers epoch boundary
2. Rank validators by total delegation (self + delegated)
3. Top N validators become the active set (24 mainnet, 50 testnet)
4. New proposer rotation computed from new active set
5. Bridge validator set updated (same signer keys)
6. validator_power_updates applied to consensus
17.4 Delegation Flow CONFIRMED
Users delegate HYPE to validators via tokenDelegate. Rewards are distributed per epoch based on commission rates.
Delegation flow:
1. User submits tokenDelegate action (validator, amount)
2. Delegation recorded in c_staking.delegations
3. Takes effect at next epoch boundary
4. Rewards staged: stage_reward_bucket_guard fires periodically
5. Rewards distributed: distribute_reward_bucket_guard fires
6. User claims via claimRewards action
Reward distribution:
validator_reward = block_reward * validator_stake_fraction
validator_commission = validator_reward * commission_bps / 10000
delegator_share = (validator_reward - commission) * delegator_fraction
Constraints:
self_delegation_requirement enforced (minimum self-stake)
pending_withdrawals tracked for unbonding period
stakes_decay_bucket_guard handles stake decay over time
17.5 Jailing CONFIRMED
Validators are jailed for poor performance (latency) or manual self-jailing for maintenance.
Jailing fields:
validator_latency_ema // EMA of response latency
latency_ema_jail_threshold // threshold for jailing
validators_missing_heartbeat // set of non-responsive validators
disconnected_validators // detected network partitions
jailed_signers // currently jailed signer set
jail_until // jail expiry timestamp per validator
signer_to_last_manual_unjail_time // unjail cooldown tracking
jail_vote_tracker // vote accumulation for jailing
Unjail requirements:
1. Jail cooldown period must have elapsed (jail_until)
2. Validator must be in active epoch set
3. Submit CSignerAction::unjailSelf with hot signer key
4. "Signer invalid or inactive for current epoch" if not in active set
17.6 RPC Backfill (9 Validation Checks)
| # | Check | Error |
|---|---|---|
| 1 | QC round | ClientBlockQcRound |
| 2 | QC hash | ClientBlockQcHash |
| 3 | Tx validity | ClientBlockTx |
| 4 | tx_hashes match | ClientBlockTxHashes |
| 5 | Timestamp monotonic | ClientBlockTime |
| 6 | Commit proof | ClientBlockMissingCommitProof |
| 7 | Child QC | CommitProofChildQc |
| 8 | Grandchild QC | CommitProofGrandchildQc |
| 9 | Consecutive rounds | CommitProofConsecutive |
18. Key Function Addresses #
| Function | VA |
|---|---|
| Main Exchange dispatcher | 0x0272a320 |
| RespHash dispatch | 0x0205a300 |
| compute_resps_hash (testnet) | 0x2355860 |
| Blake3 hasher write | 0x04e03010 |
| SSE2 paddw | 0x04e05786 |
| LtHash insert | 0x04e0ccf0 |
| MsgConcise serializer | 0x42b7e50 |
| OutMsgConcise serializer | 0x42b87e0 |
| ConciseMid serializer | 0x42b92f0 |
| HeartbeatSnapshot ser/de | 0x438fcc0 / 0x43b9a10 |
| ConciseLtHash ser/de | 0x43db480 / 0x4387640 |
| bincode-fork serializer | 0x474f3f0 |
| send_to_destination | 0x43bf670 |
| BTreeMap peer routing | 0x409c0e0 |
| tcp_bytes | 0x1cc9d00 |
| Greeting builder | 0x2767ee0 |
| Peer rejection | 0x75fe5e |
| CSignerAction dispatch | 0x3352310 |
| Signer epoch check | 0x3355790 |
| Validator lookup | 0x2eb8fb0 |
19. Binary Structure #
Source module map from testnet binary 331bef9b (2026-04-03). CONFIRMED from panic paths and debug strings in the stripped ELF.
| Property | Value |
|---|---|
| Binary | Testnet build 2026-04-03 |
| Size | 87 MB (stripped ELF) |
| SHA-256 | 1a99c892... |
| Commit | 331bef9b |
| Build date | 2026-04-03 |
19.1 Source Module Map
/home/ubuntu/hl/code_Testnet/
+-- base/src/ -- Utilities (50+ files)
| +-- types.rs, config.rs, serialize.rs, ...
+-- db/src/ -- RocksDB backend
| +-- db.rs, compaction.rs
+-- evm_rpc/src/ -- EVM JSON-RPC
| +-- server.rs, handlers.rs
+-- l1/src/ -- Core L1 logic
| +-- abci/engine.rs, state.rs
| +-- book/book/impl_insert_order.rs
| +-- clearinghouse/
| +-- exchange/impl_trading.rs, end_block.rs, exchange.rs, impl_outcome.rs
| +-- evm/hyper_evm.rs, transactor.rs, core_writer.rs
| +-- staking.rs, vault/, fees/compute.rs, bole/user_state.rs
+-- node/src/ -- Orchestration + Consensus
| +-- consensus/state.rs, server.rs, types.rs, timer.rs, mempool.rs
| +-- client_block.rs, heartbeat_tracker.rs, rpc.rs, network.rs
Compared to mainnet build 105cb1dc (40+ files in base/), the testnet binary shows 50+ files in base/ and additional modules in the evm/ subtree.
Changelog & Corrections #
Reverse engineering is iterative. This section documents wrong assumptions, corrections, and when findings were updated. Entries are newest-first.
2026-04-05
| Topic | Was | Now | How discovered |
|---|---|---|---|
| G-family success shape | Success and error both treated as the same G-style family | Success hashes as {status:"success"}; the 3-field G payload is error-only |
RE closure in re_g_success_format.json plus local source verification |
| Fill hash payload | Public fill/trade summary treated API wrapper fields as if they were the hashed payload | Hashed fills use a separate 18-field payload; coin and feeToken are API wrapper fields |
re_fill_details.json + re_ledger_serialization.json |
| Port 4003 signed greeting body | Tiny fixed body model | Variable-sized bincode-fork content with validator addr, round, variant flag, optional ABCI extra, counters/hash material, sorted heartbeat map, trailing mempool varint | re_greeting_exact.json from captured sign-input blobs + Ghidra |
2026-04-04
| Topic | Was | Now | How discovered |
|---|---|---|---|
| Signing formula | keccak256(domain + content) |
keccak256(domain + 0x00 + content) — NULL byte separator |
GDB live capture of keccak256 input at VA 0x4a9442f |
| Signing content encoding | Assumed msgpack (file is rmp_signable.rs) |
Content is bincode-encoded | GDB capture: 1601-byte input is bincode, not msgpack |
| App hash format | SHA-256(all_14_combined) — single 32-byte digest |
first_16(SHA256(L1)) || first_16(SHA256(EVM)) — two halves |
Node log at h=536290000: L1 half matched, EVM half differed |
| Port 4001 greeting | 6-byte body, u32 LE variant index, variant 0 = send_abci | 7-8 byte body, u32 BE variant index, testnet=3, mainnet=2 | Live peer connection: 8-byte greeting gets response on testnet |
| Port 4001 framing | [u32 BE len][body] |
[u32 BE len][u8 kind][body] — includes kind byte |
Wire trace: kind=0 for greeting, kind=1 for data frames |
| Book order price field | p field on order = limit price |
p = linked-list prev-pointer. Price is at c.l[0] |
Orders loading with 100-6000x wrong prices, traced to p vs c.l |
Bridge2 oaw type |
serde_json::Value (opaque) |
bool |
Binary deserializer helper confirmed read_bool call |
| BSS accumulators | Assumed to be live running accumulators | Stale heartbeat cache — never matches committed hashes | Multiple BSS captures never matched any VoteAppHash quorum value |
szDecimals fallback |
Default 0 when metadata absent | Default 5 (matches rest of bootstrap's unknown-asset path) | Price scaling divergence on assets missing from metadata map |
Heartbeat concise_lt_hashes |
Contains all 14 category accumulators (L1 + EVM) | EVM only (accounts, contracts, storage). L1 rebuilt from state. | Ghidra trace of heartbeat serializer path, confirmed 3 fields only |
2026-04-03
| Topic | Was | Now | How discovered |
|---|---|---|---|
| Hash response serialization | rmp_serde::to_vec (compact/positional mode) |
rmp_serde::to_vec_named (map mode, camelCase keys) |
Binary RE of hash serializer functions at VA 0x427xxxx |
| Order fill hash shape | Flat 9-field struct with null fields | Externally-tagged enum: {"filled":{"totalSz":...}} |
Ghidra decompile of SerializerJ at VA 0x4280c90 |
| L1 hash categories | 12 categories assumed | 11 confirmed: CValidator, CSigner, Na, LiquidatedCross, LiquidatedIsolated, Settlement, NetChildVaultPositions, SpotDustConversion, BoleMarketLiquidation, BoleBackstopLiquidation, BolePartialLiquidation | Binary rodata at 0x65fb61, consecutive enum strings |
Bridge2 field baloaw |
Single combined field | Three separate fields: bal, last_pruned_deposit_block_number, oaw |
Binary serializer/deserializer helper functions for Bridge2 |
2026-04-02
| Topic | Was | Now | How discovered |
|---|---|---|---|
| Bridge signing keys | Separate EOA keys for bridge operations | Same key as consensus — bridge signing = consensus signing | Binary string trace: same signer struct used in bridge + consensus paths |
| Gossip peer verification | Assumed open connection | Server-side connection_checks: IP must be known validator/sentry |
Connection timeout analysis + binary string "not validator or sentry" |
References #
- OBS Live mainnet: peak 7,746 actions/second, 2,451 in one 70ms block.
- BIN Crate versions from path strings in rodata. Binary: 81MB ELF, build 105cb1dc.
- BIN "CertifiedTwoChainCommit" in rodata. Domain separator at VA 0x76db94.
- BIN Consensus errors at VA 0x6600fa. Field names from serde at VA 0x660467.
- BIN No capacity string. "dropping txs/blocks" confirmed. Source: mempool.rs.
- BIN Pipeline at offset 0x539f8a.
- BIN begin_block_logic_guard. 5-step order from end_block.rs.
- BIN variant index 0..90. Dispatcher at VA 0x0272a320.
- RE Testnet: RestingOrder 12 fields, Fill 21 fields, 92 action variants.
- SNAP Exchange state at h=535280000. 57 keys. 2.1M users, $3.01B.
- BIN Cancel reasons at 0x64f964, index 0..10. Rejects at adjacent offsets.
- API Fee tiers from app.hyperliquid.xyz/fees.
- API fundingHistory 3600s apart. BTC 0.0000125 in 314/500 samples.
- BIN blake3 at 0x04e03010, paddw at 0x04e05786, SHA-256 final.
- BIN 11 categories at 0x65fb61. RespHash at 0x205a300. 14 accumulators.
- BIN compute_resps_hash at 0x2355860, table at 0x3aa3f8.
- SNAP EVM sizes from lt_hashes.json: 92B accounts, 84B storage.
- BIN Wire: bswap at 0x1cc9f59, kind at 0x1cc9f5b.
- BIN MsgConcise table 0x65f418, OutMsgConcise 0x65f458. Type: RpcUpdate.
- BIN Mid table at 0x65f47c. 5 LEA: "in", "execution state", "out", "status", "round advance".
- BIN hash_concise hex loop at 0x449e0f0, 32 bytes. ValidatorSetSnapshot 2 fields at 0x42b9b80.
- RE ModifyBroadcaster no timelock. invalidateWithdrawals confirmed.
- RE impl_outcome.rs confirmed. OutcomeDeploy(8), UserOutcomeAction(4).
- BIN BolePool(19), SetBole variants, BoleAction(3). Source: bole/user_state.rs.
- BIN Testnet binary 331bef9b (2026-04-03, 87MB). 97 action variants, 9 BeginBlock steps.
- BIN Serde struct chain at .rodata 0x543428 -- complete ABCI state serialization layout.
- BIN FeeSchedule(9) and FeeTracker(10) field layouts from struct chain.
- BIN CoreWriter scan loop, ActionDelayer silent reject at capacity, DelayedActionSerde(6).
- BIN 7 new action variants: GossipPriorityBidAction, ReserveRequestWeightAction, SystemAlignedQuoteSupplyDeltaAction, DeployerSendToEvmForFrozenUserAction, SystemUsdClassTransferAction, FinalizeEvmContractAction, SubAccountSpotTransferAction.
- BIN SetGlobalAction 4th field confirmed as nativePx (HYPE price). Oracle(4) struct fields confirmed. Oracle history ring buffer (100 entries) at Exchange field [55] oh.
- RE Bridge2(10) full field layout from ABCI state. Bridge signing = consensus signing confirmed. Deposit/withdrawal flows from binary action handlers.
- BIN OutcomeTracker(11), OutcomeDeploy(8 variants), UserOutcomeAction(4 variants). Source: l1/src/exchange/impl_outcome.rs.
- BIN CStaking(23) full field layout. CValidatorProfile(6), CValidatorAction(16 variants). Staking(6) epoch lifecycle. Jailing: latency_ema_jail, VoteJailBundle.
- BIN Hash accumulator naming: AllBoleTH3, borrowLeH3, funding_H3, 1emasH. Per-clearinghouse partitioning confirmed from binary strings.
- BIN RawRateCurve kink model fields: kink_rate, kink_utilization. BOLE health factor threshold 0.8. apply_bole_liquidations in begin_block effect #3.
The Hypurrliquid Paper · lastdotnet/hyperliquid-rust · 2026-04-03
Derived from reverse engineering. Not official Hyperliquid documentation.