Hyperliquid Support¶
Hyperliquid is the first perpetual-futures order-book venue supported by the Almanak SDK. The same intent-based workflow applies — decide() → Intent → compile → execute — but the execution substrate is unlike any EVM DEX: orders are placed on an off-EVM L1 order book (HyperCore) through a system contract on Hyperliquid's EVM layer (HyperEVM), and they settle asynchronously. Understanding that split is the key to using — and accounting for — the connector correctly.
Supported intents: PERP_OPEN and PERP_CLOSE on chain hyperevm (chain id 999).
The three layers (read this first)¶
Hyperliquid is not one chain. Value and execution live across three distinct layers, and each is visible on a different explorer. Confusing them is the single most common source of "where are my funds?" questions.
| Layer | What lives here | How you interact | Explorer |
|---|---|---|---|
| Arbitrum | The entry/exit door for USDC. The canonical Bridge2 deposit contract (0x2Df1c51E…163dF7) lives here. |
Send native Circle USDC to Bridge2 to deposit; withdrawals arrive here. | arbiscan.io |
| HyperCore (off-EVM L1) | Your USDC margin and your perp positions. The order book, the matching engine, funding, liquidations. | Not a smart contract — an L1 clearinghouse. Read via precompiles or the API. | HL app / API only — no EVM explorer |
HyperEVM (chain 999) |
The general-purpose EVM layer. The CoreWriter system contract (0x3333…3333) and read precompiles. Native gas token HYPE. |
Your strategy sends sendRawAction here to place orders; reads hit the precompiles. |
hyperevmscan.io |
The practical consequences you must internalize:
- Your USDC margin is NOT on HyperEVM. It never appears on
hyperevmscan. It was deposited from Arbitrum into HyperCore, and it lives in HyperCore.hyperevmscanfor your wallet shows onlysendRawActioncalls (your orders) and HYPE (gas). - Your ETH long is NOT an ERC-20. There is no token to
balanceOf. A perp position is a clearinghouse entry in HyperCore, read via a precompile. - A successful HyperEVM transaction is a submission, not a fill. Settlement happens later on HyperCore (see Execution model).
Hyperliquid vs a standard EVM DEX — what's different¶
| Aspect | EVM DEX (Uniswap, GMX, …) | Hyperliquid |
|---|---|---|
| Instrument | Spot token / on-chain perp position | Off-EVM perpetual, USDC-margined |
| Order placement | A contract call that executes atomically in the tx | CoreWriter.sendRawAction(bytes) — queues an order for HyperCore |
| Settlement | Synchronous — the tx succeeds ⇒ the trade happened | Asynchronous — the tx queues the order; HyperCore fills it ~1–2 s later |
| Position representation | ERC-20 balance / NFT / on-chain struct | HyperCore clearinghouse entry (no token) |
| Reading position | balanceOf / contract view |
Read precompile 0x0800 (eth_call) or the HL API |
| Price oracle | Chainlink / Pyth contracts | HyperCore oracle precompile 0x0807 (0x0806 for mark) |
| Order types | Market / limit, per-DEX | Market synthesized as an aggressive IOC limit crossing the book (see below) |
| Collateral | Deposited into the DEX contract | USDC bridged from Arbitrum into the HyperCore account |
| Fill economics in the receipt | Yes (logs) | No — the EVM receipt has no fill price/size/PnL; those live on HyperCore |
Supported intents & strategies¶
| Intent | What it does | Notes |
|---|---|---|
PERP_OPEN |
Open (or add to) a perp long/short | Market IOC, oracle-anchored, fail-closed |
PERP_CLOSE |
Reduce/close a perp | Reduce-only IOC; sized from the on-chain position |
There are no resting-limit / stop / take-profit order types in the intent vocabulary today — every perp intent is market-style (immediate IOC with a slippage bound). Strategy-side stops/targets are implemented by evaluating state each tick and emitting a market close (see the trailing-stop demo). leverage on an intent is recorded and surfaced as a warning, never faked: CoreWriter has no set-leverage action, so the position uses the account's current leverage setting.
Two reference strategies ship with the connector:
hyperliquid_trailing_perp(demo) — a single-direction perp with a ratcheting trailing stop: take-profit caps the upside, a hard stop is the liquidation buffer, and once the trade is up by an activation threshold a trailing stop ratchets behind the high-water PnL. Exits are evaluated strategy-side and fired as market reduce-only closes; it re-enters after each close.strategies/accounting/perp_hyperliquid(accounting fixture) — a USDC-margined ETH/USD round-trip (open → hold → teardown close) used to score the Accountant Test.
Execution model: CoreWriter¶
A perp order is placed by encoding a HyperCore action and submitting it to the CoreWriter system contract:
Intent (PERP_OPEN, ETH/USD, $15, long)
→ compiler reads the HyperCore oracle price (precompile 0x0807) ← fail-closed if unavailable
→ builds an aggressive IOC limit at oracle ± slippage
→ encode_limit_order_action(...) → sendRawAction(bytes) calldata
→ one tx to CoreWriter 0x3333…3333 (selector 0x17938e13)
→ tx status 1 + one RawAction log ← SUBMISSION accepted
→ HyperCore settles ~1–2 s later ← the actual FILL
Key properties:
- Market = aggressive IOC limit. HyperCore has no "market order" primitive; every order is a limit order with a time-in-force. A market order is synthesized as an IOC limit priced at
oracle ± slippage, so it crosses the book immediately or cancels the remainder. - Fail-closed anchoring. If the oracle precompile read is unavailable, compilation fails rather than sending an unanchored order.
- Reduce-only closes.
PERP_CLOSEreads the live position (precompile0x0800), derives the direction from the on-chain sign, and submits a reduce-only order sized to the position — it can only shrink, never flip.
Verifying execution: submission ≠ fill¶
Because settlement is asynchronous, a green HyperEVM transaction does not prove your order filled. An IOC order can partially fill or be rejected (insufficient margin, sub-$10 order value, no liquidity) while sendRawAction still returns status 1. The EVM receipt carries no fill information.
You confirm execution by reading HyperCore state, not the receipt — two independent ways:
- Trustless, on-chain — position precompile
0x0800.eth_callit and decode(szi, entryNtl, isolatedRawUsd, leverage, isIsolated). Ifszimatches the size you submitted, the order filled and the position is yours. This is what the SDK'sperps_read.pydoes every portfolio snapshot. - Independent API —
api.hyperliquid.xyzclearinghouseState. Same position + margin + entry + unrealized PnL in human units; cross-check it against the precompile.
The rule of thumb: a sendRawAction is a "sent," not a "done." "Done" is a position read that matches what you sent. The connector productizes this as a settlement observer: the position "appears" in the portfolio only once HyperCore has filled it and the precompile read reflects it — the same async pattern GMX V2 uses for keeper-settled fills.
Accounting¶
Accounting on Hyperliquid draws from two surfaces with very different granularity and trust properties.
A. Precompiles — trustless on-chain state (point-in-time)¶
| Read | Precompile | Granularity |
|---|---|---|
| Position (size, entry notional, margin, leverage, isolated flag) | 0x0800 |
current, per-market |
| Account margin summary | 0x080F |
current account |
| Mark / oracle / spot price | 0x0806 / 0x0807 / 0x0808 |
current, per-asset |
Precompiles give you current balances and position state, provable on-chain. They do not provide order lifecycle or fill history.
B. The HyperCore API — full order/fill lifecycle (authoritative, not on-chain)¶
| Read | API type | Granularity |
|---|---|---|
| Order status: submitted → resting → filled / partial / cancelled / rejected | orderStatus (by oid/cloid) |
per order |
| Fills — price, size, side, fee, closedPnl, time, order id | userFills |
per fill (finest) |
| Open/resting orders | openOrders |
per order |
| Funding paid/received | userFunding |
per funding event |
| Deposits / withdrawals / transfers / liquidations | userNonFundingLedgerUpdates |
per ledger event |
Our CoreWriter orders carry a deterministic client-order-id (cloid) derived from the intent id, so orderStatus-by-cloid can positively confirm fill vs reject for a specific submission.
What the SDK reads today¶
perps_read.py reads the position precompile — the trustless state layer: position size, entry notional, margin, and unrealized PnL (from the mark price). Confirmed against live mainnet: szi = ×10^szDecimals, entryNtl = 1e6 USD.
The fill-level layer (per-fill fees + realized PnL via userFills, funding via userFunding, and orderStatus-by-cloid to close the submission-vs-fill gap) is API-sourced and flows through the gateway; wiring it is ongoing work. Until it lands, position-lifecycle events and per-fill economics are not recorded, so the full 21-cell Accountant Test for the Hyperliquid perp is not yet scored — the connector's execution and position-read paths are validated on live mainnet, but the fill-economics accounting is pending.
Funding a wallet¶
USDC margin lives on HyperCore and is reached through Arbitrum, not HyperEVM:
- Get native Circle USDC (
0xaf88…5831) onto your wallet on Arbitrum (USDC.e is rejected). - Transfer that USDC to Bridge2
0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7on Arbitrum. A plain transfer credits the sender's HyperCore perp account in under a minute. Minimum$5. - Fund HYPE for gas on chain
999(CoreWriter txs are cheap — ~50k gas).
Note the $10 minimum order value applies to spot as well as perps (only reduce-only closes are exempt). Withdrawal is the reverse: HyperCore → Arbitrum via the bridge (a small fixed fee), then Arbitrum → your destination.
Safe / Zodiac permissions¶
For Safe-wallet execution, the connector authorizes exactly one target: CoreWriter sendRawAction, scoped to PERP_OPEN/PERP_CLOSE, with native-value send disallowed (margin is off-EVM, gas is native HYPE, tx value is 0). No ERC-20 approvals are needed. The selector is derived from the signature — not a hand-typed literal — so the authorized selector cannot drift from the calldata the compiler emits.
Running strategies¶
# Live on mainnet (gateway auto-starts); continuous, torn down by a separate signal
uv run almanak strat run -d almanak/demo_strategies/hyperliquid_trailing_perp --network mainnet --dashboard
# Dry run — build the snapshot and run decide(), compile the intent, but do NOT submit
uv run almanak strat run -d almanak/demo_strategies/hyperliquid_trailing_perp --network mainnet --dry-run --once
# Teardown (separate signal; resolve the deployment_id from the boot log / strategy DB)
uv run almanak strat teardown request -d almanak/demo_strategies/hyperliquid_trailing_perp -s deployment:<hash> -f
Hyperliquid cannot be tested on a managed Anvil fork — the HyperCore precompiles only exist on the live node, and orders fill off the EVM. Validation is done on live mainnet (small size) or via --dry-run against live chain-999 data.
Production considerations¶
Data layer¶
The gateway serves hyperevm price by reading the HyperCore oracle precompile (0x0807) — there is no Chainlink on HyperEVM, and perp majors have no ERC-20 to price by address. USDC/USDT0/WHYPE are statically registered so balance/price resolution is instant; other symbols on hyperevm resolve static-only (a perp index like "ETH" is not an ERC-20 balance and fails fast rather than doing on-chain discovery).
Known limitations¶
- Async settlement. A submitted order is not a confirmed fill — reconcile against the position read (above). Strategy state should be driven by the observed position, not by submission success.
- No native limit/stop/TP orders. The intent vocabulary is market-IOC only; strategy-side logic emits market closes for stops/targets.
- Fill-economics accounting is pending. Per-fill fees, realized PnL, funding, and
orderStatus-by-cloid are API-sourced and not yet wired; the 21-cell Accountant Test for the perp is not yet scored. - Cross-margin valuation. Cross-margin positions carry no per-position collateral (margin is shared at the account level); until the account-margin-summary read (
0x080F) is wired into valuation, a cross-margin position's net value is PnL-only. - Isolated-margin scale.
isolatedRawUsdis assumed1e6USD; confirm against a live isolated position before trusting isolated-margin net value.
Next steps¶
- Read Supported Chains for the
hyperevmchain descriptor. - See
almanak/connectors/hyperliquid/for the connector implementation andalmanak/demo_strategies/hyperliquid_trailing_perp/for the reference strategy. - The connector API reference is auto-generated at Connectors → Hyperliquid.