Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

NUTbits - Cashu ecash to NWC bridge

What is NUTbits?

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app can send and receive Lightning payments through the mint.

Use case: plug the NWC string into LNbits as a funding source, and your ecash mint powers the entire LNbits instance with 60+ Extensions.

Inspired by supertestnet/bankify. Built on @cashu/cashu-ts and nostr-core.

Quick Start

See INSTALL.md for local setup (bare metal, Docker, LNbits). Deploying to a VPS? See DEPLOY.md or the quick LAZYDEPLOY.md.

git clone https://github.com/DoktorShift/nutbits.git &&cd nutbits
npm install && cp .env.example .env
# Edit .env - set NUTBITS_MINT_URL and NUTBITS_STATE_PASSPHRASE
npm start

NUTbits has three main parts:

  • the service (npm start) that handles NWC traffic
  • the management console (nutbits) with CLI and TUI modes
  • the web GUI in gui/, served by npm run gui

The service usually runs in one terminal or in the background. The console and GUI connect to the same local API, so you can manage the same NUTbits instance from terminal or browser.

All connections are dedicated by default - each gets its own isolated balance starting at 0 sats. You fund them explicitly. This means every app only has access to what you put in, never your full wallet. If you need full wallet access for your own trusted apps, you can opt into shared balance during connection setup.

External apps can connect via deep link - one tap, no copy-paste. See Deeplink Integration below.

Running Modes

Run these commands from the repository root, where package.json lives.

Pick One

npm start # backend only, in your terminal
npm run nutbits # backend + GUI, in the background
npm run service:mac # macOS 24/7 backend + GUI service
npm run service:linux # Linux 24/7 backend + GUI services

That is the simplest mental model:

  • use npm start when you want the normal terminal experience
  • use npm run nutbits when you want the web GUI too
  • use npm run service:mac when you want backend + GUI to keep running 24/7
  • use npm run service:linux when you want both backend and GUI kept running under systemd

If you want the backend to run 24/7 under your operating system's service manager, see SERVICE.md.

Local NUTbits Commands

npm run nutbits # backend + GUI in the background
npm run nutbits:interactive # GUI in background, backend in your terminal
npm run nutbits:stop # stop backend + GUI
npm run nutbits:restart # restart NUTbits mode
npm run nutbits:update # update, rebuild GUI, restart background NUTbits

These helper scripts live in scripts/. In background mode, logs go to logs/nutbits.log and logs/gui.log.

Configuration

All settings in .env (see .env.example):

Required

VariableDefaultDescription
NUTBITS_MINT_URLhttps://mint.minibits.cash/BitcoinCashu mint URL (find mints)
NUTBITS_STATE_PASSPHRASE(required)Passphrase to encrypt state at rest

Wallet & Recovery

VariableDefaultDescription
NUTBITS_SEED(auto-generated)Deterministic wallet seed for proof recovery. Auto-saved to .env on first run. Back up your .env or copy the seed to a password manager.
NUTBITS_MINT_URLS(optional)Comma-separated mint URLs for multi-mint failover (first = primary). When set, overrides NUTBITS_MINT_URL.
NUTBITS_RELAYSwss://relay.getalby.com/v1,wss://relay.8333.spaceComma-separated Nostr relays for NWC
NUTBITS_STATE_BACKENDfileStorage backend: file, sqlite, or mysql
NUTBITS_STATE_FILE./nutbits_state.encPath to encrypted state file (file backend)
NUTBITS_SQLITE_PATH./nutbits_state.dbSQLite database path (sqlite backend)
NUTBITS_MYSQL_URL(optional)MySQL connection URL (mysql backend)

Spending Limits

VariableDefaultDescription
NUTBITS_MAX_PAYMENT_SATS0Max sats per payment (0 = no limit)
NUTBITS_DAILY_LIMIT_SATS0Max sats per day (0 = no limit)
NUTBITS_FEE_RESERVE_PCT1Percentage reserved for Lightning routing fees

Service Fees

VariableDefaultDescription
NUTBITS_SERVICE_FEE_PPM0Fee in parts per million on outgoing payments (0 = disabled)
NUTBITS_SERVICE_FEE_BASE0Flat base fee in sats per outgoing payment (0 = disabled)

Network & Timing

