V4HOOKSCUT SHEET DIRECTORY

Index / veLP

pattern · AGPL-3.0-or-later · last updated 2026-08-27

veLP

Curve-style vote-escrow on a v4 position: lock ticks, block early withdraw in beforeModifyPosition.

kadenzipfel ports VotingEscrow onto a Uniswap v4 hook. afterInitialize stores the PoolId. beforeModifyPosition lets unrelated ticks through, but if sender is modifying their locked range it requires liquidityDelta > 0 until lock end. afterModifyPosition checkpoints ve weight from the position’s liquidity. Early Hooks.Calls API (modifyPosition, not add/remove). AGPL-3.0 — copy the full VotingEscrow.sol. Map modifyPosition to today’s beforeAddLiquidity / beforeRemoveLiquidity if you port forward. 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

afterInitializebeforeAddLiquidityafterAddLiquiditybeforeRemoveLiquidityafterRemoveLiquidity

Solidity

Excerpt from src/VotingEscrow.sol. Copy the full file to implement this. Not an audit.

// SPDX-License-Identifier: AGPL-3.0-or-later
function getHooksCalls() public pure override returns (Hooks.Calls memory) {
    return Hooks.Calls({
        beforeInitialize: false,
        afterInitialize: true,
        beforeModifyPosition: true,
        afterModifyPosition: true,
        beforeSwap: false,
        afterSwap: false,
        beforeDonate: false,
        afterDonate: false
    });
}

function beforeModifyPosition(
    address sender,
    PoolKey calldata,
    IPoolManager.ModifyPositionParams calldata modifyPositionParams
) external view override poolManagerOnly returns (bytes4) {
    LockTicks memory lockTicks_ = lockTicks[sender];
    if (
        lockTicks_.lowerTick != modifyPositionParams.tickLower
            || lockTicks_.upperTick != modifyPositionParams.tickUpper
    ) {
        return VotingEscrow.beforeModifyPosition.selector;
    }
    LockedBalance memory locked_ = locked[sender];
    require(
        modifyPositionParams.liquidityDelta > 0 || locked_.end <= block.timestamp,
        "Can't withdraw before lock end"
    );
    return VotingEscrow.beforeModifyPosition.selector;
}

Spec

Kindpattern
Statusexperimental
LicenseAGPL-3.0-or-later
Sourcehttps://github.com/kadenzipfel/veLP
CategoriesVote-escrowLP 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.