diff options
| author | Adam Soltys <[email protected]> | 2024-08-26 21:17:43 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-08-26 21:17:43 -0700 |
| commit | fe62cadd6fb4a7e49f7d59401fc74ae0411e32a7 (patch) | |
| tree | aa8f34e1692bd2d638a2c996eeadb58671d07aea /lib/invoices.ts | |
| parent | 00e43ddc0bf3d6dd719fc9295d156567fa2fecfb (diff) | |
| download | coinos-server-fe62cadd6fb4a7e49f7d59401fc74ae0411e32a7.tar.gz coinos-server-fe62cadd6fb4a7e49f7d59401fc74ae0411e32a7.zip | |
typescript
Diffstat (limited to 'lib/invoices.ts')
| -rw-r--r-- | lib/invoices.ts | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/lib/invoices.ts b/lib/invoices.ts new file mode 100644 index 00000000..2f1225e7 --- /dev/null +++ b/lib/invoices.ts @@ -0,0 +1,128 @@ +import crypto from "crypto"; +import store from "$lib/store"; +import { l } from "$lib/logging"; +import { emit } from "$lib/sockets"; +import { db, g, s } from "$lib/db"; +import { getUser, bip21, fail, SATS } from "$lib/utils"; +import { types } from "$lib/payments"; +import { v4 } from "uuid"; + +import lq from "$lib/liquid"; +import bc from "$lib/bitcoin"; +import ln from "$lib/ln"; + +export let generate = async ({ invoice, user, sender }) => { + let { + bolt11, + currency, + expiry, + fiat, + tip, + amount, + items = [], + rate, + request_id, + memo, + memoPrompt, + prompt, + type, + webhook, + secret, + } = invoice; + + amount = parseInt(amount || 0); + tip = parseInt(tip) || null; + + if (user) user = await getUser(user.username); + else if (sender) user = await getUser(sender.username); + if (!user) fail("user not provided"); + + let rates = await g('rates'); + if (!currency) currency = user.currency; + if (!rate) rate = rates[currency]; + if (fiat) amount = Math.round((SATS * fiat) / rate); + if (amount < 0) fail("invalid amount"); + if (tip < 0) fail("invalid tip"); + if (rate < 0) fail("invalid rate"); + if (memo && memo.length > 5000) fail("memo too long"); + + let id = v4(); + + let hash, text; + if (type === types.lightning) { + let r; + if (bolt11) { + let { id: nodeid } = await ln.getinfo(); + r = await ln.decode(bolt11); + if (r.payee !== nodeid) fail("invalid invoice"); + amount = Math.round(r.amount_msat / 1000); + r.bolt11 = bolt11; + } else { + r = await ln.invoice({ + amount_msat: amount ? `${amount + tip}sat` : "any", + label: id, + description: memo || "", + expiry: expiry || 60 * 60 * 24 * 30, + deschashonly: true, + cltv: 19, + }); + } + + hash = r.bolt11; + text = r.bolt11; + } else if (type === types.bitcoin) { + hash = await bc.getNewAddress(); + text = bip21(hash, invoice); + } else if (type === types.liquid) { + hash = await lq.getNewAddress(); + text = bip21(hash, invoice); + } else if (type === types.internal) { + hash = id; + } else { + fail("unrecognized type"); + } + + invoice = { + amount, + created: Date.now(), + currency, + hash, + id, + items, + memo, + rate, + pending: 0, + received: 0, + request_id, + memoPrompt, + prompt, + secret, + text, + tip, + type, + uid: user.id, + webhook, + }; + + if (type === "liquid") { + let { unconfidential } = await lq.getAddressInfo(hash); + await s(`invoice:${unconfidential}`, id); + } + + await s(`invoice:${hash}`, id); + await s(`invoice:${id}`, invoice); + await db.lPush(`${user.id}:invoices`, id); + + if (request_id) { + let request = await g(`request:${request_id}`); + if (request) { + let { invoice_id: prev } = request; + request.invoice_id = id; + await s(`request:${request_id}`, request); + + if (!prev) emit(request.requester_id, "invoice", invoice); + } + } + + return invoice; +}; |
