A Bitcoin wallet for Cashu ecash, Lightning, and offline payments. The current app is built with Expo and React Native, ships first on iOS, and combines Coco wallet state, Nostr identity, NFC tag handoffs, BitChat BLE mesh, Whitenoise MLS groups, and Routstr AI payments. Android configuration and fallbacks exist in the codebase, but the production target is still iOS-first.
On-chain Bitcoin inputs are recognized by the parser and by BIP-321 option ranking, but on-chain send and receive are not shipped yet.
- Current status
- Protocol vocabulary
- Feature inventory
- Technical shape
- Platforms
- Getting started
- Contributing
- License
- Primary target: iOS app, minimum iOS 16.4.
- Version in
app.json: 0.1.0. - Local native projects: generated by Expo prebuild;
ios/andandroid/are not checked in. - Android: configured in Expo/EAS and guarded by platform fallbacks, but still a development target. Some surfaces need runtime configuration, such as
EXPO_PUBLIC_GOOGLE_MAPS_API_KEYfor Google Maps. - On-chain Bitcoin: parsed as an address or a BIP-321 option, then marked unavailable with "Coming soon".
- Adjacent protocol repos:
../coco,../cashu-ts,../nuts,../nips,../luds, and../bipsare reference checkouts. There is no../lipscheckout in this workspace; Lightning URL terminology comes from../luds.
Sovran uses the names below in the same sense as the sibling protocol repositories.
| Term | Meaning in this app | Reference |
|---|---|---|
| Cashu proof | Spendable ecash input generated from a mint's blind signature. | ../nuts/00.md |
| Mint / melt / swap | Minting receives ecash after paying a quote, melting pays a Lightning invoice with proofs, swapping rotates or changes proofs. | ../nuts/03.md, ../nuts/04.md, ../nuts/05.md |
| Keyset | The mint's active signing keys for each amount and unit. | ../nuts/01.md, ../nuts/02.md |
| NUT-10 spending condition | A well-known Proof.secret format for extra spend requirements. |
../nuts/10.md |
| NUT-11 P2PK | Pay-to-Public-Key locked ecash that requires a Schnorr signature from the recipient key to spend. | ../nuts/11.md |
| NUT-13 restore | Deterministic secret/counter restore used by Coco-backed recovery flows. | ../nuts/13.md |
| NUT-17 subscriptions | Mint WebSocket subscriptions used by Coco/NPC-style quote watching where supported. | ../nuts/17.md |
| NUT-18 payment request | Receiver-authored Cashu payment request, encoded as creqA... or creqB.... |
../nuts/18.md, ../cashu-ts/src/model/PaymentRequest.ts |
| BOLT-11 | Lightning invoice format used for mint quotes and melt quotes. | @gandlaf21/bolt11-decode, Lightning BOLTs |
| LNURL-pay | Static pay endpoint flow that returns a BOLT-11 invoice after amount selection. | ../luds/06.md |
| Lightning address | name@domain identifier that resolves to an LNURL-pay endpoint. |
../luds/16.md |
| NIP-05 | DNS-based mapping from an internet identifier to a Nostr pubkey. | ../nips/05.md |
| NIP-06 | BIP-39/BIP-32 derivation path m/44'/1237'/<account>'/0/0 for Nostr keys. |
../nips/06.md |
| NIP-17 / NIP-44 / NIP-59 | Private DMs: unsigned rumors, NIP-44 v2 encryption, seals, and gift wraps. | ../nips/17.md, ../nips/44.md, ../nips/59.md |
| BIP-321 | Modern bitcoin: URI replacement for BIP-21, including standard payment-instruction query parameters. Sovran also recognizes non-standard cashu hints inside the container. |
../bips/bip-0321.mediawiki |
| Coco | Headless TypeScript Cashu wallet toolkit; Sovran uses @cashu/coco-core, @cashu/coco-react, and @cashu/coco-expo-sqlite. |
../coco/README.md |
| cashu-ts | TypeScript Cashu protocol library used for low-level token/payment-request parsing and Cashu helpers. | ../cashu-ts/README.md |
Reference — every capability Sovran ships today, organized by concern. Each item is either checked ([x] — shipping) or unchecked ([ ] — recognized in the code but not yet enabled).
- Cashu ecash — proofs, tokens, payment requests via
@cashu/cashu-ts- P2PK receive — receive tokens whose proofs carry a NUT-10 well-known secret of kind
P2PK(NUT-11) locked to your pubkey; unlocked automatically with the active profile's key - Cashu payment requests — request-driven flow with amount, memo, and accepted mints
- Animated UR QR codes — multi-frame UR sequences via
@gandlaf21/bc-urfor oversized payloads
- P2PK receive — receive tokens whose proofs carry a NUT-10 well-known secret of kind
- Coco wallet engine —
@cashu/coco-core+@cashu/coco-expo-sqlite+@cashu/coco-reactfor proof storage, swaps, and reactive state -
coco-payment-ux— our own send/receive/mint-select state-machine library that sits on top of Coco - Lightning
- BOLT-11 — invoice decoding via
@gandlaf21/bolt11-decode, pay-to-invoice through mint melt quotes - Lightning address (LUD-16) — pay any
name@domain.comstatic internet identifier - LNURL-pay (LUD-06) —
payRequestflow over bech32lnurl1...orlightning:URIs
- BOLT-11 — invoice decoding via
- BIP-321 — the new
bitcoin:URI scheme (supersedes BIP-21) for onchain + Lightning, extended in practice with acashuparameter so a single URI can advertise all three rails; fallback rail UI when the chosen rail fails (the onchain rail is parsed and ranked but not yet sendable) - Ecash send — token-based Cashu sends through online recipient flows and offline handoff paths
- Online ecash send —
coco-payment-uxdrives amount, mint, recipient, and payment-request flows with mint checks before execution - Offline token handoff — Coco can compose the token with no network once spendable proofs are selected
- Share targets — QR, system share, NFC, BLE mesh
- Copy as text — raw
cashuB...token - Copy as emoji — token encoded as emoji-only string for paste into emoji-tolerant apps (Twitter, iMessage)
- Pending-ecash sweeper — outgoing tokens the recipient never claimed stay live on the mint; the Transactions screen's Pending tab surfaces a "Cancel N pending" footer that mass-reclaims every visible row back into your wallet in one tap (with per-row swipe-to-cancel for single sends)
- Online ecash send —
- NPubCash (NPC) — receive to an
npubx.cashLightning address throughcoco-cashu-plugin-npc; paid quotes sync into Coco using a persisted since-cursor. The username screen supports availability checks and free claims today; paid username claims are surfaced but not completed in that screen yet.
- Multi-mint — track balances across many mints simultaneously
- Mint rebalance — orchestrated planner that moves proofs across mints with Split/Reset/Focus actions
- Auditor integration — pulls mint uptime, swap success rate, and latency from the public auditor
- Auditor-driven mint discovery — browse vetted mints by uptime and audit score
- Nostr mint reviews — community reviews surfaced from Nostr alongside auditor data
- Mint state badges —
OK/DEGRADED/DOWNrolled up from recent swap history - Mint info screen — name, contact, TOS, audit score, swap stats
- KYM catalog —
cashu-kym"know your mint" data for onboarding - Mint selector with dimming — under-funded mints are dimmed inline rather than throwing
- Inactive-mint reclaim — proofs from removed mints are reclaimable
- Key management
- NIP-06 multi-account derivation — BIP-32/BIP-39 derivation at
m/44'/1237'/<account>'/0/0; every Sovran profile derives its Nostr key from one mnemonic at a different account index - nsec import — paste an existing
nsec1...to bring an external Nostr identity into a Sovran profile (bypasses derivation for that profile) - Multi-profile isolation — each profile has its own Nostr keys, BLE-mesh identity, and balances; switching remounts providers
- NIP-06 multi-account derivation — BIP-32/BIP-39 derivation at
- Identity resolution
- NIP-05 — map Nostr keys to DNS-based internet identifiers via
/.well-known/nostr.json?name=<local> - NIP-05 on Lightning sends — Lightning addresses (LUD-16) and NIP-05 identifiers share the same
local@domainshape, so when you scan/paste a Lightning address Sovran also queries the domain's/.well-known/nostr.jsonand surfaces the linked Nostr profile, avatar, and Vertex credibility before you confirm
- NIP-05 — map Nostr keys to DNS-based internet identifiers via
- DMs
- NIP-04 — legacy encrypted DMs with decrypt cache (
unrecommendedupstream; kept for backwards compatibility) - NIP-17 Private Direct Messages —
kind 14rumors sealed and gift-wrapped per NIP-59 (kind 1059), encrypted with NIP-44 v2
- NIP-04 — legacy encrypted DMs with decrypt cache (
- Relays & search
- NDK Mobile — relay management via
@nostr-dev-kit/ndk-mobile - Primal cache relay —
cache.primal.netfor fast feed loading and profile lookups - Vertex — Vertex trust-ranked Nostr search and follower-graph reputation scores
- Vertex credibility on rows — reputation + followers shown inline on contact search and payment-recipient confirmations
- NDK Mobile — relay management via
-
nostr-tools— low-level signing, encoding, NIP utilities - Profile switcher in drawer — header avatar opens the drawer; drawer hosts the profile chrome
- Feed (
kind 1text notes per NIP-01)- Home timeline with follow graph (
kind 3contact lists) - Threads with measured exit-shimmer skeletons while replies stream in
- Image overlay — tap an image in a note to open the fullscreen lightbox with zoom/pan
- Video player — inline Nostr video posts with autoplay and unmute on overlay
- Reactions (NIP-25,
kind 7) —+likes and emoji reactions - Reposts (NIP-18,
kind 6) — share akind 1text note to your own followers - Link parsing — hyperlinks rendered with preview affordances
- Image grid layout — multi-image posts with adaptive grid
- Home timeline with follow graph (
- Routstr integration — Routstr is a decentralized reverse proxy that fronts OpenAI-compatible LLM providers and bills per request in Cashu; Sovran uses your wallet as the funding source so there's no separate billing account
- Cashu-token top-up —
coco-payment-uxmints a Cashu token from your wallet and deposits it as Routstr balance; subsequent calls are paid out of that balance - Model picker — switch between models in chat
- Streaming responses — token-by-token rendering
- AI chat as a tab — first-class tab, not a settings page
- Pull-to-AI refresh — pull-down gesture from the wallet surface to jump into AI (currently shipping)
- AI wallpaper backdrop — tiled pattern wallpaper behind the chat surface
- Native BitChat module — local iOS
bitchat-modulebridging BLE mesh transport; Android exports degrade gracefully while the native bridge remains iOS-focused - Private DMs over BLE — peer-to-peer encrypted DMs with no relay, no internet
- Group chats over BLE — multi-peer chats on the mesh
- Geohash chat rooms — public location-bound chat rooms keyed by geohash precision
- Split-bill over BLE — settle splits across nearby peers without any server in the path
- BLE peer discovery in contacts — nearby mesh peers appear in the contact list with mesh identity
- Delivery acks — delivered / failed delivery state on DMs
- Profile-scoped BLE identity — BLE peer identity is scoped to the active Sovran profile
- Whitenoise protocol — MLS-based end-to-end encrypted Nostr group chat, powered by the vendored
@internet-privacy/marmot-ts- MLS group chats — forward-secret, post-compromise-secure ratcheting via the Marmot MLS implementation
- Key packages — publish your Whitenoise key package as a Nostr event so others can invite you
- Invite-driven join — accept or decline incoming group invites
- Profile-scoped identity — each Sovran profile has its own Whitenoise identity, isolated from the others
- Dev-gated — feature is hidden behind the developer toggle while it stabilizes
- Tap modes
- Tap to read — read a payment request, Cashu token, or other supported payload from an NFC Type 4 / IsoDep tag or terminal-like source
- Tap to write a token to a tag — write an ecash token to a blank NFC Type 4 / IsoDep tag
- Tap to read a tag back — receive a token by tapping a previously written tag
- Reliability
- Chunked writes — oversized tokens span multiple records with a commit-only-on-success protocol so an interrupted write never bricks a tag
- Auto proof reclaim — if the tap drops mid-send, the proofs are reclaimed automatically
- User-initiated dismiss is a no-op — closing the sheet doesn't burn proofs
- Steadier UX prompts — "hold your device steady" instead of raw OS errors
- Routing — NFC reads go through the same unified parser as paste/scan, so a tap drops you into the right flow (send, receive, mint add, contact open) automatically
- Bidirectional, online or offline — every flow works without network
- Unified parser — one parser handles paste / scan / NFC / deeplink and ranks results so the most useful option surfaces first
- Recognized payloads
- Cashu tokens — both
cashuA...(v3, JSON) andcashuB...(v4, CBOR), including emoji-encoded variants - Cashu payment requests (
creqA...andcreqB...) - BOLT-11 Lightning invoices
- Lightning addresses (
name@domain) - LNURL (bech32
lnurl1...) - BIP-21 / BIP-321
bitcoin:URIs (onchain + Lightning + ecash advertised together — onchain rail itself not yet sendable) - On-chain Bitcoin addresses (legacy, P2SH, bech32, taproot) — recognized and parsed, but onchain send/receive is not yet shipped
- Mint URLs (
https://mint...) - NIP-19 bech32 entities (
npub,nprofile,nevent,note,naddr) -
nsecfor import flow - Animated UR QR codes (
ur:bytes/...)
- Cashu tokens — both
- Gallery QR import — scan a QR from a saved photo
- Camera permission gating — explicit permission flow before camera access
- Flash control — toggle torch in low light
- Custom schemes —
bitcoin:,lightning:,lnurl:,cashu:,nostr:,web+nostr: - Sovran scheme —
sovran://for in-app routes - Universal links —
https://sovran.money/...opens directly into the matching flow - Cross-wallet compatibility — broadened URI ingress to match Minibits and Macadamia handling so QR codes from those wallets just work
-
expo-linkingintegration — single ingress goes through the unified parser; no flow-specific parsing branches - Modal-stacked profile opens — scanned profile deeplinks open above any active modal flow instead of replacing it
- btcmaps.org merchants — Bitcoin-accepting merchants on an interactive map
- Map clustering —
supercluster-backed zoom-aware merchant clustering - Location-aware focus — center map on user via
expo-location - Search & filter merchants — by name, payment method, proximity
- Auditor-driven mint discovery — discover new mints via auditor's index
- Nostr-driven mint discovery — discover mints via reviews and recommendations on Nostr
- Wallpaper-driven theming — theme tints are derived from the user's chosen wallpaper via
react-native-image-colors - Nostr wallpaper sharing — wallpapers are published and discovered through Nostr; download-then-apply so themes never flip before the asset is ready
- Light & dark theme — full light theme parity across chrome and content
- Liquid Glass —
liquid-glass-textnative module for iOS 26 glassmorphism text - Capability variants — Liquid Glass / blur / mesh gradient gracefully fall back on older OS versions
- Device-radius scene corners — drawer scenes adopt the device's actual screen corner radius via
expo-screen-corner-radius - Mesh gradients —
expo-mesh-gradientfor animated backdrops - Tile-pattern wallpaper — AI tab background
- Live BTC price — real-time price feeds drive fiat equivalents app-wide
- Fiat-first amount entry — type fiat, Sovran picks a composable sat amount from your proofs
- SAT / BTC / fiat unit switching — pill swapper on the wallet face
- Per-mint balance breakdown — see how proofs are distributed
- Transaction list — sends, receives, swaps, splits — sorted, sectioned, with pending/confirmed groups
- Month-pager transactions — swipe by calendar month through history
- Bulk pending-ecash sweep — Pending tab footer reclaims every visible unclaimed outgoing token at once; per-row swipe-to-cancel for single targets
- Transaction source badges — every row carries a small icon showing how the payment entered or left the wallet
- Inbound (scan history):
qr,nfc,paste,deeplink - Outbound (distribution):
copy,share,airdrop(BLE/NFC/local),displayed(shown as QR on-screen) - BIP-321 option kinds — for BIP-321 scans, the badge also exposes which rails the URI advertised (onchain / lightning / ecash)
- Inbound (scan history):
- Transaction location stamps — optional geolocation captured at the moment a transaction finalizes
- Privacy-gated reveal — locations stay hidden behind a placeholder and only render after explicit user reveal
- Grayscale map — rendered via
expo-mapswith a desaturation overlay so location is glanceable but not flashy - Per-flow capture — visible on receive-token, mint-quote, melt-quote, and send-token detail screens
- Opt-out — setting can be disabled globally; when off, nothing is captured or stored
- Transaction status indicators — single
LoadingIndicatorblock handles loading / success / error / reverted across the app
- Send flow state machine —
coco-payment-uxmachine drives amount → mint → recipient → execute - Recipient identity enrichment — NIP-05 + Nostr profile resolved before you confirm
- Mint revalidation — mint health revalidated on amount entry
- Token detail share screen — copy (text or emoji), share, NFC side-by-side
- Receive flow — mint selection, BOLT-11 mint quote, live quote status
- Lightning melt — pay an invoice from any mint that can cover it
- Multi-rail fallback — BIP-321 rails dim on failure; remaining rails are offered inline
- Participant picker — pick from contacts, BLE mesh peers, or Nostr directory
- Per-person amount adjust — split evenly or set custom amounts
- BLE-mesh settlement — settle over BitChat with no relay
- NPC / Nostr settlement — fall back to Lightning address or Nostr DM payment
- Settlement tracking — per-participant paid/owed status
- Unified search — name, NIP-05, npub, Lightning address all in one box
- Reputation + followers on rows — Vertex-backed credibility surfaced inline
- BLE peers in contact list — nearby mesh peers alongside Nostr contacts
- Mock contacts in demo mode — for first-launch and screenshots
- BIP-39 mnemonic — single seed root for every profile's Nostr key (NIP-06) and wallet derivation
- Seed display & confirmation — onboarding seed reveal + verification step
- Restore from seed — re-derive all profiles from mnemonic
-
cashu-recovery— proof recovery tooling (sibling repo) -
sovran-recover— Sovran-specific recovery flow (sibling repo) - Secure storage —
expo-secure-store(no biometric gate on boot to avoid FaceID cascades)
- Two branded widgets — both ship in the same target via
@bacons/apple-targetsundertargets/widget/- Bitcoin Pay — Bitcoin ₿ logo on the Bitcoin-orange gradient
- Sovran Pay — Sovran S-mark on the same gradient
- Six supported widget families
- Home Screen:
systemSmall,systemMedium,systemLarge - Lock Screen / accessory:
accessoryCircular,accessoryRectangular,accessoryInline
- Home Screen:
- Tap-to-launch deeplink — every size links to
sovran://camera?action=nfc-pay, opening the NFC pay flow from the lock screen or home screen in one tap (the same deeplink can be repointed to any unified-parser route) - Adaptive rendering — orange gradient + white content on home-screen sizes; white background + black content on lock-screen sizes so iOS's vibrant cutout renders cleanly
- Pure SwiftUI Shape paths — both logos are vector
Shapepaths drawn in SwiftUI (no bundled image assets); resolution-independent at every widget size - iOS 16.4+ — uses
containerBackgroundon iOS 17+ with aZStackfallback for the iOS 16 minimum target
- Profile management — create, switch, delete profiles
- Keyring — view nsec, derivation path, advanced key actions
- Mint list & rebalance entry — manage active mints
- Fiat picker — change display currency
- Theme settings — wallpaper picker, light/dark override
- Developer toggles — gate Whitenoise, mock contacts, and other dev-only surfaces
- Contact the Developer — links to
@SovranBitcoin
- Expo Router — file-based routing under
app/ - Modal flow stacks —
(send-flow),(receive-flow),(mint-flow),(split-bill-flow),(settings-flow),(theme-flow), etc. - Drawer + bottom tabs — drawer for profiles/settings, tabs for top-level surfaces
-
@gorhom/bottom-sheet— native bottom sheets for pickers and confirmations -
heroui-native— in-card buttons, dialogs, segmented chips - Project
Buttonprimitive — hero CTAs inBottomButtonsfooters -
SelectableCheckprimitive — canonical selection checkmark - Underline tabs — replaced capsule tabs across the app
-
number-flow-react-native— animated number changes on balances and amounts -
react-native-keyboard-controller— unified keyboard-lift math across AI tab and modal chats -
@legendapp/list— high-performance lists across feed, DMs, and AI chat (works around iOS 26 FlatList dimming) - Iconify + internal SVG namespace —
<Icon name="prefix:name" />for 30+ icon sets plus aninternal:namespace for brand glyphs - Design tokens —
shared/styles/tokens.ts(spacing, radius, alpha, duration, zIndex, iconSize, hitSlop, shadow) - Anchored color ramps — semantic
success/danger/warningflip with theme; no hardcoded hex - Haptics —
expo-hapticson toggles and key actions - Locale-aware dates —
shared/lib/date.ts(formatDate/formatRelative); in-app override → device locale →'en'
- On-chain send/receive rail — the parser recognizes addresses and BIP-321 onchain hints, but
availability.tsmarks the rail "Coming soon" and the send handler logsonchainNotSupported. No mint-quote-driven on-chain receive yet. - Production Android release — Android app config, EAS scripts, JS fallbacks, and many Android-specific UI branches exist, but iOS remains the shipping target and some native features are iOS-only.
- Expo SDK 55 / React Native 0.83.2 / React 19.2 / Hermes
- Bun as package manager and CI runtime
- TypeScript with
noImplicitOverride, type-aware ESLint rules,eslint-plugin-react-compiler,eslint-plugin-react-perf - Reanimated v4 (legacy
Animatedbanned by lint) - React Native Gesture Handler, Nitro Modules, Worklets
- Redux + redux-persist alongside Zustand
- Zod v4 schema validation;
@sovranbitcoin/schemasfor shared payloads -
neverthrowforResult/ResultAsyncreturn types -
react-native-quick-crypto+@noble/hashes+@scure/bip32+@scure/bip39 - Uniwind + Tailwind variants for styling
-
expo-sqlitefor Coco wallet storage -
expo-secure-storefor seeds and nsec - Apple Targets (
@bacons/apple-targets) for widgets and extensions undertargets/ - Patch-package for upstream Coco / cashu-ts modifications under
patches/
app/— Expo Router routes and route-group stacks.features/— domain modules for wallet, send, receive, mint, transactions, feed, contacts, AI, map, split bill, settings, BitChat, Whitenoise, theme, and onboarding.shared/— cross-cutting UI primitives, providers, stores, Cashu/Nostr/NFC/Routstr helpers, theme and persistence infrastructure.coco-payment-ux/— local package for the payment parser, state machine, guards, screen actions, LNURL/NIP-05 resolution, and tests.modules/— local native modules: BitChat and Liquid Glass text.targets/widget/— iOS widget target managed by@bacons/apple-targets.patches/— patch-package patches for upstream dependencies consumed by the app.__rules__/andAGENTS.md— contributor/agent rules that govern architecture, UI, storage, security, and commit workflow.
- App version in source: 0.1.0
- Local
app.jsonbuild number: 1 - EAS build numbers: remote auto-incremented by EAS (
appVersionSource: remote) - Minimum OS: 16.4
- Bundle id:
com.sovranbitcoinin production,com.sovranbitcoin.devfor development/preview profiles - Widgets: Bitcoin Pay and Sovran Pay under
targets/widget/ - App size: 415 MB raw archive at upload, 94 MB bundled on TestFlight
- Expo/EAS config exists with package
com.sovranbitcoin. - Development and preview build scripts exist.
- Google Maps requires
EXPO_PUBLIC_GOOGLE_MAPS_API_KEYorGOOGLE_MAPS_API_KEYat build time. - Android uses flat/no-glass UI fallbacks and a JS tab bar; the BitChat native bridge is iOS-only in this checkout.
How-to — fastest path to a running build.
Prerequisites
- Bun
1.3.5(pinned viapackageManagerinpackage.json) - Xcode 15+ with Command Line Tools and an iOS Simulator
- An EAS account if you want to make remote builds (
eas login)
Install & run locally
bun install # installs deps + runs patch-package + bitchat patch
bun run start # Expo dev server (Metro)
bun run ios # build and launch on iOS simulator
bun run android # build and launch on Android when configuredOther scripts
bun run build:dev:ios/bun run build:dev:android— EAS development buildsbun run build:ios— EAS production iOS build (auto-submit)bun run lint/bun run type-check/bun run test/bun run pretty:check— checksbun run analyze-structure— structural health reportbun run audit/bun run fix— Claude-driven audit and fix flows
Sovran lives inside a workspace checkout of related repos (see CLAUDE.md for the layout). Before opening a PR:
- Read
CLAUDE.mdfor workspace conventions (where to edit, which sibling repos are read-only, patch-package rules). - Read
AGENTS.mdfor the per-feature contributor rules. - Read the rule files under
__rules__/before writing UI: capability variants, responsive scaling, caching, dates, icons, design tokens, colors, status indicators, flow screens, buttons, thread skeletons. - Run
bun run lint && bun run type-check && bun run testbefore committing.
Sovran is licensed under the Mozilla Public License 2.0. See LICENSE for the full text.
Last reviewed: 2026-05-16. Capability claims cross-checked against ../bips, ../cashu-ts, ../coco, ../nips, ../nuts, ../luds, and Routstr sibling repos on this date.