
Uniswap V4
- 9 installs
- 4 repo stars
- Updated February 25, 2026
- hairyf/blockchain-master
Integrate Uniswap v4 core - the singleton PoolManager, unlock/callback flow, pool actions (swap, liquidity, donate), hooks, and types.
About
Uniswap v4 is an AMM with a singleton PoolManager where interactions flow through unlock and unlockCallback and settle balance deltas. A developer uses it to build contracts that swap, manage liquidity, or attach hooks.
- Singleton PoolManager with unlock -> unlockCallback flow
- Pool actions (swap, liquidity, donate) and lifecycle hooks
Uniswap V4 by the numbers
- 9 all-time installs (skills.sh)
- Ranked #319 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Jul 13, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hairyf/blockchain-master --skill uniswap-v4Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 9 |
|---|---|
| repo stars | ★ 4 |
| Last updated | February 25, 2026 |
| Repository | hairyf/blockchain-master ↗ |
What it does
Integrate Uniswap v4 core - the singleton PoolManager, unlock/callback flow, pool actions (swap, liquidity, donate), hooks, and types.
Files
Skill based on Uniswap v4 Core (Uniswap/v4-core), generated at 2026-02-09.
Uniswap v4 is an AMM with a singleton PoolManager: all pool state lives in one contract. Interactions go through unlock → unlockCallback, where callers perform swaps, liquidity changes, and donations, then settle balance deltas before the callback returns. Pools can attach hooks for lifecycle callbacks (initialize, add/remove liquidity, swap, donate).
Core References
| Topic | Description | Reference |
|---|---|---|
| Architecture | Singleton, unlock/callback flow, delta settlement | core-architecture |
| Unlock callback | IUnlockCallback, when to use unlock, security | core-unlock-callback |
| Pool actions | initialize, swap, modifyLiquidity, donate, take, settle, sync, mint, burn, clear | core-pool-actions |
| Types | PoolKey, PoolId, Currency, BalanceDelta, ModifyLiquidityParams, SwapParams | core-types |
Features
Hooks
| Topic | Description | Reference |
|---|---|---|
| Hooks | IHooks lifecycle, address-based flags, before/after callbacks | features-hooks |
Generation Info
- Source:
sources/uniswap-v4 - Git SHA:
d153b048868a60c2403a3ef5b2301bb247884d46 - Generated: 2026-02-09
Uniswap v4 Core Architecture
v4-core uses a singleton design: all pool state lives in a single PoolManager.sol. Pool actions (swap, modifyLiquidity, donate, etc.) are only allowed inside an unlock; the caller must implement IUnlockCallback.unlockCallback and settle net balances before the unlock ends.
Unlock flow
1. Caller calls poolManager.unlock(data). 2. PoolManager calls back IUnlockCallback(msg.sender).unlockCallback(data). 3. Inside the callback, the caller may call swap, modifyLiquidity, donate, take, settle, mint, burn on the PoolManager. 4. During the unlock, only net deltas are tracked (owed to user = positive, owed to pool = negative). 5. When the callback returns, all currency deltas must net to zero; otherwise the manager reverts with CurrencyNotSettled().
So: any positive delta (user is owed) must be matched by take; any negative delta (user owes) must be matched by settle/settleFor or by sending tokens and calling sync before settle. Pool initialization can be done outside an unlock.
Key points
- Single entry: All state-changing pool actions go through
unlock→unlockCallback. This gives one reentrancy boundary and lets callers batch many actions in one unlock. - Delta semantics:
BalanceDeltais (amount0, amount1) as int128s; positive = owed to caller, negative = owed to pool. Sum over an unlock must be zero per currency. - No direct transfers: You don’t transfer tokens to the pool before a swap. You perform the swap (which updates deltas), then
take/settle/mint/burnto clear them. - ERC20: Call
sync(currency)before sending ERC20s to the manager so it can compute deltas; native currency can be settled viasettle()withmsg.value.
Usage
import {IPoolManager} from 'v4-core/src/interfaces/IPoolManager.sol';
import {IUnlockCallback} from 'v4-core/src/interfaces/callback/IUnlockCallback.sol';
contract MyRouter is IUnlockCallback {
IPoolManager public poolManager;
function swapAndSettle(PoolKey memory key, SwapParams memory params, bytes calldata hookData) external {
poolManager.unlock(abi.encode(key, params, hookData));
}
function unlockCallback(bytes calldata data) external override returns (bytes memory) {
if (msg.sender != address(poolManager)) revert Unauthorized();
(PoolKey memory key, SwapParams memory params, bytes calldata hookData) = abi.decode(data, (PoolKey, SwapParams, bytes));
BalanceDelta delta = poolManager.swap(key, params, hookData);
// Settle: pay negative deltas (e.g. transfer in), take positive (withdraw).
_settleDelta(delta);
return "";
}
}<!-- Source references:
- https://github.com/Uniswap/v4-core (README.md – Architecture)
- sources/uniswap-v4/README.md
-->
Pool Manager Actions
All actions below (except initialize and updateDynamicLPFee) must be called from within unlockCallback.
Initialize
initialize(PoolKey key, uint160 sqrtPriceX96) → int24 tick
Creates the pool state. Can be called outside unlock. Enforces currency0 < currency1, tickSpacing > 0 and ≤ type(int16).max, and fee rules. Emits Initialize.
Swap and liquidity
- swap(
key,SwapParams params,hookData) →BalanceDelta swapDelta
Executes a swap. params: zeroForOne, amountSpecified (negative = exact in, positive = exact out), sqrtPriceLimitX96. Returns the caller’s balance delta. Fee is capped; 100% fee would make exact-out impossible.
- modifyLiquidity(
key,ModifyLiquidityParams params,hookData) →(BalanceDelta callerDelta, BalanceDelta feesAccrued)
Adds or removes liquidity in the given tick range. Use liquidityDelta == 0 to “poke” (update position without changing size). feesAccrued is informational and can be gamed (e.g. self-donate).
- donate(
key,amount0,amount1,hookData)
Donates to in-range LPs at the pool’s current tick. Can be front-run with just-in-time liquidity.
Settlement (clearing deltas)
- sync(
Currency currency)
Checkpoints the manager’s current balance for currency. Must be called before sending ERC20 to the manager when you intend to settle that currency; optional for native (zero address).
- take(
currency,to,amount)
Sends amount of currency from the manager to to, decreasing the caller’s positive delta. Reverts if not enough balance. Can be used for flash loans (take → use → settle).
- settle() payable →
uint256 paid
Pays the manager: for native currency, use msg.value; for ERC20, transfer tokens to the manager first (after sync), then call settle(). Credits the caller’s negative delta.
- settleFor(
recipient) payable →uint256 paid
Same as settle but credits recipient’s delta.
- mint(
to,id,amount)
Moves amount of currency (id = uint160 currency address) from manager balance into ERC6909 balance of to; use to settle by minting LP or hook tokens.
- burn(
from,id,amount)
Burns ERC6909 and increases manager’s balance; use to pay in by burning.
- clear(
currency,amount)
Zeros a positive manager balance without transferring; tokens are locked forever. Amount must equal the exact positive balance. For dust only.
Errors (selection)
CurrencyNotSettled,PoolNotInitialized,AlreadyUnlocked,ManagerLockedCurrenciesOutOfOrderOrEqual,TickSpacingTooSmall/TickSpacingTooLargeSwapAmountCannotBeZero,NonzeroNativeValue,MustClearExactPositiveDelta
<!-- Source references:
- https://github.com/Uniswap/v4-core
- sources/uniswap-v4/src/interfaces/IPoolManager.sol
- sources/uniswap-v4/README.md
-->
Core Types and Params
PoolKey and PoolId
- PoolKey:
currency0,currency1(must be sorted:address(currency0) < address(currency1)),fee(uint24, max 1_000_000; high bit set = dynamic fee and must be 0x800000),tickSpacing(int24),hooks(IHooks). - PoolId:
bytes32; computed askeccak256(abi.encode(poolKey)). UsePoolIdLibrary.toId(poolKey).
Currency
- Currency: custom type over
address.address(0)is native (ETH). UseCurrencyLibraryfor transfer, balance, and ERC6909 id conversion (toId/fromId).
BalanceDelta
- BalanceDelta: packed
(int128 amount0, int128 amount1)in one int256. Positive = owed to the holder (e.g. caller or hook), negative = owed to the pool. Helpers:toBalanceDelta(amount0, amount1),BalanceDeltaLibrary.amount0/amount1,ZERO_DELTA; operators+,-,==,!=.
Operation params
- ModifyLiquidityParams:
tickLower,tickUpper(int24),liquidityDelta(int256),salt(bytes32 for unique positions in same range). - SwapParams:
zeroForOne(bool),amountSpecified(int256; negative = exact input, positive = exact output),sqrtPriceLimitX96(uint160; swap stops at this price).
Usage
PoolKey memory key = PoolKey({
currency0: Currency.wrap(token0),
currency1: Currency.wrap(token1),
fee: 3000,
tickSpacing: 60,
hooks: IHooks(address(0))
});
PoolId id = key.toId();
ModifyLiquidityParams memory params = ModifyLiquidityParams({
tickLower: -60,
tickUpper: 60,
liquidityDelta: 1e18,
salt: bytes32(0)
});
SwapParams memory sp = SwapParams({
zeroForOne: true,
amountSpecified: -1e18, // exact in
sqrtPriceLimitX96: sqrtPriceLimit
});<!-- Source references:
- https://github.com/Uniswap/v4-core
- sources/uniswap-v4/src/types/PoolKey.sol
- sources/uniswap-v4/src/types/PoolId.sol
- sources/uniswap-v4/src/types/Currency.sol
- sources/uniswap-v4/src/types/BalanceDelta.sol
- sources/uniswap-v4/src/types/PoolOperation.sol
-->
Unlock and Unlock Callback
Pool state-changing actions (swap, modifyLiquidity, donate, take, settle, mint, burn) are only callable while the PoolManager is unlocked. The manager unlocks by calling back the caller’s unlockCallback.
Interface
interface IUnlockCallback {
function unlockCallback(bytes calldata data) external returns (bytes memory);
}unlock(data): Only the PoolManager may callunlockCallback; it passes the samedatathe caller gave tounlock. Return value ofunlockis the return value ofunlockCallback.- Reverts:
ManagerLocked()if a pool action is used without an active unlock;AlreadyUnlocked()ifunlockis called reentrantly;CurrencyNotSettled()if any currency delta is non-zero when the callback returns.
Callable from outside unlock
initialize(PoolKey, sqrtPriceX96)— create a new pool.updateDynamicLPFee(PoolKey, newDynamicLPFee)— only by the pool’s hook, and only for pools with dynamic fees.
Everything else that moves balances or pool state must run inside unlockCallback.
Security
- At the start of
unlockCallback, enforcemsg.sender == address(poolManager)so only the singleton can trigger the callback. - In the same callback, perform all pool actions and then settle all deltas (take/settle/sync + transfer) so no currency is left unsettled.
<!-- Source references:
- https://github.com/Uniswap/v4-core
- sources/uniswap-v4/src/interfaces/callback/IUnlockCallback.sol
- sources/uniswap-v4/src/interfaces/IPoolManager.sol (unlock, errors)
-->
Hooks in Uniswap v4
Pools can attach a hooks contract that runs at defined points in the pool lifecycle. Which callbacks run is fixed at pool creation and encoded in the hooks contract’s deployment address: the PoolManager reads the least significant bits of that address to decide which hooks to call. The hook contract must be deployed to an address whose low bits match the chosen flags (see the Hooks library in the repo for the bit layout).
Callbacks (IHooks)
All return bytes4 selector for validation; some also return deltas or fee overrides.
- beforeInitialize / afterInitialize — before/after pool state is initialized. After receives
tick. - beforeAddLiquidity / afterAddLiquidity — add liquidity. After receives caller
delta,feesAccrued, and can return a BalanceDelta (hook’s own delta in token0/token1). - beforeRemoveLiquidity / afterRemoveLiquidity — remove liquidity. Same delta/fees pattern as add.
- beforeSwap / afterSwap — swap. Before can return BeforeSwapDelta and optional lp fee override (only when pool has dynamic fee and override bit set). After can return int128 (hook delta in unspecified currency).
- beforeDonate / afterDonate — donate.
Which of these are invoked is immutable per pool: determined by the hooks address at initialization. The hook logic (e.g. what the hook does in afterSwap) can be upgradeable if the hook contract is designed that way, but you cannot add or remove which callbacks are called for an existing pool.
Practical notes
- Hooks are optional:
hooksinPoolKeycan beaddress(0). - Only the PoolManager should call hook methods; implement access control accordingly.
- Hook-returned deltas are part of the same unlock settlement: hook owes pool (negative) or pool owes hook (positive), and must be settled by the end of the unlock.
<!-- Source references:
- https://github.com/Uniswap/v4-core
- sources/uniswap-v4/src/interfaces/IHooks.sol
- sources/uniswap-v4/README.md (Architecture – hook callbacks)
-->