Uniswap V4 uses a singleton contract for all token pairs. The name of this contract is PoolManager, and the source code can be found in the v4-core repository.
Like the white paper in Part I, the source code for PoolManager.sol is remarkably short.
I will cover the most relevant parts of the contract from top to bottom, starting with imports and inherited functionality, then reviewing the functions specific to PoolManager.
Imports and Inheritance
The import block is fairly tidy, bringing several clearly-named aliases and structs from various libraries, contracts, and interfaces in the repo:
import {Hooks} from "./libraries/Hooks.sol";
import {Pool} from "./libraries/Pool.sol";
import {SafeCast} from "./libraries/SafeCast.sol";
import {Position} from "./libraries/Position.sol";
import {LPFeeLibrary} from "./libraries/LPFeeLibrary.sol";
import {Currency, CurrencyLibrary} from "./types/Currency.sol";
import {PoolKey} from "./types/PoolKey.sol";
import {TickMath} from "./libraries/TickMath.sol";
import {NoDelegateCall} from "./NoDelegateCall.sol";
import {IHooks} from "./interfaces/IHooks.sol";
import {IPoolManager} from "./interfaces/IPoolManager.sol";
import {IUnlockCallback} from "./interfaces/callback/IUnlockCallback.sol";
import {ProtocolFees} from "./ProtocolFees.sol";
import {ERC6909Claims} from "./ERC6909Claims.sol";
import {PoolId} from "./types/PoolId.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "./types/BalanceDelta.sol";
import {BeforeSwapDelta} from "./types/BeforeSwapDelta.sol";
import {Lock} from "./libraries/Lock.sol";
import {CurrencyDelta} from "./libraries/CurrencyDelta.sol";
import {NonzeroDeltaCount} from "./libraries/NonzeroDeltaCount.sol";
import {CurrencyReserves} from "./libraries/CurrencyReserves.sol";
import {Extsload} from "./Extsload.sol";
import {Exttload} from "./Exttload.sol";
import {CustomRevert} from "./libraries/CustomRevert.sol";
In all, PoolManager imports 24 contracts — 11 library contracts, 3 interface contracts, 5 type contracts, and 5 contracts in the src directory used for direct inheritance.
The top level declarations tell us a lot about the structure of the contract:
contract PoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909Claims, Extsload, Exttload {
using SafeCast for *;
using Pool for *;
using Hooks for IHooks;
using CurrencyDelta for Currency;
using LPFeeLibrary for uint24;
using CurrencyReserves for Currency;
using CustomRevert for bytes4;
int24 private constant MAX_TICK_SPACING = TickMath.MAX_TICK_SPACING;
int24 private constant MIN_TICK_SPACING = TickMath.MIN_TICK_SPACING;
mapping(PoolId id => Pool.State) internal _pools;
/// @notice This will revert if the contract is locked
modifier onlyWhenUnlocked() {
if (!Lock.isUnlocked()) ManagerLocked.selector.revertWith();
_;
}
...
}
Inherited Behavior
PoolManager inherits from these contracts to implement functionality for specific tasks:
Events, structs, and the external function interfaces, from IPoolManager.sol
Functions to set, modify, and collect pool fees, from ProtocolFees.sol
Modifiers that prevent delegate calls, from NoDelegateCall.sol
Multi-token methods proposed in ERC-6909 (a minimal alternative to ERC-1155), from ERC6909Claims.sol
An implementation in the spirit of EIP-2330 that would allow external contracts to retrieve storage values from a given slot using a lightweight external method, from Extsload.sol
The same EIP-2330 access implementation described above but for transient storage, from Exttload.sol
Type Libraries
The Solidity statement using SomeLibrary for SomeType
indicates that the compiler will expose the functions in SomeLibrary
as if they are methods on SomeType
. This is documented in the Using For sub-section of Solidity’s Contracts documentation page.
The first two statements are wildcard applications which which apply the SafeCast and Pool libraries to all types. :
using SafeCast for *;
using Pool for *;
SafeCast includes functions that convert between integer types. Whenever we see a statement like some_value.toInt256()
will substitute the toInt256
function from the library with the argument set to some_value
.
The functions, errors, and types in Pool are concerned with the operations of an individual pool — calculating swap amounts, modifying liquidity positions, updating tick and price values, etc.
We don’t expect that the functions in these libraries are applicable to every type in the contract, so this is merely a convenience for the contract authors and we assume they are applying the library functions only where appropriate.
The remaining library applications are more focused:
using Hooks for IHooks;
using CurrencyDelta for Currency;
using LPFeeLibrary for uint24;
using CurrencyReserves for Currency;
using CustomRevert for bytes4;
These libraries are found in the src/libraries subfolder of the repo. I’ll cover some of the interesting ones in more detail.
Hooks Library
The comment at the top of the library contract tells us some very interesting things about how V4 uses it:
Keep reading with a 7-day free trial
Subscribe to Degen Code to keep reading this post and get 7 days of free access to the full post archives.