V4HOOKSCUT SHEET DIRECTORY

Index / SuckerPunch

pattern · MIT · last updated 2026-08-27

SuckerPunch

Free ETH-pair buys, hold-time sell fee decay, same-block sell taxed as MEV.

First-party rewrite of PopFendi’s EthLondon 2024 SuckerPunch (MIT). afterInitialize requires a native currency0 pair and a dynamic fee pool. beforeSwap returns a per-swap fee with OVERRIDE_FEE_FLAG: buys are free, same-block sells pay MEV_FEE, never-bought sells pay BASE_FEE, and holders decay linearly to MIN_FEE over 90 days. afterSwap records buy inventory keyed by abi.encode(trader) in hookData (else the swap sender). Fixes vs the original: 14 permission fields, OpenZeppelin BaseHook onlyPoolManager, no tx.origin, no updateDynamicSwapFee, and hold-fee math that does not underflow. Experimental. Listing is not an audit. Forge tests live under test/SuckerPunch.t.sol.

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

afterInitializebeforeSwapafterSwap

Solidity

Excerpt from contracts/SuckerPunch.sol. Copy the full file to implement this. Not an audit.

// SPDX-License-Identifier: MIT
// v4hooks first-party rewrite — excerpt. Full file: source.url
function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
    return Hooks.Permissions({
        beforeInitialize: false,
        afterInitialize: true,
        beforeAddLiquidity: false,
        afterAddLiquidity: false,
        beforeRemoveLiquidity: false,
        afterRemoveLiquidity: false,
        beforeSwap: true,
        afterSwap: true,
        beforeDonate: false,
        afterDonate: false,
        beforeSwapReturnDelta: false,
        afterSwapReturnDelta: false,
        afterAddLiquidityReturnDelta: false,
        afterRemoveLiquidityReturnDelta: false
    });
}

function _beforeSwap(address sender, PoolKey calldata key, SwapParams calldata params, bytes calldata hookData)
    internal
    view
    override
    returns (bytes4, BeforeSwapDelta, uint24)
{
    if (!key.currency0.isAddressZero()) revert NotNativePair();
    address trader = traderOf(sender, hookData);
    bool isBuy = params.zeroForOne;
    uint24 fee = feeFor(key.toId(), trader, isBuy);
    return (this.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, fee | LPFeeLibrary.OVERRIDE_FEE_FLAG);
}

Spec

Kindpattern
Statusexperimental
LicenseMIT
Sourcehttps://github.com/CryptoGnome/v4hooks
CategoriesDynamic feesMEV protection
PropertiesDynamic feeCustom swap dataVanilla swap
ChainsEthereum
Docshttps://github.com/popfendi/suckerpunch

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.