Hyperbook contracts — internal security review
Static analysis (Slither 0.11.6, 93 detectors) plus a manual line-by-line review of every contract Hyperbook has deployed, with each finding triaged and the rationale written down. Full Slither output: audit-slither.json. Source: hyperbook/contracts/src, Foundry suite 32 tests.
Scope
| Contract | Address | Role |
|---|---|---|
| BookAttestor | 0x18A6824728E91CD56403E83ba5CA9c730bE540fa | EIP-712 snapshot verification, signer set, freshness |
| AttestedBookOracle | 0x6fEaB85B3EC40c0EeFF307e20DC115dA1d4e6968 | IBookOracle over the attestor |
| PrecompileBookOracle | 0x6877d7289e9034B1aBd26599a820969cd6F87e11 | IBookOracle over the future native precompile |
| AnchorHook | 0x86af60F26bef5C6586889402Cf66044b6672e080 | Uniswap v4 dynamic-fee hook |
| HyperbookRouter | 0xc8b7311827e78FcD3Adb5867F76dDd4c497Fccd1 | swap / liquidity / signed swap orders |
| BookPerp | 0x443561b059C0a46C071E812039a4a3D935cba22E | USDC perps, LP vault, signed open/close orders |
| Buyback | 0x7a70EDf7cB5E13304072F4da391AD862BA741615 | protocol revenue → token → 0xdead |
| Create2Deployer | 0x919541805A57B4ef4d350425789fAb6F23dAABfa | hook address mining |
Slither summary
| Impact | Raw count | After triage |
|---|---|---|
| High | 7 | 0 exploitable — all are v4 flash-accounting callback patterns (see F-1, F-2) |
| Medium | 35 | 0 exploitable — rounding-order, zero-checks, default-initialised locals, ignored settle() returns |
| Low | 53 | timestamp comparisons (intended: freshness windows), naming, shadowing in libs |
| Info | 23 | assembly in quote decoding, solc version pins |
Findings
F-1 · Slither High arbitrary from in transferFrom — HyperbookRouter._pay
Report: safeTransferFrom(from, poolManager, amount) with a caller-supplied from.
Analysis: from is always msg.sender of the external entry point (swapExactIn, addLiquidity) or order.owner whose EIP-712 signature over amount, minOut, deadline and nonce was just verified (swapExactInFor). unlockCallback rejects any caller except the PoolManager, and the PoolManager only invokes the callback of the account that called unlock, so no third party can inject a payload naming someone else's funds. A user who approves the router can only have tokens pulled by their own transaction or their own signature.
Status: false positive, covered by test_relayed_swap_bad_sig_and_tamper.
F-2 · Slither High balance read before external call — Buyback.unlockCallback
Report: whype.balanceOf(this) is read, then swap/settle/take are called.
Analysis: The callback is only reachable from execute(), which is nonReentrant and keeper-only; the callback itself rejects any caller but the PoolManager. The balance is used once to size the swap and the contract intends to spend its whole balance; a stale read can only under-spend, never over-spend. Sandwiching is bounded by minTokenOut.
Status: accepted / not exploitable.
F-3 · Slither Medium divide-before-multiply — BookPerp pricing
Notional is computed as margin × leverage / 10 and then multiplied again for fee and size. Loss is ≤ 1 unit of 1e-8 USD per operation. Fees and PnL are computed in the trader's disfavour by at most that dust. Status: accepted.
F-4 · Slither Medium strict equality, uninitialised locals, unused returns
All instances are x == 0 guards, locals that intentionally default to zero, or ignored return values of PoolManager.settle() / getSlot0() fields that are not needed. Status: accepted.
F-5 · Manual · Low Router reports post-swap hook fee
quoteExactIn asks the hook for its fee after the simulated swap, so on an empty pool the reported lpFee is wrong (the fee actually charged in beforeSwap is correct). Cosmetic: affects only the returned number, not funds. Status: mitigated — the API quotes the fee pre-swap via AnchorHook.quote; will be fixed in the next router version.
F-6 · Manual · Low Bad debt is socialised to the vault
If a position's loss exceeds its margin (gap move inside the 3 s freshness window), BookPerp records badDebt and the vault absorbs it. There is no insurance fund yet. Mitigations: per-market OI caps, 80 % utilisation cap, maintenance margin 5 %, leverage ≤ 10× on HYPE, permissionless liquidation with bounty. Status: disclosed; the Vault page states this.
Trust assumptions (not bugs, but you should know them)
T-1 · Snapshot signers
Every price Hyperbook contracts act on comes from a 2-of-2 signer set operated by the Hyperbook team, verified by BookAttestor with a 3 s freshness bound. Compromise of both keys would allow feeding false prices to the perp and the hook until the keys are rotated. The signer set and threshold are on-chain and visible on the Data page. This dependency disappears when Elysium ships the native HyperCore precompile (PrecompileBookOracle is already deployed for that switch).
T-2 · Owner keys
| Contract | Owner can | Owner cannot |
|---|---|---|
| BookPerp | add markets, pause opens, change leverage/OI caps, change oracle, change treasury | touch user margin or LP deposits, block closes or liquidations, mint shares |
| AnchorHook | configure fee parameters per pool, change oracle | move LP funds, set fee above the configured cap |
| BookAttestor | rotate signers, change freshness | forge a snapshot without the keys |
| Buyback | set target token once, sweep until lock() | anything after lock() |
| HyperbookRouter | — (no owner) | — |
Owner is currently the deployer EOA. Planned: move to a multisig with a timelock before TVL is material.
T-3 · Relayer and keeper
The relayer submits user-signed orders; it cannot change amount, limit price, deadline or nonce, and users can always bypass it by calling the contracts directly. The liquidation keeper is permissionless: anyone may run one and earn the bounty.
Test coverage
Foundry, 32 tests: attestor signature/threshold/freshness; hook fee model (baseline, arb direction, blind, cap); router add/swap/remove with fee accrual, slippage, ownership; relayed swap (nonce replay, tampering, expiry); perp open/close profit and loss, liquidation and bounty, funding, OI release; relayed open/close with limit prices; buyback full path USDC → WHYPE → native pool → burn, keeper gating, slippage, lock semantics.
Changelog
- 2026-11-11 · v2 review: added HyperbookRouter, BookPerp (USDC), Buyback. F-5 mitigated in API.
Questions or responsible disclosure: open an issue or contact the team via the X account linked on the site.