@lightninglabs/lightning-mcp-server 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.claude-plugin/marketplace.json +36 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/README.md +307 -0
  4. package/bin/lightning-mcp-server +15 -0
  5. package/docs/architecture.md +455 -0
  6. package/docs/commerce.md +357 -0
  7. package/docs/l402-and-lnget.md +267 -0
  8. package/docs/mcp-server.md +285 -0
  9. package/docs/quickref.md +263 -0
  10. package/docs/security.md +298 -0
  11. package/docs/two-agent-setup.md +394 -0
  12. package/package.json +52 -0
  13. package/postinstall.js +160 -0
  14. package/skills/aperture/SKILL.md +330 -0
  15. package/skills/aperture/scripts/install.sh +68 -0
  16. package/skills/aperture/scripts/setup.sh +155 -0
  17. package/skills/aperture/scripts/start.sh +81 -0
  18. package/skills/aperture/scripts/stop.sh +57 -0
  19. package/skills/aperture/templates/aperture-regtest.yaml +36 -0
  20. package/skills/aperture/templates/aperture.yaml.template +64 -0
  21. package/skills/aperture/templates/docker-compose-aperture.yml +59 -0
  22. package/skills/commerce/SKILL.md +211 -0
  23. package/skills/lib/config-gen.sh +127 -0
  24. package/skills/lib/rest.sh +69 -0
  25. package/skills/lightning-security-module/SKILL.md +253 -0
  26. package/skills/lightning-security-module/references/architecture.md +133 -0
  27. package/skills/lightning-security-module/scripts/docker-start.sh +117 -0
  28. package/skills/lightning-security-module/scripts/docker-stop.sh +53 -0
  29. package/skills/lightning-security-module/scripts/export-credentials.sh +268 -0
  30. package/skills/lightning-security-module/scripts/install.sh +178 -0
  31. package/skills/lightning-security-module/scripts/setup-signer.sh +307 -0
  32. package/skills/lightning-security-module/scripts/start-signer.sh +152 -0
  33. package/skills/lightning-security-module/scripts/stop-signer.sh +240 -0
  34. package/skills/lightning-security-module/templates/docker-compose-signer.yml +35 -0
  35. package/skills/lightning-security-module/templates/signer-lnd.conf.template +69 -0
  36. package/skills/lnd/SKILL.md +441 -0
  37. package/skills/lnd/profiles/debug.env +4 -0
  38. package/skills/lnd/profiles/default.env +3 -0
  39. package/skills/lnd/profiles/regtest.env +4 -0
  40. package/skills/lnd/profiles/taproot.env +3 -0
  41. package/skills/lnd/profiles/wumbo.env +3 -0
  42. package/skills/lnd/references/security.md +156 -0
  43. package/skills/lnd/scripts/create-wallet.sh +464 -0
  44. package/skills/lnd/scripts/docker-start.sh +256 -0
  45. package/skills/lnd/scripts/docker-stop.sh +109 -0
  46. package/skills/lnd/scripts/import-credentials.sh +145 -0
  47. package/skills/lnd/scripts/install.sh +195 -0
  48. package/skills/lnd/scripts/lncli.sh +150 -0
  49. package/skills/lnd/scripts/start-lnd.sh +241 -0
  50. package/skills/lnd/scripts/stop-lnd.sh +218 -0
  51. package/skills/lnd/scripts/unlock-wallet.sh +134 -0
  52. package/skills/lnd/templates/docker-compose-regtest.yml +122 -0
  53. package/skills/lnd/templates/docker-compose-watchonly.yml +71 -0
  54. package/skills/lnd/templates/docker-compose.yml +49 -0
  55. package/skills/lnd/templates/litd-regtest.conf.template +61 -0
  56. package/skills/lnd/templates/litd-watchonly.conf.template +57 -0
  57. package/skills/lnd/templates/litd.conf.template +88 -0
  58. package/skills/lnd/templates/lnd.conf.template +91 -0
  59. package/skills/lnget/SKILL.md +288 -0
  60. package/skills/lnget/scripts/install.sh +69 -0
  61. package/skills/macaroon-bakery/SKILL.md +179 -0
  62. package/skills/macaroon-bakery/scripts/bake.sh +337 -0
  63. package/skills/mcp-lnc/SKILL.md +280 -0
  64. package/skills/mcp-lnc/scripts/configure.sh +130 -0
  65. package/skills/mcp-lnc/scripts/install.sh +103 -0
  66. package/skills/mcp-lnc/scripts/setup-claude-config.sh +162 -0
  67. package/skills/mcp-lnc/templates/env.template +16 -0
  68. package/versions.env +23 -0
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env bash
2
+ # Set up a remote signer: create wallet, export credentials bundle.
3
+ #
4
+ # Container mode (default — auto-detects litd-signer container):
5
+ # setup-signer.sh # Auto-detect container
6
+ # setup-signer.sh --container litd-signer # Explicit container
7
+ #
8
+ # Native mode:
9
+ # setup-signer.sh --native # Local lnd signer
10
+ # setup-signer.sh --native --network mainnet # Mainnet
11
+ # setup-signer.sh --native --password "mypass" # Custom passphrase
12
+ #
13
+ # Stores credentials at:
14
+ # ~/.lnget/signer/wallet-password.txt (mode 0600)
15
+ # ~/.lnget/signer/seed.txt (mode 0600)
16
+ # ~/.lnget/signer/credentials-bundle/ (exported credentials)
17
+
18
+ set -e
19
+
20
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ LNGET_SIGNER_DIR="${LNGET_SIGNER_DIR:-$HOME/.lnget/signer}"
22
+ LND_SIGNER_DIR="${LND_SIGNER_DIR:-$HOME/.lnd-signer}"
23
+ NETWORK="testnet"
24
+ PASSWORD=""
25
+ RPC_PORT=10012
26
+ REST_PORT=10013
27
+ CONTAINER=""
28
+ NATIVE=false
29
+
30
+ # Parse arguments.
31
+ while [[ $# -gt 0 ]]; do
32
+ case $1 in
33
+ --network)
34
+ NETWORK="$2"
35
+ shift 2
36
+ ;;
37
+ --lnddir)
38
+ LND_SIGNER_DIR="$2"
39
+ shift 2
40
+ ;;
41
+ --password)
42
+ PASSWORD="$2"
43
+ shift 2
44
+ ;;
45
+ --rpc-port)
46
+ RPC_PORT="$2"
47
+ shift 2
48
+ ;;
49
+ --rest-port)
50
+ REST_PORT="$2"
51
+ shift 2
52
+ ;;
53
+ --container)
54
+ CONTAINER="$2"
55
+ shift 2
56
+ ;;
57
+ --native)
58
+ NATIVE=true
59
+ shift
60
+ ;;
61
+ -h|--help)
62
+ echo "Usage: setup-signer.sh [options]"
63
+ echo ""
64
+ echo "Set up an lnd remote signer node."
65
+ echo ""
66
+ echo "Connection options:"
67
+ echo " --container NAME Set up signer in a Docker container"
68
+ echo " --native Set up signer on local lnd process"
69
+ echo ""
70
+ echo "Options:"
71
+ echo " --network NETWORK Bitcoin network (default: testnet)"
72
+ echo " --lnddir DIR Signer lnd data directory (default: ~/.lnd-signer)"
73
+ echo " --password PASS Wallet passphrase (auto-generated if omitted)"
74
+ echo " --rpc-port PORT Signer RPC port (default: 10012)"
75
+ echo " --rest-port PORT Signer REST port (default: 10013)"
76
+ echo ""
77
+ echo "Container auto-detection: looks for litd-signer container."
78
+ exit 0
79
+ ;;
80
+ *)
81
+ echo "Unknown option: $1" >&2
82
+ exit 1
83
+ ;;
84
+ esac
85
+ done
86
+
87
+ # Auto-detect container if not native and no container specified.
88
+ if [ "$NATIVE" = false ] && [ -z "$CONTAINER" ]; then
89
+ if command -v docker &>/dev/null; then
90
+ if docker ps --format '{{.Names}}' 2>/dev/null | grep -qx 'litd-signer'; then
91
+ CONTAINER="litd-signer"
92
+ fi
93
+ fi
94
+
95
+ # If no container found, fall back to native.
96
+ if [ -z "$CONTAINER" ]; then
97
+ NATIVE=true
98
+ fi
99
+ fi
100
+
101
+ # Container mode: verify container is running.
102
+ if [ -n "$CONTAINER" ]; then
103
+ if ! docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "$CONTAINER"; then
104
+ echo "Error: Container '$CONTAINER' is not running." >&2
105
+ echo "Start it with: skills/lightning-security-module/scripts/docker-start.sh" >&2
106
+ exit 1
107
+ fi
108
+ fi
109
+
110
+ echo "=== Remote Signer Setup ==="
111
+ echo ""
112
+ if [ -n "$CONTAINER" ]; then
113
+ echo "Container: $CONTAINER"
114
+ else
115
+ echo "Mode: native"
116
+ echo "Signer dir: $LND_SIGNER_DIR"
117
+ fi
118
+ echo "Network: $NETWORK"
119
+ echo "Creds dir: $LNGET_SIGNER_DIR"
120
+ echo "RPC port: $RPC_PORT"
121
+ echo "REST port: $REST_PORT"
122
+ echo ""
123
+
124
+ # Native mode: verify lnd is installed.
125
+ if [ "$NATIVE" = true ]; then
126
+ if ! command -v lnd &>/dev/null; then
127
+ echo "Error: lnd not found. Run install.sh first." >&2
128
+ exit 1
129
+ fi
130
+ fi
131
+
132
+ # Create directories with restricted permissions.
133
+ mkdir -p "$LNGET_SIGNER_DIR"
134
+ chmod 700 "$LNGET_SIGNER_DIR"
135
+
136
+ if [ "$NATIVE" = true ]; then
137
+ mkdir -p "$LND_SIGNER_DIR"
138
+ fi
139
+
140
+ PASSWORD_FILE="$LNGET_SIGNER_DIR/wallet-password.txt"
141
+ SEED_OUTPUT="$LNGET_SIGNER_DIR/seed.txt"
142
+ CONF_FILE="$LNGET_SIGNER_DIR/signer-lnd.conf"
143
+
144
+ # Generate or use provided passphrase.
145
+ if [ -n "$PASSWORD" ]; then
146
+ echo "Using provided passphrase."
147
+ else
148
+ echo "Generating secure passphrase..."
149
+ PASSWORD=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32)
150
+ fi
151
+
152
+ # Store passphrase with restricted permissions on the host.
153
+ echo -n "$PASSWORD" > "$PASSWORD_FILE"
154
+ chmod 600 "$PASSWORD_FILE"
155
+ echo "Passphrase saved to $PASSWORD_FILE (mode 0600)"
156
+ echo ""
157
+
158
+ # Copy password file into container if applicable.
159
+ if [ -n "$CONTAINER" ]; then
160
+ docker cp "$PASSWORD_FILE" "$CONTAINER:/root/.lnd/wallet-password.txt"
161
+ echo "Password file copied into container."
162
+ fi
163
+
164
+ # Source shared REST helpers. REST_HOST defaults to localhost for
165
+ # the signer; CONTAINER_PORT defaults to REST_PORT.
166
+ REST_HOST="localhost"
167
+ source "$SCRIPT_DIR/../../lib/rest.sh"
168
+
169
+ # For native mode, create config and start lnd temporarily if needed.
170
+ if [ "$NATIVE" = true ]; then
171
+ # Create signer config from template.
172
+ TEMPLATE="$SCRIPT_DIR/../templates/signer-lnd.conf.template"
173
+ if [ -f "$TEMPLATE" ]; then
174
+ echo "Creating signer config from template..."
175
+ # Replace network flag — match any existing network variant.
176
+ sed -E "s/bitcoin\.(testnet|mainnet|signet|regtest)=true/bitcoin.$NETWORK=true/g" "$TEMPLATE" > "$CONF_FILE"
177
+
178
+ # Replace password file path.
179
+ sed -i.bak "s|wallet-unlock-password-file=.*|wallet-unlock-password-file=$PASSWORD_FILE|g" "$CONF_FILE"
180
+
181
+ # Replace port numbers. Native mode binds to localhost, not 0.0.0.0.
182
+ sed -i.bak "s|rpclisten=0.0.0.0:10012|rpclisten=localhost:$RPC_PORT|g" "$CONF_FILE"
183
+ sed -i.bak "s|restlisten=0.0.0.0:10013|restlisten=localhost:$REST_PORT|g" "$CONF_FILE"
184
+ rm -f "$CONF_FILE.bak"
185
+ echo "Config saved to $CONF_FILE"
186
+ else
187
+ echo "Error: Config template not found at $TEMPLATE" >&2
188
+ exit 1
189
+ fi
190
+ echo ""
191
+
192
+ # Start signer lnd temporarily for wallet creation if not running.
193
+ if rest_call GET "/v1/state" &>/dev/null; then
194
+ echo "Signer lnd is already running."
195
+ else
196
+ echo "Starting signer lnd temporarily for wallet creation..."
197
+ nohup lnd \
198
+ --lnddir="$LND_SIGNER_DIR" \
199
+ --configfile="$CONF_FILE" \
200
+ > "$LNGET_SIGNER_DIR/signer-setup.log" 2>&1 &
201
+ SIGNER_PID=$!
202
+
203
+ echo "Waiting for signer lnd to start (PID: $SIGNER_PID)..."
204
+ for i in {1..30}; do
205
+ if rest_call GET "/v1/state" &>/dev/null; then
206
+ break
207
+ fi
208
+ if ! kill -0 "$SIGNER_PID" 2>/dev/null; then
209
+ echo "Error: signer lnd exited. Check $LNGET_SIGNER_DIR/signer-setup.log" >&2
210
+ exit 1
211
+ fi
212
+ sleep 2
213
+ echo " Waiting... ($i/30)"
214
+ done
215
+ echo ""
216
+ fi
217
+ else
218
+ # Container mode: wait for REST API to be available inside container.
219
+ wait_for_rest "signer REST API"
220
+ fi
221
+
222
+ # Create wallet via REST API.
223
+ echo "=== Creating Signer Wallet ==="
224
+
225
+ # Generate seed.
226
+ echo "Generating wallet seed..."
227
+ SEED_RESPONSE=$(rest_call GET "/v1/genseed")
228
+
229
+ MNEMONIC=$(echo "$SEED_RESPONSE" | jq -r '.cipher_seed_mnemonic[]' 2>/dev/null)
230
+ if [ -z "$MNEMONIC" ] || [ "$MNEMONIC" = "null" ]; then
231
+ echo "Error: Failed to generate seed." >&2
232
+ echo "Response: $SEED_RESPONSE" >&2
233
+ exit 1
234
+ fi
235
+
236
+ # Store seed with restricted permissions on host.
237
+ echo "$MNEMONIC" > "$SEED_OUTPUT"
238
+ chmod 600 "$SEED_OUTPUT"
239
+ echo "Seed mnemonic saved to $SEED_OUTPUT (mode 0600)"
240
+ echo ""
241
+
242
+ # Initialize wallet with password and seed.
243
+ SEED_JSON=$(echo "$MNEMONIC" | jq -R . | jq -s .)
244
+ PAYLOAD=$(jq -n \
245
+ --arg pass "$(echo -n "$PASSWORD" | base64)" \
246
+ --argjson seed "$SEED_JSON" \
247
+ '{wallet_password: $pass, cipher_seed_mnemonic: $seed}')
248
+
249
+ RESPONSE=$(rest_call POST "/v1/initwallet" "$PAYLOAD")
250
+
251
+ ERROR=$(echo "$RESPONSE" | jq -r '.message // empty' 2>/dev/null)
252
+ if [ -n "$ERROR" ]; then
253
+ echo "Error creating wallet: $ERROR" >&2
254
+ exit 1
255
+ fi
256
+
257
+ echo "Signer wallet created successfully!"
258
+ echo ""
259
+
260
+ # Wait for signer to be fully ready (wallet unlocked, RPC available).
261
+ echo "Waiting for signer to be fully ready..."
262
+ for i in {1..30}; do
263
+ STATE=$(rest_call GET "/v1/state" 2>/dev/null | jq -r '.state // empty' 2>/dev/null)
264
+ if [ "$STATE" = "SERVER_ACTIVE" ]; then
265
+ break
266
+ fi
267
+ sleep 2
268
+ echo " Waiting for RPC... ($i/30)"
269
+ done
270
+ echo ""
271
+
272
+ # Export credentials bundle.
273
+ echo "=== Exporting Credentials Bundle ==="
274
+ if [ -n "$CONTAINER" ]; then
275
+ "$SCRIPT_DIR/export-credentials.sh" \
276
+ --container "$CONTAINER" \
277
+ --network "$NETWORK" \
278
+ --rpc-port "$RPC_PORT"
279
+ else
280
+ "$SCRIPT_DIR/export-credentials.sh" \
281
+ --network "$NETWORK" \
282
+ --lnddir "$LND_SIGNER_DIR" \
283
+ --rpc-port "$RPC_PORT"
284
+ fi
285
+
286
+ echo ""
287
+ echo "=== Signer Setup Complete ==="
288
+ echo ""
289
+ echo "Credential locations:"
290
+ echo " Passphrase: $PASSWORD_FILE"
291
+ echo " Seed: $SEED_OUTPUT"
292
+ if [ "$NATIVE" = true ]; then
293
+ echo " Config: $CONF_FILE"
294
+ fi
295
+ echo ""
296
+ echo "IMPORTANT: The seed mnemonic at $SEED_OUTPUT is the master secret."
297
+ echo "Back it up securely and restrict access to this machine."
298
+ echo ""
299
+ echo "Next steps:"
300
+ echo " 1. Copy the credentials bundle to your agent machine"
301
+ echo " 2. On the agent: skills/lnd/scripts/import-credentials.sh --bundle <path>"
302
+ echo " 3. On the agent: skills/lnd/scripts/create-wallet.sh"
303
+ if [ -n "$CONTAINER" ]; then
304
+ echo " 4. On the agent: skills/lnd/scripts/docker-start.sh --watchonly"
305
+ else
306
+ echo " 4. On the agent: skills/lnd/scripts/start-lnd.sh --native --signer-host <this-ip>:$RPC_PORT"
307
+ fi
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env bash
2
+ # Start the remote signer lnd node — delegates to Docker by default.
3
+ #
4
+ # Usage:
5
+ # start-signer.sh # Docker (default)
6
+ # start-signer.sh --network mainnet # Mainnet
7
+ # start-signer.sh --native # Native lnd signer
8
+ # start-signer.sh --native --foreground # Native, foreground
9
+
10
+ set -e
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ NATIVE=false
14
+
15
+ # Check for --native flag before parsing other args.
16
+ PASS_ARGS=()
17
+ for arg in "$@"; do
18
+ if [ "$arg" = "--native" ]; then
19
+ NATIVE=true
20
+ else
21
+ PASS_ARGS+=("$arg")
22
+ fi
23
+ done
24
+
25
+ # If not native mode, delegate to docker-start.sh.
26
+ if [ "$NATIVE" = false ]; then
27
+ if command -v docker &>/dev/null; then
28
+ exec "$SCRIPT_DIR/docker-start.sh" "${PASS_ARGS[@]}"
29
+ else
30
+ echo "Docker not available. Falling back to native mode." >&2
31
+ echo "Install Docker or use --native explicitly." >&2
32
+ echo ""
33
+ NATIVE=true
34
+ fi
35
+ fi
36
+
37
+ # --- Native mode: original signer startup logic ---
38
+
39
+ LNGET_SIGNER_DIR="${LNGET_SIGNER_DIR:-$HOME/.lnget/signer}"
40
+ LND_SIGNER_DIR="${LND_SIGNER_DIR:-$HOME/.lnd-signer}"
41
+ NETWORK="testnet"
42
+ FOREGROUND=false
43
+ EXTRA_ARGS=""
44
+ RPC_PORT=10012
45
+ CONF_FILE="$LNGET_SIGNER_DIR/signer-lnd.conf"
46
+
47
+ # Parse arguments.
48
+ set -- "${PASS_ARGS[@]}"
49
+ while [[ $# -gt 0 ]]; do
50
+ case $1 in
51
+ --network)
52
+ NETWORK="$2"
53
+ shift 2
54
+ ;;
55
+ --lnddir)
56
+ LND_SIGNER_DIR="$2"
57
+ shift 2
58
+ ;;
59
+ --foreground)
60
+ FOREGROUND=true
61
+ shift
62
+ ;;
63
+ --rpc-port)
64
+ RPC_PORT="$2"
65
+ shift 2
66
+ ;;
67
+ --extra-args)
68
+ EXTRA_ARGS="$2"
69
+ shift 2
70
+ ;;
71
+ -h|--help)
72
+ echo "Usage: start-signer.sh [options]"
73
+ echo ""
74
+ echo "Start the remote signer lnd node."
75
+ echo ""
76
+ echo "Docker options (default):"
77
+ echo " --network NET Override network (testnet, mainnet, signet)"
78
+ echo " --foreground Run in foreground (show logs)"
79
+ echo ""
80
+ echo "Native options (--native):"
81
+ echo " --native Run lnd as a local process"
82
+ echo " --lnddir DIR Signer lnd data directory (default: ~/.lnd-signer)"
83
+ echo " --rpc-port PORT Signer RPC port (default: 10012)"
84
+ echo " --extra-args ARGS Additional lnd arguments"
85
+ exit 0
86
+ ;;
87
+ *)
88
+ echo "Unknown option: $1" >&2
89
+ exit 1
90
+ ;;
91
+ esac
92
+ done
93
+
94
+ # Verify lnd is installed.
95
+ if ! command -v lnd &>/dev/null; then
96
+ echo "Error: lnd not found. Run install.sh first." >&2
97
+ exit 1
98
+ fi
99
+
100
+ # Check if signer is already running by checking the RPC port.
101
+ if curl -sk "https://localhost:$RPC_PORT/v1/state" &>/dev/null 2>&1; then
102
+ echo "Signer lnd is already running on port $RPC_PORT."
103
+ echo "Use stop-signer.sh to stop it first."
104
+ exit 1
105
+ fi
106
+
107
+ # Verify config exists.
108
+ if [ ! -f "$CONF_FILE" ]; then
109
+ echo "Error: Signer config not found at $CONF_FILE" >&2
110
+ echo "Run setup-signer.sh --native first." >&2
111
+ exit 1
112
+ fi
113
+
114
+ echo "=== Starting Signer LND ==="
115
+ echo "Network: $NETWORK"
116
+ echo "Data dir: $LND_SIGNER_DIR"
117
+ echo "Config: $CONF_FILE"
118
+ echo "RPC port: $RPC_PORT"
119
+ echo ""
120
+
121
+ LOG_FILE="$LNGET_SIGNER_DIR/signer-lnd.log"
122
+
123
+ if [ "$FOREGROUND" = true ]; then
124
+ exec lnd \
125
+ --lnddir="$LND_SIGNER_DIR" \
126
+ --configfile="$CONF_FILE" \
127
+ $EXTRA_ARGS
128
+ else
129
+ nohup lnd \
130
+ --lnddir="$LND_SIGNER_DIR" \
131
+ --configfile="$CONF_FILE" \
132
+ $EXTRA_ARGS \
133
+ > "$LOG_FILE" 2>&1 &
134
+ SIGNER_PID=$!
135
+ echo "Signer lnd started in background (PID: $SIGNER_PID)"
136
+ echo "Log file: $LOG_FILE"
137
+ echo ""
138
+
139
+ # Wait briefly and verify it's running.
140
+ sleep 2
141
+ if kill -0 "$SIGNER_PID" 2>/dev/null; then
142
+ echo "Signer lnd is running."
143
+ else
144
+ echo "Error: signer lnd exited immediately. Check $LOG_FILE" >&2
145
+ tail -20 "$LOG_FILE" 2>/dev/null
146
+ exit 1
147
+ fi
148
+
149
+ echo ""
150
+ echo "The signer is ready to accept connections from watch-only nodes."
151
+ echo "Watch-only nodes connect to this machine on port $RPC_PORT."
152
+ fi
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env bash
2
+ # Stop the remote signer — delegates to Docker by default.
3
+ #
4
+ # Usage:
5
+ # stop-signer.sh # Docker stop (auto-detect)
6
+ # stop-signer.sh --clean # Docker stop + remove volumes
7
+ # stop-signer.sh --native # Stop native signer process
8
+ # stop-signer.sh --native --force # SIGTERM native process
9
+ # stop-signer.sh --container litd-signer # Explicit container
10
+ # stop-signer.sh --rpcserver remote:10012 --tlscertpath ~/tls.cert --macaroonpath ~/admin.macaroon
11
+
12
+ set -e
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ NATIVE=false
16
+
17
+ # Check for --native flag before parsing other args.
18
+ PASS_ARGS=()
19
+ for arg in "$@"; do
20
+ if [ "$arg" = "--native" ]; then
21
+ NATIVE=true
22
+ else
23
+ PASS_ARGS+=("$arg")
24
+ fi
25
+ done
26
+
27
+ # If not native mode, delegate to docker-stop.sh.
28
+ if [ "$NATIVE" = false ]; then
29
+ # Check if we have a --container arg or docker-specific flags.
30
+ HAS_CONTAINER_ARG=false
31
+ HAS_RPCSERVER=false
32
+ for arg in "${PASS_ARGS[@]}"; do
33
+ if [ "$arg" = "--container" ]; then
34
+ HAS_CONTAINER_ARG=true
35
+ fi
36
+ if [ "$arg" = "--rpcserver" ]; then
37
+ HAS_RPCSERVER=true
38
+ fi
39
+ done
40
+
41
+ # If --rpcserver is specified, fall through to native stop logic (remote
42
+ # mode needs lncli).
43
+ if [ "$HAS_RPCSERVER" = true ]; then
44
+ NATIVE=true
45
+ elif [ "$HAS_CONTAINER_ARG" = true ]; then
46
+ # Explicit container — use native stop logic (handles docker exec).
47
+ NATIVE=true
48
+ elif command -v docker &>/dev/null; then
49
+ if docker ps --format '{{.Names}}' 2>/dev/null | grep -qx 'litd-signer'; then
50
+ exec "$SCRIPT_DIR/docker-stop.sh" "${PASS_ARGS[@]}"
51
+ fi
52
+ # No signer container found, fall through to native.
53
+ NATIVE=true
54
+ else
55
+ NATIVE=true
56
+ fi
57
+ fi
58
+
59
+ # --- Native / container-specific stop logic ---
60
+
61
+ LND_SIGNER_DIR="${LND_SIGNER_DIR:-}"
62
+ NETWORK="${NETWORK:-testnet}"
63
+ RPC_PORT=10012
64
+ FORCE=false
65
+ CONTAINER=""
66
+ RPCSERVER=""
67
+ TLSCERTPATH=""
68
+ MACAROONPATH=""
69
+
70
+ # Parse arguments.
71
+ set -- "${PASS_ARGS[@]}"
72
+ while [[ $# -gt 0 ]]; do
73
+ case $1 in
74
+ --force)
75
+ FORCE=true
76
+ shift
77
+ ;;
78
+ --network)
79
+ NETWORK="$2"
80
+ shift 2
81
+ ;;
82
+ --rpc-port)
83
+ RPC_PORT="$2"
84
+ shift 2
85
+ ;;
86
+ --container)
87
+ CONTAINER="$2"
88
+ shift 2
89
+ ;;
90
+ --rpcserver)
91
+ RPCSERVER="$2"
92
+ shift 2
93
+ ;;
94
+ --tlscertpath)
95
+ TLSCERTPATH="$2"
96
+ shift 2
97
+ ;;
98
+ --macaroonpath)
99
+ MACAROONPATH="$2"
100
+ shift 2
101
+ ;;
102
+ --clean|-v)
103
+ # Docker-specific flags; delegate to docker-stop.sh.
104
+ exec "$SCRIPT_DIR/docker-stop.sh" "${PASS_ARGS[@]}"
105
+ ;;
106
+ -h|--help)
107
+ echo "Usage: stop-signer.sh [options]"
108
+ echo ""
109
+ echo "Stop the remote signer."
110
+ echo ""
111
+ echo "Docker options (default):"
112
+ echo " --clean, -v Remove volumes (clean state)"
113
+ echo ""
114
+ echo "Native options (--native):"
115
+ echo " --native Stop native signer process"
116
+ echo " --force Send SIGTERM immediately"
117
+ echo " --container NAME Stop signer in a specific container"
118
+ echo " --rpcserver HOST:PORT Connect to a remote signer node"
119
+ echo " --tlscertpath PATH TLS certificate for remote connection"
120
+ echo " --macaroonpath PATH Macaroon for remote authentication"
121
+ echo " --rpc-port PORT Signer RPC port (default: 10012)"
122
+ exit 0
123
+ ;;
124
+ *)
125
+ echo "Unknown option: $1" >&2
126
+ exit 1
127
+ ;;
128
+ esac
129
+ done
130
+
131
+ # Apply default lnddir if not set.
132
+ if [ -z "$LND_SIGNER_DIR" ]; then
133
+ if [ -n "$CONTAINER" ]; then
134
+ LND_SIGNER_DIR="/root/.lnd"
135
+ else
136
+ LND_SIGNER_DIR="$HOME/.lnd-signer"
137
+ fi
138
+ fi
139
+
140
+ if [ -n "$CONTAINER" ]; then
141
+ # Docker container mode.
142
+ if ! docker ps --format '{{.Names}}' | grep -qx "$CONTAINER"; then
143
+ echo "Container '$CONTAINER' is not running."
144
+ exit 0
145
+ fi
146
+
147
+ echo "Stopping signer lnd in container '$CONTAINER'..."
148
+
149
+ if [ "$FORCE" = true ]; then
150
+ docker stop "$CONTAINER"
151
+ echo "Container stopped."
152
+ else
153
+ if docker exec "$CONTAINER" lncli --rpcserver="localhost:$RPC_PORT" \
154
+ --lnddir="$LND_SIGNER_DIR" \
155
+ --network="$NETWORK" \
156
+ stop 2>/dev/null; then
157
+ echo "Graceful shutdown initiated."
158
+ else
159
+ echo "lncli stop failed, stopping container..."
160
+ docker stop "$CONTAINER"
161
+ echo "Container stopped."
162
+ fi
163
+ fi
164
+ exit 0
165
+ fi
166
+
167
+ # Build connection flags for lncli.
168
+ CONN_FLAGS=(--network="$NETWORK" --lnddir="$LND_SIGNER_DIR")
169
+ if [ -n "$RPCSERVER" ]; then
170
+ CONN_FLAGS+=("--rpcserver=$RPCSERVER")
171
+ else
172
+ CONN_FLAGS+=("--rpcserver=localhost:$RPC_PORT")
173
+ fi
174
+ if [ -n "$TLSCERTPATH" ]; then
175
+ CONN_FLAGS+=("--tlscertpath=$TLSCERTPATH")
176
+ fi
177
+ if [ -n "$MACAROONPATH" ]; then
178
+ CONN_FLAGS+=("--macaroonpath=$MACAROONPATH")
179
+ fi
180
+
181
+ # Remote mode — stop via lncli only (no PID or port access).
182
+ if [ -n "$RPCSERVER" ]; then
183
+ echo "Stopping remote signer at $RPCSERVER..."
184
+ if lncli "${CONN_FLAGS[@]}" stop; then
185
+ echo "Graceful shutdown initiated."
186
+ else
187
+ echo "Error: lncli stop failed for remote signer." >&2
188
+ exit 1
189
+ fi
190
+ exit 0
191
+ fi
192
+
193
+ # Local mode — check if signer is running by probing the RPC port.
194
+ if ! curl -sk "https://localhost:$RPC_PORT/v1/state" &>/dev/null 2>&1; then
195
+ echo "Signer lnd is not running (port $RPC_PORT not responding)."
196
+ exit 0
197
+ fi
198
+
199
+ echo "Stopping signer lnd..."
200
+
201
+ if [ "$FORCE" = true ]; then
202
+ # Find the process listening on the signer RPC port and kill it.
203
+ SIGNER_PID=$(lsof -ti ":$RPC_PORT" 2>/dev/null | head -1 || true)
204
+ if [ -n "$SIGNER_PID" ]; then
205
+ kill "$SIGNER_PID"
206
+ echo "Sent SIGTERM to PID $SIGNER_PID."
207
+ else
208
+ echo "Warning: Could not find process on port $RPC_PORT." >&2
209
+ exit 1
210
+ fi
211
+ else
212
+ # Try graceful shutdown via lncli.
213
+ if lncli "${CONN_FLAGS[@]}" stop 2>/dev/null; then
214
+ echo "Graceful shutdown initiated."
215
+ else
216
+ echo "lncli stop failed, finding process on port $RPC_PORT..."
217
+ SIGNER_PID=$(lsof -ti ":$RPC_PORT" 2>/dev/null | head -1 || true)
218
+ if [ -n "$SIGNER_PID" ]; then
219
+ kill "$SIGNER_PID"
220
+ echo "Sent SIGTERM to PID $SIGNER_PID."
221
+ else
222
+ echo "Warning: Could not find process to stop." >&2
223
+ exit 1
224
+ fi
225
+ fi
226
+ fi
227
+
228
+ # Wait for process to exit.
229
+ echo "Waiting for signer lnd to exit..."
230
+ for i in {1..15}; do
231
+ if ! curl -sk "https://localhost:$RPC_PORT/v1/state" &>/dev/null 2>&1; then
232
+ echo "Signer lnd stopped."
233
+ exit 0
234
+ fi
235
+ sleep 1
236
+ done
237
+
238
+ echo "Warning: signer lnd did not exit within 15 seconds." >&2
239
+ echo "Use --force or manually kill the process." >&2
240
+ exit 1