Advanced MEV‑aware fee logic for Uniswap V4 pools. It combines cooldown‑based and impact‑based fees with Anti‑JIT liquidity penalties, multi‑address collusion detection, and fee donation back to the pool. Operational deployment: configured for Ethereum mainnet; follow SECURITY.md for approvals before broadcasting changes.
- Quickstart
- Installation
- Features
- How it works
- Makefile targets
- Configuration
- Deployment
- Development
- Security
- Code of Conduct
- Support
- License
- References
git clone https://github.com/MrLightspeed/MEVChargeHook.git
cd MEVChargeHook
make bootstrap
make build
make testSee docs/INSTALLATION.md.
- Dynamic, decaying fees after trades (cooldown‑based)
- Impact‑based fees for large sell orders
- Anti‑JIT penalties on early liquidity removals
- Fee donation: extra dynamic sell fees (beyond fixed LP fee) and Anti‑JIT penalties donated to the pool
- Collusion deterrence: linked addresses share cooldown windows
- Explicit events + custom errors for auditability
Stateful
_getFee:_getFeecomputes fees and immediately charges and donates any extra portion via_processExtraFeeDonation. Integrators must not treat it as a pure or view-like function.
See the Project Overview for diagrams and the full mechanism design.
MEVChargeHook is a Uniswap V4 Hook contract. Hooks attach custom logic that runs before/after pool lifecycle actions and are selected by permission bits encoded into the hook address. The PoolManager only calls the hook functions that match the encoded bits. A deployer must therefore mine a CREATE2 salt that yields the correct address pattern (see Deployment).
Run make help to list all targets. Common ones:
| Target | Purpose |
|---|---|
build |
Compile with Forge |
test |
Run unit tests + gas report |
lint |
Run solhint / markdownlint |
analyze |
Slither & Mythril |
fuzz |
Echidna fuzz tests |
fuzz-smoke |
Quick Echidna smoke fuzz (short run) |
clean |
Remove build artifacts |
qa |
lint + analyze + test |
Configure the following environment variables:
| Variable | Purpose |
|---|---|
RPC_URL |
JSON‑RPC endpoint for deployments |
ETHERSCAN_API_KEY |
API key for contract verification |
DEPLOYER_ADDRESS |
Named deployer address in Foundry |
See foundry.toml for additional options and remappings.
Environment tip: copy
.env.exampleto.env, fill in your local values (RPC, deployer, Etherscan key, optionalHOOK_SALT/POOL_MANAGER), and source it when running scripts..envstays gitignored—never commit real credentials. CI should inject secrets through its own secrets manager instead of editing the file.
| Path | Purpose |
|---|---|
src/ |
Production Solidity contracts |
test/ |
Foundry unit + invariant suites |
ops/scripts/ |
Deployment helpers / Forge scripts |
config/ |
Static analyzer + linter configs |
docs/ |
Design notes, playbooks, and references |
ops/ |
Operational records (e.g., ops/deployment) kept for maintainers |
.github/ |
CI workflows + templates |
See docs/ROOT_STRUCTURE.md for the full breakdown between end-user files, ops/ assets, and the gitignored local/ workspace.
JavaScript dependencies (node_modules/) and build artefacts (out/, cache/, etc.) are intentionally ignored. Run npm install (or ./bootstrap.sh) after cloning to hydrate local tooling.
- Choose PoolManager → Use official Uniswap v4 deployments for your target network. See the Deployments page for current addresses.
- Mine the hook address → The enabled hook callbacks are encoded in the least significant bits
of the contract address. Use the provided
ops/scripts/salt-miner.jsor your own miner to find a salt that yields the required bits. - Deploy → Use
forge scriptor the providedops/scripts/*helpers to broadcast and verify.
Tip: for local testing, Foundry’s
vm.deployCodeTocan spoof addresses without mining. For real networks you must mine a valid address.
- Solidity: 0.8.30 (EVM =
prague),via-irbuilds, optimizer enabled. - Contracts: Leverages OpenZeppelin 5.x utilities including
ReentrancyGuardTransient. - Testing: Forge tests cover fee donation flow and events; static + symbolic analysis in CI; optional Echidna fuzzing.
- Invariants: Forge runs
StdInvariantsuites that mirror Echidna properties to guard config regressions. - Testing playbook:
forge test→forge test --match-contract '.*Invariant.*'→make fuzz-smoke(fast Echidna) →make qa(lint + analyze + tests). Generate coverage locally if needed withforge coverage --ir-minimum. - Wake security scan:
make wake(runs the Python-based Wake detectors). CI mirrors this with thewake-securityjob and uploadswake-detections.sarifto GitHub’s code scanning UI.
MEVChargeHook never escrows user assets or schedules asynchronous callbacks. All
dynamic fees and Anti-JIT penalties are collected and immediately donated back to
the pool through poolManager.donate, which either succeeds or reverts in the same
transaction. The hook does not mint, burn, or store ERC20 balances on behalf of
swappers, and any attempted donation failure bubbles up via a revert (see
_protectedDonate). This design eliminates the class of “assets held by the hook”
risks described in recent Uniswap v4 post-mortems.
This repository is maintained for Ethereum mainnet operation. All production changes require peer review and must follow the disclosure process in SECURITY.md.
See CODE_OF_CONDUCT.md.
- See
.github/SUPPORT.mdfor help channels. - See
REPORT.mdandaudits/for reports/audit notes.
MIT © 2025 MrLightspeed.