From 99aad424ef4e3aef8605c7f58c48eeaabdcc395c Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Mon, 27 Apr 2026 03:32:10 -0400 Subject: [PATCH] local customizations: fava, litd, extensions path, lndconnect --- CLAUDE.md | 90 +++++++++++++++++++++++++++++++++++++ docker-compose.yml | 17 ++++--- lndconnect.sh | 110 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 CLAUDE.md create mode 100755 lndconnect.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..94e7945 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,90 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This is a Bitcoin Lightning Network regtest environment for local development and testing. It provides a Docker Compose setup with multiple interconnected Lightning nodes (LND, Core Lightning, Eclair), Bitcoin Core, Elements/Liquid sidechain, and supporting services like LNbits, Boltz, and Electrs. + +## Common Commands + +### Start the Environment +```sh +./start-regtest # Start all services and run initialization tests +source docker-scripts.sh # Load helper functions for CLI access +``` + +### Stop the Environment +```sh +source docker-scripts.sh +lnbits-regtest-stop # Stops containers and cleans up node data +``` + +### CLI Helpers (after sourcing docker-scripts.sh) +```sh +bitcoin-cli-sim -generate 1 # Mine blocks +lightning-cli-sim 1 getinfo # CLN node 1 (use 1, 2, or 3) +lncli-sim 1 getinfo # LND node 1 (use 1, 2, 3, or 4) +elements-cli-sim getinfo # Elements/Liquid +boltzcli-sim getinfo # Boltz client +``` + +### View Logs +```sh +docker logs lnbits-lnbits-1 -f +docker logs lnbits-lnd-1-1 -f +docker logs lnbits-clightning-1-1 -f +docker logs lnbits-boltz-1 -f +``` + +## Architecture + +### Lightning Network Topology +- **lnd-1**: Hub node with channels to all other nodes. Used for local LNbits testing +- **lnd-2**: Used for Boltz backend swaps +- **lnd-3**: Backend for the dockerized LNbits instance +- **lnd-4**: Standalone node +- **cln-1, cln-2, cln-3**: Core Lightning nodes. cln-2 has REST API via clightning-2-rest +- **eclair-1**: Eclair node with channels from lnd-1 and lnd-2 + +### Channel Graph +lnd-1 is the central hub connected to: lnd-2, lnd-3, cln-1, cln-2, cln-3, eclair-1. Additional connections: lnd-2→cln-2, lnd-3→cln-3, lnd-3→cln-1, lnd-2→eclair-1 + +### Supporting Services +- **bitcoind**: Regtest Bitcoin Core (RPC on 18443) +- **elementsd**: Liquid regtest sidechain (RPC on 18884) +- **electrs**: Bitcoin Electrum server (ports 19001, 3002) +- **electrs-liquid**: Liquid Electrum server (ports 19002, 3003) +- **boltz + boltz-client**: Swap service with Postgres backend +- **lnbits**: Lightning wallet/app platform (port 5001) +- **litd**: Lightning Terminal connected to lnd-1 (ports 8443, 8080) +- **fava**: Beancount accounting interface (port 3333) + +## Web Interfaces +- LNbits: http://localhost:5001/ +- Mempool (via electrs): http://localhost:3002/ +- Boltz API: http://localhost:9001/ +- Lightning Terminal: https://localhost:8443/ (password: testpassword123) +- Fava: http://localhost:3333/ +- Eclair API: http://localhost:8082/ (password: lnbits) + +## Configuration for Local LNbits Development + +When running LNbits locally against this regtest: + +```sh +# LND backend +LNBITS_BACKEND_WALLET_CLASS="LndRestWallet" +LND_REST_ENDPOINT=https://127.0.0.1:8081/ +LND_REST_CERT=./docker/data/lnd-1/tls.cert +LND_REST_MACAROON=./docker/data/lnd-1/data/chain/bitcoin/regtest/admin.macaroon + +# Or CLN backend +LNBITS_BACKEND_WALLET_CLASS="CoreLightningWallet" +CORELIGHTNING_RPC=./docker/data/clightning-1/regtest/lightning-rpc +``` + +## Data Persistence +- Node data stored in `./data//` +- `lnbits-regtest-stop` cleans up Lightning node directories but preserves config files +- Bitcoin/Elements data uses Docker volumes (cleaned on stop) diff --git a/docker-compose.yml b/docker-compose.yml index 996b6e9..232b814 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -222,7 +222,7 @@ services: hostname: lnd-1 depends_on: - bitcoind - image: boltz/lnd:0.18.4-beta + image: boltz/lnd:0.19.3-beta restart: on-failure command: - --listen=lnd-1:9735 @@ -237,6 +237,7 @@ services: - --bitcoind.zmqpubrawblock=bitcoind:29001 - --noseedbackup - --protocol.wumbo-channels + - --rpcmiddleware.enable expose: - 8081 - 9735 @@ -340,8 +341,12 @@ services: - -c - | echo "Waiting for LND to be ready..." - sleep 30 - exec /usr/local/bin/litd \ + while ! nc -z lnd-1 10009 2>/dev/null; do + echo "Waiting for lnd-1:10009..." + sleep 2 + done + sleep 5 + exec /bin/litd \ --httpslisten=0.0.0.0:8443 \ --insecure-httplisten=0.0.0.0:8080 \ --uipassword=testpassword123 \ @@ -350,14 +355,12 @@ services: --remote.lnd.rpcserver=lnd-1:10009 \ --remote.lnd.macaroonpath=/root/.lnd/data/chain/bitcoin/regtest/admin.macaroon \ --remote.lnd.tlscertpath=/root/.lnd/tls.cert \ - --autopilot.disable=true \ - --loop.server.host=localhost:11009 \ - --loop.server.notls=true + --autopilot.disable ports: - 8443:8443 - 8080:8080 volumes: - - ./data/lnd-1:/root/.lnd:ro + - ./data/lnd-1:/root/.lnd - ./data/litd:/root/.lit eclair: diff --git a/lndconnect.sh b/lndconnect.sh new file mode 100755 index 0000000..7af3378 --- /dev/null +++ b/lndconnect.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# +# Generate lndconnect QR strings for Zeus wallet connection +# +# Usage: +# ./lndconnect.sh [node-number] +# +# Examples: +# ./lndconnect.sh 1 # lnd-1 (requires port exposure) +# ./lndconnect.sh 3 # lnd-3 (REST port 8081 exposed by default) +# ./lndconnect.sh 4 # lnd-4 (Lightning.Pub's node, requires port exposure) +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +NODE_NUM="${1:-3}" +DATA_DIR="$SCRIPT_DIR/data/lnd-$NODE_NUM" + +# Colors +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +log() { echo -e "${GREEN}[lndconnect]${NC} $1"; } +warn() { echo -e "${YELLOW}[lndconnect]${NC} $1"; } +error() { echo -e "${RED}[lndconnect]${NC} $1"; exit 1; } + +# Get local IP +get_local_ip() { + ip route get 1 2>/dev/null | awk '{print $7; exit}' || hostname -I | awk '{print $1}' +} + +# Base64url encode (no padding, URL-safe) +base64url_encode() { + base64 -w0 | tr '+/' '-_' | tr -d '=' +} + +# Check if node data exists +if [ ! -d "$DATA_DIR" ]; then + error "Node data directory not found: $DATA_DIR" +fi + +MACAROON_PATH="$DATA_DIR/data/chain/bitcoin/regtest/admin.macaroon" +CERT_PATH="$DATA_DIR/tls.cert" + +if [ ! -f "$MACAROON_PATH" ]; then + error "Macaroon not found: $MACAROON_PATH" +fi + +if [ ! -f "$CERT_PATH" ]; then + error "TLS cert not found: $CERT_PATH" +fi + +# Get host IP +HOST_IP=$(get_local_ip) + +# Determine REST port based on node +case $NODE_NUM in + 3) REST_PORT=8081 ;; # Exposed in docker-compose + *) + warn "lnd-$NODE_NUM REST port may not be exposed to host." + warn "You may need to add port mapping to docker-compose.yml" + REST_PORT=8081 + ;; +esac + +log "Generating lndconnect for lnd-$NODE_NUM..." +log "Host: $HOST_IP:$REST_PORT" + +# Encode macaroon and cert +MACAROON_B64=$(cat "$MACAROON_PATH" | base64url_encode) +CERT_B64=$(cat "$CERT_PATH" | base64url_encode) + +# Build lndconnect URL +LNDCONNECT_URL="lndconnect://${HOST_IP}:${REST_PORT}?macaroon=${MACAROON_B64}&cert=${CERT_B64}" + +echo "" +echo "============================================================" +echo "lndconnect URL for lnd-$NODE_NUM:" +echo "============================================================" +echo "" +echo "$LNDCONNECT_URL" +echo "" + +# Generate QR code if qrencode is available +if command -v qrencode &>/dev/null; then + log "Generating QR code..." + echo "" + qrencode -t ANSIUTF8 "$LNDCONNECT_URL" + echo "" +else + warn "Install 'qrencode' for terminal QR code: sudo pacman -S qrencode" +fi + +echo "============================================================" +echo "Instructions:" +echo "============================================================" +echo "1. Open Zeus wallet" +echo "2. Go to Settings → Add a new node" +echo "3. Scan QR or paste the lndconnect URL" +echo "" +if [ "$NODE_NUM" != "3" ]; then + echo "NOTE: lnd-$NODE_NUM REST port is not exposed by default." + echo "Add this to docker-compose.yml under lnd-$NODE_NUM:" + echo " ports:" + echo " - '808$NODE_NUM:8081'" + echo "" +fi