aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2023-01-18 23:14:48 -0800
committerAdam Soltys <[email protected]>2023-01-18 23:14:48 -0800
commitef3679051214a9b3047b68f236eac656edcf8d38 (patch)
tree426eda7cf7e36026c60da2ae28ce7c61804518f8
parent90ddef9f0dd93e8f980eb728cf0519d9215163f0 (diff)
downloadcoinos-server-ef3679051214a9b3047b68f236eac656edcf8d38.tar.gz
coinos-server-ef3679051214a9b3047b68f236eac656edcf8d38.zip
bitcoin invoices
-rw-r--r--index.js1
-rw-r--r--lib/bitcoin.js2
-rw-r--r--lib/rpc.js26
-rw-r--r--lib/utils.js9
-rw-r--r--routes/invoices.js38
-rw-r--r--routes/payments.js7
6 files changed, 67 insertions, 16 deletions
diff --git a/index.js b/index.js
index 1ade59d8..6a34f543 100644
--- a/index.js
+++ b/index.js
@@ -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({});
}
};