Building Custom Hooks
What are Custom Hooks?
Custom hooks are smart contracts that intercept and enforce arbitrary logic before and/or after vault operations.
Unlike configurable hooks which merely extract and check function arguments at specific calldata offsets custom hooks allow you to encode far more sophisticated, protocol-specific, or cross-cutting constraints.
Custom hooks use the same function signatures as the operations they are intercepting so they are easy to read.
A custom hook can:
Interact with external oracles.
Maintain their own state (such as cumulative slippage).
Impose various limits.
Integrate complex calculations that cannot be captured by static calldata offsets.
Custom hooks may be deployed as pre-hooks (executed before an operation, may return values) or post-hooks (executed after, donβt return values).
Why They Matter
Custom hooks provide the necessary flexibility to incorporate many kinds of onchain constraints. While most commonly these are used for checking slippage bounds for traders or other transfers that require fees (e.g., bridging), custom hooks can support many more complex invariants such as allowing an operation depending on the state of another contract.
How to Create a Custom Hook
Consider the ERC4626 example we used for configurable hooks. This is how it would look as a custom hook:
contract ERC4626Hook {
function withdraw(uint256 assets, address receiver, address owner) public returns (bytes memory returnData) {
if (HooksLibrary.isBeforeHook()) {
return abi.encode(receiver);
} else if (HooksLibrary.isAfterHook()) {
// no action to take for this hook
return bytes("");
} else {
// this branch will only happen if the hook
// is called by a contract other than the vault
}
}
}
In the most general case, a custom hook will use the HooksLibrary
to implement actions both for the pre-hook case and the post-hook case.
Caveats
Custom hooks have a major impact on the trust model and should be audited before being used for production vaults.
Last updated