Skip to content

ci: Add Hunter invariant safety gate for DynamicFeeHook (zero-config, value-conservation regression guardrail)#1

Open
hunterinvariants wants to merge 5 commits into
AqilJaafree:mainfrom
hunterinvariants:add-hunter-invariants
Open

ci: Add Hunter invariant safety gate for DynamicFeeHook (zero-config, value-conservation regression guardrail)#1
hunterinvariants wants to merge 5 commits into
AqilJaafree:mainfrom
hunterinvariants:add-hunter-invariants

Conversation

@hunterinvariants
Copy link
Copy Markdown

Hey

I built Hunter, a deterministic CI gate for Uniswap v4 hooks (Python stdlib only, no LLM, MIT-licensed). I ran it zero-config against your DynamicFeeHook and it came back clean PASS — and I thought you might want a CI workflow that runs it on every PR as a regression guardrail.

This PR adds one optional workflow file. Deleting it removes the gate; no other dependencies in your repo.

Verbatim verdict on your hook

DynamicFeeHook [concrete] flags=0x30c0
callbacks: [beforeInitialize, afterInitialize, beforeSwap, afterSwap]
6/6 invariants PASS -- 12,800 calls/invariant, 0 reverts
10,648 exercised value-bearing ops across 5 handlers (exercised PASS, not vacuous)
HUNTER_MAX_SWAP_RT_DELTA: -5993 wei (value stayed with the pool)
HUNTER_MAX_LP_RT_DELTA:   -1 wei
Suite: 6 passed, 0 failed -- overall PASS

What Hunter checks

Six universal value-conservation properties that should hold for any v4 hook:

  1. No free swap round-trip — a 0->1->0 swap can't return more than it spent.
  2. Can't drain the shared PoolManager — the systemic v4 risk; one hook can't reach into another pool's reserves.
  3. Callbacks reject non-PoolManager callers — catches a missing onlyPoolManager guard.
  4. LP can always (eventually) withdraw — tolerates anti-JIT / timelock delays before calling it bricked.
  5. LP add + remove without a swap can't profit — delta integrity on the liquidity side.
  6. Fee within a sane bound — tiny round-trips can't lose more than 50% to fees.

Plus an anti-vacuous coverage gate — if every fuzzed swap reverted, the run reports INCONCLUSIVE instead of waving it through. Build/config breakage (wrong solc, missing remapping, a setUp() revert) reports as ERROR, never a fake "value-conservation violated."

It's fuzzing, not proof — not a full audit.

Cost

  • One file, ~15 lines effective.
  • ~25-90 seconds of CI per PR (the workflow uses the Action's defaults).
  • No new deps in your repo; the Action sets up Python + Foundry inside its own runner.

Honest framing

  • Opt-in. Deleting the file removes the gate; not load-bearing.
  • No telemetry. Runs entirely on your runner.
  • Not an audit. Hunter catches structural value-conservation breaks; it doesn't replace human review of your dynamic-fee logic.
  • I'll help debug if it ever breaks in your CI. MIT, free, no strings.

Feel free to close if it's not useful — no hard feelings.

@hunterinvariants
Copy link
Copy Markdown
Author

Hi - small update on this PR; no action needed unless it's useful.

This adds one optional CI workflow that runs Hunter's value-conservation invariant suite on this repo's hook(s) on each PR: no free swap round-trip, the hook can't drain the PoolManager, LPs can always withdraw, sane fee bounds, callbacks reject non-PoolManager callers. It's a safety floor, explicitly not a full audit.

You can see the result for this repo without approving CI - it's on the public board: https://hunterinvariants.github.io/hunter-invariants/leaderboard.html (this repo's hook shows a green PASS, exercised across thousands of fuzzed value-bearing ops). The Action was also run end-to-end on a fork to verify the full CI path.

Since it's a third-party action, the safety basics: it makes no network calls, forces ffi off (so a hook can't shell-exec on your runner), runs only its own generated suite (your own tests are excluded from the build), is time-bounded, and is now pinned to an immutable commit SHA rather than a moving tag.
Fully optional - delete the workflow file to remove it.

No pressure at all - happy to adjust anything or close it. Just wanted to make it easy to evaluate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant