The DUCAT maneki-neko, holding a Monero coin
peer-to-peer proximity commerce · spec draft 1.1.0-dev13

DUCAT

Veilid for transport. Monero for settlement. No operator in between.

There is no DUCAT server anywhere — contacts, messages, bills and receipts are DHT records and end-to-end sealed payloads, and every phone runs a full Veilid node, giving back the routing and storage it takes.

0 conformance vectors 0 operating modes 0 languages 0 servers

Debug-signed, stagenet only. Not for real money — yet.

Standing on

Commerce with nobody in the middle

A ducat was a gold coin accepted from Venice to Vienna to the Levant for six centuries — no issuer relationship, no account behind it, no permission attached. DUCAT is that, for standing in front of someone and doing business.

🐱

No server anywhere

Contacts, bills, payments and receipts travel as end-to-end sealed payloads over Veilid's DHT. There is nothing to subpoena, rate-limit, de-platform or shut down, because there is nothing running. Every phone is a full node, giving back the routing and storage it takes.

🔑

Identity is a keypair

Made on the phone. No email, no phone number, nobody to register with — which is also why nobody can restore it for you, and the app says that out loud instead of burying it.

🎫

Claim-once cards

You hand someone a card — QR, ducat: link, or an NFC tap — and it is good for one person. Once claimed it stops working, so a screenshot that ends up somewhere else is not a way in.

🔒

Sealed conversations

X3DH-shaped encryption with one-time prekeys and forward secrecy. When the app has to fall back to the signed prekey, it shows you an open lock rather than hiding it.

💬

Conversations that carry money

Mailbox-based threads that work while either side is offline — carrying itemised bills whose lines must sum to their total or the message is refused, payments, and receipts issued by the payee pointing at the transaction they acknowledge. Small groups fan out into the same pairwise threads: no group key, no shared record, every thread property unchanged.

Six steps, no account,
about a minute

Every screenshot on this page is the app running on a phone, not a mockup. Nothing here asks you to sign up, because there is nobody to sign up with.

Step 1 of 6: create your identity — a keypair made on this phone, no account
1 · Identity — a keypair, not a signup
Step 4 of 6: choose a PIN, with the no-reset warning stated plainly
4 · A PIN — and no way to reset it, said plainly
Step 5 of 6: how strangers trust each other — both sides stake, finishing returns it
5 · Trust — explained before your first deal
Step 6 of 6: the backup, honestly not a backup yet until it leaves the phone
6 · Backup — “not a backup yet” until it leaves the phone

Your identity is a keypair made on the device — no email, no phone number, nobody to register with, which is also why nobody can restore it for you. The last step is the backup, because a wallet you cannot restore is the one way a person actually loses money here.

Money that is yours

A self-custodial Monero wallet with fiat conversion throughout, scanned and spent by an embedded monero-oxide engine — no wallet daemon on the phone.

Personal home: balance in XMR and USD, sync state, spendable-notes counter, mode tiles and recent movements
The balance, and the notes behind it
Paying or requesting: amount in fiat or XMR, fee arithmetic, what is left afterwards
The whole arithmetic before you commit
The statement: running balance, receipt search, CSV export
A statement rebuilt from the chain
Picking who to pay: contacts listed with their key fingerprints
Who you're paying, by key fingerprint

Paying shows the amount, the estimated network fee, the total, what you have left afterwards, how many notes it spends and roughly how long it will take — and lets you pick a speed. History is rebuilt from the chain: sends identified by key image, change never shown as income, every row carrying the running balance, and the whole statement exportable as CSV.

Monero spends discrete notes rather than a balance, so a wallet holding one big note can be unable to pay twice in a row. The app counts the notes it can spend and tells you to break one before you are standing at a counter, rather than failing there.

Conversations that carry money

A contact is a keypair, not an identifier. One scan opens a mailbox-based conversation that works while either side is offline — and those threads carry commerce, not just text.

Your card: a claim-once QR that opens a conversation, good for one person
Your card — good for one person
A conversation carrying money: itemised bill with a tax line, the receipt, a settled-escrow banner
A bill, a payment, a receipt — in the thread
A group of three on a shared board: one record per generation, a question and its answer from another phone
Groups — one shared board per generation
Searching what people said, with name hits ranked above message hits
Search what people actually said

You hand someone a card — by QR, ducat: link, or an NFC tap — and it is good for one person: once claimed it stops working, so a screenshot that ends up somewhere else is not a way in.

