Source: M2 capability cycle. Blind-audited Kinetiq (HYPE liquid staking on Hyperliquid), self-graded vs the published C4 report (3 High + 5 Medium). Caught 1 clean (H-02 slashing-rate-lock). The other 7 fall into two reusable miss-patterns. Static tools (slither/aderyn) added zero awarded findings - all 8 were manual logic.
Two High/Med findings (H-03, M-01) lived entirely in the gap between HyperEVM and HyperCore/L1:
- H-03: HYPE returning from L1 to pay withdrawals lands as a native transfer -> receive() -> stake() -> auto-re-mints + re-stakes it. Withdrawal liquidity is silently swallowed and the exchange ratio inflates.
- M-01: a rebalance function checks address(this).balance (EVM) when the funds are on Core.
Root cause of the miss: I audited a two-domain protocol as a single-domain EVM contract. I read receive()->stake() and the balance checks but never asked "where does the asset physically sit at each step and what fires when it comes back."
DETECTION RULE (new): On any protocol that bridges or precompiles to a second execution domain (L1<->L2, EVM<->appchain Core, cross-chain), BEFORE reviewing functions, draw the asset fund-flow across BOTH domains: where funds rest after each op, the path back, and what callback/receive/fallback fires on arrival. Then re-audit every address(this).balance, receive(), fallback(), and native-transfer against that map. A receive() that does anything other than accept funds is a prime suspect when funds re-enter from the other domain.
Three findings (H-01 buffer-locks-on-cancel, M-02 confirmWithdrawal missing the withdrawal-pause modifier its sibling has, M-03 cancel doesn't reverse the L1 op / buffer it created) were all in my scratch notes - each dismissed with "Minor" or "Fine." I pre-judged intent instead of flagging the asymmetry.
DETECTION RULE (reinforce manual-audit-depth sibling-diff + each-party-POV): An ASYMMETRY is a finding until proven otherwise; never write "probably intended" and move on.
- Diff modifiers across sibling entrypoints (queue / confirm / cancel / redelegate): if one has whenWithdrawalNotPaused or a guard and a sibling doesn't, flag it.
- For every "undo" path (cancel / refund / reset / withdraw), verify it reverses EVERY effect the "do" path created - buffer deltas, pending queues, processing indices, queued L1/cross-domain ops - not just the headline state.
M-04 (process-all-withdrawals-before-deposits starves delegation) and M-05 (spam the deposit array, then delete exceeds block gas) are liveness/griefing bugs in batch-processing plumbing I treated as non-value-bearing.
DETECTION RULE: For every unbounded array/queue where one party pushes and another deletes or loop-drains: (1) can a cheap actor grow it without bound (griefing), (2) does the drain/delete cost scale past the block gas limit, (3) does processing ORDER between two queues starve one side. Add this liveness lens to the saturation hunt.
Edge + money are in the manual logic layer (confirmed: 8/8 awarded findings were logic, 0/8 from static tools). My two live gaps: (A) chain-specific cross-domain fund-flow modeling, and (B) the discipline to FLAG asymmetries I already notice rather than rationalize them away. Related: [[2026-06-10-cycle221-LST-exchange-rate-funding-clock-generalizes-balance-read-vs-price-quote]] (LST rate mechanics), [[2026-06-10-cycle213-restaking-slash-vs-withdrawal-epoch-union-bound]] (slash-vs-withdrawal timing = the H-02 class I DID catch).