feat(nip05): add Lightning Address support for zaps
Adds /.well-known/lnurlp/:username endpoint that: 1. Looks up username in NIP-05 database 2. Gets LNURL-pay info from Lightning.Pub for that user 3. Returns standard LUD-16 response for wallet compatibility This makes NIP-05 addresses (alice@domain) work seamlessly as Lightning Addresses for receiving payments and NIP-57 zaps. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8f38622395
commit
a7fb92e26d
1 changed files with 73 additions and 0 deletions
|
|
@ -94,6 +94,13 @@ export default class Nip05Extension implements Extension {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/api/v1/nip05/nostr.json',
|
path: '/api/v1/nip05/nostr.json',
|
||||||
handler: this.handleNostrJson.bind(this)
|
handler: this.handleNostrJson.bind(this)
|
||||||
|
},
|
||||||
|
// Lightning Address endpoint (LUD-16)
|
||||||
|
// Makes NIP-05 usernames work as Lightning Addresses for zaps
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
path: '/.well-known/lnurlp/:username',
|
||||||
|
handler: this.handleLnurlPay.bind(this)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -220,6 +227,72 @@ export default class Nip05Extension implements Extension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle /.well-known/lnurlp/:username request (Lightning Address / LUD-16)
|
||||||
|
*
|
||||||
|
* This enables NIP-05 usernames to work as Lightning Addresses for receiving
|
||||||
|
* payments and zaps. When someone sends to alice@domain.com:
|
||||||
|
* 1. Wallet resolves /.well-known/lnurlp/alice
|
||||||
|
* 2. We look up alice -> pubkey in our NIP-05 database
|
||||||
|
* 3. We return LNURL-pay info from Lightning.Pub for that user
|
||||||
|
*/
|
||||||
|
private async handleLnurlPay(req: HttpRequest): Promise<HttpResponse> {
|
||||||
|
try {
|
||||||
|
const { username } = req.params
|
||||||
|
const appId = req.headers['x-application-id'] || 'default'
|
||||||
|
|
||||||
|
if (!username) {
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
body: { status: 'ERROR', reason: 'Username required' },
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up the username in our NIP-05 database
|
||||||
|
const lookup = await this.manager.lookupUsername(appId, username)
|
||||||
|
|
||||||
|
if (!lookup.found || !lookup.identity) {
|
||||||
|
return {
|
||||||
|
status: 404,
|
||||||
|
body: { status: 'ERROR', reason: 'User not found' },
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get LNURL-pay info from Lightning.Pub for this user's pubkey
|
||||||
|
const lnurlPayInfo = await this.ctx.getLnurlPayInfo(lookup.identity.pubkey_hex, {
|
||||||
|
description: `Pay to ${username}`
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: lnurlPayInfo,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Cache-Control': 'max-age=60' // Cache for 1 minute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.ctx.log('error', `Error handling lnurlp: ${error}`)
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
body: { status: 'ERROR', reason: 'Internal server error' },
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export types for external use
|
// Export types for external use
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue