diff --git a/lamassu-next/apps/machine/src/services/lightning.ts b/lamassu-next/apps/machine/src/services/lightning.ts index f8a6dec..18eb69e 100644 --- a/lamassu-next/apps/machine/src/services/lightning.ts +++ b/lamassu-next/apps/machine/src/services/lightning.ts @@ -33,25 +33,37 @@ import type { ATMServices, ATMContext } from '@lamassu/state-machine' // Check if we're in a browser environment const isBrowser = typeof window !== 'undefined' -// Development infrastructure configuration -// In production, these would come from environment or secure config -// Use local network IP for testing from other devices (e.g., Shock Wallet on phone) -const LOCAL_IP = '192.168.1.122' // Change this to your machine's local IP +/** + * Lightning configuration from environment variables + * + * Environment variables (prefix with VITE_ for Vite): + * - VITE_RELAY_URL: Nostr relay WebSocket URL + * - VITE_LIGHTNING_PUB_PUBKEY: Lightning.Pub's Nostr pubkey (hex or npub) + * - VITE_LIGHTNING_PUB_API_URL: Lightning.Pub HTTP API URL + * - VITE_ATM_PRIVATE_KEY: ATM's Nostr private key (hex or nsec) + * - VITE_ADMIN_TOKEN: Lightning.Pub admin token (dev only) + */ +function loadLightningConfig() { + // Development defaults (local Docker infrastructure) + const defaults = { + relayUrl: 'ws://localhost:7777', + lightningPubPubkey: '', + lightningPubApiUrl: 'http://localhost:1776', + adminToken: 'lamassu-dev-admin-token', + atmPrivateKey: '', + } -const DEV_CONFIG = { - // Lightning.Pub Nostr pubkey (from docker logs - check with: docker logs lamassu-lightning-pub | grep pubkey) - lightningPubPubkey: '4be8e203a3341bb2b74a4dcbf8774e061437f63ec21af7ec3144c8d0a68e2f39', - // Local strfry relay - use local IP for cross-device testing - relayUrl: `ws://${LOCAL_IP}:7777`, - // Admin token for HTTP API (development only) - adminToken: 'lamassu-dev-admin-token', - // Lightning.Pub HTTP API - lightningPubApiUrl: `http://${LOCAL_IP}:1776`, - // Fixed dev identity for testing (fund this pubkey in Lightning.Pub) - // In production, identity is loaded from secure storage - devPrivateKey: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', + return { + relayUrl: import.meta.env.VITE_RELAY_URL || defaults.relayUrl, + lightningPubPubkey: import.meta.env.VITE_LIGHTNING_PUB_PUBKEY || defaults.lightningPubPubkey, + lightningPubApiUrl: import.meta.env.VITE_LIGHTNING_PUB_API_URL || defaults.lightningPubApiUrl, + adminToken: import.meta.env.VITE_ADMIN_TOKEN || defaults.adminToken, + atmPrivateKey: import.meta.env.VITE_ATM_PRIVATE_KEY || defaults.atmPrivateKey, + } } +const CONFIG = loadLightningConfig() + interface LightningServices { nostrClient: NostrClient lightningPub: LightningPubClient @@ -75,27 +87,45 @@ type PaymentReceivedCallback = (preimage: string) => void */ export async function initializeLightningServices(): Promise { console.log('[Lightning] Initializing services...') + console.log('[Lightning] Relay URL:', CONFIG.relayUrl) + console.log('[Lightning] Lightning.Pub pubkey:', CONFIG.lightningPubPubkey || '(not configured)') - // Use fixed dev identity for testing (in production, load from secure storage) - // This allows us to fund the account once and reuse across page reloads - const identity = isBrowser ? loadIdentityFromHex(DEV_CONFIG.devPrivateKey) : generateIdentity() - console.log('[Lightning] Machine identity:', identity.publicKey) - console.log('[Lightning] Fund this pubkey in Lightning.Pub for testing') + // Validate required configuration + if (!CONFIG.lightningPubPubkey) { + throw new Error( + '[Lightning] VITE_LIGHTNING_PUB_PUBKEY is required. ' + + 'Get it from: docker logs lamassu-lightning-pub | grep pubkey' + ) + } + + // Load or generate ATM identity + let identity: MachineIdentity + if (CONFIG.atmPrivateKey) { + // Use configured private key + identity = loadIdentityFromHex(CONFIG.atmPrivateKey) + console.log('[Lightning] Loaded ATM identity from config') + } else { + // Generate new identity (for development/testing) + identity = generateIdentity() + console.warn('[Lightning] No VITE_ATM_PRIVATE_KEY configured - generated ephemeral identity') + console.warn('[Lightning] Set VITE_ATM_PRIVATE_KEY for persistent identity across restarts') + } + console.log('[Lightning] ATM pubkey:', identity.publicKey) // Create Nostr client const nostrClient = new NostrClient({ - relays: [{ url: DEV_CONFIG.relayUrl }], + relays: [{ url: CONFIG.relayUrl }], identity, }) // Connect to relay await nostrClient.connect() - console.log('[Lightning] Connected to relay:', DEV_CONFIG.relayUrl) + console.log('[Lightning] Connected to relay:', CONFIG.relayUrl) // Create Lightning.Pub client const lightningPub = new LightningPubClient({ - accountPubkey: DEV_CONFIG.lightningPubPubkey, - relays: [DEV_CONFIG.relayUrl], + accountPubkey: CONFIG.lightningPubPubkey, + relays: [CONFIG.relayUrl], }) lightningPub.initialize(nostrClient, identity) @@ -105,8 +135,8 @@ export async function initializeLightningServices(): Promise const clink = new CLINKClient({ nostrClient, identity, - operatorPubkey: DEV_CONFIG.lightningPubPubkey, // Use Lightning.Pub as operator for dev - relays: [DEV_CONFIG.relayUrl], + operatorPubkey: CONFIG.lightningPubPubkey, // Use Lightning.Pub as operator for dev + relays: [CONFIG.relayUrl], }) // Callbacks for events @@ -208,8 +238,8 @@ function createATMServices( // so it must be Lightning.Pub's pubkey for it to receive and pay. // The pointer identifies which Lightning.Pub user account pays (e.g., "atm") const ndebit = encodeNdebit({ - pubkey: DEV_CONFIG.lightningPubPubkey, - relay: DEV_CONFIG.relayUrl, + pubkey: CONFIG.lightningPubPubkey, + relay: CONFIG.relayUrl, pointer: 'atm', // Lightning.Pub user identifier for the ATM account }) @@ -514,4 +544,4 @@ export function watchInvoice( }) } -export { DEV_CONFIG } +export { CONFIG } diff --git a/lamassu-next/docs/machine-installation.md b/lamassu-next/docs/machine-installation.md index 189438b..e842481 100644 --- a/lamassu-next/docs/machine-installation.md +++ b/lamassu-next/docs/machine-installation.md @@ -119,16 +119,24 @@ See [Device Configuration](./device-configuration.md) for detailed configuration The ATM needs to connect to a Lightning.Pub instance. Configure via environment: ```bash -# Nostr relay URL -VITE_NOSTR_RELAY_URL=wss://your-relay.example.com +# Nostr relay WebSocket URL (required) +VITE_RELAY_URL=wss://your-relay.example.com -# Lightning.Pub public key -VITE_LIGHTNING_PUB_PUBKEY=npub1... +# Lightning.Pub's Nostr public key (required) +# Get from: docker logs lamassu-lightning-pub | grep pubkey +VITE_LIGHTNING_PUB_PUBKEY=4be8e203a3341bb2b74a4dcbf8774e061437f63ec21af7ec3144c8d0a68e2f39 -# ATM keypair (generate with: npx @lamassu/nostr-client generate-keypair) -VITE_ATM_NSEC=nsec1... +# Lightning.Pub HTTP API URL (optional, for admin operations) +VITE_LIGHTNING_PUB_API_URL=https://lp.operator.com + +# ATM's Nostr private key (recommended for persistent identity) +# Generate with: npx @lamassu/nostr-client generate-keypair +# If not set, a new ephemeral identity is generated on each restart +VITE_ATM_PRIVATE_KEY=0123456789abcdef... ``` +**Important:** The `VITE_LIGHTNING_PUB_PUBKEY` is required. Without it, the ATM cannot communicate with Lightning.Pub. + ## Auto-Start on Boot ### Systemd Service