This article explains in detail the meaning of UniswapV4 functions and their implementation principles.
Original author: Lin Weichen Albert Lin
Original source: medium
Since the announcement of UniswapV4, the Swap platform has undergone a huge transformation. It has evolved from a Swap platform into an infrastructure service provider. In particular, the Hooks function of V4 has attracted widespread attention. After a period of in-depth research, I compiled some content, hoping to give everyone a better understanding of this change and its implementation.
The innovation focus of UniswapV4 is not to improve the AMM technology, but to expand the ecosystem. Specifically, this innovation includes the following key functions:
- Flash Accounting
- Singleton Contract
- Hooks Architecture
In the following sections, I will explain in detail what these functions mean and how they work.

Flash Accounting
Double Entry Bookkeeping
UniswapV4 adopts a recording method similar to Double Entry Bookkeeping to track the increase or decrease in the Token balance corresponding to each operation. This double-entry bookkeeping method requires that each transaction must be recorded in multiple accounts at the same time and ensure that the value of assets between these accounts is balanced. For example, assuming that the user exchanges 100 TokenA to the Pool for 50 TokenB, the record in the ledger will be as follows:
- USER: TokenA decreases by 100 units (-100), while TokenB increases by 50 units (+50).
- POOL: TokenA increases by 100 units (+100), while TokenB decreases by 50 units (-50).

Token Delta related operations
In UniswapV4, this accounting method will be used for the main operations, and a Storage Variable named lockState.currencyDelta[currency] is used in the program code to record the change in the Token balance. If the value of this change is positive, it indicates the expected increase in the number of Tokens in the pool, otherwise it indicates the expected decrease in the number of Tokens in the pool. From another perspective, if the value is positive, it represents the number of Tokens missing in the pool (the number of Tokens expected to be received), while a negative value represents the number of excess Tokens in the pool (the number of Tokens expected to be withdrawn by the user). Token quantity). The following lists the effects of various operations on the Token delta (TokenDelta):

- modifyPosition: Indicates the operation of Add/Remove liquidity. For Add liquidity, the Token delta (representing TokenA expected to be added to the pool) is updated using addition. For Remove liquidity, subtraction is used to update the Token delta (indicating that TokenB is expected to be withdrawn from the pool).
- swap: Indicates performing Swap operation. Taking Swap TokenA to TokenB as an example, addition is used to update TokenADelta, and subtraction is used to update TokenBDelta.
- settle: accompanied by the operation of transferring Token to Pool. Pool will calculate the increase in Token before and after, and update TokenDelta using subtraction. If the Pool just receives the expected number of Tokens, the subtraction update here will just reset the TokenDelta to zero.
- take: Accompanying the operation of withdrawing the Token from the Pool. Pool will update TokenDelta using addition, indicating that Token has been removed from this Pool.
- mint: The behavior of updating TokenDelta is similar to "take", except that mint does not actually withdraw the token from the pool. Instead, the corresponding ERC1155 Token is issued as proof of withdrawal, and the token remains in the pool. Afterwards, users can retrieve the Token in the Pool by destroying the ERC1155 Token. It is speculated that there are two purposes: 1. Save the gas cost of ERC20 Token transfer (contract call + one less storage write), and use ERC1155 token burn method to update TokenDelta for transaction use in the future. 2. Keep liquidity in the Pool and maintain liquidity depth so that users can have a better Swap Token experience.
- donate: Declare to donate the Token to the Pool, but in fact you still need to use "settle" to send the Token to the Pool. Therefore, addition is used here to update the Token delta.
Among the above operations, only settle and take will actually transmit the Token, and other operations simply update the TokenDelta value.
Token Delta Example
Below we use a simple example to illustrate how to actually update TokenDelta. Suppose we exchange 100 TokenA for 50 TokenB today:

