Add support for invoices that accept any amount

This commit is contained in:
Nadav Ivgi 2018-01-26 14:01:54 +02:00
parent 2aa386cfce
commit 5d3743acba
4 changed files with 31 additions and 14 deletions

View File

@ -87,21 +87,25 @@ If a currency and amount were provided, they'll be available under `quoted_{curr
Returns `201 Created` and the invoice on success.
```bash
$ curl $CHARGE/invoice -d msatoshi=10000
$ curl -X POST $CHARGE/invoice -d msatoshi=10000
{"id":"KcoQHfHJSx3fVhp3b1Y3h","msatoshi":"10000","status":"unpaid","rhash":"6823e46a08f50...",
"payreq":"lntb100n1pd99d02pp...","created_at":1515369962,"expires_at":1515373562}
# with fiat-denominated amounts
$ curl $CHARGE/invoice -d currency=EUR -d amount=0.5
$ curl -X POST $CHARGE/invoice -d currency=EUR -d amount=0.5
{"id":"OYwwaOQAPMFvg039gj_Rb","msatoshi":"3738106","quoted_currency":"EUR","quoted_amount":"0.5",...}
# without amount (accept all payments)
$ curl -X POST $CHARGE/invoice
{"id":"W8CF0UqY7qfAHCfnchqk9","msatoshi":null,...}
# with metadata as application/json
$ curl $CHARGE/invoice -H 'Content-Type: application/json' \
$ curl -X POST $CHARGE/invoice -H 'Content-Type: application/json' \
-d '{"msatoshi":7000,"metadata":{"customer_id":9817,"products":[593,182]}}'
{"id":"PLKV1f8B7sth7w2OeDOt_","msatoshi":"7000","metadata":{"customer_id":9817,"products":[593,182]},...}
# with metadata as application/x-www-form-urlencoded
$ curl $CHARGE/invoice -d msatoshi=5000 -d metadata[customer_id]=9817 -d metadata[product_id]=7189
$ curl -X POST $CHARGE/invoice -d msatoshi=5000 -d metadata[customer_id]=9817 -d metadata[product_id]=7189
{"id":"58H9eoerBpKML9FvnMQtG","msatoshi":"5000","metadata":{"customer_id":"9817","product_id":"7189"},...}
```
@ -156,7 +160,7 @@ For security reasons, the provided `url` should contain a secret token used to v
and [here](https://github.com/ElementsProject/woocommerce-gateway-lightning/blob/84592d7bcfc41db129b02d1927a6060a05c5c11e/woocommerce-gateway-lightning.php#L109-L115)).
```bash
$ curl $CHARGE/invoice/OYwwaOQAPMFvg039gj_Rb/webhook -d url=http://example.com/callback
$ curl -X POST $CHARGE/invoice/OYwwaOQAPMFvg039gj_Rb/webhook -d url=http://example.com/callback
Created
```

View File

@ -4,13 +4,19 @@ import { toMsat } from './lib/exchange-rate'
const debug = require('debug')('lightning-charge')
, status = inv => inv.pay_index ? 'paid' : inv.expires_at > now() ? 'unpaid' : 'expired'
, format = inv => ({ ...inv, completed: !!inv.pay_index, completed_at: inv.paid_at
, status: status(inv), metadata: JSON.parse(inv.metadata) })
, status: status(inv), msatoshi: (inv.msatoshi || null), metadata: JSON.parse(inv.metadata) })
, now = _ => Date.now() / 1000 | 0
// @XXX the `completed` and `completed_at` field are deprecated
// in favor `status` and `paid_at`, and will eventually be removed
// from the public API.
// @XXX invoices that accept any amount are stored as msatoshi='' (empty string)
// and converted to null when formatted. this is due to sqlite's lack of support
// for ALTER TABLE, which makes dropping the NOT NULL constraint complicated
// (requires creating a new table, copying over the data and replacing the old one).
// This will eventually be done in a future release.
const defaultDesc = process.env.INVOICE_DESC_DEFAULT || 'Lightning Charge Invoice'
module.exports = (db, ln) => {
@ -18,8 +24,8 @@ module.exports = (db, ln) => {
const { currency, amount, expiry, description, metadata, webhook } = props
const id = nanoid()
, msatoshi = props.msatoshi ? ''+props.msatoshi : await toMsat(currency, amount)
, lninv = await ln.invoice(msatoshi, id, description || defaultDesc, expiry)
, msatoshi = props.msatoshi ? ''+props.msatoshi : currency ? await toMsat(currency, amount) : ''
, lninv = await ln.invoice(msatoshi || 'any', id, description || defaultDesc, expiry)
const invoice = {
id, description, msatoshi

View File

@ -48,6 +48,12 @@ describe('Invoice API', function() {
.expect(201)
.expect(r => r.body.expires_at*1000 - Date.now() < 5000)
)
it('can create invoices that accept any amount', () => {
charge.post('/invoice')
.expect(201)
.expect(r => r.body.msatoshi == null)
})
})
const mkInvoice = props =>

View File

@ -26,12 +26,13 @@ body: .checkout.container
.desc.col-sm-6
h3= opt.title || 'Lightning Payment'
h4= opt.desc || 'Pay with Lightning'
.amounts.col-sm-6
if quoted_currency
h3 #{ quoted_amount } #{ quoted_currency }
h4 #{ formatMsat(msatoshi) }
else
h3 #{ formatMsat(msatoshi) }
if msatoshi
.amounts.col-sm-6
if quoted_currency
h3 #{ quoted_amount } #{ quoted_currency }
h4 #{ formatMsat(msatoshi) }
else
h3 #{ formatMsat(msatoshi) }
if status == 'paid'
p.thankyou= opt.thank_you || 'Thank you! Your payment has been received.'