A group is a roster that only grows, and its words ride one shared board record per generation (§16.24): every member writes its own pages under a group key the roster carries, so a message to five people is one write instead of five, and the record cannot be told apart from any other by the network. Nobody can forge as anyone else, and leaving is local. A group can split a bill — one total becomes a pairwise request to each person plus a sentence everyone can check the arithmetic against, and each request flips to paid as its reference lands.

Your phone is the whole business

Pick one of nine modes and the entire app hands over — its own tabs, nothing of the wallet's. Almost none of it needed a new wire object, which is the spec's proudest sentence.

Operating modes: personal, point of sale, bar tab, taxi, donations, marketplace, renting, hire help, kiosk
Nine modes, one protocol
Point of sale: items rung up with a computed sales-tax line
Point of sale — with the tax computed
One code for the customer to scan; the itemised bill lands on their phone
One code — the bill lands as they scan
Bar tabs: open tabs, billed-and-waiting, closed with one bill
Bar tabs — settle from the bus home
Kiosk mode, customer side: tap what you want, tax shown before you commit
Kiosk — the customer orders for themselves
Kiosk staff panel behind a PIN: orders, menu, and the tax rate
Staff panel behind a PIN
A standing donation code, with its linkability cost stated on screen
Donations — with the cost named

A point of sale rings up items or takes a typed total, computes the sales tax for its region, and shows one code; the bill arrives on the customer's phone the moment they scan it, and a receipt goes back when they pay. A bar tab pings every drink to the customer and closes with one bill. A kiosk hands the phone to the customer entirely, with a staff panel behind a PIN. A donation box offers both rails — a DUCAT code that opens a conversation and sends a receipt once the money arrives, and a standing address any Monero wallet can give to, with its linkability cost stated on the screen rather than in a policy.

A ride, with nobody dispatching it

Type where you are going. Your phone turns a GPS fix into a geocell — a public bulletin board whose address is the place itself — and posts a hail: a claim-once card, a coarse area, and an offer priced from the real driving route. No name goes on the board — not on the card, not in the record behind it. Drivers watch their cell and its neighbours and claim it; the DHT referees the race, and no matchmaker exists.

The green line is the point: DUCAT's rates sit about 15% under a rideshare's rider-side rates, and the driver keeps all of it — the absent platform cut, handed to both of them. Acceptance arrives with a face on it: name, car, colour, plate, ETA — sealed to the rider, never shown to the board. Your own name and the doorway you are standing at go the other way at the same moment, to the one driver who claimed.

One trade, stated plainly on screen: address search, routing and map tiles query OpenStreetMap — the single place DUCAT sends location off-device. The boards themselves never carry better than ~1.2 km.

Hailing a ride: route, distance, time, and the fare against what a rideshare would charge
The hail, priced against the rideshare
The taxi meter: rate typed once, a pickup code, terms landing in the chat at start
The meter, with terms in the thread

Sell it, rent it, or offer an hour of your time

The same board machinery carries more than rides. A marketplace listing, a rental, or an hour of skilled help all post to a bulletin board addressed by the neighbourhood, and a stranger nearby reads it without either of you touching a platform.

Listings sit on coarser boards than hails — about five kilometres across, because people will travel to collect a set of keys. Searching reads your board and the ring around it, drawing results as each one answers, so something parked near you is on screen in under six seconds while "nothing listed around here" takes about forty and counts the areas off as it goes.

Marketplace browse: a listing found on the board, with price, stakes and an Ask about it button
Marketplace
Hire help browse: a skill offered nearby, priced per hour
Hire help
Listing a vehicle to rent: the public half that goes on the board
The public half — what the board can read
Only for whoever books it: the address and handover details never go on the board
The private half — never on the board
Finding gear nearby: a live listing with price per day and the stake
Finding it — price, stake, and a way to ask

The listing form is split in two and the app tells you which half is which: everything in the first part goes on a public board anyone nearby can read, and the address, where the keys are, and the plate go in the second, which never leaves your phone until a booking is real.

A home, a feed,
and a shelf of your own

The records that carry a bill carry a page just as well. Your key is already an address, so what you write has somewhere to live without asking anyone for room.

