DARKHOOK — the programmable privacy hook layer for onchain markets. Put money in your private account, swap from it, take it out anywhere. The pool's hook refuses any swap that does not come from — and go back into — the private account.
DARKHOOK plugs into Socket, the hook-based AMM on Solana. Socket calls the hook before every swap on a DARKHOOK pool, and the hook decides who may trade: only the private account. The hook is open — anyone can plug it into a new pool.
Who swaps. Every swap is made by a one-time wallet paid from the private account, with a zero-knowledge proof that never says which deposit it came from. Your balance inside the account is hidden too.
Only what you choose: putting money in, and taking it out to a wallet of your choice. Swap sizes on the pool are public — but not whose. Everything in between stays inside the private account.
The hook reads the whole transaction and refuses any swap that is not funded from the private account and settled back into it. The rule is fixed when the pool is created — no website, admin or router can switch it off.
Five steps, one hook, zero changes to the AMM underneath.
Your wallet puts SOL or USDC into the private account. You get a secret note.
PUBLIC · AMOUNT INYour browser proves you own a note — not which one — for the amount you want to swap.
At before swap the hook checks: paid from the private account, settled back into it. Otherwise: refused.
A one-time wallet swaps on the Socket pool; a relayer pays the fees. Your wallet never signs.
The whole output goes back in as a new note. Withdraw any part, to any wallet, whenever you want.
YOUR CHOICEA small Rust hook guards every swap, a zero-knowledge private account holds the funds, and a TypeScript SDK builds deposits, proofs and private swaps for wallets, bots and apps.
// programs/gate-hook — the rule Socket runs before every swap pub fn check_private(ixs: &[Ix], current: usize, pool: &Pubkey, shield: &Pubkey) -> Result<(), GateError> { let swap = &ixs[current]; // must be a direct Socket swap on this pool if swap.program_id != SOCKET_PROGRAM_ID || &swap.accounts[1] != pool { return Err(NotADirectSwap); } let swapper = swap.accounts[0]; // 1. the money comes out of the private account, earlier in this transaction let funded = ixs[..current].iter().any(|ix| ix.program_id == *shield && ix.tag == Some(WITHDRAW) && is_swapper_or_its_token_account(&ix.accounts[3])); if !funded { return Err(NotFundedFromVault); } // 2. everything the swap returns goes back in, later in this transaction let settled = ixs[current + 1..].iter().any(|ix| ix.program_id == *shield && ix.tag == Some(DEPOSIT_ALL) && ix.accounts[0] == swapper); if !settled { return Err(NotSettledToVault); } Ok(()) }
// sdk — swap a private note into the other asset, without your wallet import { buildSpendWitness, formatProof, buildPrivateSwapMessage, privateSwapPayout, newNoteSecrets, noteInner, } from "@darkhook/sdk"; const temp = Keypair.generate(); // one-time wallet, holds funds only inside the tx const payout = privateSwapPayout({ from: "SOL", temp: temp.publicKey, relayer, usdcMint }); // 1 — prove: one of the notes is mine; pay 1 SOL to the swap, keep the rest as change const w = buildSpendWitness({ note, leaves, amount: 1_000_000_000n, fee, ...payout }); const { proof } = await snarkjs.groth16.fullProve(w.input, "/zk/spend.wasm", "/zk/spend.zkey"); // 2 — one transaction: withdraw → swap on the gated pool → deposit-all back const out = newNoteSecrets(); // the output note's secrets const msg = buildPrivateSwapMessage({ socketPool, usdcMint, relayer, temp: temp.publicKey, from: "SOL", proof: formatProof(proof), root: w.root, nullifierHash: w.nullifierHash, changeLeaf: w.changeLeaf, amount: 1_000_000_000n, fee, outputInner: noteInner(out), minOut, }, blockhash, lookupTable); // 3 — the one-time wallet signs, the relayer co-signs and pays: your wallet never appears
The DARKHOOK app talks straight to Solana mainnet: no account, no backend holding your keys. Connect Phantom only to put money in — the rest needs no signature.
Any amount of SOL or USDC from your wallet. Your browser keeps a secret note for it — download a backup: the note is the key to the funds.
Pick an amount and swap SOL ⇄ USDC. The app proves your note in the browser, a one-time wallet trades on the DARKHOOK pool and the whole result goes back into your account as a new note. Your wallet is not in the transaction.
Send any part to any wallet; the relayer pays the fees and the rest stays private. Rounder amounts and a little patience make you harder to match.
Phase A is live: the private account and an open hook anyone can plug into a SOL/USDC Socket pool. Next come private accounts for any token; then swap sizes disappear too.
A zero-knowledge private account (Groth16, Poseidon Merkle tree, private amounts with change) and the DARKHOOK hook: every swap on a hooked pool is funded from the account and settled back into it. The hook is permissionless — anyone can launch a private SOL/USDC market today. Relayer included, launch caps while it is young.
Private accounts for any SPL token, so private markets can trade any pair. A "launch a private market" button and a list of hooked pools in the app; Socket allowlist for routing.
Swaps settled in sealed batches inside the private account, so sizes are hidden too; a view key discloses on demand. External audit, multisig authority, higher caps, optional association sets to prove funds are clean without revealing which deposit is yours.