SocketDocs

Overview

How Socket works

A Uniswap v4 pool, the hook in its key, the permissions in the hook's address, and the order a swap runs in.

A pool#

Every pool Socket uses is a Uniswap v4 pool. All v4 pools live in one contract, PoolManager, which holds every pool's tokens. A pool is a concentrated-liquidity market for two tokens, sorted by address into currency0 and currency1. Native ETH is address(0), so a pool can trade it without wrapping. The pool's price is the amount of currency1 one currency0 buys, in base units, stored as a Q64.96 square root. Liquidity providers deposit into a price range; their liquidity only trades, and only earns fees, while the price is inside that range.

A pool is identified by its key. Every field of it is fixed when the pool is initialized:

FieldWhat it is
currency0, currency1The two tokens, sorted by address.
feeThe LP fee in hundredths of a basis point (3,000 is 0.30%), or 0x800000, the dynamic-fee flag, which lets the hook set it.
tickSpacingThe grid positions sit on, from 1 to 32,767 ticks.
hooksThe hook contract, or address(0) for none.

The starting price is set at initialization; liquidity added afterwards sets where it trades. A pool on one of Socket's hooks also fixes, in the transaction that initializes it:

SettingWhat it is
Buyback shareThe share of collected LP fees the hook sends to the Buyback, read from HookRegistry: 20% today.
Fee settingsFor the dynamic fee: the base fee, the max fee and the settings of the fee curve, chosen by the pool's creator.

A hook#

A hook is a contract PoolManager calls at fixed points of a pool's life:

  • Initialize, before and after the pool is created.
  • Add liquidity and remove liquidity, before and after every position change.
  • Swap, before and after every swap.
  • Donate, before and after a donation to the pool's liquidity.

The hook receives the pool's key, the call's parameters and any hookData the caller passes. The after-calls also see the result: afterSwap gets the swap's balance change, and afterAddLiquidity and afterRemoveLiquidity get the position's balance change and feesAccrued, the fees the position collects in that call.

A hook changes amounts in two ways. In a pool whose fee is the dynamic-fee flag, the hook sets the LP fee, and beforeSwap can return an override for this swap, marked with 0x400000. With a returns-delta flag, a call can return a delta that changes what the caller settles: a swap's amounts, or what a position change pays in or out.

When the hook itself calls PoolManager for its pool, its own callbacks aren't called.

Permissions#

The lowest 14 bits of a hook's address are its permissions. PoolManager makes only the calls whose bits are set:

BitValueFlag
138192beforeInitialize
124096afterInitialize
112048beforeAddLiquidity
101024afterAddLiquidity
9512beforeRemoveLiquidity
8256afterRemoveLiquidity
7128beforeSwap
664afterSwap
532beforeDonate
416afterDonate
38beforeSwapReturnDelta
24afterSwapReturnDelta
12afterAddLiquidityReturnDelta
01afterRemoveLiquidityReturnDelta
  • A returns-delta flag needs its call's flag. PoolManager won't initialize a pool whose hook breaks that rule.
  • A hook gets its bits by being deployed with CREATE2 at a mined salt. Different permissions mean a different address, so a different contract.
  • The address is part of the pool key, so a pool's permissions never change.

0x…15C30b01010111000011

  • Dynamic feethis one
  • TWAP oraclethis one
  • Range order0x…1543

Socket's built-in hooks set these flags:

HookFlags
Dynamic feeafterInitialize, beforeSwap, afterSwap, and the four buyback flags
TWAP oracleafterInitialize, beforeSwap, afterSwap, and the four buyback flags
Range orderafterInitialize, afterSwap, and the four buyback flags

The four buyback flags are afterAddLiquidity, afterRemoveLiquidity, afterAddLiquidityReturnDelta and afterRemoveLiquidityReturnDelta. None of the built-in hooks has a swap returns-delta flag. A swap through them pays the pool's LP fee, which only the dynamic-fee hook sets.

The order a swap runs in#

  1. Pool keyRouterNames the pool: two currencies, the fee, the tick spacing and the hook address. The address's last 14 bits say which calls PoolManager makes.
  2. Before swapHook, flag 128Reads the pool. In a dynamic-fee pool it may return this swap's LP fee; with flag 8 it may also return a delta.
  3. SwapPoolManagerMoves the price through the active ranges and accrues the LP fee. No hook runs here.
  4. After swapHook, flag 64Sees the result. With flag 4 it may take from or add to the swap's other side. The range-order hook takes filled orders out here.
  5. SettleRouterPays what the swap owes and takes what it is owed, once, at the end of the unlock. Below the swapper's minimum output, it reverts.
If any stop reverts, the whole transaction reverts: no fee taken, no price moved, no tokens sent.

A swap runs inside one unlock of PoolManager. The router calls unlock, PoolManager calls back into the router, and the router calls swap. PoolManager calls beforeSwap if the hook's address sets it, runs the pool math, then calls afterSwap. Each step records what each party owes or is owed. The router pays in what it owes and takes out what it is owed. If anything is left unsettled when unlock ends, or any hook call reverts, the whole transaction reverts and nothing moves. Only the gas is spent.

Socket's app quotes every route through v4's Quoter and executes through the Universal Router with Permit2. The router checks the minimum output you sign after the swap, whatever the pool's hook did. The app routes only through pools with no hook or a hook on the allowlist.

Liquidity#

Positions are ERC-721 tokens from PositionManager. A position holds one range and its liquidity, and earns its share of the LP fee in both tokens. Any change of a position collects its fees, including a removal of zero liquidity, which is how fees are collected. Adding and removing liquidity run the liquidity hooks the hook's address sets, which is how a hook can enforce a lockup, admit only certain ranges or track incentives.

In a pool on one of Socket's hooks, afterAddLiquidity and afterRemoveLiquidity receive the position's feesAccrued. The hook takes the pool's buyback share of it and sends that to the Buyback contract, which can only swap toward SOCKET and burn it. The position collects the rest. Swaps and quotes are untouched. Pools on External hooks, and pools with no hook, keep no buyback share. See The buyback.

Deposits round up and withdrawals round down, so rounding never takes value from the pool.

Socket's contracts#

ContractDoes
DynamicFeeHookThe dynamic fee.
TwapHookThe TWAP oracle.
RangeOrderHookRange orders.
HookRegistryThe allowlist, the listing stakes, and the buyback share new pools on Socket's hooks take. Its authority is the governance timelock.
SocketGovernor + timelockVoting with deposited SOCKET.
BuybackReceives the buyback share. It can only swap toward SOCKET and burn it.

See Socket on Uniswap v4 for how they connect.

What a hook can't do#

These bounds come from PoolManager, not from the hook's good behavior:

  • It isn't called at points its address doesn't set.
  • It can't change a swap's or a position's amounts without the matching returns-delta flag.
  • It can't set a swap's fee unless the pool's fee is the dynamic-fee flag.
  • It can't leave a balance unsettled: anything owed when unlock ends reverts the whole transaction.
  • It can't change its own permissions: they are its address.
  • It can't make a swap pay less than the minimum output you sign: the router reverts it.

The app routes only through pools with no hook or a hook SOCKET holders listed. See Limits for each bound in detail.

Public documentation snapshot · 9 October 2026 · Original page ↗
LOCAL REPLICA · DOCUMENTATION SNAPSHOT