The Feed: posts from the people you keep, and your own home
The feed — posts from the people you keep
The Library: issues filed by publisher, saved out rather than opened
The library — issues filed by publisher
Worldwide: publications on topic boards, with Everything reading every shelf at once
Worldwide — topic boards, every shelf at once
A listing opened: its bundle's pictures, the seller's description, the price they typed beside today's conversion
A listing opened — its pictures, and the price they typed

A persona's home sits at the address its own key names, and the feed is the timeline of the people you keep — a post can carry a picture and a file, and hearts come back. Sites are served from disk by whoever published them and open in a sealed room, so reading one fetches nothing from anywhere else.

Publications — a newspaper, a serial, a piece of software — are sold worldwide on topic boards rather than by neighbourhood: a post lands on the topic's board and on its language's board both, and "Everything" reads all six shelves side by side. A listing fetches its bundle from the seller's own phone — up to 24 photographs at full size, a description, specs and attached files — refused whole on any key it does not name, so a bad document cannot hide good pictures.

You both put up a stake.
Finishing gives it back.

There is no company in the middle to take sides, so DUCAT does something simpler. The money sits in an address only the two of you can open, and the release hands each side their own stake back by name. Nobody can take a stake — including us, because there is no us to pay.

~10% a ride short, low damage exposure
~20% a place to stay keys to someone's home
~30% a vehicle damage can exceed the price

Those numbers are argued rather than guessed — Bisq's 2-of-2 no-custodian model is the closest working precedent, and the dual-deposit literature proves the arrangement cheat-proof at equilibrium. Two bounds fall out: a stake worth less than the fee to return it becomes zero rather than decoration, and none exceeds half the price. The exposed side funds second, so their money never sits alone in a shared address.

⅔

Escrow with no company behind it

When a deal wants more than a bond: rider, driver and a mutually trusted arbiter contact run a distributed key generation over the sealed thread — three devices derive one Monero address, each holding only a share, any two able to sign, no dealer anywhere. The happy path is two taps.

Anything else is a settlement: either side proposes a split, the other signs or counters. A stranded party asks the arbiter, whose co-signature is the ruling — a captured arbiter can at worst pick between the named parties, never pay itself. Chain-proven on stagenet in every shape, including a two-input FROST release.

∅

What a name cost

Before there is any deal there is a stranger, and the question is what their name cost them. A persona may burn Monero — send it to an address nobody holds the keys to, derived from a hash anyone can recompute — and carry Monero's own payment proof for it. Your client checks that proof against its own node, asks a second node whether the transaction is in a block, and from then on shows the persona in words wherever you decide something: burned 0.01 XMR, since block N. Never a score. The rule that matters is the warning: when what you are about to risk is worth more than what they burned, the app says so, because a name that cost nothing has nothing to lose by vanishing.

After a settled deal either side may sign a rated receipt, and anyone you have met in person may sign a vouch. Both travel in a sealed thread and both are weighed by the reader alone — one voice per signer, counting only signers whose own burn you verified, and counting a vouch only from people already in your contacts. One hop, no graph, nothing published anywhere. Reputation that costs money instead of privacy.

And it behaves like an app

A privacy tool that is unpleasant to use gets used once. This one names what things cost you, speaks twenty languages, and has a dark theme that isn't an afterthought.

Profile: the linkability cost of letting contacts pay you directly, stated where you choose it
Costs named at the moment you choose
The same home screen in the Mocha dark theme
Mocha — the dark theme, done properly
The same home screen in Arabic: a full right-to-left mirror with Eastern Arabic numerals
Arabic — a full RTL mirror
The business half of settings: fares region, sales-tax rate, privacy, backup
The business half of settings

Convenience has a price in a privacy system, and the app names it at the moment you choose rather than in a policy nobody reads. Letting contacts pay you directly means reusing one address — so it says that anyone watching the chain can tell the same person was paid each time, including people who only ever paid you once, and points at the alternative. The same habit runs through: a mempool sighting is shown as seen, never settled; a profile is always presented as the claim it is.

It speaks twenty languages — every screen reads from resources, plurals are composed rather than concatenated, and Arabic and Farsi prove the mirror. Receipts are records, not messages: every receipt lives in its own store, survives thread and contact deletion, and rides the encrypted backup — which carries the people as well as the money.

The same application on a desk

A native window over the same Rust the phone runs — so a shopkeeper's till, a kiosk, the press room, the market and the feed are one implementation, not a port.