VariableDefaultDescription
NUTBITS_HEALTH_CHECK_INTERVAL_MS60000Mint health check interval
NUTBITS_FAILOVER_COOLDOWN_MS10000Cooldown before retrying a failed mint
NUTBITS_INVOICE_CHECK_MAX_RETRIES60Max retries for pending invoice checks
NUTBITS_INVOICE_CHECK_INTERVAL_SECS20Seconds between pending invoice checks
NUTBITS_FETCH_TIMEOUT_MS15000Timeout for mint API requests
NUTBITS_MINT_TIMEOUT_MS60000Give up on a single mint call after this long. Without it, one unresponsive mint blocks every payment to it
NUTBITS_MELT_POLL_BUDGET_MS30000How long to ask the mint what happened to a payment whose outcome is unclear, before leaving it for reconciliation

Management API

VariableDefaultDescription
NUTBITS_API_ENABLEDtrueSet to false to disable the management API, CLI, and GUI
NUTBITS_API_PORT(optional)HTTP port for the API (leave empty for Unix socket only)
NUTBITS_API_SOCKET(auto)Unix socket path (default: ~/.nutbits/nutbits.sock)
NUTBITS_API_TOKEN(auto)Bearer token for API access (auto-generated on start)
NUTBITS_LOG_LEVELinfoerror, warn, info, or debug

Storage: See DATABASE.md for backend comparison, setup, and migration. Backups: See BACKUP.md for backup and recovery procedures. Service fees: See CLI.md for fee configuration, per-connection overrides, and revenue tracking.

Encryption: NIP-44 (preferred) with NIP-04 fallback, auto-detected per client.

Supported Cashu NUTs

NUT-00NUT-01NUT-02NUT-03NUT-04NUT-05NUT-06NUT-07NUT-08NUT-09NUT-12NUT-13NUT-17

NUTNameStatusUsed For
NUT-00Cryptography & ModelssupportedProof structure, keyset IDs
NUT-01Mint Public KeyssupportedKey fetching via loadMint()
NUT-02KeysetssupportedKeyset management, fee calculation
NUT-03SwapsupportedProof selection via wallet.send()
NUT-04Mint (BOLT11)supportedReceiving: make_invoice
NUT-05Melt (BOLT11)supportedSending: pay_invoice
NUT-06Mint InfosupportedFeature detection, capability gating
NUT-07Proof State ChecksupportedVerify proofs on mint recovery
NUT-08Lightning Fee ReturnsupportedChange proofs from overpaid fees
NUT-09Signature RestoresupportedRecover proofs from seed after data loss
NUT-12DLEQ ProofssupportedVerify mint signatures, anti-counterfeit
NUT-13Deterministic SecretssupportedSeed-based proof generation for recovery
NUT-17WebSocket SubscriptionssupportedInstant invoice settlement (replaces polling)

Supported Nostr NIPs

NIP-04NIP-44NIP-47NIP-40

NIPNameUsed For
NIP-04Encrypted DMsLegacy encryption fallback
NIP-40Expiration TagIgnoring expired NWC requests
NIP-44Versioned EncryptionPreferred encryption (auto-detected)
NIP-47Nostr Wallet ConnectCore protocol for all wallet operations

Supported NWC Methods (NIP-47)

Wallet operations:

  • get_info - wallet metadata, capabilities, encryption support
  • get_balance - current balance in millisats
  • make_invoice - create a Lightning invoice (NUT-4 mint)
  • pay_invoice - pay a Lightning invoice (NUT-5 melt)
  • lookup_invoice - check invoice status by payment hash
  • list_transactions - transaction history with filtering

Notifications (push):

  • payment_received - sent when an incoming invoice settles
  • payment_sent - sent when an outgoing payment completes

Lightning Address support: Each NWC connection can optionally carry a Lightning Address (lud16). Apps that understand this parameter can use it for receiving payments. The address is included in the NWC connection string as &lud16=user@domain.com and is validated via LUD-16 resolution on create and edit.

Optional NIP-47 extensions (non-breaking, clients can ignore or honor):

  • get_info response includes service_fee object when fees are enabled (ppm, base, applies_to)
  • pay_invoice response includes service_fee field (msats) separate from fees_paid (routing)

How It Works

