HyperLiquidBench is a reproducible benchmark for measuring the operational competence of Hyperliquid trading agents. It leans on the same “declare metrics → execute → evaluate” philosophy used in SolanaBench: prove an agent can route venue actions correctly, not just print PnL. The toolchain is Rust-first, ships deterministic datasets, and records every effect so results are auditable.
- Product Deck: https://drive.google.com/file/d/1tnQpgina5jGGIV9QXQrfPQ96FWUwsiz6/view?usp=sharing
- Demo Frontend: https://hyperliquid-bench.vercel.app/
- YouTube Link: https://youtu.be/m8pSPQIDdxQ
-
Don’t trust, verify. Agents must show evidence of correct order routing, cancels, transfers, and leverage changes. Each step is logged with the submission payload, HTTP acknowledgement, and websocket confirmation.
-
Scoring favours breadth and discipline. The evaluator converts effects into normalized signatures. A weighted Base score rewards unique signatures across domains (perp, account, risk). A Bonus rewards composing multiple distinct actions within a short nonce window (default 200 ms). A Penalty highlights spam beyond the configured per‑signature cap. Final score:
FINAL_SCORE = Base + Bonus − Penalty -
Coverage + accuracy tracks. The coverage track judges overall operational surface area. The HiaN (Haystack‑in‑a‑Needle) track verifies long-context precision: from a noisy prompt, execute the exact instructed actions and nothing else.
-
Builder Codes are first‑class. Every run can tag orders with a builder code so teams can credit routed flow. Orders are also written to
orders_routed.csvfor auditing.
For the detailed hackathon rationale, see docs/TECHSPEC_MASTER.md. Coverage,
evaluator, and HiaN implementation plans live under docs/PLAN_*.
| Path | Description |
|---|---|
crates/hl-common |
Shared plan schema, action/price types, time utilities, and artifact helpers used by both CLIs. |
crates/hl-runner |
Tokio CLI that loads plans, signs requests with the Hyperliquid Rust SDK, submits actions, listens to websocket channels, and writes run artifacts (per_action.jsonl, ws_stream.jsonl, orders_routed.csv, etc.). |
crates/hl-evaluator |
CLI scorer: normalizes actions into signatures, applies domain weights and windowed bonus, emits score reports (coverage) and will host the HiaN validator. |
dataset/ |
Authoritative scoring config (domains-hl.yaml), curated coverage tasks (tasks/*.jsonl), and HiaN case bundles (hian/*). |
frontend/ |
Static leaderboard + trajectory explorer that consumes evaluator outputs for public sharing. |
scripts/ |
Convenience wrappers (run_cov.sh, run_hian.sh, ws_dump.sh). |
docs/ |
Detailed plans, TODOs, and technical specification backing every subsystem. |
- Rust toolchain (1.74 or newer recommended).
- Access to a Hyperliquid key (testnet, mainnet, or local). The runner signs requests via an Ethereum private key.
- System dependencies required by
hyperliquid_rust_sdk(OpenSSL/clang on macOS,libssl-devon Linux). - Optional: Tailwind-compatible static host if you plan to serve the frontend.
- Clone and fetch dependencies
git clone https://github.com/sigridjineth/hyperliquidbench.git cd hyperliquidbench cargo fetch - Export required secrets (or place them in a
.envfile; both CLIs load environment variables viadotenvy).export HL_PRIVATE_KEY=0xabc... # required for signing export CEREBRAS_API_KEY=csk-... # required for gpt-oss-120b plan generation export HL_BUILDER_CODE=mybuilder # optional revenue share tag export HL_API_URL=https://api.hyperliquid.com # optional override export HL_WS_URL=wss://api.hyperliquid.com/ws # optional override
- Configure build tooling
Note:
make format # runs cargo fmt make check # runs cargo clippy --deny warnings cargo build cargo test # optional
hl-evaluatordefaults to coverage mode; passhianas the first argument to run the long-context validator.
- Plans live in
dataset/tasks/*.jsonl. Each line is a full plan matchinghl_common::plan::Plan. For example, the first scenario indataset/tasks/hl_perp_basic_01.jsonlplaces two ETH perp orders (ALO and GTC) and cancels the last. - Authoring tips:
- Use the JSON schema documented in
docs/PLAN_3_1.md. - Prices can be absolute or mid±X% (
"mid-0.5%"). The runner resolvesmidper coin using the info client. - Insert
sleep_mssteps to control composition windows if you need to avoid coalescing actions into a single 200 ms bucket.
- Use the JSON schema documented in
Use this to validate the full pipeline or populate the frontend without touching live endpoints. The runner synthesizes acknowledgements and websocket effects while preserving the artifact schema expected by the evaluator and UI.
cargo run -p hl-runner --release -- \
--demo \
--plan dataset/tasks/hl_perp_basic_01.jsonl:1 \
--out runs/demo
cargo run -p hl-evaluator --release -- \
--input runs/demo/per_action.jsonl \
--domains dataset/domains-hl.yaml \
--out-dir runs/demoArtifacts match the live format but run_meta.json includes "demoMode": true and synthetic websocket frames include "demo": true so you can flag mock data downstream.
You can still exercise the LLM pipeline in demo mode. That lets you validate prompts, caching, and plan decoding without hitting the exchange.
- Set credentials (Cerebras is the benchmark default for gpt-oss-120b; OpenRouter remains usable if you explicitly select it):
export CEREBRAS_API_KEY=csk-... export BENCHMARK_MODEL_PROVIDER=cerebras export BENCHMARK_MODEL_NAME=gpt-oss-120b export HL_LLM_DRYRUN=1 # skip on-venue execution entirely
- Generate a coverage plan via LLM:
The runner writes
cargo run -p hl-runner -- \ --plan llm:coverage \ --demo \ --llm-max-steps 3 \ --llm-allowed-coins BTC,ETH \ --llm-builder-code demo-builder
plan.jsonandplan_raw.txtusing the LLM response, but no network calls are made because both--demoandHL_LLM_DRYRUN=1are active. - Inspect and (optionally) score:
RUN_DIR=$(ls -dt runs/* | head -n1) cargo run -p hl-evaluator -- \ --input "$RUN_DIR/per_action.jsonl" \ --domains dataset/domains-hl.yaml \ --out-dir "$RUN_DIR"
run_meta.json records the LLM metadata (model, temperature, prompt_hash, cache hits) alongside the standard demo flags, giving you a reproducible artifact for each prompt test.
For release-comparable Eliza/Hermes/OpenClaw rows, use the orchestrator so all
three harnesses share the same gpt-oss-120b request shape and latest snapshot
contract:
HL_PRIVATE_KEY=0x... \
CEREBRAS_API_KEY=csk-... \
VISION_LANGUAGE_PROVIDER=local-eliza \
VISION_LANGUAGE_MODEL=eliza-1-9b \
VISION_LANGUAGE_TIER=eliza-1-9b \
PYTHONPATH=. \
python -m benchmarks.orchestrator run \
--benchmarks hyperliquid_bench \
--all-harnesses \
--provider cerebras \
--model gpt-oss-120b \
--force \
--show-incompatibleThe normalized orchestrator path passes --no-demo; demo-mode Hyperliquid
artifacts are intentionally rejected by the publishability gate.
Only live (--no-demo) rows are publishable. Demo-mode output is intentionally
unpublishable — validate-latest-publishability rejects any row carrying
demo/sample markers — so a real Hyperliquid signing key is the one hard
requirement for a release-comparable run. The orchestrator enforces this with a
runtime gate: _has_hyperliquid_live_backend() returns true iff HL_PRIVATE_KEY
is set, and validate-runtime-gates fails (non-zero) for hyperliquid_bench
when the key is absent.
Run live execution on testnet first. Testnet keys are ephemeral and trade play funds, so a leaked or burned key costs nothing real; mainnet keys sign trades that move real funds.
- Open the Hyperliquid testnet UI: https://app.hyperliquid-testnet.xyz.
- Connect a fresh wallet (use a dedicated throwaway, never a personal mainnet wallet) and fund it from the testnet faucet.
- Export the wallet's Ethereum private key (
0x…). The runner signs requests with this key via the Hyperliquid Rust SDK.
Keep mainnet and testnet keys separate. --network testnet (the default for
live runs here) maps to the Hyperliquid testnet base URLs; --network mainnet
trades real funds.
# 1. Build the Rust execution crates once (required for live runs).
cd packages/benchmarks/HyperliquidBench
cargo build --release -p hl-runner -p hl-evaluator
cd -
# 2. Export the signing key (testnet) and the plan-generation provider key.
export HL_PRIVATE_KEY=0x... # testnet wallet private key
export CEREBRAS_API_KEY=csk-... # gpt-oss-120b plan generation
# 3. Run the live harnesses (eliza, hermes, openclaw) with --no-demo,
# invoked from the repo root with PYTHONPATH=packages.
PYTHONPATH=packages python -m benchmarks.orchestrator run \
--benchmarks hyperliquid_bench \
--all-harnesses \
--provider cerebras \
--model gpt-oss-120b \
--extra '{"no_demo": true, "network": "testnet"}' \
--force \
--show-incompatible
# 4. Confirm the stored rows are publishable (rejects any demo row).
PYTHONPATH=packages python -m benchmarks.orchestrator validate-latest-publishability \
--include-benchmarks hyperliquid_bench--extra '{"no_demo": true}' is what flips the run to live execution; the
--demo default (used whenever HL_PRIVATE_KEY is unset) produces rows the
publishability gate discards.
The .github/workflows/hyperliquid-bench-live.yml
workflow runs exactly this pipeline (validate gates → live --no-demo run →
publishability check) on manual dispatch.
- Operator: add
HL_PRIVATE_KEY(andCEREBRAS_API_KEYfor plan generation) as GitHub repo secrets. - Dispatch the HyperliquidBench (live) workflow (Actions tab → Run
workflow), choosing
network(defaulttestnet).
With no HL_PRIVATE_KEY secret configured the workflow skips gracefully
(emits a notice and exits 0) — it never fails CI when the key is unset. It is
manual-dispatch only by design: live trading must be an explicit operator
decision, never a scheduled run.
cargo run -p hl-runner -- \
--plan dataset/tasks/hl_perp_basic_01.jsonl:1 \
--network testnet \
--builder-code "$HL_BUILDER_CODE"- The
:<N>suffix selects a specific JSONL line (1-based). You can point to a plain JSON plan without the suffix. --networkacceptstestnet,mainnet, orlocaland maps to Hyperliquid base URLs.- Useful environment overrides:
OUT_DIR– force the output directory (defaults toruns/<timestamp>).HL_EFFECT_TIMEOUT_MS– overrides--effect-timeout-msused when waiting for websocket confirmations.
- Artifacts written (see
docs/PLAN_3_1.md):per_action.jsonl– per step: request, ack, observed events, notes, window key.ws_stream.jsonl– raw websocket frames (order updates, fills, ledger updates).orders_routed.csv– timestamped orders with builder code attribution.run_meta.json– metadata (network, wallet, builder code, effect timeout).plan.json/plan_raw.txt– executed plan (pretty + raw).
scripts/run_cov.sh wraps the two-step process (runner + evaluator) and accepts the same options. For demo runs omit NETWORK (or set it to demo) and forward --demo after the -- separator:
OUT_DIR=runs/demo scripts/run_cov.sh dataset/tasks/hl_cancel_sweep_01.jsonl:1 -- \
--demo --builder-code "demo-builder"
OUT_DIR=runs/testnet NETWORK=testnet \
scripts/run_cov.sh dataset/tasks/hl_cancel_sweep_01.jsonl:1 -- \
--builder-code "$HL_BUILDER_CODE"RUN_DIR=$(ls -dt runs/* | head -n1)
cargo run -p hl-evaluator -- \
--input "$RUN_DIR/per_action.jsonl" \
--domains dataset/domains-hl.yaml \
--out-dir "$RUN_DIR"Outputs:
eval_per_action.jsonl– normalized per-step summaries listing signatures, ignored/no-op flags, reasons, and window keys.eval_score.json– detailed score report: base/bonus/penalty, final score, per-domain contributions, signature counts, unmapped signatures.unique_signatures.json– sorted list of unique signatures observed (useful for knowledge distillation and frontend displays).- Additional diagnostics (if enabled) appear on stdout (warnings for overlapping domains, missing matches, etc.).
For convenience, the evaluator CLI also supports positional arguments identical
to scripts/run_cov.sh. See docs/PLAN_3_2.md for the full argument list.
Each confirmed action produces one or more signatures:
perp.order.{TIF}:{reduceOnly}:{trigger}(e.g.,perp.order.GTC:false:none).perp.cancel.{scope}(last,oids,all).account.usdClassTransfer.{direction}(toPerp,fromPerp).risk.setLeverage.{coin}(e.g.,risk.setLeverage.ETH).
Only steps with ack.status == "ok" and non-error statuses generate signatures.
Rejected steps become ignored: true. Multiple orders in a single step produce
a signature per accepted order.
version: "0.1"
per_action_window_ms: 200
per_signature_cap: 3
domains:
perp:
weight: 1.0
allow:
- "perp.order.*"
- "perp.cancel.*"
account:
weight: 1.0
allow:
- "account.usdClassTransfer.*"
risk:
weight: 1.0
allow:
- "risk.setLeverage.*"- Patterns use dot-separated segments with
*as a single-segment wildcard. per_action_window_mscontrols the window size for composition bonus.per_signature_capdefines how many times a single signature can contribute to Base before penalties apply.- Treat updates to this file as scoring-version changes.
- Base: For each domain, count unique signatures that match the domain’s allowlist. Multiply by the domain weight. Sum across domains.
- Bonus: Group signatures by
window_key_ms(provided by the runner as floor(submit_ts_ms/window). For each bucket, add0.25 × max(0, distinct-1). This rewards distinct effects within the same nonce window (composition). - Penalty: For every occurrence of a signature beyond the cap, add
0.1to penalty. No-op steps (failed acknowledgements) neither add to Base nor incur penalties.
Refer to docs/PLAN_3_2.md §2–§4 for worked examples and the scoring rationale.
hl_perp_basic_01.jsonl– place two ETH orders (ALO + GTC) and cancel last.hl_cancel_sweep_01.jsonl– rest an ETH order, wait 150 ms, cancel all.hl_risk_and_account_01.jsonl– transfer USDC to perp, set leverage, place IOC reduce-only order.
Each file is documented in dataset/tasks/README.md. Append :<line> when
referencing them from the runner. Extend the directory with your own deterministic
scenarios to grow coverage.
case_128k/prompt.txt– compact noisy-context seed containing a single needle instruction: transfer 7.5 USDC to perps, place an ALO bid mid−1% on ETH.case_128k/ground_truth.json– required ordered effects for PASS.case_128k/meta.json– metadata (case ID, token estimate, prompt hash).
The HiaN CLI parses these files, matches effects, and emits eval_hian.json
plus diffs. You can scale prompts to the desired token count and update
metadata accordingly.
- Keep datasets under git for deterministic scoring. When prompts exceed version
control limits, store the SHA256 in
meta.jsonand host the blob externally. - Bumping signature grammar or domain rules requires a new
versionfield indomains-hl.yamland communication to users (seedocs/PLAN_4.md§4.7).
The static frontend under frontend/ reads two data sources:
frontend/data/models.json– leaderboard entries (agent name, rank, scores, domain breakdown, artifact paths).frontend/data/samples/<run>/– evaluator outputs (per_action.jsonl,eval_score.json,unique_signatures.json, etc.).
Entry points:
index.html– overview with leaderboard and charts (Chart.js via CDN).trajectories.html– action log explorer; upload a run directory or pick a hosted sample to inspect per-step signatures and raw details.lc.html– domain breakdown table with links to policies and signature manifests.
Serve locally:
cd frontend
python -m http.server 8000Deploy to any static host (Vercel, Cloudflare Pages, GitHub Pages). Update the
JSON under frontend/data/ whenever you publish new runs.
- Specify
--builder-code <CODE>(orHL_BUILDER_CODE) when running coverage. - When supported by the Hyperliquid SDK, orders posted through
hl-runnerwill attribute flow to this code. The evaluator doesn’t read the builder code but it is stored inorders_routed.csvfor downstream analytics. - The CSV schema (
ts, oid, coin, side, px, sz, tif, reduceOnly, builderCode) is designed for ingestion into dashboards or revenue sharing reports.
- No websocket confirmation: The runner records missing confirmations in the
notesfield ofper_action.jsonl. Increase--effect-timeout-msif your environment has higher latency. - Signature unmatched: The evaluator warns if a signature doesn’t match any
domain (it lands in
unmapped_signatures.json). Updatedomains-hl.yamlcarefully and bumpversionfor scoring changes. - Penalty spikes: Check
per_signature_countsinsideeval_score.jsonto see which signatures exceeded the cap. Adjust plans or caps as needed. - HiaN development:
scripts/run_hian.shruns a local demo plan and invokeshl-evaluator hian, writingeval_hian.jsonand a diff on failure. - CI integration: Use
scripts/run_cov.shin GitHub Actions to guard lagoon runs. Persist theruns/<ts>/directory as an artifact for inspection.
docs/TECHSPEC_MASTER.md– track alignment, prize narrative, and architecture.docs/PLAN_3_1.md– runner action requirements and artifact contracts.docs/PLAN_3_2.md– evaluator normalization and scoring rules.docs/PLAN_3_3.md– HiaN validator design and acceptance notes.docs/PLAN_4.md– domains, dataset layout, acceptance tests, and versioning.docs/TODO_PLAN_MASTER.md– high-level success checklist for the hackathon.
HyperLiquidBench is designed so other teams can adopt the same dataset, scoring config, and tooling. Contributions should keep the reproducibility guarantees intact and document any scoring changes clearly.