The desk's Chat page: groups on boards above the pairwise threads, with a conversation pane
Chat — groups on boards, above the pairwise threads
The desk's till: a sale rung up, and bar tabs
The till — a sale rung up, and the bar tabs
The desk's Market page: listings near a cell with their thumbnails
The market — listings near a cell, with their thumbnails
The desk's Status page: the node, its routing table, Reconnect, the log
Status — the node, its routing table, Reconnect

It speaks the phone's twenty languages from the same resources, and is proven against the phone across every rite: chat, groups on boards, bills and receipts, a kiosk order paid from a phone that had never met the desk, files and sites served and fetched, and calls with real sound.

What is proven, and what is not

The README keeps a ledger of what has actually run end-to-end on the live network and live stagenet — and states the gaps rather than burying them.

Demonstrated end to end
  • Two complete dispatched rides phone↔desktop — geocell hail to on-chain settlement, tip and receipt — and the bonded ride since driven to the end on two phones
  • The full escrow arc — two phones and a desk arbiter derived one 2-of-3 address independently; fund → release → driver paid
  • A booking — owner and guest each funding stakes, the pot confirmed by the guest's own scan, split proposed, signed, both sides whole; it resumed rather than restarting when a Monero node timed out mid-run
  • Bar tab phone-to-desktop, bill to receipt; ten attacks refused
  • A phone wiped to nothing walked through setup, first card, first payment, a kiosk sale paid end to end — then wiped again and restored from its own backup
  • Every escrow rail through the UI in one day — a marketplace sale, a street hail with live position crossing phones, a gear rental, and a hire-help job whose first run surfaced and fixed a real race
  • The trust layer, walked rather than argued — a burn proved and checked against a stranger's own node in 12 s, a rated receipt weighed correctly at zero, four desks concluding “2 of your contacts know this person”, and a nameless hail card named by the introduction that followed it
Stated, not buried
  • No review by anyone outside the project — §2.5 is the argument for why that matters; an internal pass over five surfaces found forty-odd things and fixed most, which is a lesser thing
  • No implementer who has never read core/
  • NFC compile-verified, never field-tested between two phones — and the tap never measured on a handset
  • Latency figures measured on a desktop with an attached node, not a handset on a battery
  • Two radios, two batteries, two independent clocks — the field day is still owed
  • The desk has no second factor — no device lock and no secret of its own, so the phone's spend gate cannot run there
!

Pre-alpha. Stagenet. Not for real money.

Every build is debug-signed and settles on Monero's stagenet — coins with no value, by design. The spec is draft 1.1.0-dev13 and says of itself: nothing here is final, and §14 is the real agenda. Try it, break it, read it — just don't fund it.

The spec is the product.
Everything else keeps it honest.

ducat-protocol.md is the primary artifact — five parts, a changelog first, and a conformance suite that a second implementation runs so the document cannot drift from the code silently.

★ ducat-protocol.md   the spec — draft 1.1.0-dev13, changelog first
  core/               reference implementation (Rust)
  vectors/            406 conformance cases + schema
  conformance/        four checkers, run on every push
  harness/            end-to-end over real Veilid routes
  sim/                offline simulator, market scenarios
  applications/       android/ + desktop/ (same sources)
  mobile/             the Rust bridge: wallet · mailbox · node
  research/           evidence, not product

Four checkers, every push

  • Every vector validated against schema.json
  • A second implementation runs all 406 and must agree
  • The document audited against the code — it has caught a normative section referenced three times and never written, a field range the registry did not declare, and six vector kinds the document never named
  • Nothing imported goes undeclared

Stewardship is normative, not aspirational: §18.7 makes Veilid's ethic a conformance requirement — no protocol fees, no node payment, ever. Build anything you like from this code, but a client that monetizes carriage is not DUCAT.

Get it on a phone,
or on a desk

Nothing to install first — every build carries its own Rust library and JVM. Android on a phone, and the same application as a native window on Linux, Windows and macOS. There is no iOS build; it gets a folder when it earns one.

🤖 Android

Phone browser, newest build, no release page to navigate. armeabi-v7a only for phones older than about 2016; x86_64 is for emulators.

🐧 Linux

The .deb and .rpm install as packages; the AppImage just runs.

🪟 Windows

Unsigned — Windows will warn on first open.

🍎 macOS

Apple Silicon and Intel builds. Unsigned — macOS will warn on first open.

Debug-signed, stagenet only — not for real money.