XLinkedInTelegram
Web3 Security

Uniswap V4 Hooks: Power, Perils & Pitfalls

Know the power & pitfall of Uniswap V4 hook! Learn how customizable hook enhance DeFi but also pose security risks like DoS attack & reentrancy

Author
QuillAudits Team
March 26, 2025
Uniswap V4 Hooks: Power, Perils & Pitfalls
XLinkedInTelegram

Uniswap V4 Hooks: Power, Perils & Pitfalls

Uniswap V4 has finally hit Ethereum Mainnet last month, bringing a fresh wave of innovation to the DeFi space.

The big highlight? Hooks.

Think of them as plugins for liquidity pools—letting developers customize how swaps, liquidity provision, and even donations work.

Sounds cool, right? But with great power comes great attack surfaces.

The more flexible the design, the more potential for vulnerabilities. So, before you start injecting custom logic into Uniswap, let's talk about the security considerations you absolutely need to know.

What's New in Uniswap V4?

Uniswap V4 introduces some killer features:

  • Customizable hooks – Developers can attach logic before/after key pool operations.
  • Singleton design – All pools live inside one contract, the PoolManager.
  • Flash accounting – Transactions track balance changes in transient storage, only settling at the end.
  • Dynamic fees – Swap fees can be adjusted dynamically.
  • Native ETH support – Finally, no more WETH wrapping!

Where Hooks Fit In?

Hooks can be placed:

  • Before/after initializing a pool
  • Before/after modifying liquidity
  • Before/after swapping
  • Before/after donating liquidity

For example, when a swap happens, Uniswap first checks if a beforeSwap hook exists. If yes, it executes that logic before the swap. Once the swap is done, if an afterSwap hook exists, it executes post-swap logic.

Now, let's get into the security gotchas.

Security Considerations for Uniswap V4 Hooks

1. Reentrancy Risks in Hooks

Uniswap V4 hooks execute before and after swaps, making them a potential target for reentrancy attacks. If a hook calls an external contract before the transaction completes, an attacker could manipulate balances and drain liquidity.

Example: Vulnerable Hook with Reentrancy

The following hook allows an attacker to reenter and execute multiple swaps before the original transaction finalizes.

1
2contract ReentrantHook {
3    IPoolManager public poolManager;
4
5    constructor(address _poolManager) {
6        poolManager = IPoolManager(_poolManager);
7    }
8
9    function beforeSwap(
10        address sender,
11        PoolKey calldata poolKey,
12        SwapParams calldata params,
13        bytes calldata data
14    ) external override returns (bytes4, int128) {
15        // External call to another contract, allowing reentrancy
16        IUniswapV4Pool(poolManager.getPool(poolKey)).swap(
17            sender,
18            params.zeroForOne,
19            params.amountSpecified,
20            params.sqrtPriceLimitX96,
21            data
22        );
23
24        return (this.beforeSwap.selector, 0);
25    }
26}

Mitigation: Use a Reentrancy Guard

1
2import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
3
4contract SecureHook is ReentrancyGuard {
5    IPoolManager public poolManager;
6
7    constructor(address _poolManager) {
8        poolManager = IPoolManager(_poolManager);
9    }
10
11    function beforeSwap(
12        address sender,
13        PoolKey calldata poolKey,
14        SwapParams calldata params,
15        bytes calldata data
16    ) external override nonReentrant returns (bytes4, int128) {
17        return (this.beforeSwap.selector, 0);
18    }
19}
20
21

2. Gas Usage and DoS Risks

Hooks with high gas consumption can lead to denial-of-service (DoS) attacks, making pools unusable due to transaction failures.

Example: Gas-Intensive Hook

1
2contract ExpensiveHook {
3    function beforeSwap(
4        address sender,
5        PoolKey calldata poolKey,
6        SwapParams calldata params,
7        bytes calldata data
8    ) external override returns (bytes4, int128) {
9        for (uint256 i = 0; i < 10000; i++) {
10            // Unnecessary expensive computation
11            keccak256(abi.encodePacked(i));
12        }
13
14        return (this.beforeSwap.selector, 0);
15    }
16}
17
18

Mitigation: Gas-Efficient Hooks with Limits

1
2contract GasEfficientHook {
3    uint256 public constant MAX_ITERATIONS = 100;
4
5    function beforeSwap(
6        address sender,
7        PoolKey calldata poolKey,
8        SwapParams calldata params,
9        bytes calldata data
10    ) external override returns (bytes4, int128) {
11        for (uint256 i = 0; i < MAX_ITERATIONS; i++) {
12            keccak256(abi.encodePacked(i)); // Gas-efficient processing
13        }
14
15        return (this.beforeSwap.selector, 0);
16    }
17}
18
19

