Implement multiple sweep destination modes (static, address list, xpub) with state management and update configuration scripts. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 418bf6f8-212b-4bb0-a7a5-8231a061da4e Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 8df121fd-c189-4c73-a76b-d9a3e07de783 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9f85e954-647c-46a5-90a7-396e495a805a/418bf6f8-212b-4bb0-a7a5-8231a061da4e/sPDHkg8 Replit-Helium-Checkpoint-Created: true
194 lines
8.5 KiB
Bash
Executable File
194 lines
8.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ============================================================
|
|
# LND wallet initialization + LNbits startup
|
|
# Run AFTER Bitcoin sync is complete (verificationprogress ~1.0)
|
|
# Run as root on the droplet: bash /opt/timmy-node/lnd-init.sh
|
|
# ============================================================
|
|
set -euo pipefail
|
|
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
|
info() { echo -e "${CYAN}[lnd-init]${NC} $*"; }
|
|
ok() { echo -e "${GREEN}[ok]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
|
|
die() { echo -e "${RED}[error]${NC} $*"; exit 1; }
|
|
|
|
INFRA_DIR="/opt/timmy-node"
|
|
CREDS_FILE="/root/node-credentials.txt"
|
|
|
|
# ── Check Bitcoin sync ───────────────────────────────────────
|
|
info "Checking Bitcoin sync status..."
|
|
PROGRESS=$(docker exec bitcoin bitcoin-cli -datadir=/home/bitcoin/.bitcoin getblockchaininfo 2>/dev/null | jq -r .verificationprogress || echo "0")
|
|
info "Chain sync progress: $PROGRESS"
|
|
if (( $(echo "$PROGRESS < 0.999" | bc -l) )); then
|
|
warn "Bitcoin is not fully synced yet (progress: $PROGRESS)"
|
|
warn "LND needs a synced chain to function correctly."
|
|
read -rp "Continue anyway? (y/N) " CONFIRM
|
|
[[ "$CONFIRM" != "y" ]] && die "Aborting. Run again when sync is complete."
|
|
fi
|
|
|
|
# ── Start LND ────────────────────────────────────────────────
|
|
info "Starting LND..."
|
|
cd "$INFRA_DIR"
|
|
docker compose up -d lnd
|
|
sleep 5
|
|
|
|
# ── Wallet init ──────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} LND Wallet Setup${NC}"
|
|
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo -e " Choose one:"
|
|
echo -e " ${GREEN}c${NC} — Create a NEW wallet (generates a fresh seed phrase)"
|
|
echo -e " ${YELLOW}r${NC} — Restore from existing 24-word seed"
|
|
echo ""
|
|
read -rp " Your choice [c/r]: " WALLET_CHOICE
|
|
|
|
if [[ "$WALLET_CHOICE" == "r" ]]; then
|
|
info "Restoring wallet from seed..."
|
|
docker exec -it lnd lncli --network=mainnet create --recovery-window=2500
|
|
else
|
|
info "Creating new wallet..."
|
|
docker exec -it lnd lncli --network=mainnet create
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${RED}══════════════════════════════════════════════${NC}"
|
|
echo -e "${RED} CRITICAL: Write down your 24-word seed phrase${NC}"
|
|
echo -e "${RED} It was shown above. Store it offline, safely.${NC}"
|
|
echo -e "${RED} This is the ONLY way to recover your funds.${NC}"
|
|
echo -e "${RED}══════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
read -rp " I have written down my seed phrase. Press enter to continue..."
|
|
|
|
# ── Wait for LND to be ready ─────────────────────────────────
|
|
info "Waiting for LND to be ready..."
|
|
for i in {1..30}; do
|
|
STATE=$(docker exec lnd lncli --network=mainnet state 2>/dev/null | jq -r .state || echo "")
|
|
if [[ "$STATE" == "SERVER_ACTIVE" ]]; then
|
|
ok "LND is active"
|
|
break
|
|
fi
|
|
echo -n "."
|
|
sleep 5
|
|
done
|
|
echo ""
|
|
|
|
# ── Get LND pubkey ───────────────────────────────────────────
|
|
PUBKEY=$(docker exec lnd lncli --network=mainnet getinfo 2>/dev/null | jq -r .identity_pubkey || echo "")
|
|
if [[ -n "$PUBKEY" ]]; then
|
|
ok "LND node pubkey: $PUBKEY"
|
|
echo "LND_PUBKEY=$PUBKEY" >> "$CREDS_FILE"
|
|
fi
|
|
|
|
# ── Start LNbits ─────────────────────────────────────────────
|
|
info "Starting LNbits..."
|
|
docker compose up -d lnbits
|
|
sleep 8
|
|
|
|
# ── Wait for LNbits ──────────────────────────────────────────
|
|
for i in {1..20}; do
|
|
if curl -sf http://127.0.0.1:5000/api/v1/health &>/dev/null; then
|
|
ok "LNbits is up"
|
|
break
|
|
fi
|
|
echo -n "."
|
|
sleep 3
|
|
done
|
|
echo ""
|
|
|
|
# ── Enable Tailscale Funnel for LNbits ───────────────────────
|
|
info "Exposing LNbits via Tailscale Funnel (public HTTPS)..."
|
|
tailscale serve --bg http://127.0.0.1:5000
|
|
tailscale funnel --bg 443
|
|
|
|
TAILSCALE_HOSTNAME=$(tailscale status --json | jq -r '.Self.DNSName' | sed 's/\.$//')
|
|
LNBITS_URL="https://$TAILSCALE_HOSTNAME"
|
|
|
|
ok "LNbits is available at: $LNBITS_URL"
|
|
echo "LNBITS_URL=$LNBITS_URL" >> "$CREDS_FILE"
|
|
|
|
# ── Create Timmy wallet in LNbits ────────────────────────────
|
|
info "Creating Timmy wallet in LNbits..."
|
|
sleep 3
|
|
|
|
# Create a user + wallet via LNbits API
|
|
LNBITS_ADMIN_KEY=$(curl -sf http://127.0.0.1:5000/api/v1/wallets \
|
|
-H "Content-Type: application/json" \
|
|
| jq -r '.[0].adminkey' 2>/dev/null || echo "")
|
|
|
|
if [[ -z "$LNBITS_ADMIN_KEY" ]]; then
|
|
warn "Could not auto-create wallet. Open $LNBITS_URL in browser,"
|
|
warn "create a wallet called 'Timmy', and copy the Invoice Key."
|
|
else
|
|
# Create a dedicated Timmy wallet
|
|
TIMMY_WALLET=$(curl -sf http://127.0.0.1:5000/api/v1/account \
|
|
-X POST \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Api-Key: $LNBITS_ADMIN_KEY" \
|
|
-d '{"name":"Timmy"}' 2>/dev/null || echo "{}")
|
|
|
|
TIMMY_INVOICE_KEY=$(echo "$TIMMY_WALLET" | jq -r '.wallets[0].inkey' 2>/dev/null || echo "")
|
|
|
|
if [[ -n "$TIMMY_INVOICE_KEY" ]]; then
|
|
ok "Timmy wallet created"
|
|
echo "LNBITS_API_KEY=$TIMMY_INVOICE_KEY" >> "$CREDS_FILE"
|
|
fi
|
|
fi
|
|
|
|
# ── Configure cold storage sweep ────────────────────────────
|
|
echo ""
|
|
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN} Cold Storage Auto-Sweep Setup${NC}"
|
|
echo -e "${CYAN}══════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo -e " Excess on-chain sats above your threshold are automatically"
|
|
echo -e " sent to a cold address daily. You never touch the hot wallet."
|
|
echo ""
|
|
echo -e " Enter your cold Bitcoin address (hardware wallet, Sparrow, etc.)"
|
|
echo -e " Press Enter to skip — you can configure this later by editing"
|
|
echo -e " $INFRA_DIR/sweep.conf"
|
|
echo ""
|
|
read -rp " Cold address (bc1q... / 1... / 3...): " COLD_ADDRESS
|
|
|
|
SWEEP_CONF="$INFRA_DIR/sweep.conf"
|
|
if [[ -n "$COLD_ADDRESS" ]]; then
|
|
cat > "$SWEEP_CONF" <<CONF
|
|
# Timmy Node — Auto-sweep configuration
|
|
# Change any value then run: bash ops.sh configure-sweep
|
|
|
|
SWEEP_MODE="static"
|
|
COLD_ADDRESS="$COLD_ADDRESS"
|
|
XPUB=""
|
|
KEEP_SATS=300000
|
|
MIN_SWEEP=50000
|
|
SWEEP_CRON="0 3 * * *"
|
|
SWEEP_FREQ_LABEL="daily at 3am UTC"
|
|
CONF
|
|
chmod 600 "$SWEEP_CONF"
|
|
ok "Cold address saved to $SWEEP_CONF"
|
|
info "Change thresholds or frequency anytime: bash $INFRA_DIR/ops.sh configure-sweep"
|
|
else
|
|
warn "No cold address provided — sweep is disabled."
|
|
warn "Configure later: echo 'COLD_ADDRESS=bc1q...' >> $INFRA_DIR/sweep.conf"
|
|
fi
|
|
|
|
# ── Final output ─────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
|
|
echo -e "${GREEN} LND + LNbits ready — set these in Replit:${NC}"
|
|
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
grep "LNBITS_URL\|LNBITS_API_KEY" "$CREDS_FILE" 2>/dev/null || true
|
|
echo ""
|
|
echo -e " If LNBITS_API_KEY is blank above, open $LNBITS_URL,"
|
|
echo -e " create a wallet called 'Timmy', and copy its Invoice Key."
|
|
echo ""
|
|
echo -e " ${CYAN}Next: fund your Lightning node${NC}"
|
|
echo -e " Get your on-chain address:"
|
|
echo -e " docker exec lnd lncli --network=mainnet newaddress p2wkh"
|
|
echo -e " Send at least 0.001 BTC to open your first channel."
|
|
echo ""
|
|
echo -e " Full credentials: ${YELLOW}cat $CREDS_FILE${NC}"
|
|
echo ""
|