Dark pool · settles on Uniswap v4
Visible size
is a tax.
Every order you broadcast tells the market what you need before you get it. Here, an order is a signature, not a transaction: it costs nothing, touches no chain, and dies on a bumped nonce. Nothing is public until you choose to settle.
Open the terminal§ 01
The split below
is the whole product.
A worked example, not a live book. The terminal shows what actually settles.
Solid means it crossed against someone who was already there: filled at the reference mid, no fee, no impact, nothing in the mempool. Hatched means it went to the Uniswap v4 pool like any other swap. Put 200 WETH through it and the two halves come out like this.
Crossed at the mid
128.40WETH
- Price
- $3,142.80 — the reference
- Slippage
- 0 bps
- Fee
- 0 bps
- Impact
- none — the curve never moves
You find out that your order filled. You never find out who was on the other side, and they never find out your size.
Routed to the pool
71.60WETH
- Price
- $3,125.55 — after impact
- Slippage
- 54.9 bps
- Fee
- 5 bps
- Impact
- the pool reprices
Ordinary, public, and visible in the mempool before it lands. This leg is the price of not waiting for a counterparty.
Blended that is 19.7 bps, against 143.5 bps if the whole 200 had gone to the pool.
$7,786 kept
§ 02
Four steps. Only the last one
touches a chain.
01
You sign. Nothing happens.
The order is a typed message sitting with the matching engine. No transaction, no gas, no approval spent, nothing in the mempool. It exists as a signature you can kill by bumping your nonce.
hashIntent(intent) → 0x9f2c…41ab // EIP-712, domain "Kryptis" v102
Someone takes the other side. Or nobody does.
Orders are matched against each other, never against a book anyone can read. A 128.4 WETH bid meets a 200 WETH offer and 128.4 crosses. The other 71.6 is not filled here, and we don't pretend otherwise.
sell 200.000 WETH ┐ ├─ cross 128.400 @ mid buy 128.400 WETH ┘ remainder 71.600 → public pool03
The match is attested.
Settlement carries a proof that the engine matched what it says it matched. Right now that proof is an attestation over the intent hash. It is a placeholder, the verifier is swappable, and a Groth16 circuit drops in without changing a byte of the ABI.
_verifyAttestation(proof, intentHash) require(bytes32(proof) == intentHash) // placeholder // → Groth16Verifier.verifyProof(a, b, c, input)04
It settles in one call, or not at all.
The contract re-checks the deadline, the nonce, the signer, the proof and the quote, then moves the tokens. Eleven checks. Any one of them fails and the whole thing reverts — you lose the gas and nothing else.
executeIntent(intent, signature, proof) → IntentSettled(intentHash, trader, tokenIn, …)
§ 03
We hide your order before it fills,
not after.
This is the part most privacy pitches skip, so here it is up front. Settlement is an ordinary ERC-20 transfer emitted by a contract anyone can read on Etherscan. What you get back is the window before the fill — the window where a searcher would have front-run you and the market would have learned your size.
On-chain, permanently
- IntentSettledthe event, with both token addresses
- traderthe settling address — it is msg.sender
- amountIn / amountOutthe exact sizes that moved
- intentHashthe digest, flagged as settled forever
Never published
- your order, before it fillsnothing in the mempool to snipe
- resting depthyou learn your fill, not the book
- cancellationsa bumped nonce says nothing
- what didn't crossunfilled size is never disclosed
Set in the coarse cut of Redaction, because that is what the chain gets: the shape of a thing, not the thing.
§ 04
One file. Eleven checks.
Read it before you sign anything. There is no admin path to your funds — the only privileged call moves the pool's own inventory, and the price feed is owner-set, which is fine for a testnet and not fine for money.
- Solidity
- 0.8.24
- Standards
- EIP-712 · ERC-20 · ReentrancyGuard
- Settlement
- atomic — one call, or it reverts
- Verifier
- attestation placeholder
- Audit
- none — research software
The guard rail
if (intent.amountIn == 0) revert ZeroAmount();
if (intent.tokenIn == intent.tokenOut) revert SameToken();
if (block.timestamp > intent.deadline) revert Expired();
if (intent.trader != msg.sender) revert Unauthorized();
if (intent.nonce <= usedNonces[trader]) revert NonceUsed();
if (intent.slippageBps != 0) revert Slippage();
if (settled[intentHash]) revert AlreadySettled();
address signer = ECDSA.recover(intentHash, signature);
if (signer != intent.trader) revert BadSignature();
if (!_verifyAttestation(proof, hash)) revert InvalidProof();
amountOut = quote(tokenIn, tokenOut, amountIn);
if (amountOut < intent.minAmountOut) revert Slippage();Line six is the opinionated one. The contract refuses any order that asks for slippage tolerance. If it can't fill you at the quoted price it doesn't fill you.
Don't take our word for it.
The pool, the deploy scripts and the tests are in the repository. Point it at a testnet and settle an order end to end. It takes about five minutes and costs nothing.
cd contracts
forge test
forge script script/DeployKryptis.s.sol \
--rpc-url $SEPOLIA_RPC_URL --broadcast