Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ COMMANDS
lightning:
fund pay a bolt11 for funding
withdraw create a bolt11 for withdrawal
lnurl_auth mock lnurl-auth
lnurl_withdraw mock lnurl-withdraw

db:
psql open psql on db
Expand Down
28 changes: 28 additions & 0 deletions scripts/lnurl-auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env node
const { secp256k1 } = require('@noble/curves/secp256k1')
const { createHash } = require('crypto')
const k1 = process.argv[2]
const identityPubkey = process.argv[3]
const domain = process.argv[4]
const callbackBase = process.argv[5]
if (!k1 || !identityPubkey || !domain || !callbackBase) {
console.error('Usage: lnurl-auth.js <k1> <identity_pubkey> <domain> <callback_base>')
process.exit(1)
}
try {
const linkingKey = createHash('sha256')
.update(identityPubkey + domain)
.digest()
const k1Bytes = Buffer.from(k1, 'hex')
const signature = secp256k1.sign(k1Bytes, linkingKey)
const publicKey = secp256k1.getPublicKey(linkingKey)
const params = new URLSearchParams({
k1,
sig: Buffer.from(signature.toCompactRawBytes()).toString('hex'),
key: Buffer.from(publicKey).toString('hex')
})
console.log(`${callbackBase}?${params}`)
} catch (err) {
console.error('Failed to sign LNURL-auth:', err.message)
process.exit(1)
}
16 changes: 16 additions & 0 deletions scripts/lnurl-decode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env node
const { bech32 } = require('bech32')

const lnurl = process.argv[2]
if (!lnurl) {
console.error('Usage: lnurl-decode.js <lnurl>')
process.exit(1)
}
try {
const { words } = bech32.decode(lnurl, 2000)
const url = Buffer.from(bech32.fromWords(words)).toString('utf8')
console.log(url)
} catch (err) {
console.error('Failed to decode LNURL:', err.message)
process.exit(1)
}
68 changes: 68 additions & 0 deletions sndev
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,72 @@ sndev__withdraw() {
fi
}

sndev__lnurl_auth() {
shift
lnurl="$1"
if [ -z "$lnurl" ]; then
echo "LNURL required"
sndev__help_lnurl_auth
exit 1
fi
decoded=$(docker__exec app node /app/scripts/lnurl-decode.js "$lnurl")
echo "Decoded: $decoded"
k1=$(echo "$decoded" | sed -n 's/.*k1=\([^&]*\).*/\1/p')
identity_pubkey=$(sndev__cli lnd getinfo | jq -r '.identity_pubkey')
domain=$(echo "$decoded" | sed 's|.*://\([^/]*\).*|\1|')
callback_base=$(echo "$decoded" | cut -d'?' -f1)
callback_url=$(docker__exec app node /app/scripts/lnurl-auth.js "$k1" "$identity_pubkey" "$domain" "$callback_base")
echo "Callback: $callback_url"
curl -s "$callback_url" | jq
}

sndev__help_lnurl_auth() {
help="
mock lnurl-auth for local testing

USAGE
$ sndev lnurl_auth LNURL

DESCRIPTION
Decodes the LNURL, derives a linking key from stacker_lnd identity,
signs the k1 challenge, and sends the response to the callback URL.
"
echo "$help"
}

sndev__lnurl_withdraw() {
shift
lnurl="$1"
if [ -z "$lnurl" ]; then
echo "LNURL required"
sndev__help_lnurl_withdraw
exit 1
fi
decoded=$(docker__exec app node /app/scripts/lnurl-decode.js "$lnurl")
echo "Decoded: $decoded"
params=$(curl -s "$decoded")
echo "$params" | jq
callback=$(echo "$params" | jq -r '.callback')
max=$(echo "$params" | jq -r '.maxWithdrawable')
k1=$(echo "$params" | jq -r '.k1')
bolt11=$(sndev__cli lnd addinvoice --amt $((max/1000)) | jq -r '.payment_request')
echo "Invoice: $bolt11"
curl -s "${callback}?k1=${k1}&pr=${bolt11}" | jq
}

sndev__help_lnurl_withdraw() {
help="
mock lnurl-withdraw for local testing

USAGE
$ sndev lnurl_withdraw LNURL

DESCRIPTION
Decodes the LNURL, fetches withdrawal parameters, creates an invoice
for the maximum amount, and sends it to the callback URL.
"
echo "$help"
}
sndev__help_withdraw() {
help="
create a bolt11 for withdrawal
Expand Down Expand Up @@ -689,6 +755,8 @@ COMMANDS
lightning:
fund pay a bolt11 for funding
withdraw create a bolt11 for withdrawal
lnurl_auth mock lnurl-auth
lnurl_withdraw mock lnurl-withdraw

db:
psql open psql on db
Expand Down