Developers
Socket on Uniswap v4
How Socket's hooks, registry, governor and buyback sit on Uniswap v4's PoolManager, and how the buyback share is taken from collected fees.
Socket is a set of Uniswap v4 hooks and the contracts around them, on Robinhood Chain. Every pool lives in Uniswap's PoolManager. Socket's contracts decide what some of those pools do, which hooks Socket's app routes through, and where a share of their LP fees goes.
One PoolManager#
PoolManager is a singleton: one contract holds every v4 pool and its tokens. A router that integrates v4 once reaches every pool, whatever hook it has.
Each operation runs inside unlock. PoolManager calls back the contract that unlocked it, which swaps, adds or removes liquidity, and pays or takes what it owes. Swaps and hooks record what each party owes or is owed as deltas, and the call settles them at the end. If anything is left unsettled, or any hook call reverts, the whole transaction reverts and nothing moves.
The pool key#
A pool is identified by its key. Its id is the hash of the key.
struct PoolKey {
Currency currency0; // the lower currency, sorted numerically
Currency currency1; // the higher currency
uint24 fee; // a static LP fee, or 0x800000 for a dynamic fee
int24 tickSpacing; // 1 to 32,767
IHooks hooks; // address(0) for no hook
}- Native ETH is currency
address(0). - LP fees are in hundredths of a basis point: 1,000,000 is 100%, and 3,000 is 0.30%.
- The key is immutable, so a pool's hook is fixed for its life.
PoolManager doesn't store keys. Its Initialize event carries the full key of each new pool.
Prices, ticks and positions#
| Property | Value |
|---|---|
| Price | 1.0001^tick, currency1 per currency0 in raw units |
| Stored as | sqrtPriceX96, the square root of the price in Q64.96 |
| Ticks | −887,272 to 887,272 |
| Tick spacing | 1 to 32,767 |
| Positions | ERC-721 tokens from PositionManager |
Socket's contracts#
| Contract | Does |
|---|---|
DynamicFeeHook | Sets each swap's LP fee from recent price movement. See Dynamic fee. |
TwapHook | Records the pool's tick for a time-weighted mean. See TWAP oracle. |
RangeOrderHook | Holds limit orders and takes them out of the pool when filled. See Range order. |
HookRegistry | The allowlist and the listing stakes. It also holds the buyback share that new pools on Socket's hooks take. |
SocketGovernor + timelock | Deposit-based voting with SOCKET. The timelock is HookRegistry's authority. |
Buyback | Receives the buyback share and can only swap toward SOCKET and burn it. |
How they fit:
- A pool on the TWAP or range-order hook is created through PoolManager, like any v4 pool. A dynamic-fee pool is created through
DynamicFeeHook.createPool, which stores its settings and initializes it in one call. Either way the pool takes the buyback shareHookRegistryholds at that moment and keeps it for life. HookRegistry.isListed(address hook)tells the app, and any router, which hooks to route through. Pools with no hook are always routable.- SOCKET holders vote through
SocketGovernor. A passed vote waits 2 days in the timelock, then anyone can execute it. ThroughHookRegistry, a vote can list or remove a hook, burn a removed hook's stake, or set the buyback share for pools initialized afterwards. Buybackreceives the share from the hooks and turns it into burned SOCKET.
The buyback share#
A pool on a Socket hook keeps a share of the LP fees its positions collect. It is 20% today. SOCKET holders can set it from 0% to 50% for pools created after a vote. Each pool keeps the share it was initialized with.
The share is taken when fees are collected:
A position changes
Any change of a position collects its fees, including a removal of zero liquidity, which is how fees are collected.
The hook sees the fees
PoolManager calls afterAddLiquidity or afterRemoveLiquidity with
feesAccrued, the fees the position collects in that call.The hook takes its share
With the returns-delta flags, the hook returns the share of
feesAccruedas its delta. PoolManager subtracts it from what the position receives.The share goes to Buyback
The hook sends its share to the
Buybackcontract.
In a pool with a 20% share, a position that collects 100 USDG of fees receives 80 USDG, and 20 USDG goes to Buyback. Swaps and quotes are untouched: swappers pay the pool's fee, and LPs collect the rest of it. Pools on external hooks, and pools with no hook, keep no buyback share. No key holds the fees on the way.
The Buyback#
Anyone can run the Buyback:
- It swaps what it holds toward SOCKET, through v4 pools with no hook or a listed hook. It goes through ETH or USDG first when a token has no SOCKET pool.
- One run moves a pool's price by at most 0.25%.
- Each input token runs at most once every 10 minutes.
- It burns all the SOCKET it holds.
The Buyback can only swap toward SOCKET and burn it.
What no vote can do#
- Change an existing pool. v4 pool keys are immutable.
- Move tokens out of PoolManager or anyone's position.
- Pause trading.