Uniswap V4 went live today! Deploying right before a weekend is a huge flex, and I thank their engineers for their service while sending condolences for their rekt sleep this weekend.
I had a blast writing the Uniswap V3 series, and I’m excited to dig into the details of the new protocol right as it goes live. While the announcement linked above is nice, I always prefer to start with the protocol white paper. These are typically authored by the developers who built the protocol, and refreshingly light on marketing. Technically inclined people can gain a lot of value from a reading these first, then by working through the official documentation and the repositories.
The V4 White Paper is remarkably brief at 4 pages, contrasting sharply against the 9 page V3 White Paper and 10 page V2 White Paper.
A key reason for the brevity is that Uniswap V4 is primarily an extension to V3. If you’ve already worked through my Uniswap V3 Series, you’ll feel right at home with the general architecture of V4.
Introduction
V4 is described as non-custodial, non-upgradable, and permissionless. This approach often leads to a mixture of similar contracts as a protocol ages. The non-upgradable nature of these contracts means that bug fixes require a new deployment of peripheral contracts like the Quoter and Routers [1, 2]. Uniswap is good about maintaining a list of deployments, but much of the complexity is hidden behind the front-end of the Uniswap app.
The core contracts for V2 and V3 have been robust so far, and have not required emergency action. I hope V4 maintains this winning streak!
The key sections of the white paper are presented below with my comments.
Hooks
A hook is an externally deployed contract that can modify pool parameters and add new functionality by executing some contract-defined logic at a specific point during a pool action. This can alter the behavior of many pool actions.
The authors list these examples of hook functionality:
Executing large orders over time through TWAMM
Onchain limit orders that fill at tick prices
Volatility-shifting dynamic fees
Mechanisms to internalize MEV for liquidity providers
Median, truncated, or other custom oracle implementations
Constant Product Market Makers (Uniswap v2 functionality)
This certainly introduces a lot of complication!
The design of these hooks appears to be similar to the V2 Balancer Pool model, which used the same “hook” name for external calls to execute pool-specific logic.
I am interesting to discover how Uniswap might expose the behavior of these hooks from their immutable deployment given that the hook contracts are deployed by third parties.
Action Hooks
When a pool is created, a single hook contract can be defined which can implement up to ten hook callbacks:
beforeInitialize / afterInitialize
beforeAddLiquidity / afterAddLiquidity
beforeRemoveLiquidity / afterRemoveLiquidity
beforeSwap / afterSwap
beforeDonate / afterDonate
The paper describes upgradeable hooks, so it appears that the hook contract may vary its execution when certain modes are set, provided that it maintains the invariants required by the callback. This sounds very similar to the V3 Swap and Flash callbacks.
The paper includes a swap hook flow showing the beforeSwap and afterSwap hooks, each followed by an invariant check.
Hook-Managed Fees
The hooks can also implement custom fee logic in addition to those imposed by the base pool contract. This section specifies that hook-managed fees are limited by immutable flags specified during pool creation, though we will need to look further to learn how far “limited” actually goes.
Singleton & Flash Accounting
Previous versions of Uniswap used a pattern whereby all new pools were tracked and deployed by an immutable factory contract.
This necessarily leads to the problem of sparse liquidity. WETH is typically used as the “glue” token that allows you to swap between multiple pools.
The upside of swapping between multiple pools is that you have multiple routes to trade between any given pair of coins, even if they do not share a common pool. The downside is that each separate pool introduces a high gas cost from ERC-20 transfers. This makes for expensive swaps between multiple tokens, and has lead to the rise of DEX aggregators that optimize the routing for users.
V4 takes a different approach, instead choosing to implement all pools within a single contract. Since one contract holds the balance for all tokens, no external transfers are necessary except for the swap input and output.
The balance storage approach is very similar to the Balancer V2 Vault, which holds all token balances in one contract and the swap accounting is done by separate pools.
The accounting for V4 is done using transient storage opcodes implemented by EIP-1153 in the Cancun hardfork. Transient storage allows for arbitrary data to survive multiple contract calls within a transaction, while retaining the familiar storage ergonomics without the associated high storage costs or relying on passing calldata around. I covered using Low Level Storage here last week, and Transient Storage Using Vyper last year, which was integrated into recent bot projects to Optimize Uniswap Pool Transfers.
Native Pairs
The WETH “glue” described above necessarily requires wrapping and unwrapping Ether on one side of the swap.
The advantages of using Ether over WETH are obvious:
Transferring Ether is less expensive to transfer compared to an ERC-20 transfer of WETH, and can be attached “free” in a transaction
Swapping with Ether does not require a separate approval transaction
The paper does not say whether WETH pairs are still supported. If they are, I’m curious if a token can have two V4 pairs (Ether and WETH), or if the singleton just treats everything like Ether and enforces an unwrap.
The press release mentions the process for migrating a liquidity position from V3 → V4, and notes that is requires two separate actions.
Custom Accounting
The paper describes the ability of hook contracts to perform custom accounting for all pool actions. An intriguing option presented directly by the paper is the ability to implement the V2 pool invariant in a V4 pool.
I think this flexibility is quite nice, and the complexity of managing V3 positions for low liquidity tokens is a barrier to entry. I expect that OpenZeppelin or others will begin developing a set of boilerplate hook contracts for this kind of behavior.
This modularity-by-hook approach is likely to be a huge win for Uniswap, assuming it’s as flexible as the paper suggests.
What’s Next?
Now that I’ve churned through the white paper, I’ve set my sights on the Github v4-core contracts repo and will begin working through the critical components and doing some console exploration of the live exchange.