How it works
Every step below is one instruction of the program. The names in code are the real instruction names.
1. Open an inbox
open_inbox(mint, bond, window, encryption_key) creates ["inbox", owner].
mint: USDC or wrapped SOL.bond: at least 1 USDC or 0.01 SOL.window: how long you take to answer, between 1 and 30 days, in seconds.encryption_key: your X25519 public key, not all zeros. The app derives it from a free wallet signature of a fixed text that starts withD00R message key, so you can regenerate it on any device.
update_inbox(mint, bond, window, key, accepting) changes the terms for future knocks. Setting accepting to false pauses the inbox. Knocks already open keep the terms they were sent under.
2. Knock
send_knock(bond, window, reply_key, message) is signed by the sender. It:
- Checks that
bondandwindowequal the inbox's current terms. If the owner changed them while the transaction was in flight, it fails withTermsChanged, so nobody is charged more or held longer than they saw. - Refuses an empty message or one over 560 bytes of ciphertext (531 bytes of text in the app's format).
- Refuses a knock on your own inbox (
OwnInbox) or on a paused inbox (InboxClosed). - Moves the bond into the mint's bond vault and adds it to
Treasury.outstanding. - Creates
["knock", recipient, sender], storing the ciphertext andexpires_at = now + window. - Adds one to the inbox's
receivedcounter and emitsKnocked.
Because the knock address is built from the pair, one sender can have only one open knock per inbox. There is no instruction to take a bond back early: a spammer could otherwise deliver the message and withdraw before it is read.
3. The three endings
Reply
reply(message), signed by the recipient, any time. The whole bond goes back to the sender. The reply ciphertext (0 to 560 bytes, encrypted to the knock's reply_key) stays in the transaction data only. An empty reply still counts as answered. The Knock account closes and its rent goes to the sender. replied goes up by one; event Replied.
Spam mark
mark_spam, signed by the recipient, only before expires_at. 95% of the bond goes to the recipient and 5% to the fee vault. The Knock account closes and its rent still goes to the sender. kept goes up by one and kept_amount for that mint by the full bond; event Kept.
Expiry
expire, anyone, at or after expires_at. The whole bond goes back to the sender, and the rent too. expired goes up by one; event Expired. An unanswered knock never becomes the recipient's money.
4. The burn
crank_burn(amount), anyone. Spends up to amount of the fee vault in the configured Raydium CP-Swap pool and burns every D00R bought, in one instruction. Limits:
- No worse than 98% of the pool's own 30-minute time-weighted price.
- At most 0.1% of the pool's input reserve per call.
5. Names
claim_name(name) burns name_price D00R and records the name for your inbox: one name per inbox, one owner per name. release_name frees it and refunds the record's rent; burned D00R stays burned.