Docs

Overview

How Socket works

A pool, the hook plugged into it, the permissions that bound the hook, and the order a swap runs in.

A pool#

A Socket pool is a concentrated-liquidity market for two classic SPL tokens, called A and B. The mints are sorted by their public-key bytes, so every pair has exactly one order. The pool's price is the amount of B one A buys, in atomic units, stored as a Q64.64 square root. Liquidity providers deposit into a price range; their liquidity only trades, and only earns fees, while the price is inside that range.

Each pool has its own two vaults. Tokens never pool across markets, and no account outside the program can move them.

What a pool fixes at creation and keeps forever:

SettingWhat it is
TokensMint A and mint B, sorted.
Starting priceThe first square-root price. Liquidity added afterwards sets where it trades.
Tick spacingThe grid positions must sit on, from 1 to 32,768 ticks.
Base feeThe fee a swap pays when no hook sets one, in parts per million.
Max feeThe highest fee a hook may set, at most 100,000 ppm (10%).
Hook programOne executable, or none.
PermissionsWhich hook points the hook runs at and what it may change.
Surcharge capThe largest input surcharge a hook may add, at most 1,000 bps (10%) of the swap's input.
Hook computeThe most compute one hook call may use before Socket rejects its result.
Hook accountsUp to eight extra accounts the hook needs, with their owners and write access.

A hook#

A hook is any Solana program that answers Socket's callback. Socket calls it by cross-program invocation at fixed points:

  • Before swap, before any pool math runs.
  • After swap, after the math and before tokens move.
  • Before liquidity and after liquidity, around every deposit and withdrawal.

The hook receives the pool account read-only, a signer that proves the call came from Socket for this pool, and its own extra accounts. It never receives a vault, a position account or the user's signature. It answers with a small reply: an optional fee for this swap, and an optional input surcharge.

Permissions#

The permission mask is six bits. The first four choose the hook points, the last two grant powers:

BitNameEffect
1Before swapThe hook is called before each swap.
2After swapThe hook is called after each swap.
4Before liquidityThe hook is called before each deposit and withdrawal.
8After liquidityThe hook is called after each deposit and withdrawal.
16Fee overrideThe before-swap reply may set this swap's fee, up to the pool's max fee.
32Input surchargeThe after-swap reply may add a charge, up to the pool's surcharge cap.

Points the mask leaves out are never called. A reply that uses a power the mask doesn't grant fails the transaction.

190b010011

  • No-opany mask
  • Dynamic feefits
  • TWAP oraclefits
  • Range orderneeds 15

The order a swap runs in#

  1. AccountsRouter10 fixed accounts plus the hook's extras, read from the pool's discovery account.
  2. Before swapHook, bit 1Reads the pool. With fee override (16) it may set this swap's fee, up to the pool's max fee.
  3. CLMMSocketMoves the price through the active ranges and takes the LP fee. No hook runs here.
  4. After swapHook, bit 2Sees the result. With input surcharge (32) it may add a charge, up to the pool's surcharge cap.
  5. SettleSocketTokens move once. A surcharge is held apart for the pool creator, never mixed with LP funds.
If any stop fails, the whole transaction reverts: no fee taken, no price moved, no tokens sent.

A swap is one Solana instruction and one transaction. Every hook call happens inside it, so a hook that fails, overspends its compute or replies out of bounds reverts the whole swap. Nothing is charged and nothing moves. Routers rely on that: a failed simulation simply means the route goes elsewhere.

Liquidity#

Positions are program accounts derived from the pool, the owner and a nonce. A position holds one range and its liquidity, and accrues its share of the LP fee in both tokens. Adding and removing liquidity run the before- and after-liquidity hooks when the mask wires them, which is how a hook can enforce a lockup, admit only certain ranges or track incentives.

Deposits round up and withdrawals round down, so rounding never takes value from the pool. The few atomic units of dust that rounding leaves stay in the vaults.

What a hook can't do#

The bounds are enforced by Socket, not by the hook's good behavior:

  • It can't move tokens: it never sees a vault or the user's signature.
  • It can't set a fee above the pool's max fee, or add a surcharge above the cap.
  • It can't run past the pool's hook compute without the swap being rejected.
  • It can't call back into the pool: the pool is locked while the hook runs.
  • It can't change its own permissions, caps or accounts after creation.

What it can do inside those bounds is the reason to check a pool's hook before you trade in it. See Bounds for each limit in detail.