V4HOOKSCUT SHEET DIRECTORY

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.

Initialize
ba
Liquidity
baba
Swap
ba
Donate
ba
Return delta
baaa

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

Kindpattern
Statusexperimental
LicenseUNLICENSED
Sourcehttps://github.com/hensha256/v2-on-v4
CategoriesWrappersLP management
PropertiesVanilla swap
ChainsEthereum

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.