LogoLogo
  • HOOKRANK
    • Introduction
  • CORE FEATURES
    • Dashboard
      • Hook List
      • Hook Details
    • Earnings Analytics
    • Gas Spendings
    • Total Value Locked
    • Transaction Volume
  • HOOKS KNOWLEDGE
    • NoOp Hooks
  • HookRank indexing
    • Events
      • Swap
      • Initialize
      • ModifyLiquidity
    • Tracked Data
  • PUBLIC API
    • Introduction
    • Endpoints
      • /api/public/v1/uniswap/hooks/networks
        • GET
      • /api/public/v1/uniswap/hooks/currencies
        • GET
      • /api/public/v1/uniswap/hooks
        • GET
      • /api/public/v1/uniswap/hooks/{{chainId}}/{{hookAddress}}
        • GET
      • /api/public/v1/uniswap/hooks/{{chainId}}/{{hookAddress}}/contract-metadata
        • GET
  • GUIDES
    • FAQs
    • How To Provide Custom Hook Integration Data
  • EXTERNAL LINKS
    • Twitter / X
    • GitHub
    • Discord
    • Brand Kit
Powered by GitBook
On this page
  • What Are NoOp Hooks?
  • NoOp Implementation
  • NoOp Usecases
  • Conclusion
  1. HOOKS KNOWLEDGE

NoOp Hooks

PreviousTransaction VolumeNextEvents

Last updated 2 months ago

What Are NoOp Hooks?

NoOp Hooks are Uniswap V4 hooks offering an alternative to the conventional AMM swap formula (x * y = k), allowing developers to implement custom swap logic tailored to specific needs. These hooks provide a flexible framework where default operations can be bypassed. This capability enables developers to create bespoke trading mechanisms without altering the underlying protocol, ensuring seamless integration with existing systems. By using NoOp Hooks, developers can either extend functionality or maintain existing frameworks by simply acting as placeholders when no additional logic is required.

NoOp Implementation

Two things is need for hook to be considered NoOp - to return delta amount from respective function and to have enabled permission. For example (as a reference code was taken from this ):

contract RugPullSwap is BaseHook {
    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
        return
            Hooks.Permissions({
                beforeInitialize: false,
                afterInitialize: false,
                beforeAddLiquidity: false,
                beforeRemoveLiquidity: false,
                afterAddLiquidity: false,
                afterRemoveLiquidity: false,
                beforeSwap: true, // hook function permission
                afterSwap: false,
                beforeDonate: false,
                afterDonate: false,
                beforeSwapReturnDelta: true, // permission to return delta amount
                afterSwapReturnDelta: false,
                afterAddLiquidityReturnDelta: false,
                afterRemoveLiquidityReturnDelta: false
            });
    }

    function beforeSwap(
        address,
        PoolKey calldata key,
        IPoolManager.SwapParams calldata params,
        bytes calldata
    ) external override returns (bytes4, BeforeSwapDelta, uint24) {
        // if swap amount less then 1 ether - rekt it!
        if (params.amountSpecified < 1 ether) {
            Currency input = params.zeroForOne ? key.currency0 : key.currency1;
            
            // take the amount and omit returns to user
            input.take(
               poolManager,
               address(this),
               uint256(-params.amountSpecified),
               false
            );

            return (
              BaseHook.beforeSwap.selector,
              // returns BeforeSwapDelta, where first value is for taking 
              // all the amount and second for returning 0 back to user 
              toBeforeSwapDelta(int128(-params.amountSpecified), 0),
              0
            );
        }
        
        // if amount is more then 1 ether - swap noramlly by returning zero delta
        return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
    }
}

NoOp Usecases

contract BtcAccHook is BaseHook {
    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
        // returns permissions for afterSwap()
    }
    
    function afterSwap(
        address sender,
        PoolKey calldata key,
        IPoolManager.SwapParams calldata params,
        BalanceDelta delta,
        bytes calldata
    ) external override onlyPoolManager returns (bytes4, int128) {
        // ... security checks

        // determine user 
        address user = IValidRouter(sender).msgSender();

        // Calculate fee based on the swap amount
        bool specifiedTokenIs0 = (params.amountSpecified < 0 == params.zeroForOne);
        (Currency feeCurrency, int128 swapAmount) =
            (specifiedTokenIs0) ? (key.currency1, delta.amount1()) : (key.currency0, delta.amount0());

        Currency otherCurrency = (specifiedTokenIs0) ? key.currency0 : key.currency1;

        if (swapAmount < 0) swapAmount = -swapAmount;

        // Get the user's custom fee rate or default rate
        uint128 userFeeRate = getWalletSwapFee(user);
        uint256 feeAmount = uint128(swapAmount) * userFeeRate / TOTAL_BIPS;
        
        // take fee amount from pool manager
        manager.take(feeCurrency, address(this), feeAmount);

        address feeToken = Currency.unwrap(feeCurrency);
        address otherToken = Currency.unwrap(otherCurrency);

        // Handle fee token deposit or conversion
        if (isAllowedBaseToken[feeToken]) {
            _depositBase(user, feeAmount, feeToken, otherToken);
        } else {
            uint256 baseAmount = _swapToBase(key, feeAmount);
            address baseToken =
                Currency.unwrap(isAllowedBaseToken[Currency.unwrap(key.currency0)] ? key.currency0 : key.currency1);
            _depositBase(user, baseAmount, baseToken, feeToken);
        }
        
        // returns delta to account 
        return (BaseHook.afterSwap.selector, feeAmount.toInt128());
    }
}
  1. Custom curve hook: In certain scenarios, it may be more profitable to use an alternative pool mechanism that does not rely on the constant product AMM formula (x * y = k). For example, a pool could instead operate using a formula like x + y = k, which may better suit specific market conditions or trading strategies.

contract CustomCurveHook is BaseHook {
    int256 private constant K = 1000000;
    
    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
        // before swap permissions returned
    }
    
    function beforeSwap(
        address sender,
        PoolKey calldata key,
        IPoolManager.SwapParams calldata params,
        bytes calldata hookData
    ) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24) {
        return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(params.amountSpecified, 1000000 - params.amountSpecified), 0);
    }
}

Conclusion

Developing an accumulation hook (reference from TokenWorks ): The main idea of such hook is to have a layer between BTC assets and Uniswap V4 ecosystem and deposit user fees from swap into BTC holdings.

In conclusion, NoOp Hooks in Uniswap V4 allow developers to customize swap logic and it`s parameters, offering flexibility for unique trading strategies and easy integration with existing systems. If you want to have broader conception about NoOp hooks - please check HookRank for all hooks labeled NoOp.

article
contract
dashboard