@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.
- package/.claude-plugin/marketplace.json +36 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +307 -0
- package/bin/lightning-mcp-server +15 -0
- package/docs/architecture.md +455 -0
- package/docs/commerce.md +357 -0
- package/docs/l402-and-lnget.md +267 -0
- package/docs/mcp-server.md +285 -0
- package/docs/quickref.md +263 -0
- package/docs/security.md +298 -0
- package/docs/two-agent-setup.md +394 -0
- package/package.json +52 -0
- package/postinstall.js +160 -0
- package/skills/aperture/SKILL.md +330 -0
- package/skills/aperture/scripts/install.sh +68 -0
- package/skills/aperture/scripts/setup.sh +155 -0
- package/skills/aperture/scripts/start.sh +81 -0
- package/skills/aperture/scripts/stop.sh +57 -0
- package/skills/aperture/templates/aperture-regtest.yaml +36 -0
- package/skills/aperture/templates/aperture.yaml.template +64 -0
- package/skills/aperture/templates/docker-compose-aperture.yml +59 -0
- package/skills/commerce/SKILL.md +211 -0
- package/skills/lib/config-gen.sh +127 -0
- package/skills/lib/rest.sh +69 -0
- package/skills/lightning-security-module/SKILL.md +253 -0
- package/skills/lightning-security-module/references/architecture.md +133 -0
- package/skills/lightning-security-module/scripts/docker-start.sh +117 -0
- package/skills/lightning-security-module/scripts/docker-stop.sh +53 -0
- package/skills/lightning-security-module/scripts/export-credentials.sh +268 -0
- package/skills/lightning-security-module/scripts/install.sh +178 -0
- package/skills/lightning-security-module/scripts/setup-signer.sh +307 -0
- package/skills/lightning-security-module/scripts/start-signer.sh +152 -0
- package/skills/lightning-security-module/scripts/stop-signer.sh +240 -0
- package/skills/lightning-security-module/templates/docker-compose-signer.yml +35 -0
- package/skills/lightning-security-module/templates/signer-lnd.conf.template +69 -0
- package/skills/lnd/SKILL.md +441 -0
- package/skills/lnd/profiles/debug.env +4 -0
- package/skills/lnd/profiles/default.env +3 -0
- package/skills/lnd/profiles/regtest.env +4 -0
- package/skills/lnd/profiles/taproot.env +3 -0
- package/skills/lnd/profiles/wumbo.env +3 -0
- package/skills/lnd/references/security.md +156 -0
- package/skills/lnd/scripts/create-wallet.sh +464 -0
- package/skills/lnd/scripts/docker-start.sh +256 -0
- package/skills/lnd/scripts/docker-stop.sh +109 -0
- package/skills/lnd/scripts/import-credentials.sh +145 -0
- package/skills/lnd/scripts/install.sh +195 -0
- package/skills/lnd/scripts/lncli.sh +150 -0
- package/skills/lnd/scripts/start-lnd.sh +241 -0
- package/skills/lnd/scripts/stop-lnd.sh +218 -0
- package/skills/lnd/scripts/unlock-wallet.sh +134 -0
- package/skills/lnd/templates/docker-compose-regtest.yml +122 -0
- package/skills/lnd/templates/docker-compose-watchonly.yml +71 -0
- package/skills/lnd/templates/docker-compose.yml +49 -0
- package/skills/lnd/templates/litd-regtest.conf.template +61 -0
- package/skills/lnd/templates/litd-watchonly.conf.template +57 -0
- package/skills/lnd/templates/litd.conf.template +88 -0
- package/skills/lnd/templates/lnd.conf.template +91 -0
- package/skills/lnget/SKILL.md +288 -0
- package/skills/lnget/scripts/install.sh +69 -0
- package/skills/macaroon-bakery/SKILL.md +179 -0
- package/skills/macaroon-bakery/scripts/bake.sh +337 -0
- package/skills/mcp-lnc/SKILL.md +280 -0
- package/skills/mcp-lnc/scripts/configure.sh +130 -0
- package/skills/mcp-lnc/scripts/install.sh +103 -0
- package/skills/mcp-lnc/scripts/setup-claude-config.sh +162 -0
- package/skills/mcp-lnc/templates/env.template +16 -0
- 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
|