aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2020-05-07 20:15:56 -0700
committerAdam Soltys <[email protected]>2020-05-07 20:58:24 -0700
commit47aa48402a0d34dd8ab11f0f315393fcc4f5c61b (patch)
tree2e907e64628d26c4707660e854e9bc87b332ff08
parent2f0f9e640ead76518f7f8013b16704da89421ee4 (diff)
downloadcoinos-server-47aa48402a0d34dd8ab11f0f315393fcc4f5c61b.tar.gz
coinos-server-47aa48402a0d34dd8ab11f0f315393fcc4f5c61b.zip
c-lightning support
-rw-r--r--package.json1
-rw-r--r--routes/balances.js22
-rw-r--r--routes/lightning/invoice.js20
-rw-r--r--routes/lightning/query.js28
-rw-r--r--routes/lightning/receive.js45
-rw-r--r--routes/lightning/send.js102
-rw-r--r--routes/lightning/user.js52
-rw-r--r--routes/payments.js14
-rw-r--r--yarn.lock27
9 files changed, 180 insertions, 131 deletions
diff --git a/package.json b/package.json
index 5e1e537c..588ec7a8 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"body-parser": "^1.19.0",
"bolt11": "^1.2.5",
"buffer-reverse": "^1.0.1",
+ "clightning-client": "^0.1.2",
"compression": "^1.7.4",
"connect-redis": "3.4.1",
"cookie-parser": "^1.4.4",
diff --git a/routes/balances.js b/routes/balances.js
index 9e57750b..78567c44 100644
--- a/routes/balances.js
+++ b/routes/balances.js
@@ -11,19 +11,33 @@ app.get("/info", async (req, res) => {
group: ["asset"],
});
+ let lnchannel;
+ let lnwallet;
+ let lninfo;
+
+ if (config.lna.clightning) {
+ lninfo = await lna.getinfo();
+ const funds = await lna.listfunds();
+ lnchannel = parseInt(funds.channels.reduce((a, b) => a + b.channel_sat, 0));
+ lnwallet = parseInt(funds.outputs.reduce((a, b) => a + b.value, 0));
+ } else {
+ lninfo = await lna.getInfo({});
+ lnchannel = parseInt((await lna.channelBalance({})).balance);
+ lnwallet = parseInt((await lna.walletBalance({})).total_balance);
+ }
+
const info = {
- lnd: await lna.getInfo({}),
bitcoind: await bc.getNetworkInfo(),
elementsd: await lq.getNetworkInfo(),
accounts,
assets,
bitcoin: parseInt((await bc.getBalance()) * SATS),
liquid: parseInt(assets.bitcoin * SATS),
- lnchannel: parseInt((await lna.channelBalance({})).balance),
- lnwallet: parseInt((await lna.walletBalance({})).total_balance),
+ lnchannel,
+ lnwallet,
};
- const { bitcoin, liquid, lnchannel, user, lnwallet } = info;
+ const { bitcoin, liquid, user } = info;
info.total =
parseInt(bitcoin) +
diff --git a/routes/lightning/invoice.js b/routes/lightning/invoice.js
index f19b3484..3f4ab1db 100644
--- a/routes/lightning/invoice.js
+++ b/routes/lightning/invoice.js
@@ -3,9 +3,25 @@ module.exports = async (req, res) => {
l.info("adding lightning invoice", req.user.username, amount, tip);
+ /*
+ const exists = await db.Invoice.findOne({
+ where: {
+ [Op.or]: {
+ address: invoice.address || "undefined",
+ text: invoice.text
+ }
+ }
+ });
+ */
+
try {
- const invoice = await lnb.addInvoice({ value: amount + tip });
- res.send(invoice.payment_request);
+ if (config.lna.clightning) {
+ const invoice = await lnb.invoice(`${amount + tip}sat` || "any", new Date(), "", 360);
+ res.send(invoice.bolt11);
+ } else {
+ const invoice = await lnb.addInvoice({ value: amount + tip });
+ res.send(invoice.payment_request);
+ }
} catch (e) {
l.error("problem creating invoice", e.message);
res.status(500).send(e.message);
diff --git a/routes/lightning/query.js b/routes/lightning/query.js
deleted file mode 100644
index 6e70f30a..00000000
--- a/routes/lightning/query.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const bolt11 = require("bolt11");
-
-module.exports = async (req, res) => {
- let { amount, payreq } = req.body;
-
- try {
- let invoice = await db.Invoice.findOne({
- where: { text: payreq },
- include: {
- model: db.User,
- as: "user"
- }
- });
-
- if (invoice) emit(req.user.username, "to", invoice.user);
-
- payreq = bolt11.decode(payreq);
-
- res.send(
- await lna.queryRoutes({
- pub_key: payreq.payeeNodeKey,
- amt: amount || payreq.satoshis
- })
- );
- } catch (e) {
- res.status(500).send(e.message);
- }
-};
diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js
index 286541d2..3082c205 100644
--- a/routes/lightning/receive.js
+++ b/routes/lightning/receive.js
@@ -21,13 +21,15 @@ const handlePayment = async msg => {
}
});
+ let preimage = msg.r_preimage.toString("hex");
+
let payment = await db.Payment.create({
account_id: account.id,
user_id,
hash,
amount,
currency,
- preimage: msg.r_preimage.toString('hex'),
+ preimage,
rate,
received: true,
confirmed: true,
@@ -54,12 +56,43 @@ const handlePayment = async msg => {
"lightning payment received",
user.username,
payment.amount,
- payment.tip,
+ payment.tip
);
};
-const invoices = lna.subscribeInvoices({});
-invoices.on("data", handlePayment);
+if (config.lna.clightning) {
+ const poll = async ln => {
+ const wait = async i => {
+ const {
+ bolt11: payment_request,
+ pay_index,
+ status,
+ msatoshi_received,
+ payment_preimage: r_preimage
+ } = await ln.waitanyinvoice(i);
+
+ let settled = status === "paid";
+ let amt_paid_sat = parseInt(msatoshi_received / 1000);
+
+ await handlePayment({
+ payment_request,
+ settled,
+ amt_paid_sat,
+ r_preimage
+ });
+ wait(pay_index);
+ };
+
+ const { invoices } = await ln.listinvoices();
+ wait(Math.max(...invoices.map(i => i.pay_index).filter(n => n)));
+ };
+
+ poll(lna);
+ poll(lnb);
+} else {
+ const invoices = lna.subscribeInvoices({});
+ invoices.on("data", handlePayment);
-const invoicesb = lnb.subscribeInvoices({});
-invoicesb.on("data", handlePayment);
+ const invoicesb = lnb.subscribeInvoices({});
+ invoicesb.on("data", handlePayment);
+}
diff --git a/routes/lightning/send.js b/routes/lightning/send.js
index 2c17ba1f..e3b5c75a 100644
--- a/routes/lightning/send.js
+++ b/routes/lightning/send.js
@@ -30,57 +30,90 @@ module.exports = async (req, res) => {
throw new Error("Insufficient funds");
}
- let m = await lna.sendPaymentSync({
- amt: amount,
- payment_request: hash,
- max_parts: 10,
- });
+ let error, fee, total, preimage;
+
+ if (config.lna.clightning) {
+ let m = await lna.pay(hash);
+ let sent;
+ ({
+ msatoshi: total,
+ msatoshi_sent: sent,
+ payment_preimage: preimage
+ } = m);
+
+ fee = parseInt((sent - total)/1000);
+ total = parseInt(total / 1000);
+ } else {
+ let m = await lna.sendPaymentSync({
+ amt: amount,
+ payment_request: hash,
+ max_parts: 10
+ });
+
+ ({
+ payment_error: error,
+ payment_route: { total_fees: fee, total_amt: total },
+ payment_preimage: preimage
+ } = m);
+ }
+
+ preimage = preimage.toString("hex");
+
+
+ if (payreq.payeeNodeKey === config.lnb.id) {
+ if (config.lna.clightning) {
+ let invoice = await lna.invoice(`${amount}sat` || "any", new Date(), "", 360);
+ let { bolt11: payment_request } = invoice;
+ await lnb.pay(payment_request);
+ } else {
+ let invoice = await lna.addInvoice({ value: amount })
+ let { payment_request } = invoice;
+ await lnb.sendPaymentSync({ payment_request, max_parts: 10 });
+ }
+ l.info("lnb sent back", amount);
+ }
- if (m.payment_error) {
- l.error("error sending lightning", m.payment_hash.toString('hex'), m.payment_error);
- return res.status(500).send(m.payment_error);
- }
+ if (error) {
+ l.error("error sending lightning", error);
+ return res.status(500).send(error);
+ }
- if (seen.includes(m.payment_preimage)) {
- l.warn("duplicate payment detected", m.payment_preimage);
+ if (seen.includes(preimage)) {
+ l.warn("duplicate payment detected", preimage);
throw new Error("Duplicate payment detected");
}
- let total = parseInt(m.payment_route.total_amt);
- let fee = m.payment_route.total_fees;
+ total = parseInt(total);
+ fee = parseInt(fee);
account.balance -= total;
await account.save({ transaction });
- let payment = await db.Payment.create({
- amount: -total,
- account_id: account.id,
- user_id: user.id,
- hash,
- preimage: m.payment_preimage.toString("hex"),
- rate: app.get("rates")[user.currency],
- currency: user.currency,
- confirmed: true,
- network: "LNBTC"
- }, { transaction });
+ let payment = await db.Payment.create(
+ {
+ amount: -total,
+ account_id: account.id,
+ user_id: user.id,
+ hash,
+ preimage,
+ rate: app.get("rates")[user.currency],
+ currency: user.currency,
+ confirmed: true,
+ network: "LNBTC",
+ fee
+ },
+ { transaction }
+ );
payment = payment.get({ plain: true });
payment.account = account.get({ plain: true });
- seen.push(m.payment_preimage);
- l.info("sent lightning", user.username, -payment.amount);
+ seen.push(preimage);
+ l.info("sent lightning", user.username, total);
user = await getUser(user.username, transaction);
emit(user.username, "user", user);
- l.info(config.lnb.id, payreq.payeeNodeKey);
- if (payreq.payeeNodeKey === config.lnb.id) {
- let invoice = await lna.addInvoice({ value: amount })
- let { payment_request } = invoice;
- await lnb.sendPaymentSync({ payment_request, max_parts: 10 });
- l.info("lnb sending back", amount);
- }
-
seen.push(hash);
res.send(payment);
});
@@ -88,7 +121,6 @@ module.exports = async (req, res) => {
l.error(
"problem sending lightning payment",
user.username,
- user.balance,
e.message
);
return res.status(500).send(e.message);
diff --git a/routes/lightning/user.js b/routes/lightning/user.js
deleted file mode 100644
index 41bd507f..00000000
--- a/routes/lightning/user.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const bolt11 = require("bolt11");
-
-module.exports = async (req, res) => {
- let { payuser, amount } = req.body;
-
- let user = await db.User.findOne({
- where: {
- username: payuser
- }
- });
-
- const account = await db.Account.findOne({
- where: {
- user_id: user.id,
- asset: config.liquid.btcasset
- }
- });
-
- l.info("paying user", req.user.username, payuser);
-
- if (!user) {
- return res.status(500).send("Couldn't find the user you're trying to pay");
- }
- let err = m => res.status(500).send(m);
-
- let invoice;
- try {
- invoice = await lnb.addInvoice({ value: amount });
- } catch (e) {
- return err(e.message);
- }
-
- let hash = invoice.payment_request;
-
- await db.Payment.create({
- user_id: user.id,
- account_id: account.id,
- hash,
- amount,
- rate: app.get("rates")[req.user.currency],
- currency: req.user.currency,
- tip: 0,
- confirmed: true,
- received: false,
- network: "LNBTC"
- });
-
- req.url = "/lightning/send";
- let payreq = bolt11.decode(hash);
- req.body.payreq = hash;
- return app._router.handle(req, res);
-};
diff --git a/routes/payments.js b/routes/payments.js
index 4089ae23..04b5dc51 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -1,13 +1,21 @@
const BitcoinCore = require("bitcoin-core");
const lnd = require("../lib/lnd");
const { Op } = require("sequelize");
+const { join } = require("path");
(async () => {
bc = new BitcoinCore(config.bitcoin);
lq = new BitcoinCore(config.liquid);
- lna = lnd(config.lna);
- lnb = lnd(config.lnb);
+ if (config.lna.clightning) {
+ const lnapath = join(require('os').homedir(), '.lightningreg/regtest')
+ const lnbpath = join(require('os').homedir(), '.lightningregb/regtest')
+ lna = require('clightning-client')(lnapath);
+ lnb = require('clightning-client')(lnbpath);
+ } else {
+ lna = lnd(config.lna);
+ lnb = lnd(config.lnb);
+ }
seen = [];
addresses = {};
@@ -25,9 +33,7 @@ const { Op } = require("sequelize");
app.post("/send", auth, require("./send"));
app.post("/lightning/invoice", auth, require("./lightning/invoice"));
- app.post("/lightning/query", auth, require("./lightning/query"));
app.post("/lightning/send", auth, require("./lightning/send"));
- app.post("/lightning/user", auth, require("./lightning/user"));
require("./lightning/receive");
app.post("/bitcoin/send", auth, require("./bitcoin/send"));
diff --git a/yarn.lock b/yarn.lock
index 6782b9f3..2c63a575 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1187,6 +1187,16 @@ __metadata:
languageName: node
linkType: hard
+"clightning-client@npm:^0.1.2":
+ version: 0.1.2
+ resolution: "clightning-client@npm:0.1.2"
+ dependencies:
+ debug: ^4.1.1
+ error: ^7.2.0
+ checksum: 2/23a25632222a59a14fa44445c59c6bbe0cbf71fefe6ce0dcbb7a4beab7b008284d0cc07dd47e501a0e1e830332afdbdd9cbf58fd8b36a3c8a1294594a174c722
+ languageName: node
+ linkType: hard
+
"cliui@npm:^3.0.3":
version: 3.2.0
resolution: "cliui@npm:3.2.0"
@@ -1243,6 +1253,7 @@ __metadata:
body-parser: ^1.19.0
bolt11: ^1.2.5
buffer-reverse: ^1.0.1
+ clightning-client: ^0.1.2
compression: ^1.7.4
connect-redis: 3.4.1
cookie-parser: ^1.4.4
@@ -1921,6 +1932,15 @@ __metadata:
languageName: node
linkType: hard
+"error@npm:^7.2.0":
+ version: 7.2.1
+ resolution: "error@npm:7.2.1"
+ dependencies:
+ string-template: ~0.2.1
+ checksum: 2/21ba37fe6750a1a7357509941983af66fa5e3fbe74eca96d48573878916e38fbe77db4d11374c26cd49b3b091ed9e74dc21983fbb86b564989664b1b87ab3003
+ languageName: node
+ linkType: hard
+
"es6-promise@npm:^4.0.3":
version: 4.2.8
resolution: "es6-promise@npm:4.2.8"
@@ -5159,6 +5179,13 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
+"string-template@npm:~0.2.1":
+ version: 0.2.1
+ resolution: "string-template@npm:0.2.1"
+ checksum: 2/c64ac6e7f744d8e37961c987c70038ae4e3ab3c6c9b3822709c1350397f7f0be1e84685924afb44468484823b4e1a8b5d8d4ff925cb0a01b13d8b73e50670513
+ languageName: node
+ linkType: hard
+
"string-width@npm:^1.0.1":
version: 1.0.2
resolution: "string-width@npm:1.0.2"