LNbits -> NWC -> NUTbits -> Cashu NUTs -> Mint -> Lightning -> Network

  1. NUTbits generates a keypair and creates an NWC connection string
  2. It subscribes to NWC request events (kind 23194) on configured Nostr relays
  3. When a command arrives, it translates to Cashu operations via @cashu/cashu-ts:
    • pay_invoice -> wallet melts ecash to pay the Lightning invoice (NUT-5). Optional service fee deducted if configured.
    • make_invoice -> wallet requests a mint quote; upon payment, mints new ecash (NUT-4). No fees on incoming.
  4. Responses are sent back as NWC events (kind 23195)

State (keys, ecash proofs, transaction history) is encrypted with AES-256-GCM and persisted to disk.

For a plain-language deep dive, see HOW-IT-WORKS.md.

Management Console

NUTbits includes a CLI and interactive TUI to manage the daemon while it's running. Open a second terminal and use nutbits to control connections, check balances, pay invoices, and monitor activity, all without restarting the service.

First, register the CLI command (once):

npm link

Then:

nutbits # interactive TUI dashboard
nutbits balance # check balance across mints
nutbits connections # list NWC connections
nutbits connect # create new connection (guided wizard)
nutbits fund # fund a dedicated connection
nutbits withdraw # withdraw from a dedicated connection
nutbits revoke <label># revoke a connection
nutbits pay <invoice># pay a Lightning invoice
nutbits receive <amount># create an invoice
nutbits history# transaction history
nutbits fees # view/manage service fees
nutbits mints # mint status and health
nutbits relays # relay connection status
nutbits logs # recent log output
nutbits watch # live activity monitor
nutbits config # view runtime configuration

Create multiple NWC connections with scoped permissions and spending limits; one for LNbits with full access, another for a POS with pay-only and a daily cap. Revoke any connection without affecting the others.

Don't want to npm link? Use npm run cli or node bin/nutbits.js instead.

See CLI.md for the full command reference and CONSOLE.md for TUI usage.

Set NUTBITS_API_ENABLED=false in .env to disable the management API entirely.

Web GUI

NUTbits ships with a browser-based GUI in gui/. It talks to the same local management API as the CLI and TUI, so all three interfaces stay in sync.

  • Default local URL: http://127.0.0.1:8080
  • Backend API default: http://127.0.0.1:3338
  • The GUI can bootstrap the local API token automatically when the backend is running on loopback

GUI Pages

PageWhat it does
DashboardLive overview: balance, connections, relays, uptime, mint health, recent transactions
ConnectionsCreate, view, export, and revoke NWC connections. Card and list views. QR codes for NWC strings.
HistoryTransaction history with volume chart, type/connection filters, and CSV/JSON export
PayPay a Lightning invoice or LNURL/Lightning Address from the GUI
ReceiveCreate a Lightning invoice with QR code
MintsActive mint details, multi-mint management, failover priority, NUT capability matrix
RelaysNostr relay status, add/remove relays
NUTsDetailed NUT protocol support for each mint
FeesService fee earnings dashboard with 7-day chart and per-connection breakdown
SettingsAll configuration in one place: wallet, network, limits, fees, API, advanced
LogsLive log viewer with level filtering, search, and auto-refresh

Deeplink Integration

External apps can connect to NUTbits in one tap via deep link - no QR codes, no copy-paste. The app opens a URL, a dedicated connection is created automatically, and the NWC string goes back via callback. The user stays in their app the entire time.

Every deeplink connection is dedicated - own balance starting at 0 sats, funded by the user. External apps can never access the full wallet.

The deeplink endpoint (/connect) is served by the API server directly - no GUI needed. It works in headless mode with a self-contained HTML5 connection page.

https://<nutbits-host>/connect?appname=MyApp&callback=myapp://nwc-connected

App developers: see NWC-DEEPLINK-INTEGRATION.md for the full protocol spec.

Want to add your app to the NUTbits deeplink registry? See DEEPLINK-APPS.md.

