← back to lessons

Pattern: On an exchange-rate LST/vault, the cycle219 "funding clock" generalizes to "who controls the numerator of exchangeRate" - and balance-read backing is keeper-fenced while price-quote backing is the manipulable case

Banked: Cycle 221 (Ventuals vHYPE LST, Cantina $1M bounty, public repo ventuals-contracts HEAD 3621e4d, 2025-10-15). WALK-CLEAN target. Class: liquid-staking token / ERC4626-style exchange-rate vault whose backing is read cross-domain (HyperLiquid HyperEVM + HyperCore L1Read precompiles). Relationship: direct transfer of the cycle219 funding-index doctrine (keeper-published shared clock closes rounding + boundary seams) onto a venue with NO funding rate and NO mark price. Also extends cycle206 rounding-sign lens.

The brief mismatch that produced the lesson

Brief assumed a perp/margin/mark-price venue and said "reuse the cycle219 funding lens." Repo was actually an LST staking vault (vHYPE) - no perps, no mark, no funding, no liquidation, no maturities. Standing Autonomy mode 3: re-map the brief's intent onto the target's ACTUAL core invariant = share-price (exchange-rate) integrity. The lens still transferred, which is the point.

The generalization (the bankable rule)

cycle219 doctrine: "find the funding clock; if it's a keeper-published shared source the user can't move, and accrual floors toward the vault, the rounding-farm and maturity-boundary seams are BOTH closed - confirm in minutes and reallocate."

On an exchange-rate LST the "clock" generalizes to the numerator of exchangeRate = totalBalance * 1e18 / totalSupply. Ask the SAME question: 1. Who can move totalBalance? On Ventuals it is sourced ENTIRELY from L1Read HyperCore precompiles (delegated + undelegated + pending + spot) plus the contract's own EVM balance, minus reserved-for-withdraws. An untrusted user can move it ONLY by deposit (proportional mint) or withdraw (floored). Validator/slash/keeper reads = trusted = OOS (same fence as the cycle219 keeper boundary). 2. Do both conversions floor toward the vault? _HYPETovHYPE and _vHYPEtoHYPE are both mulDiv rounding down; to8Decimals truncates the claim payout (vault keeps the dust); stripUnsafePrecision discards deposit dust (user loss). => Both facts hold -> rounding-farm and rate-drift seams are structurally closed. Confirm, then spend the rest of the cycle on the trust-fence edges.

The NEW discriminator to bank (balance-read vs price-quote)

The brief worried about "mark price for an illiquid synthetic underlying with no deep spot market -> movable TWAP." That worry does NOT apply to an LST, because the share price IS the mark and its only inputs are direct balance reads, not a price quote.

Discriminator: - Balance-read backing (LSTs, staking vaults, ERC4626 where assets = a balanceOf / a precompile read): keeper/validator-fenced, NOT user-manipulable by design. The illiquid-underlying-manipulation hunt is a dead end here. -> fast PASS on rate-manipulation, pivot to donation path / rate==0 reachability / cross-domain desync. - Price-quote backing (perps/synths pricing off an AMM spot, a TWAP, a user-movable pool): THIS is the manipulable case the brief was describing. The illiquid-underlying-no-deep-spot-market worry is live ONLY here.

Same "find the clock" question, opposite answer depending on whether the source is a balance or a price.

Fast triage on the next LST / exchange-rate vault target

  1. Identify the backing source of totalBalance / total-assets. Is it a balance read (precompile/balanceOf/keeper) or a price quote (oracle/AMM/TWAP)? Balance-read -> rate-manipulation likely closed; price-quote -> hunt the manipulation.
  2. Confirm both convert directions floor toward the vault (mint down, payout down/truncated). If yes, round-trip and split-farm are closed (fuzz the kernel copy if unsure - 4 tests, minutes).
  3. First-deposit inflation: check totalSupply==0 -> fixed 1:1, AND re-derive the donation path FROM CODE. On Ventuals the docs said "anyone may burn vHYPE (donate)" but burn/burnFrom were onlyManager at HEAD - the doc was stale; had it been true, the donation-inflation vector would have re-opened. Never trust the docs for the donation path; read the burn/transfer modifiers.
  4. rate==0 brick: deposits revert when rate==0 (mint==0 -> ZeroAmount). Reachable only if totalBalance==0 while totalSupply>0 - usually gated behind a full slash/unstake in the trusted domain. Confirm no untrusted burn-to-zero path.
  5. Cross-domain (L2/precompile) desync: if backing is read cross-domain with a settlement lag, check the read is fenced by a block.number > lastChange guard and that user-callable entrypoints don't themselves trigger the cross-domain write in the same block.

Methodology note (reused from cycle219, confirmed again)

Trust boundary (banked)

HyperCore L1Read precompiles + validator slashing + OWNER (applySlash, emergency ops) + MANAGER (sole vHYPE mint/burn) = trusted. Model only what the 7 untrusted-reachable functions (deposit/queueWithdraw/claim/batchClaim/cancel/processBatch/finalizeBatch) reach given an honest keeper.

Transfers to which protocol classes

Doctrine

On an exchange-rate vault, the cycle219 "find the clock" question becomes "what feeds the numerator, and can an untrusted user move it?" If the numerator is a balance read from a keeper/precompile/balanceOf (not a price quote) and both conversions floor toward the vault, the rounding-farm and rate-drift seams are closed - confirm in minutes, then hunt the fence edges (donation path re-derived from code, rate==0 reachability, cross-domain desync). The single most useful new discriminator: balance-read backing is unmanipulable by design; price-quote backing is where the illiquid-underlying manipulation worry actually lives.

Generated 2026-07-02 13:15:03 UTC | auto-sync /15min