- Both TokenADelta and TokenBDelta are 0 before the transaction starts.
- swap: Calculate how many TokenA the Pool needs to receive and how many TokenB the user will receive. At this time, TokenADelta = 100, TokenBDelta = -50.
- settle: Send 100 TokenA to the Pool and update TokenADelta = 100–100 = 0.
- take: Transfer 50 TokenB from Pool to user account, and update TokenBDelta = -50 + 50 = 0.
- After the transaction, both TokenADelta and TokenBDelta are 0.
When the entire redemption operation is completed, both TokenADelta and TokenBDelta are reset to 0. This means that the operation has been fully balanced, thereby ensuring the consistency of the account balance.
EIP-1153: Transient storage opcodes
As mentioned before, UniswapV4 uses Storage Variable to record TokenDelta, but within the contract, reading and writing Storage Variable is quite costly. At this time, we should mention another EIP launched by Uniswap: EIP1153 — Transient Storage Opcodes.
UniswapV4 plans to use the two OP Codes TSTORE and TLOAD provided by EIP1153 to update TokenDelta. Storage Variable using Transient Storage Opcodes will be discarded after the Transaction ends (similar to Memory Variable), so there is no need to write to the hard disk, thereby reducing Gas costs.
EIP1153 has been confirmed to be included in the next Cancun upgrade, and UniswapV4 also pointed out that UniswapV4 will be launched after the Cancun upgrade.

Flash Accounting—Lock
UniswapV4 introduces the lock mechanism, which means that before performing Pool operations, PoolManager.lock() must first be called to obtain a lock. Before the execution of lock() ends, it will check whether the value of TokenDelta is 0, otherwise revert will be triggered. When PoolManager.lock() is called and the lock is successfully acquired, the lockAcquired() function of msg.sender will be called. Pool-related operations (such as swap, modifyPosition, etc.) are only performed in the lockAcquired() function.
The following diagram is used as an example to illustrate this process. When the user needs to perform a Token Swap operation, a Smart Contract with a lockAcquired() function must be called (herein called a callback contract, CallBack Contract). The callback contract will first call PoolManager.lock(), and then PoolManager will call the callback contract's lockAcquired() function. In the lockAcquired() function, the logic related to Pool operations is defined, such as swap, settle, and take operations. Finally, when the entire lock() is about to end, the PoolManager will check whether the TokenDelta related to this operation has been reset to 0 to ensure that the assets in the Pool remain balanced.

Singleton Contract
Singleton Contract means that UniswapV4 has abandoned the previous Factory-Pool model. Each Pool is no longer an independent Smart Contract, but all Pools share the same singleton contract. This design is combined with the Flash Accounting mechanism and only the necessary Storage Variables need to be updated, further reducing the complexity and cost of the operation.
The following diagram is used as an example. Taking UniswapV3 as an example, converting ETH into DAI requires at least four Token transfers (Storage write operations). This includes multiple change records for USDC, USDT and DAI Token. However, through the improvements of UniswapV4 and the Flash Accounting mechanism, only one token transfer is required (to transfer DAI from the Pool to the user), which greatly reduces the number of operations and costs.

Hooks Architecture
In this update of UniswapV4, the most eye-catching one is Hooks Architecture. This update will provide great flexibility around Pool availability. Hooks means that when performing a specific operation on the Pool, the Hooks Contract will be additionally called to perform additional actions. These actions can be divided into different categories, including initialize (create pool), modifyPosition (add/remove liquidity), swap and donate. Each category has pre-execution and post-execution actions:
- beforeInitialize / afterInitialize
- beforeModifyPosition / afterModifyPosition
- beforeSwap / afterSwap
- beforeDonate / afterDonate
This design allows users to more flexibly execute customized logic before and after specific operations, thus extending the functionality of UniswapV4.

Hook Example — Limit Order Hook
Next, we will use the example of a limit order to illustrate the actual operation process of Hooks. Before starting, let’s briefly explain the principle of implementing limit orders in UniswapV4.
UniswapV4 Limit Order Mechanism
The principle of implementing limit orders in UniswapV4 is to add liquidity (Add Liquidity) to a specific price range, and then perform a Remove Liquidity operation if the liquidity in that range is exchanged.
For example, let's say we add liquidity to ETH in the price range of 1900–2000, and then when the ETH price rises from 1800 to 2100. At this time, all the ETH liquidity we previously added in the 1900–2000 price range has been exchanged for USDC (assumed to be in the ETH-USDC Pool). Removing liquidity at this point would have the effect of executing an ETH market order at the current price of 1900–2000.

