feat(docker): add fund command and Nostr RPC funding script
- Add './dev.sh fund [amount]' for funding ATM via Nostr RPC - Create invoices via NIP-44 encrypted RPC instead of HTTP API - Support existing users without fail_if_exists errors - Add --fund flag to './dev.sh up' for one-command setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c4fadd7438
commit
e6e77f808e
2 changed files with 191 additions and 69 deletions
153
docker/dev.sh
153
docker/dev.sh
|
|
@ -39,6 +39,7 @@ PUBKEY_FILE="$STATE_DIR/lightning-pub-pubkey"
|
||||||
NPROFILE_FILE="$STATE_DIR/lightning-pub-nprofile"
|
NPROFILE_FILE="$STATE_DIR/lightning-pub-nprofile"
|
||||||
APP_TOKEN_FILE="$STATE_DIR/atm-app-token"
|
APP_TOKEN_FILE="$STATE_DIR/atm-app-token"
|
||||||
APP_ID_FILE="$STATE_DIR/atm-app-id"
|
APP_ID_FILE="$STATE_DIR/atm-app-id"
|
||||||
|
LINKING_TOKEN_FILE="$STATE_DIR/atm-linking-token"
|
||||||
MODE_FILE="$STATE_DIR/compose-mode" # "standalone" or "unified"
|
MODE_FILE="$STATE_DIR/compose-mode" # "standalone" or "unified"
|
||||||
|
|
||||||
# Get current compose file based on last used mode
|
# Get current compose file based on last used mode
|
||||||
|
|
@ -68,12 +69,63 @@ success() { echo -e "${GREEN}✓${NC} $1"; }
|
||||||
# Ensure state directory exists
|
# Ensure state directory exists
|
||||||
mkdir -p "$STATE_DIR"
|
mkdir -p "$STATE_DIR"
|
||||||
|
|
||||||
|
# Get ATM pubkey from its private key
|
||||||
|
get_atm_pubkey() {
|
||||||
|
local env_file="$PROJECT_DIR/apps/machine/.env"
|
||||||
|
if [[ ! -f "$env_file" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local privkey=$(grep "VITE_ATM_PRIVATE_KEY=" "$env_file" | cut -d= -f2)
|
||||||
|
if [[ -z "$privkey" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use node with @noble/curves to derive pubkey from privkey
|
||||||
|
cd "$PROJECT_DIR" && node -e "
|
||||||
|
const { secp256k1 } = require('./node_modules/.pnpm/@noble+curves@2.0.1/node_modules/@noble/curves/secp256k1.js');
|
||||||
|
const privkeyHex = '$privkey';
|
||||||
|
const privkey = Uint8Array.from(Buffer.from(privkeyHex, 'hex'));
|
||||||
|
const pubkeyFull = secp256k1.getPublicKey(privkey, true);
|
||||||
|
const pubkey = Buffer.from(pubkeyFull.slice(1)).toString('hex');
|
||||||
|
console.log(pubkey);
|
||||||
|
" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# Helper Functions
|
# Helper Functions
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
get_local_ip() {
|
get_local_ip() {
|
||||||
ip route get 1 2>/dev/null | awk '{print $7; exit}' || hostname -I | awk '{print $1}'
|
# Allow explicit override via env var
|
||||||
|
if [[ -n "${LAMASSU_HOST_IP:-}" ]]; then
|
||||||
|
echo "$LAMASSU_HOST_IP"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Linux: use ip route
|
||||||
|
if command -v ip &>/dev/null; then
|
||||||
|
local ip=$(ip route get 1 2>/dev/null | awk '{print $7; exit}')
|
||||||
|
if [[ -n "$ip" ]]; then
|
||||||
|
echo "$ip"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# macOS: use route + ifconfig
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
local iface=$(route get default 2>/dev/null | awk '/interface:/ {print $2}')
|
||||||
|
if [[ -n "$iface" ]]; then
|
||||||
|
local ip=$(ifconfig "$iface" 2>/dev/null | awk '/inet / {print $2}')
|
||||||
|
if [[ -n "$ip" ]]; then
|
||||||
|
echo "$ip"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback: hostname -I (Linux) or hostname (macOS)
|
||||||
|
hostname -I 2>/dev/null | awk '{print $1}' || hostname 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
is_regtest_running() {
|
is_regtest_running() {
|
||||||
|
|
@ -435,10 +487,19 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_atm_app() {
|
setup_atm_app() {
|
||||||
log "Creating ATM app..."
|
# Use a fixed app name so we reuse the same app across restarts
|
||||||
|
local app_name="lamassu-atm-dev"
|
||||||
|
|
||||||
# Generate unique app name to avoid conflicts
|
# Check if we already have valid app state
|
||||||
local app_name="atm-$(date +%s)"
|
if [[ -f "$APP_ID_FILE" ]] && [[ -f "$APP_TOKEN_FILE" ]]; then
|
||||||
|
local existing_app_id=$(cat "$APP_ID_FILE")
|
||||||
|
if [[ -n "$existing_app_id" ]]; then
|
||||||
|
log "Using existing ATM app: ${existing_app_id:0:16}..."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Creating ATM app..."
|
||||||
|
|
||||||
local response=$(curl -s -X POST http://localhost:1776/api/admin/app/add \
|
local response=$(curl -s -X POST http://localhost:1776/api/admin/app/add \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
|
@ -452,7 +513,7 @@ setup_atm_app() {
|
||||||
echo "$app_id" > "$APP_ID_FILE"
|
echo "$app_id" > "$APP_ID_FILE"
|
||||||
echo "$app_token" > "$APP_TOKEN_FILE"
|
echo "$app_token" > "$APP_TOKEN_FILE"
|
||||||
|
|
||||||
# Update ATM .env with app ID
|
# Update ATM .env with app ID and token
|
||||||
local env_file="$PROJECT_DIR/apps/machine/.env"
|
local env_file="$PROJECT_DIR/apps/machine/.env"
|
||||||
if [[ -f "$env_file" ]]; then
|
if [[ -f "$env_file" ]]; then
|
||||||
if grep -q "VITE_APP_ID" "$env_file"; then
|
if grep -q "VITE_APP_ID" "$env_file"; then
|
||||||
|
|
@ -462,6 +523,11 @@ setup_atm_app() {
|
||||||
echo "# ATM App ID for LNURL-withdraw" >> "$env_file"
|
echo "# ATM App ID for LNURL-withdraw" >> "$env_file"
|
||||||
echo "VITE_APP_ID=$app_id" >> "$env_file"
|
echo "VITE_APP_ID=$app_id" >> "$env_file"
|
||||||
fi
|
fi
|
||||||
|
if grep -q "VITE_APP_TOKEN" "$env_file"; then
|
||||||
|
sed -i "s|VITE_APP_TOKEN=.*|VITE_APP_TOKEN=$app_token|" "$env_file"
|
||||||
|
else
|
||||||
|
echo "VITE_APP_TOKEN=$app_token" >> "$env_file"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
success "Created ATM app: ${app_id:0:16}..."
|
success "Created ATM app: ${app_id:0:16}..."
|
||||||
|
|
@ -750,31 +816,64 @@ cmd_fund() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for app token
|
# Check for Lightning.Pub pubkey
|
||||||
if [[ ! -f "$APP_TOKEN_FILE" ]]; then
|
if [[ ! -f "$PUBKEY_FILE" ]]; then
|
||||||
error "ATM app not configured. Run './dev.sh up' first."
|
error "Lightning.Pub not configured. Run './dev.sh up' first."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local app_token=$(cat "$APP_TOKEN_FILE")
|
local lp_pubkey=$(cat "$PUBKEY_FILE")
|
||||||
|
local env_file="$PROJECT_DIR/apps/machine/.env"
|
||||||
|
|
||||||
log "Creating invoice for $amount sats..."
|
# Get ATM private key from .env
|
||||||
|
if [[ ! -f "$env_file" ]]; then
|
||||||
# Create invoice for app owner (using unique payer_identifier)
|
error "ATM not configured. Run './dev.sh up' first."
|
||||||
local payer_id="funder-$(date +%s)"
|
|
||||||
local response=$(curl -s -X POST "http://localhost:1776/api/app/add/invoice" \
|
|
||||||
-H "Authorization: Bearer $app_token" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"payer_identifier\": \"$payer_id\", \"http_callback_url\": \"\", \"invoice_req\": {\"amountSats\": $amount, \"memo\": \"ATM funding\"}}")
|
|
||||||
|
|
||||||
local invoice=$(echo "$response" | grep -oP '"invoice":"\K[^"]+')
|
|
||||||
|
|
||||||
if [[ -z "$invoice" ]]; then
|
|
||||||
error "Failed to create invoice"
|
|
||||||
echo "Response: $response"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local atm_privkey=$(grep "VITE_ATM_PRIVATE_KEY=" "$env_file" | cut -d= -f2)
|
||||||
|
if [[ -z "$atm_privkey" ]]; then
|
||||||
|
error "VITE_ATM_PRIVATE_KEY not found in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get app ID - required to ensure funds go to the same user as LNURL-withdraw
|
||||||
|
local app_id=""
|
||||||
|
if [[ -f "$APP_ID_FILE" ]]; then
|
||||||
|
app_id=$(cat "$APP_ID_FILE")
|
||||||
|
else
|
||||||
|
app_id=$(grep "VITE_APP_ID=" "$env_file" | cut -d= -f2)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$app_id" ]]; then
|
||||||
|
error "No app ID found. Run './dev.sh up' first to create the ATM app."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Creating invoice via Nostr RPC for $amount sats..."
|
||||||
|
log "Using app ID: ${app_id:0:16}..."
|
||||||
|
|
||||||
|
# Use the Nostr-based funding script (the Lightning.Pub way)
|
||||||
|
# This creates an invoice for the ATM's Nostr user under the correct app,
|
||||||
|
# ensuring balance is shared with LNURL-withdraw (Extension API)
|
||||||
|
local invoice=$(cd "$PROJECT_DIR/packages/nostr-client" && \
|
||||||
|
VITE_ATM_PRIVATE_KEY="$atm_privkey" \
|
||||||
|
VITE_LIGHTNING_PUB_PUBKEY="$lp_pubkey" \
|
||||||
|
VITE_RELAY_URL="ws://localhost:7777" \
|
||||||
|
VITE_APP_ID="$app_id" \
|
||||||
|
node fund-dev.mjs "$amount" 2>&1)
|
||||||
|
|
||||||
|
# Extract just the invoice (last line, starts with lnbc)
|
||||||
|
local bolt11=$(echo "$invoice" | grep -E "^lnbc")
|
||||||
|
|
||||||
|
if [[ -z "$bolt11" ]]; then
|
||||||
|
error "Failed to create invoice via Nostr"
|
||||||
|
echo "Output: $invoice"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Got invoice: ${bolt11:0:30}..."
|
||||||
|
|
||||||
log "Paying invoice from lnd-3..."
|
log "Paying invoice from lnd-3..."
|
||||||
|
|
||||||
# Source regtest helpers and pay
|
# Source regtest helpers and pay
|
||||||
|
|
@ -782,7 +881,7 @@ cmd_fund() {
|
||||||
(
|
(
|
||||||
cd "$REGTEST_DIR"
|
cd "$REGTEST_DIR"
|
||||||
source docker-scripts.sh 2>/dev/null
|
source docker-scripts.sh 2>/dev/null
|
||||||
lncli-sim 3 payinvoice --force "$invoice"
|
lncli-sim 3 payinvoice --force "$bolt11"
|
||||||
)
|
)
|
||||||
if [[ $? -eq 0 ]]; then
|
if [[ $? -eq 0 ]]; then
|
||||||
success "Funded ATM with $amount sats"
|
success "Funded ATM with $amount sats"
|
||||||
|
|
@ -792,7 +891,7 @@ cmd_fund() {
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Fallback: try direct docker exec
|
# Fallback: try direct docker exec
|
||||||
docker exec lnbits-lnd-3-1 lncli --network=regtest --rpcserver=lnd-3:10009 payinvoice --force "$invoice"
|
docker exec lnbits-lnd-3-1 lncli --network=regtest --rpcserver=lnd-3:10009 payinvoice --force "$bolt11"
|
||||||
if [[ $? -eq 0 ]]; then
|
if [[ $? -eq 0 ]]; then
|
||||||
success "Funded ATM with $amount sats"
|
success "Funded ATM with $amount sats"
|
||||||
else
|
else
|
||||||
|
|
@ -978,6 +1077,9 @@ case "${1:-help}" in
|
||||||
echo " --fund=<sats> Auto-fund ATM with specific amount"
|
echo " --fund=<sats> Auto-fund ATM with specific amount"
|
||||||
echo " --machine Launch ATM app after startup"
|
echo " --machine Launch ATM app after startup"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo "Environment variables:"
|
||||||
|
echo " LAMASSU_HOST_IP Override auto-detected LAN IP (for VPN/multi-NIC)"
|
||||||
|
echo ""
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
echo " $0 up # Start (uses shared regtest)"
|
echo " $0 up # Start (uses shared regtest)"
|
||||||
echo " $0 up --standalone # Start self-contained"
|
echo " $0 up --standalone # Start self-contained"
|
||||||
|
|
@ -989,5 +1091,6 @@ case "${1:-help}" in
|
||||||
echo " $0 fund 200000 # Add 200k more sats"
|
echo " $0 fund 200000 # Add 200k more sats"
|
||||||
echo " $0 logs lightning-pub"
|
echo " $0 logs lightning-pub"
|
||||||
echo " $0 reset && $0 up --fund # Fresh start with funding"
|
echo " $0 reset && $0 up --fund # Fresh start with funding"
|
||||||
|
echo " LAMASSU_HOST_IP=192.168.1.50 $0 up # Override LAN IP"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,44 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Fund the ATM's Lightning.Pub account via Nostr RPC
|
||||||
|
*
|
||||||
|
* This creates an invoice for the ATM user (authenticated via Nostr),
|
||||||
|
* so the funds go directly to the user that will be queried for balance.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* VITE_ATM_PRIVATE_KEY=xxx VITE_LIGHTNING_PUB_PUBKEY=yyy node fund-dev.mjs [amount]
|
||||||
|
*/
|
||||||
import { NostrClient, loadIdentityFromHex, encryptContent, decryptJSON } from './dist/index.js'
|
import { NostrClient, loadIdentityFromHex, encryptContent, decryptJSON } from './dist/index.js'
|
||||||
import { finalizeEvent } from 'nostr-tools'
|
import { finalizeEvent } from 'nostr-tools'
|
||||||
import { randomUUID } from 'crypto'
|
import { randomUUID } from 'crypto'
|
||||||
|
|
||||||
const DEV_PRIVATE_KEY = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
const ATM_PRIVATE_KEY = process.env.VITE_ATM_PRIVATE_KEY
|
||||||
const LIGHTNING_PUB_PUBKEY =
|
const LIGHTNING_PUB_PUBKEY = process.env.VITE_LIGHTNING_PUB_PUBKEY
|
||||||
process.env.LIGHTNING_PUB_PUBKEY ||
|
const RELAY_URL = process.env.VITE_RELAY_URL || 'ws://localhost:7777'
|
||||||
'4a72e400a254bf74a70cc711ab97e461b8d4fd9738b1ac3b5194cdeb3192ab91'
|
const APP_ID = process.env.VITE_APP_ID || ''
|
||||||
const RELAY_URL = process.env.NOSTR_RELAY_URL || 'ws://localhost:7777'
|
const FUND_AMOUNT = parseInt(process.argv[2] || process.env.FUND_AMOUNT || '100000', 10)
|
||||||
const FUND_AMOUNT = parseInt(process.env.FUND_AMOUNT || '100000', 10)
|
|
||||||
|
if (!ATM_PRIVATE_KEY) {
|
||||||
|
console.error('Error: VITE_ATM_PRIVATE_KEY environment variable required')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LIGHTNING_PUB_PUBKEY) {
|
||||||
|
console.error('Error: VITE_LIGHTNING_PUB_PUBKEY environment variable required')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!APP_ID) {
|
||||||
|
console.error('Error: VITE_APP_ID environment variable required')
|
||||||
|
console.error('This ensures funds go to the same user as LNURL-withdraw uses')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const identity = loadIdentityFromHex(DEV_PRIVATE_KEY)
|
const identity = loadIdentityFromHex(ATM_PRIVATE_KEY)
|
||||||
console.log('Using identity:', identity.publicKey)
|
console.error('[fund-dev] ATM pubkey:', identity.publicKey)
|
||||||
|
console.error('[fund-dev] Lightning.Pub pubkey:', LIGHTNING_PUB_PUBKEY)
|
||||||
|
console.error('[fund-dev] Creating invoice for', FUND_AMOUNT, 'sats')
|
||||||
|
|
||||||
const client = new NostrClient({
|
const client = new NostrClient({
|
||||||
relays: [{ url: RELAY_URL }],
|
relays: [{ url: RELAY_URL }],
|
||||||
|
|
@ -19,27 +46,27 @@ async function main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
await client.connect()
|
await client.connect()
|
||||||
console.log('Connected to relay')
|
console.error('[fund-dev] Connected to relay:', RELAY_URL)
|
||||||
|
|
||||||
const requestId = randomUUID()
|
const requestId = randomUUID()
|
||||||
|
|
||||||
|
console.error('[fund-dev] App ID:', APP_ID)
|
||||||
|
|
||||||
// Correct RPC structure per Lightning.Pub documentation
|
// Correct RPC structure per Lightning.Pub documentation
|
||||||
|
// appId ensures the Nostr user is created under the same app as HTTP API users
|
||||||
const rpcRequest = {
|
const rpcRequest = {
|
||||||
rpcName: 'NewInvoice',
|
rpcName: 'NewInvoice',
|
||||||
params: {},
|
params: {},
|
||||||
query: {},
|
query: {},
|
||||||
body: {
|
body: {
|
||||||
amountSats: FUND_AMOUNT,
|
amountSats: FUND_AMOUNT,
|
||||||
memo: `Fund dev account (${FUND_AMOUNT} sats)`,
|
memo: `ATM funding (${FUND_AMOUNT} sats)`,
|
||||||
},
|
},
|
||||||
authIdentifier: identity.publicKey,
|
authIdentifier: identity.publicKey,
|
||||||
requestId,
|
requestId,
|
||||||
|
appId: APP_ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Creating invoice for', FUND_AMOUNT, 'sats')
|
|
||||||
|
|
||||||
console.log('Request structure:', JSON.stringify(rpcRequest, null, 2))
|
|
||||||
|
|
||||||
const encryptedContent = encryptContent(identity, LIGHTNING_PUB_PUBKEY, rpcRequest)
|
const encryptedContent = encryptContent(identity, LIGHTNING_PUB_PUBKEY, rpcRequest)
|
||||||
|
|
||||||
const event = finalizeEvent(
|
const event = finalizeEvent(
|
||||||
|
|
@ -52,63 +79,55 @@ async function main() {
|
||||||
identity.privateKey
|
identity.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log('Publishing NewInvoice request (event id:', event.id, ')...')
|
|
||||||
|
|
||||||
// Subscribe to responses before publishing
|
// Subscribe to responses before publishing
|
||||||
let responseReceived = false
|
let invoice = null
|
||||||
const subId = client.subscribe(
|
const subId = client.subscribe(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
kinds: [21000],
|
kinds: [21000],
|
||||||
authors: [LIGHTNING_PUB_PUBKEY],
|
authors: [LIGHTNING_PUB_PUBKEY],
|
||||||
|
'#p': [identity.publicKey],
|
||||||
since: Math.floor(Date.now() / 1000) - 5,
|
since: Math.floor(Date.now() / 1000) - 5,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
onEvent: (evt) => {
|
onEvent: (evt) => {
|
||||||
console.log('Got event from Lightning.Pub:', evt.id.substring(0, 8) + '...')
|
try {
|
||||||
// Check if it's for us
|
const response = decryptJSON(identity, LIGHTNING_PUB_PUBKEY, evt.content)
|
||||||
const pTags = evt.tags.filter((t) => t[0] === 'p')
|
if (response.requestId === requestId && response.invoice) {
|
||||||
const eTags = evt.tags.filter((t) => t[0] === 'e')
|
invoice = response.invoice
|
||||||
const isForUs = pTags.some((t) => t[1] === identity.publicKey)
|
console.error('[fund-dev] Got invoice!')
|
||||||
const isReplyToOurEvent = eTags.some((t) => t[1] === event.id)
|
|
||||||
console.log(
|
|
||||||
' Tags p:',
|
|
||||||
pTags.map((t) => t[1].substring(0, 8)),
|
|
||||||
'e:',
|
|
||||||
eTags.map((t) => t[1].substring(0, 8))
|
|
||||||
)
|
|
||||||
console.log(' For us:', isForUs, 'Reply to our event:', isReplyToOurEvent)
|
|
||||||
|
|
||||||
if (isForUs) {
|
|
||||||
try {
|
|
||||||
const response = decryptJSON(identity, LIGHTNING_PUB_PUBKEY, evt.content)
|
|
||||||
console.log('Decrypted response:', JSON.stringify(response, null, 2))
|
|
||||||
responseReceived = true
|
|
||||||
} catch (err) {
|
|
||||||
console.log('Failed to decrypt response:', err.message)
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Ignore decrypt errors for other messages
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await client.publish(event)
|
await client.publish(event)
|
||||||
console.log('Request published, waiting for response...')
|
console.error('[fund-dev] Request published, waiting for invoice...')
|
||||||
|
|
||||||
// Wait up to 10 seconds for response
|
// Wait up to 15 seconds for response
|
||||||
for (let i = 0; i < 20; i++) {
|
for (let i = 0; i < 30; i++) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||||
if (responseReceived) break
|
if (invoice) break
|
||||||
}
|
|
||||||
|
|
||||||
if (!responseReceived) {
|
|
||||||
console.log('No response received within timeout')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client.unsubscribe(subId)
|
client.unsubscribe(subId)
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
|
|
||||||
|
if (!invoice) {
|
||||||
|
console.error('[fund-dev] Error: No invoice received within timeout')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output just the invoice to stdout (for piping to payment command)
|
||||||
|
console.log(invoice)
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error)
|
main().catch((err) => {
|
||||||
|
console.error('[fund-dev] Error:', err.message)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue