The hook
The DarkHooks hook is the dark pool inside Uniswap v4. Each listed pair has a v4 pool, base against USDG, that holds no liquidity and never shows a curve. Every swap in it carries one agent's signed two-sided quote as hookData; in beforeSwap the hook settles that quote through DarkDesk.fill, with itself as the taker, and hands the result back to the PoolManager as a BeforeSwapDelta. The swap is a real Uniswap v4 swap through the real PoolManager, routable by the Universal Router or any v4 router, and the side still exists only inside it.
Addresses
| DarkHooks | 0xb9662EA9819b6068d62d771dB3A473E5012B2888, Sourcify exact match, deployed in 0xaa217bb82f6e… |
| PoolManager | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Universal Router | 0x8876789976dEcBfCbBbe364623C63652db8C0904 |
| Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
Pools
| Pair | Pool id | Key |
|---|---|---|
| NVDA / USDG | 0x78f73e72be97586c68a14b2295490b90f397e4911504bceadff01d2bdf31e6f9 | fee 0, tick spacing 1, hooks DarkHooks |
| SPY / USDG | 0x57471330dfd7725b4f67072b5ffb16d8623fce9a7ec85978dc11cbeb170e2c19 | fee 0, tick spacing 1, hooks DarkHooks |
| TSLA / USDG | 0x8ac43cf2408a7f40da5a0b41fe300f6d04f8dbdfc4c009d91c339354211f6928 | fee 0, tick spacing 1, hooks DarkHooks |
| WETH / USDG | 0x721c2241f8eaa9d835d9c1cada2a8b7c4e523489036e2c84b033b046ee997d56 | fee 0, tick spacing 1, hooks DarkHooks |
Permissions
- beforeInitialize: only the owner, only fee 0 and tick spacing 1, only a listed base against USDG.
- beforeAddLiquidity: always reverts, so nothing ever feeds the curve.
- beforeSwap with beforeSwapReturnDelta: the specified delta always consumes the whole amountSpecified, so the PoolManager's own swap math runs on zero and the pool's price never moves.
The address ends in the permission bits 0x2888, mined with the CREATE2 deployer.
Modes
| Swap | Side on DarkDesk | Amounts |
|---|---|---|
| Exact in, base in | SELL at the bid | You pay the base amount, you receive the USDG leg minus the fee. |
| Exact out, base out | BUY at the ask | You receive the base amount, you pay the USDG leg plus the fee. |
| Exact in, USDG in | BUY at the ask | The hook buys the largest amount the input pays for, capped at the quote's size. At most 2 micro-USDG of rounding stays with the hook; more than that reverts. |
| Exact out, USDG out | none | Not supported: reverts. |
A swap with no hookData, a quote for another pair, an expired or already used quote, or a maker that cannot pay reverts the whole swap: nothing is left half done. DarkDesk charges its 5 bps fee to its caller, which is the hook, so the swapper pays it inside the swap's amounts. The $DARKHOOKS fee waiver looks at the caller, so it applies to direct fills, not to v4 swaps.
Through the Universal Router
Three v4 actions in one V4_SWAP command, exact in both ways. The input is paid before the swap, and the output is taken with the quoted amount as the minimum.
commands = 0x10 (V4_SWAP)
actions = 0x0b SETTLE(tokenIn, amountIn, payerIsUser = true)
0x06 SWAP_EXACT_IN_SINGLE(poolKey, zeroForOne, amountIn, amountOutMinimum,
minHopPriceX36 = 0, hookData = abi.encode(Quote, signature))
0x0f TAKE_ALL(tokenOut, amountOutMinimum)
deadline = the quote's expiryThe wallet approves the input token to Permit2 and Permit2 to the Universal Router once per token. The SDK builds everything locally:
import { BUY, SELL, best, requestQuotes, prepareV4, swapV4, PAIRS, USDG } from "./darkhooks.mjs";
await prepareV4(account, USDG); // once per token
await prepareV4(account, PAIRS.NVDA);
const rfq = await requestQuotes("https://darkhooks.app", "NVDA", "0.0002"); // no side
const receipt = await swapV4(account, best(rfq, BUY), BUY); // a v4 swapCalldata from the API
POST /api/darkhooks/swap with { quote, signature, side, amount? } returns ready-to-sign Universal Router calldata, the amounts and the approvals needed. The MCP endpoint has the same as darkhooks_swap_calldata, and GET /api/darkhooks lists the pools. Asking the server for calldata tells it your side a moment before you send; the app and the SDK build the calldata in your own browser or process instead.
Tested
Sixteen tests on a fork of the live chain, against the real PoolManager and DarkDesk: each direction with the base as currency0 and as currency1, each exact-in and exact-out mode, no hookData, expired and reused quotes, a quote for the wrong pair, exact out for USDG, overpaying, a maker that cannot pay, adding liquidity, who may initialize, the fee, and the pool's price unchanged after a swap. The first swaps on the live pools: a buy and a sell of NVDA through the Universal Router.