3. Hook Injection & Malicious Hooks

Uniswap V4 allows pools to use custom hooks, which means malicious contracts can disguise themselves as legitimate pools and execute harmful logic.

Example: Malicious Hook That Steals Fees

1
2contract MaliciousHook {
3    address public attacker;
4
5    constructor(address _attacker) {
6        attacker = _attacker;
7    }
8
9    function afterSwap(
10        address sender,
11        PoolKey calldata poolKey,
12        int128 amount0Delta,
13        int128 amount1Delta,
14        bytes calldata data
15    ) external override returns (bytes4) {
16        // Send part of the swapped amount to the attacker's address
17        IERC20(poolKey.token0).transfer(attacker, uint256(amount0Delta) / 10);
18        return this.afterSwap.selector;
19    }
20}
21
22

Mitigation: Hook Whitelisting

1
2contract SecurePoolManager {
3    mapping(address => bool) public approvedHooks;
4
5    function registerHook(address hook) external {
6        require(isTrusted(hook), "Hook not trusted");
7        approvedHooks[hook] = true;
8    }
9
10    function isTrusted(address hook) internal view returns (bool) {
11        // Only allow verified hooks
12        return hook == address(0x1234...) || hook == address(0x5678...);
13    }
14}
15
16

4. Broken Hook Execution Order

Improper hook execution order can lead to inconsistent state updates.

Example: Hook That Modifies State Inconsistently

1
2contract InconsistentHook {
3    uint256 public lastSwapAmount;
4
5    function beforeSwap(
6        address sender,
7        PoolKey calldata poolKey,
8        SwapParams calldata params,
9        bytes calldata data
10    ) external override returns (bytes4, int128) {
11        lastSwapAmount = uint256(params.amountSpecified); // Updates before swap
12        return (this.beforeSwap.selector, 0);
13    }
14
15    function afterSwap(
16        address sender,
17        PoolKey calldata poolKey,
18        int128 amount0Delta,
19        int128 amount1Delta,
20        bytes calldata data
21    ) external override returns (bytes4) {
22        require(uint256(amount0Delta) == lastSwapAmount, "State mismatch"); // Mismatch due to beforeSwap update
23        return this.afterSwap.selector;
24    }
25}
26
27

Mitigation: Enforce Hook Consistency

1
2contract ConsistentHook {
3    uint256 public lastSwapAmount;
4
5    function beforeSwap(
6        address sender,
7        PoolKey calldata poolKey,
8        SwapParams calldata params,
9        bytes calldata data
10    ) external override returns (bytes4, int128) {
11        return (this.beforeSwap.selector, 0);
12    }
13
14    function afterSwap(
15        address sender,
16        PoolKey calldata poolKey,
17        int128 amount0Delta,
18        int128 amount1Delta,
19        bytes calldata data
20    ) external override returns (bytes4) {
21        lastSwapAmount = uint256(amount0Delta); // Only update after swap
22        return this.afterSwap.selector;
23    }
24}
25
26

Hooks introduce powerful customization in Uniswap V4, but they also increase attack vectors. Following best practices can help prevent reentrancy, DoS attacks, malicious hooks, and state inconsistencies.

Final Thoughts

Uniswap V4 hooks open up endless possibilities, but also new security pitfalls. If you’re building custom hooks:

  • Inherit from BaseHook to avoid permission mismatches.
  • Validate return values to prevent transaction failures.
  • Restrict access to prevent unauthorized calls.
  • Audit all upgradeable contracts to mitigate centralization risks.
  • Validate input parameters to prevent malicious pool manipulation.
  • Be cautious when modifying hookDelta to avoid theft.

By following these best practices, you can leverage Uniswap V4 hooks safely and efficiently.

Contents

Tell Us About Your Project
Request An Audit
Subscribe to Newsletter
hashing bits image
Loading...

STAY IN THE LOOP

Get updates on our community, partners, events, and everything happening across the ecosystem — delivered straight to your inbox.

Subscribe Now!

newsletter
DeFi SecurityplumeUniswap FoundationAethiropt-collectivePolygon SPNBNB Chain Kickstart

Office 104/105 Level 1, Emaar Square, Building 4 Sheikh Mohammed Bin Rashid Boulevard Downtown Dubai, United Arab Emirates P.O box: 416654

audits@quillaudits.com

All Rights Reserved. © 2025. QuillAudits - LLC

Privacy Policy