darkbookDocs

03DarkBook documentation

Privacy model

Two fields are sealed and everything else is published. This page lists each one, says when it becomes public, and ends with the claims this venue does not make.

Read fromdocs/PRIVACY_MODEL.mdstate.rs:244-256state.rs:281-296ix/settlement.rs:66-71

The claim is narrow on purpose. DarkBook hides the pre-trade exact size of an order and nothing else. Side, price, leverage, declared band and trader pubkey are on the order account from the moment it is placed, and the position that opens at settlement carries the exact size in the clear. A reader who wants to know whether this venue protects something they care about should find that thing in the tables below rather than infer it from the word private.

Order fields

Read from programs/darkbook/src/state.rs:244-256. Every field listed as public is on the OrderBook account and in the OrderPlaced event, so a mempool observer and a competing trader reading the book see the same set.

FieldStatusPublic fromWhy it is there
order_idPublicplace_ordermatching and cancel lookup
traderPublicplace_ordercollateral lock and settlement binding
sidePublicplace_ordera CLOB cannot match without it
price_ticksPublicplace_ordera CLOB cannot match without it
size_bandPublicplace_orderlets a maker price a worst case, and sets the collateral taken
leverage_bpsPublicplace_ordercollateral math and risk
commitmentPublicplace_orderbinds the exact size without revealing it
placed_slotPublicplace_ordertime priority
size_lotsHiddenclaim_fillthe value the whole design exists to seal
saltHiddenclaim_fillwithout it the commitment is brute-forceable over plausible sizes

size_lots and salt are never written to the order account at all. They exist off-chain with the trader and reach the chain once, as arguments to claim_fill.

Fill fields

Read from programs/darkbook/src/state.rs:281-296. A fill is written by match_orders on the rollup and lives in the committed OrderBook account, so every field on it is public from the match, before any claim. This is the table people usually assume is smaller than it is.

FieldStatusPublic fromWhy it is there
fill_idPublicmatch_ordersclaim lookup
taker_order_idPublicmatch_ordersbook provenance
maker_order_idPublicmatch_ordersbook provenance
takerPublicmatch_ordersbinds the user account at claim
makerPublicmatch_ordersbinds the user account at claim
price_ticksPublicmatch_ordersthe matched price
taker_size_bandPublicmatch_ordersbounds the taker's revealed size at claim
maker_size_bandPublicmatch_ordersbounds the maker's revealed size at claim
claimedPublicmatch_ordersreplay guard
matched_slotPublicmatch_ordersordering

Both legs' declared ceilings are on every fill. An observer watching the tape between the match and the claim knows the counterparties, the price, and a factor-of-8 bound on each side's size.

Threat model

The question each row answers is whether that adversary can size a sandwich exactly, which is the attack the commitment is aimed at.

AdversarySeesCan read the exact size
Public mempool observerplace_order instruction fields and eventsNo, commitment only
Competing trader reading the bookevery Order fieldNo, not until the claim
MagicBlock rollup validatorthe full delegated OrderBook accountNo, unless it is given the salt
Fill-tape observer, post-match pre-claimevery Fill field, both legs' bandsNo, bounded to within a factor of 8
Settler servicethe plaintext size, by constructionYes. This is trusted, not defended
Post-settlement observerthe Position accountYes. The profit and loss path is public by design

The commitment

Computed off-chain by the trader, published on the order, recomputed by the program at cancel and at settlement. The same helper produces it in all three places.

rust
// programs/darkbook/src/ix/orders.rs
pub fn compute_commitment(
    salt: &[u8; 32],
    size_lots: u64,
    leverage_bps: u16,
    trader: &Pubkey,
) -> [u8; 32] {
    let mut hasher = Sha256::new();
    hasher.update(salt);
    hasher.update(size_lots.to_le_bytes());
    hasher.update(leverage_bps.to_le_bytes());
    hasher.update(trader.to_bytes());
    hasher.finalize().into()
}

Leverage appears both in the clear on the order and inside the hash, so a trader cannot swap leverage at reveal time and change the collateral arithmetic after the fact. The trader pubkey is inside the hash too, which is what makes a cancel self-authorising: the order's own trader is the single party who can produce a matching preimage.

What is not claimed

These are the claims this venue is not making. They are listed here and in docs/PRIVACY_MODEL.md, which is the file any marketing copy has to stay inside.

  • Not a dark pool. Price and side are public on every order from placement.
  • Not identity privacy. The trader pubkey is on the order and on both legs of the fill. There is no zero-knowledge identity layer.
  • Not flow privacy. The fill tape after settlement leaks magnitude, and since the per-leg band fix each fill publishes both sides' declared ceilings. Pre-trade exact size is the entire claim.
  • Not trustless. A settler holds plaintext sizes to submit a claim, and a compromised rollup operator is outside the guarantee.
  • Not free. Size privacy costs the taker about 0.2 bps of half-spread on the live schedule, measured rather than assumed.
  • Not a benefit sold to makers. Under size blindness makers quote wider, not tighter. The study found the opposite of the comfortable version of this story.