Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/hunter-invariants.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Drop this into a Uniswap v4 hook repo at `.github/workflows/hunter-invariants.yml` to gate every
# PR on Hunter's value-conservation invariant suite. It auto-discovers every hook in your repo,
# generates a harness for each, runs them under Foundry, and FAILS the PR if any invariant breaks OR
# the run was too thin to be meaningful (vacuous coverage -- e.g. every fuzzed swap reverted).
#
# Zero per-hook config: point `scan` at your source dir and Hunter finds the hooks itself. Hooks with
# bespoke constructor dependencies (an oracle / vault / AVS / liquidation protocol) are auto-stood-up
# (the dependency is mocked and its returns are fuzzed); a hook whose src needs IR codegen is recompiled
# with --via-ir automatically. A hook that genuinely needs hand-config is reported NEEDS_CONFIG and
# skipped (never a fabricated pass), so it can't block your PR.
name: hunter-invariants
on:
pull_request:
workflow_dispatch:

# The action posts a sticky results comment on the PR (the green/red "Safety Floor" table).
# That needs write access to pull requests; contents:read is for the checkout.
permissions:
contents: read
pull-requests: write

jobs:
invariants:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive # pull in v4-core / forge-std so `forge test` resolves

- uses: hunterinvariants/hunter-invariants/actions/v4-invariants@8a940f57c0d4efda2eb234f097e6ece946715c44 # v3
with:
scan: src # auto-discover + gate EVERY hook under src/ -- no per-hook config
# runs: 256 # optional -- lower (e.g. 50) for faster PRs, raise for nightly
# depth: 500

# ── Prefer to target ONE hook explicitly instead of scanning? Drop `scan:` and use `hook:` (+ `impl:`
# if it's an abstract base whose concrete deploy target is a *Mock):
#
# - uses: hunterinvariants/hunter-invariants/actions/v4-invariants@8a940f57c0d4efda2eb234f097e6ece946715c44 # v3
# with:
# hook: src/MyHook.sol
# impl: src/mocks/MyHookMock.sol # omit if your hook is concrete