Cashu: add LNURLp (#1484)

This commit is contained in:
calle 2023-02-13 16:24:15 +01:00 committed by GitHub
parent 9840a8b154
commit 77a6ac041c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -627,22 +627,25 @@ page_container %}
</q-form> </q-form>
{% endraw %} {% endraw %}
</div> --> </div> -->
<!-- <div v-else-if="payInvoiceData.lnurlpay"> <div v-else-if="payInvoiceData.lnurlpay">
{% raw %} {% raw %}
<q-form @submit="payLnurl" class="q-gutter-md"> <q-form @submit="lnurlPaySecond" class="q-gutter-md">
<p v-if="payInvoiceData.lnurlpay.fixed" class="q-my-none text-h6"> <p
<b>{{ payInvoiceData.lnurlpay.domain }}</b> is requesting {{ v-if="payInvoiceData.lnurlpay.maxSendable == payInvoiceData.lnurlpay.minSendable"
payInvoiceData.lnurlpay.maxSendable | msatoshiFormat }} class="q-my-none text-h6 text-center"
{{LNBITS_DENOMINATION}} >
<span v-if="payInvoiceData.lnurlpay.commentAllowed > 0"> <b>{{ payInvoiceData.domain }}</b> is requesting {{
payInvoiceData.lnurlpay.maxSendable | msatoshiFormat }} {%
endraw %} {{LNBITS_DENOMINATION}} {% raw %}
<!-- <span v-if="payInvoiceData.lnurlpay.commentAllowed > 0">
<br /> <br />
and a {{payInvoiceData.lnurlpay.commentAllowed}}-char comment and a {{payInvoiceData.lnurlpay.commentAllowed}}-char comment
</span> </span> -->
</p> </p>
<p v-else class="q-my-none text-h6 text-center"> <p v-else class="q-my-none text-h6 text-center">
<b <b
>{{ payInvoiceData.lnurlpay.targetUser || >{{ payInvoiceData.lnurlpay.targetUser ||
payInvoiceData.lnurlpay.domain }}</b payInvoiceData.domain }}</b
> >
is requesting <br /> is requesting <br />
between between
@ -654,13 +657,13 @@ page_container %}
>{{ payInvoiceData.lnurlpay.maxSendable | msatoshiFormat }}</b >{{ payInvoiceData.lnurlpay.maxSendable | msatoshiFormat }}</b
> >
{% endraw %} {{LNBITS_DENOMINATION}} {% raw %} {% endraw %} {{LNBITS_DENOMINATION}} {% raw %}
<span v-if="payInvoiceData.lnurlpay.commentAllowed > 0"> <!-- <span v-if="payInvoiceData.lnurlpay.commentAllowed > 0">
<br /> <br />
and a {{payInvoiceData.lnurlpay.commentAllowed}}-char comment and a {{payInvoiceData.lnurlpay.commentAllowed}}-char comment
</span> </span> -->
</p> </p>
<q-separator class="q-my-sm"></q-separator> <q-separator class="q-my-sm"></q-separator>
<div class="row"> <div class="row" v-if="payInvoiceData.lnurlpay.description">
<p class="col text-justify text-italic"> <p class="col text-justify text-italic">
{{ payInvoiceData.lnurlpay.description }} {{ payInvoiceData.lnurlpay.description }}
</p> </p>
@ -674,14 +677,14 @@ page_container %}
<q-input <q-input
filled filled
dense dense
autofocus
v-model.number="payInvoiceData.data.amount" v-model.number="payInvoiceData.data.amount"
type="number" type="number"
label="Amount ({{LNBITS_DENOMINATION}}) *" label="Amount ({{LNBITS_DENOMINATION}}) *"
:min="payInvoiceData.lnurlpay.minSendable / 1000" :min="payInvoiceData.lnurlpay.minSendable / 1000"
:max="payInvoiceData.lnurlpay.maxSendable / 1000" :max="payInvoiceData.lnurlpay.maxSendable / 1000"
:readonly="payInvoiceData.lnurlpay.fixed" :readonly="payInvoiceData.lnurlpay.maxSendable == payInvoiceData.lnurlpay.minSendable"
></q-input> ></q-input>
{% raw %}
</div> </div>
<div <div
class="col-8 q-pl-md" class="col-8 q-pl-md"
@ -691,23 +694,20 @@ page_container %}
filled filled
dense dense
v-model="payInvoiceData.data.comment" v-model="payInvoiceData.data.comment"
:type="payInvoiceData.lnurlpay.commentAllowed > 64 ? 'textarea' : 'text'" _type="payInvoiceData.lnurlpay.commentAllowed > 64 ? 'textarea' : 'text'"
label="Comment (optional)" label="Comment (optional)"
:maxlength="payInvoiceData.lnurlpay.commentAllowed" :maxlength="payInvoiceData.lnurlpay.commentAllowed"
></q-input> ></q-input>
</div> </div>
</div> </div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn unelevated color="primary" type="submit" <q-btn unelevated color="primary" type="submit">Send</q-btn>
>Send {{LNBITS_DENOMINATION}}</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto" <q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn >Cancel</q-btn
> >
</div> </div>
</q-form> </q-form>
{% endraw %} </div>
</div> -->
<div v-else> <div v-else>
<q-form <q-form
v-if="!camera.show" v-if="!camera.show"
@ -720,7 +720,7 @@ page_container %}
dense dense
v-model.trim="payInvoiceData.data.request" v-model.trim="payInvoiceData.data.request"
type="textarea" type="textarea"
label="Enter a Lightning invoice" label="Enter a Lightning invoice, an LNURL, or a Lightning address"
> >
</q-input> </q-input>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
@ -1580,6 +1580,7 @@ page_container %}
this.payInvoiceData.show = true this.payInvoiceData.show = true
this.payInvoiceData.invoice = null this.payInvoiceData.invoice = null
this.payInvoiceData.lnurlpay = null this.payInvoiceData.lnurlpay = null
this.payInvoiceData.domain = ''
this.payInvoiceData.lnurlauth = null this.payInvoiceData.lnurlauth = null
this.payInvoiceData.data.request = '' this.payInvoiceData.data.request = ''
this.payInvoiceData.data.comment = '' this.payInvoiceData.data.comment = ''
@ -1651,10 +1652,6 @@ page_container %}
) { ) {
this.payInvoiceData.data.request = req this.payInvoiceData.data.request = req
reqtype = 'lnurl' reqtype = 'lnurl'
return
// } else if (req.indexOf('cashu:') !== 1) {
// this.receiveData.tokensBase64 = req.slice(req.indexOf('cashu:'))
// reqtype = 'cashu'
} else if (req.indexOf('eyJwcm')) { } else if (req.indexOf('eyJwcm')) {
// very dirty way of parsing cashu tokens from either a pasted token or a URL like https://host.com?token=eyJwcm // very dirty way of parsing cashu tokens from either a pasted token or a URL like https://host.com?token=eyJwcm
this.receiveData.tokensBase64 = req.slice(req.indexOf('eyJwcm')) this.receiveData.tokensBase64 = req.slice(req.indexOf('eyJwcm'))
@ -1704,13 +1701,63 @@ page_container %}
this.payInvoiceData.invoice = Object.freeze(cleanInvoice) this.payInvoiceData.invoice = Object.freeze(cleanInvoice)
} else if (reqtype == 'lnurl') { } else if (reqtype == 'lnurl') {
console.log('#### QR CODE: LNURL') console.log('#### QR CODE: LNURL')
// not supported yet this.lnurlPayFirst(this.payInvoiceData.data.request)
} else if (reqtype == 'cashu') { } else if (reqtype == 'cashu') {
console.log('#### QR CODE: CASHU TOKEN') console.log('#### QR CODE: CASHU TOKEN')
this.payInvoiceData.show = false this.payInvoiceData.show = false
this.showReceiveTokens = true this.showReceiveTokens = true
} }
}, },
lnurlPayFirst: async function (address) {
var host
if (address.split('@').length == 2) {
let [user, lnaddresshost] = address.split('@')
host = `https://${lnaddresshost}/.well-known/lnurlp/${user}`
} else if (address.toLowerCase().slice(0, 6) === 'lnurl1') {
// let host = Buffer.from(
// bech32.fromWords(bech32.decode(address, 20000).words)
// ).toString()
// var {data} = await axios.get(host)
const {data} = await LNbits.api.request(
'POST',
'/api/v1/payments/decode',
'',
{
data: address
}
)
host = data.domain
}
var {data} = await axios.get(host)
if (data.tag == 'payRequest') {
this.payInvoiceData.domain = host.split('https://')[1].split('/')[0]
this.payInvoiceData.lnurlpay = data
if (
this.payInvoiceData.lnurlpay.maxSendable ==
this.payInvoiceData.lnurlpay.minSendable
) {
this.payInvoiceData.data.amount =
this.payInvoiceData.lnurlpay.maxSendable / 1000
}
this.payInvoiceData.show = true
}
},
lnurlPaySecond: async function () {
let amount = this.payInvoiceData.data.amount
if (
this.payInvoiceData.lnurlpay.tag == 'payRequest' &&
this.payInvoiceData.lnurlpay.minSendable <=
amount * 1000 <=
this.payInvoiceData.lnurlpay.maxSendable
) {
var {data} = await axios.get(
`${this.payInvoiceData.lnurlpay.callback}?amount=${amount * 1000}`
)
console.log(data.pr)
this.payInvoiceData.data.request = data.pr
this.decodeRequest()
}
},
payInvoice: function () { payInvoice: function () {
let dismissPaymentMsg = this.$q.notify({ let dismissPaymentMsg = this.$q.notify({
timeout: 0, timeout: 0,
@ -1725,34 +1772,35 @@ page_container %}
] ]
}) })
}, },
payLnurl: function () { // payLnurl: function () {
let dismissPaymentMsg = this.$q.notify({ // let dismissPaymentMsg = this.$q.notify({
timeout: 0, // timeout: 0,
message: 'Processing payment...', // message: 'Processing payment...',
position: 'top', // position: 'top',
actions: [ // actions: [
{ // {
icon: 'close', // icon: 'close',
color: 'white', // color: 'white',
handler: () => {} // handler: () => {}
} // }
] // ]
}) // })
}, // this.lnurlPaySecond()
authLnurl: function () { // },
let dismissAuthMsg = this.$q.notify({ // authLnurl: function () {
timeout: 10, // let dismissAuthMsg = this.$q.notify({
message: 'Performing authentication...', // timeout: 10,
position: 'top', // message: 'Performing authentication...',
actions: [ // position: 'top',
{ // actions: [
icon: 'close', // {
color: 'white', // icon: 'close',
handler: () => {} // color: 'white',
} // handler: () => {}
] // }
}) // ]
}, // })
// },
/////////////////////////////////// WALLET /////////////////////////////////// /////////////////////////////////// WALLET ///////////////////////////////////
showInvoiceCreateDialog: async function () { showInvoiceCreateDialog: async function () {