The hookthat runseverything.
One V4 hook, zero hard-coded strategy. EVH turns all eight pool callbacks into phases and runs plugins inside them — metered in fuel, gated by permits, backed by slashable bonds, and never able to break the swap.
The pool is the machine.
Plugins are guests.
A conventional hook ships one behaviour. The EVH hypervisor ships none — it schedules whatever the catalog has seated on each phase, in rank order, inside hard fuel caps.
Two functions
spec() declares label, phases, fuel cap and permits. run() executes inside the pool callback.
contract SwapCounterPlugin is PluginBase {
uint256 public swaps;
function spec() external pure returns (PluginSpec memory) {
return PluginSpec({
label: "SwapCounter", semver: "2.0.0",
phaseMask: PhaseMask.bit(Phase.PostSwap),
fuelCap: 120_000,
permits: Permits.READ_STATE | Permits.WRITE_MEMORY
| Permits.EMIT_LOGS
});
}
function _onRun(Invocation calldata inv)
internal override returns (bytes memory)
{
_store(KEY_SWAPS, bytes32(++swaps));
return _pass();
}
}Scanned & matched
Enrollment is permissionless, not free. Every gate runs on-chain before a single frame executes.
- Author holds the minimum EVH stake
- OpcodeScanner sweeps the runtime bytecode
- On-chain
spec()must match every declared field - Open permits granted; gated permits wait for the Council
Ranked per phase
A pool operator seats the plugin on a phase at a unique rank. The runtime walks the lineup every swap.
Eight phases.
One scheduler.
Every V4 lifecycle callback is a scheduling slot. Pre-phases see intent; post-phases see settled deltas. The swap pair is the hot path — it runs on every trade.
Pre-initialize
—pre-launchPost-initialize
—pre-launchPre-add liquidity
—pre-launchPost-add liquidity
—pre-launchPre-remove liquidity
—pre-launchPost-remove liquidity
—pre-launchPre-swap
—pre-launchPost-swap
—pre-launchGuests, not
root.
Nothing a plugin does can revert a pool operation. A faulting plugin is caught per frame, the runtime is caught by the hypervisor, and degradation always ends at “no plugins ran” — never “the pool is broken”.
Can
5 rights- Read price, tick and liquidity for the invocation
- Write its own namespaced PluginMemory slots
- Bid the next dynamic fee — clamped to the pool's band
- Emit events and schedule deferred jobs
- Call listed targets, once the Council certifies it
Cannot
5 walls- DELEGATECALL, CALLCODE, CREATE, CREATE2, SELFDESTRUCT
- Touch another plugin's memory namespace
- Burn past its fuel cap or its epoch allowance
- Revert the swap it runs inside
- Move a swapper's funds — the hook holds no delta permissions
The opcode scan is a necessary condition, not a sufficient one: a clean plugin can still be economically adversarial. Bonds, strikes and the Council bound that — the scan makes failures attributable.
Running
right now.
Straight from the Lens contract — runs, faults, fuel and bonds as the chain reports them.
The catalog opens at deploy
Six reference plugins ship with the system: volatility, fees, displacement, surge breaker, counter and liquidity pulse.
EVH is the
fuel standard.
Not a claim on the hook — the resource the hook meters against.
Allowance
Bond EVH behind a plugin to raise its per-epoch fuel allowance. No bond, base allowance.
Skin in it
Bonds are slashable. Three attributed faults and a share is burned — never redistributed, so nobody profits from failure.
Weight
Locked EVH votes to certify plugins, exile them, and retune every hypervisor parameter through the Chronolock.
Ship code into a live pool.
The trace you read in the lab is the trace you get on mainnet — once the pool is live.