diff options
| author | Adam Soltys <[email protected]> | 2023-01-18 23:14:48 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2023-01-18 23:14:48 -0800 |
| commit | ef3679051214a9b3047b68f236eac656edcf8d38 (patch) | |
| tree | 426eda7cf7e36026c60da2ae28ce7c61804518f8 | |
| parent | 90ddef9f0dd93e8f980eb728cf0519d9215163f0 (diff) | |
| download | coinos-server-ef3679051214a9b3047b68f236eac656edcf8d38.tar.gz coinos-server-ef3679051214a9b3047b68f236eac656edcf8d38.zip | |
bitcoin invoices
| -rw-r--r-- | index.js | 1 | ||||
| -rw-r--r-- | lib/bitcoin.js | 2 | ||||
| -rw-r--r-- | lib/rpc.js | 26 | ||||
| -rw-r--r-- | lib/utils.js | 9 | ||||
| -rw-r--r-- | routes/invoices.js | 38 | ||||
| -rw-r--r-- | routes/payments.js | 7 |
6 files changed, 67 insertions, 16 deletions
@@ -50,6 +50,7 @@ app.get("/payments/:hash", auth, payments.get); app.post("/lightning/send", auth, payments.sendLightning); app.get("/pot/:name", payments.pot); app.post("/withdraw", auth, payments.withdraw); +app.post("/bitcoin", payments.bitcoin); app.get("/voucher/:id", payments.voucher); app.post("/redeem", optional, payments.redeem); diff --git a/lib/bitcoin.js b/lib/bitcoin.js index eda8b4b0..a811dc14 100644 --- a/lib/bitcoin.js +++ b/lib/bitcoin.js @@ -1,3 +1,3 @@ import config from "$config"; -import rpc from "./rpc"; +import rpc from "$lib/rpc"; export default rpc(config.bitcoin); diff --git a/lib/rpc.js b/lib/rpc.js new file mode 100644 index 00000000..b8a2d0dd --- /dev/null +++ b/lib/rpc.js @@ -0,0 +1,26 @@ +import got from "got"; + +export default ({ host, port, wallet, username, password }) => + new Proxy( + {}, + { + get: (target, prop) => (...params) => + ((method, ...params) => { + let url = `http://${host}:${port}/wallet/${wallet}`; + return got + .post(url, { + json: { + method, + params + }, + headers: { + authorization: `Basic ${Buffer.from( + `${username}:${password}` + ).toString("base64")}` + } + }) + .json() + .then(({ result }) => result); + })(prop.toLowerCase(), ...params) + } + ); diff --git a/lib/utils.js b/lib/utils.js index 92b34be5..e653f235 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -28,3 +28,12 @@ export const toSats = n => Math.round(n * SATS); export const uniq = (a, k) => [...new Map(a.map(x => [k(x), x])).values()]; export const pick = (O, K) => K.reduce((o, k) => (typeof O[k] !== "undefined" && (o[k] = O[k]), o), {}); + +export const bip21 = (address, { amount, memo, tip }) => { + let url = amount || memo ? `bitcoin:${address}?` : address; + if (amount) + url += `amount=${((amount + tip) / SATS).toFixed(8)}${memo ? "&" : ""}`; + if (memo) url += `message=${memo}`; + + return url; +}; diff --git a/routes/invoices.js b/routes/invoices.js index acd9457e..1287de88 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -2,6 +2,8 @@ import store from "$lib/store"; import { l } from "$lib/logging"; import { emit } from "$lib/sockets"; import { db, g, s } from "$lib/db"; +import { bip21, fail } from "$lib/utils"; +import bc from "$lib/bitcoin"; import ln from "$lib/ln"; export default { @@ -12,49 +14,57 @@ export default { }, async create({ body: { invoice, user }, user: me }, res) { - let { currency, tip, amount, rate, request_id } = invoice; + let { currency, tip, amount, rate, request_id, type } = invoice; - if (amount < 0) throw new Error("amount out of range"); - if (tip > 5 * amount || tip < 0) throw new Error("tip amount out of range"); + if (amount < 0) fail("amount out of range"); + if (tip > 5 * amount || tip < 0) fail("tip amount out of range"); tip = tip || 0; if (!user) user = me; let uid = await g(`user:${user.username}`); user = await g(`user:${uid}`); - if (!user) throw new Error("user not provided"); + if (!user) fail("user not provided"); if (!currency) currency = user.currency; if (!rate) rate = store.rates[currency]; - if (amount < 0) throw new Error("invalid amount"); + if (amount < 0) fail("invalid amount"); - let { payment_hash: hash, bolt11: text } = await ln.invoice( - amount ? `${amount + tip}sat` : "any", - new Date(), - "", - 3600 - ); + let hash, text; + if (type === "lightning") { + let amt = amount ? `${amount + tip}sat` : "any"; + let r = await ln.invoice(amt, new Date(), "", 3600); + + hash = r.payment_hash; + text = r.bolt11; + } else if (type === "bitcoin") { + hash = await bc.getNewAddress(); + text = bip21(hash, invoice); + } else { + fail("unrecognized type"); + } invoice = { ...invoice, - hash, amount, + hash, + text, currency, rate, tip, uid, - text, received: 0, created: Date.now() }; + l( "creating invoice", user.username, amount, tip, currency, - `${text.substr(0, 8)}..${text.substr(-6)}` + invoice.hash ); await s(`invoice:${hash}`, invoice); diff --git a/routes/payments.js b/routes/payments.js index ba701bef..fc506685 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -265,7 +265,7 @@ export default { }, async withdraw({ body: { name, amount }, user }, res) { - amount = parseInt(amount) + amount = parseInt(amount); await t(`pot:${name}`, async balance => { await new Promise(r => setTimeout(r, 100)); if (balance < amount) fail("Insufficient funds"); @@ -282,5 +282,10 @@ export default { await db.lPush(`pot:${name}:payments`, hash); res.send({ payment }); + }, + + async bitcoin({ body }, res) { + console.log(body); + res.send({}); } }; |
