Index / V2 pair hook
pattern · UNLICENSED · last updated 2026-08-27
V2 pair hook
Run xy=k inside the hook: mint LP on the ERC20, NoOp the CLAMM swap with return-delta.
hensha256’s V2PairHook implements Uniswap v2 constant-product math inside a v4 hook instead of concentrating liquidity. beforeInitialize binds factory, fee 0, tickSpacing 1, and the pair currencies. beforeAddLiquidity always reverts so LPs mint() on the hook ERC20. beforeSwap mints and burns ERC-6909 claims, prices with _getAmountOut, and returns a specified delta that NoOps the CLAMM; afterSwap returns the unspecified delta from transient storage. Flags include both return-delta bits. UNLICENSED research code. Distinct from Uniswap FullRange, which still uses the concentrated AMM. Copy the full file. Listing is not an audit.
Permission bits
These bits must match the deployed address. Confirm on-chain before you route.
beforeInitializebeforeAddLiquiditybeforeSwapafterSwapbeforeSwapReturnDeltaafterSwapReturnDelta
Solidity
Excerpt from src/V2PairHook.sol. Copy the full file to implement this. Not an audit.
// SPDX-License-Identifier: UNLICENSED
function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: true,
afterInitialize: false,
beforeAddLiquidity: true,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: true,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: true,
afterSwapReturnDelta: true,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
});
}
function beforeAddLiquidity(address, PoolKey calldata, IPoolManager.ModifyLiquidityParams calldata, bytes calldata)
external
pure
override
returns (bytes4)
{
revert AddLiquidityDirectToHook();
}
function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata)
external
override
poolManagerOnly
returns (bytes4, int128)
{
bool exactIn = (params.amountSpecified < 0);
uint256 amountIn;
uint256 amountOut;
if (exactIn) {
amountIn = uint256(-params.amountSpecified);
amountOut = _getAmountOut(params.zeroForOne, amountIn);
} else {
amountOut = uint256(params.amountSpecified);
amountIn = _getAmountIn(params.zeroForOne, amountOut);
}
(Currency inputCurrency, Currency outputCurrency) = _getInputOutput(key, params.zeroForOne);
poolManager.mint(address(this), CurrencyLibrary.toId(inputCurrency), amountIn);
poolManager.burn(address(this), CurrencyLibrary.toId(outputCurrency), amountOut);
return (IHooks.beforeSwap.selector, int128(-params.amountSpecified));
}Spec
| Kind | pattern |
|---|---|
| Status | experimental |
| License | UNLICENSED |
| Source | https://github.com/hensha256/v2-on-v4 |
| Categories | WrappersLP management |
| Properties | Vanilla swap |
| Chains | Ethereum |
FAQ
Can I paste this into production? The snippet is an excerpt. Use the full file at the source URL, match flags to the address, and treat this page as a map, not a guarantee.
How do I build this safely? Start with secure v4 hooks and the OpenZeppelin hooks guide.