Coco-Cashu Overview
Sovran uses Coco-Cashu as its core Cashu implementation. Coco is a modular, TypeScript-native library built on top of@cashu/cashu-ts.
Architecture
CocoManager Singleton
TheCocoManager class is a singleton wrapper around Coco’s Manager that handles initialization, cleanup, and database management.
helper/coco/manager.ts:38-749
Initialization Flow
The manager initializes in two phases: Phase 1: Blocking (happens during app startup) helper/coco/manager.ts:91-166- Open SQLite database (
coco.dborcoco-N.db) - Initialize repositories
- Create seed getter (lazy - no crypto work yet)
- Create NPC plugin (constructor only - no network)
- Instantiate
Manager
- Run initial NPC sync (fetch Lightning addresses from npubx.cash)
- Enable mint quote watcher
- Enable mint quote processor
- Enable proof state watcher
Database Per Profile
Each profile gets its own SQLite database:- Proofs table - Ecash proofs with state (ready, reserved, inflight, spent)
- Mint quotes table - Lightning → Cashu mint operations
- Melt quotes table - Cashu → Lightning melt operations
- Keysets table - Mint public keys for each unit (sat, usd, eur, etc.)
- Mint info table - Cached mint metadata
Cleanup & Profile Switching
When switching profiles, the manager must be cleaned up: helper/coco/manager.ts:250-289 This is called from the drawer layout before switching profiles: app/(drawer)/_layout.tsx:102-102Proof Lifecycle
Proofs flow through several states:State Definitions
Proof State Watcher
The proof state watcher monitors inflight proofs and updates their state based on mint responses:Manual Proof Recovery
If proofs get stuck (e.g., due to a crash), users can manually free them: helper/coco/manager.ts:510-707 This is exposed in Settings → Storage → “Free Reserved Balance”.Mint Operations
Adding a Mint
hooks/coco/useMintManagement.ts:33-51 Under the hood:manager.mint.trustMint(url)fetches mint info- Stores keyset data in SQLite
- Adds mint URL to trusted mints list
- Returns mint metadata (name, icon, supported units)
Mint Info
Mint metadata is cached in SQLite:Keyset Management
Keysets define the denominations and units a mint supports:Receiving Ecash
Token Parsing
Receiving Flow
P2PK (Pay-to-Public-Key)
Sovran supports P2PK tokens that require a private key to unlock:Sending Ecash
Send Operation
hooks/coco/useSendWithHistory.ts creates a send operation:Send States
Pending Ecash Sweeper
Unredeemed sent tokens can be reclaimed:Lightning Operations
Minting (Lightning → Cashu)
Melting (Cashu → Lightning)
hooks/coco/useMeltWithHistory.ts handles melt operations:Lightning Addresses
Lightning addresses (user@domain.com) are resolved via LNURL-pay:Payment Requests (NUT-18)
hooks/coco/useProcessPaymentString.ts:216-331 Payment requests allow requesting ecash over Nostr without Lightning:Mint Swapping & Rebalancing
Swap Operation
Rebalance Planning
components/blocks/rebalance/rebalancePlanner.ts calculates optimal rebalance steps:Middleman Routing
If two mints don’t support direct swaps, Sovran can route through intermediary mints:NPC Plugin (npubx.cash)
The NPC plugin integrates with npubx.cash for Lightning addresses:React Hooks
coco-cashu-react provides hooks for common operations:hooks/coco/:
Best Practices
Always use Coco hooks in components
Always use Coco hooks in components
Never call Manager methods directly in components - use hooks:
Handle proof state transitions
Handle proof state transitions
Always handle rollback when operations fail:
Check keyset support before operations
Check keyset support before operations
Ensure the mint supports the unit you want to use:
Monitor quote states
Monitor quote states
Don’t assume quotes succeed immediately:
Related Documentation
State Management
Learn about stores that complement Coco’s SQLite storage
Nostr Integration
See how Nostr payment requests integrate with Cashu