Inspiration
In Senegal, the natt (tontine) is how many people save. Market vendors, families and friends each put in the same amount every week or month, and one member takes the whole pot each round until everyone has had a turn. With $n$ members each paying $c$:
$$\text{pot} = n \times c$$
Every member pays $n \times c$ over the cycle and receives $n \times c$ once. Early receivers get an interest-free loan; later ones get forced savings. No bank needed.
But it runs on cash and trust. The organizer carries the money, records live in a notebook, members abroad struggle to send their share, and when someone disappears with the pot there is no proof of who paid what. I wanted to keep everything people love about the natt and remove the parts that go wrong.
What it does
Natt puts the tontine on Bitcoin Lightning:
- Pay by QR: each member pays their share from any Lightning wallet (Wallet of Satoshi, Phoenix, Blink…), from Dakar or from the diaspora, in seconds.
- Fair draw: when the group starts, the payout order is drawn with a cryptographic random number generator.
- Guarded payout: the pot is released only to the member whose turn it is, only after everyone has paid, and only to an invoice for the exact amount (or their Lightning address).
- Nobody can cheat: every payment and payout becomes a Nostr event signed with the group's key, each linking to the previous one. Anyone can verify the ledger; edit or delete a record and the chain breaks.
- Natt Helper: an AI assistant that answers "When is my turn?" or "Who hasn't paid?" in simple French, Wolof or English, with amounts in sats and FCFA. It works offline with built-in answers.
- WhatsApp reminders: the organizer taps 🔔 next to a late member and WhatsApp opens with a polite reminder ready to send.
- Made for real phones: a light installable web app, French by default, live FCFA rate, invites by WhatsApp.
How I built it
- Backend: Node.js, Express 5 and the built-in SQLite module, so there are no native dependencies and setup is one command (
npm run demoordocker compose up). - Lightning: a small wallet interface with two backends: LNbits for real sats, and a simulated wallet that signs real BOLT11 invoices so the demo works with no setup. Payouts accept invoices or Lightning addresses (LNURL-pay).
- Nostr: each group gets its own key, derived from a server secret. Receipts are kind 1 events chained by
etags and checked with nostr-tools. Publishing to relays is optional. - AI: Claude through the Anthropic SDK. The model sees only a structured summary of the group (first names, turns, paid or unpaid, no phone numbers), has no tools and cannot move money.
- Frontend: a plain JavaScript PWA with no framework, a strict Content Security Policy and no
innerHTMLwith user data. - Quality: 34 automated tests, a written threat model, and CI on GitHub Actions with Docker builds.
- I built it with Claude Code as my pair programmer, step by step in small commits.
Challenges I ran into
- Who holds the money. Between collection and payout, the server's Lightning wallet holds the pot. I made that window as small and guarded as possible: a payout state lock against double payment, exact-amount checks, and a key that can send money only for payouts. I also documented the trade-off honestly in the threat model.
- A demo that works without a node. Judges shouldn't need a funded wallet, so the simulated backend creates real, decodable BOLT11 invoices instead of fake strings.
- Security vs. simplicity. A strict CSP blocks inline styles, so even the progress bar had to be built without them. Logs redact phone numbers, invoices and keys.
- Wolof. Writing clear Wolof for financial actions is hard. The current text is a first draft that needs review by native speakers.
- Flaky networks. The live price feed sometimes times out, so the app falls back to the last good rate and retries after a minute.
Accomplishments that I'm proud of
- A complete tontine cycle works end to end: create, invite, draw, pay, guarded payout, next round.
- A public ledger anyone can audit, which turns "trust the organizer" into "check the receipts".
- One-command setup with a seeded demo group of five market vendors.
- An app in French, Wolof and English, made for the people who actually run natts.
What I learned
- How BOLT11 invoices, LNURL-pay and Lightning addresses work under the hood.
- How to make an append-only, tamper-evident log from signed Nostr events.
- The CFA franc is pegged to the euro (1 EUR = 655.957 FCFA), so a BTC/EUR price is enough for an accurate FCFA display.
- Designing for low-end phones and first-time Bitcoin users changes every decision, from wording to button size.
What's next for Natt: Lightning Tontines
- Less custody: hold invoices, so a payment only settles when the payout happens.
- Nostr login (NIP-07 / Nostr Wallet Connect) and encrypted group chat.
- Scheduled reminders, including SMS for members without WhatsApp.
- Native speaker review of the Wolof text.
- A pilot with organizers at Marché HLM in Dakar.
Built With
- anthropic
- bitcoin
- bolt11
- claude
- docker
- express.js
- github-actions
- javascript
- lightning-network
- lnbits
- lnurl
- mempool.space
- noble-curves
- node.js
- nostr
- nostr-tools
- pwa
- service-worker
- sqlite