Limit Order Hook Contract
This example is provided by GitHub from UniswapV4. In this example, the Limit Order Hook contract provides two Hooks, namely afterInitialize and afterSwap. Among them, afterInitialize is used to record the price range (tick) when the Pool is established, so as to determine which limit orders have been matched after someone makes a swap.
Place Order
When the user needs to place an order, the Hook contract will perform the operation of adding liquidity based on the price range and quantity specified by the user. In the Hook contract of the limit order, you can see the place() function. The main logic is to call the lockAcquiredPlace() function after obtaining the lock to perform the operation of adding liquidity. This part is equivalent to placing a limit order.

afterSwap Hook
After the user completes the Swap Token in this Pool, the Pool will call the afterSwap() function of the Hook contract. The main logic of afterSwap is to remove liquidity from orders that have been executed between the previous price range and the current price range. Such behavior is equivalent to the order being filled.

Limit Order Flow
The following is a schematic diagram of the process for placing a limit order:

- The order placer sends the order to the Hook contract.
- The Hook contract performs adding liquidity operations based on order information.
- Generally, users perform Swap Token operations in Pool.
- After the Swap Token operation is completed, the Pool will call the afterSwap() function of the Hook contract.
- The Hook contract performs the liquidity removal operation of executed limit orders based on changes in the Swap Token's price range.
The above is the entire process of using the Hook mechanism to implement Limit-Order.
Hook: Other features
Hooks also has several interesting points that the author found interesting during the research, and I think they are worth mentioning and sharing with everyone.
Hooks Contract Address Bit
Determining whether specific before/after operations need to be performed is determined by the leftmost byte of the Hook contract address. 1 byte is equal to 8 bits, which exactly corresponds to 8 additional actions. Pool will check whether the action bit is 1 to determine whether the corresponding hook function of the Hook contract should be called. This also means that the address of the Hook contract needs to be designed in a specific way, and the contract address cannot be randomly selected as the Hook contract. The main purpose of this design is to reduce Gas consumption and transfer costs to contract deployment to achieve more efficient operations. (PS: In practice, different CREATE2 salts can be used to brute forcely calculate the qualified contract address)

Dynamic Fee
In addition to being able to perform additional operations before and after each action, Hooks also support the implementation of dynamic fees. When creating a Pool, you can specify whether to enable dynamic handling fees. If dynamic fees are enabled, the getFee() function of the Hook contract will be called when Swap Token. The Hook contract can decide how much handling fee should be charged based on the current Pool status. This design allows the calculation of handling fees to be adjusted according to actual conditions, improving the flexibility of the system.
Pool Creation
Each Pool needs to determine the Hook contract when it is created, and it cannot be changed later (but different Pools can share the same Hook contract). This is mainly because Hooks are considered part of the PoolKey, which is used by the PoolManager to identify which Pool to perform operations on. Even if the assets are the same, if the Hook contracts are different, this will be considered a different Pool. This design ensures that the status and operations of different Pools can be managed independently and ensures Pool consistency. But at the same time, the complexity of routing increases as the number of Pools increases (perhaps UniswapX is one of the ways designed to solve this problem).

TL;DR
- Flash Accounting is used to track the changes in the quantity of each Token and ensure that all changes are reset to zero after the transaction is completed. In order to save Gas costs, Flash Accounting uses the special storage method provided by EIP1153.
- The design of the Singleton Contract helps reduce gas consumption because it avoids updates to multiple stored variables.
- The Hooks architecture provides additional operations, divided into "pre-execution" and "post-execution" phases. This makes each Pool operation more flexible, but also makes Pool routing more complex.
UniswapV4 obviously places more emphasis on expanding the entire Uniswap ecosystem and building it into infrastructure so that more services can be built on the basis of Uniswap Pool. This will help enhance Uniswap's competitiveness and reduce the risk of substitution by other services, but whether it can be as successful as expected requires further observation. Some of the highlights include the combination of Flash Accounting and EIP1153, and we believe that more services will adopt these features in the future, with many different application scenarios emerging. This is the core concept of UniswapV4, and we hope this will give everyone a deeper understanding of how UniswapV4 operates. If there are any errors in the article, you are welcome to correct them, and you are also welcome to discuss and exchange opinions.
Finally, thanks to Anton Cheng and Ping Chen for their help in reviewing the article and giving valuable comments!

