diff --git a/src/cli.ts b/src/cli.ts index c682760..d37d35f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1319,8 +1319,6 @@ nwcCmd method: "POST", body: { connectionString }, }); - - console.log("\nRun 'routstrd restart' to connect to the NWC wallet."); }); nwcCmd @@ -1330,7 +1328,6 @@ nwcCmd await handleDaemonCommand("/nwc/disconnect", { method: "POST", }); - console.log("\nRun 'routstrd restart' to apply."); }); nwcCmd diff --git a/src/daemon/http/index.ts b/src/daemon/http/index.ts index 23efeb2..ff1b2d0 100644 --- a/src/daemon/http/index.ts +++ b/src/daemon/http/index.ts @@ -468,10 +468,12 @@ export function createDaemonRequestHandler(deps: { }; saveDaemonConfig(config); + // Hot-reload: reconnect the wallet adapter with the new connection string + await deps.walletAdapter.reconnect(connectionString); + return { output: { - message: - "NWC connection string saved. Restart the daemon to connect.", + message: "NWC connection string saved and connected.", }, }; }); @@ -488,8 +490,12 @@ export function createDaemonRequestHandler(deps: { } } saveDaemonConfig(config); + + // Hot-reload: disconnect the wallet adapter + await deps.walletAdapter.reconnect(); + return { - output: { message: "NWC disconnected. Restart the daemon to apply." }, + output: { message: "NWC disconnected." }, }; }); return; diff --git a/src/daemon/wallet/auto-refill.ts b/src/daemon/wallet/auto-refill.ts index 8ada839..8305942 100644 --- a/src/daemon/wallet/auto-refill.ts +++ b/src/daemon/wallet/auto-refill.ts @@ -34,7 +34,7 @@ function isFatalError(message: string): boolean { export function startAutoRefillLoop( cocod: CocodClient, - wallet: WalletConnect, + getWallet: () => WalletConnect | undefined, getConfig: () => AutoRefillConfig | undefined, intervalMs: number = 5000, ): () => void { @@ -47,7 +47,8 @@ export function startAutoRefillLoop( async function checkAndRefill(): Promise { if (!running) return; if (checkInProgress) return; - if (!wallet.service) { + const wallet = getWallet(); + if (!wallet?.service) { // NWC not connected — nothing to do return; } @@ -108,7 +109,12 @@ export function startAutoRefillLoop( // Step 2: Pay the invoice via NWC (applesauce) logger.log(`[auto-refill] Paying invoice via NWC...`); - const { preimage, fees_paid } = await wallet.payInvoice(invoice); + const currentWallet = getWallet(); + if (!currentWallet?.service) { + logger.log("[auto-refill] Wallet disconnected during refill check"); + return; + } + const { preimage, fees_paid } = await currentWallet.payInvoice(invoice); // Step 3: The Cashu mint should automatically detect the paid invoice // and issue tokens. We don't need to explicitly mint here; cocod diff --git a/src/daemon/wallet/index.ts b/src/daemon/wallet/index.ts index 129e6a2..a7a9711 100644 --- a/src/daemon/wallet/index.ts +++ b/src/daemon/wallet/index.ts @@ -67,6 +67,9 @@ export async function createWalletAdapter( let wallet: WalletConnect | undefined; let pool: RelayPool | undefined; + // Getter for the current wallet instance (used by auto-refill loop) + const getWallet = (): WalletConnect | undefined => wallet; + if (options.nwcConnectionString) { pool = new RelayPool(); wallet = WalletConnect.fromConnectURI(options.nwcConnectionString, { pool }); @@ -84,6 +87,42 @@ export async function createWalletAdapter( } const walletAdapter = { + async reconnect(connectionString?: string): Promise { + logger.log( + `[nwc] Reconnecting NWC wallet... ${connectionString ? "new connection string provided" : "disconnecting"}`, + ); + + // 1. Close existing relay pool connections + if (pool) { + for (const [url] of pool.relays) { + pool.remove(url, true); + } + } + + // 2. Update wallet reference + wallet = undefined; + pool = undefined; + + // 3. Create new wallet if connection string provided + if (connectionString) { + pool = new RelayPool(); + wallet = WalletConnect.fromConnectURI(connectionString, { pool }); + + // Connect in background (non-blocking) + wallet.waitForService() + .then(() => { + logger.log( + `[nwc] NWC wallet reconnected. Relay: ${wallet!.relays[0]}, Service: ${wallet!.service}`, + ); + }) + .catch((err) => { + logger.error(`[nwc] NWC reconnection failed: ${err.message}`); + }); + } else { + logger.log("[nwc] NWC wallet disconnected."); + } + }, + async getBalances(): Promise> { return syncMintState(); }, @@ -278,14 +317,14 @@ export async function createWalletAdapter( if (autoRefillConfig && wallet) { const getConfig = options.getAutoRefillConfig ?? (() => options.autoRefill); - stopAutoRefill = startAutoRefillLoop(client, wallet, getConfig); + stopAutoRefill = startAutoRefillLoop(client, getWallet, getConfig); logger.log( `[wallet] Auto-refill enabled: threshold=${autoRefillConfig.threshold} sats, amount=${autoRefillConfig.amount} sats, cooldown=${autoRefillConfig.cooldownMs}ms`, ); } else if (wallet && options.getAutoRefillConfig) { // Wallet exists but auto-refill is not currently enabled. // Start the loop anyway so it can pick up changes without a restart. - stopAutoRefill = startAutoRefillLoop(client, wallet, options.getAutoRefillConfig); + stopAutoRefill = startAutoRefillLoop(client, getWallet, options.getAutoRefillConfig); logger.log("[wallet] Auto-refill loop started (currently disabled — enable via CLI to activate)"); }