Concepts
Sealed orders
How commit and reveal keep the order queue hidden during the lull, what a commitment binds, and what becomes public when.
A Lull order goes on chain twice. During the lull you commit to it, and only a hash goes on chain. In the reveal window before the open you reveal it: the fields go on chain, and the program checks them against the hash.
Commit#
When you click "Seal order", your browser:
- generates a salt of 32 random bytes;
- hashes the order fields together with the salt, your wallet address and the lull;
- stores the fields and the salt in this browser;
- sends a transaction, signed by your wallet, that records the hash and posts the bond.
No tokens move, and nothing is locked. The service that runs Lull never receives the salt or the fields.
What the commitment binds#
- Tag13 bytesThe text “lull:v1:order”, which separates orders from LP quotes6c756c6c3a76313a6f72646572
- Side1 byte0, a buy00
- Amount8 bytes1,000,000,000 raw quote: 1,000 USDC × 10⁶00ca9a3b00000000
- Limit8 bytes0: market on open0000000000000000
- Salt32 bytesRandom, drawn in this browser. Whoever holds it can reveal the order.…
- Owner32 bytesExample owner: ……
- Lull32 bytesExample lull: ……
order: sha256("lull:v1:order" ‖ side ‖ amount ‖ limit ‖ salt ‖ owner ‖ lull)
quote: sha256("lull:v1:quote" ‖ spread ‖ max base ‖ max quote ‖ salt ‖ owner ‖ lull)
The leading tag separates orders from LP quotes. owner is your wallet address and lull is the lull's on-chain address. Because every field is inside the hash:
- The order cannot change. Revealing any other side, amount or limit produces a different hash, and the program rejects it.
- It belongs to one wallet and one lull. It locks and fills that wallet's balance, in that lull only.
- It cannot be guessed. The salt has 256 random bits, so nobody can recover the order by hashing likely candidates.
- A reveal needs no owner signature. The salt is the authorization. Anyone holding it can reveal the order exactly as sealed, and nobody can alter it.
Reveal#
In the reveal window (open − 30 min to open − 1 min by default), the app builds the reveal transaction with the order fields left blank, and your browser fills them in. The program recomputes the hash, checks the market minimum and locks the amount in the owner's balance. The service learns your order when the reveal lands on chain, at the same moment as everyone else. See Reveal.
Why seal at all#
During the lull, xStock pools are thin. A visible queue of orders for the next open would let anyone trade ahead of it. Sealed, the queue shows only that some wallets placed tickets. Side, size and the imbalance stay hidden until the reveal window.
What is public, and when#
| Information | Public from |
|---|---|
| That your wallet placed a ticket in this lull, and its bond | commit |
| Whether the ticket is an order or an LP quote | reveal (both post the same bond) |
| Side, amount and limit, or spread, max base and max quote | reveal |
| The book's imbalance | builds up as reveals land during the window |
| Popen and every fill | the cross |
| Deposits and withdrawals | always |
How long the imbalance is public#
The imbalance is readable from the first reveal until the cross:
exposure ≤ (open − reveal start) + open delay + capture time
With default parameters that is 30 minutes, plus 30 seconds, plus the few seconds the capture takes: at most about 30.5 minutes. Lull measures this interval on every lull.
Two things limit what a watcher can do with it. Popen is Pyth's price of the underlying stock in its regular session, not a pool price, so trading an xStock pool does not move it. And your fill does not depend on when you reveal: the heavy side fills pro rata, so there is nothing to gain by revealing first or last.
One option remains: a wallet that sealed an order could watch the imbalance and then decline to reveal. Doing so forfeits the bond, which is what the bond is for. See Bonds and forfeits.