Security

  • Dedicated connections by default (isolated balance, external apps never touch the main wallet)
  • Allocation ledger: funds are committed before a payment and settled after, so concurrent payments cannot overspend an allocation or reach into the shared pool
  • Unknown payment outcomes resolved against the mint (NUT-05), and never guessed: if the mint will not say, the sats stay committed and are reported for reconciliation
  • Atomic NUT-13 counter reservation, so two operations can never derive the same blinded message
  • Single-instance guard: a second process on the same state backend is refused at boot
  • Encrypted state persistence (AES-256-GCM + scrypt, N=65536)
  • Event deduplication across relays (prevents double-payments)
  • Per-payment and daily spend limits (global + per-connection)
  • Per-connection service fee scoping
  • NWC string masked in logs
  • State file permissions restricted to owner (0600)
  • Atomic state writes (crash-safe)
  • Graceful shutdown with state save
  • Seed-based proof recovery (NUT-09, NUT-13)
  • DLEQ proof verification (NUT-12)

All wallet data (ecash proofs, NWC keys, transaction history) is stored in an encrypted state file. Read BACKUP.md for backup, recovery, and encryption details - this is critical if you're running NUTbits with real funds.

Multi-Mint Failover

NUTbits supports optional multi-mint failover for higher reliability. Configure multiple mints and NUTbits will automatically switch to the next one if the active mint goes down. Your NWC connection string stays the same.

# In .env - first mint is primary, rest are fallbacks
NUTBITS_MINT_URLS=https://your-primary-mint.com,https://your-backup-mint.com

Multi-Mint Failover: Normal -> Failover -> Recovery

  • On startup, NUTbits tries mints in order until one responds
  • If the active mint goes down, it automatically fails over to the next healthy mint
  • A background health check runs every 60s. When the primary mint recovers, NUTbits switches back
  • In-flight invoices are checked against the mint that created them, even during failover
  • Your NWC connection string stays the same throughout

Trade-offs

Ecash proofs are cryptographically bound to the mint that issued them. Proofs from Mint A cannot be spent through Mint B. This means:

  • On failover, your spendable balance is whatever was pre-funded on the new active mint. Proofs on the old mint are not lost; they become spendable again when that mint recovers.
  • In-flight invoices (created but not yet paid) are tied to their originating mint. They will still resolve when that mint comes back online.
  • When a mint recovers, NUTbits automatically switches back and the full balance on that mint is available again.

For self-hosted / personal use

These trade-offs are minimal if you run your own mints. Pre-fund both mints, and failover is seamless. Recovery is automatic.

For multi-user servers

Be aware that switching mints can temporarily affect users trying to pay out, since the spendable balance depends on which mint is active. If you run NUTbits as a funding source for others, consider whether the failover behavior fits your use case before enabling it in production.

Documentation

DocumentDescription
HOW-IT-WORKS.mdPlain-language guide; what NUTbits does and why
CONSOLE.mdHow to use the TUI, CLI, and GUI day-to-day
CLI.mdFull command reference - flags, scripting, connections
INSTALL.mdLocal setup - bare metal, Docker, LNbits
DEPLOY.mdVPS deployment with HTTPS (Caddy / nginx)
SERVICE.md24/7 service setup (backend + GUI) with launchd and systemd
DATABASE.mdStorage backends - file, SQLite, MySQL
BACKUP.mdBackup, recovery, and encryption details
STATE.mdDeep dive into the encrypted state file
NWC-DEEPLINK-INTEGRATION.mdDeeplink protocol spec for app developers
DEEPLINK-APPS.mdAdd your app to the NUTbits deeplink registry
AGENTS.mdAgent/developer reference for building on NUTbits

Trust Model

Ecash is custodial. The mint holds the funds. Standard risks apply: the mint can steal, get shut down, or get hacked. Only use mints you trust, and only with amounts you can afford to lose.

NUTbits operators can optionally enable a service fee on outgoing payments. This fee is transparent - advertised in the NWC get_info response and reported separately in every pay_invoice response. Receiving payments is always free. By default, no fees are charged.

Related Projects

License

AGPL-3.0 - Free to use, modify, and distribute. If you run a modified version as a network service, you must share your source code.

About

NUTbits is an NWC wallet service that translates between Cashu Mint (NUTs) and Nostr Wallet Connect (NIP-47). It connects to a Cashu mint, manages ecash tokens automatically, and exposes a full NWC server, so any NWC-compatible app (or a nwc LNbits funding source) can send and receive Lightning payments through the mint

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages