I believe Uniswap v4 will be available to everyone soon!
This time, the Uniswap team has ambitious goals and plans to introduce many new features[1], including support for an unlimited number of liquidity pools and dynamic fees for each trading pair, singleton design, lightning accounting, Hooks, and support for the ERC1155 token standard. Using the transient storage introduced by EIP-1153, Uniswap v4 is expected to be released after the Ethereum Cancun upgrade.
Among the many innovations, the Hook mechanism has attracted widespread attention due to its powerful potential. The Hook mechanism supports the execution of specific code at specific points in the life cycle of the liquidity pool, greatly enhancing the scalability and flexibility of the pool.
However, the Hook mechanism can also be a double-edged sword. Although it is powerful and flexible, using Hooks safely is also a challenge. The complexity of Hooks inevitably brings new potential attack vectors. Therefore, we hope to write a series of articles to systematically introduce the security issues and potential risks related to the Hook mechanism to promote the security development of the community. We believe that these insights will help build a secure Uniswap v4 Hook.
As the opening article in this series, this article introduces the concepts related to the Hook mechanism in Uniswap v4 and outlines the security risks of the Hook mechanism.
Uniswap V4 Mechanics
Before we dive in, we need to have a basic understanding of the Uniswap v4 mechanism. According to the official announcement [1] and white paper [2], Hook, singleton architecture, and lightning accounting are three important features for implementing custom liquidity pools and efficient routing across multiple pools.
1.1 Hook
Hooks refer to contracts that run at different stages of the life cycle of a liquidity pool. The Uniswap team hopes to enable anyone to make trade-off decisions by introducing Hooks. In this way, it is possible to natively support dynamic fees, add on-chain limit orders, or disperse large orders through time-weighted average market makers (TWAMM).
There are currently eight Hook callbacks, divided into four groups (each group contains a pair of callbacks):
beforeInitialize/afterInitialize
beforeModifyPosition/afterModifyPosition
beforeSwap/afterSwap
beforeDonate/afterDonate
The following is the process of exchanging Hooks described in the white paper [2].
Figure 1: Hook swap process
The Uniswap team introduced the operation methods with some examples (such as TWAMM Hook[3]), and community participants also made some contributions. The official documentation[4] also links to the Awesome Uniswap v4 Hooks[5] repository, which collects more Hook examples.
1.2 Singleton, Lightning Accounting and Lock Mechanism
The singleton architecture and flash accounting aim to improve performance by reducing costs and ensuring efficiency. It introduces a new singleton contract, where all liquidity pools are stored in the same smart contract. This singleton design relies on a PoolManager to store and manage the status of all pools.
In earlier versions of the Uniswap protocol, operations such as redemption or adding liquidity involved direct token transfers. Version v4 is different in that it introduces lightning accounting and a lock mechanism.
The locking mechanism works as follows:
1. A locker contract requests a lock on PoolManager.
2. PoolManager adds the locker contract’s address to the lockData queue and calls its lockAcquired callback.
3. The locker contract executes its logic in the callback. During execution, the locker contract's interaction with the pool may result in non-zero currency increments. However, at the end of execution, all increments must be settled to zero. In addition, if the lockData queue is not empty, only the last locker contract can perform operations.
4. PoolManager checks the status of the lockData queue and currency increment. After verification, PoolManager will delete the locker contract.
In summary, the lock mechanism prevents concurrent access and ensures that all transactions can be cleared. The locker contract applies for locks in order and then executes transactions through the lockAcquired callback. The corresponding Hook callback is triggered before and after each pool operation. Finally, the PoolManager checks the status.
This approach means that operations adjust the internal net balance (i.e. delta) rather than performing instant transfers. Any modifications are recorded in the pool's internal balance, and the actual transfer is made at the end of the operation (i.e. lock). This process ensures that there are no unliquidated tokens, thus maintaining the integrity of the funds.
Due to the lock mechanism, Externally Owned Accounts (EOA) cannot interact with the PoolManager directly. Instead, any interaction must go through a contract. This contract acts as an intermediate locker and requires a lock to be requested before any pool operation can be performed.
There are two main contract interaction scenarios:
A locker contract comes from the official code base or is deployed by a user. In this case, we can think of the interaction as going through a router.
A locker contract and Hook are integrated into the same contract, or controlled by a third-party entity. For this case, we can think of the interaction as taking place through the Hook. In this case, the Hook plays the role of the locker contract and is responsible for handling callbacks.
Threat Model
Before discussing related security issues, we need to determine the threat model. We mainly consider the following two situations:
Threat Model I: The Hook itself is benign, but there are vulnerabilities.
Threat Model II: Hooks are inherently malicious.
In the following sections, we discuss potential security issues based on these two threat models.
2.1 Security Issues in Threat Model I
Threat Model I focuses on vulnerabilities related to Hooks themselves. This threat model assumes that developers and their Hooks are not malicious. However, existing known vulnerabilities in smart contracts may also appear in Hooks. For example, if Hooks are implemented as an upgradeable contract, then it may suffer from issues similar to OpenZeppelin's UUPSUpgradeable vulnerability.
Given the above, we chose to focus on potential vulnerabilities specific to the v4 version. In Uniswap v4, Hooks are smart contracts that are able to execute custom logic before or after core pool operations (including initialization, modifying positions, swapping, and collecting). While Hooks are expected to implement a standard interface, it is also allowed to include custom logic. Therefore, the scope of our discussion will be limited to logic involving the standard Hook interface. We will then try to identify possible sources of vulnerabilities, for example, how Hooks might abuse these standard Hook functions.
Specifically, we will focus on the following two types of Hooks:
The first type of hook keeps user funds. In this case, an attacker may attack this hook to transfer funds and cause asset loss.
The second type of hook stores critical state data that users or other protocols rely on. In this case, an attacker may try to change critical state. This may bring potential risks when other users or protocols use incorrect state.
Please note that hooks outside of these two scopes are not within the scope of our discussion.
Since there are no real-world use cases for Hooks at the time of writing, we’ll pull some information from the Awesome Uniswap v4 Hooks repository.
After an in-depth study of the Awesome Uniswap v4 Hooks repository (commit hash 3a0a444922f26605ec27a41929f3ced924af6075), we found several serious vulnerabilities. These vulnerabilities mainly stem from risky interactions between hooks, PoolManager, and external third parties, and can be divided into two categories: access control issues and input validation issues. Please see the table below for specific findings:
In total, we found 22 relevant projects (excluding projects not related to Uniswap v4). Of these projects, we believe that 8 (36%) projects are vulnerable. Of these 8 vulnerable projects, 6 had access control issues and 2 were vulnerable to untrusted external calls.
2.1.1 Access Control Issues
In this part of the discussion, we mainly focus on the problems that may be caused by callback functions in v4, including 8 hook callbacks and lock callbacks. Of course, there are other situations that need to be verified, but these situations vary depending on the design and are not within the scope of our discussion.
These functions should only be called by the PoolManager and not by other addresses (including EOAs and contracts). For example, in the case where rewards are distributed by the pool key, if the corresponding function can be called by any account, then the rewards may be claimed incorrectly.
Therefore, it is crucial to establish strong access control mechanisms for hooks, especially since they can be called by other parties besides the pool itself. By strictly managing access rights, liquidity pools can significantly reduce the risk of unauthorized or malicious interactions with hooks.
2.1.2 Input Validation Issues
In Uniswap v4, due to the lock mechanism, users must obtain a lock through the contract before performing any fund pool operations. This ensures that the contract currently participating in the interaction is the latest locker contract.
Nonetheless, there is still a possible attack scenario involving untrusted external calls due to improper input validation in some vulnerable Hook implementations:
First, the hook does not verify the pool the user intends to interact with. This could be a malicious pool that contains fake tokens and executes harmful logic.
Secondly, some key hook functions allow arbitrary external calls.
Untrusted external calls are extremely dangerous because they can lead to various types of attacks, including what are known as reentrancy attacks.
To attack these vulnerable hooks, an attacker can register a malicious pool for their own fake tokens, and then call the hook to perform operations on the pool. When interacting with the pool, the malicious token logic hijacks the control flow in order to perform bad behavior.
2.1.3 Preventive measures for threat model I
To circumvent such security issues associated with hooks, it is critical to verify the interaction by properly enforcing necessary access controls to sensitive external/public functions and validating input parameters. In addition, reentrancy protection may help ensure that hooks are not repeatedly executed in the standard logic flow. By implementing appropriate security protections, funding pools can reduce the risks associated with such threats.
2.2 Security Issues in Threat Model II
In this threat model, we assume that the developer and their hooks are malicious. Given the wide scope involved, we only focus on security issues related to version 4. Therefore, the key lies in whether the provided hook can handle the crypto assets transferred or authorized by the user.
Since the method of accessing a hook determines the permissions that may be granted to the hook, we divide hooks into two categories:
Managed Hooks: Hooks are not entry points. Users must interact with hooks through a router (possibly provided by Uniswap).
Standalone Hooks: Hooks are entry points that allow users to interact with them directly.
Figure 2: Example of a malicious Hook
2.2.1 Hosted Hook
In this case, the user's crypto assets (including native tokens and other tokens) are transferred or authorized to the router. Since the PoolManager performs balance checks, it is not easy for malicious hooks to directly steal these assets. However, there is still a potential attack surface. For example, the fee management mechanism of the v4 version may be manipulated by an attacker through a hook.
2.2.2 Independent Hook
The situation is more complicated when Hooks are used as entry points. In this case, the hook gains more power because the user can interact with the hook directly. In theory, the hook can perform any action it wants through this interaction.
In v4, verification of code logic is critical. The main question is whether the code logic can be manipulated. If the hook is upgradeable, it means that a seemingly safe hook may become malicious after the upgrade, posing a significant risk. These risks include:
Upgradable proxy (can be directly attacked);
Has self-destruct logic. Can be attacked by calling selfdestruct and create2 together.
2.2.3 Preventive measures against threat model II
It is crucial to evaluate whether a hook is malicious. Specifically, for managed hooks, we should focus on the behavior of fee management, while for independent hooks, the main concern is whether they are upgradeable.
in conclusion
In this article, we first briefly outline the core mechanisms related to the Hook security issues of Uniswap v4. Subsequently, we proposed two threat models and briefly outlined the related security risks.
In subsequent articles, we will conduct an in-depth analysis of the security issues under each threat model.
