diff --git a/docs/architecture-review.md b/docs/architecture-review.md index 3e0d534..1e26c89 100644 --- a/docs/architecture-review.md +++ b/docs/architecture-review.md @@ -668,8 +668,9 @@ Features: Machine pairing, balance check, settings ## Related Notes +- [[nostr-native-architecture]] - **Nostr as infrastructure backbone** - [[modernization-plan]] - Original tech stack decisions -- [[lnbits-integration]] - Current LNbits docs (to be revised) +- [[lnbits-integration]] - LNbits as alternative to Lightning.Pub - [[membership-lightning-integration]] - Membership feature (simplify) - [[hardware-recommendations]] - Hardware choices - [[machine-ui-modernization]] - Vue 3 UI migration @@ -700,8 +701,14 @@ Features: Machine pairing, balance check, settings - [BOLT Cards](https://bolt.cards/) - [LNbits BoltCards Extension](https://github.com/lnbits/lnbits/tree/main/lnbits/extensions/boltcards) +### Nostr Infrastructure +- [strfry](https://github.com/hoytech/strfry) - High-performance relay +- [rnostr](https://github.com/rnostr/rnostr) - Rust relay with NIP-42 +- [NIP-42: Auth](https://github.com/nostr-protocol/nips/blob/master/42.md) +- [NIP-44: Encryption](https://github.com/paulmillr/nip44) +- [NIP-17: Private DMs](https://nips.nostr.com/17) + ### Reference Implementations - [FOSSA ATM](https://github.com/lnbits/fossa) - LNbits Lightning ATM - [Bleskomat](https://github.com/samotari/bleskomat) - Minimal Lightning ATM - [RoboSats](https://github.com/RoboSats/robosats) - KYC-free P2P exchange -- [RoboSats](https://github.com/RoboSats/robosats) - KYC-free P2P exchange diff --git a/docs/modernization-plan.md b/docs/modernization-plan.md index dbf85a6..22b8b5b 100644 --- a/docs/modernization-plan.md +++ b/docs/modernization-plan.md @@ -514,6 +514,7 @@ test('user can complete transaction', async ({ page }) => { ## Related Notes - [[architecture-review]] - **KYC-free Lightning-first architecture review** +- [[nostr-native-architecture]] - **Nostr as infrastructure backbone** - [[CLAUDE]] - Claude Code guidance - [[admin-ui-modernization]] - Vue 3 migration for admin dashboard - [[machine-ui-modernization]] - Vue 3 migration for kiosk UI diff --git a/docs/nostr-native-architecture.md b/docs/nostr-native-architecture.md new file mode 100644 index 0000000..6d2fc6e --- /dev/null +++ b/docs/nostr-native-architecture.md @@ -0,0 +1,828 @@ +--- +title: Nostr-Native ATM Architecture +created: 2026-01-22 +updated: 2026-01-22 +tags: + - architecture + - nostr + - lightning-pub + - kyc-free + - decentralized +status: active +priority: critical +--- + +# Nostr-Native ATM Architecture + +> [!abstract] Summary +> A radical rethinking of ATM infrastructure where **Nostr becomes the backbone** for identity, communication, and payments. Replaces traditional server infrastructure with Lightning.Pub and a private Nostr relay, eliminating KYC vectors like phone numbers while enabling a truly decentralized, censorship-resistant system. + +## Quick Links + +- [[#Vision: Nostr as Infrastructure]] +- [[#Lightning.Pub as Core Server]] +- [[#Private Relay Architecture]] +- [[#Machine Identity]] +- [[#Replacing SMS with Nostr]] +- [[#Event Schema]] + +--- + +## Vision: Nostr as Infrastructure + +### The Problem with Traditional ATM Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ TRADITIONAL LAMASSU ARCHITECTURE │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ATM ──HTTPS/WSS──► Server ──► PostgreSQL │ +│ │ │ +│ ├──► SMS Gateway (Twilio) │ +│ ├──► Email Service │ +│ ├──► KYC Provider │ +│ └──► Lightning Node │ +│ │ +│ Problems: │ +│ • Phone numbers = KYC vector │ +│ • Complex server infrastructure │ +│ • DNS, SSL, port forwarding required │ +│ • Single point of failure │ +│ • Centralized command/control │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### The Nostr-Native Solution + +``` +┌─────────────────────────────────────────────────────────────┐ +│ NOSTR-NATIVE ATM ARCHITECTURE │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ ATM 1 │ │ ATM 2 │ │ ATM N │ │ +│ │ npub_1 │ │ npub_2 │ │ npub_n │ │ +│ └────┬────┘ └────┬────┘ └────┬────┘ │ +│ │ │ │ │ +│ └────────────┼────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────────┐ │ +│ │ Private Nostr Relay │◄─── NIP-42 Auth │ +│ │ (strfry / rnostr) │ Whitelist: ATMs + │ +│ └───────────┬────────────┘ Operators only │ +│ │ │ +│ ┌───────────┼───────────┐ │ +│ ▼ ▼ ▼ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │Lightning │ │ Operator │ │ Public │ │ +│ │ Pub │ │Dashboard │ │ Relays │ │ +│ │(LND wrap)│ │ (Vue 3) │ │(fallback)│ │ +│ └──────────┘ └──────────┘ └──────────┘ │ +│ │ +│ Benefits: │ +│ • No phone numbers (Nostr DMs instead) │ +│ • Zero server config (no DNS/SSL/ports) │ +│ • Decentralized communication │ +│ • Cryptographic machine identity │ +│ • Censorship-resistant │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## Lightning.Pub as Core Server + +> [!decision] Lightning.Pub Replaces lamassu-server +> A Nostr-native account system that wraps LND and eliminates traditional server complexity. + +### Why Lightning.Pub? + +| Aspect | Traditional Server | Lightning.Pub | +|--------|-------------------|---------------| +| Network config | DNS, SSL, ports, firewall | Zero (uses Nostr relays) | +| Deployment | Complex | One-line install | +| Communication | HTTPS/WebSocket | Nostr events (NIP-44 encrypted) | +| Account system | Custom implementation | Built-in sublayers | +| CLINK support | Must implement | Native | +| Lightning | Separate integration | Wraps LND directly | + +### One-Line Deployment + +```bash +# Linux +wget -qO- https://deploy.lightning.pub | bash + +# macOS +curl -fsSL https://deploy.lightning.pub | bash + +# Everything confined to ~/lightning_pub/ +# No sudo, no root, no system changes +``` + +### Architecture + +``` +Lightning.Pub +├── LND (Lightning Network Daemon) +│ └── Neutrino (SPV Bitcoin) +├── Account System +│ ├── Application Pools (operator level) +│ └── User Accounts (ATM wallets) +├── CLINK Native +│ ├── noffer (static payment codes) +│ └── ndebit (authorized payments) +├── Nostr Communication +│ └── NIP-44 encrypted events +└── Optional: LNURL Bridge (legacy support) +``` + +### What Lightning.Pub Gives Us + +1. **No Port Forwarding** - Nostr relays handle all communication +2. **Multi-User Accounts** - Each ATM gets its own account +3. **CLINK Native** - Static payment codes work out of the box +4. **Liquidity Management** - Auto-quotes from LSPs (Zeus, Voltage, Flashsats) +5. **Watchdog Security** - Monitors for drainage attacks +6. **Production Tested** - Years of real-world deployment + +### Configuration for ATM Fleet + +```bash +# ~/lightning_pub/.env + +# Private relay for machine communication +NOSTR_RELAYS="wss://relay.youratm.company wss://nos.lol" + +# Disable bootstrap peering for full sovereignty +DISABLE_LIQUIDITY_PROVIDER=true + +# Custom LNURL domain (optional, for legacy wallets) +SERVICE_URL=https://ln.youratm.company +``` + +--- + +## Private Relay Architecture + +> [!decision] Run a Restricted Nostr Relay +> NIP-42 authenticated relay that only accepts events from known machines and operators. + +### Why a Private Relay? + +| Concern | Public Relay | Private Relay | +|---------|--------------|---------------| +| Who can read | Anyone | Whitelisted npubs only | +| Who can write | Anyone | Whitelisted npubs only | +| Machine commands | Exposed | Encrypted, restricted | +| Fleet data | Public | Private | +| Censorship | Relay can censor | You control | + +### Relay Options + +| Relay | Language | NIP-42 | Performance | Notes | +|-------|----------|--------|-------------|-------| +| **strfry** | C++ | Yes | Excellent | Plugin system, negentropy sync | +| **rnostr** | Rust | Yes | Excellent | LMDB storage, inspired by strfry | +| **nostr-rs-relay** | Rust | Yes | Good | SQLite/PostgreSQL | + +### NIP-42 Authentication + +``` +┌─────────────────────────────────────────────────────────────┐ +│ NIP-42 AUTH FLOW │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ATM connects to relay │ +│ │ │ +│ ▼ │ +│ Relay sends AUTH challenge │ +│ ["AUTH", ""] │ +│ │ │ +│ ▼ │ +│ ATM signs challenge with its nsec │ +│ { │ +│ "kind": 22242, │ +│ "tags": [ │ +│ ["relay", "wss://relay.youratm.company"], │ +│ ["challenge", ""] │ +│ ], │ +│ "content": "", │ +│ "sig": "" │ +│ } │ +│ │ │ +│ ▼ │ +│ Relay verifies npub is in whitelist │ +│ │ │ +│ ├── Yes → Connection allowed │ +│ └── No → Connection rejected │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### strfry Configuration + +```toml +# strfry.conf + +[relay] +bind = "0.0.0.0" +port = 7777 +realIpHeader = "X-Forwarded-For" + +[relay.info] +name = "ATM Fleet Relay" +description = "Private relay for ATM communication" +contact = "operator@youratm.company" + +# Require NIP-42 authentication +authRequired = true + +[relay.writePolicy] +plugin = "./plugins/whitelist.js" + +[relay.negentropy] +enabled = true +``` + +### Whitelist Plugin (noteguard style) + +```javascript +// plugins/whitelist.js +const ALLOWED_PUBKEYS = new Set([ + 'npub1_atm_001...', // ATM 1 + 'npub1_atm_002...', // ATM 2 + 'npub1_operator...', // Operator +]) + +export function writePolicy(event, sourceInfo) { + if (!sourceInfo.authedPubkey) { + return { action: 'reject', message: 'auth-required: authenticate first' } + } + + if (!ALLOWED_PUBKEYS.has(sourceInfo.authedPubkey)) { + return { action: 'reject', message: 'restricted: not authorized' } + } + + return { action: 'accept' } +} +``` + +### NixOS Module for Relay + +```nix +# relay.nix +{ config, pkgs, ... }: +{ + services.strfry = { + enable = true; + settings = { + relay = { + bind = "127.0.0.1"; + port = 7777; + info = { + name = "ATM Fleet Relay"; + description = "Private NIP-42 authenticated relay"; + }; + authRequired = true; + }; + }; + }; + + # Nginx reverse proxy with SSL + services.nginx.virtualHosts."relay.youratm.company" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:7777"; + proxyWebsockets = true; + }; + }; +} +``` + +--- + +## Machine Identity + +> [!decision] Each ATM Has a Nostr Keypair +> Hardware-bound identity that replaces certificates and enables cryptographic authentication. + +### Identity Model + +``` +┌─────────────────────────────────────────────────────────────┐ +│ MACHINE IDENTITY │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ Traditional: │ +│ • Client certificate (complex PKI) │ +│ • API keys (can be leaked) │ +│ • IP-based auth (unreliable) │ +│ │ +│ Nostr-Native: │ +│ • Machine has nsec (private key) │ +│ • npub is machine identity │ +│ • All events signed by machine │ +│ • Operator whitelist controls access │ +│ • No certificate authority needed │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Key Generation & Storage + +```typescript +// Machine first boot - generate identity +import { generateSecretKey, getPublicKey } from 'nostr-tools' +import { writeFileSync } from 'fs' + +function initMachineIdentity() { + const nsec = generateSecretKey() + const npub = getPublicKey(nsec) + + // Store in secure location (TPM, encrypted file, etc.) + writeFileSync('/etc/lamassu/machine.nsec', nsec, { mode: 0o600 }) + + console.log(`Machine identity: ${npub}`) + console.log('Add this npub to operator whitelist') + + return { nsec, npub } +} +``` + +### Secure Key Storage Options + +| Method | Security | Complexity | Best For | +|--------|----------|------------|----------| +| Encrypted file | Medium | Low | Development | +| TPM 2.0 | High | Medium | Production | +| Secure enclave | Highest | High | High-security | +| HSM | Highest | Highest | Enterprise | + +### Tauri Integration + +```rust +// src-tauri/src/identity.rs +use nostr_sdk::prelude::*; +use std::fs; + +pub struct MachineIdentity { + keys: Keys, +} + +impl MachineIdentity { + pub fn load_or_create() -> Result { + let nsec_path = "/etc/lamassu/machine.nsec"; + + let keys = if fs::metadata(nsec_path).is_ok() { + // Load existing + let nsec = fs::read_to_string(nsec_path)?; + Keys::parse(&nsec)? + } else { + // Generate new + let keys = Keys::generate(); + fs::write(nsec_path, keys.secret_key()?.to_bech32()?)?; + keys + }; + + Ok(Self { keys }) + } + + pub fn npub(&self) -> String { + self.keys.public_key().to_bech32().unwrap() + } + + pub fn sign_event(&self, event: UnsignedEvent) -> Result { + event.sign(&self.keys) + } +} +``` + +--- + +## Replacing SMS with Nostr + +> [!decision] Nostr DMs Replace Phone-Based Messaging +> No phone numbers = no KYC vector. Users provide npub for receipts. + +### What SMS Was Used For (Old Lamassu) + +| Use Case | Old Method | New Method | +|----------|------------|------------| +| Transaction receipt | SMS to phone | NIP-17 DM to npub | +| Verification code | SMS OTP | Not needed (no KYC) | +| Operator alerts | SMS/Email | Nostr events to operator npub | +| Customer notifications | SMS | Optional NIP-17 DM | + +### NIP-17 Private Direct Messages + +```typescript +// Send encrypted receipt to user +import { nip44, nip59 } from 'nostr-tools' + +async function sendReceipt( + userNpub: string, + receipt: TransactionReceipt +) { + const content = JSON.stringify({ + type: 'transaction_receipt', + txid: receipt.txid, + amount: receipt.amountSats, + timestamp: receipt.timestamp, + atmId: receipt.atmNpub, + }) + + // NIP-17: Encrypted gift-wrapped message + const sealedEvent = await nip59.seal( + machineKeys, + userNpub, + { + kind: 14, // Direct message + content, + tags: [], + } + ) + + // Publish to relay + await relay.publish(sealedEvent) +} +``` + +### User Flow (Optional Receipt) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ OPTIONAL RECEIPT FLOW │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ 1. User completes transaction │ +│ │ +│ 2. ATM asks: "Want a receipt?" │ +│ [No Thanks] [Yes, via Nostr] │ +│ │ +│ 3. If yes, user provides npub: │ +│ • Scan NFC card with npub │ +│ • Scan QR code of npub │ +│ • Type npub manually │ +│ │ +│ 4. ATM sends NIP-17 encrypted DM │ +│ • Only user can decrypt │ +│ • Contains: amount, txid, timestamp │ +│ • No phone number collected! │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Operator Alerts via Nostr + +```typescript +// Machine publishes alert event +async function sendOperatorAlert( + alertType: 'low_cash' | 'error' | 'offline', + details: object +) { + const event = { + kind: 30078, // Replaceable application-specific + pubkey: machineNpub, + content: nip44.encrypt( + machineNsec, + operatorNpub, + JSON.stringify({ + type: alertType, + machineId: machineNpub, + timestamp: Date.now(), + details, + }) + ), + tags: [ + ['d', `alert:${machineNpub}`], // Replaceable identifier + ['p', operatorNpub], + ], + } + + await relay.publish(signEvent(event, machineNsec)) +} +``` + +--- + +## Event Schema + +> [!tip] Custom Event Kinds for ATM Operations +> Define application-specific events for machine status, transactions, and commands. + +### Event Kinds + +| Kind | Type | Description | +|------|------|-------------| +| 21001 | CLINK | Offer Request/Response | +| 21002 | CLINK | Debit Request/Response | +| 21003 | CLINK | Management Delegation | +| 30078 | Replaceable | Machine Status | +| 30079 | Replaceable | Cash Levels | +| 14 | NIP-17 | Encrypted Receipt DM | +| 22242 | Ephemeral | NIP-42 Auth | + +### Machine Status Event (Kind 30078) + +```typescript +interface MachineStatusEvent { + kind: 30078 + pubkey: string // Machine npub + content: string // NIP-44 encrypted JSON + tags: [ + ['d', 'status'], // Replaceable identifier + ['p', string], // Operator npub + ] +} + +// Decrypted content: +interface MachineStatus { + online: boolean + lastTransaction: number // timestamp + cashLevels: { + validator: number // bills in validator + dispenser: CassetteLevel[] + } + errors: string[] + version: string +} +``` + +### Transaction Record Event + +```typescript +interface TransactionEvent { + kind: 30079 + pubkey: string // Machine npub + content: string // NIP-44 encrypted + tags: [ + ['d', `tx:${txid}`], + ['p', string], // Operator npub + ] +} + +// Decrypted content: +interface TransactionRecord { + txid: string + type: 'cash_in' | 'cash_out' + amountFiat: number + amountSats: number + fee: number + timestamp: number + paymentMethod: 'lnurl_withdraw' | 'clink_offer' | 'invoice' | 'cashu' + // No user identity stored! +} +``` + +### Operator Command Event + +```typescript +interface CommandEvent { + kind: 21003 // CLINK manage + pubkey: string // Operator npub + content: string // NIP-44 encrypted + tags: [ + ['p', string], // Target machine npub + ] +} + +// Decrypted content: +interface OperatorCommand { + command: 'restart' | 'update' | 'disable' | 'enable' | 'set_limits' + params?: object + timestamp: number + signature: string // Operator signs command +} +``` + +--- + +## Full Stack Architecture + +### Component Diagram + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ NOSTR-NATIVE ATM STACK │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ ATM MACHINE │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ +│ │ │ Vue 3 UI │ │ XState v5 │ │ Rust HAL │ │ │ +│ │ │ (Tauri) │ │ (State) │ │ (Bill/Dispense) │ │ │ +│ │ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │ │ +│ │ │ │ │ │ │ +│ │ ┌──────┴────────────────┴─────────────────────┴──────────┐ │ │ +│ │ │ Nostr Client │ │ │ +│ │ │ • Machine nsec/npub identity │ │ │ +│ │ │ • CLINK SDK for payments │ │ │ +│ │ │ • NIP-44 encryption │ │ │ +│ │ │ • Event publishing/subscription │ │ │ +│ │ └────────────────────────┬───────────────────────────────┘ │ │ +│ └───────────────────────────┼──────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌───────────────────────────────────────────────────────────────┐ │ +│ │ PRIVATE NOSTR RELAY │ │ +│ │ • strfry / rnostr │ │ +│ │ • NIP-42 authentication required │ │ +│ │ • Whitelist: ATM npubs + Operator npubs │ │ +│ │ • Negentropy sync for offline reconciliation │ │ +│ └────────────────────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────┼────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────────┐ │ +│ │ Lightning.Pub │ │ Operator │ │ Public Relays │ │ +│ │ │ │ Dashboard │ │ (Fallback) │ │ +│ │ • LND node │ │ │ │ │ │ +│ │ • Accounts │ │ • Vue 3 app │ │ • nos.lol │ │ +│ │ • CLINK native│ │ • Subscribe │ │ • relay.damus.io │ │ +│ │ • Liquidity │ │ to events │ │ • For CLINK with │ │ +│ └───────────────┘ │ • Send cmds │ │ external users │ │ +│ └───────────────┘ └───────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Data Flow: Cash-In Transaction + +```mermaid +sequenceDiagram + participant User + participant ATM + participant Relay as Private Relay + participant LPub as Lightning.Pub + participant LN as Lightning Network + + User->>ATM: Insert $50 cash + ATM->>ATM: Validate bills (HAL) + ATM->>Relay: Publish status event + + ATM->>ATM: Generate CLINK offer (variable price) + ATM->>ATM: Display QR code + + User->>User: Scan with ShockWallet + User->>Relay: CLINK offer request (Kind 21001) + Relay->>ATM: Forward request + + ATM->>LPub: Request invoice (amount calculated) + LPub->>ATM: BOLT11 invoice + ATM->>Relay: CLINK response with invoice + Relay->>User: Forward response + + User->>LN: Pay invoice + LN->>LPub: Payment received + LPub->>Relay: Payment confirmation event + Relay->>ATM: Forward confirmation + + ATM->>ATM: Transaction complete + ATM->>Relay: Publish transaction record + + opt User provided npub + ATM->>Relay: Send NIP-17 receipt DM + end +``` + +--- + +## Migration Path + +### Phase 1: Add Nostr Layer + +``` +Existing Lamassu ──► Add Nostr client + Add private relay + Keep existing server (parallel) +``` + +### Phase 2: Lightning.Pub Integration + +``` +Add Lightning.Pub ──► Route payments through LPub + CLINK offers enabled + Account system active +``` + +### Phase 3: Full Migration + +``` +Remove old server ──► Nostr-only communication + NIP-17 receipts (no SMS) + Private relay primary +``` + +### Phase 4: Optional Enhancements + +``` +Advanced features ──► Cashu ecash integration + Fedimint support + Multi-relay redundancy +``` + +--- + +## Security Considerations + +### Threat Model + +| Threat | Mitigation | +|--------|------------| +| Relay compromise | NIP-44 encryption (relay can't read) | +| Key theft | TPM/HSM storage, key rotation | +| Replay attacks | Timestamps, nonces in events | +| Rogue operator | Multi-sig commands (future) | +| Network sniffing | WebSocket over TLS, NIP-44 | + +### Key Rotation + +```typescript +// Periodic key rotation for machines +async function rotateMachineKey(oldNsec: string) { + const newKeys = generateKeys() + + // Publish key rotation event (signed by old key) + const rotationEvent = { + kind: 30078, + content: nip44.encrypt(oldNsec, operatorNpub, JSON.stringify({ + type: 'key_rotation', + oldPubkey: getPublicKey(oldNsec), + newPubkey: newKeys.npub, + timestamp: Date.now(), + })), + tags: [ + ['d', 'key_rotation'], + ['p', operatorNpub], + ], + } + + await relay.publish(signEvent(rotationEvent, oldNsec)) + + // Operator must update whitelist + // Then switch to new key +} +``` + +--- + +## Comparison: Old vs Nostr-Native + +| Aspect | Old Lamassu | Nostr-Native | +|--------|-------------|--------------| +| Communication | HTTPS/WebSocket | Nostr events | +| Authentication | Client certs | NIP-42 + npub whitelist | +| Encryption | TLS | NIP-44 (content-level) | +| Identity | PKI certificates | Nostr keypairs | +| Receipts | SMS (phone = KYC) | NIP-17 DMs (npub) | +| Alerts | Email/SMS | Nostr events | +| Server config | DNS, SSL, ports | Zero config | +| Deployment | Complex | One-line | +| Censorship | Server can be seized | Relay-agnostic | +| Privacy | Phone numbers leaked | Pseudonymous npubs | + +--- + +## Open Questions + +1. **Relay redundancy** - Should machines connect to multiple relays? +2. **Offline operation** - How long can machine operate without relay? +3. **Key escrow** - How to recover if machine key is lost? +4. **Multi-operator** - Can multiple operators share a fleet? +5. **Cashu over Nostr** - Use Nostr for ecash token delivery? + +--- + +## Related Notes + +- [[architecture-review]] - Overall KYC-free architecture +- [[lnbits-integration]] - LNbits as alternative backend +- [[hardware-recommendations]] - Hardware choices +- [[machine-ui-modernization]] - Vue 3 UI migration + +--- + +## References + +### Lightning.Pub +- [Lightning.Pub GitHub](https://github.com/shocknet/Lightning.Pub) +- [ShockWallet](https://github.com/shocknet/wallet2) +- [CLINK Protocol](https://github.com/shocknet/CLINK) + +### Nostr Relays +- [strfry](https://github.com/hoytech/strfry) +- [rnostr](https://github.com/rnostr/rnostr) +- [nostr-rs-relay](https://sr.ht/~gheartsfield/nostr-rs-relay/) +- [noteguard](https://github.com/damus-io/noteguard) - strfry plugin system + +### NIPs +- [NIP-42: Authentication](https://github.com/nostr-protocol/nips/blob/master/42.md) +- [NIP-44: Versioned Encryption](https://github.com/paulmillr/nip44) +- [NIP-17: Private Direct Messages](https://nips.nostr.com/17) +- [NIP-59: Gift Wraps](https://github.com/nostr-protocol/nips/blob/master/59.md)